Thursday, October 6, 2011

Persisting Entities with Parent Child relationship using JPA


There is an Entity Class Parent, Class Parent might have children of type Child. Parent has an id column and child as well of its own. Parent has its own Contact  information.

It is common to have Entity relationship of this kind. Is there a way to persist this relation using JPA without link tables?

Yes, this is possible. This is a standard bi-directional ManyToOne/OneToMany relationship. I have used the Oracle Toplink JPA implementation.

To make it precise and to the point I made this example simple with simple six steps

1. Setup your database and make sure the connection is successful with right parameters over the network.
I used
-          NetBeans IDE 6.9.1
-          Java DB with derby driver


1.      2. Created tables Parent [id, pname], Child [pid, cname] and Contact [pid, address]

2.      3. Setup a project in your IDE, use Java 5 and included derbyclient.jar and toplink-essentials.jar to the list of dependency libraries

3.     4. Create Entity classes as follows

package jpa;

import java.io.Serializable;
import java.util.List;
import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToMany;

/**
  * @author Nageswara Rao V
  */

@Entity
public class Parent implements Serializable {

    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE)
    private String id;
    private String pname;

    @OneToMany(mappedBy="myparent", cascade=CascadeType.PERSIST)
    private List<Child> children;

    @OneToMany(mappedBy="myparent", cascade=CascadeType.PERSIST)
    private List<Contact> contacts;

    public String getId() {
        return id;
    }
    public void setId(String id) {
        this.id = id;
    }
    public String getPname() {
        return this.pname;
    }
    public void setPname(String name) {
        this.pname = name;
    }
    public List<Contact> getContacts() {
        return contacts;
    }
    public void setContacts(List<Contact> contacts) {
        this.contacts = contacts;
    }
    public List<Child> getChildren() {
        return children;
    }
    public void setChildren(List<Child> children) {
        this.children = children;
    }
}



package jpa;

import java.io.Serializable;
import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;

/**
 * @author Nageswara Rao V
 */
@Entity
public class Contact implements Serializable {

    @ManyToOne(fetch=FetchType.LAZY, cascade=CascadeType.PERSIST)
    @JoinColumn(name="pid", nullable=false)
    Parent myparent;

    @Id
    private String address;

    public String getAddress() {
        return address;
    }
    public void setAddress(String address) {
        this.address = address;
    }
    public Parent getMyparent() {
        return myparent;
    }
    public void setMyparent(Parent myparent) {
        this.myparent = myparent;
    }
}

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package jpa;

import java.io.Serializable;
import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;

/**
 * @author Nageswara Rao V
 */
@Entity
public class Child implements Serializable {

    @ManyToOne(fetch=FetchType.LAZY, cascade=CascadeType.PERSIST)
    @JoinColumn(name="pid", nullable=false)
    Parent myparent;

    @Id
    private String cname;

    public String getCname() {
        return cname;
    }
    public void setCname(String pname) {
        this.cname = pname;
    }
    public Parent getMyparent() {
        return myparent;
    }
    public void setMyparent(Parent myparent) {
        this.myparent = myparent;
    }
}




4.       5. Create META-INF/persistence.xml resource with the properties for database

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="1.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 persistence_1_0.xsd">
  <persistence-unit name="default" transaction-type="RESOURCE_LOCAL">
    <provider>oracle.toplink.essentials.PersistenceProvider</provider>
    <class>jpa.Parent</class>
    <class>jpa.Child</class>
    <class>jpa.Contact</class>
    <properties>
      <property name="toplink.logging.level" value="FINEST"/>
      <property name="toplink.jdbc.driver" value="org.apache.derby.jdbc.ClientDriver"/>
      <property name="toplink.jdbc.url" value="jdbc:derby://localhost:1527/sample"/>
      <property name="toplink.jdbc.user" value="app"/>
      <property name="toplink.jdbc.password" value="app"/>
    </properties>
  </persistence-unit>
</persistence>

5.       6. Create a test to persist entity relation and run it

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

import java.util.ArrayList;
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;

/**
 * @author Nageswara Rao V
 */
public class TestParentChild {

