Spring TCP Socket Integration Implementation not passing gateway.send method - sockets

So I am wrapping the Spring Integration TCP client to provide APIs for my application. Previous questions regarding this can be found here and here. The problem with this is that the gateway.send() doesn't end at all and the API response never comes back.
Here is my ServerConnection.java file:
package com.abc.xyz.serverconnection;
import org.springframework.context.support.GenericXmlApplicationContext;
public class ServerConnections {
private SimpleGateway gateway;
public ServerConnections() {
final GenericXmlApplicationContext context = setupContext();
this.setGateway(context.getBean(SimpleGateway.class));
}
public static GenericXmlApplicationContext setupContext() {
final GenericXmlApplicationContext context = new GenericXmlApplicationContext();
context.load("classpath:META-INF/spring/integration/tcpClientServerDemo-context.xml");
context.registerShutdownHook();
context.refresh();
return context;
}
public SimpleGateway getGateway() {
return gateway;
}
public void setGateway(SimpleGateway gateway) {
this.gateway = gateway;
}
public boolean sendData(String input) {
this.gateway.send(input);
return true;
}
public void recieveData(String output) {
System.out.println("Data from server:" + output);
}
}
In my controller, I do something like this:
#RequestMapping(value = "/logon", method = RequestMethod.GET)
#ResponseBody
public String logon() {
// logics go here and the result is stored like below and sent
String message = "0000005401F40000C1E3E304010000000020000000000000000000000000000000000000000000004040404040404040C1E3E300C1C2C3C4C5C6C7C8E8C5E2C8E6C1D540F1F7F24BF0F1F64BF0F0F34BF0F5F200";
if (serverConnections.sendData(message)) {
return "Data sent successfully!";
} else {
return "Data not sent!";
}
}
Here is how my config looks like:
<context:property-placeholder />
<int:channel id="input" />
<int:channel id="toSA" />
<int:service-activator input-channel="toSA"
ref="echoService"
method="recieveData"/>
<bean id="echoService" class="com.abc.xyz.serverconnection.ServerConnection" />
<bean id="CustomSerializerDeserializer" class="com.abc.xyz.serverconnection.CustomSerializerDeserializer" />
<int:object-to-string-transformer id="serverBytes2String"
input-channel="serverBytes2StringChannel"
output-channel="toSA"/>
<int:gateway id="gw"
service-interface="com.abc.xyz.serverconnection.SimpleGateway"
default-request-channel="input"/>
<int-ip:tcp-connection-factory id="client"
type="client"
host="<ip>"
serializer="CustomSerializerDeserializer"
deserializer="CustomSerializerDeserializer"
port="6100"
single-use="false" />
<int-ip:tcp-outbound-gateway id="outGateway"
request-channel="input"
reply-channel="serverBytes2StringChannel"
connection-factory="client" />
EDIT: Not able to get the DEBUG log of the application since I am using the TCP client implementation as a Maven Module inside a Maven Project. Another module uses this as a dependency and that is where the REST API end-points reside at.

I think your
<int:service-activator input-channel="toSA"
ref="echoService"
method="recieveData"/>
Doesn't return any result to be sent to the replyChannel header, meanwhile your gateway.send() isn't a void method. That's how it waits for the reply which never comes back.

Related

V2Listener not found error

