[p]This chapter includes information about creating tags in Java using the Lasso Java API (LJAPI). [/p]
[p]An LJAPI module is essentially a regular Java class file. When Lasso Professional 8 first starts up, it looks for module files (Windows DLLs or Mac OS X DYLIBS) in its [code]LassoModules[/code] folder. As it encounters and loads an LJAPI 7 module, it launches the JVM and proceeds to scan the folder for other LJAPI modules. Upon finding a Java class file, Lasso attempts to determine if it is derived from the [code]com.omnipilot.lassopro.JavaModule[/code] class. If it is, then Lasso loads the class while performing necessary instantiation and calls the [code]registerLassoModule()[/code] function that is implemented in that class: [/p]
[pre]public void registerLassoModule() [/pre]
[p]At this point, the module must call the following method as many times as needed, once for each tag implemented by the module: [/p]
[pre]void registerTagModule( String moduleName,
String tagName,
String methodName,
int flags,
String description); [/pre]
[p]After a tag module is registered with Lasso Professional 8, it can provide information about the name of the tag and the name of the Java method that is implementing that tag. It also can provide a short description, and any special flags describing unique features implemented by that tag. [/p]
[p]All registered information is later used for dispatching the task of executing a particular tag found in a [code].lasso[/code] Lasso page to an appropriate LJAPI module, or executing a data source action. [/p]
[p]For example, the following code tells Lasso to call the Java class called [code]ZipCountTag[/code] whenever the code [code][Zip_Count][/code] is encountered inside a [code].lasso[/code] Lasso page. The first parameter of the [code]registerTagModule[/code] method is the module name, the second is the tag name, and the third one is the name of the function implementing the tag. The last two parameters are the tag type flag and a short description: [/p]
[pre]public void registerLassoModule()
{
registerTagModule( "ZipCountTag", "zip_count", "myZipCountFunc",
FLAG_SUBSTITUTION, "Count items in a zip file" );
} [/pre]
[p]Below is the code needed in a Lasso page in order to get the custom tag to execute: [/p]
[pre]<html>
<body>
Count of items in the LjapiTest.zip file:
[Zip_Count:'LjapiTest.zip']
<!-- This should display "2" when page executes -->
</body>
</html> [/pre]
[p]This will produce the following: [/p]
[pre]➜
2 [/pre]
[p]The following section provides a walk-through of building an example tag to show how LJAPI features are used. This code will be most similar to the sample ZipCountTag LJAPI project. In order to build this project, copy the [code]ZipCountTag[/code] project folder and edit the project files inside it. [/p]
[p]The module relies on a Java class library to do most of the work, particularly the [code]java.util.zip[/code] package which provides a variety of functions for manipulating the contents of Zip files—standard compressed archives widely used on the Internet. [/p]
[p]The [code][Zip_Count][/code] tag implemented in the [code]ZipCountTag[/code] LJAPI module simply displays the number of files and directories stored in a Zip file when called from a Lasso page. [/p]
[pre][Zip_Count: -Zipfile='LJAPITest.zip', -FilesOnly] [/pre]
[p]Notice the required convention of placing a dash in front of all named parameters in order to make them easier to spot in the Lasso code, and prevent ambiguities in the Lasso parser. Notice the tag takes one string parameter named [code]-Zipfile[/code], and an optional keyword parameter named [code]-FilesOnly[/code]. In general, Lasso does not care about the order in which you pass parameters, so plan to make this tag as flexible as possible by not assuming anything about the order of parameters. The following variations should work exactly the same. [/p]
[pre][Zip_Count: -Zipfile='LJAPITest.zip', -FilesOnly] [/pre]
[pre][Zip_Count: -FilesOnly, -Zipfile='LJAPITest.zip'] [/pre]
[p]Shown below is the code for the substitution tag module. Line numbers are provided to the left of each line of code, and are referenced in the Substitution Tag Module Walk-Through section. [/p]
[note][b]Note: [/b]The line numbers shown refer to the line numbers of the code in the actual file being created, not as shown in this page. Some single lines of code may carry into two or more lines as shown on this page. [/note]
1 import com.omnipilot.lassopro.*; 2 import java.io.*; 3 import java.util.*; 4 import java.util.zip.*; 5 public class ZipCountTag extends LassoTagModule 6 { 7 public void registerLassoModule() 8 { 9 registerTagModule( "Zip", "zip_count", "myZipCountFunc", 10 FLAG_SUBSTITUTION, "Count items in a zip file" ); 11 } 12 13 public int myZipCountFunc(LassoCall lasso, int action) 14 { 15 int err = ERR_NOERR; 16 try { 17 IntValue count = new IntValue(); 18 err = lasso.getTagParamCount( count ); 19 if ( err == ERR_NOERR && count.intValue() > 0 ) 20 { 21 String zipName = null; 22 boolean filesOnly = false; 23 LassoValue param1 = new LassoValue(); 24 LassoValue param2 = new LassoValue(); 25 err = lasso.findTagParam( "
-zipfile", param1 ); 26 if ( err != ERR_NOERR || param1.name() == null ) 27 lasso.getTagParam( 0, param1 ); 28 if ( param1.name() == null || param1.name().length() == 0 ) 29 return LassoErrors.InvalidParameter; 30 if ( count.intValue() > 1 && 31 lasso.getTagParam( 1, param2 ) == ERR_NOERR ) 32 filesOnly = param2.equalsIgnoreCase("
-filesonly"); 33 String filePath = lasso.fullyQualifyPath( param1.name() ); 34 filePath = lasso.resolvePath( filePath ); 35 filePath = lasso.getPlatformSpecificPath( filePath ); 36 ZipFile zip = new ZipFile( filePath ); 37 Enumeration enum = zip.entries(); 38 ZipEntry entry = null; 39 int zipcount = 0; 40 while ( enum.hasMoreElements() ) 41 { 42 entry = (ZipEntry)enum.nextElement(); 43 if ( !filesOnly || !entry.isDirectory() ) 44 ++zipcount; 45 } 46 err = lasso.outputTagData( Integer.toString( zipcount ) ); 47 zip.close(); 48 } 49 } 50 catch ( java.io.Exception e ) 51 { 52 lasso.setResultMessage( e.getMessage() ); 53 return LassoErrors.FileNotFound; 54 } 55 return err; 56 } 57 }
[p]This section provides a step-by-step walk-through for building the substitution tag module. [/p]
- First, import [code]com.omnipilot.lassopro.*[/code] classes as shown in line 1. 1 import com.omnipilot.lassopro.*; 2 import java.io.*; 3 import java.util.*; 4 import java.util.zip.*; [#2]Define your class to be a subclass of the [code]omnipilot.lasso.LassoSubstitutionTag[/code] class. 5 public class ZipCountTag extends LassoTagModule [#3]Define the[code] registerLassoModule[/code] method. 7 public void registerLassoModule() { [*none]Every Lasso module must implement the [code]registerLassoModule()[/code] method. This method will be called by Lasso at startup, giving your module a chance to register its tags. [#4]Register the tags implemented by your module. 9 registerTagModule( "Zip", "zip_count", "myZipCountFunc", 10 FLAG_SUBSTITUTION, "Count items in a zip file" ); [*none]Call this method as many times as there are tags implemented in your module. This method takes five parameters: the module name, the name of Lasso tag, the name of the Java method implemented by your module (to be called when the corresponding Lasso tag is found on the page), any additional tag feature flags, and a brief tag description. [#5]Define the tag formatting method with the same name as indicated in the third parameter of the corresponding [code]registerTagModule[/code] call. 13 public int myZipCountFunc(LassoCall lasso, int action) [*none]This is the method that does all the work. Every tag registered by your module can have its own formatting method. Its purpose is to perform an action based on the parameters passed to the tag and/or current request properties. Most substitution tags would output the data, although some may perform other actions such as setting page variables, manipulating files, etc. [*none]When Lasso encounters one of the tags registered by your module, it creates new module instance and calls the corresponding method, passing the [code]LassoCall[/code] object which then can be used by the module for calling back into Lasso. [#6]Define the variable to hold the result code returned by various [code]LassoCall[/code] methods. 15 int err = ERR_NOERR; [#7]Our [code][Zip_Count][/code] Lasso tag takes one required and one optional parameter. We need to make sure at least one parameter (filename) is present, otherwise we won’t be able to continue. 17 IntValue count = new IntValue(); 18 err = lasso.getTagParamCount( count ); 19 if ( err == ERR_NOERR && count.intValue() > 0 ) [#8]Define the storage for the zip file name, optional [code]-FilesOnly[/code] parameter, and [code]LassoValue[/code] object to be used with various [code]LassoCall[/code] methods. 21 String zipName = null; 22 boolean filesOnly = false; 23 LassoValue param = new LassoValue(); [#9]Our tag should be flexible enough to accept both named and unnamed versions of the required parameter. First, try to search for the parameter by a name. 25 err = lasso.findTagParam( "-zipfile", param1 ); [#10]If this fails, assume the first unnamed tag parameter to hold the file path name. Call [code]getTagParam()[/code] with the index [code]0[/code] (tag parameter numbering is zero-based). 26 if ( err != ERR_NOERR || param1.name() == null ) 27 err = lasso.getTagParam( 0, param1 ); [#11]Next, make sure we’ve got a valid value. If the filename parameter contains an empty string, immediately return from our method, passing [code]InvalidParameter[/code] result code back to Lasso. 28 if ( err != ERR_NOERR || param1.name().length() == 0 ) 29 return LassoErrors.InvalidParameter; [#12]Our tag also accepts an optional boolean parameter [code]-FilesOnly[/code], indicating that directories must be ignored while counting zip file items. If more than one parameter was supplied to our tag, try determining if it was the optional [code]-FilesOnly[/code] parameter. 30 if ( count.intValue() > 1 && 31 lasso.getTagParam( 1, param2 ) == ERR_NOERR ) 32 filesOnly = param2.equalsIgnoreCase("-filesonly"); [#13]The path to the zip file is relative to the server root. In order to find out the actual location of the file, you can use a number of [code]LassoCall[/code] class methods suited for converting a file path name into a fully qualified platform-specific path. [code]fullyQualifyPath()[/code] turns a relative path into a from-the-server-root path. [code]resolvePath()[/code] converts a from-the-root path into a full internal path. Finally, [code]getPlatformSpecificPath()[/code] will convert an internal path name into a platform-specific path name. 33 String filePath = lasso.fullyQualifyPath( param1.name() ); 34 filePath = lasso.resolvePath( filePath ); 35 filePath = lasso.getPlatformSpecificPath( filePath ); [#14]Now attempt to instantiate a [code]ZipFile[/code] object using a platform-specific path name. Any exceptions thrown by the object constructor will be caught by the try/catch block wrapping our method's body. 36 ZipFile zip = new ZipFile( filePath ); [#15]Prepare to enumerate items in the zip file. 37 Enumeration enum = zip.entries(); [#16]Define the storage for holding the zip item count. 38 ZipEntry entry = null; 39 int zipcount = 0; [#17]Iterate through the zip archive items, incrementing the counter for all items matching our criteria. 40 while ( enum.hasMoreElements() ) 41 { 42 entry = (ZipEntry)enum.nextElement(); 43 if ( !filesOnly || !entry.isDirectory() ) 44 ++zipcount; 45 } [#18]Output the resulting zip file item count. 46 err = lasso.outputTagData( Integer.toString( zipcount ) ); [#19]Close the zip file. 47 zip.close(); [#20]Make sure that any possible exceptions are handled correctly in your code. In this particular case, we simply pass the message retrieved from the Exception object back to Lasso, and return the [code]FileNotFound[/code] error code. For a complete listing of error codes, see the variables defined in the [code]LassoErrors[/code] class. 50 catch ( Exception e ) 51 { 52 lasso.setResultMessage( e.getMessage() ); 53 return LassoErrors.FileNotFound; 54 }