All Downloads are FREE. Search and download functionalities are using the official Maven repository.

java.fedora.server.storage.translation.FOXMLDOSerializer Maven / Gradle / Ivy

Go to download

The Fedora Client is a Java Library that allows API access to a Fedora Repository. The client is typically one part of a full Fedora installation.

The newest version!
/*
 * -----------------------------------------------------------------------------
 *
 * 

License and Copyright: The contents of this file are subject to the * Apache License, Version 2.0 (the "License"); you may not use * this file except in compliance with the License. You may obtain a copy of * the License at * http://www.fedora-commons.org/licenses.

* *

Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for * the specific language governing rights and limitations under the License.

* *

The entire file consists of original code.

*

Copyright © 2008 Fedora Commons, Inc.
*

Copyright © 2002-2007 The Rector and Visitors of the University of * Virginia and Cornell University
* All rights reserved.

* * ----------------------------------------------------------------------------- */ package fedora.server.storage.translation; import java.io.IOException; import java.io.OutputStream; import java.io.UnsupportedEncodingException; import java.util.Date; import java.util.Iterator; import java.util.List; import java.util.Map; import org.apache.log4j.Logger; import fedora.common.Constants; import fedora.server.errors.ObjectIntegrityException; import fedora.server.errors.StreamIOException; import fedora.server.errors.StreamWriteException; import fedora.server.storage.types.AuditRecord; import fedora.server.storage.types.DigitalObject; import fedora.server.storage.types.Datastream; import fedora.server.storage.types.DatastreamXMLMetadata; import fedora.server.storage.types.Disseminator; import fedora.server.storage.types.DSBinding; import fedora.server.utilities.DateUtility; import fedora.server.utilities.StreamUtility; import fedora.server.utilities.StringUtility; /** * Creates an XML serialization of a Fedora digital object in * accordance with the Fedora Object XML (FOXML) XML Schema defined at: * http://www.fedora.info/definitions/1/0/foxml1-0.xsd. * * The serializer uses the currently instantiated digital object * as input (see fedora.server.storage.types.DigitalObject). * * The serializer will adapt its output to a specific translation contexts. * See the static definitions of different translation contexts in * fedora.server.storage.translation.DOTranslationUtility.

* * @author [email protected] * @version $Id: FOXMLDOSerializer.java 6618 2008-02-19 12:17:43Z cwilper $ */ public class FOXMLDOSerializer implements DOSerializer, Constants { /** Logger for this class. */ private static final Logger LOG = Logger.getLogger( FOXMLDOSerializer.class.getName()); public static final String FOXML_NS="info:fedora/fedora-system:def/foxml#"; public static final String FEDORA_AUDIT_NS="info:fedora/fedora-system:def/audit#"; public static final String FOXML_PREFIX="foxml"; public static final String FOXML_XSD_LOCATION="http://www.fedora.info/definitions/1/0/foxml1-0.xsd"; public static final String XSI_NS="http://www.w3.org/2001/XMLSchema-instance"; private String m_fedoraAuditPrefix="audit"; private int m_transContext; public FOXMLDOSerializer() { } public DOSerializer getInstance() { return new FOXMLDOSerializer(); } public void serialize(DigitalObject obj, OutputStream out, String encoding, int transContext) throws ObjectIntegrityException, StreamIOException, UnsupportedEncodingException { LOG.debug("Serializing FOXML for transContext: " + transContext); m_transContext=transContext; StringBuffer buf=new StringBuffer(); appendXMLDeclaration(obj, encoding, buf); appendRootElementStart(obj, buf); appendProperties(obj, buf, encoding); appendAudit(obj, buf, encoding); appendDatastreams(obj, buf, encoding); appendDisseminators(obj, buf); appendRootElementEnd(buf); writeToStream(buf, out, encoding, true); } private void appendXMLDeclaration(DigitalObject obj, String encoding, StringBuffer buf) { buf.append("\n"); } private void appendRootElementStart(DigitalObject obj, StringBuffer buf) throws ObjectIntegrityException { buf.append("<" + FOXML_PREFIX + ":digitalObject xmlns:" + FOXML_PREFIX + "=\"" + StreamUtility.enc(FOXML_NS) + "\"\n"); String indent=" "; // make sure XSI_NS is mapped... String xsiPrefix=(String) obj.getNamespaceMapping().get(XSI_NS); if (xsiPrefix==null) { xsiPrefix="fedoraxsi"; obj.getNamespaceMapping().put(XSI_NS, "fedoraxsi"); // 99.999999999% chance this is unique } appendNamespaceDeclarations(indent,obj.getNamespaceMapping(),buf); // set schemaLocation to point to the official schema for FOXML. buf.append(indent + xsiPrefix + ":schemaLocation=\"" + StreamUtility.enc(FOXML_NS) + " " + StreamUtility.enc(FOXML_XSD_LOCATION) + "\"\n"); if (obj.getPid()==null || obj.getPid().equals("")) { throw new ObjectIntegrityException("Object must have a pid."); } String objectURIAttr=""; if (m_transContext==DOTranslationUtility.SERIALIZE_EXPORT_PUBLIC){ objectURIAttr=" FEDORA_URI=\"" + "info:fedora/" + obj.getPid() + "\""; } buf.append(indent + "PID=\"" + obj.getPid() + "\"" + objectURIAttr); buf.append(">\n"); } private void appendNamespaceDeclarations(String prepend, Map URIToPrefix, StringBuffer buf) { Iterator iter=URIToPrefix.keySet().iterator(); while (iter.hasNext()) { String URI=(String) iter.next(); String prefix=(String) URIToPrefix.get(URI); if (prefix!=null && !prefix.equals("")) { if (URI.equals(FEDORA_AUDIT_NS)) { m_fedoraAuditPrefix=prefix; } else if (!URI.equals(FOXML_NS)) { buf.append(prepend + "xmlns:" + prefix + "=\"" + StreamUtility.enc(URI) + "\"\n"); } } } buf.append(prepend + "xmlns:" + m_fedoraAuditPrefix + "=\"" + FEDORA_AUDIT_NS + "\"\n"); } private void appendProperties(DigitalObject obj, StringBuffer buf, String encoding) throws ObjectIntegrityException { String ftype = getTypeAttribute(obj); String state = getStateAttribute(obj); String ownerId = obj.getOwnerId(); String label = obj.getLabel(); Date cdate = obj.getCreateDate(); Date mdate = obj.getLastModDate(); String cmodel = obj.getContentModelId(); buf.append(" <" + FOXML_PREFIX + ":objectProperties>\n"); if (ftype!=null && !ftype.equals("")) { buf.append(" <" + FOXML_PREFIX + ":property NAME=\"" + RDF.TYPE.uri + "\"" + " VALUE=\"" + ftype + "\"/>\n"); } if (state!=null && !state.equals("")) { buf.append(" <" + FOXML_PREFIX + ":property NAME=\"" + MODEL.STATE.uri + "\"" + " VALUE=\"" + state + "\"/>\n"); } if (label!=null && !label.equals("")) { buf.append(" <" + FOXML_PREFIX + ":property NAME=\"" + MODEL.LABEL.uri + "\"" + " VALUE=\"" + StreamUtility.enc(label) + "\"/>\n"); } if (ownerId!=null && !ownerId.equals("")) { buf.append(" <" + FOXML_PREFIX + ":property NAME=\"" + MODEL.OWNER.uri + "\"" + " VALUE=\"" + StreamUtility.enc(ownerId) + "\"/>\n"); } if (cdate!=null) { buf.append(" <" + FOXML_PREFIX + ":property NAME=\"" + MODEL.CREATED_DATE.uri + "\"" + " VALUE=\"" + DateUtility.convertDateToString(cdate) + "\"/>\n"); } if (mdate!=null) { buf.append(" <" + FOXML_PREFIX + ":property NAME=\"" + VIEW.LAST_MODIFIED_DATE.uri + "\"" + " VALUE=\"" + DateUtility.convertDateToString(mdate) + "\"/>\n"); } if (cmodel!=null && !cmodel.equals("")) { buf.append(" <" + FOXML_PREFIX + ":property NAME=\"" + MODEL.CONTENT_MODEL.uri + "\"" + " VALUE=\"" + StreamUtility.enc(cmodel) + "\"/>\n"); } Iterator iter = obj.getExtProperties().keySet().iterator(); while (iter.hasNext()){ String name = (String)iter.next(); buf.append(" <" + FOXML_PREFIX + ":extproperty NAME=\"" + name + "\"" + " VALUE=\"" + obj.getExtProperty(name) + "\"/>\n"); } buf.append(" \n"); } private void appendDatastreams(DigitalObject obj, StringBuffer buf, String encoding) throws ObjectIntegrityException, UnsupportedEncodingException, StreamIOException { Iterator iter=obj.datastreamIdIterator(); while (iter.hasNext()) { String dsid = (String) iter.next(); // AUDIT datastream is rebuilt from the latest in-memory audit trail // which is a separate array list in the DigitalObject class. // So, ignore it here. if (dsid.equals("AUDIT") || dsid.equals("FEDORA-AUDITTRAIL")) { continue; } // Given a datastream ID, get all the datastream versions. // Use the first version to pick up the attributes common to all versions. List dsList = obj.datastreams(dsid); for (int i=0; i\n"); } // insert the ds version elements String altIdsAttr=""; String altIds=oneString(vds.DatastreamAltIDs); if (altIds!=null && !altIds.equals("")) { altIdsAttr=" ALT_IDS=\"" + StreamUtility.enc(altIds) + "\""; } String formatURIAttr=""; if (vds.DSFormatURI!=null && !vds.DSFormatURI.equals("")) { formatURIAttr=" FORMAT_URI=\"" + StreamUtility.enc(vds.DSFormatURI) + "\""; } String dateAttr=""; if (vds.DSCreateDT!=null) { dateAttr=" CREATED=\"" + DateUtility.convertDateToString(vds.DSCreateDT) + "\""; } buf.append(" <" + FOXML_PREFIX + ":datastreamVersion ID=\"" + vds.DSVersionID + "\"" + " LABEL=\"" + StreamUtility.enc(vds.DSLabel) + "\"" + dateAttr + altIdsAttr + " MIMETYPE=\"" + StreamUtility.enc(vds.DSMIME) + "\"" + formatURIAttr + " SIZE=\"" + vds.DSSize + "\">\n"); // FIXME: In future release, add digest of datastream content. // First we need to decide how the digest is managed. Is it // automatically calculated by DefaultManagement during API-M // operations? What purposes will it serve? This is part of // Fedora Phase II. buf.append(" <" + FOXML_PREFIX + ":contentDigest TYPE=\""+ vds.getChecksumType() +"\"" + " DIGEST=\"" + vds.getChecksum() + "\"/>\n"); // if E or R insert ds content location as URL if (vds.DSControlGrp.equalsIgnoreCase("E") || vds.DSControlGrp.equalsIgnoreCase("R") ) { buf.append(" <" + FOXML_PREFIX + ":contentLocation TYPE=\"" + "URL\"" + " REF=\"" + StreamUtility.enc( DOTranslationUtility.normalizeDSLocationURLs( obj.getPid(), vds, m_transContext).DSLocation) + "\"/>\n"); // if M insert ds content location as an internal identifier } else if (vds.DSControlGrp.equalsIgnoreCase("M")) { if (m_transContext==DOTranslationUtility.SERIALIZE_EXPORT_ARCHIVE) { buf.append(" <" + FOXML_PREFIX + ":binaryContent> \n" + StringUtility.splitAndIndent( StreamUtility.encodeBase64(vds.getContentStream()), 14, 80) + " \n"); } else { buf.append(" <" + FOXML_PREFIX + ":contentLocation TYPE=\"" + "INTERNAL_ID\"" + " REF=\"" + StreamUtility.enc( DOTranslationUtility.normalizeDSLocationURLs( obj.getPid(), vds, m_transContext).DSLocation) + "\"/>\n"); } // if X insert inline XML } else if (vds.DSControlGrp.equalsIgnoreCase("X")) { appendInlineXML(obj.getFedoraObjectType(), (DatastreamXMLMetadata)vds, buf, encoding); } buf.append(" \n"); // if it's the last version, wrap-up with closing datastream element. if (i==(dsList.size() - 1)) { buf.append(" \n"); } } } } private void appendAudit(DigitalObject obj, StringBuffer buf, String encoding) throws ObjectIntegrityException { if (obj.getAuditRecords().size()>0) { // Audit trail datastream re-created from audit records. // There is only ONE version of the audit trail datastream! String dsURIAttr=""; if (m_transContext==DOTranslationUtility.SERIALIZE_EXPORT_PUBLIC){ dsURIAttr=" FEDORA_URI=\"" + "info:fedora/" + obj.getPid() + "/AUDIT" + "\""; } buf.append(" <" + FOXML_PREFIX + ":datastream ID=\"" + "AUDIT" + "\"" + dsURIAttr + " STATE=\"" + "A" + "\"" + " CONTROL_GROUP=\"" + "X" + "\"" + " VERSIONABLE=\"" + "false" + "\">\n"); // insert the ds version-level elements buf.append(" <" + FOXML_PREFIX + ":datastreamVersion ID=\"" + "AUDIT.0" + "\"" + " LABEL=\"" + "Fedora Object Audit Trail" + "\"" + " CREATED=\"" + DateUtility.convertDateToString(obj.getCreateDate()) + "\"" + " MIMETYPE=\"" + "text/xml" + "\"" + " FORMAT_URI=\"" + "info:fedora/fedora-system:format/xml.fedora.audit" + "\">\n"); buf.append(" <" + FOXML_PREFIX + ":xmlContent>\n"); buf.append(" <" + m_fedoraAuditPrefix + ":auditTrail xmlns:" + m_fedoraAuditPrefix + "=\"" + FEDORA_AUDIT_NS + "\">\n"); for (int i=0; i\n"); buf.append(" <" + m_fedoraAuditPrefix + ":process type=\"" + StreamUtility.enc(audit.processType) + "\"/>\n"); buf.append(" <" + m_fedoraAuditPrefix + ":action>" + StreamUtility.enc(audit.action) + "\n"); buf.append(" <" + m_fedoraAuditPrefix + ":componentID>" + StreamUtility.enc(audit.componentID) + "\n"); buf.append(" <" + m_fedoraAuditPrefix + ":responsibility>" + StreamUtility.enc(audit.responsibility) + "\n"); buf.append(" <" + m_fedoraAuditPrefix + ":date>" + DateUtility.convertDateToString(audit.date) + "\n"); buf.append(" <" + m_fedoraAuditPrefix + ":justification>" + StreamUtility.enc(audit.justification) + "\n"); buf.append(" \n"); } buf.append(" \n"); buf.append(" \n"); // FUTURE: Add digest of datastream content /* buf.append(" <" + FOXML_PREFIX + ":contentDigest TYPE=\"MD5\"" + " DIGEST=\"future: hash of content goes here\"/>\n"); */ buf.append(" \n"); buf.append(" \n"); } } private void appendInlineXML(int fedoraObjectType, DatastreamXMLMetadata ds, StringBuffer buf, String encoding) throws ObjectIntegrityException, UnsupportedEncodingException, StreamIOException { buf.append(" <" + FOXML_PREFIX + ":xmlContent>\n"); // Relative Repository URLs: If it's a WSDL or SERVICE-PROFILE datastream // in a BMech object search for any embedded URLs that are relative to // the local repository (like internal service URLs) and make sure they // are converted appropriately for the translation context. if ( fedoraObjectType==DigitalObject.FEDORA_BMECH_OBJECT && (ds.DatastreamID.equals("SERVICE-PROFILE") || ds.DatastreamID.equals("WSDL")) ) { // FIXME! We need a more efficient way than to search // the whole block of inline XML. We really only want to // look at service URLs in the XML. buf.append(DOTranslationUtility.normalizeInlineXML( new String(ds.xmlContent, "UTF-8").trim(), m_transContext)); } else { DOTranslationUtility.appendXMLStream(ds.getContentStream(), buf, encoding); } buf.append("\n \n"); } private void appendDisseminators(DigitalObject obj, StringBuffer buf) throws ObjectIntegrityException { Iterator dissIdIter=obj.disseminatorIdIterator(); while (dissIdIter.hasNext()) { String did=(String) dissIdIter.next(); Iterator dissIter=obj.disseminators(did).iterator(); List dissList = obj.disseminators(did); for (int i=0; i\n"); } // insert the disseminator version-level elements String dissLabelAttr=""; if (vdiss.dissLabel!=null && !vdiss.dissLabel.equals("")) { dissLabelAttr=" LABEL=\"" + StreamUtility.enc(vdiss.dissLabel) + "\""; } String dateAttr=""; if (vdiss.dissCreateDT!=null) { dateAttr=" CREATED=\"" + DateUtility.convertDateToString(vdiss.dissCreateDT) + "\""; } buf.append(" <" + FOXML_PREFIX + ":disseminatorVersion ID=\"" + vdiss.dissVersionID + "\"" + dissLabelAttr + " BMECH_SERVICE_PID=\"" + vdiss.bMechID + "\"" + dateAttr + ">\n"); // datastream bindings... DSBinding[] bindings = vdiss.dsBindMap.dsBindings; buf.append(" <" + FOXML_PREFIX + ":serviceInputMap>\n"); for (int j=0; j\n"); } buf.append(" \n"); buf.append(" \n"); } buf.append(" \n"); } } private void appendRootElementEnd(StringBuffer buf) { buf.append(""); } private void validateAudit(AuditRecord audit) throws ObjectIntegrityException { if (audit.id==null || audit.id.equals("")) { throw new ObjectIntegrityException("Audit record must have id."); } if (audit.date==null || audit.date.equals("")) { throw new ObjectIntegrityException("Audit record must have date."); } if (audit.processType==null || audit.processType.equals("")) { throw new ObjectIntegrityException("Audit record must have processType."); } if (audit.action==null || audit.action.equals("")) { throw new ObjectIntegrityException("Audit record must have action."); } if (audit.componentID==null) { audit.componentID = ""; // for backwards compatibility, no error on null // throw new ObjectIntegrityException("Audit record must have componentID."); } if (audit.responsibility==null || audit.responsibility.equals("")) { throw new ObjectIntegrityException("Audit record must have responsibility."); } } private String getTypeAttribute(DigitalObject obj) throws ObjectIntegrityException { int t=obj.getFedoraObjectType(); if (t==DigitalObject.FEDORA_BDEF_OBJECT) { return MODEL.BDEF_OBJECT.localName; } else if (t==DigitalObject.FEDORA_BMECH_OBJECT) { return MODEL.BMECH_OBJECT.localName; } else if (t==DigitalObject.FEDORA_OBJECT) { return MODEL.DATA_OBJECT.localName; } else { throw new ObjectIntegrityException("Object must have a FedoraObjectType."); } } private String getStateAttribute(DigitalObject obj) { try { char s = obj.getState().toUpperCase().charAt(0); if (s == 'D') { return MODEL.DELETED.localName; } else if (s == 'I') { return MODEL.INACTIVE.localName; } else { return MODEL.ACTIVE.localName; } } catch (Throwable th) { return null; } } private String oneString(String[] idList){ StringBuffer out=new StringBuffer(); for (int i=0; i0) { out.append(' '); } out.append((String) idList[i]); } return out.toString(); } private void writeToStream(StringBuffer buf, OutputStream out, String encoding, boolean closeWhenFinished) throws StreamIOException, UnsupportedEncodingException { try { out.write(buf.toString().getBytes(encoding)); out.flush(); } catch (IOException ioe) { throw new StreamWriteException("Problem serializing to FOXML: " + ioe.getMessage()); } finally { if (closeWhenFinished) { try { out.close(); } catch (IOException ioe2) { throw new StreamWriteException("Problem closing stream after " + " serializing to FOXML: " + ioe2.getMessage()); } } } } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy