Java

CXF @WebService and XMLGregorianCalendar with JAXB

Lately we’ve done a lot of work with some different web-services and at one point we discovered that some people have trouble formatting their timestamps properly. Good solution would be to ask people to use a proper standard and not re-invent their own wheels, but that’s not always a possibility. Fortunately there’s a rather simple solution for this. All you need is to define a @XmlJavaTypeAdapter and teach it how to convert different values into suitable formats.

JAXB and XML by default uses a timestamp format of “yyyy-MM-dd’T’HH:mm:ss’Z'” which translates to 2015-04-11T14:15:12.000 roughly and some people think it’s ok to send us SQL ISO format timestamps that look very similar – specifically missing the T letter in the timestamp, like this: “yyyy-MM-dd HH:mm:ss”.

For example, in my web service entity I have a RelaxedXMLGregorianCalendarAdapter in use which is our own implementation:

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType
@XmlRootElement(name = "Metainfo")
public class Metainfo {
    @XmlJavaTypeAdapter(RelaxedXMLGregorianCalendarAdapter.class)
    protected XMLGregorianCalendar generationTime;
}

And here’s the implementation for the adapter (note that we turn null, empty string and specifically a word “infinity” into null’s):

import javax.xml.bind.annotation.adapters.XmlAdapter;
import javax.xml.datatype.DatatypeFactory;
import javax.xml.datatype.XMLGregorianCalendar;

public class RelaxedXMLGregorianCalendarAdapter extends XmlAdapter<String, XMLGregorianCalendar> {

	@Override
	public String marshal(XMLGregorianCalendar v) {
		return v.toXMLFormat();
	}

	@Override
	public XMLGregorianCalendar unmarshal(String v) throws Exception {

		if (v == null) {
			return null;
		}
		
		if (v.trim().isEmpty()) {
			return null;
		}
		
		// Who thinks that this is OK for a date field?
		if ("infinity".equals(v.trim())) {
			return null;
		}
                // Replace the space with T to match our default pattern.
		return DatatypeFactory.newInstance().newXMLGregorianCalendar(v.replace(" ", "T"));
	}
}

So there you have it. This is how you can customize how JAXB is handling some type conversions and pretty much you can customize anything JAXB does with this approach. Like teach it to treat -1 for specific fields as null or teach it understand different date formats.

Java watermark image

Today I needed to add a watermark on my client images. I had a look around for available libraries. I didn’t find a good solutions that I could use straight out of the box in Java so I just created my own ImageUtil class and made my own Java watermark image method.

First things first – If we want to watermark an image then we have to decide on where should we anchor our watermark. For that I decided to use a simple ENUM called PlacementPosition:

public enum PlacementPosition {
	TOPLEFT, TOPCENTER, TOPRIGHT, MIDDLELEFT, MIDDLECENTER, MIDDLERIGHT, BOTTOMLEFT, BOTTOMCENTER, BOTTOMRIGHT
}

When you want to add a watermark then you probably need to resize it so you might want a good image resizer. That one I found and we can use an already existing one. I personally prefer to use Scalr named image library from https://github.com/thebuzzmedia/imgscalr because it’s very good, pretty damn fast and has controllable quality. Also it’s available on Maven repository.

