Wednesday, 21 April 2010

map, foldr & foldl higher-order functions in Java

Here are my implementations of some higher-order functions in java, foldl, foldr, map and others.

Functionals.java

package org.adrianwalker.functional;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public final class Functionals {

  private static final String EMPTY_STRING = "";
  private static final List EMPTY_LIST = Collections.EMPTY_LIST;

  private Functionals() {
  }

  public static <T1, T2> T2 foldr(final Function<T1, T2> f, final T2 b, final List<T1> lst) {
    if (lst.isEmpty()) {
      return b;
    }

    return f.call(head(lst), foldr(f, b, tail(lst)));
  }

  public static <T1, T2> T2 foldl(final Function<T1, T2> f, final T2 b, final List<T1> lst) {
    if (lst.isEmpty()) {
      return b;
    }

    return foldl(f, f.call(head(lst), b), tail(lst));
  }

  public static <T1, T2> List<T2> map(final Function<T1, T2> f, final List<T1> lst) {
    return foldr(new Function<T1, List<T2>>() {

      @Override
      public List<T2> call(final T1 t1, final List<T2> t2) {
        return cons(f.call(t1), t2);
      }
    }, (List<T2>) EMPTY_LIST, lst);
  }

  public static <T1> List<T1> cons(final T1 x, final List<T1> xs) {
    List<T1> lst = newList(xs.size() + 1);
    lst.add(0, x);
    lst.addAll(1, xs);
    return Collections.unmodifiableList(lst);
  }

  public static <T1> T1 head(final List<T1> lst) {
    return lst.get(0);
  }

  public static <T1> List<T1> tail(final List<T1> lst) {
    List<T1> xs = newList(lst.size() - 1);
    xs.addAll(0, lst.subList(1, lst.size()));
    return Collections.unmodifiableList(xs);
  }

  public static List<Character> explode(final String string) {
    if (string.isEmpty()) {
      return (List<Character>) EMPTY_LIST;
    }

    return cons(string.charAt(0), explode(string.substring(1)));
  }

  public static String implode(final List<Character> lst) {
    return foldl(new Function<Character, String>() {

      @Override
      public String call(final Character t1, final String t2) {
        return t2 + t1;
      }
    }, EMPTY_STRING, lst);
  }

  public static <T1> List<T1> rev(final List<T1> lst) {
    return foldl(new Function<T1, List<T1>>() {

      @Override
      public List<T1> call(final T1 t1, final List<T1> t2) {
        return cons(t1, t2);
      }
    }, (List<T1>) EMPTY_LIST, lst);
  }

  private static <E> List<E> newList(final int initialCapacity) {
    return new ArrayList<E>(initialCapacity);
  }
}

Example Usage

Summing a list of integers using foldr.

List<Integer> input = Arrays.asList(new Integer[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10});

Integer output = Functionals.foldr(new Function<Integer, Integer>() {

  @Override
  public Integer call(final Integer t1, final Integer t2) {
    return t1 + t2;
  }
}, 0, input);

System.out.println(String.format("Sum: %s", output));

Source Code

Download the source and see the unit tests for other examples of usage.

Monday, 12 April 2010

ColdFusion Head First Design Patterns: Decorator

Continuing in this design patterns series taken from Head First Design Patterns, is a ColdFusion implementation of the Decorator Pattern.

Abstract Beverage

Beverage.cfc

<cfcomponent output="false">

  <cfset VARIABLES.description = "Unknown Beverage">
  
  <cffunction access="public" returntype="string" name="getDescription">
    <cfreturn VARIABLES.description>
  </cffunction>

  <cffunction access="public" returntype="numeric" name="cost" >    
  </cffunction>

</cfcomponent>

Abstract Decorator

CondimentDecorator.cfc

<cfcomponent extends="Beverage" output="false">
  
  <cffunction access="public" returntype="string" name="getDescription">
  </cffunction>
  
</cfcomponent>

Concrete Beverages

HouseBlend.cfc

<cfcomponent extends="Beverage" output="false">

  <cffunction access="public" name="init" returntype="HouseBlend">
    <cfset VARIABLES.description = "House Blend Coffee">
    
    <cfreturn THIS>
  </cffunction>  

  <cffunction access="public" returntype="numeric" name="cost" >
    <cfreturn 0.89>    
  </cffunction>  

</cfcomponent>

Espresso.cfc

