Showing posts with label Java. Show all posts
Showing posts with label Java. Show all posts

Monday, January 11, 2016

Coherence backed by JPA with Java Client

We are using Order Entry Schema thats come as sample schema with Oracle Database Installation. For this blog, I have been using

  • Oracle 12c Database
  • Eclipse Mars
  • Coherence 12c 12.2.1

Here is the major steps for implementation

  • Creating JPA Persistence Unit and Entities
  • Create the Cache Configuration File for JPA
  • Create a Java Client to Interact with Data Object


Step 1 Creating JPA Persistence Unit and Entities

The first step in implementing JPA is creating entities & persistent configuration. I am assuming that you have created the necessary JPA project & added the required libraries for  creating the entities.

I am using Order, Order Entry & Product Information tables from the OE schema. The below is the corresponding java entities.

Orders.java

/**
 * The persistent class for the ORDERS database table.
 * 
 */
@Entity
@Table(name="ORDERS")
@NamedQuery(name="Order.findAll", query="SELECT o FROM Order o")
public class Order implements Serializable, PortableObject {
private static final long serialVersionUID = 1L;

@Id

@Column(name="ORDER_ID")
private long orderId;

@Column(name="CUSTOMER_ID")

private long customerId;

//@Column(name="ORDER_DATE")

//private Timestamp orderDate;

@Column(name="ORDER_MODE")

private String orderMode;

@Column(name="ORDER_STATUS")

private Float orderStatus;

@Column(name="ORDER_TOTAL")

private Float orderTotal;

@Column(name="PROMOTION_ID")

private long promotionId;

@Column(name="SALES_REP_ID")

private long salesRepId;

//bi-directional many-to-one association to OrderItem

@OneToMany(mappedBy="order", fetch=FetchType.EAGER)
private List<OrderItem> orderItems;

public Order() {

}



public List<OrderItem> getOrderItems() {

return this.orderItems;
}

public void setOrderItems(List<OrderItem> orderItems) {

this.orderItems = orderItems;
}

public OrderItem addOrderItem(OrderItem orderItem) {

getOrderItems().add(orderItem);
orderItem.setOrder(this);

return orderItem;

}

public OrderItem removeOrderItem(OrderItem orderItem) {

getOrderItems().remove(orderItem);
orderItem.setOrder(null);

return orderItem;

}

@Override

public void readExternal(PofReader in) throws IOException {
this.orderId = in.readLong(0);
this.customerId = in.readLong(1);
this.orderMode = in.readString(2);
this.orderStatus = in.readFloat(3);
this.orderTotal = in.readFloat(4);
this.promotionId = in.readLong(5);
this.salesRepId = in.readLong(6);
this.orderItems = in.readCollection(7, this.orderItems);
//this.orderDate = in.readObject(8);
}

@Override

public void writeExternal(PofWriter out) throws IOException {
out.writeLong(0, this.orderId);
out.writeFloat(1, this.customerId);
out.writeString(2, this.orderMode);
out.writeFloat(3, this.orderStatus);
out.writeFloat(4, this.orderTotal);
out.writeLong(5, this.promotionId);
out.writeLong(6, this.salesRepId);
out.writeCollection(7, this.orderItems);
//out.writeObject(8, this.orderDate);
}

}


OrderItem.Java

@Entity
@Table(name="ORDER_ITEMS")
@NamedQuery(name="OrderItem.findAll", query="SELECT o FROM OrderItem o")
public class OrderItem implements Serializable, PortableObject {
private static final long serialVersionUID = 1L;

@EmbeddedId

private OrderItemPK id;

@Column(name="QUANTITY")

private long quantity;

@Column(name="UNIT_PRICE")

private long unitPrice;

//bi-directional many-to-one association to Order

@ManyToOne
@JoinColumn(name="ORDER_ID")
private Order order;

//bi-directional many-to-one association to ProductInformation

@ManyToOne
@JoinColumn(name="PRODUCT_ID")
private ProductInformation productInformation;

public OrderItem() {

}

public OrderItemPK getId() {

return this.id;
}


public Order getOrder() {
return this.order;
}

public void setOrder(Order order) {

this.order = order;
}

public ProductInformation getProductInformation() {

return this.productInformation;
}

public void setProductInformation(ProductInformation productInformation) {

this.productInformation = productInformation;
}

@Override

public void readExternal(PofReader in) throws IOException {
this.quantity = in.readLong(0);
this.unitPrice = in.readLong(1);
this.productInformation = in.readObject(2);
this.id = in.readObject(3);
this.order = in.readObject(4);
//this.order = in.readObject(4);
}

@Override

public String toString() {
return "OrderItem [id=" + id + ", quantity=" + quantity + ", unitPrice=" + unitPrice + ", order=" + order
+ ", productInformation=" + productInformation + "]";
}

@Override

public void writeExternal(PofWriter out) throws IOException {
out.writeLong(0, this.quantity);
out.writeLong(1, this.unitPrice);
out.writeObject(2, this.productInformation);
out.writeObject(3, this.id);
out.writeObject(4, this.order);
}

}


OrderItemPK.java

package entities;

