WebSocketServlet in a WAR-file: Bad character 13 for SelectChannelEndPoint - servlets

On Mac with Oracle java "1.8.0_45" I have create a Jetty base dir with:
# java -jar /Users/afarber/jetty-distribution-9.3.10.v20160621/start.jar jetty.home=/Users/afarber/jetty-distribution-9.3.10.v20160621 jetty.base=/Users/afarber/jetty-base --add-to-startd=http,servlet,webapp,resources,ext,fcgi,websocket,proxy-protocol,deploy
INFO: ext initialised in ${jetty.base}/start.d/ext.ini
INFO: resources initialised in ${jetty.base}/start.d/resources.ini
INFO: server initialised (transitively) in ${jetty.base}/start.d/server.ini
INFO: http initialised in ${jetty.base}/start.d/http.ini
INFO: servlet initialised in ${jetty.base}/start.d/servlet.ini
INFO: fcgi initialised in ${jetty.base}/start.d/fcgi.ini
INFO: proxy-protocol initialised in ${jetty.base}/start.d/proxy-protocol.ini
INFO: webapp initialised in ${jetty.base}/start.d/webapp.ini
INFO: websocket initialised in ${jetty.base}/start.d/websocket.ini
MKDIR: ${jetty.base}/lib
MKDIR: ${jetty.base}/lib/ext
MKDIR: ${jetty.base}/resources
MKDIR: ${jetty.base}/webapps
INFO: Base directory was modified
Then I have put $JETTY_BASE/webapps/ws-servlet-0.1-SNAPSHOT.war produced by the very simple Maven project out of -
WsServlet.java
public class WsServlet extends WebSocketServlet
{
#Override
public void configure(WebSocketServletFactory factory) {
factory.register(EchoListener.class);
}
}
EchoListener.java
public class EchoListener implements WebSocketListener {
private static final Logger LOG = Log.getLogger(EchoListener.class);
private Session mSession;
#Override
public void onWebSocketConnect(Session session) {
LOG.info("onWebSocketConnect {}", session);
mSession = session;
}
#Override
public void onWebSocketText(String message) {
LOG.info("onWebSocketText {}", message);
if (mSession != null && mSession.isOpen()) {
mSession.getRemote().sendString("ECHO: " + message, null);
}
}
}
Finally I have created the $JETTY_BASE/webapps/ws.xml file pointing to the WAR-file:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN"
"http://www.eclipse.org/jetty/configure_9_0.dtd">
<Configure class="org.eclipse.jetty.webapp.WebAppContext">
<Set name="contextPath">/ws</Set>
<Set name="war"><SystemProperty name="jetty.base"/>/webapps/ws-servlet-0.1-SNAPSHOT.war</Set>
</Configure>
When I start Jetty and then connect to it using simple JavaScript code in browser var ws = new WebSocket("//127.0.0.1:8080/ws"); or the Simple Web Socket Client extension for Chrome the error comes:
# java -Dorg.eclipse.jetty.LEVEL=DEBUG -jar /Users/afarber/jetty-distribution-9.3.10.v20160621/start.jar jetty.base=/Users/afarber/jetty-base
....
WARN:oejs.ProxyConnectionFactory:qtp1993134103-12: Bad character 13 for SelectChannelEndPoint#26ba5622{/127.0.0.1:49883<->8080,Open,in,out,-,-,0/30000,ProxyConnection#49376d8e}{io=1/0,kio=1,kro=1}
Here is the full Jetty log, what have I missed here please?
UPDATE:
I have also tried connecting to ws://127.0.0.1:8080/ws-servlet-0.1-SNAPSHOT and tried adding annotations like #WebServlet(name = "WsServlet", urlPatterns = { "/ws" })- but that does not help. Also I have tried the older version 9.3.9.v20160517.
UPDATE 2:
Is the root cause the PROXY Protocol, which I have to use at my production server, because I offload SSL and normal connections to HAProxy? From the doc I read that 13 is sent as the first byte.
UPDATE 3:
The problem has been solved by adding a trailing slash: ws://127.0.0.1:8080/ws/

Related

spring boot - How to load context configuration file