<cfcomponent extends="Beverage">

  <cffunction access="public" name="init" returntype="Espresso">
    <cfset VARIABLES.description = "Espresso">
    
    <cfreturn THIS>
  </cffunction>

  <cffunction access="public" returntype="numeric" name="cost" >
    <cfreturn 1.99>    
  </cffunction>
  
</cfcomponent>

Concrete Decorators

Mocha.cfc

<cfcomponent extends="CondimentDecorator">

  <cffunction access="public" name="init" returntype="Mocha">
    <cfargument type="Beverage" name="beverage">
    
    <cfset VARIABLES.beverage = ARGUMENTS.beverage>
    
    <cfreturn THIS>
  </cffunction>

  <cffunction access="public" returntype="string" name="getDescription">
    <cfreturn VARIABLES.beverage.getDescription() & ", Mocha">
  </cffunction>

  <cffunction access="public" returntype="numeric" name="cost" >
    <cfreturn 0.20 + VARIABLES.beverage.cost()>
  </cffunction>

</cfcomponent>

Test Page

StarbuzzCoffee.cfm

<cfset beverage = createObject("component", "Espresso").init()>

<cfset beverage2 = createObject("component", "HouseBlend").init()>
<cfset beverage2 = createObject("component", "Mocha").init(beverage2)>
<cfset beverage2 = createObject("component", "Mocha").init(beverage2)>

<cfoutput>
  #beverage.getDescription()# $#beverage.cost()#
  <br />
  #beverage2.getDescription()# $#beverage2.cost()#
</cfoutput>

Source Code

Thursday, 8 April 2010

ColdFusion Builder Crack

ColdFusion Builder has been my weapon of choice for writing CFML since it has been in beta and free. Now it's at version 1.0.0, and Adobe has decided to charge $299 for it, I think I'll be going back to CFEclipse.

Shouldn't Adobe be trying to build it's user base by giving CFBuilder away for free? Even Microsoft has got in on the act with it's Express tools.

I also find it quite a poor show that Adobe has taken an Open Source project, Eclipse, added very little to it, re-branded it and is trying to charge the CF developer community, who are inexplicably loyal to Adobe, $299 a pop for it.

So just for shits and giggles here is how you might crack CFBuilder to continue using it for free.

You will need:-

  1. ColdFusion Builder Trial
  2. JD-GUI Java Decompiler
  3. 7-Zip

If you installed CFBuilder in the default location, the class files we need to modify are in:

C:\Program Files\Adobe\Adobe ColdFusion Builder\plugins\com.adobe.ide.coldfusion.common_1.0.0.271911.jar

Start the decompiler and open the above JAR file. The class we need to edit is:

com.adobe.ide.coldfusion.common.util.TestUtil.class

Navigate to the TestUtil class, the JD decompiler produces the following code:

TestUtil.java

package com.adobe.ide.coldfusion.common.util;

import com.adobe.ide.amt.Activator;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.util.Calendar;
import java.util.Date;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Timer;
import java.util.TimerTask;
import org.eclipse.core.runtime.Platform;
import org.eclipse.swt.widgets.Display;

public class TestUtil
{
  private Calendar _expDate = null;
  private Calendar _installDate = null;
  private int _evalDays = 30;
  private boolean _expired = false;
  private File _hiddenFile = null;
  private static final long MAGIC = -889275714L;
  private String _code = null;
  private boolean isBeta = true;
  private static final TestUtil instance = new TestUtil();
  private boolean isCheckDone = false;
  private boolean isValidLicense = false;
  private static final Object lockObject = new Object();
  private boolean cfbStartupPluginLoaded = false;

  public static final Object getLockObject() {
    return lockObject;
  }

  public static TestUtil getInstance() {
    return instance;
  }

  private TestUtil()
  {
    Timer timer = new Timer();

    TimerHelper timerTask = new TimerHelper(null);

    timer.schedule(timerTask, 150000L);

    this._expDate = Calendar.getInstance();
    this._expDate.set(2010, 2, 30);
    checkExpired();
  }

  static Long encodeDate(long time) {
    return Long.valueOf(0xCAFEBABE ^ (time >>> 32 | time << 32));
  }

  private void setCode() {
    Calendar now = Calendar.getInstance();
    this._code = encodeDate(now.getTime().getTime()).toString();
  }

  private void checkExpired() {
    if (!this.isBeta) {
      this._expired = false;
      return;
    }

    setHiddenFile();
    if (!hiddenFileExists()) {
      createFileIfNeeded();
    }

    setHiddenProps();
    if (!checkHiddenFile())
      this._expired = true;
  }

