Hot questions for Using GlassFish in jndi

Question:

I am developing a Java EE 7 application and have a requirement for the application to be deployed onto application servers running either GlassFish 4.0 or WildFly 8.1.0. The issue I've got is GlassFish and WildFly use slightly different formats for JNDI names but I can't see how to make my application compatible with both.

In GlassFish my persistence.xml file references the data source jdbc/myDataSouce, but in WildFly the data source needs to be java:/jdbc/myDataSource.

The same is also true for classes that are annotated with @Resource. In GlassFish the annotation for a class using JavaMail would be @Resource(name = "mail/myMailSession"), but to deploy onto WildFly this would need to be @Resource(name = "java:mail/myMailSession").

I know that I could unpack the EAR and JAR files to manually edit files such as persistence.xml but I can't do that for classes that have been annotated with @Resource.

Is there a way I can allow my complied application to be deployed onto GlassFish and WildFly without maintaining two different versions of the code? I'm assuming the answer probably lies with application specific deployment descriptors but I can't find any examples that cover these two scenarios.

Can anyone point me in the right direction please?


Answer:

You can modify the Wildfly JNDi names and strip the undesired prefixes from the respective JNDI names to find the least common denominator in both app servers. The following works for me with Glassfish and JBoss AS 7.1. Since I expect Wildfly to be backwards-compatible to JBoss in this regard, I guess it'll work for Wildfly as well.

Persistence

Inject as:

@PersistenceContext(unitName="TestPU")
private EntityManager entityManager;

or via ejb-jar.xml:

<persistence-context-ref>
    <persistence-context-ref-name>entityManager</persistence-context-ref-name>
    <persistence-unit-name>TestPU</persistence-unit-name>
    <injection-target> ... </injection-target>
</persistence-context-ref>

The corresponding persistence.xml:

<persistence version="2.0" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="         http://java.sun.com/xml/ns/persistence         http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
  <persistence-unit name="TestPU" transaction-type="JTA">
    <jta-data-source>datasources/TestDS</jta-data-source>
    <class>org.jeeventstore.persistence.jpa.EventStoreEntry</class>
    <properties>
      <property name="hibernate.show_sql" value="false"/>
      <property name="hibernate.format_sql" value="true"/>
      <property name="hibernate.hbm2ddl.auto" value="create-drop"/>
      <property name="hibernate.connection.charSet" value="UTF-8"/>
      <property name="eclipselink.logging.level" value="FINE"/>
      <property name="eclipselink.logging.level.sql" value="FINE"/>
      <property name="eclipselink.logging.parameters" value="true"/>
      <property name="eclipselink.ddl-generation" value="drop-and-create-tables"/>
    </properties>
  </persistence-unit>
</persistence>

(note the simple jta-data-source JNDI name)

Here's a glassfish-resources.xml file used to specify a Derby database on deployment, a similar setup can be used for MySQL or Postgres.

<resources>

    <jdbc-resource pool-name="ArquillianEmbeddedDerbyPool"
                   jndi-name="datasources/TestDS"/>

    <jdbc-connection-pool name="ArquillianEmbeddedDerbyPool"
                          res-type="javax.sql.DataSource"
                          datasource-classname="org.apache.derby.jdbc.EmbeddedDataSource"
                          is-isolation-level-guaranteed="false">
        <property name="databaseName" value="target/databases/derby"/>
        <property name="createDatabase" value="create"/>
    </jdbc-connection-pool>

</resources>

And the settings from the JBoss standalone.xml:

<datasource jta="true" jndi-name="java:/datasources/TestDS" pool-name="TestDS" enabled="true" use-ccm="false">
    <connection-url>jdbc:postgresql://localhost/test_db</connection-url>
    ...
</datasource>
Resources

I have not injected a JavaMail component on Glassfish, but similar to the datasoruce settings, it might be worth a try to strip the "java:" part from the @Resource annotation as well.

@Resource(name = "mail/myMailSession")

and then configure Wildfly such that that the mail resource is available at the "java:mail/myMailSession" JNDI location.

Injection via ejb-jar.xml

Another option is to manually inject the fields via a ejb-jar.xml file, and then use a build tool such as maven to copy either of ejb-jar-glassfish.xml or ejb-jar-wildfly.xml to the desired ejb-jar.xml at assembly time.

In one of our projects we use a mixed approach to avoid the burden with the xml configuration: We configure a small number of "provider" beans via ejb-jar.xml to inject, e.g., the persistence context into a PersistenceContextProvider, and then use CDI to inject the PersistenceContextProvider into the EJBs via @EJB, which are found without further configuration since they reside in the same EAR.

Question:

In Glassfish admin, I setup a JDBC connection pool that I can ping ok. Also in Glassfish admin, I have setup a JNDI JDBC resource called jdbc/myDb

However I'm unable to connect to it from Java. I have tried both injection style:

