Developing exteNd Director Applications
CHAPTER 11
This chapter gives an overview of how to access exteNd Director services programmatically. It contains the following sections:
To write Java code for exteNd Director applications, you use exteNd Director API classes in your Java code and call their methods. The exteNd Director API provides public classes (and interfaces) organized into several packages, which themselves are organized by subsystem.
The exteNd Director API is based on the Java 2 APIs (J2SE and J2EE). That means it includes classes that inherit from Java 2 classes and implement Java 2 interfaces. If you're familiar with the Java 2 APIs, you'll have a good foundation for understanding and using the exteNd Director API.
Java is a standard language for Web applications and you'll use it in a standard way when developing exteNd Director applications. For instance, you'll:
Write classes that represent the objects in your application, including fields (variables) for each object's data and methods for the actions it can perform
Organize classes in packages, directory-like hierarchies that let you group related classes and make them easy to locate
Bundle packages and classes in JARs (and other archive files), used for providing smaller, faster downloads to clients and for facilitating certain deployment operations
exteNd Director supports the Java 2 platform, including:
These encompass the core Java language and a variety of Java APIs.
The core Java language is the syntax you use to perform basic programming chores. It includes:
Much of this syntax is modeled after C and C++. JavaScript programmers will find some similarities too (although Java and JavaScript differ in other significant ways).
API stands for application programming interface. In Java, an API is a collection of public classes (in one or more packages) that:
Offers a reusable solution for implementing a particular area of application features or services
Defines public methods you can call (and possibly public fields you can access)
Provides a published specification (typically in javadoc format)
For business programming, where productivity is especially important, you'll always access one or more APIs. For example, the Java standard (J2SE) API provides many of the most fundamental capabilities you'd want to build into any application (including support for graphical user interfaces, input/output, data type manipulation, threading, networking, security, SQL, internationalization, and a lot more). There's no need to develop these capabilities yourself.
Other Java and vendor APIs (such as the exteNd Director API) take you beyond generic application services to fulfill higher-level system and business needs.
If you're new to Java or just need to explore a specific Java topic, try the following recommended learning resources.
Books There are many other Java books available, but some good ones are:
Core Java by Cay S. Horstmann and Gary Cornell, published by Prentice-Hall
Java in a Nutshell by David Flanagan, published by O'Reilly & Associates
Teach Yourself Java 2 in 21 Days by Laura Lemay, published by Sams
The Java Programming Language by Ken Arnold and James Gosling, published by Addison-Wesley
Web sites There are many Java sites on the Web, but some good ones are:
When building an application, you'll use particular Java APIs depending on the features or services that application requires. To help you choose which APIs you need, Sun has grouped them in different editions of the Java 2 platform:
Once you're familiar with the basics of Java (including the core language and J2SE API), you can learn about J2EE and its use from the following resources.
Both of these resources are available at java.sun.com.
The exteNd Director API provides public classes and interfaces organized into several packages, which themselves are organized by subsystem.
Use the following table to find the packages that provide the major exteNd Director features or services you want in your application:
Functional area |
Packages |
---|---|
Content Management |
|
Directory |
|
Framework |
|
Portal |
|
Rules |
|
Search |
|
Security |
|
User |
|
Utilities and Helper classes |
|
WebDAV |
|
Workflow |
|
The name exteNd Director API refers to all of the public packages. You'll also see the term API applied to certain subsets of these packages. For instance, the name Content Management API is typically used to refer to this group of packages:
Just remember that these other APIs are simply convenient labels for talking about specific portions of the full API.
exteNd Director provides a complete API specification in javadoc format. This specification details all of the packages, classes, interfaces, and members in the public exteNd Director API and includes links into the Java 2 API documentation. It's an indispensable reference for all the exteNd Director programming you do in Java.
For complete reference information on the exteNd Director API, see the API Reference book in online help.
To access the services of an exteNd Director subsystem, you first need to use a factory to get a reference to a manager object for the subsystem. You can do this in one of the following ways:
When you use a delegate, you do not need to know or care whether the service is using a local manager object or a remote object. Therefore, in most situations, you should use delegates to access subsystem services.
Each subsystem provides one or more factory classes called EboFactory that are suitable for accessing manager objects for the subsystem.
Once you have a reference to the manager object, you can call methods on that object just as you would call methods on any Java class.
Several exteNd Director subsystems let you use delegates to access subsystem services. A delegate is a wrapper that hides the location of a service. The delegate model follows the J2EE Business Delegate pattern.
When you use a delegate, you do not need to know or care whether the service is using a local manager object or a remote object. The delegate initially attempts to instantiate a local manager. If this fails, it attempts to use the remote object instead. This approach allows developers to use the same code on clients and servers to instantiate services.
exteNd Director provides one or more delegates per manager. For example: the Content Management subsystem has a single delegate, but the User subsystem has four delegates (User, Group, UserMeta, and UserPersonalization).
To use a delegate to access a subsystem service, you need to call a delegate accessor method on the custom EboFactory class for the subsystem you want to use. The EboFactory class that has the method you need is typically located in the subsystem package hierarchy in a subpackage called client.
The delegate model is supported by the following subsystems:
Examples For example, to use the Content Management delegate to access content management services, you might execute this code:
import com.sssw.cm.api.*; ... EbiContentMgmtDelegate contentMgr = com.sssw.cm.client.EboFactory.getDefaultContentMgmtDelegate(); ...
Once you have a reference to the delegate, you can simply invoke methods on the delegate. Here's an example that shows how you might do this:
EbiDocument tempdoc = contentMgr.getDocument(context,selectedDoc);
Similarly, to use the User delegate to access User subsystem services, you might execute this code:
import com.sssw.fw.usermgr.api.*; ... EbiUserDelegate userMgr = com.sssw.fw.usermgr.client.EboFactory.getUserDelegate(); EbiUserInfo userinfo = userMgr.createUser(context); ...
Using a delegate to access a local manager The delegate initially attempts to instantiate a local manager. If this fails, it attempts to use a remote object instead. This approach can mask errors on an attempt to use a local manager only. To help you identify situations where the local instantiation fails, the delegate constructors display an informational message in the log when an instantiation fails.
You can also force the delegate to use a local manager by using a parameterized delegate factory constructor. To do this, you pass in a string indicating that you want a local delegate only. The EbiDelegate interface provides a constant you can use to indicate that you want a local delegate. If the constructor fails, it will not swallow the instantiation error on the local manager. Here's an example:
import com.sssw.fw.api.*; ... EbiUserDelegate ud = com.sssw.fw.usermgr.client.EboFactory.getUserDelegate(EbiDelegate.SERVICE_LOCAL);
Some of the exteNd Director subsystems provide a way to get a manager object directly. For example, the EboFactory class for the Portal subsystem (com.sssw.portal.factory.EboFactory) has several methods you can use to get manager objects, such as:
For example, to get a reference to a portal manager from a portlet you might use this code:
import javax.portlet.*; ... PortletContext context = getPortletContext(); EbiPortalManager portalMgr = com.sssw.portal.factory.EboFactory.getPortalManager(context); String userUUID = portalMgr.getUserPortalInfo(context).getUserUUID(); ...
Some of the subsystems for which delegates are provided also support direct access to manager objects. This support can be used in situations where the subsystem is running locally.
Accessing a rule manager The Rule subsystem requires that you use a different technique to get a manager. The Rule subsystem allows you to work with multiple rule manager instancesunlike the other subsystems, which only allow you to have a single manager instance. Therefore, to use a rule manager, you need to instantiate the object, as shown here:
EbiRuleManager rm = com.sssw.re.factory.EboFactory.createRuleManager( "sample" );
Errors and exceptions can occur in an exteNd Director application and can come from many sources: for example, bad input from a user, problems with the application server, database errors, and inappropriate operations on exteNd Director objects.
In developing your application, you need to plan how to handle errors and exceptions and how to let the user know the application's state. Your team will want to establish guidelines for consistently displaying error messages. Most applications will want to fulfill a set of error-handling goals such as these:
Java provides the opportunity to handle errors in a reliable, consistent way. However, you must be aware of how the application flow is affected by the way you catch exceptions. For practical advice, see Practical Java Programming Language Guide by Peter Haggar, published by Addison-Wesley.
The error handling discussed here is an extension of standard Java error handling that you should do in any Java application. For more information, see the Java documentation from Sun Microsystems.
The following table describes the base exception classes in the com.sssw.fw.exception package. An exception can occur for various reasons during the runtime processing of an exteNd Director application. They are all extensions of the JDK base class Exception.
The most common exception is the NullPointerException. To avoid it, be thorough about checking return values for null. For many exteNd Director methods, a return value of null is a valid response and tells you that the object you want does not exist.
In these situations, you should always make sure you have a valid object:
When you call methods in your application code that declare exceptions, you must enclose them in try/catch/finally blocks, as you would in any Java application. For runtime exceptions, you can use try/catch/finally blocks wherever the application's state would become invalid if an error occurs.
When your code catches an exception, you should display information about the problem to users so they know what is not working. For ideas, see Displaying messages. You should also do something appropriate to return the application to an error-free state. Don't code empty catch blocks or simply log the exception.
Don't do this These examples will not help the application or the user repair a problem:
try { // code that could throw an exception } catch (Exception e) { } try { // code that could throw an exception } catch (Exception e) { System.err.println("Exception: " + e.toString() ); e.printStackTrace(context.getLocale()); }
A better way Do write catch blocks that prepare a message for the user and clean up whatever failed. The catch block can also re-throw the exception so that the calling method handles it.
These catch blocks catch two different exceptions and store an error message in the session. When the application finds a message in the session for the error key, it displays the message to the user. Constants identify the keys used for the session data.
catch (EboUnrecoverableSystemException e) { // send trace to server console e.printStackTrace(context.getLocale()); // save error message for later display String errMsg = e.getMessage(context.getLocale()); m_portalSession.setValue( COMP_KEY, ERROR_MESSAGE_KEY, errMsg); } catch (Exception e) { // send trace to server console e.printStackTrace(context.getLocale()); // get the appropriate error message for later display ResourceBundle myResources = ResourceBundle.getBundle("MyResources", context.getLocale()); String errMsg = myResources.getString("ERR_CAT_UNKWN"); m_portalSession.setValue( COMP_KEY, ERROR_MESSAGE_KEY, errMsg); }
For information about the resource bundle shown here, see Displaying errors in the user's language.
TIP: Instead of sending stack traces to the server console directly, you can use the exteNd Director logging facility, which identifies the output in useful ways. For information, see Logging Information.
One useful way to think about messages is to distinguish between messages that help users complete a task versus messages that tell them about error conditions out of their control.
Application code Your application logic might display these two types of messages in different ways. For example, it might display helpful messages right on the form that the user is filling out. To display error messages, you might replace the form as the content and explain why the form can't be displayed.
Pages A page can display errors by redirecting the browser to an error page that explains the error. JavaServer Pages provides a mechanism for displaying error pages. When an error occurs, the JSP page redirects the browser to an error page that you've created. For information on how to design error pages for JSP pages, see documentation from Sun Microsystems (java.sun.com).
If there has been a chain of exceptions that the application has re-thrown, the most recent exception may not have the most relevant message. You can get messages for all the exceptions that have occurred by checking the parent exceptions.
Example of examining parent exceptions In this example, the type of exception being caught could be any of the framework exception classes. The code concatenates all the messages for any exceptions that have been wrapped and re-thrown:
catch (EboException e) { StringBuffer msg == ""; java.lang.Throwable parent = e; while (parent != null) { msg.append( parent.getMessage(context.getLocale() + "\n"); parent = EboException.getParentException(parent); } }
To make your exteNd Director application useful internationally, you will want to display messages in the language of the user. You can get the user's locale from the EbiContext object with the getLocale() method. You can use it to get appropriately translated error messages:
For exceptions, call getMessage() with a locale argument. exteNd Director provides localized versions of exception messages.
e.getMessage(context.getLocale())
Use resource bundles for storing message strings and access them using the user's locale. For each locale you want to support, you can provide a set of translated messages in subclassed bundles. For information, see java.util.ListResourceBundle and the example below.
You can get the user's locale from the EbiContext object with the getLocale() method.
The MyErrorsResource class has one string in its array of messages. A second class provides the same string in French. You can provide additional subclasses of ListResourceBundle in all the languages you want to support. The name of each uses the name for your default bundle plus a language code. To find out more about locales and language codes, see java.util.Locale.
class MyErrorsResource extends ListResourceBundle { public Object[][] getContents() { return contents; } static final Object[][] contents = { // LOCALIZE THIS {"ERR_CAT_UNKWN", "An unknown error has occurred while attempting to save the category information."}, // unknown error for categories // END OF MATERIAL TO LOCALIZE }; } //==================== class MyErrorsResource_fr extends ListResourceBundle { public Object[][] getContents() { return contents; } static final Object[][] contents = { // LOCALIZE THIS {"ERR_CAT_UNKWN", "Une erreur inconnue a arrivé en tentant à épargne l'information de catégorie."}, // unknown error for categories // END OF MATERIAL TO LOCALIZE }; }
To access the string for a particular error situation, you need to know the key you have associated with the string. When you get the bundle, the JDK uses the locale to find the right version of the bundles you have provided. If no bundle matches the locale, the default bundle is used:
ResourceBundle myResources = ResourceBundle.getBundle( "MyErrorsResources",context.getLocale()); String msg = myResources.getString("ERR_CAT_UNKWN");
Copyright © 2004 Novell, Inc. All rights reserved. Copyright © 1997, 1998, 1999, 2000, 2001, 2002, 2003 SilverStream Software, LLC. All rights reserved. more ...