Inside Coldfusion MX
Ever since ColdFusion 4.5, developers have been able to call Java class files directly from CFOBJECT. Since then, Macromedia has made great strides in increasing the capability of CFOBJECT to work with Java classes and EJBs and in increasing CFOBJECT's robustness and performance. Before you use any Java class with CFOBJECT, you have to make sure it is specified in the Java classpath in the ColdFusion Administrator. You might also have ColdFusion automatically or dynamically load your classes by putting any class you are working with in either of these directories:
Note Dynamic class loading is really a feature meant to help speed up your development process and make your life easier, but it should not be used in production. This is because it causes performance issues due to ColdFusion having to check time stamps during disk I/O operations. So make sure you use just the classpath to register classes in production.
ColdFusion checks the time stamp on the file when it creates an object that is defined in either directory, even when the class is already in memory. If the file that contains the class is newer than the class in memory, ColdFusion loads the class from that directory. If you do not want to use automatic class loading, make sure you put all classes in the JVM classpath. Classes located on the JVM classpath are loaded once per server lifetime. To reload these classes, you need to stop and restart ColdFusion Server. Custom tag libraries that have been placed in the web_root/WEB-INF/lib directory are automatically reloaded if necessary when you import the library. To call a class that you have placed on the classpath or in one of the directories, you can use CFOBJECT like this: <cfobject type="Java" name="varname"> This causes CFOBJECT to load the class into memory, but it does not actually make an instance of the object at that time. Only static methods and fields are accessible immediately after the call to CFOBJECT. If you call a public method on the object without first calling the init method, there is an implicit call to the default constructor, but you do not get access to an object instance. To call an object constructor explicitly and thereby create an instance of the object, use the special ColdFusion init method with the appropriate arguments after you use the CFOBJECT tag. For example: <cfobject type="Java" name="myObj"> <cfset ret=myObj.init(arg1, arg2)> Note ColdFusion uses a special identifier called the init method that calls the new function on the class constructor. If you have written a Java class that has an init method, a name conflict exists, and you cannot call the object's init method. To have persistent access to an object, you must use the init function because it returns a reference to an instance of the object, and CFOBJECT does not.
Let's do a quick example. Let's make a very simple Java class like the one in Listing 22.6. Listing 22.6 testCfobject.java
class testCfobject { public string getString() return ("CFOBJECT is great"); } } After you have compiled the code and placed it in the web_root/WEBINF/classes directory, you can call it using CFOBJECT as in Listing 22.7. Listing 22.7 testcfobject.cfm
<cfobject type="java" action="create" name="test" > <cfset testoutput = test.getString()> <cfoutput> #testoutput# </cfoutput> As you can see, this is pretty straightforward. We have a class with a single method, and we access that method by using the following: <cfset testoutput = test.getString()> In general, whenever we want to call a method, we use the following syntax: <cfset returnmethod = obj.method()> If the method has one or more arguments, you need to put the arguments inside the parentheses and separate them with commas. <cfset x = 10> <cfset retVal = obj.Method1(x, "a string")> Let's try a bit more complex example. Let's say you are building a photo album application, and you need to be able to parse through a directory of images and convert all of them into thumbnails. Well, you can easily write a Java class that takes a JPEG image of some size and converts it to another, smaller JPEG thumbnail. Listing 22.8 provides an example. Listing 22.8 thumbnail.java
//Thumbnail generator //Usage java Thumbnail SomeJpeg.jpeg TheThumb.jpeg 50 import java.awt.Image; import java.awt.Graphics2D; import java.awt.geom.AffineTransform; import java.awt.image.BufferedImage; import java.io.IOException; import java.io.OutputStream; import java.io.FileOutputStream; import javax.swing.ImageIcon; import com.sun.image.codec.jpeg.JPEGCodec; import com.sun.image.codec.jpeg.JPEGImageEncoder; class Thumbnail { public static void main(String[] args) { createThumbnail(args[0], args[ 1], Integer.parseInt(args[2])); } public static void createThumbnail( String orig, String thumb, int maxDim) { try { // Get the image from a file. Image inImage = new ImageIcon( orig).getImage(); // Determine the scale. double scale = (double)maxDim/( double)inImage.getHeight(null); if (inImage.getWidth( null) > inImage.getHeight(null)) { scale = (double)maxDim/( double)inImage.getWidth(null); } // Determine size of new image. //One of them // should equal maxDim. int scaledW = (int)( scale*inImage.getWidth(null)); int scaledH = (int)( scale*inImage.getHeight(null)); // Create an image buffer in //which to paint on. BufferedImage outImage = new BufferedImage(scaledW, scaledH, BufferedImage.TYPE_INT_RGB); // Set the scale. AffineTransform tx = new AffineTransform(); // If the image is smaller than //the desired image size, // don't bother scaling. if (scale < 1.0d) { tx.scale(scale, scale); } // Paint image. Graphics2D g2d = outImage.createGraphics(); g2d.drawImage(inImage, tx, null); g2d.dispose(); // JPEG-encode the image //and write to file. OutputStream os = new FileOutputStream(thumb); JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(os); encoder.encode(outImage); os.close(); } catch (IOException e) { e.printStackTrace(); } System.exit(0); } } To call this class, we need to provide it with several properties and call its method. We also have to make sure the data passed from ColdFusion to the Java object matches Java data types by using a special function called JavaCast. Listing 22.9 estthumbnail.cfm
<cfobject action="create" type="java" name="thump"> <cfset scale=(JavaCast("int", "100"))> <cfset myVar=thump.createThumbnail("E:\dev\largeimage.jpg", "E:\dev\newimage.jpg", scale)> As you can see, we have used the JavaCast function to set the value of the variable scale to be an integer with a value of 100. We have to do this because, although ColdFusion attempts to match Java types to ColdFusion types (as listed in Table 22.1), it often runs into issues in doing so.
To resolve this issue, ColdFusion provides the JavaCast function, which enables you to specify the Java type of a variable. The function takes two parameters: a string representing the Java data type and a variable whose type you are setting. JavaCast(type, variable) You can specify these Java data types: bool, int, long, float, double, and String but you cannot specify structs or Java date/time variables. In the case of data and time, you need to pass them as strings from ColdFusion and have the Java program convert those string values into date values. Know that if you call your ColdFusion template in your browser after compiling and placing your Java class in your classes directory, you should get your JPEG image converted from a large image into a thumbnail. |