Thank you for visiting! If you liked the site, please add a bookmark, else add a critical comment! Would you like to visit Greece? Traditional Greek flag This real estate site is only available in Greek! The holy mountain

Thursday 15 September 2011

Comments on Spring 3 in action, by Craig Walls

On the bright side, the text is very well written without spelling errors. The author has organized each sequence of paragraphs so well, as neat as a chain having rings following  one chapter after another.  There are plenty of metaphors, analogies and examples from the daily life to help the reader grasp the Spring fundamentals.
On the dark side, the book has no tutorial format; in other words the reader cannot study the material, by doing some practice. The source code available online is given completed in its final form, as a whole, without the intermediate steps required to take, as presented by each chapter. Thus, if one attempts to run some code, one needs to improvise, there is no guidance as to the libraries necessary to run, other than the exceptions and the search pages found on the internet. As of now JDeveloper only supports Spring version 2.5. If one uses Eclipse Helios and the oracle DB and weblogic packages, one is bound to see errors while installing ie sts tools, since conflicts exist between failing package dependencies:

Your original request has been modified.
  "Spring IDE Core (required)" is already installed, so an update will be performed instead.
Cannot complete the install because one or more required items could not be found.
  Software being installed: SpringSource Tool Suite (required) 2.6.1.201105091000-RELEASE (com.springsource.sts.feature.group 2.6.1.201105091000-RELEASE)
  Missing requirement: com.springsource.sts.ide.ui 2.6.0.201105091000-RELEASE requires 'bundle org.eclipse.ajdt.ui 0.0.0' but it could not be found
  Cannot satisfy dependency:
    From: SpringSource Tool Suite (required) 2.6.1.201105091000-RELEASE (com.springsource.sts.feature.group 2.6.1.201105091000-RELEASE)
    To: com.springsource.sts.ide.ui [2.6.0.201105091000-RELEASE]

All in all, the book seems most suitable to the experienced Spring developer who would like to get informed of the newest advances of the framework, or people who 'd rather just read text, and some code snippets, passively. The ones who learn better by doing would be better off by following first some spring tutorials, about using Eclipse in  combination with spring, such as those offered by Rose India.

Thursday 8 September 2011

The Java SOA cookbook, by Eben Hewitt

On the bright side the cook book is well written, in American English, with some spelling errors.The error page of the book presents at the moment only unconfirmed errata:
http://oreilly.com/catalog/errataunconfirmed.csp?isbn=9780596520731
The book consists of a series of  useful stand alone ...dishes; articles structured like this: specific problem, relevant solution, discussion of java code, criticism and alternatives. The reader may not study the book from the start of the menu to the end page sequentially, one might well consult the book about everyday tasks, ie finding a specific file in jarred libraries in linux, and only that. The ...chef expresses his opinion openly about purity of ingredients, ie using cookies is not ReST style programming, uses mainly open source tools to cook; such as Eclipse, Netbeans, Glassfish, .Net clients and some weblogic, but sadly for oracle fans, no flavour of JDeveloper at all! However, the author is not prejudiced against oracle products, as he praises the enterprise service bus.
On the dark side, some of the recipes are incomplete, probably due to space restrictions, meaning that  sometimes the input to a servlet is not dynamic; fed by a database but static, hard coded values in a constructor of a convenience class. Moreover, the source code for each chapter offered on line is all pasted in a single file, not separate class files, thus finding the snippet you need can be time consuming.
All in all, this is a very useful cookbook, presenting advanced java  version 1.6 code, practical solutions to real life problems, excluding design patterns. It offers plenty of food for thought, as it tries to answer  a daily question asked by the vast majority of women, developers and chefs for centuries: what shall we cook today? Bon Appetit ladies and gentlemen!

Tuesday 23 August 2011

Providing the model layer for a ReSTful web service

