Quantcast
Channel: adrianwalker.org
Viewing all 65 articles
Browse latest View live

Codility.com Demo Test

$
0
0

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;
}

ColdFusion Builder Crack

$
0
0

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.

ColdFusion Head First Design Patterns: Decorator

$
0
0

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

map, foldr & foldl higher-order functions in Java

$
0
0

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.

GlassFish Security Review

$
0
0

GlassFish is Sun Microsystems open source application server. It is a competitor to Jboss AS and Apache Geronimo in the open source arena, and is my app server of choice.

Packt Publishing requested that I review one of their latest titles on the subject of GlassFish: GlassFish Security by Masoud Kalali, available to buy from Packt's web site.

I first took a look at GlassFish around 2007 whilst investigating EJB 3.0 and container managed persistence using JPA. Since then GlassFish has been my favourite platform for building web applications and web services, backed by EJB and JPA, sometimes taking advantage of GlassFish's load balancing and clustering features and excellent integration with other open source projects.

GlassFish Security has been a worth while read, adding to my awareness and knowledge of Java EE security best practices. I will definitely be applying the information presented in the book to current projects and future system design and development work.

GlassFish Security covers a very wide range of security topics, some of which will be applicable to web applications deployed on any JEE application server, whilst others are GlassFish and even host operating system specific.

The book doesn't just focus on programmatic security, making use of security APIs, annotations and XML configuration, but takes more of a complete systems view. OS and network security constraints, as well as enterprise wide system architecture considerations are explored.

The book is targeted at developers and system administrators, who have a sound footing working with JEE application servers, EJB development and have a working knowledge of Linux. To fully take advantage of this book you should know your way around the latest versions of GlassFish and probably NetBeans, have a Debian or Ubuntu install available, and have a keen interest in designing systems with security built in from the start.

The title of the book could quite easily have been GlassFish Security with OpenDS and OpenSSO, as they feature heavily in the later chapters. If your project has no need to interact with an LDAP server, or your organisation has no strategy for a single sign on solution or identity federation management, then these chapters may not be useful to you.

The book starts out from first principals with an overview of Java EE architecture and application modularisation and deployment. It's a slow start for an audience with experience of developing enterprise Java applications, but it establishes common terminology and is a good starting point to introduce fundamental security topics from.

The pace quickly picks up, security concepts such as authentication and authorisation, programmatic EJB security, XML configuration vs annotations, and roles, principals and groups are explained and demonstrated.

Covered next are the default security realms available to GlassFish and how to implementing custom realms and authentication methods.

A source code download for this and subsequent chapters is provided, although currently the source code for chapter two seems to be a duplicate of chapter three. Also, the book states that the build and deployment system used for the source is Maven, which it isn't. The source comes with standard NetBeans project files which use Ant for build and deployment.

Chapter three is probably the most useful for developers starting out with EJB development and web application security, and where the first real bit of programming starts. The chapter guides us through the end-to-end development and deployment of a JEE web application. The code uses a JPA persistence layer for accessing a MySQL database, a servlet containing some business logic and a simple JSP front end. Security constraints are are applied to the application, with authentication and authorisation done via interaction with a file security realm.

Some Linux administration knowledge is required for the next chapter concerned with locking down security on the host operating system and Java virtual machine. The examples given are intended for Debian based Linux distributions and consist of configuring user, file system, disk quota, network interface and port restrictions. JVM and GlassFish policy file configuration are explored, as well as a discussion on the advantages of enabling default auditing modules.

Naturally following on from the previous chapter, chapter five is concerned with configuring the GlassFish server itself, both from the command line and the admin interface. Restricting the IP addresses authorised to access network listeners and isolating applications using virtual servers are covered.

From chapter six onwards the book takes more of an architectural approach to security considerations.

This chapter describes to us the hierarchical nature of security data, and why it might not be best stored in a relational database, and instead in a directory service. OpenDS, an open source LDAP server is introduced, and its installation, administration, configuration and integration with our applications are explored.

Chapters seven, eight and nine, the remainder of the book, revolve around another open source project OpenSSO. OpenSSO is a single sign on solution which integrates seamlessly with GlassFish. Useful topics from chapter seven include using RESTful calls to the OpenSSO API to authenticate and authorise users.

Chapter eight introduces SSO Agents and filters configured in an applications web.xml to intercept calls and apply security measures. OpenSSO allows for very fine grained access controls which require no changes to application code and can be managed all from one place, very useful stuff that I'd like to take advantage of in future systems.

Finally, chapter nine builds on how to use OpenSSO in conjunction with a Web Services Agent to secure a simple SOAP web service deployed on GlassFish.

Overall this is a good book, covering a much wider range of security aspects than I expected. It gives you a great starting point on a breadth of topics but doesn't get to cover them in great depth.

As a developer I would have liked to see more advanced examples for chapters one to five, really getting to the nitty gritty of some real world examples. Maybe some advice on good practice when faced with tough design choices, how to avoid common pitfalls, security patterns and anti-patterns; the sort off stuff above and beyond what you might get from online GlassFish tutorials and Javadoc.

OpenSSO probably deserves a book in its own right, and although I have no immediate application for the information in the chapters that feature it, I'm glad I read them and now have a basic understanding to build on in the future. GlassFish Security benefits form these inclusions and they help it to be the comprehensive introduction to security that it is.

I was disappointed that source code printed in the book and available for download occasionally contained errors and wasn't supplied with Maven build scripts. These things slightly reduce the quality of an otherwise well written and well structured book.

I will definitely be implementing some of the information presented in this book in future Enterprise Java projects; I'll always consider the pros and cons of using a directory server before storing user credentials in relational tables; and GlassFish Security will be my first reference when considering system security design and implementation.

Downloads From Packt

Source

Here is some of the Packt example code repackaged as Maven projects.

Errata

Here are some errors I found in the printed code and xml configuration. Check the Packt support page for a complete listing.

  • Page 22 - missing closing XML tag </web-resource-name>.
  • Page 32 - missing double quotes and comma for @DeclareRoles annotation parameters.
  • Page 50 - missing single quotes around manager on second sql insert statement.
  • Page 85 - empty, unused method proccessRequest in Converter servlet.
  • Page 237 - stringEcho method annotation should be @WebMethod.

ColdFusion Is Dead (To Me)

$
0
0

So as from today I never have to program any ColdFusion again, it feels pretty good. ColdFusion just doesn't knock my frock off, it never did, and it probably never will.

This isn't one of those ColdFusion is dead, or ColdFusion sucks rants, those things aren't really my call, and besides, I can't be bothered to deal with ColdTard butthurt on my blog.

A Helmet

All I really know is that programming in CF made me feel a lot like this picture, and you secretly know it makes you feel like this too:

Using Ordnance Survey OpenData Street View Rasters With GeoServer

$
0
0

Getting the data

The Ordnance Survey OpenData can be downloaded or ordered on DVD from here. I thought I'd order the lot on DVD since its free and it would save my bandwidth and time burning gigs of data to disc.

The data comes on EcoDisc DVDs, packaged in cardboard sleeves:

For this post I'll only be using data on disc 1/6 and 3/6 on the OS Street View discs.

Getting GeoServer

GeoServer stable release can be downloaded here. I punted for the binary download format, because I want to run GeoServer on Linux. After unzipping and starting GeoServer, you should be able to browse to http://localhost:8080/geoserver/web/ and log in using the default username/password:

admin/geoserver

Using the Street View Rasters

First we need to decide what set of tiles we want to use. I only want maps for York and the surrounding area, so using the grid map:

I can see I only want to use the SE data.

Disc 3 of the OS Street View set contains the tif image files I want, located in the directory:

data/se
The files need to be coppied to a location in GeoServers data directory tree. I coppied the images to:
geoserver-2.0.2/data_dir/data/OpenData/StreetView/se

The image files aren't GeoTIFFs, so need geo-referencing data not contained in the image file. This information is held on the disc 1 of the OS Street View set, in the directory:

data/georeferencing files/TFW
We only need the files which start with se, and these need to be copied along side the images in the data directory:
geoserver-2.0.2/data_dir/data/OpenData/StreetView/se
We also need to make sure that the file extension of the tfw is lower cased, using a Linux shell:
rename .TFW .tfw *.TFW
We should now have a directory containing .tif image files and .tfwworld files. Each of the tif/tfw pairs needs a file containing projection information before it can be loaded into GeoServer. The files aren't supplied with the raster data, but they are simple to create. The name of the file must match the name of the tif/tfw, and each of the files must contain the same data:

PROJCS["OSGB 1936 / British National Grid", GEOGCS["OSGB 1936", DATUM["OSGB_1936", SPHEROID["Airy 1830",6377563.396,299.3249646, AUTHORITY["EPSG","7001"]], AUTHORITY["EPSG","6277"]], PRIMEM["Greenwich",0, AUTHORITY["EPSG","8901"]], UNIT["degree",0.01745329251994328, AUTHORITY["EPSG","9122"]], AUTHORITY["EPSG","4277"]], UNIT["metre",1, AUTHORITY["EPSG","9001"]], PROJECTION["Transverse_Mercator"], PARAMETER["latitude_of_origin",49], PARAMETER["central_meridian",-2], PARAMETER["scale_factor",0.9996012717], PARAMETER["false_easting",400000], PARAMETER["false_northing",-100000], AUTHORITY["EPSG","27700"], AXIS["Easting",EAST], AXIS["Northing",NORTH]]

You can create the files by hand, or running the following Python script in the directory containing the .tif files will do it for you:

import glob

content = 'PROJCS["OSGB 1936 / British National Grid", GEOGCS["OSGB 1936", DATUM["OSGB_1936", SPHEROID["Airy 1830",6377563.396,299.3249646, AUTHORITY["EPSG","7001"]], AUTHORITY["EPSG","6277"]], PRIMEM["Greenwich",0, AUTHORITY["EPSG","8901"]], UNIT["degree",0.01745329251994328, AUTHORITY["EPSG","9122"]], AUTHORITY["EPSG","4277"]], UNIT["metre",1, AUTHORITY["EPSG","9001"]], PROJECTION["Transverse_Mercator"], PARAMETER["latitude_of_origin",49], PARAMETER["central_meridian",-2], PARAMETER["scale_factor",0.9996012717], PARAMETER["false_easting",400000], PARAMETER["false_northing",-100000], AUTHORITY["EPSG","27700"], AXIS["Easting",EAST], AXIS["Northing",NORTH]]'

tifs = glob.glob('*.tif')

for tif in tifs:
  prj = tif.split('.')[0] + '.prj'
  file = open(prj,'w')
  file.writelines(content)
  file.close()


If you have a data directory with files that look a bit like this, then you're ready to load them into GeoServer:

  1. Load GeoServer up in a browser http://localhost:8080/geoserver/web/ and login. Click the 'Workspaces' link in the 'Data' section of the left hand navigation bar. Now click the 'Add new workspace' link.

  2. Name the workspace OpenData and give it the URI https://www.ordnancesurvey.co.uk/, and click save.

  3. Click the 'Stores' link in the 'Data' section of the left hand navigation bar. Now click the 'Add new Store' link. Under the 'Raster Data Sources' heading, click the 'ImageMosaic' link.

  4. Select the OpenData workspace, name the data source OS Street View SE and point the URL connection parameter to the data directory:
    file:data/OpenData/StreetView/se
    and then click save.

  5. You should be forwarded to the 'New Layer chooser page', click the 'Publish' link next to the 'se' layer in the table.

  6. About halfway down the page there should be inputs for 'Native SRS' and 'Declared SRS', make sure they both contain:
    EPSG:27700
    and click the 'Compute from data' and 'Compute from native bounds' links.

  7. Finally click save.

