Spring boot and Graylog

Graylog is a platform (free and enterprise) that is useful for log management of aggregated data. It is based on Elasticsearch, MongoDB and Scala.
It can display messages and histograms.

To send data to a graylog server through an HTTP appender with log4J2, i used the GELF layout with the following configuration :

<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="debug" monitorInterval="30">
	<Properties>
		<Property name="LOG_PATTERN">
			%d{yyyy-MM-dd HH:mm:ss.SSS} %5p ${hostName}
			--- [%15.15t] %-40.40c{1.} : %m%n%ex
		</Property>
	</Properties>
	<Appenders>
		<Console name="ConsoleAppender" target="SYSTEM_OUT" follow="true">
			<PatternLayout pattern="${LOG_PATTERN}" />
		</Console>

        <!--  Appender for GRAYLOG -->     
		<Http name="Http" url="http://xxx.yyy.zz.aa/gelf" >		
			<GelfLayout host="localhostGraylog" compressionType="OFF" includeStacktrace="true">
				<KeyValuePair key="environment" value="myappGraylog" />
			</GelfLayout>
		</Http>
		
	</Appenders>

	<Loggers>
		<Logger name="com.celinio.app" level="debug"
			additivity="false">
			<AppenderRef ref="ConsoleAppender" />
 			<AppenderRef ref="Http" /> 
		</Logger>

		<!-- Spring Boot -->
		<Logger name="org.springframework.boot" level="debug"
			additivity="false">
		        <AppenderRef ref="ConsoleAppender" />
 			<AppenderRef ref="Http" /> 
		</Logger>

		<Logger name="org.hibernate" level="debug" additivity="false">
			<AppenderRef ref="ConsoleAppender" />
 			<AppenderRef ref="Http" /> 
		</Logger>

		<Root level="debug">
			<AppenderRef ref="ConsoleAppender" />
 			<AppenderRef ref="Http" /> 
		</Root>
	</Loggers>
</Configuration>

I had to use the latest version of log4j2 (2.11.2) and i also had to comment out the use of the Spring boot starter for log4j2 :

<properties>
        ...
    	<log4j.version>2.11.2</log4j.version>
</properties>
<dependencies>
        ...
	<!-- 
	<dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-log4j2</artifactId>
	</dependency>
	 -->
	<dependency>
		<groupId>org.apache.logging.log4j</groupId>
		<artifactId>log4j-api</artifactId>	
		<version>${log4j.version}</version>
	</dependency>
	<dependency>
		<groupId>org.apache.logging.log4j</groupId>
		<artifactId>log4j-core</artifactId>
		<version>${log4j.version}</version>
	</dependency>
</dependencies>

Version of Spring boot : 1.5.21.RELEASE

Delete a file from a project generated through a custom maven archetype if a condition is met

With the help of Groovy, we can delete a file from a generated project if it meets a condition (for instance if a maven property equals a certain value).

Here is the procedure :
1) Create the archetype. To do that, type the following command from the root of a Maven project :
mvn archetype:create-from-project
result ==> [INFO] Archetype project created in E:\eclipse\workspace\celinio\target\generated-sources\archetype

The archetype project is here :
/celinio/target/generated-sources/archetype

Copy-paste this folder structure into another folder in the workspace and import it as an existing maven project.
By default, I have decided that this archetype will generate a project which contains a file /src/main/resources/META-INF/configuration.xml. This is the file that I do not want to include if the maven property configurable is set to no.

2) Add the following required property to /celinioArchetype/src/main/resources/META-INF/maven/archetype-metadata.xml

  <requiredProperties>
    <requiredProperty key="configurable">
      <defaultValue>yes</defaultValue>
    </requiredProperty>
  </requiredProperties>

Also add this property to /celinioArchetype/src/test/resources/projects/basic/archetype.properties :
configurable=yes

3) Add the following groovy script archetype-post-generate.groovy under the folder /celinioArchetype/src/main/resources/META-INF/
It will be executed upon creating a project from this archetype.
https://maven.apache.org/archetype/maven-archetype-plugin/advanced-usage.html

