<CFSCRIPT language="java">

The CFSCRIPT tag is a powerful addition to the CFML language allowing developers to express their applications using a Javascript-esq syntax notation. However, OpenBD has the ability to allow developers extend CFSCRIPT to support additional deep language integration. You can easily write complete CFC using Java without manually compiling and building JAR files.

This extension to the CFSCRIPT tag offers pure Java support within CFML pages and components. On-the-fly compilation and hotspot optimzation and easy marshalling of data from CFML -> Java -> CFML, this gives a high performance window to embed full Java within the CFML framework.

Here is an example of how easy it is to use pure Java inside of a CFML page, moving variables in and out.

<cfset s = ["A","B","C","D","E","F"]>

<cfscript language="java">
  // Retrieve the CFML object
  cfArray d = cf.getArray("s");

  for ( int x=0; x < d.size(); x++ ){
    cf.print( d.get(x) );
  }

  cf.print( cf.get("CGI.SCRIPT_NAME") );

  // Creating an array in Java, and then setting it for the CFML
  List fromJava	= Arrays.asList(new String[] { "aa", "bb", "cc", "dd" });
  cf.set( "abc", fromJava );

  // Calling out to a cfml function
  String a = (String)cf.call( "listgetat", "a,b,c,d", 3 );
  cf.print( a );

</cfscript>

<cfdump var="#abc#">

There is much more power underneath the bonnet here than this simple example illustrates. The rest of this page will look at some of the advanced functionality.

Importing Packages

Java requires that you tell it which packages you will be using classes from. There are a couple of ways we can do this in Java. The first way, is to always use the full qualified package name for a given class. For example java.util.Date. However this makes code quickly become bloated and very verbose.

An alternative is to declare which packages you wish to by using the Java import statement, that tells it to look up this package for its classes.

We can pass this information to our CFML Java block in two ways.

The first way is to simply write the import statements straight inside the CFSCRIPT body. For example:

<cfscript language="java">
  import java.util.*;

  // Creating an array in Java, and then setting it for the CFML
  List fromJava	= Arrays.asList(new String[] { "aa", "bb", "cc", "dd" });
  cf.set( "abc", fromJava );
</cfscript>

Alternatively, you can pass in a comma-separated list of imports to use as a tag attribute to CFSCRIPT.

<cfscript language="java" import="java.util.*">
  // Creating an array in Java, and then setting it for the CFML
  List fromJava	= Arrays.asList(new String[] { "aa", "bb", "cc", "dd" });
  cf.set( "abc", fromJava );
</cfscript>

Either way is acceptable and it doesn't matter if you repeat your imports. The compiler will soon complain if you are missing one.

Inner Java Functions

There are basically 2 modes to which you can embed Java code. As you have seen so far, the first and easiest way, is to simply write your Java code and when the tag gets executed, your Java code will get executed inline with it. If you wish to develop more, you can provide complete sets of Java functions that can be used internal to the Java code.

Let us look at an example of this in action. As you can see below, we are effectively embedding a Java class into the CFSCRIPT tag. So all the usual rules of Java apply here.

<cfscript language="java" import="java.util.*">
public void tagRun() {
  Date d = fromJava();
  cf.print( d );
}

public Date fromJava(){
  return new Date();
}
</cfscript>

Notice the core inner-method public void tagRun(). This is a helper method you can override if you wish you to still execute code when the CFSCRIPT is encountered.

Writing CFC components with Java

One of the exciting developments is the ability to write complete or partial CFC components using Java. Any public method you declare in Java is available as part of the CFC component to the outside calling world. Only Java methods declared 'public' are exported to the CFC.

<cfcomponent>

<cffunction name="fromCfml">
  <cfreturn now()>
</cffunction>


<cfscript language="java">
long start = System.currentTimeMillis();

public long getStart(){
  return start;
}

public Date fromJava(){
  return new Date();
}

public String echo(String al){
  return al;
}

// Will not get exported
private void myPrivate(){
}
</cfscript>

</cfcomponent>

You can then use this CFC as you would any other CFC. Assuming we save the above component in the file; compj.cfc, we could then use it very easily and quickly.

<cfoutput>
<cfscript>
cfc1 = CreateObject("compj");
cfc2 = new compj();

cfc1.getStart()   = cfc1.getStart();
cfc2.getStart()   = cfc2.getStart();
cfc2.echo("alan") = cfc2.echo("alan");
</cfscript>
<cfoutput>

This gives the CFML developer the power to write their CFC components using tags, cfscript or java, or even all 3 at the same time!

cf - context object

To facilitate communications with the underlying CFML platform, the cf object is available to the Java code and makes it easy to bring objects in and out. You do not need to declare it, it is automatically made available to your code and is contextually aware to the given request. Available methods from this object include:

/**
 * Returns the CFML variable as a Java String object
 *
 * @param var - CFML path eg "form.param1"
 * @return
 */
public String getString( String var );

/**
 * Returns the CFML variable as a Java integer
 *
 * @param var - CFML path eg "form.param1"
 * @return
 */
public int getInt( String var );

/**
 * Returns the CFML variable as a Java long
 *
 * @param var - CFML path eg "form.param1"
 * @return
 */
public long getLong( String var );

/**
 * Returns the CFML variable as a Java boolean
 *
 * @param var - CFML path eg "form.param1"
 * @return
 */
public boolean getBoolean( String var );

/**
 * Returns the CFML variable as a Java Date
 *
 * @param var - CFML path eg "form.param1"
 * @return
 */
public Date getDate( String var );