If all went well you should be able to use GeoServers 'Layer Preview' built in OpenLayers client to view the map:

Source Code

Maven, Spring, Hibernate & JPA skeleton project

$
0
0

Today I read that Spring-JPA is the 'dream team' for POJO development. So I thought I'd see what all the hype is about. Here is a skeleton Maven project using Spring, JPA implemented with Hibernate and backed with an embedded Derby database.

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/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>org.adrianwalker.maven.skeleton.spring.jpa</groupId><artifactId>maven-spring-jpa-skeleton</artifactId><version>0.1.0</version><name>Maven Spring JPA Skeleton</name><description>
    Skeleton project for using Spring, Hibernate and Derby 
    database accessed through JPA.
 
    Usage: mvn clean install
  </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>java.net - legacy</id><url>http://download.java.net/maven/1</url><layout>legacy</layout></repository></repositories><build><plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><configuration><source>1.6</source><target>1.6</target></configuration></plugin></plugins></build><dependencies><dependency><groupId>javax.persistence</groupId><artifactId>persistence-api</artifactId><version>1.0</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring</artifactId><version>2.5.6</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-test</artifactId><version>2.5.6</version></dependency><dependency><groupId>org.apache.derby</groupId><artifactId>derby</artifactId><version>10.6.1.0</version></dependency><dependency><groupId>org.hibernate</groupId><artifactId>hibernate</artifactId><version>3.2.1.ga</version></dependency><dependency><groupId>org.hibernate</groupId><artifactId>hibernate-entitymanager</artifactId><version>3.2.1.ga</version></dependency><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.4</version><scope>test</scope></dependency></dependencies></project>

Spring Configuration

context.xml

<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns:tx="http://www.springframework.org/schema/tx"
  xsi:schemaLocation="
    http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
    http://www.springframework.org/schema/tx
    http://www.springframework.org/schema/tx/spring-tx-2.0.xsd"><bean id="dataSource"
    class="org.springframework.jdbc.datasource.DriverManagerDataSource"><property name="driverClassName" value="org.apache.derby.jdbc.EmbeddedDriver" /><property name="url"
      value="jdbc:derby:target/database/message;create=true" /><property name="username" value="app" /><property name="password" value="app" /></bean><bean id="entityManagerFactory"
    class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"><property name="dataSource" ref="dataSource"></property><property name="jpaVendorAdapter"><bean
        class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"><property name="databasePlatform" value="org.hibernate.dialect.DerbyDialect" /></bean></property><property name="jpaProperties"><props><prop key="hibernate.hbm2ddl.auto">create-drop</prop></props></property></bean><bean name="jpaMessageDao"
    class="org.adrianwalker.maven.skeleton.spring.jpa.JpaMessageDao"><property name="entityManagerFactory" ref="entityManagerFactory" /></bean><bean name="messageJpaController"
    class="org.adrianwalker.maven.skeleton.spring.jpa.MessageJpaController"></bean><bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager"><property name="entityManagerFactory" ref="entityManagerFactory" /><property name="dataSource" ref="dataSource" /></bean></beans>

Persistence Configuration

persistence.xml

<?xml version="1.0" encoding="UTF-8"?><persistence version="1.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_1_0.xsd"><persistence-unit name="messagePersistenceUnit" transaction-type="RESOURCE_LOCAL"><class>org.adrianwalker.maven.skeleton.spring.jpa.MessageEntity</class></persistence-unit></persistence>

JPA Entity

A very simple entity which has an id and some message text.

MessageEntity.java

package org.adrianwalker.maven.skeleton.spring.jpa;

import java.io.Serializable;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;

@Entity
@NamedQueries({
  @NamedQuery(
    name="MessageEntity.find",
    query = "SELECT m FROM MessageEntity m"),
  @NamedQuery(
      name = "MessageEntity.count", 
      query = "SELECT COUNT(m) FROM MessageEntity m")
})
public class MessageEntity implements Serializable {

  private static final long serialVersionUID = 1L;
 
  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  private long id;

  private String text;

  public MessageEntity() {
  }

  public MessageEntity(final String text) {
    this.text = text;
  }

  public long getId() {
    return id;
  }

  public void setId(final long id) {
    this.id = id;
  }

  public String getText() {
    return text;
  }

  public void setText(final String text) {
    this.text = text;
  }

  @Override
  public String toString() {
    return "MessageEntity [id=" + id + ", text=" + text + "]";
  }
}

Spring DAO vs JPA Controller

Spring provides a JpaDaoSupport class for extension, but this couples your DAO objects to the Spring framework, and you have to do some pretty ugly stuff to execute your named queries:

JpaMessageDao.java

package org.adrianwalker.maven.skeleton.spring.jpa;

import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceException;
import javax.persistence.Query;
import org.springframework.orm.jpa.JpaCallback;
import org.springframework.orm.jpa.support.JpaDaoSupport;

public final class JpaMessageDao extends JpaDaoSupport {

  public long count() {
    return (Long) getJpaTemplate().execute(new JpaCallback() {

      public Object doInJpa(final EntityManager em) throws PersistenceException {
        Query q = em.createNamedQuery("MessageEntity.count");
        return q.getSingleResult();
      }
    });
  }

  public void create(final MessageEntity message) {
    getJpaTemplate().persist(message);
  }

  public MessageEntity read(final long id) {
    return getJpaTemplate().find(MessageEntity.class, id);
  }

  @SuppressWarnings("unchecked")
  public List<MessageEntity> read(final int firstResult, final int maxResults) {
    return (List<MessageEntity>) getJpaTemplate().execute(new JpaCallback() {

      public Object doInJpa(final EntityManager em) throws PersistenceException {
        Query q = em.createNamedQuery("MessageEntity.find");
        q.setFirstResult(firstResult);
        q.setMaxResults(maxResults);
        return q.getResultList();
      }
    });
  }

  public MessageEntity update(final MessageEntity message) {
    return getJpaTemplate().merge(message);
  }

  public void delete(final MessageEntity message) {
    getJpaTemplate().remove(message);
  }
}

A much neater alternative is to use a JPA style controller which gives you direct access to the EntityManager. The @PersistenceContext annotation is understood by Spring and your entity manager is injected into the controller class.

MessageJpaController.java

package org.adrianwalker.maven.skeleton.spring.jpa;

import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.Query;
import javax.persistence.PersistenceContext;

public class MessageJpaController {

  @PersistenceContext(unitName = "messagePersistenceUnit")
  private EntityManager em;

  public long count() {
    Query q = em.createNamedQuery("MessageEntity.count");
    return (Long) q.getSingleResult();
  }

  public void create(MessageEntity messageEntity) {
    em.persist(messageEntity);
  }

  public MessageEntity read(final long id) {
    return em.find(MessageEntity.class, id);
  }

  @SuppressWarnings("unchecked")
  public List<MessageEntity> read(int firstResult, int maxResults) {
    Query q = em.createNamedQuery("MessageEntity.find");
    q.setFirstResult(firstResult);
    q.setMaxResults(maxResults);
    return q.getResultList();
  }

  public MessageEntity update(MessageEntity messageEntity) {
    return em.merge(messageEntity);
  }

  public void delete(final MessageEntity message) {
    em.remove(message);
  }
}

Usage & Tests

And finally here are some JUnit 4 tests for both the DAO and Controller.

MessageTest.java

package org.adrianwalker.maven.skeleton.spring.jpa;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;

import java.util.List;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.transaction.TransactionConfiguration;
import org.springframework.transaction.annotation.Transactional;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "classpath:context.xml" })
@TransactionConfiguration(transactionManager = "transactionManager", defaultRollback = false)
@Transactional
public final class MessageTest {

  @Autowired
  private MessageJpaController messageJpaController;
  
  @Autowired
  private JpaMessageDao jpaMessageDao;
   
  @Test
  public void daoCreate() throws Exception {
    
    for (int i = 1; i <= 10; i++) {
      jpaMessageDao.create(new MessageEntity(String.format("Message %s", i)));
    }

    assertEquals(10, jpaMessageDao.count());
  }

  @Test
  public void daoRead() throws Exception {
    List<MessageEntity> messages = jpaMessageDao.read(1, 2);
    assertNotNull(messages);
    assertEquals(2, messages.size());
  }  
  
  @Test
  public void daoUpdate() throws Exception {
    
    MessageEntity message = jpaMessageDao.read(1);

    assertNotNull(message);
    assertEquals("Message 1", message.getText());

    message.setText("Message X");
    message = jpaMessageDao.update(message);

    message = jpaMessageDao.read(1);
    assertEquals("Message X", message.getText());
  }

  @Test
  public void daoDelete() throws Exception {
    long beforeCount = jpaMessageDao.count();
    assertTrue(beforeCount == 10);

    for (int i = 1; i <= 10; i++) {
      MessageEntity message = jpaMessageDao.read(i);
      jpaMessageDao.delete(message);
    }

    long afterCount = jpaMessageDao.count();
    assertTrue(afterCount == 0);
  }
  
  @Test
  public void controllerCreate() throws Exception {    

    for (int i = 11; i <= 20; i++) {
      messageJpaController.create(new MessageEntity(String.format("Message %s", i)));
    }

    assertEquals(10, messageJpaController.count());
  }

  @Test
  public void controllerRead() throws Exception {
    List<MessageEntity> messages = messageJpaController.read(1, 2);
    
    assertNotNull(messages);
    assertEquals(2, messages.size());
  }    
  
  @Test
  public void controllerUpdate() throws Exception {
    MessageEntity message = messageJpaController.read(11);

    assertNotNull(message);
    assertEquals("Message 11", message.getText());

    message.setText("Message X");
    message = messageJpaController.update(message);

    message = messageJpaController.read(11);
    assertEquals("Message X", message.getText());
  }

  @Test
  public void controllerDelete() throws Exception {
    long beforeCount = messageJpaController.count();
    assertTrue(beforeCount == 10);

    for (int i = 11; i <= 20; i++) {
      MessageEntity message = messageJpaController.read(i);
      messageJpaController.delete(message);
    }

    long afterCount = messageJpaController.count();
    assertTrue(afterCount == 0);
  }  
}

Don't Believe The Hype

So basically, for me anyway, using Spring in conjunction with JPA gives you nothing above and beyond using JPA directly. By the the time you decide not to bother with JpaDaoSupport, all that has been achieved is moving connection properties form persistence.xml to context.xml, which just creates more Spring configuration XML clutter.

Spring recognising the @PersistenceContext is a nice touch for testing, but using constructor/setter injection to inject an EntityManager into a JPA controller class is no big deal if you don't want to use spring.

Source Code


jchannel - a Java imageboard

$
0
0

I love the chans, so I though I'd build my own. jchannel is simple, linearly-directed, forced anonymous imageboard, implemented using enterprise Java, EJB 3.1, JPA/EclipseLink, with a Google Web Toolkit front end, designed to run on GlassFish application server.

Features

  • GWT AJAX powered front end
  • JPA RDBMS agnostic back end
  • Rich text editor message input
  • Role based administration & moderation
  • Catgegory/Topic administration
  • Post reporting & IP ban management

Screen Shots

(click to enlarge)
Auto generated contents home page

Thread view with rich text editor input

Topic administration view

Demo

A demo of jchannel with just one topic (/b/) is running at http://jchannel.org

Source Code

The latest source code can be downloaded from Google Code using svn:

svn checkout http://jchannel.googlecode.com/svn/trunk/ jchannel-read-only

or downloaded here:

Usage

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