In this new article we shall discuss about implementing the model layer for a simple REST style web service, presented in a book authored by Eben Hewitt, called SOA Cookbook.  In example 8-1 the author presents a plain servlet which draws  hard coded values from a pojo called ProductCatalog. The XML values returned in the browser are the ones that are statically hard coded in the pojo's constructor. The original idea to extend the example, was to provide dynamic data from querying a database.  Providing an entity bean for the Product and a stateless ejb 3 as a facade to query, seemed as a straightforward suggestion. As far as java 1.6 and JDeveloper 11.1.2 was concerned, that was merely wishful thinking!

The first exception deprived me of using directly the entity manager to access the db:

 com.sun.xml.bind.v2.runtime.IllegalAnnotationsException: 2 counts of IllegalAnnotationExceptions
javax.persistence.EntityManager is an interface, and JAXB can't handle interfaces.
    this problem is related to the following location:
        at javax.persistence.EntityManager
        at public javax.persistence.EntityManager com.soacookbook.ProductCatalog.entityManager
        at com.soacookbook.ProductCatalog
javax.persistence.EntityManager does not have a no-arg default constructor.
    this problem is related to the following location:
        at javax.persistence.EntityManager
        at public javax.persistence.EntityManager com.soacookbook.ProductCatalog.entityManager
        at com.soacookbook.ProductCatalog

The most I could do this way  was to access the db using a EJB client. The EJB code won't be displayed for brevity! Although I have received a warning that samplecode.oracle.com in its current form is being decommissioned on November 1st, 2011, the full source code can be found here, and is given as usual, without any guarantee of support, etc.

The view layer for now, is to remain as is!

The original code for the servlet from the aforementioned book, which was to remain intact, follows:

package com.soacookbook.web;

import com.soacookbook.ProductCatalog;

import java.io.IOException;

import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import org.w3c.dom.Document;


public class SimpleRestServlet extends HttpServlet {
    private static final String CONTENT_TYPE = "text/xml; charset=UTF-8";
    private static final String DOC_TYPE = null;

    public void init(ServletConfig config) throws ServletException {
        super.init(config);
    }

    public SimpleRestServlet() {
        super();
    }

    protected void doGet(HttpServletRequest request,
                         HttpServletResponse response) throws ServletException,
                                                              IOException {
        System.out.println("DoGet invoked on RESTful service.");
        ProductCatalog catalog = new ProductCatalog();
        Source xmlSource = asXml(catalog);
        ServletOutputStream out = response.getOutputStream();
        response.setContentType("text/xml");
        StreamResult st = new StreamResult(out);
        try {
            Transformer t = TransformerFactory.newInstance().newTransformer();
            t.transform(xmlSource, st);
        } catch (Exception e) {
            throw new ServletException(e);
        }
        System.out.println("All done.");
    }

    private static Source asXml(ProductCatalog pc) throws ServletException {
        System.out.println("Marshalling...");
        Source source = null;
        Document doc = null;
        try {
            JAXBContext ctx = JAXBContext.newInstance(ProductCatalog.class);
            Marshaller m = ctx.createMarshaller();
            DocumentBuilder parser =
                DocumentBuilderFactory.newInstance().newDocumentBuilder();
            doc = parser.newDocument();
            System.out.println("Products=" + pc);
            m.marshal(pc, doc);
            System.out.println("Marshalled catalog to XML.");
        } catch (JAXBException je) {
            throw new ServletException(je);
        } catch (ParserConfigurationException pce) {
            throw new ServletException(pce);
        }
        source = new DOMSource(doc);
        System.out.println("Returning XML source.");
        return source;
    }

    protected void doPost(HttpServletRequest request,
                          HttpServletResponse response) throws ServletException,
                                                               IOException {
        doGet(request, response);
    }
}

The model layer with the dynamic query:

The table script as generated by JDeveloper 11.1.2: 

