CometD Issues with Publishing Data - cometd

I'm new to CometD and having problems publishing data on a channel. I'm getting the following error for not invoking a handshake() on my channel:
Sender : null
Sender : L:/abc/1?
Exception in thread "Thread-9" java.lang.IllegalStateException: Method handshake() not invoked for local session L:/abc/1?
at org.cometd.server.LocalSessionImpl.getId(LocalSessionImpl.java:161)
at org.cometd.server.ServerChannelImpl.publish(ServerChannelImpl.java:309)
at packagename.CometDSender.sendData(CometDSender.java:64)
at packagename.ProcessorImp.processData(ProcessorImp.java:18)
at packagename.TestSource.processNewData(TestSource.java:50)
at packagename.TestSource.run(TestSource.java:36)
at java.lang.Thread.run(Unknown Source)
but when i include sender.handshake() i get the following exception
Sender : null
Sender : L:/abc/1?
Exception in thread "Thread-9" java.lang.NullPointerException
at org.cometd.server.BayeuxServerImpl.freeze(BayeuxServerImpl.java:868)
at org.cometd.server.BayeuxServerImpl.doPublish(BayeuxServerImpl.java:823)
at org.cometd.server.BayeuxServerImpl.handle(BayeuxServerImpl.java:649)
at org.cometd.server.LocalSessionImpl.doSend(LocalSessionImpl.java:214)
at org.cometd.server.LocalSessionImpl.handshake(LocalSessionImpl.java:125)
at org.cometd.server.LocalSessionImpl.handshake(LocalSessionImpl.java:110)
at packagename.CometDSender.sendData(CometDSender.java:62)
at packagename.ProcessorImp.processData(ProcessorImp.java:18)
at packagename.TestSource.processNewData(TestSource.java:50)
at packagename.TestSource.run(TestSource.java:36)
at java.lang.Thread.run(Unknown Source)
I've included my Class below. Can someone tell me if I'm missing something:
#Service
public class CometDSender implements Sender {
#Inject
private BayeuxServer bayeuxServer;
#Session
private LocalSession sender;
private String channelName = null;
// setup CometD Channel
public CometDSender() {
this.channelName = "/abc/1";
System.out.println("bayeuxServer : " + (bayeuxServer == null ? "Is Null" : "Is Not Null"));
if (bayeuxServer == null) {
bayeuxServer = new BayeuxServerImpl();
}
bayeuxServer.createIfAbsent(channelName, new ConfigurableServerChannel.Initializer() {
public void configureChannel(ConfigurableServerChannel channelName) {
System.out.println("channel : " + (channelName == null ? "Is Null" : "Is Not Null"));
channelName.setPersistent(true);
channelName.setLazy(true);
}
});
}
public void sendData(Agent data) {
// Convert the Update business object to a CometD-friendly format
Map<String, Object> cometData = new HashMap<String, Object>(4);
cometData.put("ID", data.getID());
// Publish to all subscribers
ServerChannel channel = bayeuxServer.getChannel(channelName);
System.out.println("Sender : " + sender);
if (sender == null) {
sender = bayeuxServer.newLocalSession(channelName);
System.out.println("Sender : " + sender);
sender.handshake();
}
channel.publish(sender, cometData, null);
}
}

You must not create BayeuxServerImpl instances unless you know what you're doing, and the same applies to LocalSession.
Since you are using CometD services, those fields must be non-null and you must not create them yourself.
They probably are null, and this is due to the fact that you have a misconfiguration most likely in your web.xml (which you did not post).
Please read the documentation about CometD services and follow the tutorials: they will guide you step by step in solving your problems with CometD services.

Related

Class not found when trying to return List from consumeEvent in Quarkus

