Wednesday, May 17, 2017

Custom Functions using Saxon HE

INTRODUCTION

SOFTWARES & TOOLS

  1. Eclipse IDE (Mars) with Maven Plugin
  2. Java 8
  3. Saxon-HE-9.7.0-18

EXAMPLE

Saxon has many inbuilt functions but after 9.2 version, those functions are moved to licensed versions PE & HE. We need to have proper license file to use the inbuilt functions.

In this post, we are going to learn how to write custom functions using Saxon-HE. These custom functions also called integrated extension functions.

Follow the below steps to calculate & display age using the date of birth of the employees.

Step 1

Create a Maven Project in eclipse and copy paste the below code into pom.xml dependency.
<dependency>
     <groupId>net.sf.saxon</groupId>
     <artifactId>Saxon-HE</artifactId>
     <version>9.7.0-18</version>
</dependency>



Step 2

Create a Java Class AgeCalculator.java which extends ExtensionFunctionDefinition.java as below.
package jbr.saxon;

import java.time.LocalDate;
import java.time.Period;

import net.sf.saxon.expr.XPathContext;
import net.sf.saxon.lib.ExtensionFunctionCall;
import net.sf.saxon.lib.ExtensionFunctionDefinition;
import net.sf.saxon.om.Sequence;
import net.sf.saxon.om.StructuredQName;
import net.sf.saxon.trans.XPathException;
import net.sf.saxon.value.SequenceType;
import net.sf.saxon.value.StringValue;

public class AgeCalculator extends ExtensionFunctionDefinition {

@Override
public SequenceType[] getArgumentTypes() {
return new SequenceType[] { SequenceType.SINGLE_STRING };
}

@Override
public StructuredQName getFunctionQName() {
return new StructuredQName("emp", "http://example.com/saxon-extension", "ageCalc");
}

@Override
public SequenceType getResultType(SequenceType[] arg0) {
return SequenceType.SINGLE_STRING;
}

@Override
public ExtensionFunctionCall makeCallExpression() {
return new ExtensionFunctionCall() {

@Override
public Sequence call(XPathContext ctx, Sequence[] args) throws XPathException {
String output = null;

String[] input = args[0].iterate().next().getStringValue().split("-");
int year = Integer.valueOf(input[0]);
int month = Integer.valueOf(input[1]);
int dayOfMonth = Integer.valueOf(input[2]);

LocalDate dob = LocalDate.of(year, month, dayOfMonth);
output = String.valueOf(Period.between(dob, LocalDate.now()).getYears());

return StringValue.makeStringValue(output);
}

};
}
}

Note:
  1. Mention no. of arguments and its types at getArgumentTypes() method
  2. Define the output type at getResultType() method
  3. I have written inner class in makeCallExpression() method for my simple requirement, you can create separate class and extend ExtensionFunctionCall.java
  4. http://example.com/saxon-extension - you can give any url.
  5. Also, you can choose your own name for emp & ageCalc

Step 3

Create a Java class AgeCalculatorMain.java to test the custom function as below.
package jbr.saxon;

import java.io.File;

import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;

import net.sf.saxon.Configuration;
import net.sf.saxon.TransformerFactoryImpl;
import net.sf.saxon.trans.XPathException;

public class AgeCalculatorMain {

public static void main(String[] args) throws XPathException {
// Set saxon as your transformer.
System.setProperty("javax.xml.transform.TransformerFactory", "net.sf.saxon.TransformerFactoryImpl");

// specify input and output
transform("testdata/input/employees.xml", "testdata/input/employees.xsl", "testdata/output/output.html");
}

public static void transform(String sourcePath, String xsltPath, String resultDir) {
try {
TransformerFactory factory = TransformerFactory.newInstance();

if (factory instanceof TransformerFactoryImpl) {
TransformerFactoryImpl tFactoryImpl = (TransformerFactoryImpl) factory;
Configuration config = tFactoryImpl.getConfiguration();
config.registerExtensionFunction(new AgeCalculator());
}

Transformer transformer = factory.newTransformer(new StreamSource(new File(xsltPath)));
transformer.transform(new StreamSource(new File(sourcePath)), new StreamResult(new File(resultDir)));

System.out.println("Output generated successfully at: " + resultDir);
} catch (TransformerException e) {
e.printStackTrace();
}
}
}


Step 4