    public static void main(String[] args) {

        EntityManagerFactory emf = Persistence.createEntityManagerFactory("default", new java.util.HashMap());
        EntityManager entityManager = (EntityManager) emf.createEntityManager();
       
        // Don't forget to begin transaction as it involved multiple entities
        entityManager.getTransaction().begin();

        // Create parent entity
        Parent myparent = new Parent();
        myparent.setPname("rao");

        // Parent can have more than one address
        List<Contact> contacts = new ArrayList<Contact>();

        Contact chennai = new Contact();
        chennai.setAddress("chennai address");
        chennai.setMyparent(myparent);
        contacts.add(chennai);

        Contact hyd = new Contact();
        hyd.setAddress("Hyd address");
        hyd.setMyparent(myparent);
        contacts.add(hyd);

        // Associate contacts to parent
        myparent.setContacts(contacts);

        // More children to parent
        List<Child> children = new ArrayList<Child>();

        // Child one
        Child nish = new Child();
        nish.setCname("nishanth");
        nish.setMyparent(myparent);
        children.add(nish);

        // Child two
        Child sri = new Child();
        sri.setCname("Shri");
        sri.setMyparent(myparent);
        children.add(sri);

        // Associate parent with children
        myparent.setChildren(children);

        // That's it... persist
        entityManager.persist(myparent);

        // Commit the transaction
        entityManager.getTransaction().commit();
    }
}

Wednesday, June 15, 2011

Loop around an array in said direction

/*
 * Class to loop an array of elements in said direction.
 */

package logic;

/**
 *
 * @author Nageswara Rao. V
 */
public class LoopArray {

    int dir = 1; // direction +1 -> forward, -1 -> reverse
    int startPos = 0; // init at zero position
    int[] source = new int[0]; // source array
    int curPos = 0; // current position in iterator
    boolean hasNext = false; // next available?

    /**
     * setter for loop direction
     *
     * @param inDir - direction of loop
     */
    public void setDirection(int inDir) {
        if(inDir > 0) {
            dir = 1;
        } else if (inDir < 0) {
            dir = -1;
        }
    }

    /**
     * setter for source array
     *
     * @param src - source array
     */
    public boolean setSource(int[] src) {
        if(src.length > 0) {
            source = src;
            hasNext = true;
            return true;
        }
        return false;
    }

    /**
     * setter for position to start looping
     *
     * @param src - source array
     */
    public boolean setStartPos(int pos) {
        if(pos > 0 && pos < source.length) {
            startPos = pos;
            curPos = pos;
            return true;
        }
        return false;
    }

    /**
     * acessor of next status
     *
     */
    public boolean hasNext() {
        return hasNext;
    }

    /**
     * calculates next position
     *
     * @param src - source array
     */
    private int getNextPos() {
        int lcurrent = (curPos+dir+source.length) % source.length;;
        return lcurrent;
    }

    /**
     * returns next value and resets current pointer
     *
     * @param src - source array
     */
    public int next() {
        int value = source[curPos];
        int nxtPos = getNextPos();
        if((hasNext = (startPos != nxtPos))) {
            curPos = nxtPos;
        }
        return value;
    }

    /**
     * reset current position and hasNext status
     *
     * @param src - source array
     */
    public void reset() {
        curPos = startPos;
        hasNext = true;
    }

    public static void main(String args[]) {
        int[] src = {90, 80, 70, 60, 50, 40, 30, 20, 10, 00};
        LoopArray bdt = new LoopArray();
        bdt.setSource(src);
        bdt.setDirection(-1);
        bdt.setStartPos(src.length-1);
        while(bdt.hasNext()) {
            System.out.println(bdt.next());
        }
    }
}

Wednesday, June 8, 2011

A simple configuration utility using StAX Parser

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package xml.parse;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.net.URLDecoder;
import java.util.Enumeration;
import javax.xml.stream.events.Attribute;
import java.util.Properties;
import javax.xml.namespace.QName;
import javax.xml.stream.EventFilter;
import javax.xml.stream.XMLEventReader;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.events.StartElement;
import javax.xml.stream.events.XMLEvent;

/**
 * Class to parse configuration properties and serve values in required format
 *
 * @author Nageswara Rao. V
 */
public class ConfigUtil implements IConfig {

