Project Wonder 2.0

er.extensions
Class ERXCompilerProxy

java.lang.Object
  extended byer.extensions.ERXCompilerProxy

public class ERXCompilerProxy
extends Object

ERXCompilerProxy is a class that creates a rapid-turnaround mode for WebObjects 5 for Java similar to how you use WebScript with WO 4.5.1.

Instead of recompiling your Application or Frameworks, you simply change the source code in question and reload your page. In some cases, you may also have to restart your Application but you won't have to rebuild it.

ERXCompilerProxy is especially well suited for DirectToWeb applications. The restrictions of Java's classloading are partially compensated by the highly dynamic nature of D2W apps.

Installation

Check if you have jikes installed in /usr/bin. On Windows, install jikes.exe in $NEXT_ROOT/Local/Library/Executables/

Usage

To use this framework you must complete a few easy steps and you will very seldom have to rebuild or even restart your project again:

That's all. Now build your app, make a change in Main.java and reload. You should see the changed version and a message from ERXCompilerProxy in the console.

What it does

The ERXCompilerProxy does several things to works it's magic. First, on startup, it registers for the ApplicationDidFinishLaunching Notification. When the App starts, it reads the CPFileList.txt files from your currently opened projects to find out about the files to watch. So remember to have your framework projects open in PB.

It also registers for the ApplicationWillDispatchRequest Notification, which gets triggered whenever a page is requested. It tries to compile the files that have changed and throws an Exception describing the errors if there where any and then aborts further handling of the request - you will get an error from your browser. However, if everything went well, it creates a new ClassLoader and throws away the component definition cache and a few other things. Then, when the next "pageWithName" is called, the updated class will be used.

This is slightly different from how WebScript handled things. In Java, you simply can't change an Object's class implementation at runtime - so if you already have a page (or any other Object) this object will not use the newer class. Only Objects created after the compilation will have new behaviour.

The freshly compiled files will be put into your App's Resources/Java directory into the proper package hierarchy. So, if you simply restart your App, the newer files will be used. When you re-build your project, your normal .jar will contains the correct classes anyway.

NOTE: Since all new class files end up in Resources/Java, when you clean-build your App, you also need to recompile your frameworks when you have changed classes there! A normal build will not delete the files, so recompilation of the frameworks is not needed.

Knows bugs and limitations


Field Summary
protected  String _className
           
protected static String _classPath
          Holds the classpath of the current app.
protected static ERXCompilerProxy _defaultProxy
          Holds the Compilerproxy singleton
protected  String _destinationPath
          Holds the path where the compiled .class files go.
protected  NSMutableDictionary _filesToWatch
          Holds the files to watch.
protected static String _jikesPath
          Path to the jikes binary.
protected  NSArray _projectSearchPath
           
protected static boolean _raiseOnError
          Holds a boolean that tells wether an error should raise an Exception or only log the error.
protected  NSMutableSet classFiles
          Currently compiled classes.
protected static ERXLogger classLoaderLog
           
static String CompilerProxyDidCompileClassesNotification
          Notification you can register to when the Compiler Proxy reloads classes.
protected static String CPFileList
          denotes the name of file which describes in each line a path to java class to watch for.
protected  boolean initialized
           
protected static ERXLogger log
           
 
Constructor Summary
ERXCompilerProxy()
          Contructor - does nothing special.
 
Method Summary
 void checkAndCompileOnNotification(NSNotification theNotification)
          Method that will be called upon ApplicationWillDispatchRequest.
 Class classForName(String className)
          Returns the class registered for the name className.
static ERXCompilerProxy defaultProxy()
          Returns the Compiler Proxy Singleton.
 void initialize()
          Initializes the CopilerProxy singleton.
static boolean isClassContainedBySet(String classNameWithPackage, NSSet cacheEntries)
          Tests whether or not the class name with package is contained in the set of CacheEntry objects.
protected  String pathForCPFileList(String directory)
           
 String projectInSearchPath(String bundleName)
          Returns an array of paths to the opened projects that have a CPFileList.txt.
