Why does Glassfish shows this facelets error:
javax.el.ELException: /foo/client.xhtml #11,74 value="#{messageBean.messages}": javax.mail.MessagingException: Socket closed;
nested exception is:
java.net.SocketException: Socket closed
Which I attribute to hitting leafnode on localhost too frequently and too rapidly. Glassfish logs below show successful message retrievals from leafnode, but multiple calls to SingletonNNTP.loadMessages().
How can deal with sockets correctly? Sometimes Leafnode gives desired output, sometimes not.
INFO: Initializing Mojarra 2.1.6 (SNAPSHOT 20111206) for context '/NNTPjsf'
INFO: WEB0671: Loading application [NNTPjsf] at [/NNTPjsf]
INFO: NNTPjsf was successfully deployed in 2,574 milliseconds.
INFO: MessageBean..
INFO: MessageBean..
INFO: MessageBean.getMessages..
INFO: MessageBean.getNNTP..
INFO: MAKING SINGLETON..
INFO: NNTP.loadMessages...
INFO: NNTP.loadMessages...
nntp: <200 Leafnode NNTP Daemon, version 1.11.8 running at localhost (my fqdn: dur.bounceme.net)
nntp: >GROUP comp.lang.java.help
nntp: <211 82 3 84 comp.lang.java.help group selected
nntp: >GROUP comp.lang.java.help
nntp: <211 82 3 84 comp.lang.java.help group selected
nntp: >XHDR Message-ID 3-84
nntp: <221 Message-ID header (from overview) for postings 3-84:
nntp: <3 <afp6m75oi6nli4b6q87s317lkc13g689c2#4ax.com>
nntp: <4 <ed7f31e9-8a19-46c7-9a7c-ad8aabfb9599#x10g2000pbi.googlegroups.com>
nntp: <5 <uA4ar.13560$fj7.13111#newsfe20.iad>
The backing bean as so:
package net.bounceme.dur.nntp;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.enterprise.context.SessionScoped;
import javax.faces.model.DataModel;
import javax.faces.model.ListDataModel;
import javax.inject.Named;
import javax.mail.Message;
#Named
#SessionScoped
public class MessageBean implements Serializable {
private static final long serialVersionUID = 1L;
private static final Logger logger = Logger.getLogger(MessageBean.class.getName());
private static Level level = Level.INFO;
private DataModel dm = null;
public MessageBean() {
logger.log(level, "MessageBean..");
}
public List<Message> getMessages() throws Exception {
logger.log(level, "MessageBean.getMessages..");
List<Message> messages = getNNTP();
return messages;
}
public DataModel getModel() throws Exception {
logger.log(level, "MessageBean.getModel..");
List<Message> messages = getNNTP();
dm = new ListDataModel(messages);
return dm;
}
private synchronized List<Message> getNNTP() throws Exception {
logger.log(level, "MessageBean.getNNTP..");
List<Message> messages = new ArrayList<Message>();
SingletonNNTP nntp = SingletonNNTP.INSTANCE;
messages = nntp.getMessages(false);
logger.log(level, "MessageBean.getNNTP nntp.size: {0}", messages.size());
return messages;
}
}
the Singleton:
package net.bounceme.dur.nntp;
import static java.lang.System.out;
import java.util.*;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.mail.*;
public enum SingletonNNTP {
INSTANCE;
private final Logger logger = Logger.getLogger(SingletonNNTP.class.getName());
private final Level level = Level.INFO;
private Properties props = new Properties();
private List<Message> messages = new ArrayList<Message>();
private SingletonNNTP() {
out.println("MAKING SINGLETON..");
props = PropertiesReader.getProps();
boolean loaded = false;
try {
loaded = setMessages(false);
} catch (Exception ex) {
Logger.getLogger(SingletonNNTP.class.getName()).log(Level.SEVERE, "FAILED TO LOAD MESSAGES", ex);
}
}
public List<Message> getMessages(boolean debug) throws Exception {
logger.log(level, "NNTP.getMessages...");
logMessages();
return Collections.unmodifiableList(messages);
}
private boolean setMessages(boolean debug) throws Exception {
logger.log(level, "NNTP.loadMessages...");
Session session = Session.getDefaultInstance(props);
session.setDebug(debug);
Store store = session.getStore(new URLName(props.getProperty("nntp.host")));
store.connect();
Folder root = store.getDefaultFolder();
Folder folder = root.getFolder(props.getProperty("nntp.group"));
folder.open(Folder.READ_ONLY);
Message[] msgs = folder.getMessages();
messages = Arrays.asList(msgs);
folder.close(false);
store.close();
if (debug) {
}
return true;
}
private void logMessages() throws Exception {
logger.log(level, "NNTP.logMessages..");
for (Message m : messages) {
logger.log(level, String.valueOf(m.getMessageNumber()));
logger.log(level, m.getSubject());
logger.log(level, m.getContent().toString());
}
}
private void persistMessages() throws Exception {
//entities.Messages
}
}
That message means that you closed the socket and then tried to read from or write to it. You are trying to read Message content after you have closed the connection. You need to save not the Messages themselves but their content, while the connection is open.
Related
I have a MailDev instance installed on a remote Server.
I'm trying to understand if is it possibile to send email with Java (using the standard JavaMailSender) using this fake SMTP server.
The config needs only the URL and the port but, in my case, it doesn't work.
It returns always:
Mail server connection failed; nested exception is com.sun.mail.util.MailConnectException: Couldn't connect to host ...
The WebUI is running correctly and I can see the empty inbox on server.
Thanks.
It seems like you are experience connections issues. Although I cannot tell you what the cause there is, perhaps I can offer an alternative solution to test your emails?
Using Wiser, you can run an embedded SMTP server and query that inside your junit test. I've used this a lot in my open source project Simple Java Mail and created a Rule for this:
package testutil.testrules;
import org.jetbrains.annotations.NotNull;
import org.junit.rules.ExternalResource;
import org.subethamail.smtp.server.SMTPServer;
import org.subethamail.wiser.Wiser;
import org.subethamail.wiser.WiserMessage;
import javax.mail.MessagingException;
import javax.mail.internet.MimeMessage;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintStream;
import java.util.Iterator;
import java.util.List;
/**
* SmtpServerRule - a TestRule wrapping a Wiser instance (a SMTP server in Java), started and stopped right before and after each test.
* <br>
* SmtpServerRule exposes the same methods as the {#link Wiser} instance by delegating the implementation to the instance. These methods, however, can not be
* used outside a JUnit statement (otherwise an {#link IllegalStateException} is raised).
* <br>
* The {#link Wiser} instance can be directly retrieved but also only from inside a JUnit statement.
*/
public class SmtpServerRule extends ExternalResource {
private final Wiser wiser = new Wiser();
private final int port;
public SmtpServerRule(#NotNull Integer port) {
this.port = port;
}
#Override
protected void before() {
this.wiser.setPort(port);
this.wiser.start();
}
#Override
protected void after() {
this.wiser.stop();
}
#NotNull
public Wiser getWiser() {
checkState("getWiser()");
return this.wiser;
}
#NotNull
public List<WiserMessage> getMessages() {
checkState("getMessages()");
return wiser.getMessages();
}
#NotNull
public MimeMessage getOnlyMessage(String envelopeReceiver)
throws MessagingException {
checkState("getMessages()");
List<WiserMessage> messages = getMessages();
assertThat(messages).hasSize(1);
Iterator<WiserMessage> iterator = messages.iterator();
WiserMessage wiserMessage = iterator.next();
assertThat(wiserMessage.getEnvelopeReceiver()).isEqualTo(envelopeReceiver);
MimeMessage mimeMessage = wiserMessage.getMimeMessage();
iterator.remove();
return mimeMessage;
}
#NotNull
public MimeMessageAndEnvelope getOnlyMessage()
throws MessagingException {
checkState("getMessages()");
List<WiserMessage> messages = getMessages();
assertThat(messages).hasSize(1);
Iterator<WiserMessage> iterator = messages.iterator();
WiserMessage wiserMessage = iterator.next();
iterator.remove();
return new MimeMessageAndEnvelope(wiserMessage.getMimeMessage(), wiserMessage.getEnvelopeSender());
}
#NotNull
public MimeMessage getMessage(String envelopeReceiver)
throws MessagingException {
checkState("getMessages()");
List<WiserMessage> messages = getMessages();
Iterator<WiserMessage> iterator = messages.iterator();
while (iterator.hasNext()) {
WiserMessage wiserMessage = iterator.next();
if (wiserMessage.getEnvelopeReceiver().equals(envelopeReceiver)) {
MimeMessage mimeMessage = wiserMessage.getMimeMessage();
iterator.remove();
return mimeMessage;
}
}
throw new AssertionError("message not found for recipient " + envelopeReceiver);
}
#NotNull
public SMTPServer getServer() {
checkState("getServer()");
return wiser.getServer();
}
public boolean accept(String from, String recipient) {
checkState("accept(String, String)");
return wiser.accept(from, recipient);
}
public void deliver(String from, String recipient, InputStream data)
throws IOException {
checkState("deliver(String, String, InputStream)");
wiser.deliver(from, recipient, data);
}
public void dumpMessages(PrintStream out)
throws MessagingException {
checkState("dumpMessages(PrintStream)");
wiser.dumpMessages(out);
}
private void checkState(String method) {
if (this.wiser == null) {
throw new IllegalStateException(format("%s must not be called outside of a JUnit statement", method));
}
}
}
Then I use it like this:
public class MailerLiveTest {
private static final Integer SERVER_PORT = 251;
#Rule
public final SmtpServerRule smtpServerRule = new SmtpServerRule(SERVER_PORT);
#Before
public void setup() {
mailer = MailerBuilder.withSMTPServer("localhost", SERVER_PORT).buildMailer();
}
#Test
public void createMailSession_EmptySubjectAndBody() {
// send mail using mailer, which goes to localhost:251
MimeMessageAndEnvelope receivedMimeMessage = smtpServerRule.getOnlyMessage();
Email receivedEmail = EmailConverter.mimeMessageToEmail(receivedMimeMessage.getMimeMessage());
// perform assertions on Email object...
}
}
Check if mail.smtp.auth and mail.smtp.starttls.enable are set to false. In my case it worked (I also set localhost as host and 1025 as port).
I am using a Java code in Eclipse which is supposed to read JMS messages continuously from JMS queue on Jboss EAP 6.4. However, I am getting exception when I am running this program.
I tried to do some troubleshooting but I am stuck now
The code I am using is as below (Actual IP of Jboss is replaced with #. "remote://#.#.#.#:4447")
import java.util.Hashtable;
import javax.jms.Connection;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageListener;
import javax.jms.Queue;
import javax.jms.QueueConnection;
import javax.jms.QueueConnectionFactory;
import javax.jms.QueueReceiver;
import javax.jms.QueueSession;
import javax.jms.TextMessage;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import EDU.oswego.cs.dl.util.concurrent.CountDown;
public class GetMessageTriggerResponses
{
static CountDown done = new CountDown(10);
QueueConnection conn;
QueueSession session;
Queue recvq;
public static class ExListener implements MessageListener
{
public void onMessage(Message msg)
{
done.release();
TextMessage tm = (TextMessage) msg;
try {
System.out.println("Received message: \n" + tm.getText());
} catch (Throwable t) {
t.printStackTrace();
}
}
}
public void setup(String[] args) throws JMSException, NamingException, InterruptedException
{
Hashtable env = new Hashtable();
env.put(InitialContext.INITIAL_CONTEXT_FACTORY,"org.jboss.naming.remote.client.InitialContextFactory");
env.put(InitialContext.PROVIDER_URL, "remote://#.#.#.#:4447"); // DEV-ENV
Context context = new InitialContext(env);
QueueConnectionFactory connectionFactory = (QueueConnectionFactory) context
.lookup("jms/RemoteConnectionFactory");
Connection connection = connectionFactory.createConnection();
recvq = (Queue) context.lookup(args[0]);
System.out.println("listening on "+args[0]);
session = conn.createQueueSession(false, QueueSession.AUTO_ACKNOWLEDGE);
conn.start();
System.out.println("Begin recv message");
QueueReceiver receiver = session.createReceiver(recvq);
receiver.setMessageListener(new ExListener());
done.acquire();
}
public void stop()
throws JMSException
{
conn.stop();
session.close();
conn.close();
}
public static void main(String args[])
throws Exception
{
/*if (args.length < 1) {
System.err.println("Usage: java prog_name msg-trigger-qname");
return;
}*/
System.out.println("Begin GetMessageTriggerResponses");
GetMessageTriggerResponses client = new GetMessageTriggerResponses();
client.setup(args);
client.stop();
System.out.println("End GetMessageTriggerResponses");
System.exit(0);
}
}
I am getting the exception:
Begin GetMessageTriggerResponses
Feb 04, 2019 12:49:42 AM org.xnio.Xnio <clinit> INFO: XNIO Version 3.0.17.GA-redhat-1 Feb 04, 2019 12:49:42 AM org.xnio.nio.NioXnio <clinit> INFO: XNIO NIO Implementation Version 3.0.17.GA-redhat-1
Feb 04, 2019 12:49:42 AM org.jboss.remoting3.EndpointImpl <clinit> INFO: JBoss Remoting version 3.3.12.Final-redhat-2
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 0
at GetMessageTriggerResponses.setup(GetMessageTriggerResponses.java:56)
at GetMessageTriggerResponses.main(GetMessageTriggerResponses.java:88)
The problem is that you're passing in an empty array into the setup() method of GetMessageTriggerResponses and then attempting to use a value from that array. This is the problematic line:
recvq = (Queue) context.lookup(args[0]);
Either when you invoke setup() or access the array you should check to make sure it has the expected number of values. This is basic input validation. You actually have some code to validate the input in main(), but you've commented it out for some reason. I recommend you restore that code to avoid this ArrayIndexOutOfBoundsException.
I am writing this MDB which will listen message on IBM MQ queues and onMessage it will make call to ilrsession for running jrules. JCA adapter
and Activation config is configured on WAS console
While starting this MDB throws the following error. Is it the static block which is why its failing.
I am posting here if something can review the code and provide some suggestions.
Here is the exception I get while starting the MDB.
An operation in the enterprise bean constructor failed. It is recommended that component initialization logic be placed in a PostConstruct method instead of the bean class no-arg constructor.; nested exception is:
java.lang.NullPointerException
at com.ibm.ws.ejbcontainer.runtime.SharedEJBRuntimeImpl.startBean(SharedEJBRuntimeImpl.java:620)
at com.ibm.ws.runtime.component.WASEJBRuntimeImpl.startBean(WASEJBRuntimeImpl.java:586)
at com.ibm.ws.ejbcontainer.runtime.AbstractEJBRuntime.fireMetaDataCreatedAndStartBean(AbstractEJBRuntime.java:1715)
at com.ibm.ws.ejbcontainer.runtime.AbstractEJBRuntime.startModule(AbstractEJBRuntime.java:667)
... 52 more
Caused by: java.lang.NullPointerException
Here is the MDB Code.
package com.abc.integration.ejb
import ilog.rules.res.model.IlrPath;
import ilog.rules.res.session.IlrEJB3SessionFactory;
import ilog.rules.res.session.IlrSessionException;
import ilog.rules.res.session.IlrSessionRequest;
import ilog.rules.res.session.IlrSessionResponse;
import ilog.rules.res.session.IlrStatelessSession;
import java.net.URL;
import java.util.Date;
import java.util.List;
import java.util.Map;
import javax.ejb.ActivationConfigProperty;
import javax.ejb.MessageDriven;
import javax.jms.Connection;
import javax.jms.ConnectionFactory;
import javax.jms.Destination;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageListener;
import javax.jms.MessageProducer;
import javax.jms.ObjectMessage;
import javax.jms.Session;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import org.apache.log4j.Logger;
import org.apache.log4j.xml.DOMConfigurator;
/**
* Message-Driven Bean implementation class for: DecisionServiceMDB
*
*/
#MessageDriven(activationConfig = { #ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue") })
public class DecisionServiceMDB implements MessageListener
{
/**
* default serial version id
*/
private static final long serialVersionUID = 2300836924029589692L;
private static final Logger responseTimeLogger = Logger.getLogger(PropertyManager.getResponseTimeLogger());
private static final Logger errorLogger = Logger.getLogger(PropertyManager.getErrorLogger());
private static final Logger ruleExceptionLogger = Logger.getLogger(PropertyManager.getRuleExceptionLogger());
private static final String RULEAPP_NAME = PropertyManager.getRuleAppName();
private static final String RULESET_NAME = PropertyManager.getRuleSetName();
private static InitialContext ic;
private static ConnectionFactory cf;
private static Destination destination;
private static String qcfLookup = PropertyManager.getQueueFactoryJndiName();
private static String qLookup = PropertyManager.getQueueDestinationJndiName();
private Connection c = null;
private Session s = null;
private MessageProducer mp = null;
private boolean isInitializedOkay = true;
private static IlrEJB3SessionFactory factory;
private static IlrStatelessSession ruleSession;
private static IlrPath path;
private IlrSessionRequest sessionRequest;
static {
URL url = Thread.currentThread().getContextClassLoader().getResource("log4j.xml");
DOMConfigurator.configure(url);
errorLogger.info("log4j xml initialized::::::::::::::::");
}
public DecisionServiceMDB() throws NamingException, JMSException
{
try
{
if (ic == null)
{
ic = new InitialContext();
}
if (cf == null)
{
cf = (ConnectionFactory) ic.lookup(qcfLookup);
}
if (destination == null)
{
destination = (Destination) ic.lookup(qLookup);
}
} catch (NamingException e)
{
isInitializedOkay = false;
errorLogger.error("FATAL:NamingException Occurred: " + e.getMessage());
errorLogger.error(e.getMessage(), e);
e.printStackTrace();
//throw e;
}
// 1. Get a POJO Session Factory
if (factory == null)
{
//factory = new IlrJ2SESessionFactory();
//to log rule execution start time by using bre logger
//transactionLogger.setRuleExecutionStartTime(new Date());
factory = new IlrEJB3SessionFactory();
// As the EJBS are embedded within the ear file, we need to prepend
// the ear file name to the JNDI.
factory.setStatelessLocalJndiName("ejblocal:ilog.rules.res.session.ejb3.IlrStatelessSessionLocal");
}
// 2. Create a stateless rule session using this factory
try
{
if (ruleSession == null)
{
ruleSession = factory.createStatelessSession();
}
} catch (Exception e)
{
e.printStackTrace();
return;
}
// 3. Create a session request to invoke the RES (defining the ruleset
// path and the input ruleset parameters)
if (path == null)
{
path = new IlrPath(RULEAPP_NAME, RULESET_NAME);
}
sessionRequest = factory.createRequest();
sessionRequest.setRulesetPath(path);
}
public void onMessage(Message receivedMsg)
{
// onMessage code goes here.
}
}
You are violating programming restrictions (see EJB spec 16.2.2):
An enterprise bean must not use read/write static fields. Using read-only static fields is allowed. Therefore, it is recommended that all static fields in the enterprise bean class be declared as final.
Remove your (non-final) static fields, your static initializer and the constructor. Intialisation is done within the postConstruct lifecycle callback method.
Your EJB could look like this:
#MessageDriven(activationConfig = { #ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue") })
public class DecisionServiceMDB implements MessageListener
{
private Logger responseTimeLogger;
private Logger errorLogger;
private Logger ruleExceptionLogger;
private String RULEAPP_NAME;
private String RULESET_NAME;
private InitialContext ic;
private ConnectionFactory cf;
private Destination destination;
private String qcfLookup;
private String qLookup;
private Connection c;
private Session s;
private MessageProducer mp;
private boolean isInitializedOkay = true;
private IlrEJB3SessionFactory factory;
private IlrStatelessSession ruleSession;
private IlrPath path;
private IlrSessionRequest sessionRequest;
#PostConstruct
public void init() {
responseTimeLogger = Logger.getLogger(PropertyManager.getResponseTimeLogger());
errorLogger = Logger.getLogger(PropertyManager.getErrorLogger());
ruleExceptionLogger = Logger.getLogger(PropertyManager.getRuleExceptionLogger());
RULEAPP_NAME = PropertyManager.getRuleAppName();
RULESET_NAME = PropertyManager.getRuleSetName();
qcfLookup = PropertyManager.getQueueFactoryJndiName();
qLookup = PropertyManager.getQueueDestinationJndiName();
ic = new InitialContext();
cf = (ConnectionFactory) ic.lookup(qcfLookup);
destination = (Destination) ic.lookup(qLookup);
factory = new IlrEJB3SessionFactory();
factory.setStatelessLocalJndiName("ejblocal:ilog.rules.res.session.ejb3.IlrStatelessSessionLocal");
ruleSession = factory.createStatelessSession();
sessionRequest.setRulesetPath(path);
}
public void onMessage(Message receivedMsg)
{
// onMessage code goes here.
}
}
I removed the static initializer. Looks like you try to configure logging, which should not be done within your EJB. Refer to the documentation of your application server how to do this properly.
This is just some example code based on the original code.
The implementation you provided looks like a plain java implementation. Be aware of requirements in an enterprise environment (e.g. EJB lifecycle, EJB providers responsibility, ...). Read the EJB spec and some JEE tutorials before proceeding.
With this in mind, you should take a look at your PropertyManager afterwards. This might not be implemented in a suitable manner.
I try to run a websocket server in a Java project that was running on Tomcat6. I have set up a Tomcat 7 server where the project now is running on.
First I tried to run the socket example of Tomcat7. This run perfectly. I copied this class to my old project. When I run the old project again all the functionalities are working like before but only the websocket server doe not work.
This is the ChatAnnotation class that I have copied from the examples from Tomcat to my old project.
import java.io.IOException;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.concurrent.atomic.AtomicInteger;
import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;
import org.apache.log4j.Logger;
#ServerEndpoint(value = "/websocket/chat")
public class ChatAnnotation {
private static Logger logger = Logger.getLogger(ChatAnnotation.class);
private static final String GUEST_PREFIX = "Guest";
private static final AtomicInteger connectionIds = new AtomicInteger(0);
private static final Set<ChatAnnotation> connections = new CopyOnWriteArraySet<ChatAnnotation>();
private final String nickname;
private Session session;
public ChatAnnotation() {
nickname = GUEST_PREFIX + connectionIds.getAndIncrement();
logger.info("ws instance");
}
#OnOpen
public void start(Session session) {
this.session = session;
connections.add(this);
String message = String.format("* %s %s", nickname, "has joined.");
broadcast(message);
}
#OnClose
public void end() {
connections.remove(this);
String message = String.format("* %s %s", nickname, "has disconnected.");
broadcast(message);
}
#OnMessage
public void incoming(String message) {
// Never trust the client
String filteredMessage = String.format("%s: %s", nickname, message.toString());
broadcast(filteredMessage);
}
#OnError
public void onError(Throwable t) throws Throwable {
logger.error("Chat Error: " + t.toString(), t);
}
private static void broadcast(String msg) {
for (ChatAnnotation client : connections) {
try {
synchronized (client) {
client.session.getBasicRemote().sendText(msg);
}
} catch (IOException e) {
logger.debug("Chat Error: Failed to send message to client", e);
connections.remove(client);
try {
client.session.close();
} catch (IOException e1) {
// Ignore
}
String message = String.format("* %s %s", client.nickname, "has been disconnected.");
broadcast(message);
}
}
}
}
I have noting added in my web.xml. In my old project are also tcpsockets used can this be the problem?
Can anyone help me with this problem?
EDIT
Class added:
import java.util.HashSet;
import java.util.Set;
import javax.websocket.Endpoint;
import javax.websocket.server.ServerApplicationConfig;
import javax.websocket.server.ServerEndpointConfig;
import org.apache.log4j.Logger;
public class ExamplesConfig implements ServerApplicationConfig {
private static Logger log = Logger.getLogger(ChatAnnotation.class);
public Set<ServerEndpointConfig> getEndpointConfigs(Set<Class<? extends Endpoint>> endpointClasses) {
Set<ServerEndpointConfig> result = new HashSet<ServerEndpointConfig>();
log.info("getEndpointConfigs");
return result;
}
public Set<Class<?>> getAnnotatedEndpointClasses(Set<Class<?>> scanned) {
log.info("getAnnotatedEndpointClasses");
return scanned;
}
}
Java websocket server use return value of ServerApplicationConfig interface to deploy programmatic endpoints and for annotated endpoints.
For Tomcat example, if you change the package name of ChatAnnotation. You have to modify websocket.ExamplesConfig too.
public Set<Class<?>> getAnnotatedEndpointClasses(Set<Class<?>> scanned) {
// Deploy all WebSocket endpoints defined by annotations in the examples
// web application. Filter out all others to avoid issues when running
// tests on Gump
Set<Class<?>> results = new HashSet<>();
for (Class<?> clazz : scanned) {
String name = clazz.getPackage().getName();
boolean ok = name.startsWith("websocket.");
if (ok) {
results.add(clazz);
}
}
return scanned;
}
The getAnnotatedEndpointClasses(scanned) only return classes which package name start with websocket. Unmatched classes will not deployed even they have #ServerEndpoint declarations.
Unfortunately, I don't understand this output from the netty server:
BUILD SUCCESSFUL
Total time: 3 seconds
Jul 27, 2014 2:04:44 AM io.netty.handler.logging.LoggingHandler channelRegistered
INFO: [id: 0xcad25a31] REGISTERED
Jul 27, 2014 2:04:44 AM io.netty.handler.logging.LoggingHandler bind
INFO: [id: 0xcad25a31] BIND(0.0.0.0/0.0.0.0:4454)
Jul 27, 2014 2:04:44 AM io.netty.handler.logging.LoggingHandler channelActive
INFO: [id: 0xcad25a31, /0:0:0:0:0:0:0:0:4454] ACTIVE
Jul 27, 2014 2:04:59 AM io.netty.handler.logging.LoggingHandler logMessage
INFO: [id: 0xcad25a31, /0:0:0:0:0:0:0:0:4454] RECEIVED: [id: 0xff40b8a2, /127.0.0.1:37558 => /127.0.0.1:4454]
Jul 27, 2014 2:04:59 AM net.bounceme.dur.netty.ServerHandler <init>
INFO: starting..
Jul 27, 2014 2:04:59 AM io.netty.channel.DefaultChannelPipeline$TailContext exceptionCaught
WARNING: An exceptionCaught() event was fired, and it reached at the tail of the pipeline. It usually means the last handler in the pipeline did not handle the exception.
io.netty.handler.codec.TooLongFrameException: Adjusted frame length exceeds 1048576: 2901213193 - discarded
at io.netty.handler.codec.LengthFieldBasedFrameDecoder.fail(LengthFieldBasedFrameDecoder.java:501)
at io.netty.handler.codec.LengthFieldBasedFrameDecoder.failIfNecessary(LengthFieldBasedFrameDecoder.java:477)
at io.netty.handler.codec.LengthFieldBasedFrameDecoder.decode(LengthFieldBasedFrameDecoder.java:403)
at io.netty.handler.codec.serialization.ObjectDecoder.decode(ObjectDecoder.java:68)
at io.netty.handler.codec.LengthFieldBasedFrameDecoder.decode(LengthFieldBasedFrameDecoder.java:343)
at io.netty.handler.codec.ByteToMessageDecoder.callDecode(ByteToMessageDecoder.java:241)
at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:149)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:333)
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:319)
at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:787)
at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:125)
at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:511)
at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:468)
at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:382)
at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:354)
at io.netty.util.concurrent.SingleThreadEventExecutor$2.run(SingleThreadEventExecutor.java:116)
at io.netty.util.concurrent.DefaultThreadFactory$DefaultRunnableDecorator.run(DefaultThreadFactory.java:137)
at java.lang.Thread.run(Thread.java:744)
^Cthufir#dur:~/NetBeansProjects/AgentServer$
thufir#dur:~/NetBeansProjects/AgentServer$
Presumably the netty-based server is complaining that it's receiving bad data in some respect?
client code:
package net.bounceme.dur.client.gui;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.Socket;
import java.util.logging.FileHandler;
import java.util.logging.Handler;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.logging.SimpleFormatter;
import net.bounceme.dur.client.jdbc.Title;
public final class ApplicationDriver {
private static final Logger log = Logger.getLogger(ApplicationDriver.class.getName());
private TitlesGUI gui = null;
private Handler handler = null;
public ApplicationDriver() throws IOException, ClassNotFoundException {
handler = new FileHandler("application.log");
handler.setFormatter(new SimpleFormatter());
log.setLevel(Level.INFO);
log.addHandler(handler);
log.info("starting log..");
MyProps p = new MyProps();
String host = p.getHost();
int port = p.getServerPort();
guiThread();
readWrite(host, port);
}
private void guiThread() {
Thread g;
g = new Thread() {
#Override
public void run() {
try {
gui = new TitlesGUI();
} catch (IOException ex) {
log.severe(ex.toString());
}
gui.setVisible(true);
}
};
g.start();
}
public static void main(String... args) throws IOException, ClassNotFoundException {
new ApplicationDriver();
}
private void readWrite(final String host, final int port) throws IOException {
Thread inputOutput;
final Socket socket = new Socket(host, port);
inputOutput = new Thread() {
#Override
public void run() {
while (true) {
try (ObjectOutputStream objectOutputStream = new ObjectOutputStream(socket.getOutputStream());
ObjectInputStream objectInputStream = new ObjectInputStream(socket.getInputStream())) {
gui.setTitle((Title) objectInputStream.readObject());
Thread.sleep(1000);
} catch (IOException | ClassNotFoundException | InterruptedException ex) {
log.severe(ex.toString());
}
}
}
};
inputOutput.start();
}
}
is it a problem that the client is using regular sockets instead of netty? Both on the client and server side POJO's are being sent. (The Title class is serializable and the serialVersionUID values match up.)
a method from the GUI client (which is a bit large, it's a Netbeans Swing JFrame):
public void setTitle(Title title) {
this.title = title;
text.setText(title.toString());
}
the point of the above method is for something to send objects to the GUI, which is then updated accordingly. Similarly, I want to fire updates, or other-wise wire the GUI to socket i/o.
I don't really understand the output from the netty server. Is it a problem that the server uses netty while the client uses sockets? Both use the same POJO, with the serialVersionUID value. Here's the netty handler code:
package net.bounceme.dur.netty;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import java.util.logging.Logger;
import net.bounceme.dur.jdbc.Title;
public class ServerHandler extends SimpleChannelInboundHandler<Title> {
private static final Logger log = Logger.getLogger(ServerHandler.class.getName());
public ServerHandler() {
log.info("starting..");
}
#Override
public boolean acceptInboundMessage(Object msg) throws Exception {
log.info(msg.toString());
return true;
}
#Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
log.info(msg.toString());
ctx.write(new Title());
}
#Override
protected void channelRead0(ChannelHandlerContext chc, Title title) throws Exception {
log.info(title.toString());
chc.write(new Title());
}
}
Apparently, none of the server handler code is executed, as everything explodes immediately after the client connects.
server code:
package net.bounceme.dur.netty;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.serialization.ClassResolvers;
import io.netty.handler.codec.serialization.ObjectDecoder;
import io.netty.handler.codec.serialization.ObjectEncoder;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import java.security.cert.CertificateException;
import java.util.logging.Logger;
import javax.net.ssl.SSLException;
public final class Server {
private static final Logger log = Logger.getLogger(Server.class.getName());
public static void main(String[] args) throws Exception {
MyProps p = new MyProps();
int port = p.getServerPort();
new Server().startServer(port, false);
}
private void startServer(int port, boolean ssl) throws CertificateException, SSLException, InterruptedException {
EventLoopGroup bossGroup = new NioEventLoopGroup(1);
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.handler(new LoggingHandler(LogLevel.INFO))
.childHandler(new ChannelInitializer<SocketChannel>() {
#Override
public void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline p = ch.pipeline();
p.addLast(
new ObjectEncoder(),
new ObjectDecoder(ClassResolvers.cacheDisabled(null)),
new ServerHandler());
}
});
b.bind(port).sync().channel().closeFuture().sync();
log.info("connected!");
} finally {
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
}
The TooLongFrameException raised by LengthFieldBasedFrameDecoder means one of the following:
The remote peer sent a very large message, which exceeds the limit. The default maximum length of a message is 1 MiB. If you expect to receive a message larger than that, specify an alternative maximum length when you construct a LengthFieldBasedFrameDecoder.
You passed wrong parameters to LengthFieldBasedFrameDecoder so that it is decoding a wrong place in your message. In this case, you'd better re-read the Javadoc of LengthFieldBasedFrameDecoder to specify the correct values for you.