    String filePath; // Path of configuration file
    String[] types; // list of types to parse, will be left null to skip type filter
    String[] tags; //list of tags to parse, will be left null to handle all tags
    Properties props = new Properties();

    /**
     * Constructor to initialize configuration utility
     *
     * @param filePath - Path to configuration file
     * @param types - array of types to filter
     */
    public ConfigUtil(String filePath, String[] propTags, String[] types) {
        this.filePath = filePath;
        this.types = types;
        this.tags = propTags;
        loadConfig();
    }

    /**
     * Overloaded Constructor to skip type filter
     *
     * @param filePath - Path to configuration file
     * @param propTags - array of tags to handle
     */
    public ConfigUtil(String filePath, String[] propTags) {
        this(filePath, propTags, null);
    }

    /**
     * Overloaded Constructor to skip type filter handle all tags declared
     *
     * @param filePath - Path to configuration file
     * @param propTags - array of tags to handle
     */
    public ConfigUtil(String filePath) {
        this(filePath, null, null);
    }

    /**
     * Method to load and parse properties and populates props object
     */
    private void loadConfig() {
        try {
            XMLConfigParser parser = new XMLConfigParser(filePath);
            parser.setTagFilter(tags);
            parser.setTypeFilter(types);
            props = parser.parseProps();
        } catch (ConfigException cExp) {
            System.out.println("Failed to parse config file. Return values will be default values");
        }
    }

    /**
     *
     * @return - Current configuration
     */
    public Properties getConfig() {
        return props;
    }

    /**
     * To returns integer value
     *
     * @param key - property key
     * @param def - default integer value
     * @return - integer value
     */
    public int getIntegerValue(String key, int def) {
        String value = props.getProperty(key);
        try {
            return Integer.parseInt(value);
        } catch (Exception numfExp) {
            System.out.println("Invalid integer "+value);
        }
        return def;
    }

    /**
     * To return String value
     *
     * @param key - Property key
     * @param def - default string value
     * @return - string value
     */
    public String getValue(String key, String def) {
        String value = props.getProperty(key);
        if (value == null) {
            return def;
        }
        return value;
    }

    /**
     * To return double value
     *
     * @param key - Property key
     * @param def - default double value
     * @return - double value
     */
    public double getDoubleValue(String key, double def) {
        String value = props.getProperty(key);
        try {
            return Double.parseDouble(value);
        } catch (Exception numfExp) {
            System.out.println("Invalid double "+value);
        }
        return def;
    }

    /**
     * To return long value
     *
     * @param key - property key
     * @param def - default long value
     * @return - long value
     */
    public long getLongValue(String key, long def) {
        String value = props.getProperty(key);
        try {
            return Long.parseLong(value);
        } catch (Exception numfExp) {
            System.out.println("Invalid long "+value);
        }
        return def;
    }

    /**
     * To return double value
     *
     * @param key - Property key
     * @param def - default double value
     * @return - double value
     */
    public float getFloatValue(String key, float def) {
        String value = props.getProperty(key);
        try {
            return Float.parseFloat(value);
        } catch (Exception numfExp) {
            System.out.println("Invalid float "+value);
        }
        return def;
    }

    /**
     * Class to parse and extract configurations from xml file
     */
    class XMLConfigParser {

        private final String ATTR_TYPE = "TYPE"; // Identifier of TYPE attribute
        private final String ATTR_KEY = "KEY"; // Identifier of KEY attribute
        private final String ATTR_VALUE = "VALUE"; // Identifier of VALUE attribute
        String[] typeFilters = new String[0];
        String[] tagFilters = new String[0];

        File configFile; // configuration file object

        Properties configProps = new Properties();

        /**
         * Constructor to initialize XML StAX Parser with the given configuration
         * file written in well formed xml format
         *
         * @param filePath - path to configuration xml
         * @throws ConfigException
         */
        public XMLConfigParser(String filePath) throws ConfigException {
            this.configFile = loadFile(filePath);
        }