  private void createFileIfNeeded()
  {
    Process p = null;
    setCode();
    try {
      PrintWriter out = new PrintWriter(
        new BufferedWriter(new OutputStreamWriter(new FileOutputStream(this._hiddenFile))));
      out.println(this._code);
      out.close();
      if (!File.separator.equalsIgnoreCase("\\")) {
        break label99;
      }

      String command = "attrib +H " + this._hiddenFile.getPath();
      p = Runtime.getRuntime().exec(command);
      label99: p.waitFor();
    }
    catch (Exception localException) {
    }
    finally {
      if (p != null)
        p.destroy();
    }
  }

  private int getDaysDiffFromHiddenFile()
  {
    int _installYear = this._installDate.get(1);
    int _expYear = this._expDate.get(1);
    int yearDiff = _expYear - _installYear;

    return this._expDate.get(6) - 
      this._installDate.get(6) + 365 * yearDiff;
  }

  private void emptyHiddenFile() {
    Process p = null;
    try {
      this._hiddenFile.delete();
      this._hiddenFile.createNewFile();
      if (!File.separator.equalsIgnoreCase("\\")) {
        break label66;
      }

      String command = "attrib +H " + this._hiddenFile.getPath();
      p = Runtime.getRuntime().exec(command);
      label66: p.waitFor();
    }
    catch (Exception localException) {
    }
    finally {
      if (p != null)
        p.destroy();
    }
  }

  private boolean checkHiddenFile()
  {
    this._installDate = Calendar.getInstance();
    if (!isEmpty(this._code)) {
      this._installDate.setTime(decodeDate(Long.parseLong(this._code)));
      this._evalDays = getDaysDiffFromHiddenFile();
      if (getEvalDaysLeftForBeta() <= 0L) {
        this._expired = true;
      }

      return true;
    }
    return false;
  }

  private void checkSystemDate() {
    this._evalDays = getDaysDiffFromBeta();
    if (this._evalDays <= 0)
      this._expired = true;
  }

  private boolean hiddenFileExists()
  {
    return this._hiddenFile.exists();
  }

  private boolean isEmpty(String s)
  {
    return (s == null) || (s.length() == 0);
  }

  static final Date decodeDate(long code) {
    Date d = null;
    if (code != 0L) {
      code = 0xCAFEBABE ^ code;
      long time = code << 32 | code >>> 32;
      d = new Date(time);
    }
    return d;
  }

  private void setHiddenProps() {
    try {
      BufferedReader br = new BufferedReader(new FileReader(this._hiddenFile));
      String line = br.readLine();

      if (!isEmpty(line)) {
        this._code = line;
      }
      br.close();
    }
    catch (Exception localException) {
    }
  }

  private void setHiddenFile() {
    if (File.separator.equalsIgnoreCase("\\"))
    {
      String _hiddenfilename = getSystemDrive() + "\\.tolb3755.bin";
      this._hiddenFile = new File(_hiddenfilename);
    } else {
      String _hiddenfilename = getUnixHome() + "/.tolb3755.bin";
      this._hiddenFile = new File(_hiddenfilename);
    }
  }

  private String getEnv(String envvar)
  {
    Map variables = System.getenv();
    String value = "";
    for (Map.Entry entry : variables.entrySet()) {
      String name = (String)entry.getKey();
      value = (String)entry.getValue();
      if (name.equalsIgnoreCase(envvar.toUpperCase())) {
        break;
      }
    }
    return value;
  }

  private String getUnixHome()
  {
    return getEnv("HOME");
  }

  private String getSystemDrive() {
    return getEnv("SYSTEMDRIVE");
  }

  private int getDaysDiffFromBeta()
  {
    Calendar now = Calendar.getInstance();
    now.setTime(new Date());
    int _nowYear = now.get(1);

    int _expYear = this._expDate.get(1);

    int yearDiff = _expYear - _nowYear;

    int daysLeft = this._expDate.get(6) - 
      now.get(6) + 365 * yearDiff;
    return daysLeft;
  }

  public long getEvalDaysLeftForBeta()
  {
    int daysLeft = getDaysDiffFromBeta();
    if (daysLeft < 0)
      daysLeft = 0;
    return daysLeft;
  }

  public boolean isExpired() {
    return this._expired;
  }

  public boolean isValidAtStartup()
  {
    return isValidHelper(true);
  }

  public boolean isValid() {
    return isValidHelper(false);
  }