Running the project with all the tests will create an embedded Derby database to test against, run an embedded GlassFish server, create some default topics and a default admin user.

To log into the admin interface go to http://127.0.0.1:8080/jchannel/#login

and use the login credentials:

username: admin
password: adminadmin

Update 8/12/10

The http://jchannel.org demo now has a bunch of 4chan style topics.

Maven Dependency Finder

$
0
0

My friend Mark had an idea for a utility to search a list of your favourite repositories for a given dependency. So I thought I'd code up a version.

Maven Dependency Finder is a command line utility that takes a list of repositories and a dependency group id,artifact id and version, and returns the repositories which contain the JAR you want.

The utility reads a list of repositories from a file, and uses multiple threads to check for the required JARs, outputting the URLs where the JARs are hosted.

MavenDependencyFinder.java

package org.adrianwalker.maven;

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

public final class MavenDependencyFinder {

  private static final int EXIT_FAILURE = -1;
  private static final int EXIT_SUCCESS = 0;
  private static final String FLAG_START = "-";
  private static final String GROUP_FLAG = FLAG_START + "g";
  private static final String ARTIFACT_FLAG = FLAG_START + "a";
  private static final String VERSION_FLAG = FLAG_START + "v";
  private static final String MAX_THREADS_FLAG = FLAG_START + "t";
  private static final String REPOSITORY_FILE_FLAG = FLAG_START + "r";
  private static final String HELP_FLAG = FLAG_START + "h";
  private static final String DEFAULT_VERSION = "";
  private static final List<String> DEFAULT_REPOSITORIES = Arrays.asList(new String[]{
            "http://mirrors.ibiblio.org/pub/mirrors/maven2/"
          });
  private static final int DEFAULT_MAX_THREADS = 2;
  private static final String ARTIFACT_VERSION_SEPERATOR = "-";
  private static final String EMPTY_STRING = "";
  private static final String HTTP_METHOD = "GET";
  private static final String JAR_FILE_EXTENSION = ".jar";
  private static final String PACKAGE_SEPERATOR = "\\.";
  private static final int TIMEOUT_MILLISECONDS = 10000;
  private static final String URL_SEPERATOR = "/";

  public static void main(final String[] args) {


    Map<String, String> parameters = readParameters(args);

    if (parameters.isEmpty() || parameters.containsKey(HELP_FLAG)) {
      printHelp();
      System.exit(EXIT_SUCCESS);
    }

    if (!parameters.containsKey(GROUP_FLAG)) {
      printError("Required parameter '-g' missing");
      System.exit(EXIT_FAILURE);
    }

    if (!parameters.containsKey(ARTIFACT_FLAG)) {
      printError("Required parameter '-a' missing");
      System.exit(EXIT_FAILURE);
    }

    String groupId = parameters.get(GROUP_FLAG);
    String artifactId = parameters.get(ARTIFACT_FLAG);

    String version = DEFAULT_VERSION;
    if (parameters.containsKey(VERSION_FLAG)) {
      version = parameters.get(VERSION_FLAG);
    }

    int maxThreads = DEFAULT_MAX_THREADS;
    if (parameters.containsKey(MAX_THREADS_FLAG)) {
      maxThreads = Integer.parseInt(parameters.get(MAX_THREADS_FLAG));
    }

    List<String> repositories = DEFAULT_REPOSITORIES;
    if (parameters.containsKey(REPOSITORY_FILE_FLAG)) {
      String fileName = parameters.get(REPOSITORY_FILE_FLAG);
      try {
        repositories = readRepositoriesFile(fileName);
      } catch (Throwable t) {
        printError(String.format("Error reading file '%s'", fileName));
        System.exit(EXIT_FAILURE);
      }
    }

    findDependency(maxThreads, repositories, groupId, artifactId, version);

    System.exit(EXIT_SUCCESS);
  }

  private MavenDependencyFinder() {
  }

  private static void findDependency(final int maxThreads, final List<String> repositories, final String groupId, final String artifactId, final String version) {

    ExecutorService threadPool = Executors.newFixedThreadPool(maxThreads);
    Map<String, Future<Boolean>> results = new HashMap<String, Future<Boolean>>();
    for (String repository : repositories) {
      Future<Boolean> isHostingDependancy = threadPool.submit(new CallableUrlFinder(repository, groupId, artifactId, version));
      results.put(repository, isHostingDependancy);
    }
    Set<String> responses = new HashSet<String>();
    while (results.size() > responses.size()) {

      for(Entry<String, Future<Boolean>> entry : results.entrySet()) {
          
        String repository = entry.getKey();
        Future<Boolean> isHostingDependancy = entry.getValue();
          
        if (!responses.contains(repository) && isHostingDependancy.isDone()) {
          Boolean found;
          try {
            found = isHostingDependancy.get();
            responses.add(repository);
          } catch (Throwable t) {
            found = false;
          }
          if (found) {
            System.out.println(repository);
          }
        }
      }
      Thread.yield();
    }
    threadPool.shutdown();
  }

  private static Map<String, String> readParameters(final String[] args) {
    int argsCount = args.length;

    if (argsCount == 1 && args[0].equals(HELP_FLAG)) {
      printHelp();
      System.exit(EXIT_SUCCESS);
    }else if (argsCount % 2 == 1) {
      printError("Invalid number of arguments");
      System.exit(EXIT_FAILURE);
    }

    Map<String, String> parameters = new HashMap<String, String>();
    for (int i = 0; i < argsCount; i = i + 2) {

      String flag = args[i];

      if (!flag.startsWith(FLAG_START)) {
        printError(String.format("Invalid flag '%s'", flag));
        System.exit(EXIT_FAILURE);
      }

      String value = args[i + 1];
      if (value.startsWith(FLAG_START)) {
        printError(String.format("Invalid value '%s' for flag '%s'", value, flag));
        System.exit(EXIT_FAILURE);
      }


      parameters.put(flag, value);
    }

    return parameters;
  }

  private static List readRepositoriesFile(final String fileName) throws IOException {
    List<String> repositories = new ArrayList<String>();
    BufferedReader reader = null;
    try {
      reader = new BufferedReader(new FileReader(fileName));
      String line;
      while ((line = reader.readLine()) != null) {
        repositories.add(line.trim());
      }
    } finally {
      if (null != reader) {
        reader.close();
      }
    }
    return repositories;
  }

  private static void printHelp() {
    String help = "Usage: mdf -g <group id> -a <artifact id> [-v <version>] [-r <filename>] [-t <threads>] [-h]\n\n"
            + "  -g\tDependency group id\n"
            + "  -a\tDependency artifact id\n"
            + "  -v\tDependency version\n"
            + "  -r\tRepository file\n"
            + "  -t\tMaximum threads\n"
            + "  -h\tHelp";
    System.out.println(help);
  }

  private static void printError(final String message) {
    System.out.println(message);
  }

  private static final class CallableUrlFinder implements Callable<Boolean> {

    private final String repository;
    private final String groupId;
    private final String artifactId;
    private final String version;

    public CallableUrlFinder(final String repository, final String groupId, final String artifactId, final String version) {
      this.repository = repository;
      this.groupId = groupId;
      this.artifactId = artifactId;
      this.version = version;
    }

    @Override
    public Boolean call() throws Exception {
      return isHostingDependency(repository, groupId, artifactId, version);
    }

    private boolean isHostingDependency(final String repository, final String groupId, final String artifactId, final String version) {

      String dependencyUrl = gavToUrl(repository, groupId, artifactId, version);

      HttpURLConnection connection = null;
      try {
        URL url = new URL(dependencyUrl);
        connection = (HttpURLConnection) url.openConnection();
        connection.setRequestMethod(HTTP_METHOD);
        connection.setReadTimeout(TIMEOUT_MILLISECONDS);
        connection.connect();
        return connection.getResponseCode() == HttpURLConnection.HTTP_OK;
      } catch (Throwable t) {
        return false;
      } finally {
        if (null != connection) {
          connection.disconnect();
        }
      }
    }

    private String gavToUrl(final String repository, final String groupId, final String artifactId, final String version) {
      /*
       * Format:
       *
       * http://mirrors.ibiblio.org/pub/mirrors/maven2/log4j/log4j/1.2.13/log4j-1.2.13.jar
       *
       */

      StringBuilder builder = new StringBuilder();
      builder.append(repository) //
              .append(repository.endsWith(URL_SEPERATOR) ? EMPTY_STRING : URL_SEPERATOR) //
              .append(groupId.replaceAll(PACKAGE_SEPERATOR, URL_SEPERATOR)) //
              .append(URL_SEPERATOR).append(artifactId);
      if (version != null && !version.isEmpty()) {
        builder.append(URL_SEPERATOR) //
                .append(version) //
                .append(URL_SEPERATOR) //
                .append(artifactId) //
                .append(ARTIFACT_VERSION_SEPERATOR) //
                .append(version).append(JAR_FILE_EXTENSION);
      }

      return builder.toString();
    }
  }
}


Build the project with:

mvn clean install
to build a directory and zip assembly containing the executable JAR file, a batch file and shell script to run the utility from the command line.

Running the command with the -h flag shows the help for the utility:

Usage: mdf -g <group id> -a <artifact id> [-v <version>] [-r <filename>] [-t <threads>] [-h]

  -g    Dependency group id
  -a    Dependency artifact id
  -v    Dependency version
  -r    Repository file
  -t    Maximum threads
  -h    Help

To run the utility with a list of repositories and search for log4j:

mdf -g log4j -a log4j -r repositories.txt

outputs:

http://mirrors.ibiblio.org/pub/mirrors/maven2/
http://repository.jboss.org/maven2/

where the repositories list input file contains:

repositories.txt

http://mirrors.ibiblio.org/pub/mirrors/maven2/
http://repository.jboss.org/maven2/
http://download.java.net/maven/2
http://repository.codehaus.org

Source Code

GWT File Upload With Event-Based Progress Bar

$
0
0
File upload with progress bar, and paged file downloads.

Adapting the event-based code from Chapter 9 of the excellent book Google Web Toolkit Applications, I coded up a file upload application with a progress bar, which is updated using server pseudo-push events.

The application also provides a download servlet, and layout using GWT UiBinder.

Full source for the webapp is available at the bottom of the page. Not all of the code is listed below, but some of the most important classes are explained here.

The UploadProgressService interface defines the server side functions available, the most important being getEvents(). This function will be called recursively on the client side to simulate a main loop.

UploadProgressService.java

package org.adrianwalker.gwt.uploadprogress.client;

import java.util.List;

import com.google.gwt.user.client.rpc.RemoteService;
import com.google.gwt.user.client.rpc.RemoteServiceRelativePath;
import org.adrianwalker.gwt.uploadprogress.common.dto.FileDto;
import org.adrianwalker.gwt.uploadprogress.common.event.Event;

@RemoteServiceRelativePath("uploadprogress")
public interface UploadProgressService extends RemoteService {

  void initialise();

  int countFiles();

  List<FileDto> readFiles(int page, int pageSize);

  List<Event> getEvents();
}

The only event in the application is UploadProgressChangeEvent. It is concerned with reporting changes in file upload percentage.

UploadProgressChangeEvent.java

package org.adrianwalker.gwt.uploadprogress.common.event;

import java.io.Serializable;

public final class UploadProgressChangeEvent implements Event, Serializable {

  private String filename;
  private Integer percentage;

  public UploadProgressChangeEvent() {
  }

  public String getFilename() {
    return filename;
  }

  public void setFilename(final String filename) {
    this.filename = filename;
  }

  public Integer getPercentage() {
    return percentage;
  }

  public void setPercentage(final Integer percentage) {
    this.percentage = percentage;
  }

