Author Archives: Vaithi Subramanian

MySQL Master/Slave configuration with EJB3 and JPA

Well this turned out to be quite an exercise.

The goal: scalable reads with MySQL in master-slave configuration, writing to the master, and reading from N slaves, load balanced in round-robin fashion (or something).

The problem: using JPA (Java Persistence API) instead of direct JDBC calls. Turns out the MySQL ReplicationDriver (used to load balance reads to slaves and send writes to the master) relies on the readOnly state of the Connection in order to decide whether it’s a read or a write. With direct JDBC calls, I could get the Connection and toggle the readOnly state as needed.
Continue reading

Building Multi-Criteria Search Queries in Hibernate

In this post I am going to show how to write queries multi-criteria search screens. There are two approaches for making this possible.

  • HQL for building the Query
  • Building Query using Criteria API

HQL for building the Query

Here I am going to show 2 approaches to building the HQL and try to point out the better approach.

Approach I:String concatenation
This approach uses String concatenation and setting up the values directly in the query.

if (startDate != null) {
   if (firstClause) {
      query = query + " where ";
   }
   else {
      query = query + " and ";
   }
 
   query += " s.date >= '" + startDate + "'";
}

Using the above approach there might be a chance of SQL Injection attack and using string concatenation is inherently error-prone.

Approach 2: Criteria as Named Parameters

In this one we create two map to hold parameter name and value which could be binded to the HQL during the execution.

Here is brief example of the approach.

public List search() {
   StringBuilder aQuery = 
      new StringBuilder(" from document p where p.id is not null ");
   HashMap parameterMap = new HashMap();
   HashMap parameterListMap =  new HashMap();
 
   //Collection Criteria
   if (countyList != null) {
      buildCollectionCriterion(aQuery, parameterListMap, "listID", countyList);
   }
 
   //Date Criteria
   if (startDate!= null || endDate != null) {
      buildDateCriterion(aQuery, parameterMap, "dateField",startDate, endDate);
   }
 
   Query query = hibSession.createQuery(aQuery.toString());
 
   for (String key : parameterMap.keySet()) {
      query.setParameter(key, parameterMap.get(key));
   }
 
   for (String key : parameterListMap.keySet()) {
      query.setParameterList(key, parameterListMap.get(key));
   }
 
   List results = query.list();
}
 
//Helper Methods for different type of criteria
 
protected void buildCollectionCriterion(StringBuilder aQuery, 
                                        Map parameterListMap, 
                                        String aFieldName, 
                                        Collection aList) {
   if (aList != null && !aList.isEmpty()) {
      aQuery
         .append(" and p.")
         .append(aFieldName)
         .append(" in (:")
         .append(aFieldName)
         .append(")");
      parameterListMap.put(aFieldName, aList);
   }
}
 