@Resource (mappedName="jdbc/myDB")
private DataSource datasource;

I have also tried Context style :

Context ctx = new InitialContext();
DataSource datasource = (DataSource)ctx.lookup("jdbc/myDB")

All I get is java.lang.NullPointerException.

I have also tried various naming styles such as java:jdbc/myDB or java:comp/env/jdbc/myDb

This is using the latest Glassfish (4.1), the latest Postgres Driver (9.3-1102 JDBC 41) against Postgres 9.4, and the latest Java (1.8.0_31-b13).


Answer:

Got to the Menu JDBC -> JDBC Resources -> jdbc/__default

Choose your DBName at the DropDown Menu "Pool Name: " and use

@Resource (mappedName="jdbc/__default")

Mind the two "_" !

At least this works for me.

p.s.: Can you specify where the NPE is thrown ?

Question:

When I deploy my web application witch use JDBC Connection pool and JNDI with Netbeans, this both created automaticly in Glassfish.

When I use Maven to create the same application, the JDBC Connection pool and JNDI not create automaticly and show me this error:

Error

Grave: Exception while preparing the app : Invalid resource : moduleJNDI__pm
java.lang.RuntimeException: Invalid resource : moduleJNDI__pm

I know the solution of this error, I just create the JNDI manualy.

My Question is: is there any solution or configuration to create the JNDI automaticly in the server Glassfish like the ordinary application, or is that a problem with Maven.

N.B

I use the server: Glassfish 3.1.2.2, Netbeans 8.1

Thank you.


Answer:

Create a glassfish-resources.xml file to define your database connection and make sure it ends up in your WEB-INF folder. You could just put it there as a static file, but in most projects I work on I need a different connection in development. You could use the Maven WAR plugin to take care of that (handling it as a filterable resource). For example, create the glassfish-resources.xml in your project at /src/main/resources_WEB-INF. Now you can put it in your WEB-INF folder when you build your project. See this pom.xml fragment:

<build>
  <plugins>
    <plugin>
      <groupId>org.apache.maven.plugins</groupId>
      <artifactId>maven-war-plugin</artifactId>
      <version>2.6</version>
      <configuration>
        <failOnMissingWebXml>false</failOnMissingWebXml>
        <webResources>
          <resource>
            <directory>${basedir}/src/main/resources_WEB-INF</directory>
            <filtering>true</filtering>
            <targetPath>WEB-INF</targetPath>
          </resource>
        </webResources>
      </configuration>
    </plugin>
  </plugins>
</build>

See also

Question:

I have tried to implement this many ways, but this is the way that makes the most sense to me, and I am still unable to return anything from my resource. I added the resource with the GlassFish admin GUI (essentially, i am trying to save username and passwords on the local server).

While I am getting a null pointer exception (NPE), please do not point me here, it doesn't help me at all. What is a NullPointerException, and how do I fix it?

Here are my supporting classes...

Creating the bean

   @LocalBean
   @Stateless

public class JndiProperties {

    @Resource(name="jndiCreds")
    private Properties properties;

    public String getUser() {
        return properties.getProperty("UserName");
    }
    public String getPass() {
        return properties.getProperty("UserPass");
    }
}

This is my bean manager:

 @ManagedBean
 @ViewScoped
    public class GetCreds {
        @Inject
        private JndiProperties property;
        public String getUserName(){
            return property.getUser();
        }
        public String getPassword(){
            return property.getPass();
        }
    }

And this is how I call them

GetCreds creds = new GetCreds();
String username = creds.getUserName();
String pass =  creds.getPassword();

I named the resource jndiCreds and have the names UserName and UserPass with the values containing respective data.

Here is the view from the GlassFish GUI:

Have any idea WHY it won't return my requested information? I AM receiving an NPE when I try to call the resource when I call either function from getCreds.

Help would be appreciated; I am very stuck.

I decided to step away from trying to use a bean and just accessing it directly (although I am giving up some security here). I am trying to access the data in a contextual manner. BUT! I still can not do it! Here is my NEW supporting class:

public class JndiProperties {