Create an input xml file (employees.xml)
<?xml version="1.0" encoding="UTF-8"?>
<employees>
 <employee>
   <name>Anbu</name>
   <address>Chennai</address>
   <dob>1990-05-15</dob>
   <phone>9600096000</phone>
   <email>anbu@email.com</email>
 </employee>
 <employee>
   <name>Bala</name>
   <address>Hydrabad</address>
   <dob>1989-01-04</dob>
   <phone>9700097000</phone>
   <email>bala@email.com</email>
 </employee>
 <employee>
   <name>Chandru</name>
   <address>Mumbai</address>
   <dob>1995-11-10</dob>
   <phone>9900099000</phone>
   <email>chandru@email.com</email>
 </employee>
</employees>


Step 5

Create an XSLT file (employees.xsl). Define the custom function and call it.

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:emp="http://example.com/saxon-extension">
 <xsl:template match="/">
   <html>
     <body>
       <h2>Employee Details</h2>
       <table border="1">
         <tr bgcolor="#9acd32">
           <th style="text-align:left">Name</th>
           <th style="text-align:left">Address</th>
           <th style="text-align:left">Date of Birth</th>
           <th style="text-align:left">Age</th>
           <th style="text-align:left">Phone</th>
           <th style="text-align:left">Email</th>
         </tr>
         <xsl:for-each select="employees/employee">
           <tr>
             <td>
               <xsl:value-of select="name" />
             </td>
             <td>
               <xsl:value-of select="address" />
             </td>
             <td>
               <xsl:value-of select="dob" />
             </td>
             <td>
               <xsl:value-of select="emp:ageCalc(dob)" />
             </td>
             <td>
               <xsl:value-of select="phone" />
             </td>
             <td>
               <xsl:value-of select="email" />
             </td>
           </tr>
         </xsl:for-each>
       </table>
     </body>
   </html>
 </xsl:template>
</xsl:stylesheet>


OUTPUT

Now Run the AgeCalculatorMain.java and the output html file will be copied to /testdata/output/output.html
Open the output.html in any browser.
That’s all about writing a custom function using Saxon HE version. Please share your comments.
Happy Knowledge Sharing!!!

Tuesday, April 25, 2017

Iterator Design Pattern in Java

INTRODUCTION

  • Iterator Design pattern is categorized under Behavioral Patterns.
  • It enables the access to all the element of an aggregate object (list of). Iteration will be performed on the collection of elements of the object sequentially without exposing the actual representation.
  • Also, enables the traversal on the element of different data structures.
  • Separating the traversal responsibility from the client code and moving to another class called Iterator. It holds the details about which elements are traversed and which elements yet to be traversed.
  • An iterator will be defined as an Interface in java and have the basic methods next() and hasNext().
    • next() method helps to get the next element in the object.
    • hasNext() method helps to check whether we have more elements to traverse.

EXAMPLE

  1. java.util.Iterator
  2. java.util.Enumeration

CLASS DIAGRAM

ENTITIES

The following entities or component will be involved in Iterator Design Pattern.
  1. Iterator
  • It is an interface defined with basic methods for accessing elements and traversing the elements.
  1. ConcreteIterator
  • Implementation of Iterator interface and keep track of all the traversal details.
  1. Aggregate
  • It is also an interface to create Iterator Object.
  1. ConcreteAggregate
  • Implementation of Aggregate Interface

USECASE

Getting the final approval for the student to receive the certificate.

PROBLEM

Usually, the college will have two different application for Finance Department and Library Department.
Each may have its own implementation. Consider Finance application has the Array implementation and Library application has the List implementation.
Create Library application (LibraryDepartment.java).
import java.util.ArrayList;
import java.util.List;

import jbr.iteratorpattern.common.Student;

public class LibraryDepartment {

 // list of student who are all got book from library.
 private List<Student> issuedTo;
 
 public LibraryDepartment() {
   issuedTo = new ArrayList<Student>();

   addStudent("Anbu", "CSE", 10001, "chennai", 98439843);
   addStudent("Bala", "IT", 20001, "bangalore", 93343433);
   addStudent("Chandru", "MECH", 30001, "chennai", 98456653);
 }

 public void addStudent(String name, String department, int regNo, String address, long phone) {
   Student student = new Student(name, department, regNo, address, phone);
   issuedTo.add(student);
 }

 // who are all got this book from library.
 public List<Student> getStudents() {
   return issuedTo;
 }

}

Create another class (LibraryClearance.java) which will provide the student report for the clearance process.
import jbr.iteratorpattern.common.Student;

public class LibraryClearance {