public void buildDateCriterion(StringBuilder aQuery, 
                               Map parameterMap, 
                               String aFieldName, 
                               Date aStartDate, 
                               Date anEndDate) {
   if (aStartDate != null && anEndDate != null) {
      aQuery
         .append(" and ( p."
         .append(aFieldName)
         .append(" between :aStartDate and :anEndDate)");
      parameterMap.put("aStartDate", aStartDate);
      parameterMap.put("anEndDate", anEndDate);
   }
   else if (aStartDate != null) {
      aQuery
         .append(" and  (p.")
         .append(aFieldName)
         .append(" >= :aStartDate)");
      parameterMap.put("aStartDate", aStartDate);
   } 
   else if (anEndDate != null) {
      aQuery
         .append(" and (p.")
         .append(aFieldName)
         .append(" <=:anEndDate");
      parameterMap.put("anEndDate", anEndDate);
   }
}

Building Query using Criteria API

public List search() {
        Criteria c = hibSession.createCriteria(Document.class);
        c.add(Restrictions.notNull("id"));
 
        if(countryList != null) {
                c.add(Restrictions.in("listId", countryList));
        }
 
        if(startDate != null) {
                c.add(Restrictions.ge("dateField", startDate);
        }
 
        if(endDate != null) {
                c.add(Restrictions.le("dateField", endDate);
        }
 
        return c.list();
}

Conclusion

The Hibernate Criteria API is a powerful and elegant library which is well adapted for implementing multi-criteria search functionality and also HQL queries must be built ‘on-the-fly’. Using it in appropriate circumstances will result in cleaner, clearer, more reliable and more maintainable code.

Image Processing Using ImageMagick and JMagick

Introduction to ImageMagick

ImageMagick® is a software suite to create, edit, and compose bitmap images. It can read, convert and write images in a variety of formats (over 100) including DPX, EXR, GIF, JPEG, JPEG-2000, PDF, PhotoCD, PNG, Postscript, SVG, and TIFF. Use ImageMagick to translate, flip, mirror, rotate, scale, shear and transform images, adjust image colors, apply various special effects, or draw text, lines, polygons, ellipses and Bézier curves.

The functionality of ImageMagick is typically utilized from the command line. In this blog I am focussing on how to use Java with ImageMagick. There are two options available to use ImageMagick

1)      JMagick provides an object-oriented Java interface to ImageMagick which I am going to show in this blog.

2)      Calling the ImagicMagick directly as the Command line using Runtime.getRuntime().exec(command);

Jmagick

JMagick is an open source Java interface of ImageMagick. It is implemented in the form of Java Native Interface (JNI) into the ImageMagick API.

JMagick does not attempt to make the ImageMagick API object-oriented. It is merely a thin interface layer into the ImageMagick API.

Image Conversion using Jmagick

This function shows how to convert one file format to other format mainly I am focusing on PDF to TIFF conversion. Conversion of PDF into multiple page TIFF  or single page TIFF and also the function is also extensible for accepting Compression Format such as GROUP4, FAX or JPEG.

public void convert(File inputFile, File outputDirectory, ImageType outputType, boolean multiple) {
 
if (inputFile != null &amp;&amp; inputFile.exists() &amp;&amp; ImageUtil.isValidMime(inputFile)) {
 
try {
 
ImageInfo info = getImageInfo(inputFile);
 
String fileName = inputFile.getName();
 
fileName = inputFile.getName().split("\\.")[0];
 
if (multiple) {
 
MagickImage image = new MagickImage(info);
 
MagickImage[] imArray = image.breakFrames();
 
for (int i = 0; i &lt; imArray.length; i++) {
 
StringBuilder outputFile = new StringBuilder(outputDirectory.getAbsolutePath());
 
outputFile.append(File.separatorChar);
 
File file = new File(outputFile.toString());
 
imArray[i].setFileName(file.getAbsolutePath());
 
imArray[i].writeImage(info);
 
}
 
} else {
 
StringBuilder outputFile = new StringBuilder(outputDirectory.getAbsolutePath());
 
outputFile.append(File.separatorChar);
 
outputFile.append(fileName);
 
outputFile.append(".");
 
outputFile.append(outputType.name().toLowerCase());
 
File file = new File(outputFile.toString());
 
report.addOutputFile(file);
 
info.setAdjoin(1);
 
MagickImage image = new MagickImage(info);
 
image.setFileName(file.getAbsolutePath());
 
image.writeImage(info);
 
}
 
} catch (Exception e) {
 
e.printStackTrace();
 
}
 
}
 
}
 
private ImageInfo getImageInfo(File inputName) throws MagickException {
 
String density = this.getProperties().getProperty(IMAGEMAGIC_DENSITY, "300");
 
ImageInfo info = new ImageInfo(inputName.getAbsolutePath());
 
info.setDensity(density);
 
info.setCompression(CompressionType.Group4Compression);
 
info.setColorspace(ColorspaceType.RGBColorspace);
 
return info;
 
}