When I try to return a Uni with a typed java.util.List in Quarkus in dev mode, i get a ClassNotFound exception. I have read about Quarkus using different class loaders in different profiles, but I don't see that I do anything fancy.
Here's the sender
#Query("offers")
public Uni<List<OfferResponse>> getOffers(#PathParam("category") Integer categoryId) {
OfferRequest event = new OfferRequest();
event.setCategoryId(categoryId);
Uni<List<OfferResponse>> offers = bus.<List<OfferResponse>>request(OfferRequest.ADDRESS, event).onItem().transform(Message::body);
return offers;
}
And here's the consumer
#ConsumeEvent(OfferRequest.ADDRESS)
public Uni<List<OfferResponse>> onOfferQuery(OfferRequest request) {
List<KelkooOffer> offers = getOffers(request.getCategoryId());
List<OfferResponse> responses = new ArrayList<OfferResponse>();
for (KelkooOffer offer : offers) {
responses.add(offer.getEventResponse());
}
return Uni.createFrom().item(responses);
}
The bean I'm trying to return is just a POJO
and the error message
2021-08-18 11:11:16,186 ERROR [io.qua.run.Application] (Quarkus Main Thread) Failed to start application (with profile dev): java.lang.ClassNotFoundException: java.util.List<se.bryderi.events.OfferResponse>
at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:581)
at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:178)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:522)
at io.quarkus.bootstrap.classloading.QuarkusClassLoader.loadClass(QuarkusClassLoader.java:414)
at io.quarkus.bootstrap.classloading.QuarkusClassLoader.loadClass(QuarkusClassLoader.java:405)
at io.quarkus.bootstrap.classloading.QuarkusClassLoader.loadClass(QuarkusClassLoader.java:414)
at io.quarkus.bootstrap.classloading.QuarkusClassLoader.loadClass(QuarkusClassLoader.java:405)
at java.base/java.lang.Class.forName0(Native Method)
at java.base/java.lang.Class.forName(Class.java:398)
at io.quarkus.deployment.steps.VertxProcessor$build609260703.deploy_0(VertxProcessor$build609260703.zig:142)
at io.quarkus.deployment.steps.VertxProcessor$build609260703.deploy(VertxProcessor$build609260703.zig:40)
at io.quarkus.runner.ApplicationImpl.doStart(ApplicationImpl.zig:784)
at io.quarkus.runtime.Application.start(Application.java:101)
at io.quarkus.runtime.ApplicationLifecycleManager.run(ApplicationLifecycleManager.java:101)
at io.quarkus.runtime.Quarkus.run(Quarkus.java:66)
at io.quarkus.runtime.Quarkus.run(Quarkus.java:42)
at io.quarkus.runtime.Quarkus.run(Quarkus.java:119)
at io.quarkus.runner.GeneratedMain.main(GeneratedMain.zig:29)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)
at io.quarkus.runner.bootstrap.StartupActionImpl$1.run(StartupActionImpl.java:98)
at java.base/java.lang.Thread.run(Thread.java:829)
I get the same result if I run the dev profile or if I run the packaged fast-jar.
Happy for any hint that will point me in the right direction
There is a limitation of the Vert.x EventBus which prevents to encode/decode lists or sets directly.
You could create a wrapper for your OfferResponse list:
import java.util.AbstractList;
import java.util.List;
public class OfferResponseList extends AbstractList<OfferResponse> {
private List<OfferResponse> wrapped;
private OfferResponseList(List<OfferResponse> wrapped) {
this.wrapped = wrapped;
}
public static OfferResponseList wrap(List<OfferResponse> list) {
return new OfferResponseList(list);
}
#Override
public OfferResponse get(int index) {
return wrapped.get(index);
}
#Override
public int size() {
return wrapped.size();
}
}
Then transform your consumer to:
#ConsumeEvent(OfferRequest.ADDRESS)
public Uni<OfferResponseList> onOfferQuery(OfferRequest request) {
List<KelkooOffer> offers = getOffers(request.getCategoryId());
List<OfferResponse> responses = new ArrayList<OfferResponse>();
for (KelkooOffer offer : offers) {
responses.add(offer.getEventResponse());
}
// Notice the call to OfferResponseList.wrap here
return Uni.createFrom().item(OfferResponseList.wrap(responses));
}
That's it. Quarkus will register a codec for OfferResponseList automatically.
On the client side, you do not need to change your code:
#Query("offers")
public Uni<List<OfferResponse>> getOffers(#PathParam("category") Integer categoryId) {
OfferRequest event = new OfferRequest();
event.setCategoryId(categoryId);
// You can use Uni<List<OfferResponse>> or Uni<OfferResponseList>
Uni<List<OfferResponse>> offers = bus.<List<OfferResponse>>request(OfferRequest.ADDRESS, event).onItem().transform(Message::body);
return offers;
}