/**
* CF : This script will be executed upon creating a project from this archetype.
* https://maven.apache.org/archetype/maven-archetype-plugin/advanced-usage.html
* It will delete a folder called configuration.xml if the value for the "configurable" property
* is set to true.
*/

import java.nio.file.Files
import java.nio.file.Path
import java.nio.file.Paths

println "artifactId: " + artifactId
println "request: " + request
println "archetypeArtifactId: " + request.getArchetypeArtifactId()
println "archetypeGroupId: " + request.getArchetypeGroupId()
println "archetypeVersion: " + request.getArchetypeVersion()
println "archetypeName: " + request.getArchetypeName()
println "artifactId: " + request.getArtifactId()
println "groupId: " + request.getGroupId()
println "version: " + request.getVersion()

Path projectPath = Paths.get(request.outputDirectory, request.artifactId)
Properties properties = request.properties
String configurableProperty = properties.get("configurable")
println "configurableProperty : " + configurableProperty

if (!configurableProperty.equals("yes")) {
   println "Deleting the configuration.xml file"
   
   Path configPath = projectPath.resolve("src/main/resources/META-INF")   
   String configurationFile = "configuration.xml";    
   Path cxfConfigPath = configPath.resolve(configurationFile)
   println "cxfConfigPath " + cxfConfigPath  
   Files.deleteIfExists cxfConfigPath
}

To test it in eclipse, you will need to create a project from a run configuration as the groovy script is not executed if you go through the wizard (File > New Maven Project > select archetype etc)
See this link for details :
https://bugs.eclipse.org/bugs/show_bug.cgi?id=514993

I have created a repository on github to host the code for this basic maven archetype :
https://github.com/longbeach/mavenArchetypeGroovy

I added two run configuration files which will help testing it.

Add UML diagrams to the JavaDoc

It is possible to add UML diagrams to the JavaDoc generated during the build phase.

The first thing to do is to install Graphviz which is an open source graph visualization software.
After installation, add the bin folder (D:\Graphviz\bin for instance) to the PATH environment variable.
Then configure the pom.xml :

<build>
		<plugins>
			<plugin>
				<groupid>org.apache.maven.plugins</groupid>
<artifactid>maven-javadoc-plugin</artifactid>
<version>3.0.1</version>
<configuration>
<doclet>org.umlgraph.doclet.UmlGraphDoc</doclet>
<docletartifact>
<groupid>org.umlgraph</groupid>
<artifactid>umlgraph</artifactid>
<version>5.6.6</version>
</docletartifact>
<additionalparam>-views -all</additionalparam>
<doclint>none</doclint>
<usestandarddocletoptions>true</usestandarddocletoptions>
</configuration>
<executions>
<execution>
<id>attach-javadocs</id>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
			</plugin>
		</plugins>
	</build>

Here i chose to add the maven-javadoc-plugin to the build maven phase. In the configuration of the plugin, i added the UmlGraphDoc doclet.
UMLGraph allows the declarative specification and drawing of UML class and sequence diagrams.

Run mvn install and then check the generated JavaDoc under the folder target/site/apidocs/
Here is a sample :

The code of this project is available on my github repository :
https://github.com/longbeach/eclipseumlgraph

How to launch the hosted mode with Jonas and Maven

GWT uses an embedded Jetty server. It is used at the beginning of the development of an application. During the prototype phase.
Personally, I used it for about a year, until we got the need to use JMS.
And since Jetty is not a Java EE server – it does not implement the JMS API – it was time to say goodbye to Jetty and use the application server that is used in production : Jonas.
There is not much info about the configuration to use in order to launch the hosted mode with a server different from Jetty. I found that the official website of the gwt-maven-plugin lacks information in that area.

I spent a few hours finding out the correct configuration for that. So here is how to do it :
1) Start Jonas
2) Deploy the application (EAR or WAR)
3) Run the goal gwt:run

And the configuration for the gwt-maven-plugin plugin is the following :


