/* 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 fedora.server.management; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.rmi.RemoteException; import java.util.Date; import org.apache.axis.types.NonNegativeInteger; import org.apache.log4j.Logger; import fedora.common.Constants; import fedora.server.ReadOnlyContext; import fedora.server.Server; import fedora.server.errors.InitializationException; import fedora.server.errors.ServerInitializationException; import fedora.server.errors.StorageDeviceException; import fedora.server.utilities.AxisUtility; import fedora.server.utilities.DateUtility; import fedora.server.utilities.TypeUtility; /** * Implements the Fedora management SOAP service. * * @author Chris Wilper */ public class FedoraAPIMBindingSOAPHTTPImpl implements Constants, FedoraAPIM { /** Logger for this class. */ private static final Logger LOG = Logger.getLogger(FedoraAPIMBindingSOAPHTTPImpl.class); /** The Fedora Server instance */ private static Server s_server; /** * Whether the service has initialized... true if we got a good Server * instance. */ private static boolean s_initialized; /** The exception indicating that initialization failed. */ private static InitializationException s_initException; private static Management s_management; /** Before fulfilling any requests, make sure we have a server instance. */ static { try { String fedoraHome = Constants.FEDORA_HOME; if (fedoraHome == null) { s_initialized = false; s_initException = new ServerInitializationException("Server failed to initialize: FEDORA_HOME is undefined"); } else { s_server = Server.getInstance(new File(fedoraHome), false); s_initialized = true; s_management = (Management) s_server .getModule("fedora.server.management.Management"); } } catch (InitializationException ie) { LOG.error("Error getting server", ie); s_initialized = false; s_initException = ie; } } public String ingest(byte[] XML, String format, String logMessage) throws java.rmi.RemoteException { LOG.debug("start: ingest"); assertInitialized(); try { // always gens pid, unless pid in stream starts with "test:" "demo:" // or other prefix that is configured in the retainPIDs parameter of // fedora.fcfg return s_management.ingest(ReadOnlyContext.getSoapContext(), new ByteArrayInputStream(XML), logMessage, format, "UTF-8", true); } catch (Throwable th) { LOG.error("Error ingesting", th); throw AxisUtility.getFault(th); } finally { LOG.debug("end: ingest"); } } public String modifyObject(String PID, String state, String label, String ownerId, String logMessage) throws RemoteException { LOG.debug("start: modifyObject, " + PID); assertInitialized(); try { return DateUtility.convertDateToString(s_management .modifyObject(ReadOnlyContext.getSoapContext(), PID, state, label, ownerId, logMessage)); } catch (Throwable th) { LOG.error("Error modifying object", th); throw AxisUtility.getFault(th); } finally { LOG.debug("end: modifyObject, " + PID); } } public byte[] getObjectXML(String PID) throws RemoteException { assertInitialized(); try { InputStream in = s_management.getObjectXML(ReadOnlyContext.getSoapContext(), PID, "UTF-8"); ByteArrayOutputStream out = new ByteArrayOutputStream(); pipeStream(in, out); return out.toByteArray(); } catch (Throwable th) { LOG.error("Error getting object XML", th); throw AxisUtility.getFault(th); } } public byte[] export(String PID, String format, String exportContext) throws RemoteException { assertInitialized(); try { InputStream in = s_management.export(ReadOnlyContext.getSoapContext(), PID, format, exportContext, "UTF-8"); ByteArrayOutputStream out = new ByteArrayOutputStream(); pipeStream(in, out); return out.toByteArray(); } catch (Throwable th) { LOG.error("Error exporting object", th); throw AxisUtility.getFault(th); } } // temporarily here private void pipeStream(InputStream in, OutputStream out) throws StorageDeviceException { try { byte[] buf = new byte[4096]; int len; while ((len = in.read(buf)) != -1) { out.write(buf, 0, len); } } catch (IOException ioe) { throw new StorageDeviceException("Error writing to stream"); } finally { try { out.close(); in.close(); } catch (IOException closeProb) { // ignore problems while closing } } } public String purgeObject(String PID, String logMessage, boolean force) throws java.rmi.RemoteException { LOG.debug("start: purgeObject, " + PID); assertInitialized(); try { return DateUtility.convertDateToString(s_management .purgeObject(ReadOnlyContext.getSoapContext(), PID, logMessage, force)); } catch (Throwable th) { LOG.error("Error purging object", th); throw AxisUtility.getFault(th); } finally { LOG.debug("end: purgeObject, " + PID); } } public String addDatastream(String pid, String dsID, String[] altIds, String label, boolean versionable, String MIMEType, String formatURI, String location, String controlGroup, String dsState, String checksumType, String checksum, String logMessage) throws RemoteException { LOG.debug("start: addDatastream, " + pid + ", " + dsID); assertInitialized(); try { return s_management.addDatastream(ReadOnlyContext.getSoapContext(), pid, dsID, altIds, label, versionable, MIMEType, formatURI, location, controlGroup, dsState, checksumType, checksum, logMessage); } catch (Throwable th) { LOG.error("Error adding datastream", th); throw AxisUtility.getFault(th); } finally { LOG.debug("end: addDatastream, " + pid + ", " + dsID); } } public String modifyDatastreamByReference(String PID, String datastreamID, String[] altIDs, String dsLabel, String mimeType, String formatURI, String dsLocation, String checksumType, String checksum, String logMessage, boolean force) throws java.rmi.RemoteException { LOG.debug("start: modifyDatastreamByReference, " + PID + ", " + datastreamID); assertInitialized(); try { return DateUtility.convertDateToString(s_management .modifyDatastreamByReference(ReadOnlyContext .getSoapContext(), PID, datastreamID, altIDs, dsLabel, mimeType, formatURI, dsLocation, checksumType, checksum, logMessage, force)); } catch (Throwable th) { LOG.error("Error modifying datastream by reference", th); throw AxisUtility.getFault(th); } finally { LOG.debug("end: modifyDatastreamByReference, " + PID + ", " + datastreamID); } } public String modifyDatastreamByValue(String PID, String datastreamID, String[] altIDs, String dsLabel, String mimeType, String formatURI, byte[] dsContent, String checksumType, String checksum, String logMessage, boolean force) throws java.rmi.RemoteException { LOG.debug("start: modifyDatastreamByValue, " + PID + ", " + datastreamID); assertInitialized(); try { ByteArrayInputStream byteStream = null; if (dsContent != null && dsContent.length > 0) { byteStream = new ByteArrayInputStream(dsContent); } return DateUtility.convertDateToString(s_management .modifyDatastreamByValue(ReadOnlyContext.getSoapContext(), PID, datastreamID, altIDs, dsLabel, mimeType, formatURI, byteStream, checksumType, checksum, logMessage, force)); } catch (Throwable th) { LOG.error("Error modifying datastream by value", th); throw AxisUtility.getFault(th); } finally { LOG.debug("end: modifyDatastreamByValue, " + PID + ", " + datastreamID); } } public String setDatastreamState(String PID, String datastreamID, String dsState, String logMessage) throws java.rmi.RemoteException { assertInitialized(); try { return DateUtility.convertDateToString(s_management .setDatastreamState(ReadOnlyContext.getSoapContext(), PID, datastreamID, dsState, logMessage)); } catch (Throwable th) { LOG.error("Error setting datastream state", th); throw AxisUtility.getFault(th); } } public String setDatastreamVersionable(String PID, String datastreamID, boolean versionable, String logMessage) throws java.rmi.RemoteException { assertInitialized(); try { return DateUtility.convertDateToString(s_management .setDatastreamVersionable(ReadOnlyContext.getSoapContext(), PID, datastreamID, versionable, logMessage)); } catch (Throwable th) { LOG.error("Error setting datastream versionable", th); throw AxisUtility.getFault(th); } } public String compareDatastreamChecksum(String PID, String datastreamID, String versionDate) throws java.rmi.RemoteException { assertInitialized(); try { return s_management.compareDatastreamChecksum(ReadOnlyContext .getSoapContext(), PID, datastreamID, DateUtility .convertStringToDate(versionDate)); } catch (Throwable th) { LOG.error("Error comparing datastream checksum", th); throw AxisUtility.getFault(th); } } public String[] purgeDatastream(String PID, String datastreamID, String startDT, String endDT, String logMessage, boolean force) throws java.rmi.RemoteException { LOG.debug("start: purgeDatastream, " + PID + ", " + datastreamID); assertInitialized(); try { return toStringArray(s_management.purgeDatastream(ReadOnlyContext .getSoapContext(), PID, datastreamID, DateUtility .convertStringToDate(startDT), DateUtility .convertStringToDate(endDT), logMessage, force)); } catch (Throwable th) { LOG.error("Error purging datastream", th); throw AxisUtility.getFault(th); } finally { LOG.debug("end: purgeDatastream, " + PID + ", " + datastreamID); } } private String[] toStringArray(Date[] dates) throws Exception { String[] out = new String[dates.length]; for (int i = 0; i < dates.length; i++) { out[i] = DateUtility.convertDateToString(dates[i]); } return out; } public fedora.server.types.gen.Datastream getDatastream(String PID, String datastreamID, String asOfDateTime) throws java.rmi.RemoteException { assertInitialized(); try { fedora.server.storage.types.Datastream ds = s_management .getDatastream(ReadOnlyContext.getSoapContext(), PID, datastreamID, DateUtility .convertStringToDate(asOfDateTime)); return TypeUtility.convertDatastreamToGenDatastream(ds); } catch (Throwable th) { LOG.error("Error getting datastream", th); throw AxisUtility.getFault(th); } } public fedora.server.types.gen.Datastream[] getDatastreams(String PID, String asOfDateTime, String state) throws java.rmi.RemoteException { assertInitialized(); try { fedora.server.storage.types.Datastream[] intDatastreams = s_management.getDatastreams(ReadOnlyContext .getSoapContext(), PID, DateUtility .convertStringToDate(asOfDateTime), state); return getGenDatastreams(intDatastreams); } catch (Throwable th) { LOG.error("Error getting datastreams", th); throw AxisUtility.getFault(th); } } private fedora.server.types.gen.Datastream[] getGenDatastreams(fedora.server.storage.types.Datastream[] intDatastreams) { fedora.server.types.gen.Datastream[] genDatastreams = new fedora.server.types.gen.Datastream[intDatastreams.length]; for (int i = 0; i < intDatastreams.length; i++) { genDatastreams[i] = TypeUtility .convertDatastreamToGenDatastream(intDatastreams[i]); } return genDatastreams; } private fedora.server.types.gen.RelationshipTuple[] getGenRelsTuples(fedora.server.storage.types.RelationshipTuple[] intRelsTuples) { fedora.server.types.gen.RelationshipTuple[] genRelsTuples = new fedora.server.types.gen.RelationshipTuple[intRelsTuples.length]; for (int i = 0; i < intRelsTuples.length; i++) { genRelsTuples[i] = TypeUtility .convertRelsTupleToGenRelsTuple(intRelsTuples[i]); } return genRelsTuples; } public fedora.server.types.gen.Datastream[] getDatastreamHistory(String PID, String datastreamID) throws java.rmi.RemoteException { assertInitialized(); try { fedora.server.storage.types.Datastream[] intDatastreams = s_management.getDatastreamHistory(ReadOnlyContext .getSoapContext(), PID, datastreamID); return getGenDatastreams(intDatastreams); } catch (Throwable th) { LOG.error("Error getting datastream history", th); throw AxisUtility.getFault(th); } } public java.lang.String[] getNextPID(NonNegativeInteger numPIDs, String namespace) throws java.rmi.RemoteException { LOG.debug("start: getNextPID"); assertInitialized(); try { if (numPIDs == null) { numPIDs = new NonNegativeInteger("1"); } return s_management.getNextPID(ReadOnlyContext.getSoapContext(), numPIDs.intValue(), namespace); } catch (Throwable th) { LOG.error("Error getting next PID", th); throw AxisUtility.getFault(th); } finally { LOG.debug("end: getNextPID"); } } private void assertInitialized() throws java.rmi.RemoteException { if (!s_initialized) { AxisUtility.throwFault(s_initException); } } public fedora.server.types.gen.RelationshipTuple[] getRelationships(String subject, String relationship) throws java.rmi.RemoteException { LOG.debug("start: getRelationships"); assertInitialized(); try { fedora.server.storage.types.RelationshipTuple[] intRelationshipTuples = null; intRelationshipTuples = s_management.getRelationships(ReadOnlyContext .getSoapContext(), subject, relationship); return getGenRelsTuples(intRelationshipTuples); } catch (Throwable th) { LOG.error("Error getting relationships", th); throw AxisUtility.getFault(th); } finally { LOG.debug("end: getRelationships"); } } public boolean addRelationship(String subject, String relationship, String object, boolean isLiteral, String datatype) throws java.rmi.RemoteException { LOG.debug("start: addRelationship"); assertInitialized(); try { return s_management.addRelationship(ReadOnlyContext .getSoapContext(), subject, relationship, object, isLiteral, datatype); } catch (Throwable th) { LOG.error("Error adding relationships", th); throw AxisUtility.getFault(th); } finally { LOG.debug("end: addRelationship"); } } public boolean purgeRelationship(String subject, String relationship, String object, boolean isLiteral, String datatype) throws java.rmi.RemoteException { LOG.debug("start: purgeRelationship"); assertInitialized(); try { return s_management.purgeRelationship(ReadOnlyContext .getSoapContext(), subject, relationship, object, isLiteral, datatype); } catch (Throwable th) { LOG.error("Error purging relationships", th); throw AxisUtility.getFault(th); } finally { LOG.debug("end: purgeRelationship"); } } }