| Oracle Internet File System Developer Reference Release 9.0.1.1.0 Part Number A90093-02 |
|
This chapter is focused on creation of a custom renderer. Topics include:
A renderer takes an object stored in the repository and outputs its content in a specific format. While the information output by a renderer may be identical to the document as it was input, it doesn't have to be. You can use a renderer to:
Once information in the original document has been parsed and stored as an object in the Oracle 9iFS, the object can be rendered in a variety of formats and layouts.
Any LibraryObject can be rendered. For example, you might write an application that calls an XML renderer to display the following:
Although, in general, any LibraryObject can be rendered, a custom renderer is likely to be written for the purpose of rendering specific kinds of objects. For example, while the IfsSimpleXmlRenderer can render any LibraryObject, a PurchaseOrder renderer can render only PurchaseOrder objects, and throws an exception if requested to render an object that it cannot handle.
Document objects are the most commonly rendered objects.
The output from a renderer is read-only and is not persistent. A renderer does not automatically create a Document object in the repository or a data file stored locally. If an application requires that the rendered output be available for later use, it is a post-rendering step to create a Document object or to save a data file locally.
Out-of-the-box, Oracle 9iFS includes a standard renderer for rendering PublicObjects as XML documents, the IfsSimpleXmlRenderer. For more information, see Chapter 10, "XML and the Oracle Internet File System".
The Oracle 9iFS rendering framework allows a developer to:
In the Oracle 9iFS Java class hierarchy, each Oracle 9iFS object has two representations:
Because rendering is a server-side operation, you must use the S_ classes.
Custom renderers can be used for many purposes:
Writing a custom renderer application requires these steps:
If one of the existing Oracle 9iFS renderers partially meets the needs of your application, you can subclass the existing renderer as a starting point. If not, you must create a custom class, directly implementing the oracle.ifs.server.renderers.Renderer interface.
Deploying a renderer involves compiling the renderer to create a.class file and placing the folder tree that contains the resulting.class file in the directory $ORACLE_HOME/ifs/custom_classes on the server where Oracle 9iFS is installed.
Registering a renderer connects a class of objects with a specific renderer. You can register the renderer through Oracle 9iFS Manager, an XML script, or the Java API.
Invoking the renderer calls the custom renderer, then renders the result to the client, attaching a stylesheet, if appropriate.
When creating a custom renderer, you can choose from two approaches:
oracle.ifs.server.renderers.Renderer interface.)
oracle.ifs.server.renderers.Renderer interface.
Whichever approach you choose, writing a custom renderer means implementing the Renderer interface, either directly or indirectly. The Renderer interface defines the following two methods:
These renderAsXxxx() methods allow the Oracle 9iFS clients or a custom application to render documents in the required format.
The syntax and arguments for each method are described below.
To write a custom renderer:
Every renderer must implement the standard constructor for a renderer. The standard constructor takes one parameter, as shown in Table 11-1.
Table 11-1 Standard Constructor Parameters
| Parameter | Datatype | Description |
|---|---|---|
|
|
S_LibrarySession |
The server-side representation of the current user's LibrarySession. |
public AirportDynamicRenderer(S_LibrarySession session) throws IfsException { m_IfsSession = ifs; }
Table 11-2 describes the parameters of the two renderAsXxxx() methods:
This example builds up a string containing the required content and uses the StringBufferInputStream class to convert the string to an InputStream, which is the object this method returns.
The overall structure of this example is:
The renderAsStream() method renders the specified LibraryObject as an InputStream.
public InputStream renderAsStream(S_LibraryObject lo, Hashtable options) throws IfsException { InputStream in = null; String stream = renderAsString(lo, options); in = new ByteArrayInputStream(stream.getBytes()); return in; }
The renderAsString() method calls the renderAirport method and returns the result as a string.
public String renderAsString(S_LibraryObject lo, Hashtable options) throws IfsException { String documentBody = null; documentBody = renderAirport(lo, options); return documentBody; }
This method:
public String renderAirport(S_LibraryObject lo, Hashtable options) { String resultOutput = ""; String xmlDoc = ""; DOMParser parser = new DOMParser(); try { //Retrieve the result from the IfsSimpleXmlRenderer //This call is referencing the IfsSimpleXmlRenderer, as defined //in the file AirportDefinitionPolicyBundle.xml. Reader reader = lo.renderAsReader("RenderXmlAirportDefinition", "AirportDefinitionXmlRenderer", null); BufferedReader r = new BufferedReader(reader); for (String nextLine = r.readLine(); nextLine != null; nextLine = r.readLine()) xmlDoc += nextLine; //Turn the XML String into an XML Document XMLDocument xml = ParseDocument(xmlDoc, parser); XMLDocument xsl = null; //Retrieves the XSL Style Sheet in a String format //from the Hashtable parameter (named options) passed in to the Renderer. String xslContent = (String)options.get("xsl"); if (xslContent != null && xslContent.length() > 0 && !xslContent.toUpperCase().equals("NONE")) { try { //Turn XSL String into an XML Document xsl = ParseDocument(xslContent, parser); } catch (Exception e) { System.err.println("XSL : " + e.toString()); } } if (xsl != null) { //Do the XSL Transformation. resultOutput = ProcessXML(xml, xsl, parser); } else { resultOutput = xmlDoc; } } catch (IfsException e) { resultOutput += ("<errorInRenderer type=\"IFS\">" + e.toString() + "</errorInRenderer>"); } catch (IOException e) { resultOutput += ("<errorInRenderer type=\"IO\">" + e.toString() + "</errorInRenderer>"); } //Return the result return resultOutput; }
For more information about renderers, see the classes shown in Table 11-3 in the Oracle 9iFS Javadoc.
Table 11-3 Renderer References in the Javadoc
For the protocol servers and other standard Oracle 9iFS components to access your custom renderer, the folder tree containing the class for the renderer must reside in the Oracle 9iFS CLASSPATH. Oracle 9iFS includes a special directory for this purpose. This directory, called custom_classes, is included in the CLASSPATH environment variable that the Oracle 9iFS server software uses.
To deploy a renderer:
.class file.
.class file in the directory $ORACLE_HOME/ifs/custom_classes on the server where Oracle 9iFS is installed.
|
Note: The compiled Java code must be copied to the native file system of the server, not to the Oracle 9iFS repository. |
The process of registering a renderer is a matter of mapping a connection between a class of objects and a specific renderer. The underlying mechanism for storing these mappings is a PolicyPropertyBundle object.
A PolicyPropertyBundle is a specific type of PropertyBundle object. In general, PropertyBundles are used to store name/value pairs. In the case of a PolicyPropertyBundle, a Policy is stored in each Property of the PropertyBundle. Each Policy contains the mapping between a class and a renderer for a specific protocol.
Each class in Oracle 9iFS has an associated PolicyPropertyBundle. When an object of a class is retrieved from the repository, Oracle 9iFS checks the associated PolicyPropertyBundle to determine which renderer to use to display the object, based on the protocol making the request for the object.
Because Oracle 9iFS includes multiple protocols (for example, FTP, HTTP, SMB), a specific Policy must be registered for each protocol; that is, one Policy each for HTTP, FTP, and SMB.
When a Property is used to store a Policy:
Each Policy object stores the attributes shown in Table 11-4:
Table 11-4 Policy Object Attributes
The process of registering a renderer connects a class of objects with a specific renderer. You can register a renderer using any of the facilities shown in Table 11-5:
Table 11-5 Renderer Registration Methods
No matter which facility you use, registering a render includes the following tasks:
For specific information about the attributes of Policy objects, see "Using PolicyPropertyBundles to Register Renderers".
To register a renderer using Oracle 9iFS Manager, follow these steps:
To register a renderer using XML, write an XML file to update the PolicyProperty bundle, creating a mapping between a specific class (for example, AirportDefinition) and its associated PolicyPropertyBundle (for example, AirportDefinitionPolicyBundle).
<?xml version = '1.0' standalone = 'yes'?> <CLASSOBJECT> <update reftype= 'name'>AirportDefinition</update> <policybundle reftype='name' classname='PolicyPropertyBundle'> AirportDefinitionPolicyBundle </policybundle> </CLASSOBJECT>
In general, you do not need to delete the PropertyPropertyBundle; you can change the list of policies associated with it. You can add/remove/update the policies associated with the bundle via XML.
The PolicyPropertyBundle (PPB) is a collection of policies. Each policy name has to be unique across an Oracle 9iFS Instance. In general, you will get duplicate values when creating a PPB if:
This sample code creates the PolicyPropertyBundle object, which is a collection of Property objects. For details about the attributes of Policy objects, see "Using PolicyPropertyBundles to Register Renderers".
<?xml version="1.0" standalone="yes"?> <POLICYPROPERTYBUNDLE> <NAME> AirportDefinitionPolicyBundle </NAME> <PROPERTIES> <PROPERTY> <NAME> RenderXmlAirportDefinition </NAME> <VALUE Datatype='SystemObject' Classname='Policy' > <NAME> AirportDefinitionXmlRenderer </NAME> <IMPLEMENTATIONNAME> oracle.ifs.server.renderers.IfsSimpleXmlRenderer </IMPLEMENTATIONNAME> <OPERATION> RenderXmlAirportDefinition </OPERATION> </VALUE> </PROPERTY> <PROPERTY> <NAME> CompleteDynamicRenderer </NAME> <VALUE Datatype='SystemObject' Classname='Policy' > <NAME> AirportDefinitionCompleteRenderer </NAME> <IMPLEMENTATIONNAME> ifs.sampleapps.OlivAirlines.AirportDynamicRenderer </IMPLEMENTATIONNAME> <OPERATION> CompleteDynamicRenderer </OPERATION> </VALUE> </PROPERTY> </PROPERTIES> </POLICYPROPERTYBUNDLE>
Whether your application invokes an Oracle 9iFS standard renderer or a custom renderer, the process is the same. Applications invoke renderers using the appropriate renderAsXxxx() method defined in oracle.ifs.beans.LibraryObject. The renderer application must invoke the appropriate method for the type of output desired.
To use any renderer, invoke one of the following methods inherited from the LibraryObject class on the object you want to render:
public java.io.InputStreamrenderAsStream
(String rendererType,
String rendererName,
Hashtable options)
throws IfsExceptionpublic java.io.ReaderrenderAsReader
(String rendererType,
String rendererName,
Hashtable options)
throws IfsException
Table 11-6 lists the parameters for the renderAsXxxx() methods. These parameters are used to determine which renderer is invoked and to pass options to the target renderer.
Table 11-6 renderAsXxxx() Parameters
The rendererType and rendererName arguments differ as follows:
rendererType argument is a String value that specifies the name of a Policy's Operation attribute.
rendererName argument is a String value that specifies the Name attribute of the Policy that contains the Operation specified by rendererType.
The rendererType and rendererName arguments together determine which renderer is to be used. The determination is made as follows:
You can use the renderAs() methods in two ways:
Table 11-7 shows the method signatures that correspond to each use.
Table 11-7 Method Signatures
To choose a specific renderer, specify the rendererName attribute. For example, an application can explicitly specify the SimpleTextRenderer, assuming Stream input:
renderAsStream("RenderAsText", "SimpleTextRenderer", myOptions)
The options argument passes additional information to the specified renderer, such as character encoding. The available options, their settings, and the meanings of each option/setting pair are renderer specific. In this example, the SimpleTextRenderer uses the myOptions Hashtable to obtain additional information. Consult the Javadoc for each standard renderer for more information about the options available.
To accept the default renderer specified by Oracle 9iFS, substitute null for the rendererName attribute. An application can allow the repository to select the default renderer for this Document object, assuming that this Document object can have two default renderers:
renderAsStream("RenderAsText", null, myOptions) renderAsStream("RenderAsXML",null, myOptions)
Example 11-7 calls the custom renderer and passes it the appropriate XSL stylesheet based on which client is making the request, then renders the result to the client.
package ifs.sampleapps.OlivAirlines; import javax.servlet.ServletConfig; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.io.PrintWriter; import java.io.Reader; import java.io.BufferedReader; import java.io.InputStream; import java.io.InputStreamReader; import java.util.Hashtable; import oracle.ifs.common.IfsException; import oracle.ifs.beans.Document; import oracle.ifs.beans.LibraryObject; import oracle.ifs.beans.LibraryService; import oracle.ifs.beans.LibrarySession; import oracle.ifs.beans.Selector; import oracle.ifs.search.AttributeQualification; import oracle.ifs.search.AttributeSearchSpecification; import oracle.ifs.search.SearchClassSpecification; import oracle.ifs.search.SearchSortSpecification; import oracle.ifs.beans.Search; public class iFSAirportServlet extends HttpServlet { private static final boolean DEBUG = false; private static final int ERRORCODE = 22000; /** * Constructs the iFSAirportServlet. */ public iFSAirportServlet() { } /** * The servlet container calls the init method exactly once * after instantiating the servlet. The init method must * complete successfully before the servlet can receive any requests. * * @param ServletConfig config * @exception An exception a servlet throws when it encounters difficulty. * @pub */ public void init(ServletConfig config) throws ServletException { super.init(config); } /** * Called by the servlet container to allow the servlet to * respond to a request. * Calls the printContent method, which does the actual work. * * @param req the ServletRequest object that contains the client's request. * @param res the ServletResponse object that contains the servlet's respond. * * @exception ServletException if an exception occurs that interferes with * the servlet's normal operation * @exception java.io.IOException if an input or output exception occurs * @pub */ public void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // Retrieve Servlet's output stream PrintWriter out = new PrintWriter(response.getOutputStream()); try { printContent(request, response, out); } catch (IfsException e) { out.println("<IfsException>" + e.toString() + "</IfsException>"); } out.close(); } /** * Calls the custom renderer and passes in the appropriate XSL * style sheet to the custom renderer based on which client is * making a request. Outputs the rendered result to the client. * * @param request the ServletRequest object that contains the client's request. * @param resonse the ServletResponse object that contains the servlet's respond. * @param out for output * @exception IfsException if operation fails. * @exception IOException if an input or output exception occurs. * @pub */ private void printContent(HttpServletRequest request, HttpServletResponse response, PrintWriter out) throws IOException, IfsException { // Retrieve User-Agent to know which kind of client is making the request. String userAgent = request.getHeader("User-Agent"); LibraryService service = new LibraryService(); String userName = request.getParameter("userName"); String passWord = request.getParameter("passWord"); String serviceName = request.getParameter("serviceName"); LibrarySession ifs = service.connect(userName, passWord, serviceName); // Finds the iFS object we are doing to render with a Selector. Selector mySelector = new Selector(ifs); // Select the Airportdefinition class based on its attribute: AIRPORTCODE. mySelector.setSearchClassname("AIRPORTDEFINITION"); // The airport code is passed in as a parameter provide along with the URL. String code = request.getParameter("code"); mySelector.setSearchSelection("AIRPORTCODE = '" + code + "'"); for (int i=0; i<mySelector.getItemCount(); i++) { LibraryObject lo = mySelector.getItems(i); String contentType = ""; Hashtable h = new Hashtable(); // Check if a given string ("HANDHTTP" here) matchs any substring // of the User-Agent parameter passed in, case insensative. // If it matches, the corresponding style sheet is read from iFS, // and put in an Hashtable, to be passed in to the renderer. if (userAgent.toUpperCase().indexOf("HANDHTTP") > -1) { h.put("xsl", getStyleSheetContent(ifs, "apHTML.xsl")); contentType = "text/html"; } else if (userAgent.toUpperCase().indexOf("MOZILLA") > -1) { h.put("xsl", getStyleSheetContent(ifs, "apHTML.xsl")); contentType = "text/html"; } else if (userAgent.toUpperCase().indexOf("UP") > -1) { h.put("xsl", getStyleSheetContent(ifs, "apWAP.xsl")); contentType = "text/x-wap.wml"; } else if (userAgent.toUpperCase().indexOf("NOKIA") > -1) { h.put("xsl", getStyleSheetContent(ifs, "apWAP.xsl")); contentType = "text/x-wap.wml"; } else if (userAgent.toUpperCase().indexOf("MOTOROLA") > -1) { h.put("xsl", getStyleSheetContent(ifs, "apVox.xsl")); contentType = "text/html"; } else { h.put("xsl", "none"); } response.setContentType(contentType); // Calls the custom renderer. Pass in the Hashtable // The custom renderer is registered in the // AirportDefinitionPolicyBundle.xml file. Reader reader = lo.renderAsReader("CompleteDynamicRenderer", "AirportDefinitionCompleteRenderer", h); // Reads results from the Reader, and prints to the Servlet output. printAirport(reader, out); } //end for loop } /** * This method seaches and gets the content of an iFS document, the XSL style * sheet that will be passed to the custom renderer, based on its file name. **/ private static String getStyleSheetContent(LibrarySession ifs, String xslName) throws IfsException { String retString = ""; String className[] = {"DOCUMENT"}; SearchClassSpecification scs = new SearchClassSpecification(className); scs.addResultClass("DOCUMENT"); AttributeQualification aq1 = new AttributeQualification(); aq1.setAttribute("DOCUMENT", "NAME"); aq1.setOperatorType(AttributeQualification.LIKE); aq1.setValue(xslName); SearchSortSpecification ss = new SearchSortSpecification(); ss.add("NAME" , SearchSortSpecification.ASCENDING); AttributeSearchSpecification ass = new AttributeSearchSpecification(); ass.setSearchClassSpecification(scs); ass.setSearchQualification(aq1); ass.setSearchSortSpecification(ss); Search srch = new Search(ifs, ass); srch.open(); try { while (true) { LibraryObject lo = srch.next().getLibraryObject(); Document d = (Document)lo; InputStream is = d.getContentStream(); BufferedReader br = new BufferedReader(new InputStreamReader(is)); for (String nextLine = br.readLine(); nextLine != null; nextLine = br.readLine()) { retString += nextLine; } br.close(); } } catch (IfsException e) { if (e.getErrorCode() == ERRORCODE) { [Is this set of braces needed????} } else { throw e; } } catch (IOException ioe) { System.err.println("IOException reading XSL : " + ioe.toString()); } srch.close(); return retString; } /** * Prints out the renderer output to the client. * * @param reader the renderer output passed in * @param out for output */ public static void printAirport(Reader reader, PrintWriter out) throws IOException { // Dumps the reader on the output. BufferedReader r = new BufferedReader(reader); for (String nextLine = r.readLine(); nextLine != null; nextLine = r.readLine()) { out.println(nextLine); } } }
To run the servlet:
Http://machineName:portNumber/XSLRenderer?code=LAX&userName=yourUserName&passWord=yourPassWord&serviceName=yourServiceName
where:
machineName is the server name where Oracle 9iFS is running.
portNumber is the port where the Oracle HTTP Server is running. Get the port number by typing http://machineName:9090.
yourUserName is the user you created during this example.
yourPassWord is the password for this user.
serviceName is the Service Name of Oracle 9iFS. The default for the Service Name is ServerManager.
You should see LAX and Los Angeles in the browser. You can change the code to SEA or SFO. For example:
Try entering the command from the previous step into different devices to see what the output looks like.
Text description of the illustration palm.jpg
|
|
![]() Copyright © 2001 Oracle Corporation. All Rights Reserved. |
|