<plugins>
  <plugin>
	<groupId>org.codehaus.mojo</groupId>
	<artifactId>gwt-maven-plugin</artifactId>		
					
	<!-- Old configuration, to run the hosted mode with JETTY. -->
	<!-- 
		<configuration>
		<runTarget>identify.html</runTarget>
		<hostedWebapp>${project.build.directory}/${project.build.finalName}</hostedWebapp>
		<modules>
			<module>${project.groupId}.foo.bla.MainApplication</module>
			<module>${project.groupId}.foo.bla.SecondEntry</module>
		</modules>
		<copyWebapp>true</copyWebapp>										
		<extraJvmArgs>-XX:MaxPermSize=512M  -Xms512M -Xmx1024M </extraJvmArgs>
	</configuration>
	 -->
	
	<!-- New configuration, to run the hosted mode with JONAS -->
	<configuration>					
		<modules>
			<module>${project.groupId}.foo.bla.MainApplication</module>
			<module>${project.groupId}.foo.bla.SecondEntry</module>
		</modules>					
		<extraJvmArgs>-XX:MaxPermSize=512M  -Xms512M -Xmx1024M </extraJvmArgs>
		
		<webappDirectory>${project.build.directory}/${project.build.finalName}</webappDirectory> 
		<runTarget>http://localhost:9000/app-context/main.html</runTarget> 
		<copyWebapp>false</copyWebapp> 
		<!--  do not start JETTY -->
		<noServer>true</noServer>
		<!-- the folder where the exploded WAR is located, inside Jonas -->
		 <!--  Constant path if jonas.development=false in conf/jonas.properties --> 					
		<hostedWebapp>${env.JONAS_BASE}\work\webapps\jonas\ear\myapp-ear-SNAPSHOT.ear\${project.build.finalName}.war</hostedWebapp>
		<bindAddress>localhost</bindAddress>   <!--  other possible value : 0.0.0.0 -->
		<logLevel>INFO</logLevel> 
		<style>OBF</style> 			
	</configuration>
	<executions>
		<execution>
			<id>gwtcompile</id>
			<phase>prepare-package</phase>
			<goals>
				<goal>compile</goal>
			</goals>
		</execution>
	</executions>
   </plugin>
...
</plugins>			

Line 35 is the most important : it specifies the path where the exploded war is deployed in Jonas.
That configuration could work with another application server of course.

M2E problem : Plugin execution not covered by lifecycle configuration

I am adding to the blogosphere of development-related blogs another post about the “Plugin execution not covered by lifecycle configuration” error.

The M2E Plugin 1.0.0 is integrated into Eclipse Indigo (3.7). Apparently, M2E connectors, which are a bridge between Maven and Eclipse, require to provide a connector for every plugin that is used in the build.
And if no connector is available, M2E shows the following annoying errors in the Eclipse problems view :

Plugin execution not covered by lifecycle configuration: org.apache.maven.plugins:maven-antrun-plugin:1.7:run (execution: run, phase: validate)

Plugin execution not covered by lifecycle configuration: org.apache.maven.plugins:maven-resources-plugin:2.5:resources (execution: default-resources, phase: process-resources)

Plugin execution not covered by lifecycle configuration: org.apache.maven.plugins:maven-resources-plugin:2.5:testResources (execution: default-testResources, phase: process-test-resources)

Plugin execution not covered by lifecycle configuration: org.codehaus.mojo:properties-maven-plugin:1.0-alpha-2:read-project-properties (execution: default, phase: initialize)

Plugin execution not covered by lifecycle configuration: org.apache.cxf:cxf-codegen-plugin:2.2:wsdl2java (execution: generate-sources, phase: generate-sources)

Plugin execution not covered by lifecycle configuration: org.codehaus.mojo:hibernate3-maven-plugin:3.0-SNAPSHOT:hbm2ddl (execution: default, phase: compile)

Plugin execution not covered by lifecycle configuration: org.apache.maven.plugins:maven-ear-plugin:2.6:generate-application-xml

To avoid these errors, it is necessary to modify the pom.xml file so that M2E will not complain about it.

These are the extra lines that I added in my parent pom.xml :

	<build>