CREATE TABLE "FUSIONEJB3"."PRODUCT"
  (
    "ID"    VARCHAR2(255 BYTE) NOT NULL ENABLE,
    "PRICE" NUMBER(19,4),
    "NAME"  VARCHAR2(255 BYTE),
    PRIMARY KEY ("ID") USING INDEX PCTFREE 10 INITRANS 2 MAXTRANS 255 COMPUTE STATISTICS STORAGE(INITIAL 65536 NEXT 1048576 MINEXTENTS 1 MAXEXTENTS 2147483645 PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1 BUFFER_POOL DEFAULT FLASH_CACHE DEFAULT CELL_FLASH_CACHE DEFAULT) TABLESPACE "USERS" ENABLE
  )
  SEGMENT CREATION IMMEDIATE PCTFREE 10 PCTUSED 40 INITRANS 1 MAXTRANS 255 NOCOMPRESS LOGGING STORAGE
  (
    INITIAL 65536 NEXT 1048576 MINEXTENTS 1 MAXEXTENTS 2147483645 PCTINCREASE 0 FREELISTS 1 FREELIST GROUPS 1 BUFFER_POOL DEFAULT FLASH_CACHE DEFAULT CELL_FLASH_CACHE DEFAULT
  )
  TABLESPACE "USERS" ; 


Impressive, isn't it? Next populate the table with sample data. 

REM INSERTING into PRODUCT
Insert into PRODUCT (ID,PRICE,NAME) values ('GermanBonds',50,'Euro BRD Bonds');
Insert into PRODUCT (ID,PRICE,NAME) values ('USShares ',20,'US dollar mutual fund  common shares');
 


The Product entity follows next:

package com.soacookbook.entities;

import java.io.Serializable;

import java.math.BigDecimal;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;

import javax.xml.bind.annotation.XmlType;

@XmlType
@Entity
@NamedQueries( { @NamedQuery(name = "Product.findAll",
                             query = "select o from Product o") })
public class Product implements Serializable {
    private String id;
    private String name;
    private BigDecimal price;

    public Product() {
    }

    public Product(String id, String name, BigDecimal price) {
        this.id = id;
        this.name = name;
        this.price = price;
    }

    @Id
    @Column(nullable = false)
    public String getId() {
        return id;
    }

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

    public String getName() {
        return name;
    }

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

    public BigDecimal getPrice() {
        return price;
    }

    public void setPrice(BigDecimal price) {
        this.price = price;
    }
}

Some more modifications of the book code:

Although the first thought was to preserve the original working source code provided by the book author, some modifications were necessary. The final form of ProductCatalog follows:

package com.soacookbook;

import com.soacookbook.client.ProductCatalogSEClient;
import com.soacookbook.entities.Product;

import java.util.ArrayList;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;

import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement
public class ProductCatalog {
   
   
    private List<Product> products;
   
    public ProductCatalog() {
        super();
        ProductCatalogSEClient productCatalogSEClient = new ProductCatalogSEClient();
         products = productCatalogSEClient.getAllProducts();
              
    }

    //Don't you dare, no other getter there!   

    public void setProducts(List<Product> products) {
        this.products = products;
    }

  
}

Had you dared to generate an accessor, this would be the exception:


com.sun.xml.bind.v2.runtime.IllegalAnnotationsException:
 1 counts of IllegalAnnotationExceptions
Class has two properties of the same name "products"
this problem is related to the following location:at
public java.util.List com.soacookbook.ProductCatalog.getProducts()
at com.soacookbook.ProductCatalog
this problem is related to the following location:at
 public java.util.List com.soacookbook.ProductCatalog.products
at com.soacookbook.ProductCatalog



Application-managed EntityManagers, outside the Java EE container, save the day!

The first successful attempt to access the db was via the Java SE client:

package com.soacookbook.client;

import com.soacookbook.ProductCatalog;
import com.soacookbook.entities.Product;

import java.util.ArrayList;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import javax.persistence.Query;

public class ProductCatalogSEClient {
   
    private  EntityManager entityManager;
    private  EntityManagerFactory entityManagerFactory;
   
    private  Hashtable emProps = new Hashtable();
   
   
    public ProductCatalogSEClient() {
        super();
    }
   
