Defining two data sources in jetty (jetty-env.xml) - java

I'm trying to define two data sources in my web application, using the jetty-env.xml file.
It works ok with just one data source, however I get this exception when the second data source is added:
java.lang.IllegalStateException: Nothing to bind for name javax.sql.DataSource/default
Here's my configuration:
jetty-env.xml
<Configure class="org.eclipse.jetty.webapp.WebAppContext">
<New id="ds" class="org.eclipse.jetty.plus.jndi.Resource">
<Arg>jdbc/mybd1</Arg>
<Arg>
<New class="com.mchange.v2.c3p0.ComboPooledDataSource">
<Set name="driverClass">com.microsoft.sqlserver.jdbc.SQLServerDriver</Set>
<Set name="jdbcUrl">jdbc:jtds:sqlserver://url:1433/mybd1</Set>
<Set name="user">xx</Set>
<Set name="password">yy</Set>
</New>
</Arg>
</New>
<New id="ds2" class="org.eclipse.jetty.plus.jndi.Resource" >
<Arg>jdbc/mybd2</Arg>
<Arg>
<New class="com.mchange.v2.c3p0.ComboPooledDataSource">
<Set name="driverClass">com.microsoft.sqlserver.jdbc.SQLServerDriver</Set>
<Set name="jdbcUrl">jdbc:jtds:sqlserver://url:1433/mybd2</Set>
<Set name="user">xx</Set>
<Set name="password">yy</Set>
</New>
</Arg>
</New>
</Configure>
web.xml
<resource-ref>
<res-ref-name>jdbc/mybd1</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
</resource-ref>
<resource-ref>
<res-ref-name>jdbc/mybd2</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
</resource-ref>
hibernate.cfg.xml (there is another hibernate.cfb.xml to configure the second data source)
<session-factory>
<property name="connection.datasource">jdbc/mybd1</property>
<!-- ... -->
Any clue?

I haven't had a chance to test it, but it looks to me like your problem is that you're missing an <Arg /> for the scope.
Your DS should be:
<New id="ds" class="org.eclipse.jetty.plus.jndi.Resource">
<Arg></Arg>
<Arg>jdbc/mybd1</Arg>
<Arg>
<New class="com.mchange.v2.c3p0.ComboPooledDataSource">
etc.
That first "Arg" is the scope, and without it, the rest of your arguments are out of position, and are probably causing your issue.

The id parameter values should match in jetty-env.xml and web.xml
jetty-env.xml
<Configure class="org.eclipse.jetty.webapp.WebAppContext">
<New id="DS1" class="org.eclipse.jetty.plus.jndi.Resource">...</New>
<New id="DS2" class="org.eclipse.jetty.plus.jndi.Resource">...</New>
</Configure>
web.xml
<resource-ref id="DS1">...</resource-ref>
<resource-ref id="DS2">...</resource-ref>

Try to enable logging in Jetty.
Be carefull logger name is "jndi".
Jetty developers don't use class-name as a logger-name for JNDI.
I spent 2 days to finding difference between name defined in web.xml and jetty-env.xml.

Take a look in :
https://www.eclipse.org/jetty/documentation/9.4.x/using-jetty-jndi.html
Deciding Where to Declare Resources
You can define naming resources in three places:
jetty.xml
Naming resources defined in a jetty.xml file are scoped at either the JVM level or the Server level.
The classes for the resource must be visible at the Jetty container level. If the classes for the resource only exist inside your webapp, you must declare it in a WEB-INF/jetty-env.xml file.
WEB-INF/jetty-env.xml
Naming resources in a WEB-INF/jetty-env.xml file are scoped to the web app in which the file resides. While you can enter JVM or Server scopes if you choose, we do not recommend doing so. The resources defined here may use classes from inside your webapp. This is a Jetty-specific mechanism.
Context xml file
Entries in a context xml file should be scoped at the level of the webapp to which they apply, although you can supply a less strict scoping level of Server or JVM if you choose. As with resources declared in a jetty.xml file, classes associated with the resource must be visible on the container’s classpath.
And put a file like this :
<?xml version="1.0"?>
<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://jetty.mortbay.org/configure.dtd">
<Configure class="org.eclipse.jetty.webapp.WebAppContext">
<!-- Add an EnvEntry only valid for this webapp -->
<New id="gargle" class="org.eclipse.jetty.plus.jndi.EnvEntry">
<Arg>gargle</Arg>
<Arg type="java.lang.Double">100</Arg>
<Arg type="boolean">true</Arg>
</New>
<!-- Add an override for a global EnvEntry -->
<New id="wiggle" class="org.eclipse.jetty.plus.jndi.EnvEntry">
<Arg>wiggle</Arg>
<Arg type="java.lang.Double">55.0</Arg>
<Arg type="boolean">true</Arg>
</New>
<!-- an XADataSource -->
<New id="mydatasource99" class="org.eclipse.jetty.plus.jndi.Resource">
<Arg>jdbc/mydatasource99</Arg>
<Arg>
<New class="com.atomikos.jdbc.SimpleDataSourceBean">
<Set name="xaDataSourceClassName">org.apache.derby.jdbc.EmbeddedXADataSource</Set>
<Set name="xaDataSourceProperties">databaseName=testdb99;createDatabase=create</Set>
<Set name="UniqueResourceName">mydatasource99</Set>
</New>
</Arg>
</New>
</Configure>