I am trying to convert spring mvc app to spring boot. I used to deploy this application in tomcat and test. Now with spring boot I am trying to do the same thing but I am facing issues to load xml file configuration.
<?xml version="1.0" encoding="UTF-8"?>
<Context>
<!-- Data sources -->
<Environment name="/source/schema" value="${schema}" type="java.lang.String" />
<Resource auth="Container" driverClass="org.postgresql.Driver"
factory="org.apache.naming.factory.BeanFactory"
idleConnectionTestPeriod="30" jdbcUrl="${url}"
maxAdministrativeTaskTime="0" maxConnectionAge="30" maxIdleTime="9" maxPoolSize="3" minPoolSize="2"
name="/source/DataSource" password="${password}"
preferredTestQuery="select 1" testConnectionOnCheckout="true" type="com.mchange.v2.c3p0.ComboPooledDataSource" user="${user}"/>
</Context>
This is my configuration file which I am trying to load. When I put
#ImportResource({"classpath:applicationContext.xml", "classpath:context.xml"})
I am able to load all the bean configuration from applicationcontext.xml but while loading context.xml it is giving
Caused by: org.xml.sax.SAXParseException: cvc-elt.1: Cannot find the declaration of element 'Context'.
How should I load these entries when deploying spring boot app in tomcat?
By default, JNDI is disabled in embedded Tomcat. You need to call Tomcat.enableNaming() to enable it.
If you can live by Java config,you can try below snippet to add JNDI and other configurations from context.xml using the java config.
#Bean
public TomcatEmbeddedServletContainerFactory tomcatFactory() {
return new TomcatEmbeddedServletContainerFactory() {
#Override
protected TomcatEmbeddedServletContainer getTomcatEmbeddedServletContainer(
Tomcat tomcat) {
tomcat.enableNaming();
return super.getTomcatEmbeddedServletContainer(tomcat);
}
};
}
Example :
#Bean
public TomcatEmbeddedServletContainerFactory tomcatFactory() {
return new TomcatEmbeddedServletContainerFactory() {
#Override
protected TomcatEmbeddedServletContainer getTomcatEmbeddedServletContainer(
Tomcat tomcat) {
tomcat.enableNaming();
return super.getTomcatEmbeddedServletContainer(tomcat);
}
#Override
protected void postProcessContext(Context context) {
ContextResource resource = new ContextResource();
resource.setName("jdbc/myDataSource");
resource.setType(DataSource.class.getName());
resource.setProperty("driverClassName", "your.db.Driver");
resource.setProperty("url", "jdbc:yourDb");
context.getNamingResources().addResource(resource);
}
};
}
#Bean(destroyMethod="")
public DataSource jndiDataSource() throws IllegalArgumentException, NamingException {
JndiObjectFactoryBean bean = new JndiObjectFactoryBean();
bean.setJndiName("java:comp/env/jdbc/myDataSource");
bean.setProxyInterface(DataSource.class);
bean.setLookupOnStartup(false);
bean.afterPropertiesSet();
return (DataSource)bean.getObject();
}
Have a look at this github link for related sample
context.xml should go into the /META-INF/ directory in your war files. It is instructions to the Tomcat server, there's no need to configure anything in Spring to try to load it.

Why does C3p0's ComboPooledDataSource successfully connect to a database, but its clone doesn't?