  @Override
  public String toString() {
    return filename + " - " + percentage;
  }
}

The UploadProgressServlet implements the methods defined by UploadProgressService. The getEvents() method returns the events stored in the servlets session scope. If the event list is empty, the thread waits for 30 seconds. If the list contained events, they are retuned to the client, and then the event list is cleared.

UploadProgressServlet.java

package org.adrianwalker.gwt.uploadprogress.server;

import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpSession;
import com.google.gwt.user.server.rpc.RemoteServiceServlet;
import java.io.File;
import java.io.FileFilter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
import java.util.Properties;
import org.adrianwalker.gwt.uploadprogress.client.UploadProgressService;
import org.adrianwalker.gwt.uploadprogress.common.dto.FileDto;
import org.adrianwalker.gwt.uploadprogress.common.event.Event;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public final class UploadProgressServlet extends RemoteServiceServlet implements UploadProgressService {

  private static final int EVENT_WAIT = 30 * 1000;
  private static final String PROPERTIES_FILE = "WEB-INF/classes/uploadprogress.properties";
  private static final Logger LOGGER = LoggerFactory.getLogger(UploadProgressServlet.class);
  private String uploadDirectory;

  @Override
  public void init() throws ServletException {
    Properties properties = new Properties();
    try {
      properties.load(getServletContext().getResourceAsStream(PROPERTIES_FILE));
    } catch (IOException ioe) {
      throw new ServletException(ioe);
    }

    uploadDirectory = properties.getProperty("upload.directory", "target");
  }

  @Override
  public void initialise() {
    getThreadLocalRequest().getSession(true);
  }

  @Override
  public List<FileDto> readFiles(final int page, final int pageSize) {

    File[] listFiles = readFiles(this.uploadDirectory);
    sortFiles(listFiles);

    int firstFile = pageSize * (page - 1);
    int lastFile = firstFile + pageSize;

    int fileCount = listFiles.length;
    if (fileCount < lastFile) {
      lastFile = fileCount;
    }

    if (firstFile < fileCount) {
      List<FileDto> files = new ArrayList<FileDto>();

      for (int i = firstFile; i < lastFile; i++) {

        File file = listFiles[i];
        FileDto fileDto = new FileDto();
        fileDto.setFilename(file.getName());
        fileDto.setDateUploaded(new Date(file.lastModified()));
        files.add(fileDto);
      }
      return files;
    } else {
      return Collections.EMPTY_LIST;
    }
  }

  @Override
  public List<Event> getEvents() {

    HttpSession session = getThreadLocalRequest().getSession();
    UploadProgress uploadProgress = UploadProgress.getUploadProgress(session);

    List<Event> events = null;
    if (null != uploadProgress) {
      if (uploadProgress.isEmpty()) {
        try {
          synchronized (uploadProgress) {
            LOGGER.debug("waiting...");
            uploadProgress.wait(EVENT_WAIT);
          }
        } catch (final InterruptedException ie) {
          LOGGER.debug("interrupted...");
        }
      }

      synchronized (uploadProgress) {
        events = uploadProgress.getEvents();
        uploadProgress.clear();
      }
    }

    return events;
  }

  @Override
  public int countFiles() {
    return readFiles(this.uploadDirectory).length;
  }

  private File[] readFiles(final String directory) {
    File uploadDirectory = new File(directory);
    return uploadDirectory.listFiles(new FileFilter() {

      @Override
      public boolean accept(final File file) {
        return null == file ? false : file.isFile();
      }
    });
  }

  private void sortFiles(final File[] listFiles) {
    Arrays.sort(listFiles, new Comparator<File>() {

      @Override
      public int compare(final File f1, final File f2) {
        return Long.valueOf(f2.lastModified()).compareTo(f1.lastModified());
      }
    });
  }
}

UploadProgress stores the list of events, and has a factory method for creating/retrieving an instance of its self in the session.

UploadProgress.java

package org.adrianwalker.gwt.uploadprogress.server;

import java.util.ArrayList;
import java.util.List;
import javax.servlet.http.HttpSession;
import org.adrianwalker.gwt.uploadprogress.common.event.Event;

public final class UploadProgress {

  private static final String SESSION_KEY = "uploadProgress";
  private List<Event> events = new ArrayList<Event>();

  private UploadProgress() {
  }

  public List<Event> getEvents() {

    return events;
  }

  public void add(final Event event) {
    events.add(event);
  }

  public void clear() {
    events = new ArrayList<Event>();
  }

  public boolean isEmpty() {
    return events.isEmpty();
  }

  public static UploadProgress getUploadProgress(final HttpSession session) {
    Object attribute = session.getAttribute(SESSION_KEY);
    if (null == attribute) {
      attribute = new UploadProgress();
      session.setAttribute(SESSION_KEY, attribute);
    }

    return null == attribute ? null : (UploadProgress) attribute;
  }
}

The UploadServlet uses Apache Commons FileUpload library to parse the multipart post request and stream the file to disk. An UploadProgressListener is added to a custom input stream, UploadProgressInputStream, which together report the status of the upload back to the client.

UploadServlet.java

package org.adrianwalker.gwt.uploadprogress.server;

import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.File;
import java.io.FileOutputStream;
import java.util.Properties;
import javax.servlet.http.HttpServlet;

import org.apache.commons.fileupload.FileItemFactory;
import org.apache.commons.fileupload.FileItemIterator;
import org.apache.commons.fileupload.FileItemStream;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.commons.fileupload.util.Streams;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public final class UploadServlet extends HttpServlet {

  private static final String PROPERTIES_FILE = "WEB-INF/classes/uploadprogress.properties";
  private static final Logger LOGGER = LoggerFactory.getLogger(UploadServlet.class);
  private static final String FILE_SEPERATOR = System.getProperty("file.separator");
  private String uploadDirectory;

  @Override
  public void init() throws ServletException {
    Properties properties = new Properties();
    try {
      properties.load(getServletContext().getResourceAsStream(PROPERTIES_FILE));
    } catch (IOException ioe) {
      throw new ServletException(ioe);
    }

    uploadDirectory = properties.getProperty("upload.directory", "target");
  }

  @Override
  protected void doPost(final HttpServletRequest request, final HttpServletResponse response) throws ServletException, IOException {
    try {
      uploadFile(request);
    } catch (FileUploadException fue) {
      throw new ServletException(fue);
    }
  }

  private void uploadFile(final HttpServletRequest request) throws FileUploadException, IOException {

    if (!ServletFileUpload.isMultipartContent(request)) {
      throw new FileUploadException("error multipart request not found");
    }

    FileItemFactory fileItemFactory = new DiskFileItemFactory();
    ServletFileUpload servletFileUpload = new ServletFileUpload(fileItemFactory);

    FileItemIterator fileItemIterator = servletFileUpload.getItemIterator(request);

    HttpSession session = request.getSession();
    UploadProgress uploadProgress = UploadProgress.getUploadProgress(session);

    while (fileItemIterator.hasNext()) {
      FileItemStream fileItemStream = fileItemIterator.next();

      String filePath = fileItemStream.getName();
      String fileName = filePath.substring(filePath.lastIndexOf(FILE_SEPERATOR) + 1);

      UploadProgressListener uploadProgressListener = new UploadProgressListener(fileName, uploadProgress);

      UploadProgressInputStream inputStream = new UploadProgressInputStream(fileItemStream.openStream(), request.getContentLength());
      inputStream.addListener(uploadProgressListener);

      File file = new File(uploadDirectory, fileName);

      Streams.copy(inputStream, new FileOutputStream(file), true);

      LOGGER.info(String.format("uploaded file %s", file.getAbsolutePath()));
    }
  }
}

UploadProgressInputStream is a FilterInputStream which reports the number of bytes read to attached listeners.

UploadProgressInputStream.java

package org.adrianwalker.gwt.uploadprogress.server;

import java.io.FilterInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.fileupload.ProgressListener;

public final class UploadProgressInputStream extends FilterInputStream {

  private List<ProgressListener> listeners;
  private long bytesRead = 0;
  private long totalBytes = 0;

  public UploadProgressInputStream(final InputStream in, final long totalBytes) {
    super(in);

    this.totalBytes = totalBytes;

    listeners = new ArrayList<ProgressListener>();
  }

  public void addListener(final ProgressListener listener) {
    listeners.add(listener);
  }

  @Override
  public int read() throws IOException {
    int b = super.read();

    this.bytesRead++;

    updateListeners(bytesRead, totalBytes);

    return b;
  }

  @Override
  public int read(final byte b[]) throws IOException {
    return read(b, 0, b.length);
  }

  @Override
  public int read(final byte b[], final int off, final int len) throws IOException {
    int bytesRead = in.read(b, off, len);

    this.bytesRead = this.bytesRead + bytesRead;

    updateListeners(this.bytesRead, totalBytes);

    return bytesRead;
  }

  @Override
  public void close() throws IOException {
    super.close();

    updateListeners(totalBytes, totalBytes);
  }

  private void updateListeners(final long bytesRead, final long totalBytes) {

    for (ProgressListener listener : listeners) {

      listener.update(bytesRead, totalBytes, listeners.size());
    }
  }
}

An UploadProgressListener attached to the input stream, adds UploadProgressChangeEvent events to the event list and calls notifyAll() to reply to the waiting client.

UploadProgressListener.java

package org.adrianwalker.gwt.uploadprogress.server;

import org.adrianwalker.gwt.uploadprogress.common.event.UploadProgressChangeEvent;
import org.apache.commons.fileupload.ProgressListener;

public final class UploadProgressListener implements ProgressListener {

  private static final double COMPLETE_PERECENTAGE = 100d;
  private int percentage = -1;
  private String fileName;
  private UploadProgress uploadProgress;

  public UploadProgressListener(final String fileName, final UploadProgress uploadProgress) {
    this.fileName = fileName;
    this.uploadProgress = uploadProgress;
  }

  @Override
  public void update(final long bytesRead, final long totalBytes, final int items) {
    int percentage = (int) Math.floor(((double) bytesRead / (double) totalBytes) * COMPLETE_PERECENTAGE);

    if (this.percentage == percentage) {
      return;
    }

    this.percentage = percentage;

    UploadProgressChangeEvent event = new UploadProgressChangeEvent();
    event.setFilename(this.fileName);
    event.setPercentage(percentage);

    synchronized (this.uploadProgress) {
      this.uploadProgress.add(event);
      this.uploadProgress.notifyAll();
    }
  }
}

The client side ProgressController is responsible for calling the getEvents() method on the service servlet, and calling it again after a successful response; creating an event loop.

ProgressController.java

package org.adrianwalker.gwt.uploadprogress.client.controller;

import com.google.gwt.core.client.GWT;
import java.util.List;

import com.google.gwt.user.client.rpc.AsyncCallback;
import org.adrianwalker.gwt.uploadprogress.client.state.UploadProgressState;
import org.adrianwalker.gwt.uploadprogress.common.dto.FileDto;
import org.adrianwalker.gwt.uploadprogress.common.event.Event;
import org.adrianwalker.gwt.uploadprogress.common.event.UploadProgressChangeEvent;

public final class ProgressController extends AbstractController {

  public static final ProgressController INSTANCE = new ProgressController();

  private ProgressController() {
  }

  public void findFiles(final int page, final int pageSize) {
    SERVICE.readFiles(page, pageSize, new AsyncCallback<List<FileDto>>() {

      @Override
      public void onFailure(final Throwable t) {
        GWT.log("error find files", t);
      }

      @Override
      public void onSuccess(final List<FileDto> files) {
        UploadProgressState.INSTANCE.setFiles(files);
      }
    });
  }