/**
 * Returns the CFML variable as a Java Object
 *
 * @param var - CFML path eg "form.param1"
 * @return
 */
public Object get( String var );

/**
 * Returns the CFML array as a Java cfArray
 *
 * @param var - CFML path eg "form.param1"
 * @return - null if not found or not an array
 */
public cfArray getArray( String var );

/**
 * Returns the CFML array as a Java cfQuery
 *
 * @param var - CFML path eg "form.param1"
 * @return - null if not found or not an query
 */
public cfQuery getQuery( String var );

/**
 * Returns the CFML array as a Java cfStruct
 *
 * @param var - CFML path eg "form.param1"
 * @return - null if not found or not an struct
 */
public cfStruct getStruct( String var );

/**
 * Sets the given Java object to the CFML path.
 * It will automatically convert to Array, Struct accordingly
 *
 * @param var - CFML path eg "form.param1"
 * @param data
 */
public void set( String var, Object data );

/**
 * Prints the given parameter to the request output
 * @param s
 */
public void print(String s);
public void print(int s);
public void print(StringBuilder s);
public void print(long s);
public void print(double s);
public void print(boolean s);
public void print(byte s);
public void print(Object s);

/**
 * Attributes for storing Java objects between calls
 */
public void setAttribute(String name, Object o);
public Object getAttribute(String name);
public void removeAttribute(String name);
public Iterator getAttributeNames();

/**
 * Executes a CFML function returning back the Java object
 *
 * @param function
 * @param objects
 * @return
 * @throws Exception
 */
public Object call( String function, Object... objects ) throws Exception ;

cfArray - object

The cfArray object makes it easy to work with CFML arrays with minimal overhead. It implements the java.util.List interface.

Any operations performed on a cfArray object will adjust the original CFML object.

public Object get(int index);
public boolean add(Object value);
public void add(int index, Object value);
public boolean addAll(Collection col);
public boolean addAll(int index, Collection col);

public void clear();
public boolean contains(Object arg0);
public boolean containsAll(Collection arg0);
public int indexOf(Object arg0);
public boolean isEmpty();
public Iterator iterator();

public int lastIndexOf(Object arg0);
public ListIterator listIterator();
public ListIterator listIterator(int arg0);

public boolean remove(Object arg0);
public Object remove(int index);
public boolean removeAll(Collection arg0);
public boolean retainAll(Collection arg0);

public Object set(int index, Object value);
public int size();
public List subList(int arg0, int arg1);

public Object[] toArray();
public Object[] toArray(Object[] arg0);

All index references, are 0 (zero) based, unlike CFML, which is 1 (one) based.

cfStruct - object

The cfStruct object makes it easy to work with CFML structures with minimal overhead. It implements the java.util.Map interface.

Any operations performed on a cfStruct object will adjust the original CFML structure.

public java.lang.Object get(String name);
public Object get(Object arg0);

public void put(String name, Object value);
public Object put(Object name, Object value);
public void putAll(Map arg0)

public void clear();
public Object remove(Object arg0);

public boolean containsKey(Object key);
public boolean containsValue(Object arg0);
public Collection values();
public Set entrySet();
public Set keySet();

public boolean isEmpty();
public int size();

cfQuery - object

The cfQuery object makes it easy to work with CFML arrays with minimal overhead.

Any operations performed on a cfQuery object will adjust the original CFML query object.

public String[] getColumns();
public int size();

public int addRow();
public void deleteRow(int index);

public Object get(int iRow, int iCol);
public String getString(int iRow, int iCol);
public int getInt(int iRow, int iCol);
public long getLong(int iRow, int iCol);
public boolean getBoolean(int iRow, int iCol);
public Date getDate(int iRow, int iCol);

public void set(int iRow,int iCol,String data);
public void set(int iRow,int iCol,int data);
public void set(int iRow,int iCol,boolean data);
public void set(int iRow,int iCol,Date date);

All index references, are 0 (zero) based, unlike CFML, which is 1 (one) based.

Hints and Tips

  • In order for this extension to operate correctly, the tools.jar must be in the classpath of the Application server
  • Java 6 is minimum requirement for this plugin
  • Each Java snippet is compiled and operated in memory. No overhead of disk is incurred
  • All index operations are 0 (zero) based
  • Dynamic compilation is performed at page load time, and performed once.
  • The common Java packages are imported automatically for you (java.io, java.lang, java.util, java.net, java.math)
  • Any class you wish to use, specify its full package name
  • Use cfArray, cfStruct, cfQuery for manipulating existing CFML data elements as they are extremely fast and provide as late-binding as possible for all inner objects
  • The full Java language and syntax is available. No preprocessing by OpenBD is performed.
  • The Attribute store associate with the cf context is a raw storage mechanism for objects with no CFML transformations
  • Use the optional JARLIST attribute to specify which jar files the compiler should use. Jar files must be in the /WEB-INF/lib/ folder

Here is an example of interacting with the popular MongoDB after dropping the jar file into the /WEB-INF/lib/ folder. We add the jar file to the tag, and then we look to see if we have initialised this before, and if not, we create a new one, and put it into the java object store.

<cfscript language="java" jarlist="mongo-2.0.jar" import="com.mongodb.*">
Mongo mongoConnection = (Mongo)cf.getAttribute("mongo");

if ( mongoConnection == null ){
  try{
    Mongo mongoConnection = new Mongo();
    cf.setAttribute( "mongo", mongoConnection );
  }catch(Exception e){
    cf.print( "Something went wrong: " + e.getMessage() );
  }
}

</cfscript>