Using shared UDP Socket in Jersey REST Api

I am developing a simple rest service with jersey and jetty, which gets some requests from the clients and sends the prepared request further to another software (which is not made by me). The software sends some messages back that must be analyzed and sends back to the client. Therefore I've developed a new thread called SocketReceiver which starts after the request ist send to the software. This class uses a helper class which stores the connection to the udp socket (implemented as singleton). The solution works perfect as long as I have only one request per time. If two requests (from two separate clients) are made, there is a concurrency issue and no response is written back to the client by jersey.
Here's the run method of the socket receiver:
#Override
public void run() {
byte[] message = new byte[9999];
DatagramPacket p = new DatagramPacket(message, message.length);
while (returnedObject == null) {
logger.debug("Waiting for incomming message ...");
try {
onDemandInfoServer.getDataRadioSocket().receive(p);
MessageFrame messageFrame = new MessageFrame(message);
// CHECK Length (2. and 3. byte) and CODE (first byte)
if ((message[1] == 0 && message[2] == 0) || !(message[0] == DC_Constants.D_Code
|| message[0] == DC_Constants.G_Code || message[0] == DC_Constants.P_Code)) {
logger.warn("wrong message!");
continue;
}
int length = messageFrame.getLength();
if (length > message.length) {
logger.warn("wrong message!");
continue;
}
byte[] msg = new byte[length];
System.arraycopy(message, 0, msg, 0, length);
logger.debug(LogHelper.getDataAsString(msg));
if (message[0] == DC_Constants.P_Code) {
msg = messageIsParanet(messageFrame);
}
MessageFrame msgFrame = new MessageFrame(msg);
if (!msgFrame.isAcknowledge()) {
newMessageFromDataradio(msgFrame);
}
} catch (IOException e) {
// error handling
}
}
asyncResponse.resume(returnedObject); // returned objects sets when messages being analyszed
}
And here's a example jersey rest service:
#Path("/trips")
public class RequestTripListService extends BaseRestService {
private static final Logger logger = Logger.getLogger(RequestTripListService.class);
#POST
#Compress
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.APPLICATION_JSON)
public void logonToBlock(TripListRequest tripListRequest, #Suspended final AsyncResponse asyncResponse,
#Context HttpServletRequest request) throws IOException {
// Send message via udp
byte[] logonTelegramm = createLogonTelegramm(sequenceNumber);
getOnDemandInfoServer().sendToDataRadio(logonTelegramm);
// Build a new socket receiver and execute it
JourneyOnDemandInfo info = new JourneyOnDemandInfo(terminal, tripListRequest.getBlockNo(), 0, 0, sequenceNumber);
SocketReceiver<TripListUpdate> socketReceiver = new SocketReceiver<>(asyncResponse,
getOnDemandInfoServer(), getXmlCodec(), info, TripListUpdate.class);
socketReceiver.start();
}
}
What is the correct and thread safe way to use a shared udp socket?
How can I solve my problem described above?
Thanks for your help!

Securing a GWT app with a request param to be checked in a crosscontext attribute