So now the actual code of watermarking an image:


	/**
	 * Generate a watermarked image.
	 * 
	 * @param originalImage
	 * @param watermarkImage
	 * @param position
	 * @param watermarkSizeMaxPercentage
	 * @return image with watermark
	 * @throws IOException
	 */
	public static BufferedImage watermark(BufferedImage originalImage,
			BufferedImage watermarkImage, PlacementPosition position,
			double watermarkSizeMaxPercentage) throws IOException {

		int imageWidth = originalImage.getWidth();
		int imageHeight = originalImage.getHeight();

		int watermarkWidth = getWatermarkWidth(originalImage, watermarkImage,
				watermarkSizeMaxPercentage);
		int watermarkHeight = getWatermarkHeight(originalImage, watermarkImage,
				watermarkSizeMaxPercentage);

		// We create a new image because we want to keep the originalImage
		// object intact and not modify it.
		BufferedImage bufferedImage = new BufferedImage(imageWidth,
				imageHeight, BufferedImage.TYPE_INT_RGB);
		Graphics2D g2d = (Graphics2D) bufferedImage.getGraphics();
		g2d.drawImage(originalImage, 0, 0, null);
		g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
		        RenderingHints.VALUE_ANTIALIAS_ON);

		int x = 0;
		int y = 0;
		if (position != null) {
			switch (position) {
			case TOPLEFT:
				x = 0;
				y = 0;
				break;
			case TOPCENTER:
				x = (imageWidth / 2) - (watermarkWidth / 2);
				y = 0;
				break;
			case TOPRIGHT:
				x = imageWidth - watermarkWidth;
				y = 0;
				break;

			case MIDDLELEFT:
				x = 0;
				y = (imageHeight / 2) - (watermarkHeight / 2);
				break;
			case MIDDLECENTER:
				x = (imageWidth / 2) - (watermarkWidth / 2);
				y = (imageHeight / 2) - (watermarkHeight / 2);
				break;
			case MIDDLERIGHT:
				x = imageWidth - watermarkWidth;
				y = (imageHeight / 2) - (watermarkHeight / 2);
				break;

			case BOTTOMLEFT:
				x = 0;
				y = imageHeight - watermarkHeight;
				break;
			case BOTTOMCENTER:
				x = (imageWidth / 2) - (watermarkWidth / 2);
				y = imageHeight - watermarkHeight;
				break;
			case BOTTOMRIGHT:
				x = imageWidth - watermarkWidth;
				y = imageHeight - watermarkHeight;
				break;

			default:
				break;
			}
		}

		g2d.drawImage(Scalr.resize(watermarkImage, Method.ULTRA_QUALITY,
				watermarkWidth, watermarkHeight), x, y, null);

		return bufferedImage;

	}

watermark-full-width

That method uses some specific methods to calculate the watermark size. I wanted the user to be able to upload their own watermarks but that caused a problem where I didn’t want to hard-code the size of the watermark. So we ended up using a solution where we have defined a maximum percentage of size that the watermark can be relative to the original image.

For that we use these methods:



	/**
	 * 
	 * @param originalImage
	 * @param watermarkImage
	 * @param maxPercentage
	 * @return
	 */
	private static Pair<Double, Double> calculateWatermarkDimensions(
			BufferedImage originalImage, BufferedImage watermarkImage,
			double maxPercentage) {

		double imageWidth = originalImage.getWidth();
		double imageHeight = originalImage.getHeight();

		double maxWatermarkWidth = imageWidth / 100.0 * maxPercentage;
		double maxWatermarkHeight = imageHeight / 100.0 * maxPercentage;

		double watermarkWidth = watermarkImage.getWidth();
		double watermarkHeight = watermarkImage.getHeight();

		if (watermarkWidth > maxWatermarkWidth) {
			double aspectRatio = watermarkWidth / watermarkHeight;
			watermarkWidth = maxWatermarkWidth;
			watermarkHeight = watermarkWidth / aspectRatio;
		}

		if (watermarkHeight > maxWatermarkHeight) {
			double aspectRatio = watermarkWidth / watermarkHeight;
			watermarkHeight = maxWatermarkHeight;
			watermarkWidth = watermarkHeight / aspectRatio;
		}

		return Pair.of(watermarkWidth, watermarkHeight);
	}

	/**
	 * 
	 * @param originalImage
	 * @param watermarkImage
	 * @param maxPercentage
	 * @return
	 */
	public static int getWatermarkWidth(BufferedImage originalImage,
			BufferedImage watermarkImage, double maxPercentage) {

		return calculateWatermarkDimensions(originalImage, watermarkImage,
				maxPercentage).getLeft().intValue();

	}

	/**
	 * 
	 * @param originalImage
	 * @param watermarkImage
	 * @param maxPercentage
	 * @return
	 */
	public static int getWatermarkHeight(BufferedImage originalImage,
			BufferedImage watermarkImage, double maxPercentage) {

		return calculateWatermarkDimensions(originalImage, watermarkImage,
				maxPercentage).getRight().intValue();

	}

And now we have our scaled logo, this time it’s aligned to middle-left:
Java watermark image

If you have a question or having trouble getting it to work then feel free to write me a comment and I’ll do my best to help you out. If you would like to read more about general Java related subjects then also make sure to comment on that and if you liked what you read then make sure to subscribe – It’s FREE!

Why use Liferay?

The Good side of Liferay

Liferay is NOT just a Java based CMS. It’s a complete portal environment that’s suitable for large enterprise usage. It should be used as a platform to develop in-house applications or intranet. If you need just a small website to promote something then Liferay is not for you.