  private void getEvents() {

    SERVICE.getEvents(new AsyncCallback<List<Event>>() {

      @Override
      public void onFailure(final Throwable t) {
        GWT.log("error get events", t);
      }

      @Override
      public void onSuccess(final List<Event> events) {

        for (Event event : events) {
          handleEvent(event);
        }
        SERVICE.getEvents(this);
      }

      private void handleEvent(final Event event) {

        if (event instanceof UploadProgressChangeEvent) {
          UploadProgressChangeEvent uploadPercentChangeEvent = (UploadProgressChangeEvent) event;
          String filename = uploadPercentChangeEvent.getFilename();
          Integer percentage = uploadPercentChangeEvent.getPercentage();

          UploadProgressState.INSTANCE.setUploadProgress(filename, percentage);
        }
      }
    });
  }

  public void initialise() {
    SERVICE.initialise(new AsyncCallback<Void>() {

      @Override
      public void onFailure(final Throwable t) {
        GWT.log("error initialise", t);
      }

      @Override
      public void onSuccess(final Void result) {
        getEvents();
      }
    });
  }

  public void countFiles() {
    SERVICE.countFiles(new AsyncCallback<Integer>() {

      @Override
      public void onFailure(final Throwable t) {
        GWT.log("error count files", t);
      }

      @Override
      public void onSuccess(final Integer result) {
        int pageSize = UploadProgressState.INSTANCE.getPageSize();
        int pages = (int) Math.ceil((double) result / (double) pageSize);
        UploadProgressState.INSTANCE.setPages(pages);
      }
    });
  }
}

Changes to the files upload percentage are stored in UploadProgressState which can have listerners attached to be notified of updates to its fields.

UploadProgressState.java

package org.adrianwalker.gwt.uploadprogress.client.state;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.adrianwalker.gwt.uploadprogress.common.dto.FileDto;

public final class UploadProgressState extends PageableState {

  public static final UploadProgressState INSTANCE = new UploadProgressState();
  private Map<String, Integer> uploadProgress;
  private List<FileDto> files;

  private UploadProgressState() {
    uploadProgress = new HashMap<String, Integer>();
  }

  public List<FileDto> getFiles() {
    return files;
  }

  public void setFiles(final List<FileDto> files) {
    List<FileDto> old = this.files;
    this.files = files;
    firePropertyChange("files", old, files);
  }

  public Integer getUploadProgress(final String filename) {
    return uploadProgress.get(filename);
  }

  public void setUploadProgress(final String filename, final Integer percentage) {
    Integer old = this.uploadProgress.get(filename);
    uploadProgress.put(filename, percentage);
    firePropertyChange("uploadProgress", old, uploadProgress);
  }
}

Finally, UploadProgress listens for changes to UploadProgressState and updates the UploadPanel with percentage changes for the file upload, which in turn updates the panels ProgressBar.

UploadProgress.java

package org.adrianwalker.gwt.uploadprogress.client.view;

import com.google.gwt.user.client.Timer;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;

import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.Panel;
import com.google.gwt.user.client.ui.VerticalPanel;
import java.util.HashMap;
import java.util.Map;
import org.adrianwalker.gwt.uploadprogress.client.state.UploadProgressState;

public final class UploadProgress extends Composite {

  private Panel panel;
  private Map<String, UploadPanel> uploads;

  public UploadProgress() {

    panel = new VerticalPanel();
    panel.setStyleName("UploadProgress");
    uploads = new HashMap<String, UploadPanel>();

    this.initWidget(panel);

    UploadProgressState.INSTANCE.addPropertyChangeListener("uploadProgress", new UploadProgressListener());
  }

  private final class UploadProgressListener implements PropertyChangeListener {

    private static final int COMPLETE_PERECENTAGE = 100;
    private static final int REMOVE_DELAY = 3000;

    @Override
    public void propertyChange(final PropertyChangeEvent event) {

      Map<String, Integer> uploadPercentage = (Map<String, Integer>) event.getNewValue();

      for (Map.Entry<String, Integer> entry : uploadPercentage.entrySet()) {
        String file = entry.getKey();
        Integer percentage = entry.getValue();

        final UploadPanel uploadPanel;
        if (!uploads.containsKey(file)) {
          uploadPanel = new UploadPanel(file);
          uploads.put(file, uploadPanel);
          panel.add(uploadPanel);
        } else {
          uploadPanel = uploads.get(file);
        }

        uploadPanel.update(percentage);

        if (percentage == COMPLETE_PERECENTAGE) {
          Timer timer = new Timer() {

            @Override
            public void run() {
              panel.remove(uploadPanel);
            }
          };
          timer.schedule(REMOVE_DELAY);
        }
      }
    }
  }

  private static final class UploadPanel extends HorizontalPanel {

    private ProgressBar bar;
    private Label label;

    public UploadPanel(final String file) {

      setStyleName("UploadPanel");

      bar = new ProgressBar();
      label = new Label(file);

      add(bar);
      add(label);
    }

    public void update(final int percentage) {
      bar.update(percentage);
    }
  }
}

Source Code

Usage

Run the project with 'mvn clean install tomcat:run-war' and point your brower at http://localhost:8080/uploadprogress.

Update - 29/7/2012

If you're seeing the following exception during compilation try this updated pom.xml :

[gwt:compile]
auto discovered modules [org.adrianwalker.gwt.uploadprogress.UploadProgress]
You're project declares dependency on gwt-user 2.1.0. This plugin is designed for at least gwt version 2.5.0-rc1
You're project declares dependency on gwt-user 2.1.0. This plugin is designed for at least gwt version 2.5.0-rc1
Compiling module org.adrianwalker.gwt.uploadprogress.UploadProgress
   Validating units:
      Ignored 50 units with compilation errors in first pass.
Compile with -strict or with -logLevel set to TRACE or DEBUG to see all errors.
   [ERROR] Unexpected internal compiler error
java.lang.NullPointerException
 at com.google.gwt.dev.javac.CompilationProblemReporter.reportErrors(CompilationProblemReporter.java:200)
 at com.google.gwt.dev.jjs.impl.UnifyAst.assimilateUnit(UnifyAst.java:666)
 at com.google.gwt.dev.jjs.impl.UnifyAst.searchForTypeBySource(UnifyAst.java:985)
 at com.google.gwt.dev.jjs.impl.UnifyAst.addRootTypes(UnifyAst.java:530)
 at com.google.gwt.dev.jjs.JavaToJavaScriptCompiler.precompile(JavaToJavaScriptCompiler.java:601)
 at com.google.gwt.dev.jjs.JavaScriptCompiler.precompile(JavaScriptCompiler.java:33)
 at com.google.gwt.dev.Precompile.precompile(Precompile.java:278)
 at com.google.gwt.dev.Precompile.precompile(Precompile.java:229)
 at com.google.gwt.dev.Precompile.precompile(Precompile.java:141)
 at com.google.gwt.dev.Compiler.run(Compiler.java:232)
 at com.google.gwt.dev.Compiler.run(Compiler.java:198)
 at com.google.gwt.dev.Compiler$1.run(Compiler.java:170)
 at com.google.gwt.dev.CompileTaskRunner.doRun(CompileTaskRunner.java:88)
 at com.google.gwt.dev.CompileTaskRunner.runWithAppropriateLogger(CompileTaskRunner.java:82)
 at com.google.gwt.dev.Compiler.main(Compiler.java:177)

Java Sleep Sort - For The Lulz

$
0
0

Strictly for the lulz, here is an implementation of Sleep Sort, first seen on 4chan.

SleepSort.java

package sleepsort;

import java.util.Arrays;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorCompletionService;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public final class SleepSort {

  public static void main(final String[] args) throws Exception {

    int[] numbers = {90, 80, 70, 60, 50, 40, 30, 20, 10};
    int[] sortedNumbers = sort(numbers);
    System.out.println(Arrays.toString(sortedNumbers));
  }

  private static int[] sort(final int[] numbers) throws InterruptedException, ExecutionException {

    ExecutorService executor = Executors.newFixedThreadPool(numbers.length);
    ExecutorCompletionService<Integer> ecs = new ExecutorCompletionService<Integer>(executor);
    for (int number : numbers) {
      ecs.submit(new SleepSortCallable((number)));
    }

    int[] sortedNumbers = new int[numbers.length];
    for (int i = 0; i < sortedNumbers.length; i++) {
      sortedNumbers[i] = ecs.take().get();
    }

    executor.shutdown();

    return sortedNumbers;
  }

  private static class SleepSortCallable implements Callable<Integer> {

    private final int number;

    public SleepSortCallable(final int number) {
      this.number = number;
    }

    @Override
    public Integer call() throws Exception {
      Thread.sleep(number);
      return number;
    }
  }
}

EJB 3.1 Cookbook Review

$
0
0

The Enterprise JavaBeans 3.1 specification is the latest standard from Oracle to further simplify EJB technology. It provides developers with the ability to construct simple and reliable architectures, building on the previous EJB 3.0 standard with more annotations, more POJOS, simplified packaging and less XML configuration.

EJB 3.1 is part of the wider JavaEE 6 enterprise development platform, and is my favoured technology for building new projects, vastly superior to the older EJB 2.0 technology, a productivity step up from JavaEE 5 / EJB 3.0.

Packt Publishing requested that I review one of their titles about EJB 3.1 and the JavaEE 6 platform: EJB 3.1 Cookbook by Richard M. Reese, available to buy from Packt's website.

EJB 3.1 Cookbook is at best an average book. The information in the book is very densely packed, but often repetitive and sometimes tangential to the current topic being addressed. The information in the book is presented in recipes - short how-to examples focusing on a specific JavaEE / EJB feature, put together to form a cookbook.

Each recipe is presented in a formulaic way, with information under the sub-headings: Getting ready, How to do it..., How it works... and There's more. Some of the code examples, especially at the start of the book, are trivial; and the explanations of how the code works are sometimes no more useful then reading the JavaEE 6 javadoc.

The book covers the full range of EJB beans and the Java Persistence API, with about equal time being spent on features new to EJB 3.1 and existing features from 3.0.

It's difficult to say who the books target audience is. It doesn't provide enough guidance to developers new to Java, but spends too much time covering some of the basics which more experienced EJB developers will already be familiar with. If you're already experienced with EJB 3.0 development and need a handy reference for existing annotations, and want to get a good understanding of the new annotations in 3.1 and how to use them, then this book might be useful.

This book was laborious to read from cover to cover, and I wouldn't suggest reading it that way. I would recommend consulting its relevant recipes before implementing new code.

NetBeans 6.9.1 and GlassFish v3.0.1 are stated as requirements for using this book. In practice, specific features of these products are barely used. There is no reason why you couldn't use Eclipse and JBoss AS, or any other code editors and application servers which support EJB 3.1.

Chapter 1 is an introduction to Enterprise JavaBeans, Dependency Injection and the Java Naming and Directory Interface. It covers creating a simple Stateless session bean and accessing its functionality from a variety of clients. Developers who are familiar with EJB development will find this chapter a waste of time. Developers new to EJB and JNDI will find it baffling and of no immediate practical use, I'd recommend skipping this chapter.

Chapter 2 covers session beans - Stateless, Stateful and the new Singleton bean. It provides examples of how to use the new @Startup and @DependsOn annotations to control order of singleton initialisation, concurrency and locking, controlling initialization and local and remote interfaces.

The last and most useful part of the chapter uses the @Asynchronous annotation to schedule background processes, and demonstrates the Future and AsyncResult classes.

