How do I make JNDI names compatible with both GlassFish and WildFly

前端 未结 3 1966
花落未央
花落未央 2021-02-06 06:37

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 iss

相关标签:
3条回答
  • 2021-02-06 07:06

    I haven't hit the mail-dilemma just yet. But I've ran into the same problem your having when it comes to data source definition and my solution has been to not setup the data sources using the server's console, but make them deployable together with your archive using the @DataSourceDefinition annotation. Turns out WildFly won't complain about java:app/blabla.. if the data source is setup during deployment!

    Here is a real world example for you that works on both GlassFish and WildFly:

    https://github.com/martinanderssondotcom/java-ee-concepts/../ArquillianDS.java

    Note that the data source JNDI name declared is:

    java:app/env/ArquillianDS

    And here is the related persistence.xml file (don't mind the name of the file in this repository, the repository represents a test project that build archives during runtime and the app will change the name of the file in the archive to persistence.xml):

    https://github.com/MartinanderssonDotcom/java-ee-concepts/../persistence-update.xml

    Also note that the persistence unit need a data source located using this JNDI name:

    java:app/env/ArquillianDS

    This deployment works perfectly fine with both GlassFish and WildFly. I've noted that if we declare the data source during deployment, then we pay the price of not seeing the data source listed anywhere in the admin gui/console. For me, that is a small price to pay in order to have a truly portable application. As an added bonus, I don't have to write lengthy installation/setup instructions. For all my projects, the data source is an intrinsic part of the application and I don't mind having a class file in the archive that represents the data source.

    The above data source is using a Java DB (or "Apache Derby" for old school people). As some comments in the ArquillianDS.java file describe: GlassFish has problems using a simple URL connection string combined with Java DB. Hence I resorted to specifying all attributes of the @DataSourceDefinition explicitly. Recently in another project of mine (alas not a public one), I used the same construct of deployment time data source definition but targeting MySQL. Here's that data source definition and it works on both servers:

    @DataSourceDefinition(
            name = "java:app/env/maLivechatDS",
            url = "jdbc:mysql://localhost:3306/malivechat_db?createDatabaseIfNotExist=true&user=root&password",
            className = "com.mysql.jdbc.jdbc2.optional.MysqlDataSource"
    )
    @ManagedBean
    public class MySQLDataSource { }
    

    Note that the driver is MysqlDataSource and not MysqlXADataSource. One point in my application uses a rather complex transaction scheme and GlassFish ran into problems if I used the XA-driver. However, the non-XA driver used by my application still work properly with JTA transactions so for me, it was just a cheap trick to get the boat floating. You should probably use the XA-driver.

    0 讨论(0)
  • 2021-02-06 07:07

    For JNDI Portability with portable DataSourceDefinition annotation, I test it On payara-5.192, wildfly-17.0.1, tomee-8-M3 and openLiberty-19.0.0.7

    @DataSourceDefinition(
    name = "java:app/env/jdbc/mysql_app_name",
    className = "com.mysql.cj.jdbc.MysqlConnectionPoolDataSource",
    url = "jdbc:mysql://localhost:3306/db_name?characterEncoding=utf-8&zeroDateTimeBehavior=CONVERT_TO_NULL&user=root&password=password",
    minPoolSize = 1,
    properties = {"characterEncoding=utf-8","zeroDateTimeBehavior=CONVERT_TO_NULL"})
    

    I used it with MySQL connector 8. refer to reference. for wildfly I created a startup bean class for configuration and set the annotation in the startup class. for openLiberty add in server.xml

    <application id="app_name" contextRoot="/app_name" name="app_name" location="../app_name.war" type="war">
      <classloader commonLibraryRef="mysql"/>
    </application>
    <library id="mysql">
        <file name="/path_to/mysql-connector-java-8.0.17.jar"/>
    </library>
    

    and put the war file in

    usr/servers/defaultServer

    folder

    0 讨论(0)
  • 2021-02-06 07:11

    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.

    0 讨论(0)
提交回复
热议问题