Copyright (c) 2014 Oracle and/or its affiliates. All rights reserved.
You may not modify, use, reproduce, or distribute this software except in compliance with the terms of the License at: http://java.net/projects/javaeetutorial/pages/BerkeleyLicense
Please find the Oracle dukes-forest tutorial documentation at Duke's Forest Case Study Example
This document is divided into Installation and running and Notes on changes to the original source
-
Date 02/2106
-
Clone git repository
git clone https://github.com/karlnicholas/dukes-forest.git
.
-
Create a schema in MySQL named
forest
in lowercase. I used the workbench. -
Create the database user and password in your
MySQL
server. Give this user full privileges to theforest
schema. This username and password will need to be added to yourForest
datasource. -
Create the schema. There is an issue with having JPA auto create the schema and load the data. It works, but it works for both dukes-shipment and dukes-store. The create sql script won't create the database twice, but the load sql script will load twice, so let's just do it by hand because I have commented out the create and load properties in the entities persistence.xml file. The create.sql script is in
entities/src/main/resources/META-INF/sql/create.sql
. -
Load the default data. The load data.sql script is in
entities/src/main/resources/META-INF/sql/data.sql
.
-
Pick a Wildfly configuration file to work with: Be sure you are running the
standalone-full
version., or at least have JMS messaging enabled ( I used the standalone-full.xml, I don't know the exact configuration needed, but standalone-full.xml worked). -
You can either edit and run the wildfly-commands.cli command line file found in dukes-forest/wildfly-commands.cli, you can can manually do each step below.
-
Add
XA
mysql jdbc driver module to Wildfly if you have not already done so. See Example MySQL XA Datasource for example. -
Add a
XA
datasource and driver to wildfly. See Example MySQL XA Datasource for example. Set the jndi-namejava:jboss/ForestXADS
and nameForestXADS
. This can be done through the management console, or by copying and pasting the XML snippet shown in the notes below. Be sure the datasource is enabled and you can sucessfully test the connection from the wildfly management console.<datasources> <xa-datasource jndi-name="java:jboss/ForestXADS" pool-name="ForestXADS" enabled="true"> <driver>com.mysql</driver> <xa-datasource-property name="URL">jdbc:mysql://localhost:3306/forest</xa-datasource-property> <security> <user-name>forest</user-name> <password>forest</password> </security> </xa-datasource> <drivers> <driver name="mysql" module="com.mysql"> <datasource-class>com.mysql.jdbc.Driver</datasource-class> <xa-datasource-class>com.mysql.jdbc.jdbc2.optional.MysqlXADataSource</xa-datasource-class> </driver> </drivers> </datasources>
and ...
<driver name="mysql" module="com.mysql"> <xa-datasource-class>com.mysql.jdbc.jdbc2.optional.MysqlXADataSource</xa-datasource-class> </driver>
-
Add a message queue wildfly named OrderQueue, as per specs below.
<jms-queue name="OrderQueue"> <entry name="java:global/jms/queue/OrderQueue"/> <durable>true</durable> </jms-queue>
-
Add a security-domain to wildfly named dukes-forest, as per specs below. Note that on unix systems the queries are case sensitive.
<security-domain name="dukes-forest" cache-type="default"> <authentication> <login-module code="org.jboss.security.auth.spi.DatabaseServerLoginModule" flag="required"> <module-option name="dsJndiName" value="java:jboss/ForestXADS"/> <module-option name="rolesQuery" value="select NAME as 'ROLES', 'Roles' as 'ROLEGROUP' from forest.GROUPS g inner join forest.PERSON_GROUPS pg on g.ID = pg.GROUPS_ID join forest.PERSON p on p.EMAIL = pg.EMAIL where p.EMAIL = ?"/> <module-option name="hashAlgorithm" value="MD5"/> <module-option name="hashEncoding" value="HEX"/> <module-option name="principalsQuery" value="select PASSWORD from forest.PERSON where EMAIL=?"/> </login-module> </authentication> <authorization> <policy-module code="org.jboss.security.auth.spi.DatabaseServerLoginModule" flag="required"> <module-option name="dsJndiName" value="java:jboss/ForestXADS"/> <module-option name="rolesQuery" value="select NAME as 'ROLE', 'ROLES' as 'ROLEGROUP' from forest.GROUPS g inner join forest.PERSON_GROUPS pg on g.ID = pg.GROUPS_ID join forest.PERSON p on p.EMAIL = pg.EMAIL where p.EMAIL = ?"/> <module-option name="hashAlgorithm" value="MD5"/> <module-option name="hashEncoding" value="HEX"/> <module-option name="principalsQuery" value="select PASSWORD from forest.PERSON where EMAIL=?"/> </policy-module> </authorization> </security-domain>
-
Run
mvn clean verify
from the dukes-forest directory. This will build 3 jar files and 3 war files,events.jar
,entities.jar
,dukes-resources.jar
, anddukes-payment.war
,dukes-shipment.war
, anddukes-store.war
, in that order. -
Run
mvn install
from the dukes-forest directory, so that the jars will be put into your repository. -
Deploy dukes-payment, dukes-shipment, and dukes-store to wildfly. This can be done by running
mvn wildfly:deploy
from each subdirectory, or by copying the .war files to the wildfly-9.0.2.Final/standalone/deployments directory, or by using EclipseRun->Run on Server
. There was an issue here. See Schema not generated if Entities and Persistence.xml in another jar. Since dukes-forest has its entities in the entities.jar, the database create scripts would not get executed if you deployed from maven or copied the .war files manually. OnlyRun on Server
from Eclipse worked. There was also a problem because both the dukes-shipment.war and the dukes-store.war have the entities.jar in them. The entities.jar has the persistence.xml file, which was configurated to tell the server to create the database and load the default data. That means it was done twice, which was problematic. The issue doesn't apply because the created the schema was created and loaded manually as per the database procedures above. -
Open
http://localhost:8080/dukes-store
to run dukes-store. You will need the built-in administrator account to login to dukes-shipment, which is username=admin@example.com and password=1234. -
Refer to the Duke's Forest Case Study Example tutorial for further information on using the example.
Port of Dukes-Forest tutorial to Wildfly 9 and MySql 5.6.
-
Date: 10/2015
-
Created projects for jboss developer studio 9.0 ga, eclipse 4.5 (Mars). dukes-payment, dukes-resources, dukes-shipment, dukes-store, entities, events.
-
Changed entities/src/main/resources/META-INF/persistence.xml to comment out the drop-create properties.
-
Fixed up Database scripts and model. I used the dukes-forest-model.mwb, the MySQL workbench EER Diagram. The diagram was out of sync with the entities/src/main/resources/META-INF/sql/create.sql script. Mostly the differences included auto increment of indexes, non-null fields, and, more importantly, the length of various var-char fields. Also, there was an issue with a Foreign Key Index on the Product table being named the same as the Foreign Key.
-
Changed entities/src/main/resources/META-INF/persistence.xml to use java:jboss/ForestXADS instead of java:global/ForestXADS.
-
Added java:jboss/ForestXADS datasource and mysql driver in standalone-full.xml.
<datasources> <xa-datasource jndi-name="java:jboss/ForestXADS" pool-name="ForestXADS" enabled="true"> <driver>com.mysql</driver> <xa-datasource-property name="URL">jdbc:mysql://localhost:3306/forest</xa-datasource-property> <security> <user-name>forest</user-name> <password>forest</password> </security> </xa-datasource> <drivers> <driver name="mysql" module="com.mysql"> <datasource-class>com.mysql.jdbc.Driver</datasource-class> <xa-datasource-class>com.mysql.jdbc.jdbc2.optional.MysqlXADataSource</xa-datasource-class> </driver> </drivers> </datasources>
and ...
<driver name="mysql" module="com.mysql"> <xa-datasource-class>com.mysql.jdbc.jdbc2.optional.MysqlXADataSource</xa-datasource-class> </driver>
-
Created appropriate queue in Wildfly and made Eclipse run Wildfly with standalone-full.xml so that JMS services would be available.
<jms-queue name="OrderQueue"> <entry name="java:global/jms/queue/OrderQueue"/> <durable>true</durable> </jms-queue>
-
Changed dukes-shipment/src/main/java/com.forest.shipment.ejb.OrderBrowser to use jboss compatible jndi name for jms message queue.
@Resource(mappedName = "java:global/jms/queue/OrderQueue")
-
Changed dukes-store/src/main/java/com/forest/ejb/OderJMSManager.java to use jboss compatible jndi name for jms message queue.
name = "java:jboss/jms/queue/OrderQueue", @Resource(mappedName = "java:global/jms/queue/OrderQueue")
-
Removed src/main/webapp/WEB-INF/glassfish-web.xml in dukes-payment, dukes-shipment and dukes-store projects. Added jboss-web.xml set to dukes-forest security domain in WEB-INF directory.
<?xml version="1.0" encoding="UTF-8"?> <jboss-web> <security-domain>dukes-forest</security-domain> </jboss-web>
-
Added dukes-forest security-domain in standalone-full.xml. Added both authentication and authorization sections.
Had to work out the correct rolesQuery and principalsQuery sql statements to use the database for authentication.<security-domain name="dukes-forest" cache-type="default"> <authentication> <login-module code="org.jboss.security.auth.spi.DatabaseServerLoginModule" flag="required"> <module-option name="dsJndiName" value="java:jboss/ForestXADS"/> <module-option name="rolesQuery" value="select NAME as 'ROLES', 'Roles' as 'ROLEGROUP' from forest.GROUPS g inner join forest.PERSON_GROUPS pg on g.ID = pg.GROUPS_ID join forest.PERSON p on p.EMAIL = pg.EMAIL where p.EMAIL = ?"/> <module-option name="hashAlgorithm" value="MD5"/> <module-option name="hashEncoding" value="HEX"/> <module-option name="principalsQuery" value="select PASSWORD from forest.PERSON where EMAIL=?"/> </login-module> </authentication> <authorization> <policy-module code="org.jboss.security.auth.spi.DatabaseServerLoginModule" flag="required"> <module-option name="dsJndiName" value="java:jboss/ForestXADS"/> <module-option name="rolesQuery" value="select NAME as 'ROLE', 'ROLES' as 'ROLEGROUP' from forest.GROUPS g inner join forest.PERSON_GROUPS pg on g.ID = pg.GROUPS_ID join forest.PERSON p on p.EMAIL = pg.EMAIL where p.EMAIL = ?"/> <module-option name="hashAlgorithm" value="MD5"/> <module-option name="hashEncoding" value="HEX"/> <module-option name="principalsQuery" value="select PASSWORD from forest.PERSON where EMAIL=?"/> </policy-module> </authorization> </security-domain>
-
Changed /src/main/java/webapp/WEB-INF/web.xml for dukes-shipment and dukes-shop projects to use dukes-forest security domain for login.
<!--Defining security constraint for type of roles available --> <security-constraint> <web-resource-collection> <web-resource-name>Secure Pages</web-resource-name> <description/> <url-pattern>/admin/*</url-pattern> </web-resource-collection> <auth-constraint> <role-name>ADMINS</role-name> </auth-constraint> </security-constraint> <!--Defining security constraint for type of roles available --> <!--Defining type of authentication mechanism --> <login-config> <auth-method>FORM</auth-method> <realm-name>dukes-forest</realm-name> <form-login-config> <form-login-page>/login.xhtml</form-login-page> <form-error-page>/login.xhtml</form-error-page> </form-login-config> </login-config> <!--Defining type of authentication mechanism --> <!--Defining security role --> <security-role> <role-name>ADMINS</role-name> </security-role> <!--Defining security role -->
-
Changed /src/main/java/webapp/WEB-INF/web.xml for dukes-payment project to security-contraints for login.
<security-constraint> <web-resource-collection> <web-resource-name>Secure payment service</web-resource-name> <description/> <url-pattern>/*</url-pattern> <http-method-omission>GET</http-method-omission> </web-resource-collection> <auth-constraint> <role-name>USERS</role-name> </auth-constraint> </security-constraint> <login-config> <auth-method>BASIC</auth-method> </login-config> <security-role> <role-name>USERS</role-name> </security-role>
-
Changed entities/src/main/java/com/forest/entity/Person.java to make fetch of groupsList EAGER instead of LAZY, which is was by default.
@ManyToMany(cascade = CascadeType.ALL, fetch=FetchType.EAGER ) protected List<Groups> groupsList;
-
Commented out the "data-source" from web.xml for dukes-store project.
-
Changed com.forest.handlers.PaymentHandler to use "Basic " instead of "BASIC " for the "Authorization" header. See WildFly issue HTTP Authentication Basic header is case sensitive.
-
Added @JsonIgnore to com.forest.entity.CustomerOrder.setCustomer(Person person) because it was a duplicate signature with CustomerOrder.setCustomer(Order order) and causing problems with JSON serialization.
@JsonIgnore public void setCustomer(Person person) { this.customer = (Customer) person; }
-
Added fetch=FetchType.EAGER to orderDetailList in com.forest.entity.CustomerOrder because lazy initialization was failing when used CustomerOrder was being used as a service by dukes-shipping.
@OneToMany(cascade = CascadeType.ALL, mappedBy = "customerOrder", fetch=FetchType.EAGER)
-
Added code to com.forest.ejb.UserBean in dukes-store project to add USERS role to new users, otherwise new users would not be able to sign in.
Query createNamedQuery = getEntityManager().createNamedQuery("Groups.findByName"); createNamedQuery.setParameter("name", "USERS"); if (createNamedQuery.getResultList().size() > 0) { customer.getGroupsList().add( (Groups)createNamedQuery.getSingleResult()); super.create(customer); return true; } else { return false; }
-
Issues about upper/lower case table and field names in MySQL when running on UNIX. COnverted everything to UPPERCASE. Tried lowercase, but hiberate generated names in uppercase.