Chapter 3 explains Message Driven Beans and introduces Queues and Topics. Good program design and possible performance enhancements of separating object production from consumption is illustrated. More interesting and useful recipes are presented towards the end of the chapter, but the first five which deal with different message types are almost identical.

Chapter 4 introduces Object-relational mapping and the Java Persistence API. Familiar JPA concepts and annotations are covered as well as new annotations for temporal validation @Past and @Future, regular expression validation using @Pattern and integer and boolean validation.

Chapter 5 builds on chapter 4 and introduces the Java Persistence Query Language and the new Criteria API. CRUD operations using JPQL are covered extensively, but the new Criteria API is only given one recipe. I would have liked as many pages covering the Criteria API as there were on JPQL, the increased performance and type safety of this new feature are things I would like to know more about.

Chapter 6 contains very useful information on transaction processing. The defaults of Container Managed Transactions have always been sufficient for me, so I was interested to learn more about transaction types and Bean Managed Transactions.

EJB Security is covered in chapter 7. The concepts of users, groups and realms are introduced and specific features of GlassFish are used for the first time to prepare a File Realm. Declarative role based security using annotations is covered, as well as controlling security programmatically when annotations are inadequate.

Chapter 8 introduces Aspect Oriented Programming and the @Interceptor annotation. I've never been impressed with AOP, it always seemed more trouble than it was worth, but this chapter shows how simple EJB 3.1 makes it. There is some good information in this chapter, it demonstrates well how AOP can simplify code by moving functionality not central to a business method outside of the method.

Chapter 9 - Timer Services demonstrates automatic/declarative timers, implemented using annotations and programmatic timers using the TimerService class.

Chapter 10 covers SOAP web services using JAX-WS, which will be familiar to EJB 3.0 developers, as well as creating RESTful services with JAX-RS.

The pros of using XML deployment descriptors in environments which require more dynamic configuration are highlighted in chapter 11. Also covered is the usage of the 'jar' command to examine JAR and WAR file contents, and a quick overview of the java classpath and class loading.

Chapter 12 ends the book with recipes which are applicable to Java programming in general, not just EJB development. The chapter contains general good practice tips like using a logging framework instead of printing to System.out, not leaving empty catch blocks, using BigDecimal to avoid rounding errors for currency, and avoiding string concatenation performance inefficiencies by using StringBuilder.

Overall, I think this book is OK. I'd recommend using it as a reference to consult rather than a book to pick up and work through end to end.

I think the book is suitable for developers looking to brush up on the newest EJB annotations, but because of this, much of the book will be old news to many readers. Even the information I felt was relevant and interesting to me can easily be found on the Oracle website in the form of The Java EE 6 Tutorial and javadocs.

Downloads From Packt

Java EE 6 Development with NetBeans 7 Review

$
0
0

NetBeans is Oracle’s (formerly Sun Microsystems’s) open source pure Java integrated design environment (IDE). Since starting to program in Java I’ve tried a few free IDEs, Eclipse, JEdit and IntelliJ IDEA Community, but I believe non are currently as intuitive, feature rich, reliable and well integrated with Java EE technologies as NetBeans.

In the past NetBeans has been considered to be slow and less feature rich when compared to Eclipse – these things are simply no longer true. Eclipse may still have a sight performance edge over NetBeans because of its native code components, but not enough to be bothered by, and more importantly everything you can do in Eclipse, you can do in NetBeans and loads more!

NetBeans is not only a great IDE for Java development, but also supports other languages. NetBeans is also my preferred IDE for C and Python development.

JavaEE 6 (JEE 6) is the latest Java Enterprise specification, consisting of EJB 3.1, JPA 2.0, JSF 2.0, Servlet 3.0 and other updates to the JavaEE stack. New additions include JAX-RS for RESTful web service development and CDI for dependency injection.

The JavaEE 6 standard is my technology of choice for new projects, vastly superior to the older EJB 2.0 technology, a productivity step up from JavaEE 5 / EJB 3.0, and in my opinion more reliable and simpler to maintain than Spring/Hibernate technologies.

Packt Publishing requested that I review one of their new titles about NetBeans and JavaEE: JavaEE 6 Development with NetBeans 7 by David R. Heffelfinger, available to buy from Packt’s website.

JavaEE 6 Development with NetBeans 7 is a very good book which complements a very good IDE. It has improved my usage of NetBeans and has brought me up to speed with the latest additions to the Java EE specification. I’m looking forward to the next project which will let me put into practice the new things I’ve learnt from this book. JavaEE 6 Development with NetBeans 7 covers the full JEE 6 stack, from first principals, with examples deployed on GlassFish application server.

The book focuses on the full JEE 6 technology range, including some elements which aren’t used much anymore in production deployments (JSP SQL tags), but are there for the sake of thoroughness. Each part of the JEE stack has a chapter which is a great introduction to that topic, and will get you up and running with a usable example in no time at all.

No part of the stack is covered in great depth, but you wouldn’t expect that from book only 360ish pages long. Each chapter provides a solid foundation for you get grips with the basics, and up and running with a working example, so you can feel confident in exploring further using other books or online sources if you wanted.

The book will appeal to a range of developers. If you are familiar with Java and wanted to learn JavaEE 6 development, this book would give a great start. If you are already a JEE developer and wanted to brush up on the new additions to the JEE standards than this book is a worthwhile read. Or if you’re a developer, convinced that Eclipse, Spring, Hibernate and JBoss are the pinnacle of Enterprise Java development, then please give this book a try, it could be an eye opener.

The first chapter starts out by introducing the reader to NetBeans and it’s JEE capabilities. You are shown where to download the IDE from, what bundle to choose from, and how to install it on your development platform; with information for Windows, Linux and Mac OS X. The chapter guides you through the installation procedure with excellent step by step screen shots (which are provided for every step in every example throughout the book), and how to start the IDE for the first time.

The book then goes through the steps to integrate NetBeans with other applications servers and databases in case you want to use JBoss or MySQL, but I decided to stick with GlassFish and Derby that come installed by default. To make sure everything is working, the books show you how to create a sample application, deploy to GlassFish and test it in your browser. Only a few pages into the book and you’re up and running with a JavaEE web app – good stuff.

The remainder of the chapter details the developer productivity features that NetBeans provides, such as code completion, code templates, keyboard shortcuts and the editors visual queues; helpful stuff for knocking out the code faster and with fewer errors.

Chapter two covers how to create and deploy a simple JSP and Servlet application. The reader is guided thought how to modify the default new project code and how to create new HTML by dragging and dropping from NetBeans HTML palette. The Model-View-Controller design pattern is introduced and implemented, and authentication and authorisation are added to the application using GlassFish security realms, with form based authentication using a file realm. Finally the code is made more maintainable by using JSP fragments to reduce code duplication.

At only 100 pages into the book you have rapidly created a maintainable, secure and well architected web application!

Building on the previous chapter, chapter three introduces using JSP tags for conditional logic. SQL tags are introduced for querying and modifying data from a database, and the reader is rightly advised that a more robust method should be used for accessing the database in production systems. Custom tags are then used to encapsulate HTML mark-up and JSP functionality.

Chapter four introduces JavaServer Faces and chapter five builds on it with PrimeFaces. I’ve not used JSF since version 1.2 and was not familiar with PrimeFaces, so I was very impressed with the visual results achieved by the end of the two chapters. PrimeFaces and its AJAX capabilities are definitely something I want to explore further.

Chapter six contains some great information; it begins with how to access the database using the Java Persistence API, covering Entity Beans and how to annotate them. The Data Access Object pattern in demonstrated with JPA Controllers for encapsulating data access functionality. Now this is where NetBeans really starts to shine with respect to its code generation capabilities. The last half of the chapter shows how to generate Entities and Controllers from the database without having to manually write a line of code. Finally a whole JSF application for viewing and modifying the database data is generated from the Entity Beans. By the end of this chapter you can create a complete end-to-end data driven web application without writing a line of code. If you’re a developer who is already familiar with the JPA, its worth giving this chapter a read for the new features introduced as part of JPA 2.0, such as the new JSR 303 Bean Validation annotations.

Chapter 7 covers how you will implement your business rules and domain logic in an EJB environment using session beans. The chapter guides us through creating remote stateless session beans and how their functionality can be access across the network from a client. Aspect Oriented Programming using Interceptors is introduced as well as the EJB Timer service for scheduling tasks. Again NetBeans code generation capabilities are used to automatically create session beans from our JPA entities, saving development time.

The new API introduced in Java 6 for dependency injection CDI (Contexts and Dependency Injection), is covered in chapter 8. This great new feature should simplify integrating different application layers, and improve the maintainability of your code. CDI scopes and the @Inject and @Named annotations are used in the examples along with Stereotypes to group together CDI code.

Messaging with JMS and message driven beans is covered in chapter nine. The chapter introduces Queues and Topics, message producers and consumers, and demonstrates how to implement a message Queue and receiver bean. NetBeans can generate the all boilerplate code required to use Message Driven Beans, taking the work out of creating loosely coupled architectures.

The final two chapters detail the usage of Web Services. Chapter ten covers how to create SOAP Web Services with JAX-WS, and chapter eleven RESTful Web Services with JAX-RS. The advantages of using web services as they are client platform agnostic are discussed before creating a web service by using the @WebService and @WebMethod annotations.

NetBeans graphical Web Service design interface is used to create a web service without having to manually write a WSDL file, and then tested with NetBeans web service testing features to view the XML messages sent backwards and forwards.

The rest of chapter ten shows us how to simple crate a SOAP client my dragging and dropping the Web Service methods on to a class, how to generate code to create a web service from an existing Session Bean and how to generate a web service from an existing WSDL.

The last chapter shows us how to generate the code to REST enable a database and create a client with just a few clicks.

Overall I think this is a great book. It contains the things that make me enthusiastic about Enterprise Java Development: EJB 3.1, JPA 2.0 and GlassFish. The book is well written and well structured; it flows from one chapter to the next, building on what you have learned before. The text is accurate and concise, and the screen shots throughout the book are so useful that you could follow most of the examples from them alone.

Most importantly, the code printed in the book is correct and easy to follow, I found no syntax errors in it.

The book should appeal to novice Enterprise Java developers as well as experienced programmers who want to brush up on the latest standards or need a firm foundation in an area of JEE they haven’t covered before.

I’m looking forward to using some of the new things I’ve learned from the book in new projects. I hope the author continues to update the book in subsequent editions as and when the JEE standards evolve.

Downloads From Packt

jboard - yet another imageboard

$
0
0

This time I've kept it super simple - no SQL databases, no EJB containers, no extra features, just a simple imageboard web app which writes to the file system.

Image resizing is handled by ImageMagick which needs to be installed and configured before you run jboard.

Source Code

Usage

Set the location of ImageMagick's convert binary in: src\main\resources\BoardConfiguration.properties

Run the project with 'mvn clean install tomcat:run-war' and point your brower at http://localhost:8080/jboard.


HTTP Proxy

$
0
0

Sometimes you just want a simple HTTP proxy without the hastle.

HttpProxy.java

