Saturday, June 13, 2015

Basics of JPA (Java Persistence API)

Java Persistence API

The Java Persistence API (JPA) is a Java application programming interface specification that describes the management of relational data in applications using Java Platform, Standard Edition and Java Platform, Enterprise Edition.

The Java Persistence API provides a POJO persistence model for object-relational mapping (ORM).
ORM is a programming ability to covert data from object type to relational type and vice versa. The main feature of ORM is mapping or binding an object to its data in the database.

Following architecture explains the flow of storing objects into any relational database.

       




Understanding the above architecture:

Module 1: In this module there will be Object data under POJO classes and business logic under service interfaces and classes will be implemented. It is the main business component layer, which has business logic operations and attributes.

For example let us take any table ‘Payment’ from any database:
Payment POJO class contain attributes such as Id, CompanyId, Status, Payment type etc.
And methods like setter and getter methods of those attributes and Payment DAO/Service classes contains service methods such as create Payment, find Payment etc.

Module 2: In this module we will be creating the bindings for data mapping using the Java persistence framework.
This module will be holding the persistence.xml (replicating the ORM config file ORM.xml), JPA loader, JPA provider and Object grid.

1.    JPA Provider: Any vendor product providing the Java Persistence flavor like Eclipselink, Hibernate, Toplink.
2.    Object mapping file: This will be persistence.xml in case of Eclipselink based implementation or it could be any ORM.xml file depending on the vendor we have selected.
3.    JPA Loader: This acts like a cache memory which holds relational grid data and works as if a copy of database to interact with Service classes for data in POJOs for our implementation.
4.    Object Grid: It is a temporary location holding data before all queries hit the database it is first effected on the data in the object grid. Only after it is committed, it effects the main database.


Module 3: This is the last phase where object – data mapping actually comes into action and deals with the database for Select / Insert / Update / Delete data.
Only when the business component commit the data, it is stored into the database physically. Until then the modified data is stored in a cache memory as a grid format. Same is the process for obtaining data.


There are following areas which can be covered in Java Persistence

·         The Java Persistence API
·         The query language
·         The Java Persistence Criteria API
·         Object/relational mapping metadata


Where to use JPA?
To reduce the burden of writing codes for relational object management, a programmer follows the ‘JPA Provider’ framework. It brings following benefits along with its ORM framework / implementation:
·         Idiomatic persistence: It enables you to write the persistence classes using object oriented classes.
·         High Performance: It has many fetching techniques and hopeful locking techniques.
·         Reliable: It is highly stable and eminent. Used by many industrial programmers.



Entities
An entity is a lightweight persistence domain object. Typically an entity represents a table in a relational database, and each entity instance corresponds to a row in that table.



An entity class must follow these requirements.

·         The class must be annotated with the javax.persistence.Entity annotation.
·         The class must have a public or protected, no-argument constructor. The class may have other constructors.
·         The class must not be declared final. No methods or persistent instance variables must be declared final.
·         Entities may extend both entity and non-entity classes, and non-entity classes may extend entity classes.
·         The persistent state of an entity can be accessed through either the entity’s instance variables or properties. The fields or properties must be of the following Java language types:
§  Java primitive types
§  java.lang.String
§  Other serializable types, including:
§  Wrappers of Java primitive types
§  java.math.BigInteger
§  java.math.BigDecimal
§  java.util.Date
§  java.util.Calendar
§  java.sql.Date
§  java.sql.Time
§  java.sql.TimeStamp
§  User-defined serializable types
§  byte[]
§  Byte[]
§  char[]
§  Character[]
·         If the entity class uses persistent fields, the Persistence runtime accesses entity-class instance variables directly. All fields not annotated javax.persistence.Transient or not marked as Java transient will be persisted to the data store.

·         Primary Keys in Entities
Each entity has a unique object identifier. A customer entity, for example, might be identified by a customer number. The unique identifier, or primary key, enables clients to locate a particular entity instance. Every entity must have a primary key. An entity may have either a simple or a composite primary key.