 public void getReport() {
   LibraryDepartment libraryDepartment = new LibraryDepartment();

   for (Student student : libraryDepartment.getStudents()) {

     System.out.println("Reg No: " + student.getRegNo());
     System.out.println("Name: " + student.getName());
     System.out.println("Department: " + student.getDepartment());
     System.out.println("Address: " + student.getAddress());
     System.out.println("Phone: " + student.getPhone());
     System.out.println("\n");
   }
 }
}

Now create the Finance application which implements the Array Concept.
public class FinanceDeptartment {

 static final int MAX_STUDENTS = 2;
 int noOfStudents = 0;

 // students who are all yet to pay the fees.
 Student[] feesBalance;

 public FinanceDeptartment() {
   feesBalance = new Student[MAX_STUDENTS];

   addStudent("Anbu", "CSE", 10001, "chennai", 98439843);
   addStudent("Bala", "IT", 20001, "bangalore", 93343433);
 }

 public void addStudent(String name, String department, int regNo, String address, long phone) {
   Student student = new Student(name, department, regNo, address, phone);

   if (noOfStudents >= MAX_STUDENTS) {
     System.out.println("Sorry maximum students reached. Pay Attention!!!");
   } else {
     feesBalance[noOfStudents] = student;
     noOfStudents = noOfStudents + 1;
   }
 }

 public Student[] getStudents() {
   return feesBalance;
 }
}

Now create a class for finance clearance.(FinanceClearance.java)
import jbr.iteratorpattern.common.Student;

public class FinanceClearance {

 public void getReport() {
   FinanceDeptartment financeDepartment = new FinanceDeptartment();
   Student[] students = financeDepartment.getStudents();

   for (int i = 0; i < students.length; i++) {
     Student student = students[i];

     System.out.println("Reg No: " + student.getRegNo());
     System.out.println("Name: " + student.getName());
     System.out.println("Department: " + student.getDepartment());
     System.out.println("Address: " + student.getAddress());
     System.out.println("Phone: " + student.getPhone());
     System.out.println("\n");
   }
 }
}

Now create a client to proceed clearance process.
(IteratorPatternProblem .java)
public class IteratorPatternProblem {

 public static void main(String[] args) {

   System.out.println("FINANCE REPORTS");
   System.out.println("=========================");
   FinanceClearance financeClearance = new FinanceClearance();
   financeClearance.getReport();

   System.out.println("\nLIBRARY REPORTS");
   System.out.println("=========================");
   LibraryClearance libraryClearance = new LibraryClearance();
   libraryClearance.getReport();

 }
}

OUTPUT


FINANCE REPORTS
=========================
Reg No: 10001
Name: Anbu
Department: CSE
Address: chennai
Phone: 98439843


Reg No: 20001
Name: Bala
Department: IT
Address: bangalore
Phone: 93343433



LIBRARY REPORTS
=========================
Reg No: 10001
Name: Anbu
Department: CSE
Address: chennai
Phone: 98439843


Reg No: 20001
Name: Bala
Department: IT
Address: bangalore
Phone: 93343433


Reg No: 30001
Name: Chandru
Department: MECH
Address: chennai
Phone: 98456653

The problem with the above implementation are
  1. The client has to write separate logic to access both applications.
  2. Iteration logic is tightly coupled.

SOLUTION

Through Iterator Design Pattern, we can solve this problem.
Here
Iterator -> StudentIterator
ConcreateIterator -> LibraryDepartmentIterator & FinanceDepartmentIterator
Aggregate -> Department
ConcreateAggregate -> LibraryDepartment & FinanceDepartment

Step 1

The clearance process basically checks whether a student has any pending item to be completed (library - books to return & finance - fees balance).
So define an interface for the Student.
public interface StudentIterator {
 boolean hasNext();
 Object next();
}

Also, define an another interface for Department.
public interface Department {
 StudentIterator getStudents();
}

Step 2

Now Create Iterators for Library & Finance Department which needs to implement the Student Iterator.
LibraryDepartmentIterator.java
import java.util.List;

import jbr.iteratorpattern.common.Student;

public class LibraryDepartmentIterator implements StudentIterator {
 List<Student> students;
 int index = 0;

 public LibraryDepartmentIterator(List<Student> students) {
   this.students = students;
 }

 @Override
 public boolean hasNext() {
   if (index < students.size())
     return true;
   else
     return false;
 }

 @Override
 public Object next() {
   Student student = students.get(index);
   index = index + 1;

   return student;
 }
}

FinanceDepartmentIterator.java
import jbr.iteratorpattern.common.Student;