        /**
         * Method to validate and load configuration file
         *
         * @param filePath - file path
         * @return - File object if the path locates valid configuration xml
         * @throws ConfigException
         */
        private File loadFile(String filePath) throws ConfigException {
            File configFile = null;
            filePath = URLDecoder.decode(filePath);
            if ((filePath != null) && (configFile = new File(filePath)).exists() && configFile.isFile()) {
                    return configFile;
            } else {
                throw new ConfigException("Invalid config file : "+filePath, null);
            }
        }

        /**
         * Method to set tags that needs to pay attention
         *
         * @param tags - array of tags
         */
        public void setTagFilter(String[] tags) {
            if(tags != null) {
                this.tagFilters = tags;
            }
        }

        /**
         * Method to set attributes that needs to pay attention
         *
         * @param tags - array of attributes
         */
        public void setTypeFilter(String[] attrs) {
            if(attrs != null) {
                this.typeFilters = attrs;
            }
        }

        /**
         * Parse and extract attributes in <PROP> tag, enforce if filter is defined
         *
         * @throws ConfigException
         */
        public Properties parseProps() throws ConfigException {
            XMLEventReader reader = getReader();
            if(typeFilters == null || typeFilters.length == 0) {
                parseAttributes(reader);
            } else {
                parseFilteredAttributes(reader);
            }
            return configProps;
        }

        /**
         * Method to key/value from filtered types
         *
         * @param reader - StAX reader to run through the document
         * @throws ConfigException
         */
        private void parseFilteredAttributes(XMLEventReader reader) throws ConfigException {
            while(reader.hasNext()) {
                StartElement startElement = null;
                if((startElement = getStartElement(reader)) != null) {
                    Attribute attr = startElement.getAttributeByName(new QName(ATTR_TYPE));
                    if(attr != null && acceptAttribute(attr)) {
                        extractProperty(startElement);
                    }
                }
            }
        }

        private boolean acceptAttribute(Attribute attr) {
            String value = attr.getValue();
            for(int indx = 0; indx < typeFilters.length; indx++) {
                if(typeFilters[indx].equalsIgnoreCase(value)) {
                    return true;
                }
            }
            return false;
        }

        /**
         * Method to parse key/value from all <PROP> tags
         *
         * @param reader - StAX reader to run through the document
         * @param TAG_NAME - Tag name to handle
         * @throws ConfigException
         */
        private void parseAttributes(XMLEventReader reader) throws ConfigException {
            while(reader.hasNext()) {
                StartElement startElement = null;
                if((startElement = getStartElement(reader)) != null) {
                    extractProperty(startElement);
                }
            }
        }

        private StartElement getStartElement(XMLEventReader reader) throws ConfigException {
            StartElement startElement = null;
            try {
                XMLEvent event = reader.nextEvent();
                if(event.isStartElement()) {
                    startElement = event.asStartElement();
                }
            } catch (XMLStreamException xmlStrmExp) {
                throw new ConfigException("Exception while reading next event", xmlStrmExp);
            }
            return startElement;
        }

        /**
         * Method to extract key/value from tag
         *
         * @param startElement - Element to parse
         */
        private void extractProperty(StartElement startElement) {
            Attribute keyAttr = startElement.getAttributeByName(new QName(ATTR_KEY));
            if(keyAttr == null) {
                return;
            }
            String key = keyAttr.getValue();
            String value = startElement.getAttributeByName(new QName(ATTR_VALUE)).getValue();
            if(key != null) {
                configProps.put(key, value);
            }
        }

        /**
         * Method to construct StAX reader to parse the xml
         *
         * @return - Handle to reader
         * @throws ConfigException
         */
        private XMLEventReader getReader() throws ConfigException {
            XMLEventReader parser = null;
            try {
                FileInputStream inStream = new FileInputStream(configFile);
                XMLInputFactory factory = XMLInputFactory.newInstance();
                parser = factory.createXMLEventReader(inStream);
                parser = factory.createFilteredReader(parser, new PropEventFilter(tagFilters));
            } catch (FileNotFoundException fnfExp) {
                throw new ConfigException("Invalid Config file", fnfExp);
            } catch (XMLStreamException xmlSExp) {
                throw new ConfigException("Invalid config format", xmlSExp);
            }
            return parser;
        }
    }

    /**
     * Class to filter meta and only the filtered tags from xml document
     */
    class PropEventFilter implements EventFilter {