  public boolean isValidHelper(boolean calledFromStartup) {
    synchronized (getLockObject()) {
      if (this.isCheckDone) {
        return this.isValidLicense;
      }
    }
    return validate(calledFromStartup);
  }

  private boolean validate(boolean calledFromStartup)
  {
    if (!calledFromStartup)
    {
      return true;
    }

    synchronized (getLockObject())
    {
      try {
        if (this.isCheckDone)
          break label56;
        this.cfbStartupPluginLoaded = true;
        Activator.AMT_Initialize();
        int iProductActionIndicator = Activator.AMT_ObtainLicense(
          "ColdFusionBuilder_Base", 1, 0);
        label56: if (iProductActionIndicator > 1)
          this.isValidLicense = false;
        else {
          this.isValidLicense = true;
        }

      }
      catch (Throwable localThrowable)
      {
        this.isValidLicense = false;
      } finally {
        this.isCheckDone = true;
      }

      return this.isValidLicense;
    }
  }

  private class TimerHelper extends TimerTask
  {
    private TimerHelper()
    {
    }

    public void run()
    {
      try
      {
        if (TestUtil.this.cfbStartupPluginLoaded) {
          break label58;
        }
        Runnable task = new Runnable()
        {
          public void run()
          {
            TestUtil.this.isValidHelper(true);
          }
        };
        if (Platform.getOS().equalsIgnoreCase("macosx"))
        {
          Display.getDefault().syncExec(task);
        }
        else
        {
          Display display1 = new Display();
          display1.syncExec(task);
          label58: display1.dispose();
        }

      }
      catch (Throwable localThrowable)
      {
      }
      finally
      {
        TestUtil.this.isCheckDone = true;
      }
    }
  }
}

What we want to do is remove any validation logic and always return values indicating the the license is valid. After a bit of editing, your new TestUtil.java should look something like:

TestUtil.java

package com.adobe.ide.coldfusion.common.util;

import java.util.Date;

public class TestUtil {
  private static final TestUtil instance = new TestUtil();
  private static final Object lockObject = new Object();

  public static final Object getLockObject() {
    return lockObject;
  }

  public static TestUtil getInstance() {
    return instance;
  }

  private TestUtil() {
  }

  static Long encodeDate(long time) {
    return Long.valueOf(0xCAFEBABE ^ (time >>> 32 | time << 32));
  }

  static final Date decodeDate(long code) {
    Date d = null;
    if (code != 0L) {
      code = 0xCAFEBABE ^ code;
      long time = code << 32 | code >>> 32;
      d = new Date(time);
    }
    return d;
  }

  public long getEvalDaysLeftForBeta() {
    return 1;
  }

  public boolean isExpired() {
    return false;
  }

  public boolean isValidAtStartup() {
    return true;
  }

  public boolean isValid() {
    return true;
  }

  public boolean isValidHelper(boolean calledFromStartup) {
    return true;
  }
}

Recompile this class, and using 7-Zip, replace the old class in:

C:\Program Files\Adobe\Adobe ColdFusion Builder\plugins\com.adobe.ide.coldfusion.common_1.0.0.271911.jar

with the one you just compiled.

Now just start ColdFusion Builder and the registration screen should not appear.

As always with this type of thing, I won't be held responsible for anyone actually doing this, it's naughty and you might get a telling off, so don't do it. Either pay for CFBuilder or go download CFEclipse for free.

Friday, 12 March 2010

Codility.com Demo Test

I like online programming challenges like this demo offered by Codility, it reassures me that I might still be able to think, check it out here:

Sample Test

This was my solution:

private static int equi(int[] A) {

  if (null == A) {
    return -1;
  }

  int size = A.length;

  if (size == 0) {
    return -1;
  }

  long runningSum = 0;
  long[] runningSums = new long[size];

  for (int i = 0; i < size; i++) {
    runningSum += A[i];
    runningSums[i] = runningSum;      
  }

  for (int i = 0; i < size; i++) {
    long lhsSum = runningSums[i] - A[i];
    long rhsSum = runningSum - runningSums[i];

    if(lhsSum == rhsSum) {
      return i;
    }
  }

  return -1;
}

Monday, 1 March 2010

Maven, Jython & Glassfish Example

I keep meaning to get stuck in and learn some Python, and especially make use of some Jython. After coming across this post about using Jython with Glassfish, I thought I'd give it a go myself.

This post is about creating a Maven WAR project making use of Python scripts running on embedded Jython on an embedded Glassfish v3 instance.

Here is the projects POM:

pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">

  <modelVersion>4.0.0</modelVersion>
  <groupId>org.adrianwalker.maven.skeleton.war.jython.glassfish</groupId>
  <artifactId>maven-war-jython-glassfish-example</artifactId>
  <packaging>war</packaging>
  <version>0.1.0</version>
  <name>Maven WAR-Jython-Glassfish Example</name>

  <description>
    Example project for creating a Jython WAR running on Glassfish.
    
    Usage: mvn clean install embedded-glassfish:run
  </description>

  <url>http://www.adrianwalker.org</url>

  <organization>
    <name>adrianwalker.org</name>
    <url>http://www.adrianwalker.org</url>
  </organization>

  <developers>
    <developer>
      <name>Adrian Walker</name>
      <email>ady.walker@gmail.com</email>
      <organization>adrianwalker.org</organization>
      <organizationUrl>http://www.adrianwalker.org</organizationUrl>
    </developer>
  </developers>

  <repositories>
    <!--
    Use project lib directory as repository
    -->
    <repository>
      <id>project</id>
      <url>file://${basedir}/lib</url>
    </repository>
  </repositories>

  <pluginRepositories>
    <pluginRepository>
      <id>java.net</id>
      <url>http://download.java.net/maven/glassfish</url>
    </pluginRepository>
  </pluginRepositories>

  <build>
    <finalName>example</finalName>

    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-war-plugin</artifactId>
        <configuration>
          <webResources>
            <webResource>
              <directory>${basedir}/src/main/python</directory>
              <includes>
                <include>**/*.py</include>
              </includes>
            </webResource>
          </webResources>
        </configuration>
      </plugin>

      <plugin>
        <groupId>org.glassfish</groupId>
        <artifactId>maven-embedded-glassfish-plugin</artifactId>
        <configuration>
          <port>8080</port>
          <app>${project.build.directory}/${build.finalName}.war</app>
          <instanceRoot>${project.build.directory}/glassfish</instanceRoot>
          <contextRoot>${build.finalName}</contextRoot>
        </configuration>
      </plugin>
    </plugins>
  </build>

  <dependencies>
    <!--
    Jython version 2.5.1 and it's standard library
    are included in the project lib directory
    -->
    <dependency>
      <groupId>org.python</groupId>
      <artifactId>jython</artifactId>
      <version>2.5.1</version>
    </dependency>
    <dependency>
      <groupId>org.python</groupId>
      <artifactId>jython-lib</artifactId>
      <version>2.5.1</version>
    </dependency>
  </dependencies>
</project>

I couldn't find the latest version (2.5.1) of the Jython JAR in any Maven repository, so I have included it with the project source code in the lib directory. Also, I wanted the Jython instance to be completely self contained, so instead of referencing an install external to the project, I have JAR'ed up the standard library and included it in the project as lib/jython-lib-2.5.1.jar.

The project uses the embedded Glassfish v3 plugin to quickly start a basic configuration Glassfish server.

PyServlet, distributed with Jython is used to create Java Servlets using Jython source files. It is configured in the project's web.xml:

web.xml

<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xmlns="http://java.sun.com/xml/ns/javaee"
         xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
         http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="Message" version="2.5">

  <servlet>
    <servlet-name>PyServlet</servlet-name>
    <servlet-class>org.python.util.PyServlet</servlet-class>
    <load-on-startup>1</load-on-startup>
  </servlet>

  <servlet-mapping>
    <servlet-name>PyServlet</servlet-name>
    <url-pattern>*.py</url-pattern>
  </servlet-mapping>

  <welcome-file-list>
    <welcome-file>Calendar.py</welcome-file>
  </welcome-file-list>
</web-app>

Python code to create a Java servlet which uses the Python calendar library:

Calendar.py

import time
import calendar
from javax.servlet.http import HttpServlet

class Calendar (HttpServlet):
  def doGet(self, request, response):
    response.setContentType ("text/html")
    out = response.getWriter()

    out.println ("""
    <html>
      <head>
        <title>Calendar</title>
      </head>
      <body>
        <h1>Calendar</h1>
        <pre>%s</pre>
      </body>
    </html>
    """ % calendar.calendar(time.localtime()[0]))

Run the project with 'mvn clean install embedded-glassfish:run' and point your brower at http://localhost:8080/example/.

Source Code

Sunday, 28 February 2010

ColdFusion Head First Design Patterns: Observer

Continuing in this design patterns series taken from Head First Design Patterns, is a ColdFusion implementation of the Observer Pattern.

Interfaces

Subject.cfc

<cfinterface>
  <cffunction access="public" returntype="void" name="registerObserver">
    <cfargument required="true" type="Observer" name="o">
  </cffunction>

  <cffunction access="public" returntype="void" name="removeObserver">
    <cfargument required="true" type="Observer" name="o">
  </cffunction>
  
  <cffunction access="public" returntype="void" name="notifyObservers">
  </cffunction>
</cfinterface>

Observer.cfc

<cfinterface>
  <cffunction access="public" returntype="void" name="update">
    <cfargument required="true" type="numeric" name="temperature">
    <cfargument required="true" type="numeric" name="humidity">
    <cfargument required="true" type="numeric" name="pressure">        
  </cffunction>
</cfinterface>

DisplayElement.cfc

<cfinterface>
  <cffunction access="public" returntype="void" name="display">
  </cffunction>
</cfinterface>

Subject Implementation

WeatherData.cfc

<cfcomponent implements="Subject" output="false">

  <cffunction access="public" returntype="Subject" name="init">
    <cfset VARIABLES.observers = arrayNew(1)>
    
    <cfreturn THIS>
  </cffunction> 

  <cffunction access="public" returntype="void" name="registerObserver">
    <cfargument required="yes" type="Observer" name="o" />
    
    <cfset arrayAppend(VARIABLES.observers, ARGUMENTS.o)>
  </cffunction>

  <cffunction access="public" returntype="void" name="removeObserver">
    <cfargument required="yes" type="Observer" name="o" />
    
    <cfset arrayDelete(VARIABLES.observers, ARGUMENTS.o)>    
  </cffunction>

  <cffunction access="public" returntype="void" name="notifyObservers">
    <cfset var LOCAL = {}>
  
    <cfloop index="LOCAL.o" array="#VARIABLES.observers#">
      <cfset LOCAL.o.update(VARIABLES.temperature, VARIABLES.humidity, VARIABLES.pressure)>
    </cfloop>
  </cffunction>
  
  <cffunction access="public" returntype="void" name="measurementsChanged">
    <cfset notifyObservers()>
  </cffunction>
  
  <cffunction access="public" returntype="void" name="setMeasurements">
    <cfargument required="yes" type="numeric" name="temperature" />
    <cfargument required="yes" type="numeric" name="humidity" />
    <cfargument required="yes" type="numeric" name="pressure" />
    
    <cfset VARIABLES.temperature = ARGUMENTS.temperature>
    <cfset VARIABLES.humidity = ARGUMENTS.humidity>
    <cfset VARIABLES.pressure = ARGUMENTS.pressure>
    <cfset measurementsChanged()>
  </cffunction>
</cfcomponent>

Display Elements

CurrentConditionsDisplay.cfc

<cfcomponent implements="Observer, DisplayElement" output="true">

  <cffunction access="public" returntype="CurrentConditionsDisplay" name="init">
    <cfargument required="true" type="WeatherData" name="weatherData">
    
    <cfset VARIABLES.weatherData = ARGUMENTS.weatherData>
    <cfset VARIABLES.weatherData.registerObserver(THIS)>
    
    <cfreturn THIS>
  </cffunction>

  <cffunction access="public" returntype="void" name="update">
    <cfargument required="true" type="numeric" name="temperature">
    <cfargument required="true" type="numeric" name="humidity">
    <cfargument required="true" type="numeric" name="pressure">
    
    <cfset VARIABLES.temperature = ARGUMENTS.temperature>
    <cfset VARIABLES.humidity = ARGUMENTS.humidity>
    <cfset display()>
  </cffunction>

  <cffunction access="public" returntype="void" name="display">
    <cfoutput>
      Current conditions: #VARIABLES.temperature#F degrees and #VARIABLES.humidity#% humidity
      <br />
    </cfoutput>
  </cffunction>
</cfcomponent>

HeatIndexDisplay.cfc

<cfcomponent implements="Observer, DisplayElement" output="true">

  <cffunction access="public" returntype="HeatIndexDisplay" name="init">
    <cfargument required="true" type="WeatherData" name="weatherData">
    
    <cfset VARIABLES.weatherData = ARGUMENTS.weatherData>
    <cfset VARIABLES.weatherData.registerObserver(THIS)>
    
    <cfreturn THIS>
  </cffunction>

  <cffunction access="public" returntype="void" name="update">
    <cfargument required="true" type="numeric" name="temperature">
    <cfargument required="true" type="numeric" name="humidity">
    <cfargument required="true" type="numeric" name="pressure">
    
    <cfset VARIABLES.temperature = ARGUMENTS.temperature>
    <cfset VARIABLES.humidity = ARGUMENTS.humidity>
    <cfset VARIABLES.heatIndex = computeHeatIndex(VARIABLES.temperature, VARIABLES.humidity)>
    <cfset display()>
  </cffunction>

  <cffunction access="public" returntype="void" name="display">
    <cfoutput>
      Heat index is #VARIABLES.heatIndex#
      <br />
    </cfoutput>
  </cffunction>

  <cffunction access="private" returntype="numeric" name="computeHeatIndex">
    <cfargument required="true" type="numeric" name="t">
    <cfargument required="true" type="numeric" name="rh">

    <cfset var LOCAL = {}>
    <cfset LOCAL.index = ((16.923 + (0.185212 * t) + (5.37941 * rh) - (0.100254 * t * rh) +
            (0.00941695 * (t * t)) + (0.00728898 * (rh * rh)) +
            (0.000345372 * (t * t * rh)) - (0.000814971 * (t * rh * rh)) +
            (0.0000102102 * (t * t * rh * rh)) - (0.000038646 * (t * t * t)) + (0.0000291583 *  
            (rh * rh * rh)) + (0.00000142721 * (t * t * t * rh)) +
            (0.000000197483 * (t * rh * rh * rh)) - (0.0000000218429 * (t * t * t * rh * rh)) +     
            0.000000000843296 * (t * t * rh * rh * rh)) -
            (0.0000000000481975 * (t * t * t * rh * rh * rh)))>
  
    <cfreturn LOCAL.index>
  </cffunction> 
</cfcomponent>

Test Page

WeatherStation.cfm

<cfset weatherData = createObject("component", "WeatherData").init()>

<cfset currentDisplay = createObject("component", "CurrentConditionsDisplay").init(weatherData)>
<cfset heatDisplay = createObject("component", "HeatIndexDisplay").init(weatherData)>

<cfset weatherData.setMeasurements(80, 65, 30.4)>
<cfset weatherData.setMeasurements(82, 70, 29.2)>
<cfset weatherData.setMeasurements(78, 90, 29.2)>

Source Code

Saturday, 27 February 2010

Maven GWT WAR & Glassfish skeleton project

Another skeleton project implementing the same functionality as this previous post, a Google Web Toolkit front-end, with an embedded Derby database, accessed using the Java Persistence API; but this time running on an embedded Glassfish 3 instance and making use of EJB3.1 features.

Here is the projects POM:

pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">

  <modelVersion>4.0.0</modelVersion>
  <groupId>org.adrianwalker.maven.skeleton.war.gwt.glassfish</groupId>
  <artifactId>maven-war-gwt-glassfish-skeleton</artifactId>
  <packaging>war</packaging>
  <version>0.1.0</version>
  <name>Maven WAR-GWT-Glassfish Skeleton</name>

  <description>
    Skeleton project for creating a GWT WAR running on Glassfish, with a Derby
    database accessed through JPA.

    Usage: mvn clean install embedded-glassfish:run
  </description>

  <url>http://www.adrianwalker.org</url>

  <organization>
    <name>adrianwalker.org</name>
    <url>http://www.adrianwalker.org</url>
  </organization>

  <developers>
    <developer>
      <name>Adrian Walker</name>
      <email>ady.walker@gmail.com</email>
      <organization>adrianwalker.org</organization>
      <organizationUrl>http://www.adrianwalker.org</organizationUrl>
    </developer>
  </developers>

  <repositories>
    <repository>
      <id>java.net</id>
      <url>http://download.java.net/maven/2</url>
    </repository>

    <repository>
      <id>codehaus.org</id>
      <url>http://repository.codehaus.org</url>
    </repository>
  </repositories>

  <pluginRepositories>
    <pluginRepository>
      <id>java.net</id>
      <url>http://download.java.net/maven/glassfish</url>
    </pluginRepository>
  </pluginRepositories>

  <properties>
    <gwt.version>2.0.2</gwt.version>
  </properties>

  <build>
    <outputDirectory>war/WEB-INF/classes</outputDirectory>

    <finalName>message</finalName>

    <resources>
      <resource>
        <directory>${basedir}/src/main/resources</directory>
        <includes>
          <include>META-INF/persistence.xml</include>
        </includes>
      </resource>
    </resources>

    <plugins>
      <plugin>
        <artifactId>maven-clean-plugin</artifactId>
        <configuration>
          <filesets>
            <fileset>
              <directory>war</directory>
              <includes>
                <include>**/*</include>
              </includes>
            </fileset>
          </filesets>
        </configuration>
      </plugin>

      <plugin>
        <groupId>org.codehaus.mojo</groupId>
        <artifactId>gwt-maven-plugin</artifactId>
        <executions>
          <execution>
            <goals>
              <goal>compile</goal>
            </goals>
          </execution>
        </executions>
      </plugin>

      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <configuration>
          <source>1.6</source>
          <target>1.6</target>
        </configuration>
      </plugin>

      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-war-plugin</artifactId>
      </plugin>

      <plugin>
        <groupId>org.glassfish</groupId>
        <artifactId>maven-embedded-glassfish-plugin</artifactId>
        <configuration>
          <app>${project.build.directory}/${build.finalName}.war</app>
          <instanceRoot>${project.build.directory}/glassfish</instanceRoot>
          <contextRoot>${build.finalName}</contextRoot>
          <configFile>${basedir}/src/test/resources/config/domain.xml</configFile>
        </configuration>
      </plugin>
    </plugins>
  </build>

  <dependencies>
    <dependency>
      <groupId>org.glassfish.extras</groupId>
      <artifactId>glassfish-embedded-all</artifactId>
      <version>3.0</version>
      <scope>provided</scope>
    </dependency>

    <dependency>
      <groupId>com.google.gwt</groupId>
      <artifactId>gwt-servlet</artifactId>
      <version>${gwt.version}</version>
      <scope>runtime</scope>
    </dependency>

    <dependency>
      <groupId>com.google.gwt</groupId>
      <artifactId>gwt-user</artifactId>
      <version>${gwt.version}</version>
      <scope>provided</scope>
    </dependency>

    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>3.8.2</version>
      <scope>test</scope>
    </dependency>
  </dependencies>

  <reporting>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-checkstyle-plugin</artifactId>
      </plugin>

      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-javadoc-plugin</artifactId>
      </plugin>

      <plugin>
        <groupId>org.codehaus.mojo</groupId>
        <artifactId>cobertura-maven-plugin</artifactId>
      </plugin>

      <plugin>
        <groupId>org.codehaus.mojo</groupId>
        <artifactId>jxr-maven-plugin</artifactId>
      </plugin>

      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-pmd-plugin</artifactId>
      </plugin>

      <plugin>
        <groupId>org.codehaus.mojo</groupId>
        <artifactId>findbugs-maven-plugin</artifactId>
      </plugin>
    </plugins>
  </reporting>