My application is supposed to received a request parameter called sessionId which is supposed to be used to lookup for a crosscontext attribute.
I was looking at Spring Security to implement this and I think already have a good implementation of my AuthenticationProvider :
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
ServletContext servletContext = request.getSession().getServletContext();
String sessionId = request.getParameter("sessionId");
if (sessionId != null) {
ServletContext sc = request.getSession().getServletContext();
Object obj = sc.getContext("/crosscontext").getAttribute(sessionId);
if (obj != null) {
// return new Authentication
}
} else {
logger.error("No session id provided in the request");
return null;
}
if (!GWT.isProdMode()) {
// return new Authentication
} else {
logger.error("No session id provided in the request");
return null;
}
}
Now, what I would like to do is to configure Spring Security to not prompt for a user name and password, to let it reach this authentication provider call the authenticate method.
How can I achieve this ?
I fixed my issue by reviewing the design of my security and going for something closer to the preauthenticated mechanisms that are already provided by Spring Security.
I extended 2 components of Spring Security.
First one is an AbstractPreAuthenticatedProcessingFilter, usually his role is to provide the principal provided in the headers. In my case, I retrieve the header value and search in the context shared between 2 application for an attribute that corresponds to that header and returns it as principal :
public class MyApplicationPreAuthenticatedProcessingFilter extends AbstractPreAuthenticatedProcessingFilter {
private static final Logger logger = Logger.getLogger(MyApplicationPreAuthenticatedProcessingFilter.class);
#Override
protected Object getPreAuthenticatedPrincipal(HttpServletRequest request) {
if (MyApplicationServerUtil.isProdMode()) {
String principal = request.getHeader("MY_HEADER");
String attribute = (String) request.getSession().getServletContext().getContext("/crosscontext").getAttribute(principal);
logger.info("In PROD mode - Found value in crosscontext: " + attribute);
return attribute;
} else {
logger.debug("In DEV mode - passing through ...");
return "";
}
}
#Override
protected Object getPreAuthenticatedCredentials(HttpServletRequest request) {
return null;
}
}
The other component is the AuthenticationProvider which will just check if the authentication contains a principal when it runs in prod mode (GWT prod) :
public class MyApplicationAuthenticationProvider implements AuthenticationProvider {
private static final Logger logger = Logger.getLogger(MyApplicationAuthenticationProvider.class);
public static final String SESSION_ID = "sessionId";
#Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
if (MyApplicationServerUtil.isProdMode()) {
if (StringUtils.isNotEmpty((String) authentication.getPrincipal())) {
logger.warn("Found credentials: " + (String) authentication.getPrincipal());
Authentication customAuth = new CustomAuthentication("ROLE_USER");
customAuth.setAuthenticated(true);
return customAuth;
} else {
throw new PreAuthenticatedCredentialsNotFoundException("Nothing returned from crosscontext for sessionId attribute ["
+ (String) authentication.getPrincipal() + "]");
}
} else {
Authentication customAuth = new CustomAuthentication("ROLE_USER");
customAuth.setAuthenticated(true);
return customAuth;
}
}
#Override
public boolean supports(Class<?> authentication) {
return PreAuthenticatedAuthenticationToken.class.isAssignableFrom(authentication);
}
}
I understand that it might not be the most secure application. However, it will already be running in a secure environment. But if you have suggestions for improvement, they're welcome !

Generating random session id whenever user uses login() in web services