import java.io.IOException;

import java.io.Serializable;
import javax.persistence.*;

import com.tangosol.io.pof.PofReader;

import com.tangosol.io.pof.PofWriter;
import com.tangosol.io.pof.PortableObject;

/**

 * The primary key class for the ORDER_ITEMS database table.
 * 
 */
@Embeddable
public class OrderItemPK implements Serializable, PortableObject {
@Override
public String toString() {
return "OrderItemPK [orderId=" + orderId + ", lineItemId=" + lineItemId + "]";
}

//default serial version id, required for serializable classes.

private static final long serialVersionUID = 1L;

@Column(name="ORDER_ID", insertable=false, updatable=false)

private long orderId;

@Column(name="LINE_ITEM_ID")

private long lineItemId;

public OrderItemPK() {

}
public long getOrderId() {
return this.orderId;
}
public void setOrderId(long orderId) {
this.orderId = orderId;
}
public long getLineItemId() {
return this.lineItemId;
}
public void setLineItemId(long lineItemId) {
this.lineItemId = lineItemId;
}

public boolean equals(Object other) {

if (this == other) {
return true;
}
if (!(other instanceof OrderItemPK)) {
return false;
}
OrderItemPK castOther = (OrderItemPK)other;
return (this.orderId == castOther.orderId);
}

public int hashCode() {

//System.out.print("PK hashCode");
final int prime = 31;
int hash = 17;
hash = hash * prime + ((int) (this.orderId ^ (this.orderId >>> 32)));
hash = hash * prime + ((int) (this.lineItemId ^ (this.lineItemId >>> 32)));

return hash;
}

@Override
public void readExternal(PofReader in) throws IOException {
this.orderId = in.readLong(0);
this.lineItemId = in.readLong(1);
}

@Override

public void writeExternal(PofWriter out) throws IOException {
out.writeLong(0, this.orderId);
out.writeLong(1, this.lineItemId);
}
//@Override
public int compareTo(Object o) {
OrderItemPK i = (OrderItemPK) o;
    if(this.getOrderId() < i.getOrderId())
        return -1;

    if(this.getOrderId() > i.getOrderId())

        return 1;

    return 0;

}
}

ProductInformation.java

@Entity
@Table(name="PRODUCT_INFORMATION")
@NamedQuery(name="ProductInformation.findAll", query="SELECT p FROM ProductInformation p")
public class ProductInformation implements Serializable, PortableObject {

private static final long serialVersionUID = 1L;

@Id

@Column(name="PRODUCT_ID")
private long productId;

@Column(name="CATALOG_URL")

private String catalogUrl;

@Column(name="CATEGORY_ID")

private int categoryId;

@Column(name="LIST_PRICE")

private float listPrice;

@Column(name="MIN_PRICE")

private float minPrice;

@Column(name="PRODUCT_DESCRIPTION")

private String productDescription;

@Column(name="PRODUCT_NAME")

private String productName;

@Column(name="PRODUCT_STATUS")

private String productStatus;

@Column(name="SUPPLIER_ID")

private long supplierId;

@Column(name="WEIGHT_CLASS")

private int weightClass;

//bi-directional many-to-one association to OrderItem

@OneToMany(mappedBy="productInformation")
private List<OrderItem> orderItems;

public ProductInformation() {

}

public List<OrderItem> getOrderItems() {

return this.orderItems;
}

public void setOrderItems(List<OrderItem> orderItems) {

this.orderItems = orderItems;
}

public OrderItem addOrderItem(OrderItem orderItem) {

getOrderItems().add(orderItem);
orderItem.setProductInformation(this);

return orderItem;

}

public OrderItem removeOrderItem(OrderItem orderItem) {

getOrderItems().remove(orderItem);
orderItem.setProductInformation(null);
return orderItem;
}

@Override

public void readExternal(PofReader in) throws IOException {
this.productId = in.readLong(0);
this.catalogUrl = in.readString(1);
this.categoryId = in.readInt(2);
this.listPrice = in.readFloat(3);
this.minPrice = in.readFloat(4);
this.productDescription = in.readString(5);
this.productName = in.readString(6);
this.productStatus = in.readString(7);
this.supplierId = in.readLong(8);
this.weightClass = in.readInt(9);
}

@Override

public void writeExternal(PofWriter out) throws IOException {
out.writeLong(0, this.productId);
out.writeString(1, this.catalogUrl);
out.writeInt(2, this.categoryId);
out.writeFloat(3, this.listPrice);
out.writeFloat(4, this.minPrice);
out.writeString(5, this.productDescription);
out.writeString(6, this.productName);
out.writeString(7, this.productStatus);
out.writeLong(8, this.supplierId);
out.writeInt(9, this.weightClass);
}

}