    public Properties getProperties(String jndiName) {
        Properties properties = null;
        try {
            InitialContext context = new InitialContext();
            properties = (Properties) context.lookup(jndiName);
            context.close();
        }
        catch (NamingException e) {

            return null;
        }
        return properties;
    }

And this is how I grab the information:

JndiProperties creds = new JndiProperties();

String username = creds.getProperties("jndiCreds").getProperty("UserName");
String pass =  creds.getProperties("jndiCreds").getProperty("UserPass");

String credentials = String.join(System.getProperty("line.separator"),
                                 "user=" + username,
                                 "password=" + pass);
System.out.print(credentials);

I am using the same resource shown above. I am STILL ending up with null pointer... ANY help would be greatly appreciated.Feel free to answer what was wrong with my bean implementation also.


Answer:

I have figured it out!

What was happening is first, I was a complete idiot, and I was trying to test my program with JUnit (IT DOES NOT RUN ON THE SERVER!)

Since the program wasn't being run on GlassFish, it couldn't access the resource.

Secondly, (and most importantly) I was missing the appserver-rt.jar- very important.

Question:

I need to have the same application deployed in GlassFish several times, with different JNDI parameters, but I can't find a way to do that.

I know I can have different standalone instances and apply the different JNDI resources to one or several instances, but I can't have the same resource name with different values for the different instances. What is the way to achieve what I need?


Answer:

To achieve the requirement, you can use different JNDI configurations in a property file and pass the values in JVM arguments to apply each configuration to several glassfish server instances.

Question:

I want to provide configuration for a web-app I'm developing via the context/JNDI. I'm currently developing in Netbeans 8.1 using the bundled Glassfish server, although my solution should be container-agnostic.

I have working settings for getting database connections, but am stumped with custom resource types.

In web.xml:

<resource-ref>
    <res-ref-name>SHOWmail/search</res-ref-name>
    <res-type>com.example.SearchProvider</res-type>
    <res-auth>Container</res-auth>
</resource-ref>

In glassfish-resources.xml:

    <custom-resource jndi-name="SHOWmail/search" res-type="com.example.SearchProvider" factory-class="com.example.SearchProviderFactory">
    <property name="name" value="value"/>
</custom-resource>

In code:

   initContext = new InitialContext();
   envContext = (Context) initContext.lookup("java:comp/env");
   search = (SearchProvider)envContext.lookup("SHOWmail/search");

I reliable get javax.naming.NameNotFoundException: No object bound to name java:SHOWmail/search. My factory and class aren't touched (will add if needed).

Pointers on where I've gone wrong greatly appreciated.


Answer:

It seems that I misunderstood the different JNDI namespaces here in the netbeans/glassfish combination.

The solution is to look under java:app instead of java:comp/env; this searches WEB-INF/glassfish-resources.xml.

web.xml

<resource-env-ref>
    <resource-env-ref-name>SHOWmail/search</resource-env-ref-name>
    <resource-env-ref-type>com.example.SearchProviderFactory</resource-env-ref-type>
</resource-env-ref>

glassfish-resources.xml

<custom-resource jndi-name="java:app/SHOWmail/search" res-type="com.example.ElasticSearchProvider" factory-class="com.example.SearchProviderFactory">
</custom-resource>

Question:

We have a common web module (foo.war) we'd like to deploy as a WAR in a number of different EARs. foo.war accesses the database via a JNDI datasource that foo knows by the name jdbc/FOO-DATASOURCE

But for each application XXX, this datasource must be remapped to the the datasource associated with the XXX application, that is jdbc/XXX-DATASOURCE.

foo.war has the following in its web.xml:

<resource-ref>
    <res-ref-name>jdbc/FOO-DATASOURCE</res-ref-name>
    <res-type>javax.sql.DataSource</res-type>
    <res-auth>Container</res-auth>
</resource-ref>

I had thought that I could use the following entries in glassfish-application.xml in the XXX project to remap this:

<resource-ref>
    <res-ref-name>jdbc/FOO-DATASOURCE</res-ref-name>
    <jndi-name>jdbc/XXX-DATASOURCE</jndi-name>
</resource-ref>

but when I deploy the XXX app to glassfish, I get the messages:

This app [xxx-ear-0.0.1-SNAPSHOT] has no resource reference by the name of [jdbc/FOO-DATASOURCE]
DPL8007: Unsupported deployment descriptors element jndi-name value jdbc/XXX-DATASOURCE

Is there some way I can set up a translation at the EAR-level for the resource defined in the web.xml? Where is glassfish looking for the resource reference? Is there a better way to accomplish this?


Answer:

It turned out that I can declare the resource at the EAR-level: in the application.xml. Where I was going wrong was that I was originally using an old version of the application.xml schema. When I changed it to version="6", I was then able to add a resource-ref which was then also accepted by glassfish in the glassfish-application.xml.

But there's a complication: I can only declare application-level (java:app/) resources in the application.xml whereas my Datasources in web.xml are component-level (java:comp/env/).

To work around this, I map the resource to an application-level resource in the glassfish-web.xml and then remap it to the correct name in glassfish-application.xml:

foo web.xml:

<resource-ref>
  <res-ref-name>jdbc/FOO-DATASOURCE</res-ref-name>
  <res-type>javax.sql.DataSource</res-type>
  <res-auth>CONTAINER</res-auth>
</resource-ref>

foo glassfish-web.xml:

<resource-ref>
  <res-ref-name>jdbc/FOO-DATASOURCE</res-ref-name>
  <jndi-name>java:app/FOO-DATASOURCE</jndi-name>
</resource-ref>

XXX application.xml (version="6"):

<resource-ref>
  <res-ref-name>java:app/jdbc/FOO-DATASOURCE</res-ref-name>
  <res-type>javax.sql.DataSource</res-type>
  <res-auth>CONTAINER</res-auth>
</resource-ref>

XXX glassfish-application.xml:

<resource-ref>
  <res-ref-name>java:app/jdbc/FOO-DATASOURCE</res-ref-name>
  <jndi-name>java:app/jdbc/XXX-DATASOURCE</jndi-name>
</resource-ref>

This worked but I don't really know why a resource that would be called jdbc/XXX-DATASOURCE in a web.xml file ends up being equivalent to a resource called java:app/jdbc/XXX-DATASOURCE in an application.xml file.

Question:

I managed to deploy and use a JPA connection using the below files. This is currently working, but it's not ideal.

The connection should be using the postgres pool driver, and a JNDI data source rather than a data source in web.xml.

What is the best practice way of deploying a database connection in a JEE container.

Here is my current setup, using a global connection that is not using the pooled driver.

persistence.xml

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<persistence xmlns="http://xmlns.jcp.org/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             version="2.1"
             xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">

