/** * The contents of this file are subject to the license and copyright * detailed in the LICENSE and NOTICE files at the root of the source * tree and available online at * * http://www.dspace.org/license/ */ package org.dspace.content.crosswalk; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.sql.SQLException; import java.util.List; import org.dspace.authorize.AuthorizeException; import org.dspace.content.DSpaceObject; import org.dspace.content.packager.PackageDisseminator; import org.dspace.content.packager.PackageException; import org.dspace.content.packager.PackageIngester; import org.dspace.content.packager.PackageParameters; import org.dspace.content.packager.RoleDisseminator; import org.dspace.core.ConfigurationManager; import org.dspace.core.Constants; import org.dspace.core.Context; import org.dspace.core.PluginManager; import org.jdom.Document; import org.jdom.Element; import org.jdom.JDOMException; import org.jdom.Namespace; import org.jdom.input.SAXBuilder; import org.jdom.output.XMLOutputter; /** * Role Crosswalk * <p> * Translate between DSpace Group & EPeople definitions and a DSpace-specific * XML export format (generated by the RoleDisseminator). This is primarily * used for AIPs, but may be used by other Packagers as necessary. * <p> * This crosswalk allows you to export DSpace Groups & EPeople to this XML * structured format. It also allows you to import an XML file of this format * in order to restore DSpace Groups and EPeople defined within it. * <p> * This is just wrappers; the real work is done in RoleDisseminator and * RoleIngester. * * @author mwood * @author Tim Donohue * @see org.dspace.content.packager.RoleDisseminator * @see org.dspace.content.packager.RoleIngester * @see AbstractPackagerWrappingCrosswalk * @see IngestionCrosswalk * @see DisseminationCrosswalk */ public class RoleCrosswalk extends AbstractPackagerWrappingCrosswalk implements IngestionCrosswalk, DisseminationCrosswalk { // Plugin Name of DSPACE-ROLES packager to use for ingest/dissemination // (Whatever plugin is defined with this name in 'dspace.cfg' will be used by this Crosswalk) private static final String ROLE_PACKAGER_PLUGIN = "DSPACE-ROLES"; // ---- Dissemination Methods ----------- /** * Get XML namespaces of the elements this crosswalk may return. * Returns the XML namespaces (as JDOM objects) of the root element. * * @return array of namespaces, which may be empty. */ @Override public Namespace[] getNamespaces() { Namespace result[] = new Namespace[1]; result[0] = RoleDisseminator.DSROLES_NS; return result; } /** * Get the XML Schema location(s) of the target metadata format. * Returns the string value of the <code>xsi:schemaLocation</code> * attribute that should be applied to the generated XML. * <p> * It may return the empty string if no schema is known, but crosswalk * authors are strongly encouraged to implement this call so their output * XML can be validated correctly. * @return SchemaLocation string, including URI namespace, followed by * whitespace and URI of XML schema document, or empty string if unknown. */ @Override public String getSchemaLocation() { return ""; } /** * Predicate: Can this disseminator crosswalk the given object. * * @param dso dspace object, e.g. an <code>Item</code>. * @return true when disseminator is capable of producing metadata. */ @Override public boolean canDisseminate(DSpaceObject dso) { //We can only disseminate SITE, COMMUNITY or COLLECTION objects, //as Groups are only associated with those objects. return (dso.getType() == Constants.SITE || dso.getType() == Constants.COMMUNITY || dso.getType() == Constants.COLLECTION); } /** * Predicate: Does this disseminator prefer to return a list of Elements, * rather than a single root Element? * * @return true when disseminator prefers you call disseminateList(). */ @Override public boolean preferList() { //We prefer disseminators call 'disseminateElement()' instead of 'disseminateList()' return false; } /** * Execute crosswalk, returning List of XML elements. * Returns a <code>List</code> of JDOM <code>Element</code> objects representing * the XML produced by the crosswalk. This is typically called when * a list of fields is desired, e.g. for embedding in a METS document * <code>xmlData</code> field. * <p> * When there are no results, an * empty list is returned, but never <code>null</code>. * * @param dso the DSpace Object whose metadata to export. * @return results of crosswalk as list of XML elements. * * @throws CrosswalkInternalException (<code>CrosswalkException</code>) failure of the crosswalk itself. * @throws CrosswalkObjectNotSupported (<code>CrosswalkException</code>) Cannot crosswalk this kind of DSpace object. * @throws IOException I/O failure in services this calls * @throws SQLException Database failure in services this calls * @throws AuthorizeException current user not authorized for this operation. */ @Override public List<Element> disseminateList(DSpaceObject dso) throws CrosswalkException, IOException, SQLException, AuthorizeException { Element dim = disseminateElement(dso); return dim.getChildren(); } /** * Execute crosswalk, returning one XML root element as * a JDOM <code>Element</code> object. * This is typically the root element of a document. * <p> * * @param dso the DSpace Object whose metadata to export. * @return root Element of the target metadata, never <code>null</code> * * @throws CrosswalkInternalException (<code>CrosswalkException</code>) failure of the crosswalk itself. * @throws CrosswalkObjectNotSupported (<code>CrosswalkException</code>) Cannot crosswalk this kind of DSpace object. * @throws IOException I/O failure in services this calls * @throws SQLException Database failure in services this calls * @throws AuthorizeException current user not authorized for this operation. */ @Override public Element disseminateElement(DSpaceObject dso) throws CrosswalkException, IOException, SQLException, AuthorizeException { try { PackageDisseminator dip = (PackageDisseminator) PluginManager.getNamedPlugin(PackageDisseminator.class, ROLE_PACKAGER_PLUGIN); if (dip == null) { throw new CrosswalkInternalException("Cannot find a PackageDisseminator plugin named " + ROLE_PACKAGER_PLUGIN); } // Create a temporary file to disseminate into String tempDirectory = ConfigurationManager.getProperty("upload.temp.dir"); File tempFile = File.createTempFile("RoleCrosswalkDisseminate" + dso.hashCode(), null, new File(tempDirectory)); tempFile.deleteOnExit(); // Initialize our packaging parameters PackageParameters pparams; if(this.getPackagingParameters()!=null) { pparams = this.getPackagingParameters(); } else { pparams = new PackageParameters(); } //actually disseminate to our temp file. Context context = new Context(); dip.disseminate(context, dso, pparams, tempFile); context.complete(); // if we ended up with a Zero-length output file, // this means dissemination was successful but had no results if(tempFile.exists() && tempFile.length()==0) { return null; } try { //Try to parse our XML results (which were disseminated by the Packager) SAXBuilder builder = new SAXBuilder(); Document xmlDocument = builder.build(tempFile); //If XML parsed successfully, return root element of doc if(xmlDocument!=null && xmlDocument.hasRootElement()) { return xmlDocument.getRootElement(); } else { return null; } } catch (JDOMException je) { throw new MetadataValidationException("Error parsing Roles XML (see wrapped error message for more details) ",je); } } catch (PackageException pe) { throw new CrosswalkInternalException("Failed to export Roles via packager (see wrapped error message for more details) ",pe); } } // ---- Ingestion Methods ----------- /** * Ingest a List of XML elements * * @param context * @param dso * @param metadata * @throws CrosswalkException * @throws IOException * @throws SQLException * @throws AuthorizeException */ @Override public void ingest(Context context, DSpaceObject dso, List<Element> metadata) throws CrosswalkException, IOException, SQLException, AuthorizeException { if(!metadata.isEmpty()) { ingest(context, dso, ((Element) metadata.get(0)).getParentElement()); } } /** * Ingest a whole XML document, starting at specified root. * <P> * This essentially just wraps a call to the configured Role PackageIngester. * * @param context * @param dso * @param root * @throws CrosswalkException * @throws IOException * @throws SQLException * @throws AuthorizeException */ @Override public void ingest(Context context, DSpaceObject dso, Element root) throws CrosswalkException, IOException, SQLException, AuthorizeException { if (dso.getType() != Constants.SITE && dso.getType() != Constants.COMMUNITY && dso.getType() != Constants.COLLECTION) { throw new CrosswalkObjectNotSupported("Role crosswalk only valid for Site, Community or Collection"); } //locate our "DSPACE-ROLES" PackageIngester plugin PackageIngester sip = (PackageIngester) PluginManager.getNamedPlugin(PackageIngester.class, ROLE_PACKAGER_PLUGIN); if (sip == null) { throw new CrosswalkInternalException("Cannot find a PackageIngester plugin named " + ROLE_PACKAGER_PLUGIN); } // Initialize our packaging parameters PackageParameters pparams; if(this.getPackagingParameters()!=null) { pparams = this.getPackagingParameters(); } else { pparams = new PackageParameters(); } // Initialize our license info String license = null; if(this.getIngestionLicense()!=null) { license = this.getIngestionLicense(); } // Create a temporary file to ingest from String tempDirectory = ConfigurationManager.getProperty("upload.temp.dir"); File tempFile = File.createTempFile("RoleCrosswalkIngest" + dso.hashCode(), null, new File(tempDirectory)); tempFile.deleteOnExit(); FileOutputStream fileOutStream = null; try { fileOutStream = new FileOutputStream(tempFile); XMLOutputter writer = new XMLOutputter(); writer.output(root, fileOutStream); } finally { if (fileOutStream != null) { fileOutStream.close(); } } //Actually call the ingester try { sip.ingest(context, dso, tempFile, pparams, license); } catch (PackageException e) { throw new CrosswalkInternalException(e); } } }