diff --git a/dspace-api/src/main/java/org/dspace/app/itemimport/ItemImport.java b/dspace-api/src/main/java/org/dspace/app/itemimport/ItemImport.java index 12a79c32f0..e150a95938 100755 --- a/dspace-api/src/main/java/org/dspace/app/itemimport/ItemImport.java +++ b/dspace-api/src/main/java/org/dspace/app/itemimport/ItemImport.java @@ -54,6 +54,7 @@ import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.StringTokenizer; +import java.util.Vector; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; @@ -67,6 +68,8 @@ import org.apache.commons.cli.Options; import org.apache.commons.cli.PosixParser; import org.apache.xpath.XPathAPI; import org.dspace.authorize.AuthorizeException; +import org.dspace.authorize.AuthorizeManager; +import org.dspace.authorize.ResourcePolicy; import org.dspace.content.Bitstream; import org.dspace.content.BitstreamFormat; import org.dspace.content.Bundle; @@ -81,6 +84,7 @@ import org.dspace.core.ConfigurationManager; import org.dspace.core.Constants; import org.dspace.core.Context; import org.dspace.eperson.EPerson; +import org.dspace.eperson.Group; import org.dspace.handle.HandleManager; import org.dspace.workflow.WorkflowManager; import org.w3c.dom.Document; @@ -639,9 +643,10 @@ public class ItemImport + File.separatorChar); // and the bitstreams from the contents file - // process contents file, add bistreams and bundles - processContentsFile(c, myitem, path + File.separatorChar + itemname, - "contents"); + // process contents file, add bistreams and bundles, return any + // non-standard permissions + Vector options = processContentsFile(c, myitem, path + + File.separatorChar + itemname, "contents"); if (useWorkflow) { @@ -671,6 +676,13 @@ public class ItemImport mapOutput = itemname + " " + myhandle; } + + // set permissions if specified in contents file + if (options.size() > 0) + { + System.out.println("Processing options"); + processOptions(c, myitem, options); + } } // now add to multiple collections if requested @@ -875,7 +887,7 @@ public class ItemImport } else { - // If we're just test the import, let's check that the actual metadata field exists. + // If we're just test the import, let's check that the actual metadata field exists. MetadataSchema foundSchema = MetadataSchema.find(c,schema); if (foundSchema == null) @@ -895,26 +907,6 @@ public class ItemImport } } - /** - * Return the String value of a Node - */ - public String getStringValue(Node node) - { - String value = node.getNodeValue(); - - if (node.hasChildNodes()) - { - Node first = node.getFirstChild(); - - if (first.getNodeType() == Node.TEXT_NODE) - { - return first.getNodeValue(); - } - } - - return value; - } - /** * Read in the handle file or return null if empty or doesn't exist */ @@ -964,14 +956,16 @@ public class ItemImport /** * Given a contents file and an item, stuffing it with bitstreams from the - * contents file + * contents file Returns a Vector of Strings with lines from the contents + * file that request non-default bitstream permission */ - private void processContentsFile(Context c, Item i, String path, + private Vector processContentsFile(Context c, Item i, String path, String filename) throws SQLException, IOException, AuthorizeException { String contentspath = path + File.separatorChar + filename; String line = ""; + Vector options = new Vector(); System.out.println("\tProcessing contents file: " + contentspath); @@ -1051,29 +1045,99 @@ public class ItemImport continue; // process next line in contents file } - // look for a bundle name - String bundleMarker = "\tbundle:"; + int bitstreamEndIndex = line.indexOf("\t"); - int markerIndex = line.indexOf(bundleMarker); - - if (markerIndex == -1) + if (bitstreamEndIndex == -1) { - // no bundle found + // no extra info processContentFileEntry(c, i, path, line, null); System.out.println("\tBitstream: " + line); } else { - // found bundle - String bundleName = line.substring(markerIndex - + bundleMarker.length()); - String bitstreamName = line.substring(0, markerIndex); - bitstreamName = bitstreamName.trim(); - - processContentFileEntry(c, i, path, bitstreamName, - bundleName); - System.out.println("\tBitstream: " + bitstreamName - + "\tBundle: " + bundleName); + + String bitstreamName = line.substring(0, bitstreamEndIndex); + + boolean bundleExists = false; + boolean permissionsExist = false; + boolean descriptionExists = false; + + // look for a bundle name + String bundleMarker = "\tbundle:"; + int bMarkerIndex = line.indexOf(bundleMarker); + int bEndIndex = 0; + if (bMarkerIndex > 0) + { + bEndIndex = line.indexOf("\t", bMarkerIndex + 1); + if (bEndIndex == -1) + { + bEndIndex = line.length(); + } + bundleExists = true; + } + + // look for permissions + String permissionsMarker = "\tpermissions:"; + int pMarkerIndex = line.indexOf(permissionsMarker); + int pEndIndex = 0; + if (pMarkerIndex > 0) + { + pEndIndex = line.indexOf("\t", pMarkerIndex + 1); + if (pEndIndex == -1) + { + pEndIndex = line.length(); + } + permissionsExist = true; + } + + // look for descriptions + String descriptionMarker = "\tdescription:"; + int dMarkerIndex = line.indexOf(descriptionMarker); + int dEndIndex = 0; + if (dMarkerIndex > 0) + { + dEndIndex = line.indexOf("\t", dMarkerIndex + 1); + if (dEndIndex == -1) + { + dEndIndex = line.length(); + } + descriptionExists = true; + } + + if (bundleExists) + { + String bundleName = line.substring(bMarkerIndex + + bundleMarker.length(), bEndIndex); + + processContentFileEntry(c, i, path, bitstreamName, + bundleName); + System.out.println("\tBitstream: " + bitstreamName + + "\tBundle: " + bundleName); + } + else + { + processContentFileEntry(c, i, path, bitstreamName, null); + System.out.println("\tBitstream: " + bitstreamName); + } + + if (permissionsExist || descriptionExists) + { + String extraInfo = bitstreamName; + + if (permissionsExist) + { + extraInfo = extraInfo + + line.substring(pMarkerIndex, pEndIndex); + } + + if (descriptionExists) + { + extraInfo = extraInfo + + line.substring(dMarkerIndex, dEndIndex); + } + + options.add(extraInfo); + } } } } @@ -1084,10 +1148,21 @@ public class ItemImport is.close(); } } + return options; } - // each entry represents a bitstream.... - public void processContentFileEntry(Context c, Item i, String path, + /** + * each entry represents a bitstream.... + * @param c + * @param i + * @param path + * @param fileName + * @param bundleName + * @throws SQLException + * @throws IOException + * @throws AuthorizeException + */ + private void processContentFileEntry(Context c, Item i, String path, String fileName, String bundleName) throws SQLException, IOException, AuthorizeException { @@ -1158,7 +1233,7 @@ public class ItemImport * @throws IOException * @throws AuthorizeException */ - public void registerBitstream(Context c, Item i, int assetstore, + private void registerBitstream(Context c, Item i, int assetstore, String bitstreamPath, String bundleName ) throws SQLException, IOException, AuthorizeException { @@ -1215,72 +1290,261 @@ public class ItemImport } } - // XML utility methods - public String getAttributeValue(Node n, String myattributename) + /** + * + * Process the Options to apply to the Item. The options are tab delimited + * + * Options: + * 48217870-MIT.pdf permissions: -r 'MIT Users' description: Full printable version (MIT only) + * permissions:[r|w]-['group name'] + * description: 'the description of the file' + * + * where: + * [r|w] (meaning: read|write) + * ['MIT Users'] (the group name) + * + * @param c + * @param myItem + * @param options + * @throws SQLException + * @throws AuthorizeException + */ + private void processOptions(Context c, Item myItem, Vector options) + throws SQLException, AuthorizeException { - String myvalue = ""; + for (int i = 0; i < options.size(); i++) + { + String line = options.elementAt(i).toString(); + System.out.println("\tprocessing " + line); + + boolean permissionsExist = false; + boolean descriptionExists = false; + + String permissionsMarker = "\tpermissions:"; + int pMarkerIndex = line.indexOf(permissionsMarker); + int pEndIndex = 0; + if (pMarkerIndex > 0) + { + pEndIndex = line.indexOf("\t", pMarkerIndex + 1); + if (pEndIndex == -1) + { + pEndIndex = line.length(); + } + permissionsExist = true; + } + + String descriptionMarker = "\tdescription:"; + int dMarkerIndex = line.indexOf(descriptionMarker); + int dEndIndex = 0; + if (dMarkerIndex > 0) + { + dEndIndex = line.indexOf("\t", dMarkerIndex + 1); + if (dEndIndex == -1) + { + dEndIndex = line.length(); + } + descriptionExists = true; + } + + int bsEndIndex = line.indexOf("\t"); + String bitstreamName = line.substring(0, bsEndIndex); + + int actionID = -1; + String groupName = ""; + Group myGroup = null; + if (permissionsExist) + { + String thisPermission = line.substring(pMarkerIndex + + permissionsMarker.length(), pEndIndex); + + // get permission type ("read" or "write") + int pTypeIndex = thisPermission.indexOf("-"); + + // get permission group (should be in single quotes) + int groupIndex = thisPermission.indexOf("'", pTypeIndex); + int groupEndIndex = thisPermission.indexOf("'", groupIndex + 1); + + // if not in single quotes, assume everything after type flag is + // group name + if (groupIndex == -1) + { + groupIndex = thisPermission.indexOf(" ", pTypeIndex); + groupEndIndex = thisPermission.length(); + } + + groupName = thisPermission.substring(groupIndex + 1, + groupEndIndex); + + if (thisPermission.toLowerCase().charAt(pTypeIndex + 1) == 'r') + { + actionID = Constants.READ; + } + else if (thisPermission.toLowerCase().charAt(pTypeIndex + 1) == 'w') + { + actionID = Constants.WRITE; + } + + try + { + myGroup = Group.findByName(c, groupName); + } + catch (SQLException sqle) + { + System.out.println("SQL Exception finding group name: " + + groupName); + // do nothing, will check for null group later + } + } + + String thisDescription = ""; + if (descriptionExists) + { + thisDescription = line.substring( + dMarkerIndex + descriptionMarker.length(), dEndIndex) + .trim(); + } + + Bitstream bs = null; + boolean notfound = true; + if (!isTest) + { + // find bitstream + Bitstream[] bitstreams = myItem.getNonInternalBitstreams(); + for (int j = 0; j < bitstreams.length && notfound; j++) + { + if (bitstreams[j].getName().equals(bitstreamName)) + { + bs = bitstreams[j]; + notfound = false; + } + } + } + + if (notfound && !isTest) + { + // this should never happen + System.out.println("\tdefault permissions set for " + + bitstreamName); + } + else if (!isTest) + { + if (permissionsExist) + { + if (myGroup == null) + { + System.out.println("\t" + groupName + + " not found, permissions set to default"); + } + else if (actionID == -1) + { + System.out + .println("\tinvalid permissions flag, permissions set to default"); + } + else + { + System.out.println("\tSetting special permissions for " + + bitstreamName); + setPermission(c, myGroup, actionID, bs); + } + } + + if (descriptionExists) + { + System.out.println("\tSetting description for " + + bitstreamName); + bs.setDescription(thisDescription); + bs.update(); + } + } + } + } + + /** + * Set the Permission on a Bitstream. + * + * @param c + * @param g + * @param actionID + * @param bs + * @throws SQLException + * @throws AuthorizeException + */ + private void setPermission(Context c, Group g, int actionID, Bitstream bs) + throws SQLException, AuthorizeException + { + if (!isTest) + { + // remove the default policy + AuthorizeManager.removeAllPolicies(c, bs); + + // add the policy + ResourcePolicy rp = ResourcePolicy.create(c); + + rp.setResource(bs); + rp.setAction(actionID); + rp.setGroup(g); + + rp.update(); + } + else + { + if (actionID == Constants.READ) + { + System.out.println("\t\tpermissions: READ for " + g.getName()); + } + else if (actionID == Constants.WRITE) + { + System.out.println("\t\tpermissions: WRITE for " + g.getName()); + } + } + + } + + // XML utility methods + /** + * Lookup an attribute from a DOM node. + * @param n + * @param name + * @return + */ + private String getAttributeValue(Node n, String name) + { NamedNodeMap nm = n.getAttributes(); for (int i = 0; i < nm.getLength(); i++) { Node node = nm.item(i); - String name = node.getNodeName(); - String value = node.getNodeValue(); - if (myattributename.equals(name)) + if (name.equals(node.getNodeName())) { - return value; + return node.getNodeValue(); } } - return myvalue; + return ""; } - // XML utility methods stolen from administer. - + /** - * Get the CDATA of a particular element. For example, if the XML document - * contains: - *
- *
- * <foo><mimetype>application/pdf</mimetype></foo>
- *
- * passing this the foo node and mimetype will
- * return application/pdf.
- *
String
+ * Return the String value of a Node.
+ * @param node
+ * @return
*/
- private String getElementData(Node parentElement, String childName)
- throws TransformerException
+ private String getStringValue(Node node)
{
- // Grab the child node
- Node childNode = XPathAPI.selectSingleNode(parentElement, childName);
+ String value = node.getNodeValue();
- if (childNode == null)
+ if (node.hasChildNodes())
{
- // No child node, so no values
- return null;
+ Node first = node.getFirstChild();
+
+ if (first.getNodeType() == Node.TEXT_NODE)
+ {
+ return first.getNodeValue();
+ }
}
- // Get the #text
- Node dataNode = childNode.getFirstChild();
-
- if (dataNode == null)
- {
- return null;
- }
-
- // Get the data
- String value = dataNode.getNodeValue().trim();
-
return value;
}
diff --git a/dspace/CHANGES b/dspace/CHANGES
index abcdd1cb8c..d00550325b 100644
--- a/dspace/CHANGES
+++ b/dspace/CHANGES
@@ -1,3 +1,6 @@
+(Mark Diggory)
+- New options for ItemImporter to support bitstream permissions and descriptions.
+
(Graham Triggs/Mark Diggory)
- S.F. Bug 1824710 Creative Commons RDF has changed. Adjusted CC processing to be XSL driven
and adjusted generated XML/RDF. Created LicenseCleanup CLI to process existing CC license_rdf
diff --git a/dspace/docs/application.html b/dspace/docs/application.html
index 88cfd27df8..a71ab7fd2b 100644
--- a/dspace/docs/application.html
+++ b/dspace/docs/application.html
@@ -807,6 +807,8 @@ archive_directory/
-r -s n -f filepath -r -s n -f filepath\tbundle:bundlename +-r -s n -f filepath\tbundle:bundlename\tpermissions: -[r|w] 'group name' +-r -s n -f filepath\tbundle:bundlename\tpermissions: -[r|w] 'group name'\tdescription: some text
where
@@ -817,6 +819,8 @@ archive_directory/-f filepath indicates the path and name of the content file to be registered (filepath)\t is a tab characterbundle:bundlename is an optional bundle namepermissions: -[r|w] 'group name' is an optional read or write permission that can be attached to the bitstreamdescription: some text is an optional description field to add to the fileThe bundle, that is everything after the filepath, is optional and is normally not used.