<pluginManagement>
	<plugins>
	<!--The configuration of this plugin is used to store the Eclipse M2E settings
                  only. It has no influence on the Maven build itself. -->
	<plugin>
		      <groupId>org.eclipse.m2e</groupId>
		      <artifactId>lifecycle-mapping</artifactId>
		      <version>1.0.0</version>
		      <configuration>
		        <lifecycleMappingMetadata>
		          <pluginExecutions>
		            <pluginExecution>
		              <pluginExecutionFilter>
		                <groupId>org.apache.maven.plugins</groupId>
		                <artifactId>maven-antrun-plugin</artifactId>
		                <versionRange> [1.7,)</versionRange>
		                <goals>
		                       <!-- plugin goals-->
		                  <goal>run</goal>
		                </goals>
		              </pluginExecutionFilter>
		              <action>
		             	 <!-- M2E should ignore the plugin-->
		                <ignore />
		              </action>
		            </pluginExecution>
		            <pluginExecution>
		              <pluginExecutionFilter>
		                <groupId>org.apache.maven.plugins</groupId>
		                <artifactId>maven-resources-plugin</artifactId>
		                <versionRange> [2.5,)</versionRange>
		                <goals>
		                       <!-- plugin goals-->
		                  <goal>resources</goal>
		                  <goal> testResources </goal>
		                </goals>
		              </pluginExecutionFilter>
		              <action>
		             	 <!-- M2E should ignore the plugin-->
		                <ignore />
		              </action>
		            </pluginExecution>
		            <pluginExecution>
		              <pluginExecutionFilter>
		                <groupId>org.codehaus.mojo</groupId>
		                <artifactId>properties-maven-plugin</artifactId>
		                <versionRange> [1.0-alpha-2,)</versionRange>
		                <goals>
		                       <!-- plugin goals-->
		                  <goal>read-project-properties</goal>
		                </goals>
		              </pluginExecutionFilter>
		              <action>
		             	 <!-- M2E should ignore the plugin-->
		                <ignore />
		              </action>
		            </pluginExecution>
		            <pluginExecution>
		              <pluginExecutionFilter>
		                <groupId>org.apache.cxf</groupId>
		                <artifactId>cxf-codegen-plugin</artifactId>
		                <versionRange> [2.2,)</versionRange>
		                <goals>
		                       <!-- plugin goals-->
		                  <goal>wsdl2java</goal>
		                </goals>
		              </pluginExecutionFilter>
		              <action>
		             	 <!-- M2E should ignore the plugin-->
		                <ignore />
		              </action>
		            </pluginExecution>
		            <pluginExecution>
		              <pluginExecutionFilter>
		                <groupId>org.codehaus.mojo</groupId>
		                <artifactId>hibernate3-maven-plugin</artifactId>
		                <versionRange> [3.0-SNAPSHOT,)</versionRange>
		                <goals>
		                       <!-- plugin goals-->
		                  <goal>hbm2ddl</goal>
		                </goals>
		              </pluginExecutionFilter>
		              <action>
		             	 <!-- M2E should ignore the plugin-->
		                <ignore />
		              </action>
		            </pluginExecution>
		                  <pluginExecution>
		              <pluginExecutionFilter>
		                <groupId>org.apache.maven.plugins</groupId>
		                <artifactId>maven-ear-plugin</artifactId>
		                <versionRange> [2.6,)</versionRange>
		                <goals>
		                       <!-- plugin goals-->
		                  <goal>generate-application-xml</goal>
		                </goals>
		              </pluginExecutionFilter>
		              <action>
		             	 <!-- M2E should ignore the plugin-->
		                <ignore />
		              </action>
		            </pluginExecution>
		          </pluginExecutions>
		        </lifecycleMappingMetadata>
		      </configuration>
  	</plugin>
...
  </plugins>
      </pluginManagement>
</build>

Links :
http://wiki.eclipse.org/M2E_plugin_execution_not_covered
http://objectledge.org/confluence/display/TOOLS/M2E+Connectors

Extracting metadata information from files using Apache Tika

I recently discovered a useful library called Apache Tika that makes it easy to extract metadata information from many types of files.
The ECM Alfresco makes use of Apache Tika for both metadata extraction and content transformation.
With Apache Tika, you do not have to worry about which parser to use with a type of file. Apache Tika will look for a parser implementation that matches the type of the document, once it is known, using Mime Type detection.
Here is a basic usage of the library to extract metadata information from files such as documents (PDF/DOC/XLS), images (JPG), songs (MP3).

