Christoph Hartmann on October 27th, 2009

Have you ever faced the challenge to model a company process? Of course you want to be the shining star and use the newest modeling notation. The Business Process Modeling Notation (BPMN) is such notation and standardized by OMG.

Additionally you want to start right now. Therefore you are not able to wait until your boss gives the approval for any cool BPMN app out there. For the time being you could start with your existing MS Office installation base. Either you are going to use the Visio Stencils or start modeling your processes via Powerpoint. How knows maybe your boss likes the first drafts and introduces a cool BPMN tool afterwards.

For Powerpoint I created a template that contains the most useful BPMN elements. Following you will find the templates:

Further information about BPMN is available at:

Any feedback is welcome…

Update: Thanks to Oliver, I added a few upgrades. At first of all the first version was missing a message flow and a pool. You will find both implemented in the current version. Additionally, some annoying design issues were solved. So have fun with the update.

Tags: , , , ,

Christoph Hartmann on April 16th, 2009

In most cases a Grails application uses a database to store its content. Fortunately Grails is tightly coupled with GORM to ease the use. Since Grails distinguish between different deployment environments, it uses a special configuration for development and production. Therefore you have to think of a database in production environment while you don not in development stage.

Glassfish v2 and v3 Prelude comes with an internal database JavaDB (based on the Apache Derby) that could be used for first tests. It would be great to use the default database by default for deployments for Glassfish via JNDI. This article shows how to use the bundled database with an Grails application.

In preparation for the next steps you have to install Grails 1.1 and Glassfish v2 or Glassfish v3 Prelude.

To create the demo app just run the following at command line:

grails create-app glassfishapp
cd glassfishapp
grails create-domain-class Bookmark
grails create-controller Bookmark

As the next step edit the domain class and the controller. E.g. open Eclipse with installed Groovy plugin.

class BookmarkController {
    def scaffold = Bookmark
}
class Bookmark {
    static constraints = {
    }
 
    String url
}

Now you are ready to test your app with


grails run-app

To prepare the Grails application for Glassfish the data source for the production environment has to be changed. Open the DataSource.groovy and change

production {
	dataSource {
		dbCreate = "update"
		url = "jdbc:hsqldb:file:prodDb;shutdown=true"
	}
}

to

production {
	dataSource {
		dbCreate = "update"
		// do not use java:/jdbc as documented
		jndiName = "jdbc/__default"
		username = "APP"
		password = "APP"
	}
}

Do not use jndiName = "java:jdbc/__default" as documented. Be aware that it may be dangerous to use dbCreate= "update" in production environments.

Now compile the web archive with

grails war

Start your database and the application server
./asadmin start-database
./asadmin start-domain

Finally open the sun web interface at http://localhost:4848/ to deploy the war file

http://localhost:8080/glassfishapp-0.1/

I experienced some memory problems by using Grails with Glassfish. To fix that problem I added -XX:MaxPermSize=256m and -Xmx1024m as JVM option. JVM options can be changed via the web interface (Common Tasks -> Application Server -> JVM Settings -> JVM Options)

Grails running in Glassfish

Grails running in Glassfish

Tags: , ,

Christoph Hartmann on January 7th, 2009

Within my current research project I faced the challenge to index a whole bunch of files. To be platform independent the Java programming language was the first choice. Then I came along the Lucene project.

Lucene is an open-source project that “provides Java-based indexing and search technology”. I have to mention that Lucene is a framework library instead of an out-of-the-box application. If you think of indexing your files, you may have Microsoft Office files, Adobe pfds or OpenOffice documents in mind. None of these file format can be indexed by Lucene with the standard configuration. But Lucene provides a great API to do parsing of files by other code.

I looked at two projects:

While Tika is not available as a binary download Aperture is. I decided for Tika due to Maven support and clean source code. Aperture comes along a whole bunch of dependencies which make it quite complex to figure out what is really required. Although Tika is only available via source code I’ve done the Lucene Tika integration within an half hour.