persistence.java

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.1" xmlns="http://xmlns.jcp.org/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">
<persistence-unit name="OrderEntryPrj" transaction-type="RESOURCE_LOCAL">
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<class>entities.Order</class>
<class>entities.OrderItem</class>
<class>entities.OrderItemPK</class>
<class>entities.ProductInformation</class>
<properties>
<property name="eclipselink.target-server" value="None"/>
<property name="javax.persistence.jdbc.url" value="zzz:1521:orcl"/>
<property name="javax.persistence.jdbc.user" value="oe"/>
<property name="javax.persistence.jdbc.password" value="oracle"/>
<property name="javax.persistence.jdbc.driver" value="oracle.jdbc.OracleDriver"/>
      <property name="eclipselink.logging.timestamp" value="false"/>
      <property name="eclipselink.logging.thread" value="false"/>
      <property name="eclipselink.logging.session" value="false"/>
      <property name="eclipselink.logging.connection" value="false"/>
      <property name="eclipselink.logging.exceptions" value="true"/>
      <property name="eclipselink.cache.shared.default" value="false"/>
     
</properties>
</persistence-unit>
</persistence>


2. Create the Cache Configuration File for JPA

The 2nd step is to create coherence config file.

<cache-config>
  <caching-scheme-mapping>
    <cache-mapping>
      <!-- Set the name of the cache to be the entity name.  -->
      <cache-name>Order</cache-name>
      <!-- Configure this cache to use the following defined scheme. -->
      <scheme-name>jpa-distributed</scheme-name>
    </cache-mapping>
    <cache-mapping>
      <!-- Set the name of the cache to be the entity name.  -->
      <cache-name>OrderItem</cache-name>
      <!-- Configure this cache to use the following defined scheme. -->
      <scheme-name>jpa-distributed</scheme-name>
    </cache-mapping>
  </caching-scheme-mapping>
  <caching-schemes>
    <distributed-scheme>
      <scheme-name>jpa-distributed</scheme-name>
      <service-name>JpaDistributedCache</service-name>
       <serializer>
      <instance>
      <class-name>com.tangosol.io.pof.ConfigurablePofContext</class-name>
      <init-params>
        <init-param>
          <param-type>String</param-type>
          <param-value>pof-config.xml</param-value>
        </init-param>
      </init-params>
      </instance>
    </serializer>
      <backing-map-scheme>
        <read-write-backing-map-scheme>
          <internal-cache-scheme>
            <local-scheme/>
          </internal-cache-scheme>
          <!-- Define the cache scheme. -->
          <cachestore-scheme>
            <class-scheme>
              <class-name>
                com.tangosol.coherence.jpa.JpaCacheStore
              </class-name>
              <init-params>

                <!-- This param is the entity name. -->

                <init-param>
                  <param-type>java.lang.String</param-type>
                  <param-value>{cache-name}</param-value>
                </init-param>

                <!-- This param is the fully qualified entity class. -->

                <init-param>
                 <param-type>java.lang.String</param-type>
                  <param-value>entities.{cache-name}</param-value>
                </init-param>

                <!-- This param should match the value of the -->

                <!-- persistence unit name in persistence.xml. -->
                <init-param>
                  <param-type>java.lang.String</param-type>
                  <param-value>OrderEntryPrj</param-value>
                </init-param>
              </init-params>
            </class-scheme>
          </cachestore-scheme>
        </read-write-backing-map-scheme>
      </backing-map-scheme>
    <autostart>true</autostart>
    </distributed-scheme>
<!-- The below is required for extendes client. For this example, this can be removed -->
  <proxy-scheme>
      <service-name>ExtendTcpProxyService</service-name>
      <acceptor-config>
        <tcp-acceptor>
          <local-address>
            <address>localhost</address>
            <port>9099</port>
          </local-address>
        </tcp-acceptor>
        <serializer>
          <instance><class-name>com.tangosol.io.pof.ConfigurablePofContext</class-name></instance>
        </serializer>
      </acceptor-config>
      <autostart>true</autostart>
    </proxy-scheme>
  </caching-schemes>
</cache-config>


3. Create a Java Client to Interact with Data Object
package client;

public class OrderClient {

public static void main(String[] args) {

System.out.println("Accessing Coherence Cache from Java - Order Client");
Scanner in = new Scanner(System.in);
OrderItem item = null;
System.out.print("Enter Order ID to fetch: ");
String orderId = in.nextLine();
NamedCache<Object, Object> orderCache = CacheFactory.getCache("Order");


Order order1 = (Order) orderCache.get(Long.parseLong(orderId));
System.out.println("[Order ID: " + order1.getOrderId() + ", Order Mode: " + order1.getOrderMode()
+ ", Order Total: $" + order1.getOrderTotal() + ", Products Ordered = {");
int size = order1.getOrderItems().size();
for (int i = 0; i < size; i++) {
item = order1.getOrderItems().get(i);
System.out.println("ItemID: " + item.getId().getLineItemId() + ", Qty: " + item.getQuantity() + ", Product Name: " + item.getProductInformation().getProductName() + "#");
}
System.out.println("}");

order1.setOrderMode("online");
orderCache.put(orderId, order1);
Order order2 = (Order) orderCache.get(orderId);
System.out.println("Order Status:" + order2.getOrderStatus() + "<->Order Mode:" + order2.getOrderMode()
+ "<->:Order Item Size: " + order1.getOrderItems().size());

}


}



PS: Both Client & Server are using same coherence config in this example.