        String[] tagFilters = new String[0];

        PropEventFilter() {
        }

        PropEventFilter(String[] tagFilters) {
            this.tagFilters = tagFilters;
        }

        public boolean accept(XMLEvent event) {
            return doAccept(event);
        }

        private boolean doAccept(XMLEvent event) {
            // Exclude PIs
            if(event.isProcessingInstruction()) {
                return false;
            } else if (tagFilters.length > 0) {
                // filter tag if set
                boolean accept = false;
                StartElement startElement = null;
                if(event.isStartElement()) {
                    startElement = event.asStartElement();
                    String tag = startElement.getName().toString();
                    for(int idx = 0; idx < tagFilters.length; idx++) {
                        if(tag.equalsIgnoreCase(tagFilters[idx])) {
                            accept = true;
                            break;
                        }
                    }
                }
                return accept;
            }
            return true;
        }
    }

    /**
     *
     * Class to handle exceptions while parsing
     */
    class ConfigException extends Exception {
        String message;

        public ConfigException(String message, Throwable exp) {
            super(exp);
            this.message = message;
        }

        public String getMessage() {
            return message;
        }
    }

    public static void main(String args[]) {
        try {
            System.out.println("With types");
            String[] types = {"person", "address", "employment"};
            String[] tags = {"PROP"};
            ConfigUtil cfgUtil = new ConfigUtil("D:\\ws\\algorithms\\algorithms\\config.xml",
                    tags, types);

            System.out.println("Name : "+cfgUtil.getValue("name", "Default Value"));
            System.out.println("Sal : "+cfgUtil.getIntegerValue("age", 25));
            System.out.println("double : "+cfgUtil.getDoubleValue("salary", 25));

            System.out.println("General accessor");
            Properties props = cfgUtil.getConfig();
            Enumeration enumrt = props.keys();
            while(enumrt.hasMoreElements()) {
                String name  = (String)enumrt.nextElement();
                String value  = (String)props.getProperty(name);
                System.out.println("Name : "+name+ " Value : "+value);
            }
        } catch (Exception exp) {
            exp.printStackTrace();
            System.out.println("Exception "+exp.getMessage());
        }
    }
}

/*---- Sample configuration ---*/
<?xml version="1.0" encoding="UTF-8"?>

<!--
    Document   : config.xml
    Created on : May 23, 2011, 12:53 PM
    Author     : Nageswara Rao. V
    Description:
        Purpose of the document follows.
-->

<CONFIG>
    <PROP TYPE="person" KEY="name" VALUE="RAO"/>
    <PROP TYPE="person" KEY="age" VALUE="30"/>
    <PROP TYPE="person" KEY="height" VALUE="177"/>
    <PROP TYPE="employment" KEY="salary" VALUE="4550.00"/>
    <PROP TYPE="employment" KEY="firm" VALUE="ABC Inc."/>
    <PROP TYPE="address" KEY="dno" VALUE="170"/>
    <PROP TYPE="address" KEY="street" VALUE="AS Puram"/>
    <PROP TYPE="address" KEY="city" VALUE="Chennai"/>
</CONFIG>

Insertion sort

package algorithms.sort;

/**
 *
 * @author Nageswara Rao. V
 * @version 1.0 date : June 8, 2011
 */
public class InsertionSort {
    public static int[] insertionSort(int[] src) {
        for(int pos = 1; pos < src.length; pos++) {
            int i = pos;
            while((i>0) && (src[i] < src[i-1])) {
                swap(src, i, i-1);
                i = i-1;
            }
        }
        return src;
    }

    public static void swap(int[] src, int start, int end) {
        src[start] = src[start]+src[end];
        src[end] = src[start] - src[end];
        src[start] = src[start] - src[end];
    }

    public static void print(int[] src) {
        for(int i=0; i < src.length; i++) {
            System.out.print(src[i]+" ");
        }
    }

    public static void main(String args[]) {
        int[] src = {4, 3, 8, 2, 1, 0};
        System.out.println("\nSource");
        print(src);
        insertionSort(src);
        System.out.println("\nResult");
        print(src);
        System.out.println("\n");
    }
}