You can start from a maven archetype such as quickstart. Then all you need is to add the following two dependencies :

<dependencies>
...
 <dependency>
	            <groupId>org.apache.tika</groupId>
	            <artifactId>tika-core</artifactId>
	            <version>1.0</version>
 </dependency>
 <dependency>
	            <groupId>org.apache.tika</groupId>
	            <artifactId>tika-parsers</artifactId>
	            <version>1.0</version>
 </dependency>
</dependencies>

The org.apache.tika.parser.AutoDetectParser class is in charge of dispatching the incoming document to the appropriate parser. It is especially useful when the type of the document is not known in advance.

package net.celinio.tika.firstProject;

import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;

import org.apache.tika.metadata.Metadata;
import org.apache.tika.parser.AutoDetectParser;
import org.apache.tika.sax.BodyContentHandler;

public class MetaDataExtraction {

	public static void main(String[] args) {
		 
		try {
			//String resourceLocation = "d:\\tempTika\\TikainAction.pdf";
			//String resourceLocation = "d:\\tempTika\\06-takefive.mp3";			
			String resourceLocation = "d:\\tempTika\\mariniere14juillet2011.jpg";
			//String resourceLocation = "d:\\tempTika\\02b-blank-timetable.doc";
			//String resourceLocation = "d:\\tempTika\\examstudytable.doc";
			//String resourceLocation = "d:\\tempTika\\timetable.xls";
			
			File file = new File(resourceLocation);
			 
			InputStream input = new FileInputStream(file);			 
			System.out.println( file.getPath());				
			
			Metadata metadata = new Metadata();
			 
			BodyContentHandler handler = new BodyContentHandler(10*1024*1024);
			AutoDetectParser parser = new AutoDetectParser();		
	
			parser.parse(input, handler, metadata);
			 /*
			String content = new Tika().parseToString(f);
			//System.out.println("Content: " + content);
			//System.out.println("Content: " + handler.toString());
			System.out.println("Title: " + metadata.get(Metadata.TITLE));
			System.out.println("Last author: " + metadata.get(Metadata.LAST_AUTHOR));
			System.out.println("Last modified: " + metadata.get(Metadata.LAST_MODIFIED));
			System.out.println("Content type: " + metadata.get(Metadata.CONTENT_TYPE));
			System.out.println("Application name: " + metadata.get(Metadata.APPLICATION_NAME));
			System.out.println("Author: " + metadata.get(Metadata.AUTHOR));
			System.out.println("Line count: " + metadata.get(Metadata.LINE_COUNT));
			System.out.println("Word count: " + metadata.get(Metadata.WORD_COUNT));
			System.out.println("Page count: " + metadata.get(Metadata.PAGE_COUNT));
			System.out.println("MIME_TYPE_MAGIC: " + metadata.get(Metadata.MIME_TYPE_MAGIC));
			System.out.println("SUBJECT: " + metadata.get(Metadata.SUBJECT));
			
			*/

			String[] metadataNames = metadata.names();
			
			// Display all metadata
			for(String name : metadataNames){
				System.out.println(name + ": " + metadata.get(name));
			}
			
			}
			catch (Exception e) {
				e.printStackTrace();
			}
			 
	}
}

Line 30, I am using the BodyContentHandler constructor that takes an argument because i need to increase the size limit. Otherwise the WriteLimitReachedException exception is raised when parsing the file TikainAction.pdf (16,4 MB) :

org.apache.tika.sax.WriteOutContentHandler$WriteLimitReachedException: 
Your document contained more than 100000 characters, and so your requested limit has been reached. To receive the full text of the document, increase your limit. (Text up to the limit is however available).

Here is the output for the image file mariniere14juillet2011.jpg :

