0. Introduction
I have been googling and found 2 important posts on this matter, they both use Apache DBCP with JPA Hibernate- Boraji.com : No persistence.xml is used. All programmatically.
- Memorynotfound.com : With persistence.xml
- JavaHelps: Simplifies the process of using JPA with Hibernate
However, I want to define the data sources in Tomcat as JNI resource.
1. Create a simple web Maven project
a. Project-New Maven project (check "Create a simple project (skip archetype selection)" and "Use default Workspace location") - Next.
b. Select "WebJPA" for Group Id, Artifact Id and Name. Select Packaging to "war". Optionally provide a Description, Finish.
c. A Maven pom.xml has been created.
d. A properties section is inclosed for detailing java compiler version, encoding, web.xml omitting.
e. A dependencies section for enclosing the needed jars.
e.1 Servlet Api (javax.servlet-api: 4.0.0)
e.2 Oracle implementation of JSF 2.3.3 (javax.faces: 2.3.3)
e.3 Java expresion language evaluation (javax.el-api 3.0.1-b04)
e.4 Primefaces (primefaces: 6.1)
e.5 Weld CDI (weld-servlet-shaded: 3.0.1)
e.6 Project Lombok -setters and getters (lombok: 1.16.18)
e.7 Java Assist -for bytecode manipulation (javassist: 3.22.0-GA)
e.8 Hibernate Core (hibernate-core: 5.2.12.Final)
e.9 Postgres JDBC (postgresql: 42.1.4)
e.10 Hibernate Bean Validator (hibernate-validator: 6.04)
e.11 Apache Tomcat dbcp (tomcat-dbcp: 9.0.1)
The final pom.xml is:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 | <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>WebJPA</groupId> <artifactId>WebJPA</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>war</packaging> <name>WebJPA</name> <properties> <failOnMissingWebXml>false</failOnMissingWebXml> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <maven.compiler.source>1.8</maven.compiler.source> <maven.compiler.target>1.8</maven.compiler.target> </properties> <dependencies> <!-- https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api --> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>4.0.0</version> <scope>provided</scope> </dependency> <!-- JSF 2.3.3 OracleImplementation --> <!-- https://mvnrepository.com/artifact/org.glassfish/javax.faces --> <dependency> <groupId>org.glassfish</groupId> <artifactId>javax.faces</artifactId> <version>2.3.3</version> </dependency> <!-- Expression EL evaluation --> <!-- https://mvnrepository.com/artifact/javax.el/javax.el-api --> <dependency> <groupId>javax.el</groupId> <artifactId>javax.el-api</artifactId> <version>3.0.1-b04</version> </dependency> <!-- Primefaces --> <dependency> <groupId>org.primefaces</groupId> <artifactId>primefaces</artifactId> <version>6.1</version> </dependency> <!-- Weld CDI for Tomcat with all dependencies included (does not fulfill all capabilities !!!) --> <dependency> <groupId>org.jboss.weld.servlet</groupId> <artifactId>weld-servlet-shaded</artifactId> <version>3.0.1.Final</version> </dependency> <!-- https://mvnrepository.com/artifact/org.projectlombok/lombok --> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.16.18</version> <scope>provided</scope> </dependency> <!-- Javassist required by Hibernate in some computers --> <!-- https://mvnrepository.com/artifact/org.javassist/javassist --> <dependency> <groupId>org.javassist</groupId> <artifactId>javassist</artifactId> <version>3.22.0-GA</version> </dependency> <!-- JPA 2.1 Provider --> <!-- https://mvnrepository.com/artifact/org.hibernate/hibernate-core --> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-core</artifactId> <version>5.2.12.Final</version> </dependency> <!--Postgress JDBC 4 --> <!-- https://mvnrepository.com/artifact/org.postgresql/postgresql --> <dependency> <groupId>org.postgresql</groupId> <artifactId>postgresql</artifactId> <version>42.1.4</version> </dependency> <!-- Hibernate Bean Validator Optional --> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-validator</artifactId> <version>6.0.4.Final</version> </dependency> <!-- https://mvnrepository.com/artifact/org.apache.tomcat/tomcat-dbcp --> <dependency> <groupId>org.apache.tomcat</groupId> <artifactId>tomcat-dbcp</artifactId> <version>9.0.1</version> </dependency> </dependencies> </project> |
2. Create the Postgres database
You should have Postgres and PgAdmin installed. For this example, we will create a user "user" with password "password".Enter PgAdmin, and create a database (for instance mydb)
You can optionally create schemas if you want. But for educationnal purposes I will create myschema
3. Create a persistence.xml
First, we will create a simple persitence.xml file with the minimum configuration to access our Postgres database. Have a look at the information in read color. Hibernate should create the entities in the database (hibernate.hbm2ddl.auto=update) and we should provide the URL to the database and login credentials for accessing the database.1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | <persistence 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" version="2.1"> <persistence-unit name="mydb_psu" transaction-type="RESOURCE_LOCAL"> <provider>org.hibernate.jpa.HibernatePersistenceProvider</provider> <properties> <property name="hibernate.dialect" value="org.hibernate.dialect.PostgreSQLDialect" /> <property name="hibernate.hbm2ddl.auto" value="update" /> <property name="hibernate.show_sql" value="true" /> <property name="hibernate.connection.url" value="jdbc:postgresql://localhost:5432/mydb" /> <property name="hibernate.connection.driver_class" value="org.postgresql.Driver" /> <property name="hibernate.connection.username" value="user" /> <property name="hibernate.connection.password" value="password" /> </properties> </persistence-unit> </persistence> |
As mentioned in this blog, we will put it in the src/main/resources/META-INF/persistence.xml
4. Create a simple entity (MyEntity.java)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 | package model; import java.io.Serializable; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.Table; import javax.persistence.Transient; import javax.validation.constraints.NotNull; import javax.validation.constraints.Size; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; @Entity @Table(name = "myentity", schema = "util") @NoArgsConstructor() public class MyEntity implements Serializable { private static final long serialVersionUID = 20171201L; @Getter @Id @GeneratedValue(strategy=GenerationType.IDENTITY) private Short id; /** attribute that contains the description, unique value*/ @Size(max = 50) @NotNull () @Column(unique = true) @Getter @Setter private String description; /** Transient attribute that means that the system should make a log on any JPA operation of this class*/ @Transient @Getter private boolean ok = true; /** Setters*/ public void setId(Number id) { this.id = id.shortValue(); } } |
Now you should go to PgAdmin and create the database "mydb" and the schema "util"
5. Create a Bootstrap class (HibernateBootstrap.java)
This class lets Hibernate create the entity in the DB. Thi class should have a main method that creates an EntityManagerFactory, and then closes the EntityManagerFactory. In this process, the entity(table) will be created in the database.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | package bootstrap; import javax.enterprise.context.SessionScoped; import javax.inject.Named; import javax.persistence.EntityManager; import javax.persistence.EntityManagerFactory; import javax.persistence.Persistence; @Named @SessionScoped public class HibernateBootstrap implements Serializable { public static void updateSchema() { EntityManagerFactory emf = Persistence.createEntityManagerFactory("mydb_psu"); emf.close(); } public static void main(String[] args) { updateSchema(); } } |
This class has been annotated by @Named and @SessionScoped so that it can be used as a bean in a xhtml file.
Up till now our project structure (Maven) is this one:
src/main/java (Java resources folder)
|--model (package)
|--MyEntity.class
|--bootstrap (package)
|--HibernateBootstrap.java
src/main/resources
|--META-INF (folder)
|--persistence.xml (JPA configuration)
6. Executing HibernateBootStrap as a Java Application
As this class has a main method, it can be executed (Right-Click - Run As - Java Appliction.Let's see the DDL that generates Hibernate:
create table util.myentity (id serial not null, description varchar(255), primary key (id))
alter table util.myentity drop constraint UK_oqxmbwpgnxdnw0hi1683s3n9a
alter table util.myentity add constraint UK_oqxmbwpgnxdnw0hi1683s3n9a unique (description)
In order to create the table field of a length of 50, this annotation should have been used @Column (length=50). See Stackoverflow.
But when executed in a web environment, this annotation is taken into account, and the DDL sentence is correct, see my posted question in Stackoverflow again.
But in the next part of this blog, when we create the table using Tomcat JNDI data source, this @Size annotation is used to create correctly the field.
7. Defining a Tomcat JNDI DataSource
The webapp folder that is in- Deployed Resources (in the eclipse project view)
- src/main (in the project folder)
It should be created the META-INF folder into the webapp folder. In the META-INF folder, we will create the context.xml file that will contain the definition of the Datasource that Tomcat will use. Remember this file is located in the project folder into :
src/main/webapp/META-INF/context.xml
(Remember that the persistence.xml should be placed in another META-INF folder located in src/main/resources folder!)
This is the content of the contex.xml file:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | <Context path="/mydb" docBase="mydb" debug="5" reloadable="true" crossContext="true"> <Resource name="mydb_rsc" auth="Container" type="javax.sql.DataSource" username="user" password="paswword" maxTotal="50" maxIdle="20" maxWait="10000" driverClassName="org.postgresql.Driver" url="jdbc:postgresql://localhost:5432/mydb"/> /> </Context> |
AS you can see, we have defined a connection pool and the connection URL and credentials for accessing the database.
The only important name is the resource name "mydb_rsc"
8. Updating persistence.xml to focus the JNDI Datasource
Now, we need to connect to the JNDI DataSource. The persistence.xml should look as follows:1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | <persistence 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" version="2.1"> <persistence-unit name="mydb_psu" transaction-type="RESOURCE_LOCAL"> <provider>org.hibernate.jpa.HibernatePersistenceProvider</provider> <jta-data-source>java:comp/env/mydb_rsc</jta-data-source> <properties> <property name="hibernate.dialect" value="org.hibernate.dialect.PostgreSQLDialect" /> <property name="hibernate.hbm2ddl.auto" value="update" /> <property name="hibernate.show_sql" value="true" /> </properties> </persistence-unit> </persistence> |
Note the highlighted line which makes reference to the datasource. The prefix java:comp/env is added to the resource name mydb_rsc.
Now we need to create a xhtml page with a button that points to HibernateBootstrap.updateSchema to order Hibernate to create the entities. But we need to delete now created entities!
9. A simple xhtml
We have only one button, to perform the schema update. Here is create-table-page.xhtml1 2 3 4 5 6 7 8 9 10 11 12 13 | <html xmlns="http://www.w3.org/1999/xhtml" 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> <p:commandButton value="Create Tables" action="#{hibernateBootstrap.updateSchema}"/> </h:form> </h:body> </html> |
10. Completing the project structure as JSF web application
As mentioned in an older post, we have to provide additional files to the webapp folder to fulfil a JSF web application pattern.
1. Create WEB-INF folder in the webapp folder
2. Create an empty file beans.xml into the WEB-INF folder
3. Create the file faces-config.xml with this content:
1
2
3
4
5
6
7
8
<?xml version="1.0" encoding="UTF-8"?>
<faces-config
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-facesconfig_2_2.xsd"
version="2.2">
</faces-config>
11. Executing the page create-table-page.xhtml on the Server
1 2 3 4 5 6 7 8 | <?xml version="1.0" encoding="UTF-8"?> <faces-config 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-facesconfig_2_2.xsd" version="2.2"> </faces-config> |
Rember to delete myentity table in the database!
Place the mouse on the page and Right-click - Run on Server , press the button
and see the generated DDL sentences:
create table util.myentity (id serial not null, description varchar(50) not null, primary key (id))
alter table util.myentity drop constraint UK_oqxmbwpgnxdnw0hi1683s3n9a
alter table util.myentity add constraint UK_oqxmbwpgnxdnw0hi1683s3n9a unique (description)
Hi,
ReplyDeleteThank you for your help, nice paper ^^