OSGi and JPA: Websphere/RAD Workbook
Development Platform and Tools:
- Windows 7-64
- Rational Application Developer v9 (beta)
- Linux/CentOS v6.3 OS
- Websphere Application Server v8.5
- Database: DB2 v9.7 sp7
Reference:
Apache ARIES Blueprint tutorial
Blueprint Services by Guillaume Nodet (slideshare)
Resources:
OSGi and JPA on Websphere Application Server v8.5
1) Create a Database and Table
Using the DB2 tools (Control Center)
2a) Create a Websphere Application Server
I used the Profile Management Tool (PMT). I'm using a "stand alone" (not ND) application server because Rational doesn't require a jython/wasadmin script to deploy into this configuration.
2b) In Websphere Console, Create a JAAS - J2C authentication
Global security > JAAS - J2C authentication data > new
3) In Websphere Console, Create a DataSource
Resources -> Data sources -> new
NOTE: You may need to add the DB2 drivers to Websphere
After creating the datasource... "Test Connetion"
4) Create Database Connection
From Rational Application Developer (RAD)
Create a Database Connection
Right click Database Connections -> new
Connection Parameters
After connection is created, you should be able to browse to the test table
5) Create JPA OSGi Bundle Project
From Rational Application Developer (RAD)
NOTE: Runtime and Server configured for Websphere v8.5. For development I use the "stand-alone" (not ND) application server because RAD doesn't require a wasadmin script to deploy into this environment.
Top-menu: File -> New -> Other -> filter Wizard on "osgi" ->OSGi Bundle Project
- Next
Configure OSGi Bundle Project for JPA
- check "add persistence support" - JPA 2.0
- uncheck "add bundle to application (we'll create an application later for this project)
-> Next
Change the Active Target Platform (if required)
I was previously working on Websphere Liberty...
Java
- leave defaults
Configure JPA Facet
NOTE: I'm going to try some Junit testing with this project... so I added the "driver library to build path". Normally, this isn't necessary because we'll be using a Websphere provided datasource.
-> Next
OSGi Bundle settings
-> Finish
OSGi JPA Project Created
6) Create JPA Entity
Right-click the jpa project -> JPA Tools -> Generate Entities from Tables
Select Tables
-> Next
Table Associations (none for this example)
-> Next
Defaults (no changes required)
- no key generator
- creating a package: model
- no superclass
-> Next
More options... Customize Individual Entities (none required)
-> Finish
Color Entity Created
Configure Entity: Color
Right-click project -> JPA Tools -> Configure JPA Entities...
Select the Entity: Color (for our example)
-> Next
Primary Key
- colorCode
Relationships
- Not using "relationships" in this example
Named Queries
-> Add
Add Named Query: Result Attributes
Add Named Query: Order Results
Move colorcode into the "Order Attributes"
-> OK
Tasks: Other
Make sure "convert Java set objects to Java list objects" is checked
-> Finish
Color.java (should look something like what's listed below)
===========
package model;
import java.io.Serializable;
import javax.persistence.*;
/**
* The persistent class for the COLORS database table.
*
*/
@Entity
@Table(name="COLORS")
@NamedQuery(name = "getColor", query = "SELECT c FROM Color c ORDER BY c.colorCode")
public class Color implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@Column(name="COLOR_CODE")
private String colorCode;
@Column(name="COLOR_NAME")
private String colorName;
public Color() {
}
public String getColorCode() {
return this.colorCode;
}
public void setColorCode(String colorCode) {
this.colorCode = colorCode;
}
public String getColorName() {
return this.colorName;
}
public void setColorName(String colorName) {
this.colorName = colorName;
}
}
===========
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 ="jpa_osgi_example_01" transaction-type="RESOURCE_LOCAL" >
<jta-data-source >jdbc/JPA_TEST </ jta-data-source>
<non-jta-data-source >jdbc/JPA_TEST</ non-jta-data-source>
<class >model.Color </class >
</persistence-unit >
</persistence>
7) Create JPA Entity Manager (Manager Bean)
NOTE: See appendix (bottom of page) for full source list
Right-click project -> JPA Tools -> Add JPA Manager Beans
JPA ManagerBean Wizard
- Select Color Entity
-> Next
Tasks: Other
- select "I want the container to inject the persistence unit..."
- We'll be generating an interface for BluePrint. So, add the "Impl" suffix to the generated Bean Name.
-> Finish
Controller Created
- We'll follow the RAD package naming conventions for now
Note the "persistence injection"
- NOTE: Don't forget to add in the "unitName" value. This is the "persistence-unit name" from "persitsence.xml".
- We'll get Blueprint to make this happen
@SuppressWarnings("unchecked" )
@JPAManager(targetEntity = model.Color.class)
public class ColorManagerImpl {
// @PersistenceUnit
@PersistenceUnit(unitName="jpa_osgi_example_01") // NOTE: Added this in for now - will set later in blueprint
private EntityManagerFactory emf;
@Resource
private UserTransaction utx;
public ColorManager() {
}
Generate an Interface from the ColorManagerImpl
right-click ColorManagerImpl -> Refactor -> Extract interface
- check "Declare interface methods as public"
- uncheck "Declare interface methods as abstract"
-> OK
Generated Interface ColorManager
-------------
package model.controller;
import java.util.List;
import model.Color;
import com.ibm.jpa.web.Action;
import com.ibm.jpa.web.NamedQueryTarget;
public interface ColorManager {
public void createColor(Color color) throws Exception;
public void deleteColor(Color color) throws Exception;
public void updateColor(Color color) throws Exception;
public Color findColorByColorCode(String colorCode);
public Color getNewColor();
public List<Color> getColor();
}
------------
7a) Make sure the JTA datasource matches your Websphere datasource!
I had to go back and change "jpa_test" to upper-case (new value: jdbc/JPA_TEST)
8) Add Blueprint to JPA OSGI Bundle
Blueprint helps us manage component instances and their interdependencies/wiring to each other.
right-click project -> new -> under osgi -> blueprint file
-> next
leave default name and location:
[project_name]/BundleContent/OSGI-INF/blueprint
-> next
Only using the standard features for now (no IBM proprietary extensions or security)
-> Finish
Blueprint file created
Add Bean
right-click Blueprint -> select Bean
-> OK
1) Browse for the ColorManagerImple
2) Filter on the package path
3) Select ColorManagerImpl (within model.controller)
4) Make sure you're looking within the correct project!
5) OK
NOTE: Make sure you pick the class from the correct project!
Accept the default assigned Bean ID name
-> OK
Create a Service
Select Blueprint -> Click add -> Select Service
-> OK
NOTE: We'll reference the service from within other components
1) Click Brows
2) filter on model.controller package
3) Select the interface: ColorManager (from within model.controller package)
4) Make sure you pointing to the correct project!
5) OK
(continued)
6) Click browse for "Bean Reference"
7) Select the Bean we just created above, "ColorManagerImplBean"
8) OK
Leave the default generated Service ID name
-> OK
ColorManagerImpleBeanService (service) created
Showing relationship between interface, implementation, bean and service
Adding some methods for notification purposes only
- This helps us track state as we create and test our JPA bundle service
Add this to the interface:
public void startUp();
public void onRegisterService(ColorManager colorManager, Map props);
public void onUnRegisterService(ColorManager colorManager, Map props);
public void referenceBind(ColorManager colorManager);
public void referenceUnBind(ColorManager colorManager);
Implementations:
@Override
public void startUp() {
System. out.println( "*** ColorManagerImpl.startUp()");
}
@Override
public void onRegisterService(ColorManager colorManager, Map props) {
System. out.println( "*** ColorManagerImpl.startUp()");
}
@Override
public void onUnRegisterService(ColorManager colorManager, Map props) {
System. out.println( "*** ColorManagerImpl.onUnRegisterService()");
}
@Override
public void referenceBind(ColorManager colorManager) {
System. out.println( "*** ColorManagerImpl.referenceBind()");
}
@Override
public void referenceUnBind(ColorManager colorManager) {
System. out.println( "*** ColorManagerImpl.referenceUnBind()");
}
Set Initialization method to "startUp"
using "blueprint" editor
Add RegisterService Listeners
1) Select ColorManagaerImplBleanService
2) Add
3) Reigstration listener
-> OK
Fill in property details for Registration Listener
NOTE: Bind listeners will be added next step
blueprint.xml
-------------------------
<?xml version="1.0" encoding= "UTF-8"?>
<blueprint xmlns= "http://www.osgi.org/xmlns/blueprint/v1.0.0" xmlns:bpjpa= "http://aries.apache.org/xmlns/jpa/v1.0.0" xmlns:bptx= "http://aries.apache.org/xmlns/transactions/v1.0.0" xmlns:bpresref="http://www.ibm.com/appserver/schemas/8.0/blueprint/resourcereference" >
<bean id ="ColorManagerImplBean"
class= "model.controller.ColorManagerImpl" init-method= "startUp">
<!-- <bptx:transaction method="*" value="Required"/> -->
<!-- <bpjpa:unit property=" emf" unitname="jpa_osgi_example_01"/> -->
</bean >
<service id ="ColorManagerImplBeanService" ref= "ColorManagerImplBean"
interface= "model.controller.ColorManager">
<registration-listener ref ="ColorManagerImplBean" registration-method="onRegisterService" unregistration-method="onUnRegisterService" />
</service >
</blueprint>
Export the model and controller so it's available for other bundles
Edit the MANIFEST.MF and export the two packages
Runtime tab -> Exported Packages
1) Add
2) select model and model.controller
3) OK
9) Create JPA Test Harness
Because OSGi can be a little difficult to unit-test... well, I wasn't able to get jUnit running well enough for a test. So, quick workaround is to simply role-a-custom unit test harness for now (PaxExam is the recommended approach - and we'll get to that later).
This will be yet-another OSGi bundle that tests the JPA bundle...
Create a Test OSGi bundle project - named: jpa_osgi_example_01_test
Accept defaults except that we set the versio nto "1.0.0"
-> Finish
Create a blueprint that we'll use to wire into the jpa bundle
accept defaults except for setting support for: JPA, Transaction, and Resource Reference
-> Finish
Blueprint ready to be used for connecting into JPA project
Import Packages
Edit MANIFEST.MF
Dependencies tab
1) Imported Packages -> Add
2) Select the "model" and "model.controller" packages
3) OK
Create a simple test class
- add a property and setter for reference to ColorManager (the thing we'll be testing)
- add one method for now: startUp()
package jpa_tests;
import model.controller.ColorManager;
public class JpaExampleTest {
private ColorManager colorManager = null ;
public ColorManager getColorManager() {
return colorManager;
}
public void setColorManager(ColorManager colorManager) {
this. colorManager = colorManager;
}
public void startUp() {
System. out.println( "*** CJpaExampleTest.startUp CALLED");
}
}
Configure blueprint to wire JpaExampleTest the ColorManager...
Create a "Bean" for JpaExampleTest
NOTE: Moving more quickly through the tutorial since we already covered bean and service creation...
- Set "initialization method" to our "startUp()" method
In blueprint, create a Reference to ColorManager service
1) Select "Blueprint"
2) click Add
3) Select Reference
4) OK
(continued...)
5) Click Browse
6) Filter on "model.controller." package
7) Select the interface from the jpa_osgi_example_01 project
8) verify we're pointing to the correct project and interface
9) OK
(continued...)
10) manually type in the ID we'll use: ColorManagerReference
11) OK
NOTE: Do Not set "component name" (for some reason this prevented the reference from working correctly)
blueprint reference created
NOTE: Leave component name blank!
Create a Reference Listener for the ColorManagerReference
1) select ColorManagerReference
2) Click Add
3) Select Reference Listener
4) OK
Add details to Reference Listener
1) Browse and select ColorManagerReference (don't leave it blank...)
2) Browse to referenceBind and referenceUnBind methods we created in ColorManager/ColorManagerImpl
Add a blueprint Property to JpaExampleTestBean
1) Select ColorManagerReference
2) Click Add
3) Select Property
4) OK
(continued...)
5) With colorManager Property selected
6) type in the property name used in JpaExapmleTest class
7) Browse Reference
8) select ColorManagerReference
9) OK
Slightly confusing map of pointers between blueprint and java classes
blueprint.xml
---------------------------
<?xml version="1.0" encoding= "UTF-8"?>
<blueprint xmlns= "http://www.osgi.org/xmlns/blueprint/v1.0.0" xmlns:bpjpa= "http://aries.apache.org/xmlns/jpa/v1.0.0" xmlns:bptx= "http://aries.apache.org/xmlns/transactions/v1.0.0" xmlns:bpresref="http://www.ibm.com/appserver/schemas/8.0/blueprint/resourcereference" >
<bean id ="JpaExampleTestBean" class= "jpa_tests.JpaExampleTest"
init-method= "startUp">
<property name ="colorManager" ref= "ColorManagerReference"/>
</bean >
<reference id ="ColorManagerReference"
interface= "model.controller.ColorManager">
<reference-listener bind-method ="referenceBind" unbind-method="referenceUnBind" ref ="ColorManagerReference"/>
</reference >
</blueprint>
10) Create an OSGi app and Deploy
- run a quick "sanity" check to make sure everything is in-place prior to coding our actual tests
Create an OSGi Application Project
-> Next
Naming it something identifiable... example: jpa_osgi_example_01_test_app
-> Next
Add our two OSGi bundles
- jpa_osgi_example
- jpa_osgi_example test
-> Finish
Add the OSGi app to our Websphere Server
-> Finish
Debugging...
Well, I did have a few errors (and yes... I did update the instructions!)
My mistakes:
1) Forgot (somehow) to save the jpa_osgi_example_01_test blueprint. Didn't have a required reference value...
2) Forgot to add "unitName" to ColorManagerImple "@PersistenceUnit" annotation
-> @PersistenceUnit(unitName="jpa_osgi_example_01") We'll later migrate this setting/value into blueprint
3) copy/paste error... pasted the "startup" sys'out message into the "onRegisterService" callback
I noticed the "waiting for" message on Websphere's "SystemOut.log" - this usually means something was missed. The missing "unitName" value caused the blueprint service to wait... (but since I've already made that mistake a few times - was easy to fix). I'll cover adding the property later in the blueprint itself.
If everything is working properly, the startup and listener callbacks should report:
- using CentOS v6.3 KDE console ("konsole") with a "find" left looking for "***" prefixes to all my "systemout" messages
1) ColorManagerImple.startUp() - we have ignition...
2) ColorManagerImple.onRegisterService() - service registers with manager (called twice due to it being referenced by our test)
3) ColorManagerImple.referenceBind() - The jpa_osgi_exapmle_01_test binds to the (above) published (registered) interface
4) JpaExampleTest.startUp() - The test harness starts and is ready... for testing!
Test Code (roll-your-own... )
Couldn't get something simple like junit running within OSGi
See appendix for "JpaExampleTest.java" test code.
- Tests execute within the "startUp()" method that's set to run, via blueprint, at jpa_osgi_example_01_test app startup
APPENDIX
---------------------------------------
ColorManager.java (interface)
---------------------------------------
package model.controller;
import java.util.List;
import java.util.Map;
import model.Color;
import com.ibm.jpa.web.Action;
import com.ibm.jpa.web.NamedQueryTarget;
public interface ColorManager {
public void createColor(Color color) throws Exception;
public void deleteColor(Color color) throws Exception;
public void updateColor(Color color) throws Exception;
public Color findColorByColorCode(String colorCode);
public Color getNewColor();
public List<Color> getColor();
// notifications
// --------------------
public void startUp();
public void onRegisterService(ColorManager colorManager, Map props);
public void onUnRegisterService(ColorManager colorManager, Map props);
public void referenceBind(ColorManager colorManager);
public void referenceUnBind(ColorManager colorManager);
// --------------------
}
--------------------------------
ColorManagerImpl.java
--------------------------------
package model.controller;
import com.ibm.jpa.web.JPAManager;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction;
import com.ibm.jpa.web.NamedQueryTarget;
import com.ibm.jpa.web.Action;
import javax.persistence.PersistenceUnit;
import javax.annotation.Resource;
import javax.transaction.UserTransaction;
import model.Color;
import java.util.List;
import java.util.Map;
import javax.persistence.Query;
@SuppressWarnings("unchecked")
@JPAManager(targetEntity = model.Color.class)
public class ColorManagerImpl implements ColorManager {
@PersistenceUnit(unitName="jpa_osgi_example_01")
private EntityManagerFactory emf;
// Couldn't get UserTransaction working within OSGi
// Using EntityTransaction instead
// @Resource
// private UserTransaction utx;
public ColorManagerImpl() {
}
private EntityManager getEntityManager() {
return emf.createEntityManager();
}
@Override
@Action(Action.ACTION_TYPE.CREATE)
public void createColor(Color color) throws Exception {
EntityManager em = this.getEntityManager();
EntityTransaction et = em.getTransaction();
try {
et = em.getTransaction();
et.begin();
em.persist(color);
et.commit();
} catch (Exception ex) {
ex.printStackTrace();
try {
et.rollback();
} catch (Exception e) {
ex.printStackTrace();
throw e;
}
throw ex;
} finally {
em.close();
}
}
@Override
@Action(Action.ACTION_TYPE.DELETE)
public void deleteColor(Color color) throws Exception {
EntityManager em = getEntityManager();
EntityTransaction et = em.getTransaction();
try {
et.begin();
color = em.merge(color);
em.remove(color);
et.commit();
} catch (Exception ex) {
try {
et.rollback();
} catch (Exception e) {
ex.printStackTrace();
throw e;
}
throw ex;
} finally {
em.close();
}
}
@Override
@Action(Action.ACTION_TYPE.UPDATE)
public void updateColor(Color color) throws Exception {
EntityManager em = getEntityManager();
EntityTransaction et = em.getTransaction();
try {
et.begin();
color = em.merge(color);
et.commit();
} catch (Exception ex) {
try {
et.rollback();
} catch (Exception e) {
ex.printStackTrace();
throw e;
}
throw ex;
} finally {
em.close();
}
}
@Override
@Action(Action.ACTION_TYPE.FIND)
public Color findColorByColorCode(String colorCode) {
Color color = null;
EntityManager em = getEntityManager();
try {
color = (Color) em.find(Color.class, colorCode);
} finally {
em.close();
}
return color;
}
@Override
@Action(Action.ACTION_TYPE.NEW)
public Color getNewColor() {
Color color = new Color();
return color;
}
@Override
@NamedQueryTarget("getColor")
public List<Color> getColor() {
EntityManager em = getEntityManager();
List<Color> results = null;
try {
Query query = em.createNamedQuery("getColor");
results = (List<Color>) query.getResultList();
} finally {
em.close();
}
return results;
}
@Override
public void startUp() {
System.out.println("*** ColorManagerImpl.startUp()");
}
@Override
public void onRegisterService(ColorManager colorManager, Map props) {
System.out.println("*** ColorManagerImpl.onRegisterService()");
}
@Override
public void onUnRegisterService(ColorManager colorManager, Map props) {
System.out.println("*** ColorManagerImpl.onUnRegisterService()");
}
@Override
public void referenceBind(ColorManager colorManager) {
System.out.println("*** ColorManagerImpl.referenceBind()");
}
@Override
public void referenceUnBind(ColorManager colorManager) {
System.out.println("*** ColorManagerImpl.referenceUnBind()");
}
}
------------------------------------
JpaExampleTest.java
------------------------------------
package jpa_tests;
import java.util.List;
import model.Color;
import model.controller.ColorManager;
public class JpaExampleTest {
private Color testColor = new Color("TestCode1","TestName1");
private ColorManager colorManager = null;
public ColorManager getColorManager() {
return colorManager;
}
public void setColorManager(ColorManager colorManager) {
this.colorManager = colorManager;
}
public void startUp() {
System.out.println("*** JpaExampleTest.startUp CALLED");
// start tests
testAllOps();
}
public String testAllOps() {
System.out.println("*** JpaExampleTest: STARTING TESTS");
System.out.println("*** JpaExampleTest: ------------------");
// ---------------------------------
// colorManager must be set by blueprint (cannot be null)
// ---------------------------------
if(this.colorManager==null){
System.out.println("*** JpaExampleTest: colorManager==null ");
return "fail";
}
// ---------------------------------
// ---------------------------------
// test select
// ---------------------------------
System.out.println("*** JpaExampleTest: ------------------");
System.out.println("*** JpaExampleTest: Test getColor");
List<Color> list = null;
try {
list = colorManager.getColor();
} catch (Exception e) {
e.printStackTrace();
}
for (Color color : list) {
System.out.println("*** color code: "+ color.getColorCode());
}
System.out.println("*** JpaExampleTest: createColor(myTestColor)");
// Color myNewColor = new Color("foo","bar");
try {
this.colorManager.createColor(this.testColor);
// this.colorManager.createColor(myNewColor);
System.out.println("*** JpaExampleTest: createColor -> no errors so far");
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("*** JpaExampleTest: ------------------");
System.out.println("*** JpaExampleTest: verify Create - look up created color");
Color color = this.colorManager.findColorByColorCode(this.testColor.getColorCode());
if (color.getColorCode().equals(this.testColor.getColorCode())) {
System.out.println("*** JpaExampleTest created color found: "+ color.getColorCode());
} else {
System.out.println("*** JpaExampleTest created color NOT FOUND!");
}
System.out.println("*** JpaExampleTest: ------------------");
System.out.println("*** JpaExampleTest: update color name");
Color changedColor = new Color(this.testColor.getColorCode(),
this.testColor.getColorName()+"_meh");
try {
this.colorManager.updateColor(changedColor);
} catch (Exception e) {
e.printStackTrace();
}
Color myChangedSavedColor = this.colorManager.findColorByColorCode(this.testColor.getColorCode());
if (myChangedSavedColor.getColorName().equals(changedColor.getColorName())) {
System.out.println("*** JpaExampleTest changed color did change: "+ myChangedSavedColor.getColorName());
} else {
System.out.println("*** JpaExampleTest hanged color did NOT change!: "+ myChangedSavedColor.getColorName());
}
System.out.println("*** JpaExampleTest: ------------------");
System.out.println("*** JpaExampleTest: delete test color");
try {
this.colorManager.deleteColor(testColor);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Color myDeletedColorGone = this.colorManager.findColorByColorCode(this.testColor.getColorCode());
if (myDeletedColorGone == null ) {
System.out.println("*** JpaExampleTest: delete test color PASSED... NOT FOUND");
}
System.out.println("*** JpaExampleTest: DONE...");
System.out.println("*** JpaExampleTest: ------------------");
System.out.println("*** JpaExampleTest: ------------------");
return "pass";
}
}