public class FinanceDepartmentIterator implements StudentIterator {

 Student[] students;
 int index = 0;

 public FinanceDepartmentIterator(Student[] students) {
   this.students = students;
 }

 @Override
 public boolean hasNext() {
   if (index >= students.length || students[index] == null)
     return false;
   else
     return true;
 }

 @Override
 public Object next() {
   Student student = students[index];
   index = index + 1;

   return student;
 }
}

Step 3

Existing Library & Finance Department has to be modified as below.
LibraryDepartment.java
import java.util.ArrayList;
import java.util.List;

import jbr.iteratorpattern.common.Student;

public class LibraryDepartment implements Department {

 // list of student who are all got book from library.
 private List<Student> issuedTo;

 public LibraryDepartment() {
   issuedTo = new ArrayList<Student>();

   addStudent("Anbu", "CSE", 10001, "chennai", 98439843);
   addStudent("Bala", "IT", 20001, "bangalore", 93343433);
   addStudent("Chandru", "MECH", 30001, "chennai", 98456653);
 }

 public void addStudent(String name, String department, int regNo, String address, long phone) {
   Student student = new Student(name, department, regNo, address, phone);
   issuedTo.add(student);
 }

 /**
  * who are all got this book from library
  */
 @Override
 public StudentIterator getStudents() {
   return new LibraryDepartmentIterator(issuedTo);
 }
}

FinanceDepartment.java
import jbr.iteratorpattern.common.Student;

public class FinanceDepartment implements Department {

 static final int MAX_STUDENTS = 2;
 int noOfStudents = 0;

 // students who are all yet to pay the fees.
 Student[] feesBalance;

 public FinanceDepartment() {
   feesBalance = new Student[MAX_STUDENTS];

   addStudent("Anbu", "CSE", 10001, "chennai", 98439843);
   addStudent("Bala", "IT", 20001, "bangalore", 93343433);
 }

 public void addStudent(String name, String department, int regNo, String address, long phone) {
   Student student = new Student(name, department, regNo, address, phone);

   if (noOfStudents >= MAX_STUDENTS) {
     System.out.println("Sorry maximum students reached. Pay Attention!!!");
   } else {
     feesBalance[noOfStudents] = student;
     noOfStudents = noOfStudents + 1;
   }
 }

 /**
  * who are all got this book from library
  */
 @Override
 public StudentIterator getStudents() {
   return new FinanceDepartmentIterator(feesBalance);
 }
}

Step 4

Separate the clearance process from the client and make the client lightweight.
Clearance.java
public class Clearance {
 public void collectReport(Department financeDepartment, Department libraryDepartment) {
   System.out.println("\nFINANCE REPORTS");
   System.out.println("=========================");
   getReport(financeDepartment.getStudents());

   System.out.println("\nLIBRARY REPORTS");
   System.out.println("=========================");
   getReport(libraryDepartment.getStudents());
 }

 public void getReport(StudentIterator studentIterator) {
   while (studentIterator.hasNext()) {
     Student student = (Student) studentIterator.next();

     System.out.println("Reg No: " + student.getRegNo());
     System.out.println("Name: " + student.getName());
     System.out.println("Department: " + student.getDepartment());
     System.out.println("Address: " + student.getAddress());
     System.out.println("Phone: " + student.getPhone());
     System.out.println("\n");
   }
 }
}

Step 5

Now look at our simplified client (IteratorPatternSolution.java) .
public class IteratorPatternSolution {

 public static void main(String[] args) {
   Clearance clearance = new Clearance();
   clearance.collectReport(new FinanceDepartment(), new LibraryDepartment());
 }
}

OUTPUT



FINANCE REPORTS
=========================
Reg No: 10001
Name: Anbu
Department: CSE
Address: chennai
Phone: 98439843


Reg No: 20001
Name: Bala
Department: IT
Address: bangalore
Phone: 93343433



LIBRARY REPORTS
=========================
Reg No: 10001
Name: Anbu
Department: CSE
Address: chennai
Phone: 98439843


Reg No: 20001
Name: Bala
Department: IT
Address: bangalore
Phone: 93343433


Reg No: 30001
Name: Chandru
Department: MECH
Address: chennai
Phone: 98456653

WHEN TO USE?

The iterator design pattern can be used when
  1. Want to provide the access to the elements of an aggregate object without knowing its internal representation.
  2. Want to traverse an aggregate object which consists different data structures.
Hope this example clarifies the Iterator Design Pattern. Please share your comments and suggestions below.

Happy Knowledge Sharing!!!