d:\tempTika\mariniere14juillet2011.jpg
Number of Components: 3
Windows XP Title: Popo
Date/Time Original: 2011:07:14 14:16:10
Image Height: 600 pixels
Image Description: Popo
Data Precision: 8 bits
Sub-Sec Time Digitized: 31
tiff:BitsPerSample: 8
Windows XP Subject: Moules
date: 2011-07-14T14:16:10
exif:DateTimeOriginal: 2011-07-14T14:16:10
Component 1: Y component: Quantization table 0, Sampling factors 2 horiz/2 vert
tiff:ImageLength: 600
Component 2: Cb component: Quantization table 1, Sampling factors 1 horiz/1 vert
Component 3: Cr component: Quantization table 1, Sampling factors 1 horiz/1 vert
Date/Time Digitized: 2011:07:14 14:16:10
description: Popo
tiff:ImageWidth: 800
Unknown tag (0xea1c): 28 -22
Image Width: 800 pixels
Sub-Sec Time Original: 31
Content-Type: image/jpeg
Artist: Popo;Cel
Windows XP Author: Popo;Cel

And the output for the song file 06-takefive.mp3 :

d:\tempTika\06-takefive.mp3
xmpDM:releaseDate: null
xmpDM:audioChannelType: Stereo
xmpDM:album: Take Five
Author: Dave Brubeck
xmpDM:artist: Dave Brubeck
channels: 2
xmpDM:audioSampleRate: 44100
xmpDM:logComment: null
xmpDM:trackNumber: 6/8
version: MPEG 3 Layer III Version 1
xmpDM:composer: null
xmpDM:audioCompressor: MP3
title: Take Five
samplerate: 44100
xmpDM:genre: null
Content-Type: audio/mpeg

And the output for the ebook TikainAction.pdf :

d:\tempTika\TikainAction.pdf
xmpTPg:NPages: 257
Creation-Date: 2011-11-09T12:20:20Z
title: Tika in Action
created: Wed Nov 09 13:20:20 CET 2011
Licensed to: Celinio Fernandes  <xxx@yyy.com>
Last-Modified: 2011-11-16T12:25:00Z
producer: Acrobat Distiller 9.4.6 (Windows)
Author: Chris A. Mattmann, Jukka L. Zitting
Content-Type: application/pdf
creator: FrameMaker 8.0

And the output for the Word document 02b-blank-timetable.doc :

d:\tempTika\02b-blank-timetable.doc
Revision-Number: 4
Comments: 
Last-Author: CeLTS
Template: Normal.dot
Page-Count: 1
subject: 
Application-Name: Microsoft Office Word
Author: CeLTS
Word-Count: 1921
xmpTPg:NPages: 1
Edit-Time: 3600000000
Creation-Date: 2006-02-09T00:31:00Z
title: Study Timetable
Character Count: 10951
Company: Monash University
Content-Type: application/msword
Keywords: 
Last-Save-Date: 2006-10-30T05:52:00Z

As you can see, the list of metadata information (title, author, image height, etc) is varying, depending on which parser is used and of course which type of document it is.
You can also search the content of the files as Apache Tika provides access to the textual content of files.
By the way, there is a Tika GUI which is a handy tool that makes it possible to extract metadata information by simply drag and dropping a file into it.
To launch it, just download the jar tika-app-1.0.jar and run it :

java -jar tika-app-1.0.jar --gui


Drag and drop a file into it and read the extracted metadata :

Links :

http://tika.apache.org/
The book Tika in Action (Manning)

Handling form-based file upload with GWT and the Apache Jakarta Commons FileUpload library

Uploading files to a filesystem, a remote server, a database, etc, is a frequent need in web applications.
These files are often multipart data (that is of varying types such as XML, HTML, plain text, binary … ).
With GWT, a good solution to handle this need is the use of the Apache Jakarta Commons FileUpload library.

First, generate a skeleton project using the gwt-maven-plugin archetype :

mvn archetype:generate  

Choose archetype number 298 which makes use of the gwt-maven-plugin and generates a simple hello world sample.

298: remote -> gwt-maven-plugin (Maven plugin for the Google Web Toolkit.)

You can easily import that project into Eclipse (File > Import …> Maven > Existing Maven projects).

Add the following dependency to the pom.xml file:

<dependency>
    <groupId>commons-fileupload</groupId>
    <artifactId>commons-fileupload</artifactId>
    <version>1.2.2</version>
</dependency>

In the client side, modify the onModuleLoad() method of the entry point class (called Firstmodule.java in my project) and add the following code at the end :