Simple primary keys use the javax.persistence.Id annotation to denote the primary key property or field.

Friday, June 12, 2015

Common Configuration Errors / Exceptions


Error / Exception 1 ::
While configuring for my first sample JPA application , I faced many weird errors and exceptions but that was all due to my inexperience on this side, I have few documented below which could help other developers 

a) Internal Exception: java.sql.SQLException: Io exception: NL Exception was generated

Possible Cause:: Check your jdbc url in the Persistence.xml file under Meta-Inf configuration 

I had :: jdbc:oracle:thin://host:1521/dbname3t;create=true for my JPA configuration

It should have been :: jdbc:oracle:thin:@host:1521:dbname3t


b) persistence, oracle thin, ORA-12505, TNS listener does not currently know of SID

I was getting  org.eclipse.persistence.exceptions.DatabaseException ORA-12505, TNS:listener does not currently know of SID given in connect descriptor

While trying to fix it I found the URL configured in the persistance.xml was incorrect 

I had :: jdbc:oracle:thin://host:1521/dbname3t;create=true for my JPA configuration

It should have been :: jdbc:oracle:thin:@host:1521:dbname3t

c) javax.persistence.PersistenceException: No Persistence provider for EntityManager named         "TestJPAEntity"

In JPA a database connection is represented by the EntityManager interface. In order to access and work with an ObjectDB database we need an EntityManager instance. If there is any problem in locating the Entitymanager defined in your client/service class then this error will be thrown

You can update the persistence.xml or your testClient/Service java class to have same name
refer below sample code for persistence Unit Name and name in your java class.

Sample Persistence XML ::
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="JPATestPaymentCreation">
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
          <class>payments.Payment</class>
          <properties>
               <property name="javax.persistence.jdbc.driver"    
                              value="oracle.jdbc.driver.OracleDriver" />
               <property name="javax.persistence.jdbc.url"
                    value="jdbc:oracle:thin:@dbhost03:1521:dbName3t" />
               <property name="javax.persistence.jdbc.user" value="online_service" />
               <property name="javax.persistence.jdbc.password" value="EW66P#$A" />
          </properties>
</persistence-unit>

</persistence>

TestJPAJava Class

public class TestInsertPaymentViaJPA {
private static final String PERSISTENCE_UNIT_NAME = "JPATestPaymentCreation";
 private static EntityManagerFactory factory;

 public static void main(String[] args) {
factory = Persistence.createEntityManagerFactory(PERSISTENCE_UNIT_NAME);
        EntityManager em = factory.createEntityManager();       
       // Read the existing entries and write to console
          Query q = em.createQuery("SELECT emp FROM Employee emp");    
         List<Employee> empList = q.getResultList();
         for (Employee emp : empList) {
              System.out.println(emp.getEmpNameId());
         }
         System.out.println("Size: " + empList.size());
            em.close();
}
}

c) java.lang.ClassCastException: org.eclipse.persistence.jpa.PersistenceProvider cannot be cast to javax.persistence.spi.PersistenceProvider

If you are using Eclipselink as your persistence provider , then you could have faced this error , this is a run time error and could be due to following causes:
            i) The version of the Eclipselink and javax.persistence.xx jars are not compatible
            ii) If you are running your application on Tomcat and the jars in Tomcat/lib directory are of different   
               version then the ones you have packaged in your web application.
            iii) Another possible cause could be any other jar in your workspace or packaged WAR is causing conflict

I was having issues with below combinations ::
            persistence-api-1.0.2.jar and eclipselink.jar (1.0)
            persistence-api-1.0 and eclipselink(1.0)

I was able to make it work with :: javax.persistence-2.1.0 and eclipselink (eclipselink-2.1.0.v20100614-r7608)

