0

I've checked in google many hours without good results so i share my code. If you have a better solution i'm very interessed!


The problem is :

I've added a JPA datasource into jboss configuration and i've added some properties

<datasource jta="false" jndi-name="java:/jdbc/MyApp" pool-name="MyApp_main" enabled="true" use-ccm="false">
    <connection-url>jdbc:h2:mem:test;INIT=CREATE SCHEMA IF NOT EXISTS test</connection-url>
    <driver-class>org.h2.Driver</driver-class>
    <connection-property name="hibernate.hbm2ddl.auto">
        create-drop
    </connection-property>
    <connection-property name="hibernate.show_sql">
        true
    </connection-property>
    <driver>h2</driver>
    <validation>
        <validate-on-match>false</validate-on-match>
        <background-validation>false</background-validation>
    </validation>
    <timeout>
        <set-tx-query-timeout>false</set-tx-query-timeout>
        <blocking-timeout-millis>0</blocking-timeout-millis>
        <idle-timeout-minutes>0</idle-timeout-minutes>
        <query-timeout>0</query-timeout>
        <use-try-lock>0</use-try-lock>
        <allocation-retry>0</allocation-retry>
        <allocation-retry-wait-millis>0</allocation-retry-wait-millis>
    </timeout>
    <statement>
        <share-prepared-statements>false</share-prepared-statements>
    </statement>
</datasource>

My persistence.xml :

<?xml version="1.0" encoding="UTF-8"?>
<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="mainDatabase"
        transaction-type="RESOURCE_LOCAL">
        <jta-data-source>java:/jdbc/MyApp</jta-data-source>
        <class>org.company.app.business.class1</class>
        <class>org.company.app.business.class2</class>
        <class>org.company.app.business.class3</class>
        <properties>
            <!-- Scan for annotated classes and Hibernate mapping XML files -->
            <property name="hibernate.archive.autodetection" value="class, hbm" />
        </properties>
    </persistence-unit>
</persistence>

And my code to instanciate the EntityManager :

Persistence.createEntityManagerFactory("mainDatabase");

The problem is that properties hibernate.hbm2ddl.auto and hibernate.show_sql wasn't added to the EntityManager. But these properties exists on datasource when i get it with

final Context lInitCtx = new InitialContext();
final Object lEnvCtx = lInitCtx.lookup(lJNDIName);
final DataSource lWrapperDataSource = (DataSource ) lEnvCtx;

So my solution is :

I've get the JNDI name from EntityManager :

EntityManagerFactory lEntityManagerFactory = Persistence.createEntityManagerFactory("mainDatabase");
final Map<String, Object> lConnectionProperties = lResult.getProperties();

// Extract JNDI name
final String lJNDIName = (String ) lConnectionProperties.get("hibernate.connection.datasource");

I've get datasource with it

final Context lInitCtx = new InitialContext();
final Object lEnvCtx = lInitCtx.lookup(lJNDIName);
final DataSource lWrapperDataSource = (DataSource ) lEnvCtx;

I've extracted properties form this datasource. It's the most bad code of the solution :

final Connection lConnection = lWrapperDataSource.getConnection();
final Field lField = lWrapperDataSource.getClass().getDeclaredField("mcf");
lField.setAccessible(true);
final Object lMCF = lField.get(lWrapperDataSource);
final Field lConnectionProps = lMCF.getClass().getDeclaredField("connectionProps");
lConnectionProps.setAccessible(true);
final Properties lProperties = (Properties ) lConnectionProps.get(lMCF);

I've copied these properties into a map

final Map<String, String> lPersistenceProperties = new HashMap<>();
for (final Entry<Object, Object> lEntry : lProperties.entrySet()) {
    final String lKey = (String ) lEntry.getKey();
    final String lValue = (String ) lEntry.getValue();
    lPersistenceProperties.put(lKey, lValue);
}

And i've re-create the EntityManager with theses properties

lEntityManagerFactory = Persistence.createEntityManagerFactory("mainDatabase", lPersistenceProperties);

Again : If you have a better solution i will very happy to not use reflexion and get private member, use Context, ....

Chklang
  • 857
  • 1
  • 8
  • 17
  • I'm lost - why are you not adding those two properties to your persistence.xml? You already declare one hibernate specific property there (autodetection), just add these two as well. – Gimby May 27 '15 at 08:09
  • I want to give possibility to use Oracle or H2 database. And into my company, if we use Oracle, we must externalize scripts for database creation/evolution. But if it's h2-memory i must do it directly by my webapplication. – Chklang May 27 '15 at 14:36
  • I used two different persistence units for that purpose myself. – Gimby May 27 '15 at 15:19
  • Gimby > And you have persistence-h2.xml /persistence-oracle.xml and you say to user "Rename it into your war" no? I don't want say to users to modify war because installation is automatic. – Chklang May 28 '15 at 11:20

1 Answers1

0

try this code, I used Wildfly, JPA, and jsf:

standalone.xml:

<subsystem xmlns="urn:jboss:domain:datasources:2.0">
            <datasources>
                <datasource jndi-name="java:jboss/datasources/employee" pool-name="MysqlDS2" enabled="true" use-java-context="true">
                    <connection-url>jdbc:mysql://localhost:3306/employee</connection-url>
                    <driver>mysqld</driver>
                    <pool>
                        <min-pool-size>10</min-pool-size>
                        <max-pool-size>20</max-pool-size>
                        <prefill>true</prefill>
                    </pool>
                    <security>
                        <user-name>root</user-name>
                        <password>123456</password>
                    </security>
                </datasource>
                <drivers>
                    <driver name="mysqld" module="com.mysql">
                        <driver-class>com.mysql.jdbc.Driver</driver-class>
                    </driver>
                </drivers>
            </datasources>
        </subsystem>