In a Tomcat 8.5.15 environment using an Oracle 11 database, I want to implement a data source that handles encrypted passwords in the context.xml. I'm having troubles with that, as described in this StackOverflow question.
In hopes of determining the underlying problem, I simplified the scenario. First, I verified that the C3p0 resource specification worked fine.
<Resource
auth="Container"
description="MyDataSource"
driverClass="oracle.jdbc.OracleDriver"
maxPoolSize="100"
minPoolSize="10"
acquireIncrement="1"
name="jdbc/MyDataSource"
user="me"
password="mypassword"
factory="org.apache.naming.factory.BeanFactory"
type="com.mchange.v2.c3p0.ComboPooledDataSource"
jdbcUrl="jdbc:oracle:thin:#mydb:1521:dev12c"
/>
It worked fine. Then, I created a clone of the ComboPooledDataSource, based on decompiling the class file:
public final class ComboPooledDataSourceCopy
extends AbstractComboPooledDataSource
implements Serializable, Referenceable {
private static final long serialVersionUID = 1L;
private static final short VERSION = 2;
public ComboPooledDataSourceCopy() {
}
public ComboPooledDataSourceCopy(boolean autoregister) {
super(autoregister);
}
public ComboPooledDataSourceCopy(String configName) {
super(configName);
}
private void writeObject(ObjectOutputStream oos) throws IOException {
oos.writeShort(2);
}
private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
short version = ois.readShort();
switch(version) {
case 2:
return;
default:
throw new IOException("Unsupported Serialized Version: " + version);
}
}
}
I created a revised resource specification using the cloned class:
<Resource
auth="Container"
description="MyDataSource"
driverClass="oracle.jdbc.OracleDriver"
maxPoolSize="100"
minPoolSize="10"
acquireIncrement="1"
name="jdbc/MyDataSource"
user="me"
password="mypassword"
factory="org.apache.naming.factory.BeanFactory"
type=type="com.mycompany.ComboPooledDataSourceCopy"
jdbcUrl="jdbc:oracle:thin:#mydb:1521:dev12c"
/>
When I try to connect to the database using this specification, the connection attempt fails.
...
Caused by: java.sql.SQLException: com.mchange.v2.c3p0.impl.NewProxyConnection#6950dfda
[wrapping: oracle.jdbc.driver.T4CConnection#765426dd]
is not a wrapper for or implementation of oracle.jdbc.OracleConnection
at com.mchange.v2.c3p0.impl.NewProxyConnection.unwrap(NewProxyConnection.java:1744)
at org.jaffa.security.JDBCSecurityPlugin.executeStoredProcedure(JDBCSecurityPlugin.java:117)
... 67 more
Why does the clone attempt fail to connect?
UPDATE:
With assistance from our local DBA, we’ve been able to audit my connection attempts. It appears that we are successfully connecting to the database and logging in. Based on this, it sounds like the problem may be in how the code is handling the database’s response, rather than in our request generation.
The error was a result of a class loading problem, where the Oracle classes were being loaded from multiple jars (%CATALINA_HOME%\lib\ojdbc7-12.1.0.2.0.jar and %CATALINA_HOME%\webapps\my-webapp-1.0.0\WEB-INF\lib\ojdbc7-12.1.0.2.0.jar) by different class loaders. When I deleted %CATALINA_HOME%\webapps\my-webapp-1.0.0\WEB-INF\lib\ojdbc7-12.1.0.2.0.jar, my problem went away.
These sources (1, 2, 3) discuss this in more detail.

Spring cloud contract: is possible to use constant from Java in grrovy Contract file?

I would like to share constants from Java classes in groovy Contracts.
Test base class:
#SpringBootTest(classes = TestBase.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class TestBase {
public static final String NAME = "just constant";
#Before
public void setup() {
RestAssured.baseURI = "https://rest-service.com";
RestAssured.port = 443;
}
}
Contract file:
package contracts.test_contract
import org.springframework.cloud.contract.spec.Contract
import static test.TestBase.NAME;
Contract.make {
request {
method 'GET'
url ''
body (
"""${value(client(NAME), server(NAME))}"""
)
}
response {
status 200
}
}
pom.xml - spring cloud contract plugin config:
<plugin>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-contract-maven-plugin</artifactId>
<extensions>true</extensions>
<configuration>
<testMode>EXPLICIT</testMode>
<baseClassForTests>test.TestBase</baseClassForTests>
</configuration>
</plugin>
Running mvn clean install and getting
[ERROR] Exception occurred while trying to evaluate the contract at path [C:\dev\_idea_workspace\test_1\src\test\resources\contracts\test_contract\c1.groovy]
org.codehaus.groovy.control.MultipleCompilationErrorsException: startup failed:
C:\dev\_idea_workspace\test_1\src\test\resources\contracts\test_contract\c1.groovy: 7: unable to resolve class test.TestBase
# line 7, column 1.
import static test.TestBase.NAME;
^
1 error
But when I try to import statically constant from another file, like Long.MAX_VALUE, it works.
Any suggestions how to go over this or how to share variable in more groovy contract files?
Thanks!
Yes, please read this section of the documentation - https://docs.spring.io/spring-cloud-contract/docs/current/reference/html/advanced.html#customization-customization . Here you can see the code with shared stuff - https://github.com/spring-cloud-samples/spring-cloud-contract-samples/tree/main/common . Here you can see how it's added on the producer side https://github.com/spring-cloud-samples/spring-cloud-contract-samples/blob/main/producer/pom.xml#L106-L111 and here on the consumer https://github.com/spring-cloud-samples/spring-cloud-contract-samples/blob/main/consumer/pom.xml#L63-L68

call Remote EJB from client JAVA

