Package org.fcrepo.server.access

Source Code of org.fcrepo.server.access.FedoraAccessServlet$ProfileSerializerThread

/* The contents of this file are subject to the license and copyright terms
* detailed in the license directory at the root of the source tree (also
* available online at http://fedora-commons.org/license/).
*/

package org.fcrepo.server.access;

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PipedReader;
import java.io.PipedWriter;
import java.net.URLDecoder;
import java.text.ParseException;
import java.util.Date;
import java.util.Enumeration;
import java.util.Hashtable;

import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.xml.transform.Templates;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;

import org.fcrepo.common.Constants;
import org.fcrepo.server.Context;
import org.fcrepo.server.ReadOnlyContext;
import org.fcrepo.server.Server;
import org.fcrepo.server.errors.DatastreamNotFoundException;
import org.fcrepo.server.errors.DisseminationException;
import org.fcrepo.server.errors.GeneralException;
import org.fcrepo.server.errors.InitializationException;
import org.fcrepo.server.errors.MethodNotFoundException;
import org.fcrepo.server.errors.ObjectNotFoundException;
import org.fcrepo.server.errors.ObjectNotInLowlevelStorageException;
import org.fcrepo.server.errors.ServerException;
import org.fcrepo.server.errors.StreamIOException;
import org.fcrepo.server.errors.authorization.AuthzException;
import org.fcrepo.server.errors.servletExceptionExtensions.InternalError500Exception;
import org.fcrepo.server.errors.servletExceptionExtensions.NotFound404Exception;
import org.fcrepo.server.errors.servletExceptionExtensions.RootException;
import org.fcrepo.server.storage.types.MIMETypedStream;
import org.fcrepo.server.storage.types.Property;
import org.fcrepo.server.utilities.StreamUtility;
import org.fcrepo.utilities.DateUtility;
import org.fcrepo.utilities.XmlTransformUtility;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
* Implements the three methods GetObjectProfile, GetDissemination, and
* GetDatastreamDissemination of the Fedora Access LITE (API-A-LITE) interface
* using a java servlet front end. The syntax defined by API-A-LITE defines
* three bindings for these methods:
* <ol>
* <li>GetDissemination URL syntax:
* <p>
* protocol://hostname:port/fedora/get/PID/sDefPID/methodName[/dateTime][?
* parmArray]
* </p>
* <p>
* This syntax requests a dissemination of the specified object using the
* specified method of the associated service definition object. The result is
* returned as a MIME-typed stream.
* </p>
* </li>
* <ul>
* <li>protocol - either http or https.</li>
* <li>hostname - required hostname of the Fedora server.</li>
* <li>port - required port number on which the Fedora server is running.</li>
* <li>fedora - required path name for the Fedora access service.</li>
* <li>get - required path name for the Fedora service.</li>
* <li>PID - required persistent idenitifer of the digital object.</li>
* <li>sDefPID - required persistent identifier of the service definition object
* to which the digital object subscribes.</li>
* <li>methodName - required name of the method to be executed.</li>
* <li>dateTime - optional dateTime value indicating dissemination of a version
* of the digital object at the specified point in time.
* <li>parmArray - optional array of method parameters consisting of name/value
* pairs in the form parm1=value1&parm2=value2...</li>
* </ul>
* <li>GetObjectProfile URL syntax:
* <p>
* protocol://hostname:port/fedora/get/PID[/dateTime][?xml=BOOLEAN]
* </p>
* <p>
* This syntax requests an object profile for the specified digital object. The
* xml parameter determines the type of output returned. If the parameter is
* omitted or has a value of "false", a MIME-typed stream consisting of an html
* table is returned providing a browser-savvy means of viewing the object
* profile. If the value specified is "true", then a MIME-typed stream
* consisting of XML is returned.
* </p>
* </li>
* <ul>
* <li>protocol - either http or https</li>
* <li>hostname - required hostname of the Fedora server.</li>
* <li>port - required port number on which the Fedora server is running.</li>
* <li>fedora - required name of the Fedora access service.</li>
* <li>get - required verb of the Fedora service.</li>
* <li>PID - required persistent identifier of the digital object.</li>
* <li>dateTime - optional dateTime value indicating dissemination of a version
* of the digital object at the specified point in time.
* <li>xml - an optional parameter indicating the requested output format. A
* value of "true" indicates a return type of text/xml; the absence of the xml
* parameter or a value of "false" indicates format is to be text/html.</li>
* </ul>
* <li>GetDatastreamDissemination URL syntax:
* <p>
* protocol://hostname:port/fedora/get/PID/DSID[/dateTime]
* </p>
* This syntax requests a datastream dissemination for the specified digital
* object. It is used to return the contents of a datastream.
* <p></li>
* <ul>
* <li>protocol - either http or https.</li>
* <li>hostname - required hostname of the Fedora server.</li>
* <li>port - required port number on which the Fedora server is running.</li>
* <li>fedora - required name of the Fedora access service.</li>
* <li>get - required verb of the Fedora service.</li>
* <li>PID - required persistent identifier of the digital object.</li>
* <li>DSID - required datastream identifier for the datastream.</li>
* <li>dateTime - optional dateTime value indicating dissemination of a version
* of the digital object at the specified point in time.
* </ul>
* </ol>
*
* @author Ross Wayland
*/
public class FedoraAccessServlet
        extends SpringAccessServlet
        implements Constants {

    private static final Logger logger =
            LoggerFactory.getLogger(FedoraAccessServlet.class);

    private static final long serialVersionUID = 1L;

    /** Content type for html. */
    private static final String CONTENT_TYPE_HTML = "text/html; charset=UTF-8";

    /** Content type for xml. */
    private static final String CONTENT_TYPE_XML = "text/xml; charset=UTF-8";

    /** Portion of initial request URL from protocol up to query string */
    private String requestURI = null;

    /** 4K Buffer */
    private final static int BUF = 4096;

    /**
     * <p>
     * Process Fedora Access Request. Parse and validate the servlet input
     * parameters and then execute the specified request.
     * </p>
     *
     * @param request
     *        The servlet request.
     * @param response
     *        servlet The servlet response.
     * @throws ServletException
     *         If an error occurs that effects the servlet's basic operation.
     * @throws IOException
     *         If an error occurrs with an input or output operation.
     */
    @Override
    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        String PID = null;
        String sDefPID = null;
        String methodName = null;
        String dsID = null;
        Date asOfDateTime = null;
        Date versDateTime = null;
        Property[] userParms = null;
        boolean isGetObjectProfileRequest = false;
        boolean isGetDisseminationRequest = false;
        boolean isGetDatastreamDisseminationRequest = false;
        boolean xml = false;

        requestURI =
                request.getRequestURL().toString()
                        + (request.getQueryString() != null ? "?"
                                + request.getQueryString() : "");
        logger.info("Got request: " + requestURI);

        // Parse servlet URL.
        // For the Fedora API-A-LITE "get" syntax, valid entries include:
        //
        // For dissemination requests:
        // http://host:port/fedora/get/pid/sDefPid/methodName
        // http://host:port/fedora/get/pid/sDefPid/methodName/timestamp
        // http://host:port/fedora/get/pid/sDefPid/methodName?parm=value[&parm=value]
        // http://host:port/fedora/get/pid/sDefPid/methodName/timestamp?parm=value[&parm=value]
        //
        // For object profile requests:
        // http://host:port/fedora/get/pid
        // http://host:port/fedora/get/pid/timestamp
        //
        // For datastream dissemination requests:
        // http://host:port/fedora/get/pid/dsID
        // http://host:port/fedora/get/pid/dsID/timestamp
        //
        String[] URIArray = request.getRequestURL().toString().split("/");
        if (URIArray.length == 6 || URIArray.length == 7) {
            // Request is either an ObjectProfile request or a datastream
            // request
            if (URIArray.length == 7) {
                // They either specified a date/time or a datastream id.
                if (URIArray[6].indexOf(":") == -1) {
                    // If it doesn't contain a colon, they were after a
                    // datastream,
                    // so this is a DatastreamDissemination request
                    dsID = URLDecoder.decode(URIArray[6], "UTF-8");
                    isGetDatastreamDisseminationRequest = true;
                } else {
                    // If it DOES contain a colon, they were after a
                    // date/time-stamped object profile
                    try {
                        versDateTime = DateUtility.parseDateStrict(URIArray[6]);
                    } catch (ParseException e) {
                        String message =
                                "ObjectProfile Request Syntax Error: DateTime value "
                                        + "of \""
                                        + URIArray[6]
                                        + "\" is not a valid DateTime format. "
                                        + " <br></br> The expected format for DateTime is \""
                                        + "YYYY-MM-DDTHH:MM:SS.SSSZ\".  "
                                        + " <br></br> The expected syntax for "
                                        + "ObjectProfile requests is: \""
                                        + URIArray[0]
                                        + "//"
                                        + URIArray[2]
                                        + "/"
                                        + URIArray[3]
                                        + "/"
                                        + URIArray[4]
                                        + "/PID[/dateTime] \"  ."
                                        + " <br></br> Submitted request was: \""
                                        + requestURI + "\"  .  ";
                        logger.warn(message);
                        throw new ServletException("from FedoraAccessServlet"
                                + message);
                        /*
                         * commented out for exception.jsp test
                         * response.setStatus
                         * (HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
                         * response
                         * .sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR
                         * , message); return; commented out for exception.jsp
                         * test
                         */
                    }
                    asOfDateTime = versDateTime;
                    isGetObjectProfileRequest = true;
                }
            } else {
                // URIArray.length==6 so this is a GetObjectProfile request
                isGetObjectProfileRequest = true;
            }
        } else if (URIArray.length > 7) {
            // Request is either dissemination request or timestamped get
            // datastream request
            methodName = URLDecoder.decode(URIArray[7], "UTF-8");
            if (URIArray.length == 8) {
                if (URIArray[6].indexOf(":") == -1) {
                    // If it doesn't contain a colon, they were after a
                    // timestamped
                    // datastream, so this is a GetDatastreamDissemination
                    // request.
                    dsID = URLDecoder.decode(URIArray[6], "UTF-8");

                    try {
                        versDateTime = DateUtility.parseDateStrict(URIArray[7]);
                    } catch (ParseException e) {
                        String message =
                                "GetDatastreamDissemination Request Syntax Error: DateTime value "
                                        + "of \""
                                        + URIArray[7]
                                        + "\" is not a valid DateTime format. "
                                        + " <br></br> The expected format for DateTime is \""
                                        + "YYYY-MM-DDTHH:MM:SS.SSSZ\".  "
                                        + " <br></br> The expected syntax for GetDatastreamDissemination requests is: \""
                                        + URIArray[0]
                                        + "//"
                                        + URIArray[2]
                                        + "/"
                                        + URIArray[3]
                                        + "/"
                                        + URIArray[4]
                                        + "/PID/dsID[/dateTime] \"  "
                                        + " <br></br> Submitted request was: \""
                                        + requestURI + "\"  .  ";
                        logger.warn(message);
                        throw new ServletException("from FedoraAccessServlet"
                                + message);
                    }

                    asOfDateTime = versDateTime;
                    isGetDatastreamDisseminationRequest = true;
                } else {
                    isGetDisseminationRequest = true;
                }
            } else if (URIArray.length == 9) {
                try {
                    versDateTime = DateUtility.parseDateStrict(URIArray[8]);
                } catch (ParseException e) {
                    String message =
                            "Dissemination Request Syntax Error: DateTime value "
                                    + "of \""
                                    + URIArray[8]
                                    + "\" is not a valid DateTime format. "
                                    + " <br></br> The expected format for DateTime is \""
                                    + "YYYY-MM-DDTHH:MM:SS.SSS\".  "
                                    + " <br></br> The expected syntax for Dissemination requests is: \""
                                    + URIArray[0]
                                    + "//"
                                    + URIArray[2]
                                    + "/"
                                    + URIArray[3]
                                    + "/"
                                    + URIArray[4]
                                    + "/PID/sDefPID/methodName[/dateTime][?ParmArray] \"  "
                                    + " <br></br> Submitted request was: \""
                                    + requestURI + "\"  .  ";
                    logger.warn(message);
                    throw new ServletException("from FedoraAccessServlet"
                            + message);
                    /*
                     * commented out for exception.jsp test
                     * response.setStatus(HttpServletResponse
                     * .SC_INTERNAL_SERVER_ERROR);
                     * response.sendError(HttpServletResponse
                     * .SC_INTERNAL_SERVER_ERROR, message); return; commented
                     * out for exception.jsp test
                     */
                }
                asOfDateTime = versDateTime;
                isGetDisseminationRequest = true;
            }
            if (URIArray.length > 9) {
                String message =
                        "Dissemination Request Syntax Error: The expected "
                                + "syntax for Dissemination requests is: \""
                                + URIArray[0]
                                + "//"
                                + URIArray[2]
                                + "/"
                                + URIArray[3]
                                + "/"
                                + URIArray[4]
                                + "/PID/sDefPID/methodName[/dateTime][?ParmArray] \"  "
                                + " <br></br> Submitted request was: \""
                                + requestURI + "\"  .  ";
                logger.warn(message);
                throw new ServletException("from FedoraAccessServlet" + message);
                /*
                 * commented out for exception.jsp test
                 * response.setStatus(HttpServletResponse
                 * .SC_INTERNAL_SERVER_ERROR);
                 * response.sendError(HttpServletResponse
                 * .SC_INTERNAL_SERVER_ERROR, message); return; commented out
                 * for exception.jsp test
                 */
            }
        } else {
            // Bad syntax; redirect to syntax documentation page.
            response
                    .sendRedirect("/userdocs/client/browser/apialite/index.html");
            return;
        }

        // Separate out servlet parameters from method parameters
        Hashtable<String, String> h_userParms = new Hashtable<String, String>();
        for (Enumeration<?> e = request.getParameterNames(); e
                .hasMoreElements();) {
            String name = URLDecoder.decode((String) e.nextElement(), "UTF-8");
            if (isGetObjectProfileRequest && name.equalsIgnoreCase("xml")) {
                xml = new Boolean(request.getParameter(name)).booleanValue();
            } else {
                String value =
                        URLDecoder.decode(request.getParameter(name), "UTF-8");
                h_userParms.put(name, value);
            }
        }

        // API-A interface requires user-supplied parameters to be of type
        // Property[] so create Property[] from hashtable of user parameters.
        int userParmCounter = 0;
        userParms = new Property[h_userParms.size()];
        for (Enumeration<String> e = h_userParms.keys(); e.hasMoreElements();) {
            Property userParm = new Property();
            userParm.name = e.nextElement();
            userParm.value = h_userParms.get(userParm.name);
            userParms[userParmCounter] = userParm;
            userParmCounter++;
        }

        PID = URIArray[5];
        String actionLabel = "Access";

        try {
            if (isGetObjectProfileRequest) {
                logger.debug("Servicing getObjectProfile request " + "(PID="
                        + PID + ", asOfDate=" + versDateTime + ")");

                Context context =
                        ReadOnlyContext.getContext(HTTP_REQUEST.REST.uri,
                                                   request);
                getObjectProfile(context,
                                 PID,
                                 asOfDateTime,
                                 xml,
                                 request,
                                 response);

                logger.debug("Finished servicing getObjectProfile request");
            } else if (isGetDisseminationRequest) {
                sDefPID = URIArray[6];
                logger.debug("Servicing getDissemination request (PID=" + PID
                        + ", sDefPID=" + sDefPID + ", methodName=" + methodName
                        + ", asOfDate=" + versDateTime + ")");

                Context context =
                        ReadOnlyContext.getContext(HTTP_REQUEST.REST.uri,
                                                   request);
                getDissemination(context,
                                 PID,
                                 sDefPID,
                                 methodName,
                                 userParms,
                                 asOfDateTime,
                                 response,
                                 request);

                logger.debug("Finished servicing getDissemination request");
            } else if (isGetDatastreamDisseminationRequest) {
                logger.debug("Servicing getDatastreamDissemination request "
                        + "(PID=" + PID + ", dsID=" + dsID + ", asOfDate="
                        + versDateTime + ")");

                Context context =
                        ReadOnlyContext.getContext(HTTP_REQUEST.REST.uri,
                                                   request);
                getDatastreamDissemination(context,
                                           PID,
                                           dsID,
                                           asOfDateTime,
                                           response,
                                           request);

                logger.debug("Finished servicing getDatastreamDissemination "
                        + "request");
            }
        } catch (MethodNotFoundException e) {
            logger.error("Method not found for request: " + requestURI
                    + " (actionLabel=" + actionLabel + ")", e);
            throw new NotFound404Exception("", e, request, actionLabel, e
                    .getMessage(), new String[0]);
        } catch (DatastreamNotFoundException e) {
            logger.error("Datastream not found for request: " + requestURI
                    + " (actionLabel=" + actionLabel + ")", e);
            throw new NotFound404Exception("", e, request, actionLabel, e
                    .getMessage(), new String[0]);
        } catch (ObjectNotFoundException e) {
            logger.error("Object not found for request: " + requestURI
                    + " (actionLabel=" + actionLabel + ")", e);
            throw new NotFound404Exception("", e, request, actionLabel, e
                    .getMessage(), new String[0]);
        } catch (DisseminationException e) {
            logger.error("Dissemination failed: " + requestURI
                    + " (actionLabel=" + actionLabel + ")", e);
            throw new NotFound404Exception("", e, request, actionLabel, e
                    .getMessage(), new String[0]);
        } catch (ObjectNotInLowlevelStorageException e) {
            logger.error("Object or datastream not found for request: "
                    + requestURI + " (actionLabel=" + actionLabel + ")", e);
            throw new NotFound404Exception("", e, request, actionLabel, e
                    .getMessage(), new String[0]);
        } catch (AuthzException ae) {
            logger.error("Authorization failed for request: " + requestURI
                    + " (actionLabel=" + actionLabel + ")", ae);
            throw RootException.getServletException(ae,
                                                    request,
                                                    actionLabel,
                                                    new String[0]);
        } catch (Throwable th) {
            logger.error("Unexpected error servicing API-A request", th);
            throw new InternalError500Exception("",
                                                th,
                                                request,
                                                actionLabel,
                                                "",
                                                new String[0]);
        }
    }

    public void getObjectProfile(Context context,
                                 String PID,
                                 Date asOfDateTime,
                                 boolean xml,
                                 HttpServletRequest request,
                                 HttpServletResponse response)
            throws ServerException {

        OutputStreamWriter out = null;
        Date versDateTime = asOfDateTime;
        ObjectProfile objProfile = null;
        PipedWriter pw = null;
        PipedReader pr = null;
        try {
            pw = new PipedWriter();
            pr = new PipedReader(pw);
            objProfile = m_access.getObjectProfile(context, PID, asOfDateTime);
            if (objProfile != null) {
                // Object Profile found.
                // Serialize the ObjectProfile object into XML
                new ProfileSerializerThread(context,
                                            PID,
                                            objProfile,
                                            versDateTime,
                                            pw).start();
                if (xml) {
                    // Return results as raw XML
                    response.setContentType(CONTENT_TYPE_XML);

                    // Insures stream read from PipedReader correctly translates
                    // utf-8
                    // encoded characters to OutputStreamWriter.
                    out =
                            new OutputStreamWriter(response.getOutputStream(),
                                                   "UTF-8");
                    char[] buf = new char[BUF];
                    int len = 0;
                    while ((len = pr.read(buf, 0, BUF)) != -1) {
                        out.write(buf, 0, len);
                    }
                    out.flush();
                } else {
                    // Transform results into an html table
                    response.setContentType(CONTENT_TYPE_HTML);
                    out =
                            new OutputStreamWriter(response.getOutputStream(),
                                                   "UTF-8");
                    File xslFile =
                            new File(m_server.getHomeDir(),
                                     "access/viewObjectProfile.xslt");
                    Templates template =
                            XmlTransformUtility.getTemplates(xslFile);
                    Transformer transformer = template.newTransformer();
                    transformer.setParameter("fedora", context
                            .getEnvironmentValue(FEDORA_APP_CONTEXT_NAME));
                    transformer.transform(new StreamSource(pr),
                                          new StreamResult(out));
                }
                out.flush();

            } else {
                throw new GeneralException("No object profile returned");
            }
        } catch (ServerException e) {
            throw e;
        } catch (Throwable th) {
            String message = "Error getting object profile";
            logger.error(message, th);
            throw new GeneralException(message, th);
        } finally {
            try {
                if (pr != null) {
                    pr.close();
                }
                if (out != null) {
                    out.close();
                }
            } catch (Throwable th) {
                String message = "Error closing output";
                logger.error(message, th);
                throw new StreamIOException(message);
            }
        }
    }

    public void getDatastreamDissemination(Context context,
                                           String PID,
                                           String dsID,
                                           Date asOfDateTime,
                                           HttpServletResponse response,
                                           HttpServletRequest request)
            throws IOException, ServerException {
        ServletOutputStream out = null;
        MIMETypedStream dissemination = null;
        dissemination =
                m_access.getDatastreamDissemination(context,
                                                    PID,
                                                    dsID,
                                                    asOfDateTime);
        try {
            // testing to see what's in request header that might be of interest
            if (logger.isDebugEnabled()) {
                for (Enumeration<?> e = request.getHeaderNames(); e
                        .hasMoreElements();) {
                    String name = (String) e.nextElement();
                    Enumeration<?> headerValues = request.getHeaders(name);
                    StringBuffer sb = new StringBuffer();
                    while (headerValues.hasMoreElements()) {
                        sb.append((String) headerValues.nextElement());
                    }
                    String value = sb.toString();
                    logger.debug("FEDORASERVLET REQUEST HEADER CONTAINED: "
                            + name + " : " + value);
                }
            }

            // Dissemination was successful;
            // Return MIMETypedStream back to browser client
            if (dissemination.MIMEType
                    .equalsIgnoreCase("application/fedora-redirect")) {
                // A MIME type of application/fedora-redirect signals that
                // the MIMETypedStream returned from the dissemination is
                // a special Fedora-specific MIME type. In this case, the
                // Fedora server will not proxy the datastream, but
                // instead perform a simple redirect to the URL contained
                // within the body of the MIMETypedStream. This special
                // MIME type is used primarily for streaming media where
                // it is more efficient to stream the data directly
                // between the streaming server and the browser client
                // rather than proxy it through the Fedora server.

                BufferedReader br =
                        new BufferedReader(new InputStreamReader(dissemination
                                .getStream()));
                StringBuffer sb = new StringBuffer();
                String line = null;
                while ((line = br.readLine()) != null) {
                    sb.append(line);
                }

                response.sendRedirect(sb.toString());
            } else {

                response.setContentType(dissemination.MIMEType);
                Property[] headerArray = dissemination.header;
                if (headerArray != null) {
                    for (int i = 0; i < headerArray.length; i++) {
                        if (headerArray[i].name != null
                                && !headerArray[i].name
                                        .equalsIgnoreCase("transfer-encoding")
                                && !headerArray[i].name
                                        .equalsIgnoreCase("content-type")) {
                            response.addHeader(headerArray[i].name,
                                               headerArray[i].value);
                            logger.debug("THIS WAS ADDED TO FEDORASERVLET "
                                    + "RESPONSE HEADER FROM ORIGINATING "
                                    + "PROVIDER " + headerArray[i].name + " : "
                                    + headerArray[i].value);
                        }
                    }
                }
                out = response.getOutputStream();
                int byteStream = 0;
                logger.debug("Started reading dissemination stream");
                InputStream dissemResult = dissemination.getStream();
                byte[] buffer = new byte[BUF];
                while ((byteStream = dissemResult.read(buffer)) != -1) {
                    out.write(buffer, 0, byteStream);
                }
                buffer = null;
                dissemResult.close();
                dissemResult = null;
                out.flush();
                out.close();
                logger.debug("Finished reading dissemination stream");
            }
        } finally {
            dissemination.close();
        }
    }

    /**
     * <p>
     * This method calls the Fedora Access Subsystem to retrieve a MIME-typed
     * stream corresponding to the dissemination request.
     * </p>
     *
     * @param context
     *        The read only context of the request.
     * @param PID
     *        The persistent identifier of the Digital Object.
     * @param sDefPID
     *        The persistent identifier of the Service Definition object.
     * @param methodName
     *        The method name.
     * @param userParms
     *        An array of user-supplied method parameters.
     * @param asOfDateTime
     *        The version datetime stamp of the digital object.
     * @param response
     *        The servlet response.
     * @param request
     *        The servlet request.
     * @throws IOException
     *         If an error occurrs with an input or output operation.
     * @throws ServerException
     *         If an error occurs in the Access Subsystem.
     */
    public void getDissemination(Context context,
                                 String PID,
                                 String sDefPID,
                                 String methodName,
                                 Property[] userParms,
                                 Date asOfDateTime,
                                 HttpServletResponse response,
                                 HttpServletRequest request)
            throws IOException, ServerException {
        ServletOutputStream out = null;
        MIMETypedStream dissemination = null;
        dissemination =
                m_access.getDissemination(context,
                                          PID,
                                          sDefPID,
                                          methodName,
                                          userParms,
                                          asOfDateTime);
        out = response.getOutputStream();
        try {
            // testing to see what's in request header that might be of interest
            if (logger.isDebugEnabled()) {
                for (Enumeration<?> e = request.getHeaderNames(); e
                        .hasMoreElements();) {
                    String name = (String) e.nextElement();
                    Enumeration<?> headerValues = request.getHeaders(name);
                    StringBuffer sb = new StringBuffer();
                    while (headerValues.hasMoreElements()) {
                        sb.append((String) headerValues.nextElement());
                    }
                    String value = sb.toString();
                    logger.debug("FEDORASERVLET REQUEST HEADER CONTAINED: "
                            + name + " : " + value);
                }
            }

            // Dissemination was successful;
            // Return MIMETypedStream back to browser client
            if (dissemination.MIMEType
                    .equalsIgnoreCase("application/fedora-redirect")) {
                // A MIME type of application/fedora-redirect signals that
                // the MIMETypedStream returned from the dissemination is
                // a special Fedora-specific MIME type. In this case, the
                // Fedora server will not proxy the datastream, but
                // instead perform a simple redirect to the URL contained
                // within the body of the MIMETypedStream. This special
                // MIME type is used primarily for streaming media where
                // it is more efficient to stream the data directly between
                // the streaming server and the browser client rather than
                // proxy it through the Fedora server.

                BufferedReader br =
                        new BufferedReader(new InputStreamReader(dissemination
                                .getStream()));
                StringBuffer sb = new StringBuffer();
                String line = null;
                while ((line = br.readLine()) != null) {
                    sb.append(line);
                }

                response.sendRedirect(sb.toString());
            } else {
                response.setContentType(dissemination.MIMEType);
                Property[] headerArray = dissemination.header;
                if (headerArray != null) {
                    for (int i = 0; i < headerArray.length; i++) {
                        if (headerArray[i].name != null
                                && !headerArray[i].name
                                        .equalsIgnoreCase("transfer-encoding")
                                && !headerArray[i].name
                                        .equalsIgnoreCase("content-type")) {
                            response.addHeader(headerArray[i].name,
                                               headerArray[i].value);
                            logger.debug("THIS WAS ADDED TO FEDORASERVLET "
                                    + "RESPONSE HEADER FROM ORIGINATING "
                                    + "PROVIDER " + headerArray[i].name + " : "
                                    + headerArray[i].value);
                        }
                    }
                }
                int byteStream = 0;
                logger.debug("Started reading dissemination stream");
                InputStream dissemResult = dissemination.getStream();
                byte[] buffer = new byte[BUF];
                while ((byteStream = dissemResult.read(buffer)) != -1) {
                    out.write(buffer, 0, byteStream);
                }
                buffer = null;
                dissemResult.close();
                dissemResult = null;
                out.flush();
                out.close();
                logger.debug("Finished reading dissemination stream");
            }
        } finally {
            dissemination.close();
        }
    }

    /**
     * <p>
     * A Thread to serialize an ObjectProfile object into XML.
     * </p>
     */
    public class ProfileSerializerThread
            extends Thread {

        private PipedWriter pw = null;

        private String PID = null;

        private ObjectProfile objProfile = null;

        private Date versDateTime = null;

        /**
         * <p>
         * Constructor for ProfileSerializeThread.
         * </p>
         *
         * @param PID
         *        The persistent identifier of the specified digital object.
         * @param objProfile
         *        An object profile data structure.
         * @param versDateTime
         *        The version datetime stamp of the request.
         * @param pw
         *        A PipedWriter to which the serialization info is written.
         */
        public ProfileSerializerThread(Context context,
                                       String PID,
                                       ObjectProfile objProfile,
                                       Date versDateTime,
                                       PipedWriter pw) {
            this.pw = pw;
            this.PID = PID;
            this.objProfile = objProfile;
            this.versDateTime = versDateTime;
        }

        /**
         * <p>
         * This method executes the thread.
         * </p>
         */
        @Override
        public void run() {
            if (pw != null) {
                try {
                    pw.write("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
                    pw.write("<objectProfile");
                    pw.write(" pid=\"" + StreamUtility.enc(PID) + "\"");
                    if (versDateTime != null) {
                        DateUtility.convertDateToString(versDateTime);
                        pw.write(" dateTime=\""
                                + DateUtility.convertDateToString(versDateTime)
                                + "\"");
                    }
                    pw.write(" xmlns=\"" + OBJ_PROFILE1_0.namespace.uri + "\"");
                    pw.write(" xmlns:xsi=\"" + XSI.uri + "\""
                            + " xsi:schemaLocation=\""
                            + OBJ_PROFILE1_0.namespace.uri + " "
                            + OBJ_PROFILE1_0.xsdLocation + "\">");

                    // PROFILE FIELDS SERIALIZATION
                    pw.write("<objLabel>"
                            + StreamUtility.enc(objProfile.objectLabel)
                            + "</objLabel>");
                    pw.write("<objOwnerId>"
                            + StreamUtility.enc(objProfile.objectOwnerId)
                            + "</objOwnerId>");

                    pw.write("<objModels>\n");
                    for (String model : objProfile.objectModels) {
                        pw.write("<model>" + model + "</model>\n");
                    }
                    pw.write("</objModels>");

                    String cDate =
                            DateUtility
                                    .convertDateToString(objProfile.objectCreateDate);
                    pw.write("<objCreateDate>" + cDate + "</objCreateDate>");
                    String mDate =
                            DateUtility
                                    .convertDateToString(objProfile.objectLastModDate);
                    pw.write("<objLastModDate>" + mDate + "</objLastModDate>");;

                    pw.write("<objDissIndexViewURL>"
                            + StreamUtility.enc(objProfile.dissIndexViewURL)
                            + "</objDissIndexViewURL>");
                    pw.write("<objItemIndexViewURL>"
                            + StreamUtility.enc(objProfile.itemIndexViewURL)
                            + "</objItemIndexViewURL>");
                    pw.write("</objectProfile>");
                    pw.flush();
                    pw.close();
                } catch (IOException ioe) {
                    logger.error("WriteThread IOException", ioe);
                } finally {
                    try {
                        if (pw != null) {
                            pw.close();
                        }
                    } catch (IOException ioe) {
                        logger.error("WriteThread IOException", ioe);
                    }
                }
            }
        }
    }

    /**
     * <p>
     * For now, treat a HTTP POST request just like a GET request.
     * </p>
     *
     * @param request
     *        The servet request.
     * @param response
     *        The servlet response.
     * @throws ServletException
     *         If thrown by <code>doGet</code>.
     * @throws IOException
     *         If thrown by <code>doGet</code>.
     */
    @Override
    public void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        doGet(request, response);
    }

}
TOP

Related Classes of org.fcrepo.server.access.FedoraAccessServlet$ProfileSerializerThread

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.