Some people compare Liferay with PHP based CMS systems like Joomla or Wordpress but that’s completely wrong. Liferay does contain CMS and it’s not a bad one. It’s rather useful for providing small applications and even better for big applications.

Supporting JSR 168 and JSR 286 means you can deploy Portlet applications that others have developed. Liferay also has a very good support for groups and communities allowing you to build team sites and custom environments for different user-groups with ease. Some cool features that you get with Liferay out of the box are:

  • User and Group management
  • Multi-site support for having different pages and themes for different user groups
  • Proper Access rights and Role management
  • Internationalization
  • Document library management
  • Wiki, Blogging and Forums
  • Service Oriented Architecture
  • Theme support
  • Integrates with other existing systems using LDAP, RSS, iFrames and other technologies

Liferay

 

The Bad side of Liferay

Developing applications and portals for the first time is a taunting task and comes with a rather massive learning curve. If you plan to use Liferay Service Builder and do everything “the Liferay way” then you have to plan probably at least couple of weeks for learning it first.

If you need to develop a small application quickly AND you don’t have an existing Liferay installation already in-house then you can get your application done way faster by NOT using Liferay. But once you have learned Liferay and have enough need for proper portal then Liferay becomes rather irresistible.

When it comes to documentation and tutorials then it’s not the best situation either. It does have a massive developer’s guide. But the Wiki is filled with tons of content that’s rather old and not updated for the latest releases.

The official developer and administration guides are good but often lack information about some crucial parts or fail to provide decent examples. While they claim to be developer friendly I have to admit that some parts of the development platform is severely lacking. Also note that releases are rather infrequent. Also one should be very cautious because early versions are always rather buggy.

AlloyUI that’s provided with Liferay for Javascript and UI is rather difficult to learn and seems also a very large investment time-wise – save yourself the trouble and use jQuery or some other favorite JS library instead.

Download PDF or JPG from portlet

To create a Download PDF link or serve images in your portlet, you need to implement serveResource method in your Liferay portlet class. Here’s an example on how to serve a JPG file from the server.

First we need to define a link to our file, this can be done using portlet taglib resourceURL like this.

<portlet:resourceURL var="niceImageUrl">
	<portlet:param name="fileName" value="flowers.jpg" />
</portlet:resourceURL>
<img src="<%= niceImageUrl %>" alt="flowers.jpg" />

Please note that you need to have portlet taglib in your JSP file header.

<%@ taglib uri="http://java.sun.com/portlet_2_0" prefix="portlet" %>

This generates a resource URL, so now we must implement the serveResource method to handle this call.

public class ImagesPortlet extends MVCPortlet {

	@Override
	public void serveResource(ResourceRequest request, ResourceResponse response)
			throws IOException, PortletException {

		String fileName = ParamUtil.getString(request, "fileName");

		File outputFile = new File("/Folder/On/Server/"+fileName);

		response.setContentType("image/jpg");
		OutputStream out = response.getPortletOutputStream();
		InputStream in = new FileInputStream(outputFile);
		IOUtils.copy(in, out);
		out.flush();
	}	
}

For PDF files you could easily tune it to have a link to your PDF like this:

<portlet:resourceURL var="pdfDownloadUrl">
	<portlet:param name="fileName" value="document.pdf" />
</portlet:resourceURL>
<a href="<%= pdfDownloadUrl %>">Download PDF</a>

And in the portlet class you can use code like this

public class PDFPortlet extends MVCPortlet {

	@Override
	public void serveResource(ResourceRequest request, ResourceResponse response)
			throws IOException, PortletException {

		String fileName = ParamUtil.getString(request, "fileName");

		File outputFile = new File("/Folder/On/Server/"+fileName);

		response.setContentType("application/pdf");
		OutputStream out = response.getPortletOutputStream();
		InputStream in = new FileInputStream(outputFile);
		IOUtils.copy(in, out);
		out.flush();
	}	
}

It’s important to use application/pdf content type so that the browser would know how to properly handle the file.

If you need to output multiple file types or handle different actions then you can pass an extra parameter that decides what file type to serve. Another idea could be to use a parameter to decide between serving a file or serving a JSON response, in case you need need to retrieve some data using AJAX. Here’s a simple example on how to pass content type in the URL to use it during serving the file.

