Developing exteNd Director Applications

CHAPTER 11

Coding Java for exteNd Director Applications

This chapter gives an overview of how to access exteNd Director services programmatically. It contains the following sections:

 
Top of page

About coding Java for exteNd Director applications

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.

 
Top of page

Using Java

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:

 
Top of section

Java platform support

exteNd Director supports the Java 2 platform, including:

These encompass the core Java language and a variety of Java APIs.

 
Top of section

About the core language

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).

 
Top of section

About APIs

API stands for application programming interface. In Java, an API is a collection of public classes (in one or more packages) that:

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.

 
Top of section

Resources for learning Java

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:

Web sites   There are many Java sites on the Web, but some good ones are:

 
Top of page

Using the Java APIs

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:

Edition

Description

J2SE includes the standard API

Serves as the foundation for virtually any Java application you build

J2EE includes several APIs

For adding specific enterprise-level features and services to a Java application, including:

  • Enterprise JavaBeans (EJB)

  • Java Servlets

  • JavaServer Pages (JSP)

  • Java Portlets

  • JDBC Standard Extension

  • Java Transaction (JTA)

  • JavaMail

  • Java Message Service (JMS)

  • Java Naming and Directory Interface (JNDI)

  • RMI-IIOP

  • JavaBeans Activation Framework (JAF)

 
Top of section

Resources for learning J2EE

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.

Resource

Description

Java 2 SDK, Enterprise Edition Documentation Bundle

An index to J2EE learning and reference materials from Sun, with links to various documents and Web sites

API specification

A reference guide to the J2EE APIs, in javadoc format

Both of these resources are available at java.sun.com.

 
Top of page

Using the exteNd Director API

 
Top of section

exteNd Director API packages

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

com.sssw.cm.api

com.sssw.cm.client

com.sssw.cm.event.api

com.sssw.cm.event.util

com.sssw.cm.factory

com.sssw.cm.task.api

com.sssw.cm.util

Directory

com.sssw.fw.directory.api

com.sssw.fw.directory.client

Framework

com.sssw.fw.api

com.sssw.fw.cachemgr.api

com.sssw.fw.event.api

com.sssw.fw.event.factory

com.sssw.fw.exception

com.sssw.fw.factory

com.sssw.fw.log

com.sssw.fw.resource

com.sssw.fw.resource.api

com.sssw.fw.resource.factory

com.sssw.fw.resource.search

com.sssw.fw.task.api

com.sssw.fw.task.event

com.sssw.fw.task.factory

com.sssw.fw.timer

Portal

com.novell.afw.portal.proxy

com.novell.afw.component.api

com.novell.afw.component.factory

com.novell.afw.portlet.api

com.novell.afw.portlet.consumer.factory

com.novell.afw.portlet.factory

com.sssw.portal.api

com.sssw.portal.factory

com.sssw.portal.util

Rules

com.sssw.re.api

com.sssw.re.core

com.sssw.re.exception

com.sssw.re.factory

Search

com.sssw.search.api

com.sssw.search.client

com.sssw.search.factory

Security

com.sssw.fw.security.api

com.sssw.fw.security.client

User

com.sssw.fw.usermgr.api

com.sssw.fw.usermgr.client

Utilities and Helper classes

com.novell.afw.util

com.sssw.fw.util

com.sssw.fw.util.crypto

com.sssw.fw.util.http

com.sssw.fw.util.jndi

WebDAV

com.sssw.webdav.client

com.sssw.webdav.common

com.sssw.webdav.event.api

Workflow

com.sssw.wf.activity

com.sssw.wf.api

com.sssw.wf.client

com.sssw.wf.exception

com.sssw.wf.factory

com.sssw.wf.link

com.sssw.wf.ui.api

 
Top of section

exteNd Director API terminology

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.

 
Top of section

exteNd Director API reference documentation

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 more information    For complete reference information on the exteNd Director API, see the API Reference book in online help.

 
Top of page

Accessing subsystem services

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.

 
Top of section

Accessing a subsystem service by using a delegate

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);

 
Top of section

Getting a direct reference to a subsystem manager

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 instances—unlike 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" );

 
Top of page

Handling exceptions

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:

Goal

Information

Handle system exceptions

For example, when users try to access objects for which they don't have permission, you might inform them or redirect them to appropriate areas of the application. When an error occurs on the server or database, let the user know what to expect next.

Handle application exceptions

For example, your application needs to handle attempts to process an object in a way exteNd Director didn't intend or bad argument values that come from bad user input or saved data.

Provide feedback to users

A user needs to know whether requested operations succeeded or failed. If something fails because of the user's bad input, you need to supply a specific message telling the user what to do to make the input right.

Leave objects and data in a consistent state after an exception occurs

Treat operations on your business data transactionally. Plan for rolling back partially done operations so that the system correctly reflects what the user thinks happened. For example, if the user cancels an order or a system error occurs after you've saved most of the order data, be prepared to correct the state of the whole order.

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.

 
Top of section

Errors thrown by the exteNd Director API

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.

Exception Class

Description

EboException

This is the base exception class for the exteNd Director framework. Contains subclasses related to subsystem processing.

EboRuntimeException

A wrapper around java.lang.RuntimeException. Used for unexpected failures and instances when you cannot access the throws clause of a method's signature at runtime.

EboApplicationException

Indicates an error in the application. Typically, this signifies a programmer error such as an incorrect usage of an API method, illegal argument values, and so on.

 
Top of section

Avoiding errors

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:

Situation

What to check

Getting values from the whiteboard or session

Did a value actually exist for the specified key?

Getting input data from forms

Did the parameter you tried to retrieve exist? If not, should you tell the user about the missing data or supply a default value? Was the value the user entered appropriate? If not, you need to tell the user what is correct.

Cached objects

Has the object you want been purged? If so, you need to reconstruct it.

Restricted objects

Does the current user have rights to the requested object? If not, you need to tell the user why the operation can't proceed.

User profile and preference data

Does a value exist for a profile key? If not, do you need to write one for the next access?

 
Top of section

Catching errors

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 more information    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.

 
Top of section

Displaying messages

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).

Parent exceptions

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);
    }
  }

 
Top of section

Displaying errors in the user's language

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:

You can get the user's locale from the EbiContext object with the getLocale() method.

Example of using resource bundles

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 ...