I am connecting a web api service to a backend-stateless service.
The Backservice is called MyProject.Management.Company and its code is:
internal sealed class Company: StatelessService,ICompanyManagement
{
private readonly CompanyManagementImpl _impl;
public Tenents(StatelessServiceContext context, CompanyManagementImpl impl)
: base(context)
{
this._impl = impl;
}
/// <summary>
/// Optional override to create listeners (e.g., TCP, HTTP) for this service replica to handle client or user requests.
/// </summary>
/// <returns>A collection of listeners.</returns>
protected override IEnumerable<ServiceInstanceListener> CreateServiceInstanceListeners()
{
return new[]
{
new ServiceInstanceListener(serviceContext => new FabricTransportServiceRemotingListener(serviceContext, this), "ServiceEndpoint")
};
}
/// <summary>
/// This is the main entry point for your service instance.
/// </summary>
/// <param name="cancellationToken">Canceled when Service Fabric needs to shut down this service instance.</param>
protected override async Task RunAsync(CancellationToken cancellationToken)
{
// TODO: Replace the following sample code with your own logic
// or remove this RunAsync override if it's not needed in your service.
long iterations = 0;
while (true)
{
cancellationToken.ThrowIfCancellationRequested();
ServiceEventSource.Current.ServiceMessage(this.Context, "Working-{0}", ++iterations);
await Task.Delay(TimeSpan.FromSeconds(1), cancellationToken);
}
}
public Task CreateCompany(Company company)
{
return _impl.CreateCompany(company);
}
public Task<List<Company>> GetAllCompanies()
{
return _impl.GetAllCompanies();
}
public Task<Company> GetCompanyById(string companyId)
{
return _impl.GetCompanyById(companyId);
}
}
The code is Listener code is adopted from This Blog Post and even the documentation code doesn't compile documentation the CreateServiceRemotingListenervextension method doesn't exist.
The ICompanyManagement is an interface inherting from IService interface and the implementation is realized via the CompanyManagament that in this phase just returns static objects.
The API is called MyProject.Portal and the controller code is:
public class CompanyController : Controller
{
ICompanyManagement _proxy;
public CompanyController(StatelessServiceContext context)
{
string serviceUri = $"{context.CodePackageActivationContext.ApplicationName}" + "/MyProject.Management.Company";
_proxy = ServiceProxy.Create<ICompanyManagement>(new Uri(serviceUri));
}
// GET: api/Company
[HttpGet]
public async Task<JsonResult> Get()
{
try
{
var result = await _proxy.GetAllCompanies();
return this.Json(result);
}
catch (Exception ex)
{
throw ex;
}
}
}
When the code run it returns the following error.
NamedEndpoint 'V2Listener' not found in the address
'{"Endpoints":{"ServiceEndpoint":"localhost:59286+12a705ed-11a5-4bf5-bafd-84179c966257-131719261525940414-9e876439-9294-4ec9-8b33-05f17515aaf4"}}'
for partition '12a705ed-11a5-4bf5-bafd-84179c966257'
Finally: I am using .netcore v2, service fabric v6.2.274.
Right after usings in your ICompanyManagement file add following line:
[assembly: FabricTransportServiceRemotingProvider(RemotingListener = RemotingListener.V2Listener, RemotingClient = RemotingClient.V2Client)]
In your service (CompanyManagement) manifest (ServiceManifest.xml file) make sure that endpoint is set to version 2:
<Resources>
<Endpoints>
<Endpoint Name="ServiceEndpointV2" />
</Endpoints>
</Resources>
Change your CreateServiceInstanceListeners method to:
protected override IEnumerable<ServiceInstanceListener> CreateServiceInstanceListeners()
{
return this.CreateServiceRemotingInstanceListeners();
}
Finally in your web api controller register your service proxy like this:
ICompanyManagement companyManagementClient = ServiceProxy.Create<ICompanyManagement>(new Uri($"fabric:/{applicationName}/{serviceName}"));
If you follow these steps it will work.

Service Fabric, Remoting V2 to Stateful Service not working