protected  NSArray projectPaths()
           
 void setClassForName(Class clazz, String className)
          Sets the class registered for the name className to the given class.
static void setDefaultProxy(ERXCompilerProxy p)
           
 
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
 

Field Detail

log

protected static final ERXLogger log

classLoaderLog

protected static final ERXLogger classLoaderLog

CompilerProxyDidCompileClassesNotification

public static final String CompilerProxyDidCompileClassesNotification
Notification you can register to when the Compiler Proxy reloads classes.
The object is an array of classes that did recompiled since the last time the notification was sent.

See Also:
Constant Field Values

CPFileList

protected static final String CPFileList
denotes the name of file which describes in each line a path to java class to watch for.
The format of this file is:
name.of.package:unix_path_to_java_file_relative_to_this_file<return>

See Also:
Constant Field Values

_jikesPath

protected static String _jikesPath
Path to the jikes binary.


_defaultProxy

protected static ERXCompilerProxy _defaultProxy
Holds the Compilerproxy singleton


_classPath

protected static String _classPath
Holds the classpath of the current app.


_raiseOnError

protected static boolean _raiseOnError
Holds a boolean that tells wether an error should raise an Exception or only log the error.


initialized

protected boolean initialized

_filesToWatch

protected NSMutableDictionary _filesToWatch
Holds the files to watch.


_className

protected String _className

_destinationPath

protected String _destinationPath
Holds the path where the compiled .class files go. Default is Contents/Resources/Java.


classFiles

protected NSMutableSet classFiles
Currently compiled classes.


_projectSearchPath

protected NSArray _projectSearchPath
Constructor Detail

ERXCompilerProxy

public ERXCompilerProxy()
Contructor - does nothing special.

Method Detail

defaultProxy

public static ERXCompilerProxy defaultProxy()
Returns the Compiler Proxy Singleton.
Creates one if needed.

Returns:
compiler proxy singleton

setDefaultProxy

public static void setDefaultProxy(ERXCompilerProxy p)

pathForCPFileList

protected String pathForCPFileList(String directory)

projectInSearchPath

public String projectInSearchPath(String bundleName)
Returns an array of paths to the opened projects that have a CPFileList.txt.
This code is pretty fragile and subject to changes between versions of the dev-tools. You can get around it by setting NSProjectSearchPath to the paths to your projects: (/Users/ak/Wonder/Common/Frameworks,/Users/Work) will look for directories with a CPFileList.txt in all loaded bundles. So when you link to ERExtensions.framework, /Users/ak/Wonder/Common/Frameworks/ERExtensions will get found.

Returns:
paths to opened projects

projectPaths

protected NSArray projectPaths()

classForName

public Class classForName(String className)
Returns the class registered for the name className.
Uses the private WebObjects class cache.

Parameters:
className - class name
Returns:
class for the registered name or null

setClassForName

public void setClassForName(Class clazz,
                            String className)
Sets the class registered for the name className to the given class.
Changes the private WebObjects class cache.

Parameters:
clazz - class object
className - name for the class - normally clazz.getName()

initialize

public void initialize()
Initializes the CopilerProxy singleton.
Registers for ApplicationWillDispatchRequest notification.


checkAndCompileOnNotification

public void checkAndCompileOnNotification(NSNotification theNotification)
Method that will be called upon ApplicationWillDispatchRequest.
Checks if the request is not a resource request and then calls #checkAndCompileOnNotification()

Parameters:
theNotification - notification sent upon ApplicationWillDispatchRequest

isClassContainedBySet

public static boolean isClassContainedBySet(String classNameWithPackage,
                                            NSSet cacheEntries)
Tests whether or not the class name with package is contained in the set of CacheEntry objects. Convenient to check if a specific class was recompiled in a CompilerProxyDidCompileClassesNotification.

Parameters:
classNameWithPackage - string of the class name
cacheEntries - NSSet contains CacheEntry objects; typically obtained by a notification's object() method
Returns:
if the classNameWithPackage is contained by cacheEntries

Last updated: Do, Dez 9, 2004 • 12:46 PM CET

Copyright © 2002 – 2004 Project Wonder.