/* 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.File;
import java.io.IOException;
import java.io.InputStream;
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.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.ws.rs.core.HttpHeaders;
import javax.xml.transform.Templates;
import javax.xml.transform.Transformer;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
import org.apache.http.HttpStatus;
import org.fcrepo.common.Constants;
import org.fcrepo.server.Context;
import org.fcrepo.server.ReadOnlyContext;
import org.fcrepo.server.errors.DatastreamNotFoundException;
import org.fcrepo.server.errors.DisseminationException;
import org.fcrepo.server.errors.GeneralException;
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:
*
* 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>
* <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>
*
* 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>
* <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>
*
* GetDatastreamDissemination URL syntax:
* <p>
* protocol://hostname:port/fedora/get/PID/DSID[/dateTime]
* </p><p>
* This syntax requests a datastream dissemination for the specified digital
* object. It is used to return the contents of a datastream.
* </p>
* <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>
*
* @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";
/** 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;
// Portion of initial request URL from protocol up to query string
// Moved to a local variable to be thread-safe
String requestURI = request.getQueryString() != null ?
request.getRequestURL().toString() + "?" + request.getQueryString()
: request.getRequestURL().toString();
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
//
// use substring to avoid an additional char array copy
String[] URIArray = requestURI.substring(0, request.getRequestURL().length()).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 = Boolean.parseBoolean(request.getParameter(name));
} 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={}, asOfDate={})", PID, 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={}, sDefPID={}, methodName={}, asOfDate={})",
PID, sDefPID, methodName, 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={}, dsID={}, asOfDate={})",
PID, dsID, 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(), EMPTY_STRING_ARRAY);
} catch (DatastreamNotFoundException e) {
logger.error("Datastream not found for request: " + requestURI
+ " (actionLabel=" + actionLabel + ")", e);
throw new NotFound404Exception("", e, request, actionLabel, e
.getMessage(), EMPTY_STRING_ARRAY);
} catch (ObjectNotFoundException e) {
logger.error("Object not found for request: " + requestURI
+ " (actionLabel=" + actionLabel + ")", e);
throw new NotFound404Exception("", e, request, actionLabel, e
.getMessage(), EMPTY_STRING_ARRAY);
} catch (DisseminationException e) {
logger.error("Dissemination failed: " + requestURI
+ " (actionLabel=" + actionLabel + ")", e);
throw new NotFound404Exception("", e, request, actionLabel, e
.getMessage(), EMPTY_STRING_ARRAY);
} catch (ObjectNotInLowlevelStorageException e) {
logger.error("Object or datastream not found for request: "
+ requestURI + " (actionLabel=" + actionLabel + ")", e);
throw new NotFound404Exception("", e, request, actionLabel, e
.getMessage(), EMPTY_STRING_ARRAY);
} catch (AuthzException ae) {
logger.error("Authorization failed for request: " + requestURI
+ " (actionLabel=" + actionLabel + ")", ae);
throw RootException.getServletException(ae,
request,
actionLabel,
EMPTY_STRING_ARRAY);
} catch (Throwable th) {
logger.error("Unexpected error servicing API-A request", th);
throw new InternalError500Exception("",
th,
request,
actionLabel,
"",
EMPTY_STRING_ARRAY);
}
}
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.getStatusCode() == HttpStatus.SC_MOVED_TEMPORARILY) {
String location = "";
for (Property prop: dissemination.header) {
if (prop.name.equalsIgnoreCase(HttpHeaders.LOCATION)) {
location = prop.value;
break;
}
}
response.sendRedirect(location);
} else {
int status = dissemination.getStatusCode();
response.setStatus(status);
if (status == HttpStatus.SC_OK) {
response.setContentType(dissemination.getMIMEType());
}
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.getStatusCode() == HttpStatus.SC_MOVED_TEMPORARILY) {
String location = "";
for (Property prop: dissemination.header) {
if (prop.name.equalsIgnoreCase(HttpHeaders.LOCATION)) {
location = prop.value;
break;
}
}
response.sendRedirect(location);
} else {
response.setContentType(dissemination.getMIMEType());
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 pid=\"");
StreamUtility.enc(PID, pw);
pw.write('"');
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, pw);
pw.write("</objLabel>");
pw.write("<objOwnerId>");
StreamUtility.enc(objProfile.objectOwnerId, pw);
pw.write("</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, pw);
pw.write("</objDissIndexViewURL>");
pw.write("<objItemIndexViewURL>");
StreamUtility.enc(objProfile.itemIndexViewURL, pw);
pw.write("</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);
}
}