Is there any way to enable cdi within this #ClientEndpoint class (still using annotations as opposed to programmatic endpoint classes)? I am using wildfly 14 and java 8.
Here is the code that creates the session, passing the classname to the "createConnection" method:
#ApplicationScoped //TODO move this to be request scoped
public class SessionProducer {
#Produces
public Session getSession(InjectionPoint ip) {
SessionAnnotation annotation = ip.getAnnotated().getAnnotation(SessionAnnotation.class);
if(annotation != null) {
Class clazz = annotation.clazz();
String url = annotation.serverURL();
WebSocketContainer webSocketContainer = ContainerProvider.getWebSocketContainer();
try {
return webSocketContainer.connectToServer(clazz, new URI(url)); //<----------this is the line that uses the annotated class (clazz is a reference to the class)
} catch (DeploymentException | IOException | URISyntaxException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
return null;
}
/**
* The destroy/disposer metho for the session
* #param session
*/
public void close(#Disposes Session session) {
try {
session.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
Here is the annotated endpoint class:
#ClientEndpoint
public class CryptoCompareWSClient {
#Inject
#CryptoCompare
private Event<String> cryptoCompareEvent; //<--------this is always null, no cdi happens
public CryptoCompareWSClient() {
System.out.println("constructor");
//cryptoCompareEvent = new Event();
}
#PostConstruct
public void init() {
System.out.println("post construct"); //<---------this never gets called
}
#OnOpen
public void open(Session session) {
//session.getAsyncRemote().sendText("SubAdd: { subs: ['0~Poloniex~BTC~USD'] }" /*"test"*/);
System.out.println("opened");
}
#OnClose
public void close(Session session) {
System.out.println("Session " + session + " closed");
}
#OnError
public void error(Throwable error) {
System.out.println("Error: " + error.getMessage());
}
#OnMessage
public void message(String message, Session session) {
System.out.println("Message");
//cryptoCompareEvent.fireAsync(message);
}
}
Is there any way to enable cdi in the enabled class?
Thanks.
Related
I am creating a group chat functionality on my app and I am having some issues. Requirements are Java and Websockets in Java(both server and the client part). I have created both server and client WebSockets and communication by itself works(sending text from client to server and visa versa), but what I want to do is send Objects through the socket and serialize it into XML. I have created the serialization and it work perfectly without the socket. The problem appears when I want to combine the two.
For now I tried embedding the encoder and decoder to socket implementation and sending Player object through the socket and got this error(whatever I tried later the error stayed the same):
java.lang.ClassNotFoundException: model/Player
Continuing ...
java.lang.NoSuchMethodException: <unbound>=XMLDecoder.new();
Continuing ...
java.lang.IllegalStateException: The outer element does not return value
Continuing ...
java.lang.IllegalStateException: The outer element does not return value
Continuing ...
java.lang.ArrayIndexOutOfBoundsException: 0
at java.beans.XMLDecoder.readObject(Unknown Source)
at Util.Util.getObjectFromXml(Util.java:43)
at Util.WebDecoder.decode(WebDecoder.java:28)
at org.apache.tomcat.websocket.pojo.PojoMessageHandlerWholeText.decode(PojoMessageHandlerWholeText.java:108)
at org.apache.tomcat.websocket.pojo.PojoMessageHandlerWholeText.decode(PojoMessageHandlerWholeText.java:39)
at org.apache.tomcat.websocket.pojo.PojoMessageHandlerWholeBase.onMessage(PojoMessageHandlerWholeBase.java:57)
at org.apache.tomcat.websocket.WsFrameBase.sendMessageText(WsFrameBase.java:395)
at org.apache.tomcat.websocket.WsFrameBase.processDataText(WsFrameBase.java:495)
at org.apache.tomcat.websocket.WsFrameBase.processData(WsFrameBase.java:294)
at org.apache.tomcat.websocket.WsFrameBase.processInputBuffer(WsFrameBase.java:133)
at org.apache.tomcat.websocket.WsFrameClient.processSocketRead(WsFrameClient.java:95)
at org.apache.tomcat.websocket.WsFrameClient.resumeProcessing(WsFrameClient.java:209)
at org.apache.tomcat.websocket.WsFrameClient.access$300(WsFrameClient.java:31)
at org.apache.tomcat.websocket.WsFrameClient$WsFrameClientCompletionHandler.doResumeProcessing(WsFrameClient.java:186)
at org.apache.tomcat.websocket.WsFrameClient$WsFrameClientCompletionHandler.completed(WsFrameClient.java:163)
at org.apache.tomcat.websocket.WsFrameClient$WsFrameClientCompletionHandler.completed(WsFrameClient.java:148)
at sun.nio.ch.Invoker.invokeUnchecked(Unknown Source)
at sun.nio.ch.Invoker$2.run(Unknown Source)
at sun.nio.ch.AsynchronousChannelGroupImpl$1.run(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
at java.lang.Thread.run(Unknown Source)
I tried serializing the data into String sending it through the socket like text, receiving String and deserializing it on the client side of the app. The Exception persisted.
Xml decoder and encoder, they both work properly, but just in case I am wrong I'll put it here.
public class Util
{
public static String getXmlFromObject(Object o)
{
ByteArrayOutputStream baos = new ByteArrayOutputStream();
XMLEncoder xmlEncoder = new XMLEncoder(baos);
xmlEncoder.writeObject(o);
xmlEncoder.close();
return new String(baos.toByteArray()).replace("\n", "")+"\n";
}
public static Object getObjectFromXml(String xml)
{
ByteArrayInputStream bais = new ByteArrayInputStream(xml.getBytes());
XMLDecoder xmlDecoder = new XMLDecoder(bais);
Object o = xmlDecoder.readObject();
xmlDecoder.close();
return o;
}
}
WebSocket on the server side:
#ServerEndpoint(value="/chat", encoders= {WebEncoder.class}, decoders= {WebDecoder.class})
public class ChatWebSocket
{
List<Session> sessions = new ArrayList<Session>();
#OnOpen
public void open(Session session)
{
sessions.add(session);
}
#OnClose
public void close(Session session)
{
sessions.remove(session);
}
#OnError
public void OnError(Session session, Throwable t)
{
System.out.println(session);
sessions.remove(session);
t.printStackTrace();
}
#OnMessage
public void handleMessage(Object message, Session session)
{
for (Session s : sessions)
{
System.out.println(s);
try
{
s.getBasicRemote().sendObject(message);
} catch (IOException | EncodeException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
WebSocket for the client side and a code snippet sending the message and for receiving it on the client side:
#ClientEndpoint(encoders= {WebEncoder.class}, decoders= {WebDecoder.class})
public class ChatWebSocketClient
{
Session session = null;
private MessageHandler messageHandler;
public ChatWebSocketClient(URI endpointURI)
{
try
{
WebSocketContainer container = ContainerProvider.getWebSocketContainer();
container.connectToServer(this, endpointURI);
} catch (Exception e)
{
e.printStackTrace();
}
}
#OnOpen
public void open(Session session)
{
this.session = session;
}
#OnClose
public void close(Session sesion, CloseReason reason)
{
this.session = null;
}
#OnError
public void onError(Session session, Throwable t)
{
t.printStackTrace();
}
#OnMessage
public void OnMessage(Object message)
{
if (this.messageHandler != null)
{
this.messageHandler.handleMessage(message);
}
}
public void addMessageHandler(MessageHandler msgHandler)
{
messageHandler = msgHandler;
}
public void sendMessage(Object message)
{
try
{
session.getBasicRemote().sendObject(message);
} catch (IOException | EncodeException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
final ChatWebSocketClient webSocket = new ChatWebSocketClient(new URI("ws://localhost:8080/XOX/chat"));
webSocket.addMessageHandler(new MessageHandler(){
#Override
public void handleMessage(Object message)
{
System.out.println("jsp "+message.getClass().getName());
System.out.println("jsp "+Util.getXmlFromObject(message));
}
});
webSocket.sendMessage(player);
I have these 4 methods which each close a different connection type, meaning each of those has a different input object. Each method calls the close() method on the provided input object. Is there a way to combine those methods into one, taking in a generic object? I have no way to implement an interface on the provided objects or extend them.
import java.sql.Statement;
import javax.jms.Connection;
import javax.mail.Transport;
private void close(Statement stm) {
if(stm == null) {
return;
}
try {
stm.close();
} catch (SQLException ex) {
logger.error("Error while closing statement", ex);
}
}
private void close(java.sql.Connection con) {
if(con == null) {
return;
}
try {
con.close();
} catch (SQLException ex) {
logger.error("Error while closing connection", ex);
}
}
private void close(javax.jms.Connection con) {
if(con == null) {
return;
}
try {
con.close();
} catch(JMSException ex) {
logger.error("Error while closing JMS connection", ex);
}
}
private void close(Transport transport) {
if(transport == null) {
return;
}
try {
transport.close();
} catch (MessagingException ex) {
logger.error("Error while closing mail transport", ex);
}
}
EDIT:
Thank you for your answers regarding Java 1.7. Unfortunately our servers are running Java 1.6, so is there any solution for that?
You can use reflection.
First sample give you support for try() with resources:
#Test
public void testRes() throws Exception {
try(ClosableWrapper<StringWriter> rs = new ClosableWrapper<>(new StringWriter())){
Writer wr = rs.getResource();
}
}
static class ClosableWrapper<T> implements AutoCloseable{
private T resource;
private String closeMethod = "close";
public ClosableWrapper(T resource) {
this.resource = resource;
}
public ClosableWrapper(T resource, String closeMethod) {
this.resource = resource;
this.closeMethod = closeMethod;
}
public T getResource() {
return resource;
}
#Override
public void close() throws Exception {
if(resource!=null){
Method m = resource.getClass().getMethod(closeMethod);
m.invoke(resource);
}
}
}
or just one method:
public void close(Object resource) throws Exception {
if(resource!=null){
Method m = resource.getClass().getMethod("close");
m.invoke(resource);
}
}
Assuming these are your classes, use the AutoCloseable interface and put them in a try-with-resource.
I am experiencing a problem where client does not start in non-debug mode in eclipse. Message do appear in debug mode.
Please let me know if any one else also facing same issue.
Calling method:
client = ClientManager.createClient();
ClientEndpointConfig cec = ClientEndpointConfig.Builder.create().build();
client.getProperties().put(ClientProperties.PROXY_URI, "http://192.168.1.1:80");
session = client.connectToServer(new ClientEndpoint(), cec, URI.create(url));
Below is the code of ClientEndpoint class:
private static class ClientEndpoint extends Endpoint {
#Override
public void onOpen(final Session session, EndpointConfig config) {
System.out.println("ClientEndpoint: server session opened: "+session);
session.addMessageHandler(new MessageHandler.Whole<String>() {
#Override
public void onMessage(String message) {
System.out.println("ClientEndpoint: received message: "+message);
if(lastmessage != message)
{
lastmessage = message;
session.getUserProperties().put("Message", lastmessage);
}
else
{
enter code here
session.getUserProperties().put("Message", lastmessage);
}
}
});
}
#Override
public void onClose(Session session, CloseReason closeReason) {
try {
latch.countDown();
session.close();
safeDisconnect(session);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
#Override
public void onError(Session session, Throwable th)
{
try {
session.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
th.printStackTrace();
}
}
Any thoughts? Please do let me know the configuration.
I have a simple EJB , and when i run it through my standalone client every thing is working well,
But once i add an interceptor, The #PostConstruct in the EJB stops working:
package interceptor;
public class LogInterceptor {
#PostConstruct
public void init(InvocationContext context) {
System.out.println(new Date().toString() +" Entered interceptor");
}
#PreDestroy
public void aboutToBeRemoved(InvocationContext context) {
System.out.println(new Date().toString() + " Leaving interceptor");
}
#AroundInvoke
public Object gettingToBusiness(InvocationContext context) {
String methodName = context.getMethod().getName();
System.out.println("The method name is: " +methodName);
if (methodName.equals("add")) {
}
try {
return context.proceed();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
My test client:
public class Test {
public static void main(String[] args){
InitialContext ctx=getInitialContext();
ListRemote stub=null;
try {
stub = (ListRemote)ctx.lookup("ejb:/Lab12/ListEJB!interceptor.ListRemote?stateful");
} catch (NamingException e) {
System.out.println("Lookup Failed");
e.printStackTrace();
}
System.out.println("Adding data");
stub.add("Hello");
stub.add("-");
stub.add("World");
stub.add("!!!");
System.out.println("Getting data :");
for(Object o:stub.getAll()){
System.out.print(o+" ");
}
System.out.println("Removing '-' element");
stub.remove(1);
System.out.println("Getting data again:");
for(Object o:stub.getAll()){
System.out.print(o+" ");
}
stub.destroy();
}
public static InitialContext getInitialContext(){
Properties properties = new Properties();
properties.put(Context.URL_PKG_PREFIXES , "org.jboss.ejb.client.naming");
try {
return new InitialContext(properties);
} catch (NamingException e) {
System.out.println("Cannot generate InitialContext");
e.printStackTrace();
}
return null;
}
}
My EJB:
#Stateful(name="ListEJB")
#Interceptors({LogInterceptor.class})
public class ListBean implements ListRemote{
private ArrayList<Serializable> list;
#PostConstruct
public void init(){
System.out.println("In it init ---------------------------------------------------");
list=new ArrayList<Serializable>();
}
public void add(Serializable object){
System.out.println("Currently in the list is: " +list);
System.out.println("The object is: " +object);
list.add(object);
System.out.println("Added");
}
public Serializable get(int index){
return list.get(index);
}
public void remove(int index){
list.remove(index);
}
public Object[] getAll(){
return list.toArray();
}
#Remove
public void destroy(){
list=null;
}
}
Why does it disables my EJB #PostConstruct ?
In this code:
#PostConstruct
public void init(InvocationContext context) {
System.out.println(new Date().toString() +" Entered interceptor");
}
You are intercepting the PostConstruct of the original EJB and not letting it pass. If you want to pass it through to the target EJB, you need to call proceed:
#PostConstruct
public void init(InvocationContext context) {
System.out.println(new Date().toString() +" Entered interceptor");
context.proceed();
}
Same applies for your PreDestroy. Basically it applies to all intercepted methods. See the EJB3 specification, section 12.5 (page 308):
Interceptor methods must always call InvocationContext.proceed() or no
subsequent interceptor methods or bean business method or lifecycle
callback methods will be invoked.
import java.util.concurrent.CountDownLatch;
import quickfix.Initiator;
public class UserSession {
private final CountDownLatch latch = new CountDownLatch(1);
public String await() {
try {
System.out.println("waiting...");
if (latch.await(5, TimeUnit.SECONDS))
System.out.println("released!");
else
System.out.println("timed out");
return secret;
} catch (InterruptedException e) {
// TODO Auto-generated catch block
System.out.println(e.getMessage());
e.printStackTrace();
}
return null;
}
public void countdown(String s) {
System.out.println("In countdown: "+s+ ". Latch count: "+latch.getCount());
secret = s;
latch.countDown();
System.out.println("Latch count: "+latch.getCount());
}
}
public class LogonHandler extends AbstractHandler {
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException
{
Map<String,String[]> query = request.getParameterMap();
if (query.containsKey("method")) {
if (query.get("method")[0].compareTo(method) == 0) {
baseRequest.setHandled(true);
response.getWriter().println(logon(query));
}
}
else
baseRequest.setHandled(false);
}
private String logon(Map<String,String[]> query) {
if (query.containsKey("username") && query.containsKey("password") && query.containsKey("sendercompid")) {
app.mapUser(query.get("sendercompid")[0], new UserSession(query.get("username")[0], query.get("password")[0]));
SessionID session = new SessionID(new BeginString("FIX.4.4"), new SenderCompID(query.get("sendercompid")[0]), new TargetCompID("PARFX"));
try {
ThreadedSocketInitiator tsi = new ThreadedSocketInitiator(app, app.getFileStoreFactory(), settings, app.getLogFactory(), app.getMessageFactory());
UserSession userSession = new UserSession(query.get("username")[0], query.get("password")[0]);
userSession.setInitiator(tsi);
tsi.start();
return userSession.await();
} catch (ConfigError e) {
// TODO Auto-generated catch block
e.printStackTrace();
return e.toString();
}
}
return "fail";
}
}
public class QuickfixjApplication implements Application {
private Map<String,UserSession> users = new HashMap<String,UserSession>();
public void mapUser(String s, UserSession u) {
users.put(s, u);
}
public void toAdmin(Message message, SessionID sessionId) {
try {
if (message.getHeader().getField(new StringField(MsgType.FIELD)).valueEquals(Logon.MSGTYPE)) {
UserSession user = users.get(sessionId.getSenderCompID());
message.setField(new Username(user.getUsername()));
message.setField(new Password(user.getPassword()));
}
} catch (FieldNotFound e) {
e.printStackTrace();
}
}
public void fromAdmin(Message message, SessionID sessionId)
throws FieldNotFound, IncorrectDataFormat, IncorrectTagValue, RejectLogon {
if (message.getHeader().getField(new StringField(MsgType.FIELD)).valueEquals(Logon.MSGTYPE)) {
System.out.println(message.toString());
UserSession user = users.get(sessionId.getSenderCompID());
user.countdown(message.toString());
}
}
}
Ok, I've tried to only include the minimum amount of code here. There are three interesting classes, UserSession is the internal glue between the Jetty handler and the QuickFix/j application.
The LogonHandler receives an HTTP logon request and tries to log a user onto a QuickFix/j application session.
QuickFix/j is sending a logon message to a FIX server, this logon request / response is asynchronous. The HTTP logon request is of course synchronous. So we have to wait for the reply from the FIX server before we return from the HTTP request. I do this using CountDownLatch and this UserSession object.
When I create the QuickFix/j session object I also create a UserSession object and add it to a map (that happens in the LogonHandler logon method).
There are two callbacks in the QuickFix/j application object, toAdmin() and fromAdmin(). In fromAdmin() I check if the message is a logon response and if it is I call a method of UserSession to countdown the latch. In debugging the code I see that the fromAdmin() method is hit, the UserSession object is found in the map and the countdown() method is called and the latch.getCount() goes from 1 to 0, but the latch.await() method in UserSession await() never returns. It always times out.
You could use CountDownLatch like this:
public class LogonHandler implements Handler {
private final CountDownLatch loginLatch = new CountDownLatch (1);
private boolean callbackResults;
public void serverResponseCallback(boolean result) {
callbackResults = result;
loginLatch.countDown ();
}
public boolean tryLogon(Credentials creds) throws InterruptedException {
SomeServer server = new SomeServer(address);
server.tryLogon (creds.getName (), creds.getPass ());
loginLatch.await ();
return callbackResults;
}
}
If you want to limit waiting time by, for example, 5 seconds, then instead of loginLatch.await () use the following:
if (loginLatch.await (5L, TimeUnit.SECONDS))
return callbackResults;
else
return false; // Timeout exceeded