Just download the Tika source code via
svn checkout http://svn.apache.org/repos/asf/lucene/tika/trunk tika and use maven to install the binary into your local maven repository.

The following part do the core binding between Tika and Lucene. It asks our own written ContentParser which returns a Lucene Document.

logger.debug("Indexing " + file);
try {
	Document doc = null;
	// parse the document
	synchronized (contentParserAccess) {
		doc = contentParser.getDocument(file);
	}
 
	// put it into Lucene
	if (doc != null) {
		writer.addDocument(doc);
	} else {
		logger.error("Cannot handle "
				+ file.getAbsolutePath() + "; skipping");
	}
} catch (IOException e) {
	logger.error("Cannot index " + file.getAbsolutePath()
			+ "; skipping (" + e.getMessage() + ")");
}

The ContentParser calls the TikaParser for each file and put the metadata it returns into a Lucene document. The most difficult part is determine the Mime-Type. Unfortunately Tike does not use it by default. Therefore we have to call the suitable method MimeTypes repo = config.getMimeRepository() and repo.getMimeType(bufIn). Afterward we have to reset the stream to the start. Otherwise Tika could not retrieve the data properly.

package de.acidum.indexer.tika.parser;
 
import ...
 
/**
*
* This class the is the bridge between Lucene and Tika. It uses Tika to
* retrieve the file content and metadata and generates a Lucene document.
*
* @author Christoph Hartmann
*
*/
public class TikaDocumentParser implements ContentParser {
 
Logger logger = Logger.getLogger(this.getClass());
 
AutoDetectParser autoDetectParser;
TikaConfig config;
 
public TikaDocumentParser() {
	try {
		// load tika config to replace the image parser with our own
		InputStream is = this.getClass().getClassLoader()
				.getResourceAsStream("tika-config.xml");
		config = new TikaConfig(is);
 
		// use tika's auto detect parser
		autoDetectParser = new AutoDetectParser(config);
	} catch (Exception e) {
		logger.error(e);
	}
}
 
private Document getDocument(InputStream input, MimeType mimeType)
		throws ContentParserException {
	Document doc = null;
	try {
		Metadata metadata = new Metadata();
 
		if (mimeType != null) {
			metadata.set(Metadata.CONTENT_TYPE, mimeType.getName());
		}
		ContentHandler handler = new BodyContentHandler();
		try {
			autoDetectParser.parse(input, handler, metadata);
		} catch (Exception e) {
			throw new ContentParserException(e);
		}
 
		doc = new Document();
		// add the content to lucene index document
		doc.add(new Field("body", handler.toString(), Field.Store.NO,
				Field.Index.ANALYZED));
 
		// add meta data
		String[] names = metadata.names();
		for (String name : names) {
			String value = metadata.get(name);
			doc.add(new Field(name, value, Field.Store.YES,
					Field.Index.ANALYZED));
		}
 
	} finally {
		try {
			input.close();
		} catch (IOException e) {
			throw new ContentParserException(e);
		}
	}
 
	return doc;
}
 
public Document getDocument(File file) throws ContentParserException {
 
	InputStream input;
	try {
		input = new FileInputStream(file);
 
		if (input == null) {
			System.out
					.println("Could not open stream from specified resource: "
							+ file.getName());
		}
 
		Document doc = getDocument(input);
 
		// add the file name to the meta data
		if (doc != null) {
			try {
				doc.add(new Field("filename", file.getCanonicalPath(),
						Field.Store.YES, Field.Index.NO));
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
 
		return doc;
 
	} catch (FileNotFoundException e) {
		throw new ContentParserException(e);
	}
 
}
 
public Document getDocument(InputStream input)
		throws ContentParserException {
 
	// try to retrieve the mime type... unfortunately the Tika parser don't
	// handle this automatically
 
	BufferedInputStream bufIn = new BufferedInputStream(input);
 
	MimeType mimeType = null;
 
	if (bufIn.markSupported()) {
		// TODO this may be dangerous...
		bufIn.mark(2048);
		MimeTypes repo = config.getMimeRepository();
		try {
			mimeType = repo.getMimeType(bufIn);
		} catch (IOException e) {
			throw new ContentParserException(e);
		}
		try {
			bufIn.reset();
		} catch (IOException e) {
			logger.error(e);
		}
	}
 
	Document doc = getDocument(bufIn, mimeType);
 
	return doc;
}
 
}

Additionally I wrote a custom TikaParser that extracts the Exif data from JPEG files. To achieve this I used the metadata-extractor. Unfortunately the lib is not available via maven therefore we have to add the lib manually.


mvn install:install-file -Dfile=metadata-extractor-2.3.1.jar -DgroupId=com.drew -DartifactId=metadata-extractor -Dversion=2.3.1 -Dpackaging=jar

A custom tika parser may looks like:

package de.acidum.tika;
 
import java.io.IOException;
import java.io.InputStream;
import java.util.Iterator;
 
import javax.imageio.ImageIO;
import javax.imageio.ImageReader;
 
import org.apache.commons.io.input.CloseShieldInputStream;
import org.apache.log4j.Logger;
import org.apache.tika.exception.TikaException;
import org.apache.tika.metadata.Metadata;
import org.apache.tika.parser.Parser;
import org.apache.tika.sax.XHTMLContentHandler;
import org.xml.sax.ContentHandler;
import org.xml.sax.SAXException;
 
import com.drew.imaging.jpeg.JpegMetadataReader;
import com.drew.imaging.jpeg.JpegProcessingException;
import com.drew.metadata.Directory;
import com.drew.metadata.MetadataException;
import com.drew.metadata.Tag;
 
/**
* This class implements a tika parser. To activate the parser we have to change
* the tika-config.xml.
*
* Compared to the default Tika Image handling we read the Jpeg Exif data and
* return these values as metadata for Lucene
*
* @author Christoph Hartmann
*
*/
public class ImageParser implements Parser {
 
Logger logger = Logger.getLogger(this.getClass());
 
public void parse(InputStream stream, ContentHandler handler,
		Metadata metadata) throws IOException, SAXException, TikaException {
 
	String type = metadata.get(Metadata.CONTENT_TYPE);
 
	if (type != null) {
		// hey we get a jpeg lets read the exif
		if (type.equals("image/jpeg")) {
			extractJPEGMetaData(stream, metadata);
		}
		// if picture is unknown do the default tika handling
		else {
 
			Iterator<ImageReader> iterator = ImageIO
					.getImageReadersByMIMEType(type);
			if (iterator.hasNext()) {
				ImageReader reader = iterator.next();
				reader.setInput(ImageIO
						.createImageInputStream(new CloseShieldInputStream(
								stream)));
				metadata.set("height", Integer
						.toString(reader.getHeight(0)));
				metadata.set("width", Integer.toString(reader.getWidth(0)));
				reader.dispose();
			}
		}
	}
 
	XHTMLContentHandler xhtml = new XHTMLContentHandler(handler, metadata);
	xhtml.startDocument();
	xhtml.endDocument();
}
 
/**
 * get additional metadata for jpeg files
 *
 * @param inputStream
 * @param tikaMetaData
 */
private void extractJPEGMetaData(InputStream inputStream,
		Metadata tikaMetaData) {
 
	// read the exif meta data
	com.drew.metadata.Metadata jpegMetaData;
	try {
		jpegMetaData = JpegMetadataReader.readMetadata(inputStream);
 
		// iterate through metadata directories
		Iterator<?> directories = jpegMetaData.getDirectoryIterator();
		while (directories.hasNext()) {
			Directory directory = (Directory) directories.next();
			// iterate through tags and print to System.out
			Iterator<?> tags = directory.getTagIterator();
			while (tags.hasNext()) {
				Tag tag = (Tag) tags.next();
 
				try {
					tikaMetaData.set(tag.getDirectoryName() + "."
							+ tag.getTagName(), tag.getDescription());
					logger.debug(tag.getDirectoryName() + "."
							+ tag.getTagName() + " -> "
							+ tag.getDescription());
				} catch (MetadataException e) {
					logger.error(e);
				}
			}
		}
 
	} catch (JpegProcessingException e) {
		logger.error(e);
	}
}
}

You can download the whole Lucene + Tika example and try yourself.

zip

UPDATE: The project uses Maven 2 to build the jar. The official page offers installation instructions and guidelines.

Tags: , , , ,

Christoph Hartmann on December 29th, 2008

Unfortunately J2ME does not provide the best basis for writing a REST Web Service. As I already mentioned in previous posts the J2ME reference implementation does not support all HTTP methods. To overcome this restriction I wrote a J2ME Rest Client that uses HTTP method emulation like Rails does. Even though I heard that some J2ME platforms support PUT and DELETE I decided to use the standard. Method emulation may become a challenge if you’re not talking to your own services since it require a suitable server implementation like I posted for Grails earlier.

The following code illustrates how the Rest Client works. It uses the BasicAuth class from Sun. I removed the imports, because it should be obvious. In future versions of the class I plan to use one method to read the data from stream an check the status to reduce the file size. But for my first prototype it works that way.

/**
 * This class provided a REST implementation for J2ME.
 * @author Christoph Hartmann
 */
public class RestClient {
	String userid;
	String password;
	// User Agent
	private String ua;
 
	public RestClient() {}
 
	public RestClient(String userid, String password) {
		this.userid = userid;
		this.password = password;
		ua = "Profile/" + System.getProperty("microedition.profiles")
				+ " Configuration/"
				+ System.getProperty("microedition.configuration");
	}
 
	/**
	 * prepare the HTTP connection
	 * @param conn
	 * @throws IOException
	 */
	private void configureConncetion(HttpConnection conn) throws IOException {
		conn.setRequestProperty("User-Agent", ua);
		String locale = System.getProperty("microedition.locale");
		if (locale == null) { locale = "en-US";	}
		conn.setRequestProperty("Accept-Language", locale);
		conn.setRequestProperty("Content-Type", "text/plain");
		conn.setRequestProperty("Accept", "text/plain");
		// set HTTP basic authentification
		if (userid != null &#038;&#038; password != null) {
			conn.setRequestProperty("Authorization", "Basic " + BasicAuth.encode(userid, password));
		}
	}
 
	public HttpConnection getConnection(String url) throws IOException {
		HttpConnection conn = (HttpConnection) Connector.open(url);
		configureConncetion(conn);
		return conn;
	}
 
	public HttpConnection getConnection(String url, int access) throws IOException {
		HttpConnection conn = (HttpConnection) Connector.open(url, access);
		configureConncetion(conn);
		return conn;
	}
 
	/**
	 * READ
	 * @param url
	 * @return
	 * @throws IOException
	 */
	public String get(String url) throws IOException {
		HttpConnection hcon = null;
		DataInputStream dis = null;
		StringBuffer responseMessage = new StringBuffer();
 
		try {
			int redirectTimes = 0;
			boolean redirect;
 
			do {
				redirect = false;
 
				// a standard HttpConnection with READ access
				hcon = getConnection(url);
				// obtain a DataInputStream from the HttpConnection
				dis = new DataInputStream(hcon.openInputStream());
				// retrieve the response from the server
				int ch;
				while ((ch = dis.read()) != -1) {
					responseMessage.append((char) ch);
				}// end while ( ( ch = dis.read() ) != -1 )
				// check status code
				int status = hcon.getResponseCode();
 
				switch (status) {
				case HttpConnection.HTTP_OK: // Success!
					break;
				case HttpConnection.HTTP_TEMP_REDIRECT:
				case HttpConnection.HTTP_MOVED_TEMP:
				case HttpConnection.HTTP_MOVED_PERM:
					// Redirect: get the new location
					url = hcon.getHeaderField("location");
					System.out.println("Redirect: " + url);
 
					if (dis != null) dis.close();
					if (hcon != null) hcon.close();
 
					hcon = null;
					redirectTimes++;
					redirect = true;
					break;
				default:
					// Error: throw exception
					hcon.close();
					throw new IOException("Response status not OK:" + status);
				}
 
				// max 5 redirects
			} while (redirect == true &#038;&#038; redirectTimes < 5);
 
			if (redirectTimes == 5) {
				throw new IOException("Too much redirects");
			}
 
		} catch (Exception e) {
			e.printStackTrace();
			// TODO bad style
			responseMessage.append("ERROR: ");
		} finally {
			try {
				if (hcon != null)
					hcon.close();
				if (dis != null)
					dis.close();
			} catch (IOException ioe) {
				ioe.printStackTrace();
			}// end try/catch
		}// end try/catch/finally
		return responseMessage.toString();
 
	}// end sendGetRequest( String )
 
	/**
	 * UPDATE
	 *
	 * @param url
	 * @param data
	 *            the request body
	 * @throws IOException
	 */
	public String post(String url, String data) throws IOException {
 
		HttpConnection hcon = null;
		DataInputStream dis = null;
		DataOutputStream dos = null;
		StringBuffer responseMessage = new StringBuffer();
 
		try {
			int redirectTimes = 0;
			boolean redirect;
 
			do {
				redirect = false;
				// an HttpConnection with both read and write access
				hcon = getConnection(url, Connector.READ_WRITE);
				// set the request method to POST
				hcon.setRequestMethod(HttpConnection.POST);
				// overwrite content type to be form based
				hcon.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
				// set message length
				if (data != null) {
					hcon.setRequestProperty("Content-Length", ""
							+ data.length());
				}
 
				if (data != null) {
					// obtain DataOutputStream for sending the request string
					dos = hcon.openDataOutputStream();
					byte[] request_body = data.getBytes();
					// send request string to server
					for (int i = 0; i < request_body.length; i++) {
						dos.writeByte(request_body[i]);
					}// end for( int i = 0; i < request_body.length; i++ )
					dos.flush(); // Including this line may produce
					// undesiredresults on certain devices
				}
 
				// obtain DataInputStream for receiving server response
				dis = new DataInputStream(hcon.openInputStream());
				// retrieve the response from server
				int ch;
				while ((ch = dis.read()) != -1) {
					responseMessage.append((char) ch);
				}// end while( ( ch = dis.read() ) != -1 ) {
				// check status code
				int status = hcon.getResponseCode();
				switch (status) {
				case HttpConnection.HTTP_OK: // Success!
					break;
				case HttpConnection.HTTP_TEMP_REDIRECT:
				case HttpConnection.HTTP_MOVED_TEMP:
				case HttpConnection.HTTP_MOVED_PERM:
					// Redirect: get the new location
					url = hcon.getHeaderField("location");
					System.out.println("Redirect: " + url);
 
					if (dis != null) dis.close();
					if (hcon != null) hcon.close();
					hcon = null;
					redirectTimes++;
					redirect = true;
					break;
				default:
					// Error: throw exception
					hcon.close();
					throw new IOException("Response status not OK:" + status);
				}
 
				// max 5 redirects
			} while (redirect == true &#038;&#038; redirectTimes < 5);
 
			if (redirectTimes == 5) {
				throw new IOException("Too much redirects");
			}
		} catch (Exception e) {
			e.printStackTrace();
			responseMessage.append("ERROR");
		} finally {
			// free up i/o streams and http connection
			try {
				if (hcon != null) hcon.close();
				if (dis != null) dis.close();
				if (dos != null) dos.close();
			} catch (IOException ioe) {
				ioe.printStackTrace();
			}// end try/catch
		}// end try/catch/finally
		return responseMessage.toString();
	}
 
	/**
	 * DELETE
	 * not possible on J2ME therefore we use Rails emulation on PUT and
	 * DELETE like
	 * http://localhost:8080/CandyStreamServer/airport/1?_method=delete
	 * @param url
	 */
	public String delete(String url) throws IOException {
		url += "?_method=DELETE";
		return post(url, null);
	}
 
	/**
	 * CREATE not possible on J2ME therefore we use Rails emulation on PUT and
	 * DELETE
	 * @param url
	 * @param data
	 */
	public String put(String url, String data) throws IOException {
		data += "&#038;_method=PUT";
		url += "?" + data;
		return post(url, null);
	}
}

Tags: ,

Christoph Hartmann on December 13th, 2008

The groovy swing builder is one of Groovys best features. It becomes quite easy to build a gui with the builder. In some cases you may like to add a custom Java swing component to your swing builder. For such cases the swing builder is equipped with the widget() method. The following code uses the swing builder tabbed pane and add a custom component implemented in the getSearchPanel() method as tab.

package de.acidum.candystreams.gui;
 
import groovy.swing.SwingBuilder
import javax.swing.SwingUtilities
import javax.swing.JFrame
import java.awt.BorderLayout
import javax.swing.JLabel
import javax.swing.JLabel
import javax.swing.JPanel
 
public class CandystreamsClient implements Runnable {
 
	CandystreamsClient(){
		// set system property to use mac os menu bar
		System.setProperty("apple.laf.useScreenMenuBar", "true")
 
		// set the application name for mac os
		System.setProperty("com.apple.mrj.application.apple.menu.about.name", "CandyStreams")
	}
 
	public void run() {
		def swing = new SwingBuilder()
		def frame = swing.frame(title: "CandyStreams",
			defaultCloseOperation: JFrame.DISPOSE_ON_CLOSE,
		    size: [800, 600]){
			// add a simple menu bar
			menuBar() {
			    menu(text: "File", mnemonic: 'F') {
			      menuItem(text: "Exit", mnemonic: 'X', actionPerformed: { System.exit(0) })
			    }
			}
			// add a tabbed pane
			tabbedPane() {
				panel(title:'Panel 1', tabBackground:java.awt.Color.GREEN,tabToolTip:'Panel1')
                                // add custom swing component
				widget(title:'Search', getSearchPanel())
			}
		}
		frame.show()
	}
 
	public getSearchPanel(){
		JPanel panel = new JPanel()
		panel.add(new JLabel("Search Panel"))
		return panel
	}
 
	public static void main(String[] args) {
		SwingUtilities.invokeLater(new CandystreamsClient())
	}
}

Tags: , ,

Christoph Hartmann on November 15th, 2008

I set up an mobile application that sends data via a REST based interface to a Grails-based server. Unfortunately J2ME does not support all HTTP methods. To overcome this weakness we have to emulate the methods PUT and DELETE. Like Rails just did this by adding a “_method=PUT” parameter to the query URL, we will do the same. Rails does the HTTP method emulation handling automatically, whilst in Grails we have do this by ourselves. By using the UrlMapping.groovy it will become quite easy to overcome this weakness. A standard REST mapping should look like:

 
class UrlMappings {
   static mappings = {
          // identifies a rest object like /rest/airport/1
	  "/rest/$domain/$id"{
		  controller = "rest"
		  action = [GET:"show", PUT:"create", POST:"update",DELETE:"delete"]
         }
   }
}

The action attribute may be a simple string, a hash map or a closure. Grails calls the following method evaluateNameForValue(Object value, GrailsWebRequest webRequest) to retrieve the value. The method is located within the org.codehaus.groovy.grails.web.mapping.DefaultUrlMappingInfo.

private String evaluateNameForValue(Object value, GrailsWebRequest webRequest) {
        if (value == null) {
            return null;
        }
        String name;
        if (value instanceof Closure) {
            Closure callable = (Closure) value;
            Object result = ((Closure) callable.clone()).call();
            name = result != null ? result.toString() : null;
        } else if (value instanceof Map) {
            Map httpMethods = (Map) value;
            name = (String) httpMethods.get(webRequest.getCurrentRequest().getMethod());
        } else {
            name = value.toString();
        }
        return name;
    }

Due to our knowledge of the action retrieval process, we are able to implement a “_method” emulation. This could look like:

 
class UrlMappings {
   static mappings = {
          // identifies a rest object like /rest/airport/1
	  "/rest/$domain/$id"{
		  controller = "rest"
		  // action = [GET:"show", PUT:"create", POST:"update",DELETE:"delete"]
 
	         action = {
		   // closure will not be invoked with request, log ... therefore we have to do this manually
		  GrailsWebRequest webRequest = (GrailsWebRequest) RequestContextHolder.getRequestAttributes();
		  String method = webRequest.getCurrentRequest().getMethod();
		  String methodParam = webRequest.getCurrentRequest().getParameter("_method");
 
		  // check if we can use _method
		  if (methodParam != null) {
		    methodParam = methodParam.toUpperCase()
 
		    switch (methodParam) {
			case "PUT" :
			case "DELETE" :
			case "POST" :
			case "GET" :
			  method = methodParam;
			break
		  }
		} 
 
		switch (method.toUpperCase()) {
		  case "PUT" : return "create"
			break
		  case "DELETE" : return "delete"
			break
		  case "POST" : return "update"
			break
		  case "GET" : return "show"
			break
		  default:  return "show"
		        break
		}
		return method;
		}
         }
   }
}

I hope that helps all Grails REST developers to enable their services for J2ME.

Tags: , , ,

Christoph Hartmann on October 8th, 2008

For my current grails project I use the Spring Security Plugin (formerly Acegi Security) to secure my views and services. A tutorial at the Grails site gives a great overview how to install the grails plugin.

Right after installation I faced some issues:

Secure your Rest Services

This sounds quite easy due to a simple switch within the SecurityConfig.groovy. Just activate the BasicProcessingFilter. Now grails uses the Http Basic Authentification.

/** use basicProcessingFilter */
basicProcessingFilter = true

At the client side the code would like:

import sun.misc.BASE64Encoder
import groovy.util.XmlSlurper
 
def userid = "john.doe"
def password = "pass"
 
def url = "http://localhost:8080/CandyStreamServer/rest/gps/"
 
def conn = new URL(url).openConnection()
 
if (userid && password) {
	println "set authorization"
 
	// add HTTP authentication
       String encodedAuth = new BASE64Encoder().encode((userid + ":" + password).getBytes()) 
 
	conn.setRequestProperty("Authorization", "Basic " + encodedAuth)
}
 
def slurper = new XmlSlurper()
 
conn.requestMethod = "GET"
conn.doOutput = true
 
println "check connection"
def response
if (conn.responseCode == conn.HTTP_OK) {
	conn.inputStream.withStream {
		response = slurper.parse(it)
	}
} else {
	response = conn.responseCod
}
println response
conn.disconnect()

Retrieve the Current User

On the server side it may necessary to retrieve the current user. Spring Security offers a SecurityContextHolder. Unfortunately the securityContext.getAuthentication().getPrincipal(); does not return the Groovy user object. Instead the Spring Security Plugin uses its own user implementation that holds the Groovy user object. This is required due to Springs dependency on a specific interface.

The plugin provides a org.codehaus.groovy.grails.plugins.springsecurity.GrailsUser interface that extends the org.springframework.security.userdetails.UserDetails interface. To retrieve your Groovy user object just call getDomainClass()

SecurityContext securityContext = SecurityContextHolder.getContext();
def springUser = securityContext.getAuthentication().getPrincipal();
return springUser.getDomainClass()

Tags: , , ,

Christoph Hartmann on October 7th, 2008

Im Rahmen des Seminars Meta-Programmierung haben Lars Blumberg, Arvid Heise und ich eine Ausarbeitung erstellt, welche die Metaprogrammierung von Groovy untersucht.

Abstract:

Der Name der Programmiersprache ist Programm. Dass Groovy als noch junge Sprache viele neue und interessante Sprachkonzepte mitbringt, möchten wir im ersten Teil dieses Papers aufzeigen. Ein weiteres Highlight des ersten Kapitels ist vielleicht die Erkenntnis über die gelungene, nahtlos Integration mit der Java-Plattform. Im folgenden Hauptteil wird insbesondere die Möglichkeit der Meta-Programmierung mit Groovy beschrieben. Es wird auf die Umsetzung des Meta-Object-Protocols eingegangen und erläutert, wie die zugehörigen Konzepte mit Hilfe der Java Virtual Machine umgesetzt werden konnten. Im dritten und letzten Teil wird dem Leser eine implementierte Beispiel-Anwendung vorgestellt. Sie ist wie dieses Paper im Rahmen der Veranstaltung “Metaprogrammierung und Reflection” entstanden und demonstriert eindrucksvoll die Meta-Programmierung in Groovy.

Keywords:

Groovy, Metaprogramming

PfdGroovy Meta Programming Paper

PfdGroovy Meta Programming Slides

Tags: ,

Christoph Hartmann on October 7th, 2008

The Apple Wireless Keyboard is a amazing slim keyboard. But how to clean? The following pictures illustrate this process. It’s quite difficult to remove the keys without breaking them. Use a small screwdriver and keep cool. ;-)

Apple Wireless Keyboard 03Apple Wireless Keyboard 01Apple Wireless Keyboard 02Apple Wireless Keyboard 03

Tags: ,

Christoph Hartmann on September 11th, 2008

Java Iteration Example

import java.util.Date;
 
public class Foo {
    public static void main(String[] args) {
        int start = 1;
        int summe = 0;
 
        for (int i = start; i <= 5; i++) {
            summe += i;
        }
 
        Date now = new Date();
        System.out.println(now.toString() + " Die Summe ist: " + summe);
    }
}

Groovy Iteration Example within Groovy Shell

 
        start = 1
        summe = 0
 
        for (i in start..5) {
            summe += i
        }
 
        now = new Date()
        println "$now Die Summe ist: $summe"

Groovy Map Handling with Closures

map = ["a":1, "b":2]
 
// inline closure
map.each { key, value ->
    map[key] = value*2
}
println map
 
// extern closure
doubler = { key, value ->
    map[key] = value*2
}
map.each(doubler)
println map

Groovy Beans

class Book {
    String title
 
    Book (String theTitle) {
        title = theTitle
    }
    Book plus(Book anotherBook) {
        return new Book(title + ", " + anotherBook.title)
    }
}
Book gina = new Book("Groovy in Action")
// getters are generated automatically 
println gina.getTitle()
 
println ((gina + new Book("Groovy for Experts")).title)

Groovy Duck Typing

 
class Dog {
    def speak() { println "wuff" }
}
class Cat {
    def speak() { println "miau" }
}
def saySomething(somewhat) {
    somewhat.speak()
}
 
saySomething(new Dog())
saySomething(new Cat())

Simple XML Example:

 
class XmlBuilder {
   def out
   XmlBuilder(out) { this.out = out }
   def invokeMethod(String name, args) {
       out << "<$name>"
       if(args[0] instanceof Closure) {
            args[0].delegate = this
            args[0].call()
       }
       else {
           out << args[0].toString()
       }
       out << "</$name>"
   }
}
 
def xml = new XmlBuilder(new StringBuffer())
xml.html {
    head {
        title "Hello World"
    }
    body {
        p "Welcome!"
    }
}
println xml.out

Tags: , ,