I have to implement two simples java projects ; the first is an EJB projectwho contains a simple service which implement a remote interface, and the second project is a java client which try to call this ejb project ,
so here is what I did until now :
Context context = new InitialContext(jndiProperties);
TestServiceRemote proxy = (TestServiceRemote) context
.lookup("java:global/testEJB/TestService!services.TestServiceRemote");
System.out.println(proxy.showHello());
and this my ejb service :
#Stateless
public class TestService implements TestServiceRemote {
public TestService() {
}
#Override
public String showHello() {
return "Hello";
}
}
finally this my Remote interface :
#Remote
public interface TestServiceRemote {
public String showHello();
}
I had deployed the EJB in WIldfly 9 , but when I launch the java client i get this error shown in console :
Exception in thread "main" javax.naming.NoInitialContextException: Need to specify class name in environment or system property, or as an applet parameter, or in an application resource file: java.naming.factory.initial
at javax.naming.spi.NamingManager.getInitialContext(NamingManager.java:662)
at javax.naming.InitialContext.getDefaultInitCtx(InitialContext.java:313)
at javax.naming.InitialContext.getURLOrDefaultInitCtx(InitialContext.java:350)
at javax.naming.InitialContext.lookup(InitialContext.java:417)
at swing.testClient.main(testClient.java:22)
Can someone tell me what I had wrong in my code ?
The java: namespace is not available by default in Java. You can either package your main class as an application client JAR inside an EAR and run it using an application client container launcher, or you can configure the InitialContext to have access to the java: namespace as described in this blog post.

Restart/ReInit a servlet

I want to restart a servlet (declared in web.xml, when JBoss is running) simply because its init-param points to a file which content has changed (i.e. providers.fac below has been modified).
If there is a way to reload the init-param without restarting the servlet, it will be good too.
I suppose I can modify the servlet to add a request param and function to restart itself ?
Is there any other option?
<servlet>
<servlet-name>coverage</servlet-name>
<servlet-class>coverageServlet</servlet-class>
<init-param>
<param-name>ConfigUrl</param-name>
<param-value>file:///C:/coverage/providers.fac</param-value>
</init-param>
<init-param>
<param-name>CacheDir</param-name>
<param-value>coverage</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
Environment:
Servlet Api 2.4
JBoss 4.2
Spring Framework 2.5
If you are in jboss you can simply restart a servlet by altering the web.xml file if your servlet is exploded. On linux a touch would do.
Not sure what format your config file is but if you are trying to reload automatically a property configuration file I would have a look at the commons configuration lib that supports this out of the box(FileChangedReloadingStrategy)
If you are planning to restart your servlet automatically and many many times in a day/week you should make sure your permgen is good enough to handle the servlet reloads. There were instances where I had done this in production and burnt myself down with a lot of PermGen errors.
2 options:
Add an extra check on doGet() or doPost() which reloads the file when a certain request parameter is been set while an admin user is logged in and provide an admin screen which invokes that request.
Rewrite the servlet (or refactor the part to ServletContextListener) to store it in ServletContext instead of as an instance variable of the servlet and have some admin screen which reloads the file in ServletContext.
I would separate these concerns by pulling the file management out of the servlet and putting it into a JBoss JMX ServiceMBean. The MBean can take care of watching the file for changes and reloading when necessary, and can also expose the required operations [to the calling servlet]. This will allow you not to have to reload and re-init the servlet (or the WAR) which are fairly heavyweight operations.
I will invent a couple of operations for the FileManager:
public interface FileManagerMBean extends org.jboss.system.ServiceMBean {
public void setFileName(String fileName);
public void setCheckFrequency(long freq);
public String getCoverageData(......);
public String getProviderData(......);
}
The implementation might be (in the same package please :) )
public class FileManager extends org.jboss.system.ServiceMBeanSupport implements FileManagerMBean {
public void setFileName(String fileName) { .... }
public void setCheckFrequency(long freq) { .... }
public String getCoverageData(......) { /* impl */ }
public String getProviderData(......) { /* impl */ }
public void startService() throws Exception {
/* Start a file watcher thread */
}
public void stopService() throws Exception {
/* Stop the file watcher thread */
}
}
Your servlet might look like this:
// A ref to the MBean
FileManagerMBean fileMgr = null;
// The JMX MBean's ObjectName
ObjectName fileMgrOn = org.jboss.mx.util.ObjectNameFactory.create("portoalet.com:service=FileManager");
public void init() {
// Get the JBoss MBeanServer
MBeanServer server = org.jboss.mx.util.MBeanServerLocator.locateJBoss();
// Create an MBeanInvoker for the service
fileMgr = (FileManagerMBean)javax.management.MBeanServerInvocationHandler.newProxyInstance(server, fileMgrOn,FileManagerMBean.class, false);
}
Now you can use the fileMgr instance to make calls to your FileManager MBean, which should be thread safe unless you synchronize access to fileMgr.
I realize this looks a bit over-engineered, but you really should separate the functions of the servlet from the functions of managing the file.

Resources