    <persistence-unit name="pcc" transaction-type="JTA">
        <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
        <jta-data-source>java:global/pccData</jta-data-source>
        <exclude-unlisted-classes>false</exclude-unlisted-classes>
        <properties>
            <property name="eclipselink.deploy-on-startup" value="true"/>
            <property name="eclipselink.logging.level" value="INFO"/>
            <property name="eclipselink.logging.level.sql" value="CONFIG"/>
            <property name="eclipselink.jdbc.fetch-size" value="1000"/>
            <property name="eclipselink.jdbc.cache-statements" value="true"/>
            <property name="eclipselink.persistence-context.flush-mode" value="commit"/>
            <property name="eclipselink.ddl-generation.output-mode" value="database"/>
        </properties>
    </persistence-unit>

</persistence>

web.xml I am sure PGSimpleDataSource is not the recommended approach

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
         version="3.1">
  <display-name>PCC Web Application</display-name>
  <data-source>
    <name>java:global/pccData</name>
    <class-name>org.postgresql.ds.PGSimpleDataSource</class-name>
    <server-name>localhost</server-name>
    <port-number>5432</port-number>
    <database-name>pcc</database-name>
    <user>postgres</user>
    <password>postgres</password>
    <property>
      <name>fish.payara.slow-query-threshold-in-seconds</name>
      <value>5</value>
    </property>
  </data-source>
</web-app>

Answer:

To answer your question:

What is the best practice way of deploying a database connection in a JEE container?

This is pretty much it.

It doesn't need to be any more complex than the set up you currently have. I assume you have already seen the official Payara-Examples repository but, if not, there is a JPA example there which is configured exactly as you have in your question: https://github.com/payara/Payara-Examples/blob/master/Payara-Micro/jpa-datasource-example/ReadMe.md

As a general point about configuring Payara Micro, you can think of it as a Payara Server in a different package, so if you're still unsure about something and want to do things in the same way as in the more traditional server then you can do.

There are --postbootcommandfile and --postdeploycommandfile options which will allow you to run asadmin commands against Payara Micro and configure it just like Payara Server.

For your connection pool example, if you really wanted to define it in the server (really, defining it in the web.xml as you already have done is more portable and would be my preferred option), then you could start a normal Payara Server, click the button to enable asadmin command recording in the admin console, and then make the changes using the GUI. The necessary commands will then by dumped to a file for you to apply to Payara Micro later.

Payara Micro also dumps out a temporary directory (controllable with --rootDir, by default has the same value as java.io.tmpdir) so you can always see how a configuration change has affected it by inspecting the domain.xml in that directory structure. This gives you some form of manual verification.

Question:

I managed to get camel working with its CDI module, but I'm unable to register datasources in the registry. I basically have a sql route that looks like this:

sql:SELECT * FROM INBOX_DFEP WHERE id > :#lastID?dataSource=jdbc/DFEP

my application server is glassfish 4, and I've registered a jdbc resource with that name, as I usually do with JPA. Anyway camel does not seems to be able to lookup that datasource for me.

org.apache.camel.NoSuchBeanException: No bean could be found in the registry for: jdbc/DFEP of type: javax.sql.DataSource

what am I doing wrong? how do I register a datasource in the camel registry using CDI?


Answer:

You can try this:

public class DataSourceFactory {

@Resource(lookup = "jdbc/DFEP")
private javax.sql.DataSource datasource;

@Produces
@Named("queryDatasource")
public javax.sql.DataSource getDatasource() {
    return datasource;
}

}

After that you only have to change your toute to:

sql:SELECT * FROM INBOX_DFEP WHERE id > :#lastID?dataSource=queryDatasource