    public static void main(String[] args) {

        ProductCatalogSEClient productCatalogSEClient = new ProductCatalogSEClient();
        List<Product> products = productCatalogSEClient.getAllProducts();
        Iterator  i = products.iterator();
                  while (i.hasNext())
                  {
                    Product product = (Product) i.next();
                    System.out.println("Id:"+ product.getId() +" Name:"+product.getName()
                                             + " price " + product.getPrice());
                  }
                 
    }
   
    public  List<Product> getAllProducts(){
          
           List<Product> products= null;
           try {
             entityManagerFactory =
                Persistence.createEntityManagerFactory("JavaSEClient");
                // not the same with example8-1  !
            entityManager = entityManagerFactory.createEntityManager(emProps);
            Query query = entityManager.createNamedQuery("Product.findAll");
            products=query.getResultList();
          
        } catch (Exception e) {
            // TODO: Add catch code
            e.printStackTrace();
        } finally {
            entityManager.close();
            entityManagerFactory.close();
          
        }
            return products;
        }

}

A second introduction to EE is superfluous: no more user credentials please!

However, if one copied the working properties for the SE client and pasted to the EE edition unit:

Internal Exception: java.sql.SQLException: User: fusionEJB3, failed to be authenticated.
Error Code: 0
    at org.eclipse.persistence.exceptions.DatabaseException.sqlException(DatabaseException.java:309)
    at org.eclipse.persistence.sessions.JNDIConnector.connect(JNDIConnector.java:138)
    at org.eclipse.persistence.sessions.JNDIConnector.connect(JNDIConnector.java:94)
    at org.eclipse.persistence.sessions.DatasourceLogin.connectToDatasource(DatasourceLogin.java:162)


The correct persistence.xml has no user credentials for the EJB client, unlike the java SE one:

<?xml version="1.0" encoding="UTF-8" ?>
<persistence 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"
             version="1.0">
    <persistence-unit name="example8-1">
        <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
        <jta-data-source>jdbc/fusionEJB3</jta-data-source>
        <class>com.soacookbook.entities.Product</class>
        <properties>
            <property name="eclipselink.target-server" value="WebLogic_10"/>
            <property name="eclipselink.target-database" value="Oracle"/>
            <property name="eclipselink.logging.level" value="ALL"/>
          </properties>
    </persistence-unit>
    <persistence-unit name="JavaSEClient" transaction-type="RESOURCE_LOCAL">
        <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
        <class>com.soacookbook.entities.Product</class>
        <properties>
            <property name="eclipselink.target-server" value="WebLogic_10"/>
            <property name="eclipselink.target-database" value="Oracle"/>
            <property name="javax.persistence.jdbc.driver"                value="oracle.jdbc.OracleDriver"/>
            <property name="javax.persistence.jdbc.password"          value="fusionEJB3"/>
            <property name="javax.persistence.jdbc.user" value="fusionEJB3"/>
            <property name="eclipselink.logging.level" value="ALL"/>
            <property name="eclipselink.orm.validate.schema" value="true"/>
            <property name="javax.persistence.jdbc.url"     value="jdbc:oracle:thin:@hera:1521:orcl"/>
        </properties>
    </persistence-unit>
</persistence>


Finally, if one types: http://localhost:7101/example8-1/Products

the XML datagram appears:

<productCatalog>
<products><id>GermanBonds</id><name>Euro BRD Bonds</name><price>50</price></products>
<products><id>USShares </id><name>US dollar mutual fund  common shares</name><price>20</price></products>
</productCatalog>

Making use of EJB 3.1 features via Netbeans 7.0.1

If one has the option of using the latest jdk 1.7, things can be far less complicated:

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package com.soacookbook.facade;

import com.soacookbook.entities.Product;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import javax.ejb.Stateless;
import javax.ejb.LocalBean;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import javax.xml.bind.annotation.XmlRootElement;

/**
 *
 * @author Nick
 */
