Package com.ibm.portal.resolver.data

Provides for the interfaces required to serve data via the POC resolution framework.

See:
          Description

Interface Summary
Addressable Interface that allows to retrieve the address of a piece of content.
ByteDataSource Implemented by providers of byte data streams.
CharDataSource Implemented by providers of character data streams.
DataSink Base interface implemented by all data sinks, independent on their actual stream type.
DataSource Base interface implemented by all data sources, independent on their actual stream type.
DataSourceFactory Tagging interface for data source factory.
DataSourceFactoryEx Data source factory that allows to instantiate DataSource objects.
MultipartDataSink Data sink that accepts a multipart data request.
XmlDataSource Implemented by providers of XML data streams.
 

Package com.ibm.portal.resolver.data Description

Provides for the interfaces required to serve data via the POC resolution framework.

POC DataSource

Using POC addressability it is possible to handle GET operations on a particular piece of content. For each POCURI handlers can be registered that will be invoked, if the resource is served via the content handler servlet. Handlers can plug into the content handler servlet to process GET requests. The content handler servlet deals with the details of the request processing such as security, virtual portal support and the initialization of the request to allow calls into the WebSphere Portal APIs. Handlers that plug into the content handler servlet then provide the request-specific processing logic. The responsiblity of a handler is to

DataSourceFactory

Data source factory that allows to instantiate {@link com.ibm.portal.resolver.data.DataSource} objects. The data sources need to implement one of the strongly typed interfaces {@link com.ibm.portal.resolver.data.ByteDataSource}, {@link com.ibm.portal.resolver.data.CharDataSource}, {@link com.ibm.portal.resolver.data.XmlDataSource} or {@link com.ibm.portal.resolver.data.MultipartDataSource}. Clients of the {@link DataSourceFactoryEx} will determine the type of the returned data source via introspection.

A data source factory is registered in the plugin.xml of the providing extension as a serviceHandler

.
        <extension
                point="com.ibm.content.operations.registry.locationServiceHandler">
                <serviceHandler
                        class="YOUR_IMPLEMENTATION_CLASS"
                        locationTypeId="LOCATION_TYPE_ID"
                        id="com.ibm.portal.resolver.data.DataSourceFactoryEx" />
        </extension>
 

Example

Example

In this example we show how a simple data source is developed and integrated. The data source in this example will serve a dynamically generated JPEG image. We develop the example bottom-up.

DataSource

The data source represents the actual data that is served as a response to a POC request for a POCURI. In this example the data source is a ByteDataSource because it represents a jpeg image:

package com.ibm.wps.test.resolver.data.binary;

import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.OutputStream;
import java.net.URI;
import java.util.Collections;
import java.util.Date;
import java.util.Map;

import javax.imageio.ImageIO;
import javax.imageio.ImageWriter;
import javax.imageio.stream.ImageOutputStream;

import com.ibm.portal.resolver.data.ByteDataSource;

/**
 * The representation of your actual data stream. Your implementation just needs
 * to be able to write the bytes dynamically out to the target stream.
 * 
 * @author cleue
 *
 */
public class DownloadSource implements ByteDataSource {
        
        /** copyright */
        public final static String COPYRIGHT = com.ibm.wps.Copyright.SHORT;
        
        /** mime type of the image we intend to produce **/
        public static final String mimeType = "image/jpeg";
        
        /**
         *      URI of this image
         */
        private URI pocURI;
        
        /** created timestamp **/
        private Date created;
        
        /**
         * pass the POC URI via reset to already prepare for object pooling
         * 
         * @param aPocURI
         */
        public void reset(final URI aPocURI) {
                pocURI = aPocURI;
                created = new Date();
        }
                
        /* (non-Javadoc)
         * @see com.ibm.portal.resolver.data.ByteDataSource#write(java.io.OutputStream)
         */
        public OutputStream write(final OutputStream out) throws IOException {
                // dimensions
                final int width = 128;
                final int height = 128;
                
                // construct the image
                final BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
                final Graphics2D graph = image.createGraphics();
                graph.clearRect(0, 0, width, height);
                // draw a circle
                graph.drawOval(0, 0, width, height);
                // draw the POC URI
                graph.drawString(pocURI.toString(), 0, height/2);
                // done with the graph
                graph.dispose();
                
                // write the image
                final ImageWriter writer = (ImageWriter) ImageIO.getImageWritersByMIMEType(mimeType).next();
                final ImageOutputStream imgOut = ImageIO.createImageOutputStream(out);
                writer.setOutput(imgOut);
                writer.write(image);
                imgOut.close();
                // done with the  the writer
                writer.dispose();
                
                // done
                return out;
        }

        /* (non-Javadoc)
         * @see com.ibm.portal.resolver.data.DataSource#getContentType()
         */
        public String getContentType() {
                // return the mime type of the data
                return mimeType;
        }

        /*
         * Overriding method... does not require Javadoc.
         * @see com.ibm.portal.resolver.data.DataSource#getExpiration()
         */
        public Date getExpiration() {
                // some arbitrary expiration info
                return new Date(created.getTime() + 1000 * 10 * 10);
        }