package org.adrianwalker.httpproxy;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public final class HttpProxy {

  public static final int MAX_THREADS = 2;
  public static final int LOCAL_PORT = 9090;
  public static final String REMOTE_HOST = "localhost";
  public static final int REMOTE_PORT = 8080;

  public static void main(final String[] args) throws Exception {

    ServerSocket server = new ServerSocket(LOCAL_PORT);

    Socket remoteSocket = new Socket(REMOTE_HOST, REMOTE_PORT);
    while (true) {
      Socket localSocket = server.accept();

      ExecutorService executor = Executors.newFixedThreadPool(MAX_THREADS);
      executor.submit(new SocketStreamCopy(remoteSocket.getInputStream(), localSocket.getOutputStream()));
      executor.submit(new SocketStreamCopy(localSocket.getInputStream(), remoteSocket.getOutputStream()));
    }
  }

  public static final class SocketStreamCopy implements Callable<Void> {

    public static final int BUFFER_SIZE = 1024;
    private final BufferedInputStream in;
    private final BufferedOutputStream out;

    SocketStreamCopy(final InputStream in, final OutputStream out) {

      this.in = new BufferedInputStream(in);
      this.out = new BufferedOutputStream(out);
    }

    @Override
    public Void call() throws Exception {
      byte[] b = new byte[BUFFER_SIZE];
      int n;
      try {
        while ((n = in.read(b)) > 0) {
          out.write(b, 0, n);
          out.flush();

          System.out.write(b, 0, n);
          System.out.flush();
        }
      } finally {
        in.close();
        out.close();
      }

      return Void.TYPE.newInstance();
    }
  }
}

Java Multiline String

$
0
0

Here is an implementation of multiline string literals in Java, using Javadoc comments, an annotation and an annotation processor.

This method works by annotating a String field with a @Multiline annotation, placing the fields initialisation value in a Javadoc comment, then using an annotation processor to set the fields value to the contents of the Javadoc comment at compile time.

First off, the @Multiline annotation.

Multiline.java

package org.adrianwalker.multilinestring;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.SOURCE)
public @interface Multiline {
}

Next, the annotation processor to insert the value of the Javadoc comment into the String field.

MultilineProcessor.java

package org.adrianwalker.multilinestring;

import com.sun.tools.javac.model.JavacElements;
import com.sun.tools.javac.processing.JavacProcessingEnvironment;
import com.sun.tools.javac.tree.JCTree;
import com.sun.tools.javac.tree.TreeMaker;
import java.util.Set;
import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.ProcessingEnvironment;
import javax.annotation.processing.RoundEnvironment;
import javax.annotation.processing.SupportedAnnotationTypes;
import javax.annotation.processing.SupportedSourceVersion;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element;
import javax.lang.model.element.TypeElement;

@SupportedAnnotationTypes({"org.adrianwalker.multilinestring.Multiline"})
@SupportedSourceVersion(SourceVersion.RELEASE_6)
public final class MultilineProcessor extends AbstractProcessor {

  private JavacElements elementUtils;
  private TreeMaker maker;

  @Override
  public void init(final ProcessingEnvironment procEnv) {
    super.init(procEnv);
    JavacProcessingEnvironment javacProcessingEnv = (JavacProcessingEnvironment) procEnv;
    this.elementUtils = javacProcessingEnv.getElementUtils();
    this.maker = TreeMaker.instance(javacProcessingEnv.getContext());
  }

  @Override
  public boolean process(final Set<? extends TypeElement> annotations, final RoundEnvironment roundEnv) {

    Set<? extends Element> fields = roundEnv.getElementsAnnotatedWith(Multiline.class);
    for (Element field : fields) {
      String docComment = elementUtils.getDocComment(field);
      if (null != docComment) {
        JCTree.JCVariableDecl fieldNode = (JCTree.JCVariableDecl) elementUtils.getTree(field);
        fieldNode.init = maker.Literal(docComment);
      }
    }

    return true;
  }
}

And finally, a class which demonstrates the usage of the annotation.

MultilineStringUsage.java

package org.adrianwalker.multilinestring;

public final class MultilineStringUsage {

  /**
  <html><head/><body><p>
        Hello<br/>
        Multiline<br/>
        World<br/></p></body></html>
  */
  @Multiline
  private static String html;
   
  public static void main(final String[] args) {
    System.out.println(html);
  }
}

Remember to include an <annotationProcessor> element when compiling classes which use @Multiline in the compiler plugin configuration when using Maven.

pom.xml

...
<plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><version>2.3.2</version><configuration><source>1.6</source><target>1.6</target><annotationProcessors><annotationProcessor>
        org.adrianwalker.multilinestring.MultilineProcessor
      </annotationProcessor></annotationProcessors></configuration></plugin>
...

Source Code

Usage

Build and install the Multiline String project which contains the @Multiline annotation and annotation processor, using 'mvn clean install'.

Build and install the Multiline String Usage project which contains an example of how to use the @Multiline annotation, using 'mvn clean install'.

Run the MultilineStringUsage class to output the multiline string.

Java 7 New Features Cookbook Review

$
0
0
Java 7 is the latest major release of the Java Language from Oracle. This release contains a number of language enhancements and new APIs, including better exception handling, new threading mechanisms and additions to the core libraries.

Packt Publishing requested that I review one of their titles about Java 7: Java 7 New Features Cookbook by Richard M. Reese and Jennifer L. Reese, available to buy from Packt's website.

Java 7 New Features Cookbook is an OK, but sometimes inconsistent book. I found parts of it very informative and other parts frustrating, with errors here and there in the example code – overall I'd give it an average score. 

The information in the book is very densely packed, but often repetitive and sometimes very slow reading. The information is presented in recipes - how-to examples focusing on a specific Java 7 feature, put together to form a cookbook.

Each recipe is presented in a formulaic way, with information under the sub-headings: 'Getting ready', 'How to do it...', 'How it works...' and 'There's more'. The code examples sufficiently cover the new feature they are trying to demonstrate, and are quite self contained, so you don't need to read the whole chapter to quickly get going with a new Java 7 feature. The 'There's more' sections expand on the basics, fleshing out the examples and include some good tips.

The book covers the full range of Java 7 new features, without going over old ground with respect to previous versions of Java. The book is definitely aimed at developers who are familiar with writing programs in Java 5 and beyond, and not for developers new to Java and OOP. A previous knowledge of Java file I/O, concurrency and a bit of SQL is required to get the most from this book.

This book was difficult to read from cover to cover, and I wouldn't suggest reading it that way. I would recommend consulting its relevant recipes before implementing new code.

A Java 7 JDK installation and an editor are requirements to reproduce the examples in the book. NetBeans 7 is stated as the IDE used to develop the code, but Eclipse or any other IDE or text editor could be used.

A note on the code examples in the book: the immediate thing you notice about the code examples is that they are badly formatted. This coupled with occasional errors in the code and new language syntax, such as try-with-resources, makes for frustrating debugging. The poor code layout is a problem throughout the book and spoilt my enjoyment of it slightly.

Chapter 1 covers new language features from Project Coin. These are small language enhancements designed to make code more readable, more useful and reduce verbosity. The useful new features to take away from this chapter are the new try-with-resources exception handling code, the use of the new AutoClosable interface, catching multiple exception types and using the diamond operator. 

This chapter is a good introduction to Java 7 and I think most developers will want to get to grips with all the recipes.

Chapter 2 introduces the new Paths and FileSystem objects, which are used extensively in subsequent chapters. The new classes provide utility methods to simplify the manipulation and comparison of file paths, helping to reducing some of the bespoke code you may have had to write in previous Java versions. The most important feature introduced in this chapter is the managing of symbolic links, but you will need to be running an operating system that supports them.

Chapter 3 deals with file and directory attributes. The first recipe demonstrates a useful new method for determining a files MIME type, something which has required 3rd party libraries in the past. The chapter goes on to give examples of managing file attributes, including support for DOS and POSIX file systems, very useful for managing Linux file permissions, which wasn't directly possible before.

Chapter 4 builds on the previous chapters and uses the new Files object to create, copy, move and delete files and directories with much more control, and much less code than was previously possible. Useful new features presented are temporary file and directory management and creating symbolic and hard links.

Chapter 5 has loads of useful information for interacting with file systems. Recipes include: accessing root file store information, processing directory contents with DirectoryStream, file filtering, globbing patterns, file event monitoring and more! Lastly in this chapter, the ZIP filesystem provider recipe demonstrates how to treat a ZIP or JAR file as though they were file systems.

Java is often criticised for the amount of code needed to perform simple file reading and writing operations. Chapter 6 shows how simple these operations can now be with Java 7, including new APIs for working with buffered I/O.  The new SeekableByteChannel class for random access I/O, and the new AsynchronousServerSocketChannel class for building client-server applications are recipes also worth visiting.

Thankfully, after half the book, this is the last chapter that deals with paths, files, files systems, file permissions and file I/O.

Chapter 7 showcases additions to swing which can improve the look of your GUI interfaces. Some of the cool looking new features include window opacity, varying gradient window translucency, and custom window shapes. Less exciting, but definitely useful, border type and print dialog box control recipes are also worth taking a look at in this chapter.

Chapter 9 contains a mix of new features, but has some really useful recipes. Firstly the RowSetFactory example shows how to really reduce the amount of JDBC boiler plate code needed to connect to a SQL database, execute queries and iterate over the returned data.

The next recipe demonstrates further database enhancements for reading database schema and pseudo-column information.

Another recipe worth a look include secure client-server communication using the ExtendedSSLSession interface, making use of the keytool, a serverside keystore and a client side trust store.

A new nested class, ProcessBuilder.Redirect, has been introduced to provide redirecting of input and output of external processes – useful for interacting with other executables and scripts.

I think chapter 9 is another chapter all developers will want to read.

Chapter 10's recipes deal with further concurrency enhancements to the Java language, which have been getting more and more powerful since Java 5. The new fork/join framework allows a task to be split into smaller parallelisable chunks, and then combining the results.

Other useful recipes in this chapter demonstrate using the new ThreadLocalRandom class for more efficient random number generation in a threaded environment. And the ConcurrentLinkedDeque example shows how concurrent threads can safely access the same collection data.

Chapter 11 contains bit and bobs which don't fit in other chapters. The Handling null references recipe introduces the new Objects class which provides utility methods for object comparison, null checking and hashing.

The JavaBean enhancements recipe shows how to use the new Expression class to programatically create and execute Java statements. Also the Introspector and BeanInfo class provide a new way of determining a classes' methods and fields without using the Reflection API.

Overall, I think this book is good in places, but repetitive and difficult to work though in others. About half the book is devoted to paths, files, filesystems and I/O, which I'm sure could be slimmed down a bit. I'd recommend using the book as a reference to consult rather than a book to pick up and read cover to cover.  Java 7 New Features Cookbook is definitely worth a read, and I will be using the things I've learned from it in future blog posts.

Downloads From Packt

Filtered JTree

$
0
0

The solutions (1, 2) out there for filtering a JTree's nodes weren't suitable for me, so I rolled by own FilteredTreeModel class which wraps a JTree's underlying TreeModel and applies a string filter to the node names.

The tree model recurses over the tree nodes, from the root to the leaf nodes, checking if the nodes toString() value contains the filter value:

FilteredTreeModel.java

package org.adrianwalker.filteredjtree;

import javax.swing.event.TreeModelListener;
import javax.swing.tree.TreeModel;
import javax.swing.tree.TreePath;

public final class FilteredTreeModel implements TreeModel {

  private TreeModel treeModel;
  private String filter;

  public FilteredTreeModel(final TreeModel treeModel) {
    this.treeModel = treeModel;
    this.filter = "";
  }

  public TreeModel getTreeModel() {
    return treeModel;
  }

  public void setFilter(final String filter) {
    this.filter = filter;
  }

  private boolean recursiveMatch(final Object node, final String filter) {

    boolean matches = node.toString().contains(filter);

    int childCount = treeModel.getChildCount(node);
    for (int i = 0; i < childCount; i++) {
      Object child = treeModel.getChild(node, i);
      matches |= recursiveMatch(child, filter);
    }
    
    return matches;
  }

  @Override
  public Object getRoot() {
    return treeModel.getRoot();
  }