d) While Configuring Maven in the local workspace , most of the developers get below issue initially
   Eclipse complains “Could not resolve archetype” 

Could not resolve archetype org.apache.maven.archetypes:maven-archetype-webapp:RELEASE from any of the configured repositories.

While analyzing this issue and going through multiple posts online I figured this is related to proxy settings in the settings conf file under 9C:\Users\anyUserProfile\.m2\settings.xml), even though I had included the proxy settings with correct User/Password to get the Maven schema validated the format was incorrect , see below 

For my network settings below proxy config did nt work ::
<proxies>
    <!-- proxy Specification for one proxy, to be used in connecting to the network.-->
    <proxy>
      <active>true</active>
      <protocol>http</protocol>
      <username>anyUser</username>
      <password>passxxx</password>
       <host>host.name.com/</host>
<port>80</port> 
    </proxy>

  </proxies>

So instead of above settings I replaced with below ::

<proxy>
  <id>optional</id> 
  <active>true</active> 
  <protocol>http</protocol> 
  <username /> 
  <password /> 
  <host>proxy.test.com</host> 
  <port>8080</port> 
  <nonProxyHosts>localhost,127.0.0.1</nonProxyHosts> 

  </proxy>

And this resolved my issue of Maven Project not getting created.
      
d) Missing [SEI] when generating artifacts with WSGEN
     
    I faced this error while generating the artifacts for my Service implementation, which      
    needed to be exposed as a WebService.

    I tried following command on command prompt to generate my classes :
                         wsgen -verbose -cp . com.test.ws.EchoService -wsdl

    This throws me below error : WSGEN [options] <SEI
    
    and the reason being the utility not able to reach out or find the SEI Service Implementation       class for which we might want to write a client.

    What is happening here is the option " -cp " will set the classpath and try to retrieve or          resolve the EchoService class location according your classpath so in my case it was build/classes hence this makes it looks as ::

build/classes/com/test/ws/EchoService but the actual path is ::  C:\Users\EchoWebServiceExample\build\classes and then the package so it should be

wsgen -cp C:\Users\EchoWebServiceExample\build\classes  com.test.ws.EchoService -wsdl

    
e) Issue with new configuration on Eclipse to execute POM.xml to resolve all config metadata and execute the maven commands.

Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:2.3.2:compile 

Issue Faced: Error " WARNING: Error injecting: org.apache.maven.plugin.CompilerMojo
**java.lang.NoClassDefFoundError: org/codehaus/plexus/compiler/CompilerException**

Actually my JAVA_HOME was pointing to JRE_HOME , I found out when I executed this with below command
 mvn clean install -X

Java version: 1.7.0_79, vendor: Oracle Corporation 
Java home: C:\Program Files\Java\jre7

To fix this in eclipse I updated my CLASSPATH Variables under Eclipse -> Preferences -> Java -> Build Path - CLASSPATh VARIABLES to have a new entry as JAVA_HOME and pointed it to my JDK home it worked perfectly fine

f) Issue in building Web Application in Eclipse via inbuilt Maven plugin

JDK's tools.jar was not found in C:\Program Files\Java\lib\tools.jar. Usually this means you are running JRE, not JDK

Go to Preferences/Java/Installed JREs and add one more location as "C:\Program Files\Java\jdk1.7.0_7 or something like below you can update existing JRE location to point to JRE under your JDK as I removed the one for C:\Program Files\Java\jre7 and added C:\Program Files\Java\jdk1.7.0_79\jre
As you can see, the path C:\Program Files\Java\jre7\..\lib\tools.jar only makes sense if the first part (til the /..) is replaced by C:\Program Files\Java\jdk1.7.0_79\jre.



Tuesday, June 2, 2015

Publishing WebService using Axis2

Publishing REST ful WebService using Axis2