        /*
         * Overriding method... does not require Javadoc.
         * @see com.ibm.portal.TimeStamped#getCreated()
         */
        public Date getCreated() {
                return created;
        }

        /*
         * Overriding method... does not require Javadoc.
         * @see com.ibm.portal.TimeStamped#getLastModified()
         */
        public Date getLastModified() {
                return created;
        }

        public void dispose() {
                // reset internal data
                pocURI = null;
                created = null;
                // if you do object pooling, return the object to the pool, here
        }

        /* (non-Javadoc)
         * @see com.ibm.portal.resolver.data.Addressable#getURI()
         */
        public URI getURI() {
                // the URI for this datasource
                return pocURI;
        }

        /* (non-Javadoc)
         * @see com.ibm.portal.resolver.data.Addressable#getParameters()
         */
        public Map getParameters() {
                // no parameters required
                return Collections.EMPTY_MAP;
        }

}

DataSourceFactoryEx

The data source is managed and instantiated by a DataSourceFactoryEx. This factory is called by the framework with the POCURI and the parameter map and constructs data sources based on these parameters. In this example we always serve the same image so the code is independent from the URI. In a real world example the selection of the matching data source would depend on the URI and probably on the parameter map.

package com.ibm.wps.test.resolver.data.binary;

import java.io.IOException;
import java.net.URI;
import java.util.Map;

import com.ibm.content.operations.registry.api.Context;
import com.ibm.portal.resolver.data.DataSource;
import com.ibm.portal.resolver.data.DataSourceFactoryEx;

/**
 * Simply data source factoy that creates the same {@link DataSource} (an image)
 * for all URIs. 
 */
public class ByteDownload implements DataSourceFactoryEx {

        /** copyright */
        public final static String COPYRIGHT = com.ibm.wps.Copyright.SHORT;

        /* (non-Javadoc)
         * @see com.ibm.portal.resolver.helper.AbstractByteDataSouceFactory#newSource(java.net.URI, java.util.Map, com.ibm.content.operations.registry.api.Context)
         */
        public DataSource newSource(final URI uri, final String verb,
                        final Map params, final Context ctx) throws IOException {
                // TODO somehow access your data
                // recommendation: for performance reasons use object pooling to get
                // ByteDataSource objects. You can return them in the dispose() call
                // on the source

                // in this example I just dynamically generate a JPEG image 
                final DownloadSource result = new DownloadSource();
                result.reset(uri);

                return result;
        }

}

COR artefacts

In order to register a DataSourceFactoryEx with the COR framework we need glue code that binds our implementation to the COR.

The ContentLocationFactory implementation:

package com.ibm.wps.test.resolver.cor;

import com.ibm.portal.resolver.helper.cor.SingleContentLocationFactory;
import com.ibm.wps.test.resolver.Constants;

/**
 * Code artifact that can be references via the <code>plugin.xml</code> to
 * perform a COR registration.
 */
public class SampleContentLocationFactory extends SingleContentLocationFactory implements Constants {

        public SampleContentLocationFactory() {
                super(SCHEME_TEST, new SampleContentLocation());
        }
}

The ContentLocation implementation referenced by the code above:

package com.ibm.wps.test.resolver.cor;

import com.ibm.portal.resolver.helper.cor.DefaultContentLocation;
import com.ibm.wps.test.resolver.Constants;

/**
 * 
 */
public class SampleContentLocation extends DefaultContentLocation implements Constants {

        public SampleContentLocation() {
                super(LOCATION_TYPE_ID, SCHEME_TEST);
        }
}

The LOCATION_TYPE_ID constant used in this code references the ID as registered in the plugin.xml (set to com.ibm.wps.test.resolver.locationTypeID). The SCHEME_TEST identifies the URI scheme that is used to access the content location (set to SampleScheme).

Registration

Our implementations must not be glued together via the plugin.xml. First the ContentLocationFactory is registered with its URI scheme:

  <extension
        point="com.ibm.content.operations.registry.locationTypeContribution">
        
       <!-- this is the location for the download URIs -->

      <contentLocationType
            class="com.ibm.wps.test.resolver.cor.SampleContentLocationFactory"
            id="com.ibm.wps.test.resolver.locationTypeID"
            match.uri.scheme="SampleScheme"
            title="Sample Content Location Factory"/>

 </extension>

Then the data source factory is registered as a service for this ContentLocationFactory (and therefore implicitly for the URI scheme). Note that the locationTypeId attribute in the serviceHandler matches the id attribute in the contentLocationType:

    <extension
                point="com.ibm.content.operations.registry.locationServiceHandler">

                <!-- this service handles the binary download of your data -->
                <serviceHandler
                        class="com.ibm.wps.test.resolver.data.binary.ByteDownload"
                        locationTypeId="com.ibm.wps.test.resolver.locationTypeID"

                        id="com.ibm.portal.resolver.data.DataSourceFactoryEx"/>

        </extension>