persistence.xml

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.1"
    xmlns="http://xmlns.jcp.org/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">
    <persistence-unit name="employee" transaction-type="JTA">
        <jta-data-source>java:jboss/datasources/employee</jta-data-source>

        <class>model.Employee</class>
    </persistence-unit>
</persistence>

JPA entity:

@Entity
@Table(name="employees")
@NamedQuery(name="Employee.findAll", query="SELECT e FROM Employee e")
public class Employee implements Serializable {
    private static final long serialVersionUID = 1L;

    @Id
    private int id;

    private String address;

    private String name;

    public Employee() {
    }

    public int getId() {
        return this.id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getAddress() {
        return this.address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    public String getName() {
        return this.name;
    }

    public void setName(String name) {
        this.name = name;
    }

}

JSF Controller:

package com.java.experts.controllers;

import javax.ejb.EJB;

import model.Employee;
import beans.EmployeeBean;

public class EmployeeController {
    @EJB
    EmployeeBean employeeBean;
    Employee emp;


    public EmployeeController() {
        emp=new Employee();

        employeeBean=new EmployeeBean();
    }

    public String add()
    {
        employeeBean.create(emp);
        return "";
    }

    public Employee getEmp() {
        return emp;
    }

    public void setEmp(Employee emp) {
        this.emp = emp;
    }


}

EmployeeBean.java

package beans;

import inteceptors.MyInterceptor;

import javax.ejb.Stateless;
import javax.ejb.TransactionManagement;
import javax.ejb.TransactionManagementType;
import javax.interceptor.Interceptors;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;

import model.Employee;

@Stateless
@TransactionManagement(TransactionManagementType.CONTAINER) // class level
public class EmployeeBean {
     @PersistenceContext(unitName="employee")
       private EntityManager em;

       public void create(Employee... gs) {
           if(em==null)
           {
               System.out.println("entitymanager is null");
               return;

           }


           try {
            for(Employee g : gs) {
                   em.persist(g);
               }
        } catch (Exception e) {
            System.out.println("Error");
            e.printStackTrace();
        }
       }

}

JSF Page:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
    xmlns:ui="http://java.sun.com/jsf/facelets"
    xmlns:h="http://java.sun.com/jsf/html"
    xmlns:f="http://java.sun.com/jsf/core"
    xmlns:p="http://primefaces.org/ui">
<h:head>
</h:head>
<h:body>
    <h:form id="main" prependId="false">


        <table width="100%" border="0" cellpadding="3" cellspacing="0"
            align="center" class="bodyTable">


            <tr>
                <td>
                    <h:inputText value="#{employeeController.emp.name}"></h:inputText>
                </td>
            </tr>
            <tr>
                <td colspan="2"><label> <h:commandButton id="add"
                            action="#{employeeController.add}" value="Add Employee" />
                </label> <label></label></td>
            </tr>
        </table>
    </h:form>
</h:body>
</html>
Safwan Hijazi
  • 2,089
  • 2
  • 17
  • 29
  • I not see any `connection-property` into your standalone.xml. Do you have tried to add some `connection-property` to verify that these properties overrides persistence.xml? – Chklang May 27 '15 at 14:34
  • I created connection in standalone.xml and use it persistence.xml by using JNDI name java:jboss/datasources/employee – Safwan Hijazi May 27 '15 at 14:36
  • all information required to connect to MySql DB are there in standalone.xml – Safwan Hijazi May 27 '15 at 14:37
  • This thing works very well, but i must add **connection-property**! All others things already works. – Chklang May 28 '15 at 11:18
  • This is example how to put connection-property jdbc:mysql://localhost:3306/mydb?useUnicode=true instead of true – Safwan Hijazi May 28 '15 at 11:40
  • Your exemple no instanciate an EntityManager. My problem is with an entitymanager to use javax.* instead of java.* to have generics methods (TypedQuery, ...) – Chklang May 28 '15 at 15:41
  • your question is not clear, I gave example you can use with any database, and with any property you want (hibernate.hbm2ddl.auto and hibernate.show_sql), just add to connection at the end, now your problem in different place, please tell the problem exactly. Your way to create Entity Manager has a problem, in this way you have to handle transactions and pass entity manager from method and class to another method and class, or create another entity manager in new place. – Safwan Hijazi May 28 '15 at 16:06
  • Hum.. ok. I begin to understand your solution... You're rights, i think also that my way to create the EntityManager isn't good. I would use this way last month : `@PersistenceContext(unitName="employee")` `private EntityManager em;` but i had another problem : i must to abstract database management to a "common project", so the unitName="employee" isn't possible in my case : I must use an injected value, not a constant value :/ – Chklang May 29 '15 at 09:14
  • What database abstraction you need? – Safwan Hijazi May 29 '15 at 09:28
  • Hi Safwan Thank you for all these examples. I've been time to try your solution yesterday, and all works except Jboss properties! So when i do @PersistenceContext(unitName = "MyApplicationDatabase") And in jboss i've added some properties on this datasource, but these properties aren't added. To reply to you, i've added an abstraction layer to add automatically controls and basic operations on a DAO (get/delete/getAll, ...). – Chklang Sep 09 '15 at 10:13