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: BPMN, Business Process, Modeling, PowerPoint, Template
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)
Tags: Code Examples, Glassfish, Grails
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.
UPDATE: The project uses Maven 2 to build the jar. The official page offers installation instructions and guidelines.
Tags: Index, Java, Lucene, Search Engine, Tika
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 && 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 && 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 && 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 += "&_method=PUT"; url += "?" + data; return post(url, null); } }
Tags: J2ME, Web Service
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()) } }
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: Grails, Groovy, J2ME, Web Service
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: Acegi Security, Grails, Groovy, Spring Security
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
Groovy Meta Programming Slides
Tags: Groovy, Metaprogramming
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.
Tags: Apple, Wireless Keyboard
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: Code Examples, Groovy, Metaprogramming