WSDL 2.0 HTTP Binding defines a way to implement REST (Representational State Transfer) with Web services. Axis2 implements the most defined HTTP binding specification. REST Web services are a reduced subset of the usual Web service stack.
  1. REST Web services are Synchronous and Request Response in nature.
  2. When REST Web services are accessed via GET, the service and the operations are identified based on the URL. The parameters are assumed as parameters of the Web service. In this case, the GET based REST Web services support only simple types as arguments and it should adhere to the IRI style.
  3. POST based Web services do not need a SOAP Envelope or a SOAP Body. REST Web Services do not have Headers and the payload is sent directly.
Axis2 can be configured as a REST Container and can be used to send and receive RESTful Web service requests and responses. REST Web services can be accessed using HTTP GET and POST.

The sample explains how to write a Web service and Web service client with 
Apache Axis2 using XML based client APIs (Axis2's Primary APIs).

First of all we will have to set up the Axis2 WAR to set up our REST container so that once we are ready with our service implementation and we have our .aar file generated  , we can get this deployed as a service on Axis 2 container.

The .AAR file will have META-INF holding services.xml which will have service implementation details:
      a. Service Class -> The actual Java class file holding implementation
      b. operation name -> The actual method name

1. Deploy Axis2 War on the local set up, I deployed my axis2.war under web apps directory of tomcat server as below ::



Deployed Services will be available on the below location after we execute build and get .aar file generated::

http://localhost:8080/axis2/services/

2. Create a Simple WebService which will just echo any String passed to it
import org.apache.axiom.om.OMElement;
import org.apache.axis2.AxisFault;
import javax.xml.stream.XMLStreamException;
public class MyService {
    public OMElement echo(OMElement element) throws XMLStreamException {
        //Praparing the OMElement so that it can be attached to another OM Tree.
        //First the OMElement should be completely build in case it is not fully built and still
        //some of the xml is in the stream.
        element.build();
        //Secondly the OMElement should be detached from the current OMTree so that it can be attached
        //some other OM Tree. Once detached the OmTree will remove its connections to this OMElement.
        element.detach();
        return element;
    }
}

3.  Bundle in a Axis Archive file i.e .AAR file
     a. build.xml for Ant based build / aar file generation
   <project name="userguide1" default="generate.service">
    <property name="mainDir" value="../.."/>
    <property name="classes.dir" value="build/classes"/>
    <path id="axis.classpath">
        <fileset dir="../../lib">
            <include name="*.jar"/>
        </fileset>
        <pathelement location="build/userguide1.jar"/>
    </path>
    <mkdir dir="${basedir}/build/classes"/>
    <target name="run.client.all"
            depends="run.client.blocking">
    </target>
    <target name="compile">
    <mkdir dir="${classes.dir}" />
<javac srcdir="src" destdir="${classes.dir}">
<classpath refid="axis.classpath" />
</javac>
<jar destfile="build/userguide1.jar">
            <fileset dir="${classes.dir}">
                <include name="userguide1/**"/>
            </fileset>
        </jar>
    </target>
    
    <target name="generate.service" depends="compile">
            <jar destfile="build/MyService1.aar">
           <fileset dir="src/userguide/example1/">
               <include name="META-INF/**"/>
           </fileset>
           <fileset dir="${classes.dir}">
               <include name="userguide/example1/**/*.class"/>
           </fileset>
        </jar>
        <copy file="build/MyService1.aar" tofile="../../repository/services/MyService1.aar" overwrite="true"/>
    </target>
   <target name="run.client.blocking" depends="compile">
        <java classname="userguide.clients.EchoBlockingClient"
              classpathref="axis.classpath" fork="true">
            <jvmarg value="-Daxis2.repo=${mainDir}/repository"/>
    <jvmarg value="-Daxis2.xml=conf/axis2.xml"/>
        </java>
    </target>
    <target name="run.client">
<echo message="Please use the following ant targets to run the clients" />
<echo message="run.client.all  -  run all clients" />
    </target>
    <target name="clean">
<delete dir="build" />
    </target>
</project>

c. Execute ant / build.xml and get the MyService1.aar generated which will be using the below src code.

    i) services.xml
            <service name="MyService1">
                      <description>
                      This is a sample Web Service with an echo operations
                        </description>
                 <parameter name="ServiceClass">userguide.example1.MyService</parameter>
                <operation name="echo">
               <messageReceiver class="org.apache.axis2.receivers.RawXMLINOutMessageReceiver"/>
               <actionMapping>urn:echo</actionMapping>
               </operation>
             </service>

     ii) MyService.java