  @Override
  public Object getChild(final Object parent, final int index) {
    int count = 0;
    int childCount = treeModel.getChildCount(parent);
    for (int i = 0; i < childCount; i++) {
      Object child = treeModel.getChild(parent, i);
      if (recursiveMatch(child, filter)) {
        if (count == index) {
          return child;
        }
        count++;
      }
    }
    return null;
  }

  @Override
  public int getChildCount(final Object parent) {
    int count = 0;
    int childCount = treeModel.getChildCount(parent);
    for (int i = 0; i < childCount; i++) {
      Object child = treeModel.getChild(parent, i);
      if (recursiveMatch(child, filter)) {
        count++;
      }
    }
    return count;
  }

  @Override
  public boolean isLeaf(final Object node) {
    return treeModel.isLeaf(node);
  }

  @Override
  public void valueForPathChanged(final TreePath path, final Object newValue) {
    treeModel.valueForPathChanged(path, newValue);
  }

  @Override
  public int getIndexOfChild(final Object parent, final Object childToFind) {
    int childCount = treeModel.getChildCount(parent);
    for (int i = 0; i < childCount; i++) {
      Object child = treeModel.getChild(parent, i);
      if (recursiveMatch(child, filter)) {
        if (childToFind.equals(child)) {
          return i;
        }
      }
    }
    return -1;
  }

  @Override
  public void addTreeModelListener(final TreeModelListener l) {
    treeModel.addTreeModelListener(l);
  }

  @Override
  public void removeTreeModelListener(final TreeModelListener l) {
    treeModel.removeTreeModelListener(l);
  }
}

Example Application

JTree before and after filtering

Below is a simple example of how the FilteredTreeModel can be used. The tree is filtered using the value of the text field as characters are typed.

FilteredJTreeExample.java

package org.adrianwalker.filteredjtree;

import java.awt.Container;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import javax.swing.JTree;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;

public final class FilteredJTreeExample {

  public static void main(final String[] args) {
    javax.swing.SwingUtilities.invokeLater(new Runnable() {

      @Override
      public void run() {
        createAndShowGUI();
      }
    });
  }

  private static void createAndShowGUI() {
    JFrame frame = new JFrame("Filtered JTree Demo");
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

    addComponentsToPane(frame.getContentPane());

    frame.pack();
    frame.setVisible(true);
  }

  private static void addComponentsToPane(final Container pane) {
    pane.setLayout(new GridBagLayout());

    JTree tree = createTree(pane);
    JTextField filter = createFilterField(pane);

    filter.getDocument().addDocumentListener(createDocumentListener(tree, filter));
  }

  private static JTree createTree(final Container pane) {
    DefaultMutableTreeNode root = new DefaultMutableTreeNode("JTree");
    FilteredTreeModel model = new FilteredTreeModel(new DefaultTreeModel(root));
    JTree tree = new JTree(model);
    JScrollPane scrollPane = new JScrollPane(tree);
    GridBagConstraints c = new GridBagConstraints();
    c.weightx = 1;
    c.weighty = 1;
    c.fill = GridBagConstraints.BOTH;
    c.gridx = 0;
    c.gridy = 1;
    pane.add(scrollPane, c);
    createTreeNodes(root);
    expandTree(tree);

    return tree;
  }

  private static JTextField createFilterField(final Container pane) {
    JTextField filter = new JTextField();
    GridBagConstraints c = new GridBagConstraints();
    c.weightx = 0;
    c.weighty = 0;
    c.fill = GridBagConstraints.HORIZONTAL;
    c.gridx = 0;
    c.gridy = 0;
    pane.add(filter, c);

    return filter;
  }
  
  private static DocumentListener createDocumentListener(final JTree tree, final JTextField filter) {
    return new DocumentListener() {

      @Override
      public void insertUpdate(final DocumentEvent e) {
        applyFilter();
      }

      @Override
      public void removeUpdate(final DocumentEvent e) {
        applyFilter();
      }

      @Override
      public void changedUpdate(final DocumentEvent e) {
        applyFilter();
      }

      public void applyFilter() {
        FilteredTreeModel filteredModel = (FilteredTreeModel) tree.getModel();
        filteredModel.setFilter(filter.getText());
        
        DefaultTreeModel treeModel = (DefaultTreeModel) filteredModel.getTreeModel();
        treeModel.reload();
        
        expandTree(tree);
      }
    };
  }

  private static void expandTree(final JTree tree) {
    for (int i = 0; i < tree.getRowCount(); i++) {
      tree.expandRow(i);
    }
  }

  private static void createTreeNodes(final DefaultMutableTreeNode node) {
    DefaultMutableTreeNode ab = new DefaultMutableTreeNode("ab");
    DefaultMutableTreeNode cd = new DefaultMutableTreeNode("cd");
    DefaultMutableTreeNode ef = new DefaultMutableTreeNode("ef");
    DefaultMutableTreeNode gh = new DefaultMutableTreeNode("gh");
    DefaultMutableTreeNode ij = new DefaultMutableTreeNode("ij");
    DefaultMutableTreeNode kl = new DefaultMutableTreeNode("kl");
    DefaultMutableTreeNode mn = new DefaultMutableTreeNode("mn");
    DefaultMutableTreeNode op = new DefaultMutableTreeNode("op");
    DefaultMutableTreeNode qr = new DefaultMutableTreeNode("qr");
    DefaultMutableTreeNode st = new DefaultMutableTreeNode("st");
    DefaultMutableTreeNode uv = new DefaultMutableTreeNode("uv");
    DefaultMutableTreeNode wx = new DefaultMutableTreeNode("wx");
    DefaultMutableTreeNode yz = new DefaultMutableTreeNode("yz");

    node.add(ab);
    node.add(cd);
    ab.add(ef);
    ab.add(gh);
    cd.add(ij);
    cd.add(kl);
    ef.add(mn);
    ef.add(op);
    gh.add(qr);
    gh.add(st);
    ij.add(uv);
    ij.add(wx);

    node.add(yz);
  }
}

Source Code

Usage

Build and install the Filtered JTree project, using 'mvn clean install'.

Run the FilteredJTreeExample class, and enter characters in the filter text field.

C Legs

$
0
0

Every now and again I vow to learn C, and now seems like a good time to have another go.

My plan for learning C is always the same:

  1. Read K&R
  2. ?
  3. Profit

Where step 2 might as well be 'Don't use C and forget everything in K&R'. The problem is that I'm not a systems programmer, so everything I want to program is just easier to do in Java.

This time round I'm having a go with Learn C The Hard Way. It takes a way more modern and pragmatic approach than K&R, and introduces tools like make and valgrind early on.

I'm going to try and not fall back on more familiar languages, and see if I can knock out interesting things in C where appropriate, and blog about them to help me learn.

First off a simple Sudoku solver:

main.c

#include <stdio.h>
#include <stdlib.h>

#define _ 0
#define GRID_SIZE 9
#define SQUARE_SIZE 3
#define FALSE 0
#define TRUE !FALSE

void print(int grid[GRID_SIZE][GRID_SIZE]);
int complete(int grid[GRID_SIZE][GRID_SIZE]);
int contains(int array[GRID_SIZE], int value);
void row(int grid[GRID_SIZE][GRID_SIZE], int rowIndex, int row[GRID_SIZE]);
void column(int grid[GRID_SIZE][GRID_SIZE], int columnIndex, int column[GRID_SIZE]);
void square(int grid[GRID_SIZE][GRID_SIZE], int rowIndex, int columnIndex, int square[GRID_SIZE]);

int main(int argc, char** argv) {

  int grid[GRID_SIZE][GRID_SIZE] ={
    {_, 3, 6, _, 5, _, _, 8, 7},
    {9, _, 1, 7, 8, _, _, 6, 2},
    {_, _, 7, _, _, _, 1, 4, _},
    {_, _, 5, _, 9, _, _, _, 3},
    {_, _, _, _, 1, _, _, _, _},
    {8, _, _, _, 7, _, 6, _, _},
    {_, 2, 9, _, _, _, 5, _, _},
    {5, 7, _, _, 2, 9, 8, _, 6},
    {6, 1, _, _, 3, _, 2, 9, _}
  };

  int rowIndex;
  int columnIndex;
  int value;
  int possibleValue;
  int possibleValueCount;
  int inRow;
  int inColumn;
  int inSquare;
  int tmp[GRID_SIZE];

  while (!complete(grid)) {
    for (rowIndex = 0; rowIndex < GRID_SIZE; rowIndex++) {
      for (columnIndex = 0; columnIndex < GRID_SIZE; columnIndex++) {

        if (grid[rowIndex][columnIndex] != _) {
          continue;
        }

        possibleValue = _;
        possibleValueCount = 0;

        for (value = 1; value <= GRID_SIZE; value++) {

          row(grid, rowIndex, tmp);
          inRow = contains(tmp, value);
          if (inRow) {
            continue;
          }

          column(grid, columnIndex, tmp);
          inColumn = contains(tmp, value);
          if (inColumn) {
            continue;
          }

          square(grid, rowIndex, columnIndex, tmp);
          inSquare = contains(tmp, value);
          if (inSquare) {
            continue;
          }

          possibleValue = value;
          possibleValueCount++;
        }

        if (possibleValueCount == 1) {
          grid[rowIndex][columnIndex] = possibleValue;
        }
      }
    }
  }

  print(grid);

  return (EXIT_SUCCESS);
}

void print(int grid[GRID_SIZE][GRID_SIZE]) {

  int rowIndex;
  int columnIndex;

  for (rowIndex = 0; rowIndex < GRID_SIZE; rowIndex++) {
    for (columnIndex = 0; columnIndex < GRID_SIZE; columnIndex++) {
      if (columnIndex != 0) {
        printf(", ");
      }
      printf("%d", grid[rowIndex][columnIndex]);
    }
    printf("\n");
  }
}

int complete(int grid[GRID_SIZE][GRID_SIZE]) {
  int tmp[GRID_SIZE];
  int rowIndex;
  int inRow;

  for (rowIndex = 0; rowIndex < GRID_SIZE; rowIndex++) {
    row(grid, rowIndex, tmp);
    inRow = contains(tmp, _);
    if (inRow) {
      return FALSE;
    }
  }
  return TRUE;
}

int contains(int array[GRID_SIZE], int value) {

  int i;

  for (i = 0; i < GRID_SIZE; i++) {
    if (array[i] == value) {
      return TRUE;
    }
  }
  return FALSE;
}

void row(int grid[GRID_SIZE][GRID_SIZE], int rowIndex, int row[GRID_SIZE]) {

  int columnIndex;

  for (columnIndex = 0; columnIndex < GRID_SIZE; columnIndex++) {
    row[columnIndex] = grid[rowIndex][columnIndex];
  }
}

void column(int grid[GRID_SIZE][GRID_SIZE], int columnIndex, int column[GRID_SIZE]) {

  int rowIndex;

  for (rowIndex = 0; rowIndex < GRID_SIZE; rowIndex++) {
    column[rowIndex] = grid[rowIndex][columnIndex];
  }
}

void square(int grid[GRID_SIZE][GRID_SIZE], int rowIndex, int columnIndex, int square[GRID_SIZE]) {

  int i;
  int j;

  int x = SQUARE_SIZE * (rowIndex / SQUARE_SIZE);
  int y = SQUARE_SIZE * (columnIndex / SQUARE_SIZE);

  for (i = 0; i < SQUARE_SIZE; i++) {
    for (j = 0; j < SQUARE_SIZE; j++) {
      square[(i * SQUARE_SIZE) + j] = grid[x + i][y + j];
    }
  }
}
Viewing all 65 articles
Browse latest View live