Oracle Internet File System Developer's Guide Release 1.1 A75172-04 |
|
This chapter covers the following topics:
A renderer takes an object stored in the repository and outputs its content in a specific format. In a sense, a renderer is the opposite of a parser. 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 Internet File System, the object can be rendered in a variety of formats and layouts.
The Oracle iFS rendering framework allows a developer to:
As a developer, you have two options to render a repository object:
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.
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 SimpleXmlRenderer 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.
Because Document objects are the most commonly rendered objects, we will refer to documents for the balance of this discussion.
In the Oracle iFS Java class hierarchy each Oracle iFS object has two representations:
Because rendering is a server-side operation, you must use the S_ classes.
The process of registering a renderer is, at the basic level, 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 iFS has an associated PolicyPropertyBundle. When an object of a class is retrieved from the repository, Oracle iFS 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 iFS includes multiple protocols (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 following attributes:
For the procedures to register a renderer, see "Registering a Renderer Using Oracle iFS Manager". For an XML code sample of a PolicyPropertyBundle, see "Registering a Renderer Using XML".
Out-of-the-box, Oracle iFS includes two standard renderers that will meet the needs of most developers creating new applications in Oracle iFS.
Note: A renderer must be registered before you can use it. The standard renderers are registered by default.
Whether your application invokes an Oracle iFS 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.InputStream
renderAsStream
(String rendererType,
String rendererName,
Hashtable options)
throws IfsExceptionpublic java.io.Reader
renderAsReader
(String rendererType,
String rendererName,
Hashtable options)
throws IfsException
The following table 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.
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:
The following table shows the method signatures that correspond to each use:
To choose a specific renderer, specify the rendererName
attribute. The following example shows how 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 iFS, substitute null
for the rendererName
attribute. The following example shows how 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)
The only reason for creating a custom renderer is if one of the standard renderers provided with Oracle iFS does not allow you to render a repository object in the format required by a particular application.
Custom renderers can be used for many purposes:
When you plan a custom renderer application, include the following stages:
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 iFS 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 the following table.
Parameter | Datatype | Description |
---|---|---|
|
S_LibrarySession |
The server-side representation of the current user's LibrarySession. |
public AirportDynamicRenderer(S_LibrarySession ifs) throws IfsException { m_IfsSession = ifs; }
The following table describes the parameters of the two renderAsXxxx()
methods:
The 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 SimpleXmlRenderer //This call is referencing the SimpleXMLRenderer, 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 following classes in the Oracle iFS Javadoc.
For the protocol servers and other standard Oracle iFS components to access your custom renderer, the folder tree containing the class for the renderer must reside in the Oracle iFS CLASSPATH. Oracle iFS includes a special directory for this purpose. This directory, called custom_classes
, is already in the CLASSPATH environment variable that the Oracle iFS server software uses.
To deploy a renderer:
.class
file.
.class
file in the directory $ORACLE_HOME/ifs/custom_classes
on the server where Oracle iFS is installed.
The process of registering a renderer connects a class of objects with a specific renderer. You can register a renderer using any of the following facilities:
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 iFS 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 (AirportDefinition) and its associated PolicyPropertyBundle (AirportDefinitionPolicyBundle).
<?xml version = '1.0' standalone = 'yes'?> <CLASSOBJECT> <update reftype= 'name'>AirportDefinition</update> <policybundle reftype='name' classname='PolicyPropertyBundle'> AirportDefinitionPolicyBundle </policybundle> </CLASSOBJECT>
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.SimpleXmlRenderer </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>
This servlet 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 the iFS is running.
portNumber is the port where the Java Web 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 iFS. 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.
|
Copyright © 2000 Oracle Corporation. All Rights Reserved. |
|