I can't get this working, I've googled and probably found every page on how to do this, all two of them!
Basically I'm just trying to get SF Remoting V2 working from a stateless .NET Core 2 MVC App' to a Statefull service.
Here's what I have done:
Client Code in Controller: (Simplified as much as Possible):
public class ValuesController : Controller
{
[HttpGet]
public async Task<IEnumerable<string>> Get()
{
// Provide certificate details.
var serviceProxyFactory = new ServiceProxyFactory((c) => new FabricTransportServiceRemotingClientFactory());
var proxy = serviceProxyFactory.CreateServiceProxy<ICallMe>(new Uri("fabric:/SFExperiment/Stateful1"));
var value3 = await proxy.GetGreeeting("Bob");
return new[] { "value1", "value2", value3 };
}
Service Code Interface:
using System.Threading.Tasks;
using Microsoft.ServiceFabric.Services.Remoting;
using Microsoft.ServiceFabric.Services.Remoting.FabricTransport;
[assembly: FabricTransportServiceRemotingProvider(RemotingListener =
RemotingListener.V2Listener, RemotingClient = RemotingClient.V2Client)]
namespace Stateful1.Abstractions
{
public interface ICallMe : IService
{
Task<string> GetGreeeting(string name);
}
}
Service Code:
Public sealed class Stateful1 : StatefulService, ICallMe
{
public Stateful1(StatefulServiceContext context)
: base(context)
{ }
protected override IEnumerable<ServiceReplicaListener> CreateServiceReplicaListeners()
{
return this.CreateServiceRemotingReplicaListeners();
}
public Task<string> GetGreeeting(string name)
{
return Task.FromResult(#"Congratulations, you have remoting working. :-) ");
}
I have added below to ServiceManifest.xml
<Resources>
<Endpoints>
<!-- To enable Service remonting for remoting services V2-->
<Endpoint Name="ServiceEndpointV2" />
<Endpoint Name="ReplicatorEndpoint" />
</Endpoints>
</Resources>
And it doesn't work.. I get the following Exception:
Invalid partition key/ID '{0}' for selector {1}
What am I doing wrong?
In the call to create a service proxy, you must specify a partition key because you are connecting to a stateful service.
long partitionKey = 0L; //TODO: Determine partition key
var proxy = serviceProxyFactory.CreateServiceProxy<ICallMe>(new Uri("fabric:/SFExperiment/Stateful1"), new ServicePartitionKey(partitionKey), TargetReplicaSelector.PrimaryReplica);
Also, make sure you reuse your service proxy factory, instead of creating a new one.
Have a look at this code for example.

Best way to handle incoming messages with XMPP

Is there a work-around to get Spring to handle incoming messages from XMPP? I have tried many different configurations to get an inbound-channel-adapter to respond to incoming XMPP messages and nothing happens. I know that they show up at the Spring Integration layer (I can see that in the logs) but they are ignored. Is there any way to get them into my application layer? I hope to avoid needing to make changes to Spring Integration itself if I can.
Here is my integration configuration:
<int-xmpp:inbound-channel-adapter id="gcmIn"
channel="gcmInChannel"
xmpp-connection="gcmConnection"
auto-startup="true"
/>
<bean id="inboundBean" class="example.integration.GcmInputHandler"/>
<int:service-activator input-channel="gcmInChannel" output-channel="nullChannel" ref="inboundBean" method="handle"/>
Using the outbound-channel-adapter works fine. I can send messages over GCM 100% easily. But inbound does nothing, even though I know the messages are coming in.
Thanks
Not a very clean one, you would need to overwrite the ChatMessageListeningEndpoint, which drops all empty body messages.
This one needs then to be used as inbound-channel adapter in your config.
In addition you need to register the GCM package extension on the Smack Provider Manager, otherwise you lose the JSON message.
Working on a sample project -- so if you need more help let me know and I will post a link as soon it works somehow in a understandable way.
Here a sample GCM Input Adapter
public class GcmMessageListeningEndpoint extends ChatMessageListeningEndpoint {
private static final Logger LOG = LoggerFactory.getLogger(GcmMessageListeningEndpoint.class);
#Setter
protected PacketListener packetListener = new GcmPacketListener();
protected XmppHeaderMapper headerMapper = new DefaultXmppHeaderMapper();
public GcmMessageListeningEndpoint(XMPPConnection connection) {
super(connection);
ProviderManager.addExtensionProvider(GcmPacketExtension.GCM_ELEMENT_NAME, GcmPacketExtension.GCM_NAMESPACE,
new PacketExtensionProvider() {
#Override
public PacketExtension parseExtension(XmlPullParser parser) throws Exception {
String json = parser.nextText();
return new GcmPacketExtension(json);
}
});
}
#Override
public void setHeaderMapper(XmppHeaderMapper headerMapper) {
super.setHeaderMapper(headerMapper);
this.headerMapper = headerMapper;
if (this.headerMapper == null) throw new IllegalArgumentException("Null XmppHeaderMapper isn't supported!");
}
public String getComponentType() {
return "xmpp:inbound-channel-adapter-gcm";
}
#Override
protected void doStart() {
Assert.isTrue(this.initialized, this.getComponentName() + " [" + this.getComponentType() + "] must be initialized");
this.xmppConnection.addPacketListener(this.packetListener, null);
}
#Override
protected void doStop() {
if (this.xmppConnection != null) {
this.xmppConnection.removePacketListener(this.packetListener);
}
}
class GcmPacketListener implements PacketListener {
#Override
public void processPacket(Packet packet) throws NotConnectedException {
if (packet instanceof org.jivesoftware.smack.packet.Message) {
org.jivesoftware.smack.packet.Message xmppMessage = (org.jivesoftware.smack.packet.Message) packet;
Map<String, ?> mappedHeaders = headerMapper.toHeadersFromRequest(xmppMessage);
sendMessage(MessageBuilder.withPayload(xmppMessage).copyHeaders(mappedHeaders).build());
} else {
LOG.warn("Unsuported Packet {}", packet);
}
}
}
}
And here the new configuration for the inbound-channel-adapter remove the one in XML:
#Bean
public GcmMessageListeningEndpoint inboundAdpater(XMPPConnection connection, MessageChannel gcmInChannel) {
GcmMessageListeningEndpoint endpoint = new GcmMessageListeningEndpoint(connection);
endpoint.setOutputChannel(gcmInChannel);
return endpoint;
}

How to launch Spring DM service consumer in OSGI

I started creating an OSGI project with Spring DM. I Created two bundles, the first one (bundle1) provides a service that changes the order of a recieved string. The seconde one (bundle2) consumes that service and prints the result in the console.
service implementation:
public final class Bundle1ServiceImpl implements Bundle1Service {
public Bundle1ServiceImpl() {
System.out.println("Bundle1ServiceImpl contructor...");
}
public String scramble(String text) {
List charList = new ArrayList();
char[] textChars = text.toCharArray();
for (int i = 0; i < textChars.length; i++) {
charList.add(new Character(textChars[i]));
}
Collections.shuffle(charList);
char[] mixedChars = new char[text.length()];
for (int i = 0; i < mixedChars.length; i++) {
mixedChars[i] = ((Character) charList.get(i)).charValue();
}
return new String(mixedChars);
}}
spring file for service provider :
bundle1-osgi.xml
<service ref="bundle1Service" interface="fr.thispro.bundle1.Bundle1Service" />
bundle1-context.xml
<bean id="bundle1Service" class="fr.thispro.bundle1.internal.Bundle1ServiceImpl">
</bean>
consumer :
public class Bundle2Consumer {
private final Bundle1Service service;
public Bundle2Consumer(Bundle1Service service) {
this.service = service;
}
public void start() {
System.out.println(service.scramble("Text"));
System.out.println("im started");
}
public void stop() {
System.out.println("im stopped");
}}
spring files for consumer:
bundle2-context.xml
<beans:bean id="consumer" class="fr.thispro.bundle2.Bundle2Consumer" init-method="start" destroy-method="stop" lazy-init="false" ><beans:constructor-arg ref="bundle1Service"/>
bundle2-osgi.xml
<reference id="bundle1Service" interface="fr.thispro.bundle1.Bundle1Service" />
The service is well registred referenced and discovered. But the consumer doesn't print anything even when i start it explicitly by start command.
Thanks in adanvance,
I found the problem. You bundle2 incldues an Activtor but you did not define the activator in the Manifest. So the bundle never actually starts up.
If you intended to start the bundle2 using spring dm then the problem is that the jar does not contain the spring xml files.

Search form that redirects to results page

Hello i have the following problem.
I have a search page lets call it search.xhtml and you can search for a bar-code. This value is unique so the result is always one or zero objects from the database
<p:panelGrid columns="1" style="margin:20px;">
<h:form>
<p:messages id="messages" globalOnly="true" showDetail="false" />
<p:message for="barcode" />
<p:inputText id="barcode" value="#{searchForm.barCode}"
required="true" requiredMessage="Value needed" />
<p:commandButton value="search"
action="#{searchForm.searchBarcode}" id="search"/>
</h:form>
</p:panelGrid>
This is the backingbean:
#ManagedBean
#ViewScoped
public class SearchForm extends BasePage {
private Long barCode;
#ManagedProperty("#{daoManager}")
public DaoManager daoManager;
public void setDaoManager(DaoManager daoManager) {
this.daoManager = daoManager;
}
public Long getBarCode() {
return barCode;
}
public void setBarCode(Long barCode) {
this.barCode = barCode;
}
public String searchBarcode() {
//request to dao to get the object
DataList<Data> data = daoManager.findbybarcode(barCode);
if (data.size() == 0) {
this.addMessage(FacesMessage.SEVERITY_ERROR,
"Not Found: " + barCode);
return null;
} else {
getFacesContext().getExternalContext().
getRequestMap().put("id", data.getId());
return "details";
}
}
So if i go to my details page which expect the parameter id this isnt send to the detail page.
backing bean details page:
#ManagedBean
#ViewScoped
public class DetailBean extends BasePage implements Serializable {
#PostConstruct
public void init() {
if (id != null) {
//Go on with the stuff
} else {
addMessage(FacesMessage.SEVERITY_ERROR,"Object not found");
}
}
}
What am i doing wrong? And is this wrong use of JSF? I know i can generate a list and the click on the result but thats not what i want. Also i can take the barcode from the first bean and pass it as a parameter but i want the details page only to accept the id from the objects. So is my thinking wrong? Or is there a solution to get it like this?
If I understand correctly, you wish to pass the ID of the barcode to the details page and yes this is possible.
getFacesContext().getExternalContext().getRequestMap().put("id", data.getId());
The following line is putting the ID parameter into the request that the client just sent you, but the navigation action to details will result in a different request. Try this instead:
return "details?faces-redirect=true&id=" + data.getId();
This will return an HTTP GET navigation action with the ID of the barcode passed as a request parameter in the request.