import org.apache.axiom.om.OMElement;
import org.apache.axis2.AxisFault;
import javax.xml.stream.XMLStreamException;

public class MyService {
    public OMElement echo(OMElement element) throws XMLStreamException {
        //Praparing the OMElement so that it can be attached to another OM Tree.
        //First the OMElement should be completely build in case it is not fully built and still
        //some of the xml is in the stream.
        element.build();
        //Secondly the OMElement should be detached from the current OMTree so that it can be attached
        //some other OM Tree. Once detached the OmTree will remove its connections to this OMElement.
        element.detach();
        return element;
    }
}

d. Once build is completed the generated MyService1.aar file will be placed fine in the services of Axis repository, if it does nt get hot deployed on the running Axis2 container which is hosted on any Tomcat server, then you can restart service by axis2server.bat

Once deployed the newly made service will be available under below location::
C:\Softwares\axis2-1.6.2\repository\services


e. Verify if the service is properly deployed:

http://localhost:8080/axis2/services/



d. Test the Service using REST based call via simple java class by hitting the URL ::
     http://localhost:8080/axis2/services/MyService1?wsdl
import javax.xml.namespace.QName;
import javax.xml.parsers.FactoryConfigurationError;
import javax.xml.stream.XMLOutputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamWriter;
import org.apache.axiom.om.OMAbstractFactory;
import org.apache.axiom.om.OMElement;
import org.apache.axiom.om.OMFactory;
import org.apache.axiom.om.OMNamespace;
import org.apache.axis2.AxisFault;
import org.apache.axis2.Constants;
import org.apache.axis2.addressing.EndpointReference;
import org.apache.axis2.client.Options;
import org.apache.axis2.client.ServiceClient;


public class RESTClient {

    private static String toEpr = "http://localhost:8080/axis2/services/MyService1?wsdl";
    
    @SuppressWarnings("deprecation")
public static void main(String[] args) throws AxisFault {

        Options options = new Options();
        options.setTo(new EndpointReference(toEpr));
        
        options.setProperty(Constants.Configuration.ENABLE_REST, Constants.VALUE_TRUE);

        ServiceClient sender = new ServiceClient();
        sender.engageModule(new QName(Constants.MODULE_ADDRESSING));
        sender.setOptions(options);
        OMElement result = sender.sendReceive(getPayload());

        try {
            XMLStreamWriter writer = XMLOutputFactory.newInstance().createXMLStreamWriter(System.out);
            result.serialize(writer);
            writer.flush();
        } catch (XMLStreamException e) {
            e.printStackTrace();
        } catch (FactoryConfigurationError e) {
            e.printStackTrace();
        }
    }
    private static OMElement getPayload() {
        OMFactory fac = OMAbstractFactory.getOMFactory();
        OMNamespace omNs = fac.createOMNamespace("http://example1.org/example1", "example1");
        OMElement method = fac.createOMElement("echo", omNs);
        OMElement value = fac.createOMElement("Text", omNs);
        value.addChild(fac.createOMText(value, "Axis2 Echo 2323232 String "));
        method.addChild(value);

        return method;
    }
}


And on execution we have the below response from Echo Service client

<example1:echo xmlns:example1="http://example1.org/example1">
<example1:Text>Axis2 Echo 2323232 String </example1:Text>
</example1:echo>