Am new to web services. Am trying to generate unique session id for every login that a user does, in web services.
What I thought of doing is,
Write a java file which has the login and logout method.
Generate WSDL file for it.
Then generate web service client(using Eclipse IDE), with the WSDl file which I generate.
Use the generated package(client stub) and call the methods.
Please let me know if there are any flaws in my way of implementation.
1. Java file with the needed methods
public String login(String userID, String password) {
if (userID.equalsIgnoreCase("sadmin")
&& password.equalsIgnoreCase("sadmin")) {
System.out.println("Valid user");
sid = generateUUID(userID);
} else {
System.out.println("Auth failed");
}
return sid;
}
private String generateUUID(String userID) {
UUID uuID = UUID.randomUUID();
sid = uuID.toString();
userSessionHashMap = new HashMap<String, String>();
userSessionHashMap.put(userID, sid);
return sid;
}
public void logout(String userID) {
Set<String> userIDSet = userSessionHashMap.keySet();
Iterator<String> iterator = userIDSet.iterator();
if (iterator.equals(userID)) {
userSessionHashMap.remove(userID);
}
}
2. Generated WSDL file
Developed the web service client from the wsdl.
4. Using the developed client stub.
public static void main(String[] args) throws Exception {
ClientWebServiceLogin objClientWebServiceLogin = new ClientWebServiceLogin();
objClientWebServiceLogin.invokeLogin();
}
public void invokeLogin() throws Exception {
String endpoint = "http://schemas.xmlsoap.org/wsdl/";
String username = "sadmin";
String password = "sadmin";
String targetNamespace = "http://WebServiceLogin";
try {
WebServiceLoginLocator objWebServiceLoginLocator = new WebServiceLoginLocator();
java.net.URL url = new java.net.URL(endpoint);
Iterator ports = objWebServiceLoginLocator.getPorts();
while (ports.hasNext())
System.out.println("ports Iterator size-->" + ports.next());
WebServiceLoginPortType objWebServiceLoginPortType = objWebServiceLoginLocator
.getWebServiceLoginHttpSoap11Endpoint();
String sid = objWebServiceLoginPortType.login(username, password);
System.out.println("sid--->" + sid);
} catch (Exception exception) {
System.out.println("AxisFault at creating objWebServiceLoginStub"
+ exception);
exception.printStackTrace();
}
}
On running the this file, I get the following error.
AxisFault
faultCode: {http://schemas.xmlsoap.org/soap/envelope/}Server.userException
faultSubcode:
faultString: java.net.ConnectException: Connection refused: connect
faultActor:
faultNode:
faultDetail:
{http://xml.apache.org/axis/}stackTrace:java.net.ConnectException: Connection refused: connect
Can anyone suggest an alternate way of handling this task ? And what could probably be the reason for this error.
Web services are supposed to be stateless, so having "login" and "logout" web service methods doesn't make much sense.
If you want to secure web services calls unfortunately you have to code security into every call. In your case, this means passing the userId and password to every method.
Or consider adding a custom handler for security. Read more about handlers here.

GWT XMPP client using GWT-Strophe

I'm using GWT-Strophe to connect to my XMPP server. Things are going well and I am able to connect to my XMPP server and send other users messages. I'm having a problem with receiving messages. I'm attempting to copy the Strophe echobot example, but the code in my Handler is not getting executed when a message is received.
Here is the code I am using to connect and register the handler:
connection = new Connection("http://localhost/proxy/");
handler = new Handler<Element>() {
#Override
public boolean handle(Element element) {
GWT.log("Handling...");
GWT.log(element.toString());
String to = element.getAttribute("to");
String from = element.getAttribute("from");
String type = element.getAttribute("type");
NodeList<com.google.gwt.dom.client.Element> elems = element.getElementsByTagName("body");
if ((type == null ? "chat" == null : type.equals("chat")) && elems.getLength() > 0) {
Element body = (Element) elems.getItem(0);
GWT.log("ECHOBOT: I got a message from " + from + ": " + body.getText());
String[][] attributes = {{"to", from}, {"from", to}, {"type", "chat"}};
Builder reply = Builder.$msg(attributes).cnode(body.copy());
connection.send(reply.tree());
GWT.log("ECHOBOT: I sent " + from + ": " + body.getText());
}
return true;
}
};
StatusCallback callback = new Connection.StatusCallback() {
#Override
public void statusChanged(Status status, String reason) {
if (status == Status.CONNECTING) {
GWT.log("Strophe is connecting.");
} else if (status == Status.CONNFAIL) {
GWT.log("Strophe failed to connect.");
} else if (status == Status.DISCONNECTING) {
GWT.log("Strophe is disconnecting.");
} else if (status == Status.DISCONNECTED) {
GWT.log("Strophe is disconnected.");
} else if (status == Status.CONNECTED) {
GWT.log("Strophe is connected.");
connection.addHandler(null, null, "message", null, null, handler);
Builder pres = Builder.$pres(null);
connection.send(pres);
GWT.log("ECHOBOT: Send a message to " + connection.getJid() + " to talk to me.");
}
}
};
connection.connect("me#myserver.com", "password", callback);
Change your line
connection.addHandler(null, null, "message", null, null, handler);
with
connection.addHandler(null, "message", null, null, null, handler);
and it should work fine.
Can you post here how you connected gwt-strophe (if you successfully connected)?
Or if you found better solution please post it here. I've made GWT compatible module from gwt-strophe(included gwt.xml and all sources) and used in my GWT project. During compilation there was no error but when i called my widget it says "Cannot read property 'Connection' of undefined". After some code inspection i didn't found where Strophe object is initialized
private native JavaScriptObject connection(String boshService) /*-{
var connection = new $wnd.Strophe.Connection(boshService);
return connection;
}-*/;
Error thrown during runtime execution because window.Strophe object is undefined
p.s. i haven't found here how to add comment so i've made "answer" to ask question in this thread...
All i need is connection from GWT to my openfire server