</project>

The embedded Glassfish server is configured using a domain.xml taken from a fresh install of Glassfish 3, located \src\test\resources\config\domain.xml and referenced from the embedded Glassfish Maven plugin configuration element in the pom.xml

The default domain.xml has been amended to include jdbc-resource and jdbc-datasource entries for the web applications database. The domain.xml below shows the amendments, with the rest of the file removed for brevity:

domain.xml

<domain log-root="${com.sun.aas.instanceRoot}/logs" application-root="${com.sun.aas.instanceRoot}/applications" version="10.0">

  ...

  <resources>

    ...

    <jdbc-resource pool-name="MessagePool" jndi-name="jdbc/message" />

    ...

    <jdbc-connection-pool name="MessagePool" datasource-classname="org.apache.derby.jdbc.EmbeddedDataSource" res-type="javax.sql.DataSource">
      <property name="databaseName" value="target/database/message" />
      <property name="connectionAttributes" value=";create=true" />
    </jdbc-connection-pool>
  </resources>
  <servers>
    <server name="server" config-ref="server-config">

      ...

      <resource-ref ref="jdbc/message" />
    </server>
  </servers>

  ...

</domain>

The configured datasource is referenced in the projects persistence.xml, which uses EclipseLink to implement the JPA.

persistence.xml

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.0" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
  <persistence-unit name="messagePersistenceUnit" transaction-type="JTA">
    <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
    <jta-data-source>jdbc/message</jta-data-source>
    <class>org.adrianwalker.maven.skeleton.jpa.entity.MessageEntity</class>
    <exclude-unlisted-classes>true</exclude-unlisted-classes>
    <properties>
      <property name="eclipselink.ddl-generation" value="create-tables"/>
    </properties>
  </persistence-unit>
</persistence>

Run the project with 'mvn clean install embedded-glassfish:run' and point your brower at http://localhost:8080/message/.

Source Code