Related

How do I properly initialize a WebAppContext in Jetty when running as OSGi?

I'm trying to get Jetty 9.4.30 running as an OSGi Service (following this: https://examples.javacodegeeks.com/enterprise-java/jetty/jetty-osgi-example/ with updated versions) that can host WebApp Bundles. I can deploy and servlets work fine, but JSPs aren't working and I keep hitting an exception for TLD loading caused by:
Caused by:
java.lang.NullPointerException
at org.apache.jasper.JspCompilationContext.getTldResourcePath(JspCompilationContext.java:563)
at org.apache.jasper.compiler.Parser.parseTaglibDirective(Parser.java:430)
at org.apache.jasper.compiler.Parser.parseDirective(Parser.java:489)
The problem is almost exactly that described at http://bengreen.eu/fancyhtml/quickreference/jettyjsp9error.html, except that in this case the author is using Jetty as Embedded and is able to set org.eclipse.jetty.containerInitializers using code where the server is started.
In OSGi, I don't have a place where I'm starting it - it's all happening in the bundles. After a lot of tweaking (and untweaking) config files the closest I feel I've got is when I copied the configuration performed in code into the jetty-web.xml file (which would be deployed in each WAB and isn't ideal in itself) as follows:
<Configure id="webappctxt" class="org.eclipse.jetty.webapp.WebAppContext">
<New id="initList" class="java.util.ArrayList"></New>
<Call name="setAttribute">
<Arg>org.eclipse.jetty.containerInitializers</Arg>
<Arg>
<Call class="java.util.Arrays" name="asList">
<Array type="org.eclipse.jetty.plus.annotation.ContainerInitializer">
<Item>
<New
class="org.eclipse.jetty.plus.annotation.ContainerInitializer">
<Arg>
<New class="org.eclipse.jetty.apache.jsp.JettyJasperInitializer"></New>
</Arg>
<Arg></Arg>
</New>
</Item>
</Array>
</Call>
</Arg>
</Call>
<Call name="addBean">
<Arg>
<New class="org.eclipse.jetty.annotations.ServletContainerInitializersStarter">
<Arg>
<Ref refid="webappctxt" />
</Arg>
</New>
</Arg>
</Call>
<Get name="ServletContext">
<Call name="setAttribute">
<Arg>org.apache.tomcat.InstanceManager</Arg>
<Arg>
<New class="org.apache.tomcat.SimpleInstanceManager"></New>
</Arg>
</Call>
</Get>
</Configure>
When running, I can see the org.eclipse.jetty.annotations.ServletContainerInitializersStarter, and it has the TLDs from the platform (so all my dependencies seem to be there!) but the XML version of the code fails because there are two constructors for org.eclipse.jetty.plus.annotation.ContainerInitializer:
ContainerInitializer​(java.lang.ClassLoader loader, java.lang.String toString)
ContainerInitializer​(javax.servlet.ServletContainerInitializer target, java.lang.Class<?>[] classes)
...and the Jetty XML code picks the first one and throws a "java.lang.IllegalArgumentException: argument type mismatch".
Plugins currently "required" by my WAB are:
Require-Bundle: org.eclipse.jetty.jndi;bundle-version="9.4.30",
org.mortbay.jasper.apache-jsp;bundle-version="8.5.54",
org.eclipse.jetty.server;bundle-version="9.4.30",
org.eclipse.jetty.deploy;bundle-version="9.4.30",
org.eclipse.jetty.http;bundle-version="9.4.30",
org.eclipse.jetty.io;bundle-version="9.4.30",
org.eclipse.jetty.osgi.boot;bundle-version="9.4.30",
org.eclipse.jetty.security;bundle-version="9.4.30",
org.eclipse.jetty.servlet;bundle-version="9.4.30",
org.eclipse.jetty.util;bundle-version="9.4.30",
org.eclipse.jetty.webapp;bundle-version="9.4.30",
org.eclipse.jetty.xml;bundle-version="9.4.30",
org.eclipse.jetty.annotations;bundle-version="9.4.30",
org.eclipse.jetty.apache-jsp;bundle-version="9.4.30"
...and only the WAB bundle is set to auto-start.
For completeness, the VM arguments to configure plugins are:
-Djetty.home.bundle=jetty-config-bundle -Djava.naming.factory.url.pkgs=org.eclipse.jetty.jndi -Djava.naming.factory.initial=org.eclipse.jetty.jndi.InitialContextFactory
And jetty-config-bundle does contain the jetty.xml, etc. files and they are being processed.
Can anyone tell me if they've got this working, and how? Is it configurable to just work without needing a jetty-web.xml in each WAB, or am I missing a dependency bundle on my plugin?

Jetty - connection pool for different contexts and database, but same lookup code

I'm trying to configure the connection pool 2 web applications using .xml context descriptor for 2 separate context paths and databases, but with the same logical code.
The problem is that when using JNDI to lookup the datasource, the resources are overridden when jetty loads the context, and the apps end up using the same database. Here is my configuration and code:
Configuration for MyApp1.xml:
<New id="myDataBase" class="org.eclipse.jetty.plus.jndi.Resource">
<Arg></Arg>
<Arg>jdbc/myDataBase</Arg>
<Arg>
<New class="com.mysql.jdbc.jdbc2.optional.MysqlConnectionPoolDataSource">
<Set name="Url">jdbc:mysql://host:3306/mydb</Set>
<Set name="User">...</Set>
<Set name="Password">...</Set>
</New>
</Arg>
</New>
Configuration for MyApp2.xml
<New id="myDataBase" class="org.eclipse.jetty.plus.jndi.Resource">
<Arg></Arg>
<Arg>jdbc/myDataBase</Arg>
<Arg>
<New class="com.mysql.jdbc.jdbc2.optional.MysqlConnectionPoolDataSource">
<Set name="Url">jdbc:mysql://host:3306/mydb-test2</Set>
<Set name="User">...</Set>
<Set name="Password">...</Set>
</New>
</Arg>
</New>
Code used by the apps:
public class MyDb {
...
static {
try {
datasource = (DataSource) new InitialContext().lookup("jdbc/myDataBase");
} catch (NamingException e) {
// ...
}
...
}
So, jetty loads context for MyApp1.xml, then MyApp2.xml. When I try to access the apps, they both use the same database: mydb-test2.
How can I properly resolve this problem?
EDIT:
I have tried adding the argument in the configuration but it is not working; it is strange that now the contexts both use the first configured database: mydb
This is the xml for each app:
<Configure id='wac1' class="org.eclipse.jetty.webapp.WebAppContext">
...
<New id="myDataBase" class="org.eclipse.jetty.plus.jndi.Resource">
<Arg><Ref refid='wac1'/></Arg>
<Arg>jdbc/myDataBase</Arg>
<Arg>
<New class="com.mysql.jdbc.jdbc2.optional.MysqlConnectionPoolDataSource">
<Set name="Url">jdbc:mysql://host:3306/mydb</Set>
<Set name="User">...</Set>
<Set name="Password">...</Set>
</New>
</Arg>
</New>
...
<Configure id='wac2' class="org.eclipse.jetty.webapp.WebAppContext">
...
<New id="myDataBase" class="org.eclipse.jetty.plus.jndi.Resource">
<Arg><Ref refid='wac2'/></Arg>
<Arg>jdbc/myDataBase</Arg>
<Arg>
<New class="com.mysql.jdbc.jdbc2.optional.MysqlConnectionPoolDataSource">
<Set name="Url">jdbc:mysql://host:3306/mydb-test2</Set>
<Set name="User">...</Set>
<Set name="Password">...</Set>
</New>
</Arg>
</New>
...
What am I missing? Do I have to change the code (way in which I make the lookup)?
I've tried
datasource = (DataSource) new InitialContext().lookup("java:comp/env/jdbc/myDataBase");
but I get a javax.naming.NameNotFoundException - probably because I dont use env variables, but I don't think I need that, just per context scope lookup)
EDIT 2:
Ok, so I was actually missing a web.xml config which solved the issue (see http://www.eclipse.org/jetty/documentation/current/jndi-configuration.html#configuring-datasources)
<resource-ref>
<res-ref-name>jdbc/HugaDataBase</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
</resource-ref>
You need to set the scope for the JNDI entries. Instead of the empty first argument, you should have something like this:<Arg><Ref refid='myapp'/></Arg>

Jetty and SQLite connection in servlets

I'm making a small servlet app in Java, with Maven, in Netbeans. I'm using SQLite database, and newest Jetty server. I have problem with creating connection pool for use in servlets. What works(in servlet):
Class.forName("org.sqlite.JDBC");
String url = "jdbc:sqlite:c:\\db\\base";
Connection con = DriverManager.getConnection(url);
And this works without specific settings in jetty.xml/web.xml/pom.xml
I have libraries to use SQLite and connection pools (org.xerial.sqlite-jdbc, commons-pool, commons-dbcp).
What doesn't work:
web.xml:
<resource-ref>
<description>DB Connection Pool</description>
<res-ref-name>jdbc/DSTestPool</res-ref-name>
<res-type>javax.sql.ConnectionPoolDataSource</res-type>
<res-auth>Container</res-auth>
</resource-ref>
jetty.xml
<New id="DSTestPool" class="org.eclipse.jetty.plus.jndi.Resource">
<Arg>jdbc/DSTestPool</Arg>
<Arg>
<New class="org.sqlite.SQLiteConnectionPoolDataSource">
<Set name="driverClassName">org.sqlite.JDBC</Set>
<Set name="url">jdbc:sqlite:c:\\db\\base</Set>
</New>
</Arg>
</New>
pom.xml - dependencies.
This configuration, even without changes in code (change to using pool) creates error in jetty console:
java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
....
Caused by:
java.lang.IllegalStateException: Nothing to bind for name jdbc/DSTestPool at org.eclipse.jetty.plus.webapp.PlusDescriptorProcessor.bindEntry(PlusDescriptorProcessor.java:895)
...
Opening app in Jetty: Error 503
I think there is something wrong with my declaration of jdbc/DSTestPool in jetty.xml, I've tried different parameters, but result was the same.
There is one parameter missing in your jetty.xml, you can declare any of the following types:
org.eclipse.jetty.plus.jndi.EnvEntry: for env-entry type of entries
org.eclipse.jetty.plus.jndi.Resource: for all other type of resources
org.eclipse.jetty.plus.jndi.Transaction: for a JTA manager
org.eclipse.jetty.plus.jndi.Link: for link between a web.xml resource name and a naming entry
And each of these types follow the same pattern:
<New class="org.eclipse.jetty.plus.jndi.xxxx">
<Arg><!-- scope --></Arg>
<Arg><!-- name --></Arg>
<Arg><!-- value --></Arg>
</New>
Your jetty.xml file have the name and value but the scope is missing.
Try with the following for JVM instance scope (the name is unique across the JVM instance)
<New id="DSTestPool" class="org.eclipse.jetty.plus.jndi.Resource">
<Arg></Arg><!-- empty arg -->
<Arg>jdbc/DSTestPool</Arg>
<Arg>
<New class="org.sqlite.SQLiteConnectionPoolDataSource">
<Set name="driverClassName">org.sqlite.JDBC</Set>
<Set name="url">jdbc:sqlite:c:\\db\\base</Set>
</New>
</Arg>
</New>
Or something like the following for a web app context scope (the name is unique to the WebAppContext instance)
<Configure id='wac' class="org.eclipse.jetty.webapp.WebAppContext">
<New id="DSTestPool" class="org.eclipse.jetty.plus.jndi.Resource">
<Arg><Ref refid='wac'/></Arg><!-- reference to WebAppContext -->
<Arg>jdbc/DSTestPool</Arg>
<Arg>
<New class="org.sqlite.SQLiteConnectionPoolDataSource">
<Set name="driverClassName">org.sqlite.JDBC</Set>
<Set name="url">jdbc:sqlite:c:\\db\\base</Set>
</New>
</Arg>
</New>
</Configure>
See the documentation here for details.
An approach could be to use HikariCp (or any other pooler..).
In jetty-env.xml:
<Configure class="org.eclipse.jetty.webapp.WebAppContext">
<New id="DSTest" class="org.eclipse.jetty.plus.jndi.Resource">
<Arg></Arg>
<Arg>jdbc/ds</Arg>
<Arg>
<New class="com.zaxxer.hikari.HikariDataSource">
<Arg>
<New class="com.zaxxer.hikari.HikariConfig">
<Set name="dataSourceClassName">org.sqlite.SQLiteDataSource</Set>
<Call name="addDataSourceProperty">
<Arg>url</Arg>
<Arg>jdbc:sqlite:path/to/test.db</Arg>
</Call>
</New>
</Arg>
</New>
</Arg>
In web.xml:
<resource-ref id="ds">
<res-ref-name>jdbc/ds</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
</resource-ref>
then you get datasource:
(DataSource)new InitialContext().lookup("java:/comp/env/jdbc/ds");
...

What does "context" file mean in jetty world

I am following this tutorial instruction: http://www.eclipse.org/jetty/documentation/current/spnego-support.html
It says the following: A corresponding UserRealm needs to be created either programmatically if embedded, via the jetty.xml or in a context file for the webapp.
Now I am using embedded jetty and I could create a web.xml using the WebAppContext and \jee but what is the context file? Is it talking about something like a Spring context?
(I am fairly new to Java)
With context file for the webapp, they probably mean the jetty.xml configuration file, which can also be used on a per-app basis, when you name it jetty-web.xml and place it in your WEB-INF directory (alongside the web.xml configuration file).
Frame of a jetty-web.xml:
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE Configure PUBLIC "//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure.dtd">
<Configure class="org.eclipse.jetty.webapp.WebAppContext">
<!-- configuration here -->
</Configure>
You can configure your realms with it, e.g.:
<Configure class="org.eclipse.jetty.webapp.WebAppContext">
<Set name="contextPath">/test</Set>
<Set name="war"><SystemProperty name="jetty.home" default="."/>/webapps/test</Set>
<Get name="securityHandler">
<Set name="loginService">
<New class="org.eclipse.jetty.security.HashLoginService">
<Set name="name">Test Realm</Set>
<Set name="config"><SystemProperty name="jetty.home" default="."/>/etc/realm.properties</Set>
</New>
</Set>
</Get>
</Configure>
For details, see:
https://wiki.eclipse.org/Jetty/Reference/jetty-web.xml
https://wiki.eclipse.org/Jetty/Tutorial/Realms
Since you are using embedded jetty, I am unsure if you can configure user realms using the normal jetty-web.xml configuration, or if you have to set them up programmatically.
I did this programmatically, but with an older (6.1) version of Jetty. But I also have used the jetty-web.xml in an embedded jetty to configure some parameters, e.g. the upload file size limit.

Jetty and custom sessionIdManager

In order to have custom session storage I have implemented a custom sessionManager (by extending NoSqlSessionManager) and sessionIdManager. My code (along with jars it requires) went into ${jetty.home}/lib/ext (version 8.1.4 BTW). With start.ini i included another config file with following content:
<Configure id="Server" class="org.eclipse.jetty.server.Server">
<Set name="sessionIdManager">
<New id="customIdMgr" class="com.me.customSessionIdManager">
<Arg>...</Arg>
</New>
</Set>
</Configure>
Jetty starts and sessionIdManager appears to be working. At least scavenge() method is being called. So far so good. Next step is to associate my custom sessionManager with the WebAppContext of my choice. I did it within the overlay template (overlay.xml) with following content:
<Configure class="org.eclipse.jetty.webapp.WebAppContext">
<Get name="server">
<Get id="customIdMgr" name="sessionIdManager"/>
</Get>
<Set name="sessionHandler">
<New class="org.eclipse.jetty.server.session.SessionHandler">
<Arg>
<New class="com.me.customSessionManager">
<Set name="sessionIdManager"><Ref id="customIdMgr"/></Set>
</New>
</Arg>
</New>
</Set>
</Configure>
However when starting Jetty I get this:
WARN:oejx.XmlConfiguration:Config error at <Get id="customIdMgr" name="sessionIdManager"/> java.lang.NullPointerException
...which implies that the object that was registered in the main jetty configuration is now gone when overlays are processed.
Any idea what I'm doing wrong here?
After quite a lot of debugging it turns out, the root of the problem is <Get name="server"> returns null. Most probably reference to Server class is injected into WebAppContext much later in the deployment process. So instead of getting Server i referenced it with <Ref id="Server"> and that did the trick.

Categories

Resources