@XmlRootElement
@Stateless
@LocalBean

public class ProductCatalog implements Serializable {
     private static final long serialVersionUID = 1L;
     @PersistenceContext(unitName="chapter8-1-ejbPU")
       private EntityManager em;
    private List<Product> products;

    public List<Product> getProducts() {
        return products;
    }

    public void setProducts(List<Product> products) {
        this.products = products;
    }
  
  
    public List<Product> getAllProducts() {
       
        Query  query = em.createNamedQuery("Product.findAll");
        products = new ArrayList<Product>();
        //logger.info("Query max results: "+ query.getMaxResults());
        products = query.getResultList();
        return products;
    }
}

As far as the servlet is concerned, one may now use dependency injection:

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package com.soacookbook.web;

import com.soacookbook.facade.ProductCatalog;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.ejb.EJB;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Source;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.w3c.dom.Document;

/**
 * @date Aug 26, 2011
 * @author Nick
 */
public class SimpleRestServlet   extends HttpServlet {
  
@EJB
private ProductCatalog catalog;

    public void init(ServletConfig config) throws ServletException {
        //try {
            super.init(config);
             /*Context context = new InitialContext();
                 catalog =
                            (ProductCatalog) context.lookup("java:global/chapter8-1/chapter8-1-ejb/ProductCatalog");*/
                catalog.getAllProducts();
       /* } catch (NamingException ex) {
            Logger.getLogger(SimpleRestServlet.class.getName()).log(Level.SEVERE, null, ex);
        }*/
    }

    public SimpleRestServlet() {
        super();
    }

    protected void doGet(HttpServletRequest request,
                         HttpServletResponse response) throws ServletException,
                                                              IOException {
        try {
            System.out.println("DoGet invoked on RESTful service.");
          
            Source xmlSource = asXml(catalog);
            ServletOutputStream out = response.getOutputStream();
            response.setContentType("text/xml");
            StreamResult st = new StreamResult(out);
            try {
                javax.xml.transform.Transformer t = TransformerFactory.newInstance().newTransformer();
                t.transform(xmlSource, st);
            } catch (Exception e) {
                throw new ServletException(e);
            }
            System.out.println("All done.");
        } catch (Exception ex) {
            Logger.getLogger(SimpleRestServlet.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    private static Source asXml(ProductCatalog pc) throws ServletException {
        System.out.println("Marshalling...");
        Source source = null;
        Document doc = null;
        try {
            JAXBContext ctx = JAXBContext.newInstance(ProductCatalog.class);
            Marshaller m = ctx.createMarshaller();
            DocumentBuilder parser =
                DocumentBuilderFactory.newInstance().newDocumentBuilder();
            doc = parser.newDocument();
            System.out.println("Products=" + pc);
            m.marshal(pc, doc);
            System.out.println("Marshalled catalog to XML.");
        } catch (JAXBException je) {
            throw new ServletException(je);
        } catch (ParserConfigurationException pce) {
            throw new ServletException(pce);
        }
        source = new DOMSource(doc);
        System.out.println("Returning XML source.");
        return source;
    }

    protected void doPost(HttpServletRequest request,
                          HttpServletResponse response) throws ServletException,
                                                               IOException {
        doGet(request, response);
    }

}


The morale of the story
Automatically generated code is not certain to be error free! It could cause run time exceptions in one IDE and specific application servers, ie Weblogic 10.3.5. In addition, migration to newer  jdk versions are advantageous in most cases.
Even though some resources, excellent books, or tutorials such as those from the open source or Sun Netbeans community, are highly advanced, demonstrating  the latest technology quite well, some are still incomplete. Given that oracle bred java EE developers have a different philosophy, i.e. are accustomed to setup db access as a first step, it is obvious that there is a huge gap in the way of thinking, between the two communities. This gap is for Sun Oracle press, university, marketing, or whatever  other department to bridge. Until then, all incomplete open source recipes are candidates for some kind of integration coding exercise, or maybe not?