<portlet:resourceURL var="pdfDownloadUrl">
	<portlet:param name="type" value="application/pdf" />
	<portlet:param name="fileName" value="document.pdf" />
</portlet:resourceURL>
<a href="<%= pdfDownloadUrl %>">Download PDF</a>

<portlet:resourceURL var="niceImageUrl">
	<portlet:param name="type" value="image/jpg />
	<portlet:param name="fileName" value="flowers.jpg" />
</portlet:resourceURL>
<img src="<%= niceImageUrl %>" alt="flowers.jpg" />

And in the portlet class you can just output the provided content type without having to detect it during download time. This allows you to define the expected content types dynamically, which can be very useful when you are generating a file list.

public class FilesPortlet extends MVCPortlet {

	@Override
	public void serveResource(ResourceRequest request, ResourceResponse response)
			throws IOException, PortletException {

		String type = ParamUtil.getString(request, "type");
		String fileName = ParamUtil.getString(request, "fileName");

		File outputFile = new File("/Folder/On/Server/"+fileName);

		response.setContentType( type );
		OutputStream out = response.getPortletOutputStream();
		InputStream in = new FileInputStream(outputFile);
		IOUtils.copy(in, out);
		out.flush();
	}	
}

More info on how to generate PDF on the fly can be read in this useful blog post.

As always, free feel to ask questions and provide suggestions in the comments.

OrientDB database creation class

Problem: OrientDB does not support BigInteger’s out of the box. The simple solution is to tune OrientDB serializer to output BigIntegers as Integers and this allows us to store them in database nicely.

Although it’s a pretty straight-forward and simple class I decided to create a post about it because it took me a while to fight with the BigInteger issue.

Example:

import java.io.File;
import java.math.BigInteger;

import com.orientechnologies.orient.core.serialization.serializer.object.OObjectSerializer;
import com.orientechnologies.orient.object.db.OObjectDatabaseTx;
import com.orientechnologies.orient.object.serialization.OObjectSerializerContext;
import com.orientechnologies.orient.object.serialization.OObjectSerializerHelper;
import com.sun.org.apache.xerces.internal.jaxp.datatype.XMLGregorianCalendarImpl;

public class CreateNewDatabase {

	public static void main(String[] args) {

		// Don't run without database location argument.
		if (args == null || args.length != 1) {
			System.out
					.println("Expected single argument of folder path where to store the database.");
			return;
		}

		String path = args[0];
		if (path.length() < 2) {
			System.out.println("Path is too short: " + path);
			return;
		}

		if (!path.endsWith(File.separator)) {
			path = path + File.separator;
		}

		OObjectDatabaseTx db = null;

		try {

			File folder = new File(path);
			if (folder.exists()) {
				throw new Exception("Database already exists on that path!");
			}

			// Create the folder as required.
			if (!folder.mkdirs()) {
				throw new Exception("Failed to create required folders:"
						+ folder.getAbsolutePath());
			}
			System.out.println("Creating database to: " + path);
			db = new OObjectDatabaseTx("plocal:" + path);
			// Avoid overwriting existing databases.
			if (db.exists()) {
				throw new Exception("Database already exists on that path!");
			}

			// Create database
			db.create();

			// Important code to serialize BigIntegers to Integers.
			// It's vital that this code is run before you register your classes.
			OObjectSerializerContext serializerContext = new OObjectSerializerContext();
			serializerContext
					.bind(new OObjectSerializer<BigInteger, Integer>() {

						public Integer serializeFieldValue(Class<?> itype,
								BigInteger iFieldValue) {
							return iFieldValue.intValue();
						}

						public BigInteger unserializeFieldValue(Class<?> itype,
								Integer iFieldValue) {
							return new BigInteger(iFieldValue.toString());
						}

					});
			OObjectSerializerHelper.bindSerializerContext(null,
					serializerContext);

			// Tell OrientDB to automatically generate schema during class
			// registration, this saves us some code.
			db.setAutomaticSchemaGeneration(true);
			// Now register our classes...
			db.getEntityManager().registerEntityClasses(
					"your.entity.package.goes.here");

			// Save the schema of our new database...
			db.getMetadata().getSchema().save();

			System.out.println("DONE");

		} catch (Exception e) {
			System.out.println(e.getMessage());
			e.printStackTrace();
		} finally {
			if (db != null) {
				db.close();
			}
		}

	}

}


As always, freel free to comment and ask questions in the comments.