Index: BitstreamFormat.java =================================================================== --- BitstreamFormat.java (.../dspace/trunk/dspace-api/src/main/java/org/dspace/content) (revision 5257) +++ BitstreamFormat.java (.../sandbox/aip-external-1_6-prototype/dspace-api/src/main/java/org/dspace/content) (revision 5257) @@ -44,7 +44,6 @@ import org.apache.log4j.Logger; import org.dspace.authorize.AuthorizeException; import org.dspace.authorize.AuthorizeManager; -import org.dspace.core.ConfigurationManager; import org.dspace.core.Context; import org.dspace.core.LogManager; import org.dspace.storage.rdbms.DatabaseManager; @@ -83,6 +82,13 @@ */ public static final int SUPPORTED = 2; + + /** translate support-level ID to string. MUST keep this table in sync + * with support level definitions above. + */ + public static final String supportLevelText[] = + { "UNKNOWN", "KNOWN", "SUPPORTED" }; + /** Our context */ private Context bfContext; @@ -90,7 +96,7 @@ private TableRow bfRow; /** File extensions for this format */ - private List extensions; + private List extensions; /** * Class constructor for creating a BitstreamFormat object based on the @@ -106,7 +112,7 @@ { bfContext = context; bfRow = row; - extensions = new ArrayList(); + extensions = new ArrayList(); TableRowIterator tri = DatabaseManager.query(context, "SELECT * FROM fileextension WHERE bitstream_format_id= ? ", @@ -298,7 +304,7 @@ public static BitstreamFormat[] findAll(Context context) throws SQLException { - List formats = new ArrayList(); + List formats = new ArrayList(); TableRowIterator tri = DatabaseManager.queryTable(context, "bitstreamformatregistry", "SELECT * FROM bitstreamformatregistry ORDER BY bitstream_format_id"); @@ -352,7 +358,7 @@ public static BitstreamFormat[] findNonInternal(Context context) throws SQLException { - List formats = new ArrayList(); + List formats = new ArrayList(); String myQuery = "SELECT * FROM bitstreamformatregistry WHERE internal='0' " + "AND short_description NOT LIKE 'Unknown' " @@ -456,7 +462,7 @@ throws SQLException { // You can not reset the unknown's registry's name - BitstreamFormat unknown = null;; + BitstreamFormat unknown = null; try { unknown = findUnknown(bfContext); } catch (IllegalStateException e) { @@ -672,11 +678,34 @@ */ public void setExtensions(String[] exts) { - extensions = new ArrayList(); + extensions = new ArrayList(); for (int i = 0; i < exts.length; i++) { extensions.add(exts[i]); } } + + /** + * If you know the support level string, look up the corresponding type ID + * constant. + * + * @param action + * String with the name of the action (must be exact match) + * + * @return the corresponding action ID, or -1 if the action + * string is unknown + */ + public static int getSupportLevelID(String slevel) + { + for (int i = 0; i < supportLevelText.length; i++) + { + if (supportLevelText[i].equals(slevel)) + { + return i; + } + } + + return -1; + } } Index: Site.java =================================================================== --- Site.java (.../dspace/trunk/dspace-api/src/main/java/org/dspace/content) (revision 5257) +++ Site.java (.../sandbox/aip-external-1_6-prototype/dspace-api/src/main/java/org/dspace/content) (revision 5257) @@ -137,4 +137,8 @@ return ConfigurationManager.getProperty("dspace.name"); } + public String getURL() + { + return ConfigurationManager.getProperty("dspace.url"); + } } Index: WorkspaceItem.java =================================================================== --- WorkspaceItem.java (.../dspace/trunk/dspace-api/src/main/java/org/dspace/content) (revision 5257) +++ WorkspaceItem.java (.../sandbox/aip-external-1_6-prototype/dspace-api/src/main/java/org/dspace/content) (revision 5257) @@ -163,6 +163,13 @@ boolean template) throws AuthorizeException, SQLException, IOException { + return create(c, coll, template, c.getCurrentUser(), null); + } + + public static WorkspaceItem create(Context c, Collection coll, + boolean template, EPerson submitter, String handle) + throws AuthorizeException, SQLException, IOException + { // Check the user has permission to ADD to the collection AuthorizeManager.authorizeAction(c, coll, Constants.ADD); @@ -547,7 +554,7 @@ .getCurrentUser().getID() != item.getSubmitter() .getID()))) { - // Not an admit, not the submitter + // Not an admin, not the submitter throw new AuthorizeException("Must be an administrator or the " + "original submitter to delete a workspace item"); } Index: Community.java =================================================================== --- Community.java (.../dspace/trunk/dspace-api/src/main/java/org/dspace/content) (revision 5257) +++ Community.java (.../sandbox/aip-external-1_6-prototype/dspace-api/src/main/java/org/dspace/content) (revision 5257) @@ -182,7 +182,7 @@ } /** - * Create a new community, with a new ID. + * Create a new top-level community, with a new ID. * * @param context * DSpace context object @@ -192,9 +192,23 @@ public static Community create(Community parent, Context context) throws SQLException, AuthorizeException { - // Only administrators and adders can create communities - if (!(AuthorizeManager.isAdmin(context) || AuthorizeManager - .authorizeActionBoolean(context, parent, Constants.ADD))) + return create(parent, context, null); + } + + /** + * Create a new top-level community, with a new ID. + * + * @param context + * DSpace context object + * @param handle the pre-determined Handle to assign to the new community + * + * @return the newly created community + */ + public static Community create(Community parent, Context context, String handle) + throws SQLException, AuthorizeException + { + if (!(AuthorizeManager.isAdmin(context) || + (parent != null && AuthorizeManager.authorizeActionBoolean(context, parent, Constants.ADD)))) { throw new AuthorizeException( "Only administrators can create communities"); @@ -202,12 +216,31 @@ TableRow row = DatabaseManager.create(context, "community"); Community c = new Community(context, row); - c.handle = HandleManager.createHandle(context, c); if(parent != null) { parent.addSubcommunity(c); } + try + { + c.handle = (handle == null) ? + HandleManager.createHandle(context, c) : + HandleManager.createHandle(context, c, handle); + } + catch(IllegalStateException ie) + { + //If an IllegalStateException is thrown, then an existing object is already using this handle + //Remove the community we just created -- as it is incomplete + try + { + if(c!=null) + c.delete(); + } catch(Exception e) { } + + //pass exception on up the chain + throw ie; + } + // create the default authorization policy for communities // of 'anonymous' READ Group anonymousGroup = Group.find(context, 0); @@ -781,10 +814,23 @@ public Collection createCollection() throws SQLException, AuthorizeException { + return createCollection(null); + } + + /** + * Create a new collection within this community. The collection is created + * without any workflow groups or default submitter group. + * + * @param handle the pre-determined Handle to assign to the new community + * @return the new collection + */ + public Collection createCollection(String handle) throws SQLException, + AuthorizeException + { // Check authorisation AuthorizeManager.authorizeAction(ourContext, this, Constants.ADD); - Collection c = Collection.create(ourContext); + Collection c = Collection.create(ourContext, handle); addCollection(c); return c; @@ -843,10 +889,22 @@ public Community createSubcommunity() throws SQLException, AuthorizeException { + return createSubcommunity(null); + } + + /** + * Create a new sub-community within this community. + * + * @param handle the pre-determined Handle to assign to the new community + * @return the new community + */ + public Community createSubcommunity(String handle) throws SQLException, + AuthorizeException + { // Check authorisation AuthorizeManager.authorizeAction(ourContext, this, Constants.ADD); - Community c = create(this, ourContext); + Community c = create(this, ourContext, handle); addSubcommunity(c); return c; @@ -1052,7 +1110,10 @@ // exception framework throw new RuntimeException(e.getMessage(),e); } - + + // Remove any Handle + HandleManager.unbindHandle(ourContext, this); + // Delete community row DatabaseManager.delete(ourContext, communityRow); Index: InstallItem.java =================================================================== --- InstallItem.java (.../dspace/trunk/dspace-api/src/main/java/org/dspace/content) (revision 5257) +++ InstallItem.java (.../sandbox/aip-external-1_6-prototype/dspace-api/src/main/java/org/dspace/content) (revision 5257) @@ -90,40 +90,76 @@ Item item = is.getItem(); String handle; + // if no previous handle supplied, create one + if (suppliedHandle == null) + { + // create handle + handle = HandleManager.createHandle(c, item); + } + else + { + handle = HandleManager.createHandle(c, item, suppliedHandle); + } + + populateHandleMetadata(item, handle); + // this is really just to flush out fatal embargo metadata // problems before we set inArchive. DCDate liftDate = EmbargoManager.getEmbargoDate(c, item); - // create accession date - DCDate now = DCDate.getCurrent(); - item.addDC("date", "accessioned", null, now.toString()); - - // add date available if not under embargo, otherwise it will - // be set when the embargo is lifted. - if (liftDate == null) - item.addDC("date", "available", null, now.toString()); + populateMetadata(c, item, liftDate); - // create issue date if not present - DCValue[] currentDateIssued = item.getDC("date", "issued", Item.ANY); + return finishItem(c, item, is, liftDate); - if (currentDateIssued.length == 0) - { - DCDate issued = new DCDate(); - issued.setDateLocal(now.getYear(),now.getMonth(),now.getDay(),-1,-1,-1); - item.addDC("date", "issued", null, issued.toString()); - } + } - // if no previous handle supplied, create one + /** + * Turn an InProgressSubmission into a fully-archived Item, for + * a "restore" operation such as ingestion of an AIP to recreate an + * archive. This does NOT add any descriptive metadata (e.g. for + * provenance) to preserve the transparency of the ingest. The + * ingest mechanism is assumed to have set all relevant technical + * and administrative metadata fields. + * + * @param c current context + * @param is + * submission to install + * @param suppliedHandle + * the existing Handle to give the installed item, or null + * to create a new one. + * + * @return the fully archived Item + */ + public static Item restoreItem(Context c, InProgressSubmission is, + String suppliedHandle) + throws SQLException, IOException, AuthorizeException + { + Item item = is.getItem(); + String handle; + if (suppliedHandle == null) { - // create handle handle = HandleManager.createHandle(c, item); + //only populate handle metadata for new handles + // (existing handles should already be in the metadata -- as it was restored by ingest process) + populateHandleMetadata(item, handle); } else { handle = HandleManager.createHandle(c, item, suppliedHandle); } + //NOTE: this method specifically skips over "populateMetadata()" + // As this is a "restore" all the metadata should have already been restored + + //@TODO: Do we actually want a "Restored on ..." provenance message? Or perhaps kick off an event? + + return finishItem(c, item, is, null); + } + + private static void populateHandleMetadata(Item item, String handle) + throws SQLException, IOException, AuthorizeException + { String handleref = HandleManager.getCanonicalForm(handle); // Add handle as identifier.uri DC value. @@ -135,8 +171,32 @@ identifierExists = true; if (!identifierExists) item.addDC("identifier", "uri", null, handleref); + } - String provDescription = "Made available in DSpace on " + now + // fill in metadata needed by new Item. + private static void populateMetadata(Context c, Item item, DCDate embargoLiftDate) + throws SQLException, IOException, AuthorizeException + { + // create accession date + DCDate now = DCDate.getCurrent(); + item.addDC("date", "accessioned", null, now.toString()); + + // add date available if not under embargo, otherwise it will + // be set when the embargo is lifted. + if (embargoLiftDate == null) + item.addDC("date", "available", null, now.toString()); + + // create issue date if not present + DCValue[] currentDateIssued = item.getDC("date", "issued", Item.ANY); + + if (currentDateIssued.length == 0) + { + DCDate issued = new DCDate(); + issued.setDateLocal(now.getYear(),now.getMonth(),now.getDay(),-1,-1,-1); + item.addDC("date", "issued", null, issued.toString()); + } + + String provDescription = "Made available in DSpace on " + now + " (GMT). " + getBitstreamProvenanceMessage(item); if (currentDateIssued.length != 0) @@ -148,7 +208,13 @@ // Add provenance description item.addDC("description", "provenance", "en", provDescription); + } + // final housekeeping when adding new Item to archive + // common between installing and "restoring" items. + private static Item finishItem(Context c, Item item, InProgressSubmission is, DCDate embargoLiftDate) + throws SQLException, IOException, AuthorizeException + { // create collection2item mapping is.getCollection().addItem(item); @@ -163,7 +229,7 @@ // Notify interested parties of newly archived Item c.addEvent(new Event(Event.INSTALL, Constants.ITEM, item.getID(), - handle)); + item.getHandle())); // remove in-progress submission is.deleteWrapper(); @@ -171,15 +237,14 @@ // remove the item's policies and replace them with // the defaults from the collection item.inheritCollectionDefaultPolicies(is.getCollection()); - + // set embargo lift date and take away read access if indicated. - if (liftDate != null) - EmbargoManager.setEmbargo(c, item, liftDate); + if (embargoLiftDate != null) + EmbargoManager.setEmbargo(c, item, embargoLiftDate); return item; } - /** * Generate provenance-worthy description of the bitstreams contained in an * item. Index: Bitstream.java =================================================================== --- Bitstream.java (.../dspace/trunk/dspace-api/src/main/java/org/dspace/content) (revision 5257) +++ Bitstream.java (.../sandbox/aip-external-1_6-prototype/dspace-api/src/main/java/org/dspace/content) (revision 5257) @@ -288,6 +288,11 @@ return bRow.getIntColumn("bitstream_id"); } + /** + * Bitstreams do not have Handles. Required for DSpaceObject interface. + * + * @return null + */ public String getHandle() { // No Handles for bitstreams Index: Collection.java =================================================================== --- Collection.java (.../dspace/trunk/dspace-api/src/main/java/org/dspace/content) (revision 5257) +++ Collection.java (.../sandbox/aip-external-1_6-prototype/dspace-api/src/main/java/org/dspace/content) (revision 5257) @@ -236,10 +236,47 @@ static Collection create(Context context) throws SQLException, AuthorizeException { + return create(context, null); + } + + /** + * Create a new collection, with a new ID. This method is not public, and + * does not check authorisation. + * + * @param context + * DSpace context object + * + * @param handle the pre-determined Handle to assign to the new community + * @return the newly created collection + * @throws SQLException + * @throws AuthorizeException + */ + static Collection create(Context context, String handle) throws SQLException, + AuthorizeException + { TableRow row = DatabaseManager.create(context, "collection"); Collection c = new Collection(context, row); - c.handle = HandleManager.createHandle(context, c); + try + { + c.handle = (handle == null) ? + HandleManager.createHandle(context, c) : + HandleManager.createHandle(context, c, handle); + } + catch(IllegalStateException ie) + { + //If an IllegalStateException is thrown, then an existing object is already using this handle + //Remove the collection we just created -- as it is incomplete + try + { + if(c!=null) + c.delete(); + } catch(Exception e) { } + + //pass exception on up the chain + throw ie; + } + // create the default authorization policy for collections // of 'anonymous' READ Group anonymousGroup = Group.find(context, 0); @@ -1132,6 +1169,9 @@ // exception framework throw new RuntimeException(e.getMessage(), e); } + + // Remove any Handle + HandleManager.unbindHandle(ourContext, this); // Delete collection row DatabaseManager.delete(ourContext, collectionRow); Index: Item.java =================================================================== --- Item.java (.../dspace/trunk/dspace-api/src/main/java/org/dspace/content) (revision 5257) +++ Item.java (.../sandbox/aip-external-1_6-prototype/dspace-api/src/main/java/org/dspace/content) (revision 5257) @@ -1972,13 +1972,7 @@ AuthorizeManager.removeAllPolicies(ourContext, this); // Remove any Handle - // FIXME: HandleManager should provide a way of doing this. - // Plus, deleting a Handle may have ramifications - // that need considering. - DatabaseManager.updateQuery(ourContext, - "DELETE FROM handle WHERE resource_type_id= ? " + - "AND resource_id= ? ", - Constants.ITEM,getID()); + HandleManager.unbindHandle(ourContext, this); // Finally remove item row DatabaseManager.delete(ourContext, itemRow);