package com.mycompany.client;

import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.core.client.GWT;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.KeyCodes;
import com.google.gwt.event.dom.client.KeyUpEvent;
import com.google.gwt.event.dom.client.KeyUpHandler;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.DialogBox;
import com.google.gwt.user.client.ui.FileUpload;
import com.google.gwt.user.client.ui.FormPanel;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.RootPanel;
import com.google.gwt.user.client.ui.TextBox;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.mycompany.shared.FieldVerifier;

/**
 * Entry point classes define <code>onModuleLoad()</code>.
 */
public class Firstmodule implements EntryPoint {
...
 /**
   * This is the entry point method.
   */
  public void onModuleLoad() {
...
 final FormPanel form = new FormPanel();	  
    VerticalPanel vPanel = new VerticalPanel(); 
    // http://google-web-toolkit.googlecode.com/svn/javadoc/latest/com/google/gwt/user/client/ui/FileUpload.html
    form.setMethod(FormPanel.METHOD_POST);
    //The HTTP request is encoded in multipart format. 
    form.setEncoding(FormPanel.ENCODING_MULTIPART); //  multipart MIME encoding
    form.setAction("/FileUploadGreeting"); // The servlet FileUploadGreeting
    
    form.setWidget(vPanel);
    
    FileUpload fileUpload = new FileUpload();
    fileUpload.setName("uploader"); // Very important    
    vPanel.add(fileUpload);    
    
    Label maxUpload =new Label();
    maxUpload.setText("Maximum upload file size: 1MB");
    vPanel.add(maxUpload);
        
    vPanel.add(new Button("Submit", new ClickHandler() {
        public void onClick(ClickEvent event) {
                form.submit();
        }
    }));
    
    RootPanel.get("uploadContainer").add(form); 
...
}     
}

You need to add the FileUpload widget inside a FormPanel widget. Set the action (servlet) that will be called when the user submits the form.
Line 43 is very important. You need to set a name to the FileUpload widget, otherwise the upload will not work. In fact, all of the fields under the FormPanel that you want to use need to have a name so that the HttpServlet can identify them.
The HTTP request is encoded in multipart format (line 37).
The generated HTML code will contain the following line :

<form action="FileUploadGreeting" method="POST" enctype="multipart/form-data">

In the server side, create the servlet that will be called when the user clicks on the Submit button :

package com.mycompany.server.form;

import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Iterator;
import java.util.List;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileItemFactory;
import org.apache.commons.fileupload.FileUploadBase.SizeLimitExceededException;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;

public class UploadFileHandler extends HttpServlet {
	
	private static final long serialVersionUID = 1L;
	
	public void doPost(HttpServletRequest request, HttpServletResponse response)
	throws ServletException, IOException {
			
	 System.out.println("Inside doPost");		
		
		// Create a factory for disk-based file items
		FileItemFactory factory = new DiskFileItemFactory();
		// Create a new file upload handler
		ServletFileUpload fileUpload  = new ServletFileUpload(factory);
		// sizeMax - The maximum allowed size, in bytes. The default value of -1 indicates, that there is no limit.
		// 1048576 bytes = 1024 Kilobytes = 1 Megabyte
		fileUpload.setSizeMax(1048576);  
		
		if (!ServletFileUpload.isMultipartContent(request)) {
		      try {
		    	
				throw new FileUploadException("error multipart request not found");
			} catch (FileUploadException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		 		  		
		try {

			List<FileItem> items = fileUpload.parseRequest(request);
			
			if (items == null) {			
                response.getWriter().write("File not correctly uploaded");
                return;
          }
			
			Iterator<FileItem> iter = items.iterator();

			while (iter.hasNext()) {
				FileItem item = (FileItem) iter.next();
				
				////////////////////////////////////////////////
				// http://commons.apache.org/fileupload/using.html								
				////////////////////////////////////////////////

				//if (item.isFormField()) {															
					String fileName = item.getName();
					System.out.println("fileName is : " + fileName);	
					String typeMime = item.getContentType();
					System.out.println("typeMime is : " + typeMime);	
					int sizeInBytes = (int) item.getSize();
					System.out.println("Size in bytes is : " + sizeInBytes);	
					//byte[] file = item.get();					
					item.write(new File("fileOutput.txt"));		        							
				//}
			}
			
			PrintWriter out = response.getWriter();
			response.setHeader("Content-Type", "text/html");
			out.println("Upload OK");
			out.flush();
			out.close();

		} catch (SizeLimitExceededException e) {
			System.out.println("File size exceeds the limit : 1 MB!!" );			
		} catch (Exception e) {
			e.printStackTrace();
			PrintWriter out = response.getWriter();
			response.setHeader("Content-Type", "text/html");
			out.println("Error");
			out.flush();
			out.close();
		}
		
	}
	
	public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		doPost(request, response);
	}

}

You can easily set a size limit for uploaded files (line 36). An SizeLimitExceededException exception is raised if the size exceeds the limit (line 84).
The parseRequest(…) method, line 50, returns the list of items that were submitted.
The method isFormField() determines whether or not an item is a plain form field, as opposed to a file upload. I have commented it out at line 66 because the form only contains one field, which is the uploaded file.
You can also easily get information about the uploaded file (name, size, typeMime).
In the end, i simply write the uploaded file into a new file called fileOutput.txt which is saved at the root of the project.

Update the deployment descriptor file to declare the servlet and map it to an URL:

 <!-- Upload -->
	<servlet>
		<servlet-name>FileUploadGreeting</servlet-name>
		<servlet-class>com.mycompany.server.form.UploadFileHandler</servlet-class>
	</servlet>
	
	<servlet-mapping>
		<servlet-name>FileUploadGreeting</servlet-name>
		<url-pattern>/FileUploadGreeting</url-pattern>
	</servlet-mapping>

Finally compile and run the project in GWT Development Mode. Right-click anywhere in the Project Explorer and choose “Run As -> Maven Build…” and run the “gwt:run” goal:

Here is a screenshot of the page with the FileUpload widget added:

The whole code is available on GitHub : https://github.com/longbeach/GWTCommonsFileUpload

Links :
http://www.ietf.org/rfc/rfc1867.txt

Generate the database schema with Hibernate3 Maven Plugin

There is a nice Maven plugin for JPA/Hibernate that makes it possible to quickly generate the database schema (SQL) and save it in a file.
The artifactId of this plugin is hibernate3-maven-plugin.
It will scan all JPA annotations in the class files of the entities and generate the corresponding SQL queries.
A persistence.xml file is required.

  1. With version 2.2 :

Content of the pom.xml :


<build>
  <plugins>
...
<plugin>
				<groupId>org.codehaus.mojo</groupId>
				<artifactId>hibernate3-maven-plugin</artifactId>	
                                <version>2.2</version>			
				<configuration>
		       	   <components>
						<component>
							<name>hbm2ddl</name>
							<implementation>jpaconfiguration</implementation>																									
						</component>							
					</components>
				   <componentProperties>
                    <drop>true</drop>
                    <create>true</create>
                    <export>false</export>
                    <format>true</format>                    <outputfilename>schema-${DataBaseUser}-${DatabaseName}.sql</outputfilename>
                    <persistenceunit>myPU</persistenceunit>
                    <propertyfile>src/main/resources/database.properties</propertyfile>
                </componentProperties>
			  </configuration>		
			  <dependencies>
			  	<dependency>
					<groupId>com.oracle</groupId>
					<artifactId>ojdbc14</artifactId>
					<version>10.2.0.2.0</version>
				</dependency>			  
			  </dependencies>					
		</plugin>
	  </plugins>
	</build>

Continue reading

[Tutorial] Log4J with Maven profiles

Here is a quick tutorial to get your hands dirty with the Log4j logging framework.
Log4j allows logging requests to print to multiple output destinations, also known as appenders.
There are several output destinations: console, files, sockets, emails …
First create a Maven project :
mvn archetype:generate
Choose archetype number 109 (quickstart)

Continue reading

Assembla

I found another cool website that offers free workspaces that can be managed with Subversion, Git, Mercurial etc…
Of course it also offers various plans with monthly payments.
Anyway, I just put an empty project in my workspace. Check out the screenshots :
Continue reading