mirror of
https://github.com/DSpace/DSpace.git
synced 2025-10-07 01:54:22 +00:00
Merge pull request #72 from atmire/dspace3-versioning
[DS-1194] Atmire dspace 3.0 versioning contribution
This commit is contained in:
@@ -106,13 +106,35 @@
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
|
||||
<!--
|
||||
The ant plugin below ensures that the dspace "woven" configuration file ends up in the dspace directory
|
||||
The dspace service manager needs this "woven" configuration file when it starts
|
||||
-->
|
||||
<plugin>
|
||||
<artifactId>maven-antrun-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>process-test-resources</phase>
|
||||
<configuration>
|
||||
<tasks>
|
||||
<copy file="${project.build.directory}/testing/dspace.cfg.woven" tofile="${project.build.directory}/testing/dspace/config/dspace.cfg"/>
|
||||
</tasks>
|
||||
</configuration>
|
||||
<goals>
|
||||
<goal>run</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<configuration>
|
||||
<systemPropertyVariables>
|
||||
<dspace.dir>${project.build.directory}/testing/dspace</dspace.dir>
|
||||
<dspace.dir.static>${basedir}/src/test/data/dspaceFolder</dspace.dir.static>
|
||||
<dspace.configuration>${project.build.directory}/testing/dspace.cfg.woven</dspace.configuration>
|
||||
<dspace.configuration>${project.build.directory}/testing/dspace/config/dspace.cfg</dspace.configuration>
|
||||
<db.schema.path>${project.build.directory}/testing/dspace/etc/h2/database_schema.sql</db.schema.path>
|
||||
<dspace.log.init.disable>true</dspace.log.init.disable>
|
||||
</systemPropertyVariables>
|
||||
|
@@ -73,7 +73,7 @@ public class BrowseConsumer implements Consumer
|
||||
|
||||
// If an Item is created or its metadata is modified..
|
||||
case Constants.ITEM:
|
||||
if (et == Event.MODIFY_METADATA || et == Event.CREATE)
|
||||
if (et == Event.MODIFY_METADATA || et == Event.CREATE || et == Event.MODIFY)
|
||||
{
|
||||
Item subj = (Item)event.getSubject(ctx);
|
||||
if (subj != null)
|
||||
|
@@ -8,6 +8,7 @@
|
||||
package org.dspace.browse;
|
||||
|
||||
import org.apache.log4j.Logger;
|
||||
import org.dspace.authorize.AuthorizeException;
|
||||
import org.dspace.authorize.AuthorizeManager;
|
||||
import org.dspace.content.*;
|
||||
import org.dspace.core.Constants;
|
||||
@@ -384,6 +385,12 @@ public class BrowseItem extends DSpaceObject
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update() throws SQLException, AuthorizeException
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateLastModified()
|
||||
{
|
||||
|
@@ -321,7 +321,7 @@ public class IndexBrowse
|
||||
{
|
||||
indexItem(new ItemMetadataProxy(item), addingNewItem);
|
||||
}
|
||||
else if (item.isWithdrawn())
|
||||
else if (item.isWithdrawn() || !item.isArchived())
|
||||
{
|
||||
indexItem(new ItemMetadataProxy(item), false);
|
||||
}
|
||||
|
@@ -974,7 +974,7 @@ public class Collection extends DSpaceObject
|
||||
* @throws IOException
|
||||
* @throws AuthorizeException
|
||||
*/
|
||||
public void update() throws SQLException, IOException, AuthorizeException
|
||||
public void update() throws SQLException, AuthorizeException
|
||||
{
|
||||
// Check authorisation
|
||||
canEdit(true);
|
||||
|
@@ -509,7 +509,7 @@ public class Community extends DSpaceObject
|
||||
/**
|
||||
* Update the community metadata (including logo) to the database.
|
||||
*/
|
||||
public void update() throws SQLException, IOException, AuthorizeException
|
||||
public void update() throws SQLException, AuthorizeException
|
||||
{
|
||||
// Check authorisation
|
||||
canEdit();
|
||||
|
@@ -7,13 +7,14 @@
|
||||
*/
|
||||
package org.dspace.content;
|
||||
|
||||
import java.sql.SQLException;
|
||||
|
||||
import org.dspace.authorize.AuthorizeException;
|
||||
import org.dspace.core.Constants;
|
||||
import org.dspace.core.Context;
|
||||
import org.dspace.eperson.EPerson;
|
||||
import org.dspace.eperson.Group;
|
||||
|
||||
import java.sql.SQLException;
|
||||
|
||||
/**
|
||||
* Abstract base class for DSpace objects
|
||||
*/
|
||||
@@ -171,5 +172,7 @@ public abstract class DSpaceObject
|
||||
return null;
|
||||
}
|
||||
|
||||
public abstract void update() throws SQLException, AuthorizeException;
|
||||
|
||||
public abstract void updateLastModified();
|
||||
}
|
||||
|
@@ -37,7 +37,7 @@ public interface InProgressSubmission
|
||||
/**
|
||||
* Update the submission, including the unarchived item.
|
||||
*/
|
||||
void update() throws SQLException, IOException, AuthorizeException;
|
||||
void update() throws SQLException, AuthorizeException;
|
||||
|
||||
/**
|
||||
* Get the incomplete item object
|
||||
|
@@ -15,7 +15,9 @@ import org.dspace.core.Constants;
|
||||
import org.dspace.core.Context;
|
||||
import org.dspace.embargo.EmbargoManager;
|
||||
import org.dspace.event.Event;
|
||||
import org.dspace.handle.HandleManager;
|
||||
import org.dspace.identifier.IdentifierException;
|
||||
import org.dspace.identifier.IdentifierService;
|
||||
import org.dspace.utils.DSpace;
|
||||
|
||||
/**
|
||||
* Support to install an Item in the archive.
|
||||
@@ -58,21 +60,18 @@ public class InstallItem
|
||||
IOException, AuthorizeException
|
||||
{
|
||||
Item item = is.getItem();
|
||||
String handle;
|
||||
|
||||
// if no previous handle supplied, create one
|
||||
if (suppliedHandle == null)
|
||||
{
|
||||
// create a new handle for this item
|
||||
handle = HandleManager.createHandle(c, item);
|
||||
}
|
||||
else
|
||||
{
|
||||
// assign the supplied handle to this item
|
||||
handle = HandleManager.createHandle(c, item, suppliedHandle);
|
||||
IdentifierService identifierService = new DSpace().getSingletonService(IdentifierService.class);
|
||||
try {
|
||||
if(suppliedHandle == null)
|
||||
{
|
||||
identifierService.register(c, item);
|
||||
}else{
|
||||
identifierService.register(c, item, suppliedHandle);
|
||||
}
|
||||
} catch (IdentifierException e) {
|
||||
throw new RuntimeException("Can't create an Identifier!");
|
||||
}
|
||||
|
||||
populateHandleMetadata(item, handle);
|
||||
|
||||
populateMetadata(c, item);
|
||||
|
||||
@@ -102,21 +101,17 @@ public class InstallItem
|
||||
throws SQLException, IOException, AuthorizeException
|
||||
{
|
||||
Item item = is.getItem();
|
||||
String handle;
|
||||
|
||||
// if no handle supplied
|
||||
if (suppliedHandle == null)
|
||||
{
|
||||
// create a new handle for this item
|
||||
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
|
||||
{
|
||||
// assign the supplied handle to this item
|
||||
handle = HandleManager.createHandle(c, item, suppliedHandle);
|
||||
IdentifierService identifierService = new DSpace().getSingletonService(IdentifierService.class);
|
||||
try {
|
||||
if(suppliedHandle == null)
|
||||
{
|
||||
identifierService.register(c, item);
|
||||
}else{
|
||||
identifierService.register(c, item, suppliedHandle);
|
||||
}
|
||||
} catch (IdentifierException e) {
|
||||
throw new RuntimeException("Can't create an Identifier!");
|
||||
}
|
||||
|
||||
// Even though we are restoring an item it may not have the proper dates. So let's
|
||||
@@ -146,28 +141,6 @@ public class InstallItem
|
||||
return finishItem(c, item, is);
|
||||
}
|
||||
|
||||
private static void populateHandleMetadata(Item item, String handle)
|
||||
throws SQLException, IOException, AuthorizeException
|
||||
{
|
||||
String handleref = HandleManager.getCanonicalForm(handle);
|
||||
|
||||
// Add handle as identifier.uri DC value.
|
||||
// First check that identifier doesn't already exist.
|
||||
boolean identifierExists = false;
|
||||
DCValue[] identifiers = item.getDC("identifier", "uri", Item.ANY);
|
||||
for (DCValue identifier : identifiers)
|
||||
{
|
||||
if (handleref.equals(identifier.value))
|
||||
{
|
||||
identifierExists = true;
|
||||
}
|
||||
}
|
||||
if (!identifierExists)
|
||||
{
|
||||
item.addDC("identifier", "uri", null, handleref);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static void populateMetadata(Context c, Item item)
|
||||
throws SQLException, IOException, AuthorizeException
|
||||
|
@@ -38,9 +38,13 @@ import org.dspace.event.Event;
|
||||
import org.dspace.eperson.EPerson;
|
||||
import org.dspace.eperson.Group;
|
||||
import org.dspace.handle.HandleManager;
|
||||
import org.dspace.identifier.IdentifierException;
|
||||
import org.dspace.identifier.IdentifierService;
|
||||
import org.dspace.storage.rdbms.DatabaseManager;
|
||||
import org.dspace.storage.rdbms.TableRow;
|
||||
import org.dspace.storage.rdbms.TableRowIterator;
|
||||
import org.dspace.utils.DSpace;
|
||||
import org.dspace.versioning.VersioningService;
|
||||
|
||||
/**
|
||||
* Class representing an item in DSpace.
|
||||
@@ -2039,10 +2043,30 @@ public class Item extends DSpaceObject
|
||||
// Remove any Handle
|
||||
HandleManager.unbindHandle(ourContext, this);
|
||||
|
||||
// remove version attached to the item
|
||||
removeVersion();
|
||||
|
||||
|
||||
// Finally remove item row
|
||||
DatabaseManager.delete(ourContext, itemRow);
|
||||
}
|
||||
|
||||
private void removeVersion() throws AuthorizeException, SQLException
|
||||
{
|
||||
VersioningService versioningService = new DSpace().getSingletonService(VersioningService.class);
|
||||
if(versioningService.getVersion(ourContext, this)!=null)
|
||||
{
|
||||
versioningService.removeVersion(ourContext, this);
|
||||
}else{
|
||||
IdentifierService identifierService = new DSpace().getSingletonService(IdentifierService.class);
|
||||
try {
|
||||
identifierService.delete(ourContext, this);
|
||||
} catch (IdentifierException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove item and all its sub-structure from the context cache.
|
||||
* Useful in batch processes where a single context has a long,
|
||||
|
@@ -96,7 +96,7 @@ public class Site extends DSpaceObject
|
||||
}
|
||||
|
||||
public void update()
|
||||
throws SQLException, AuthorizeException, IOException
|
||||
throws SQLException, AuthorizeException
|
||||
{
|
||||
}
|
||||
|
||||
|
@@ -506,7 +506,7 @@ public class WorkspaceItem implements InProgressSubmission
|
||||
/**
|
||||
* Update the workspace item, including the unarchived item.
|
||||
*/
|
||||
public void update() throws SQLException, AuthorizeException, IOException
|
||||
public void update() throws SQLException, AuthorizeException
|
||||
{
|
||||
// Authorisation is checked by the item.update() method below
|
||||
|
||||
|
@@ -9,13 +9,7 @@ package org.dspace.core;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.EmptyStackException;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Stack;
|
||||
import java.util.*;
|
||||
|
||||
import org.apache.log4j.Logger;
|
||||
import org.dspace.eperson.EPerson;
|
||||
@@ -24,6 +18,7 @@ import org.dspace.event.Dispatcher;
|
||||
import org.dspace.event.Event;
|
||||
import org.dspace.event.EventManager;
|
||||
import org.dspace.storage.rdbms.DatabaseManager;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
/**
|
||||
* Class representing the context of a particular DSpace operation. This stores
|
||||
@@ -77,7 +72,7 @@ public class Context
|
||||
private List<Integer> specialGroups;
|
||||
|
||||
/** Content events */
|
||||
private List<Event> events = null;
|
||||
private LinkedList<Event> events = null;
|
||||
|
||||
/** Event dispatcher name */
|
||||
private String dispName = null;
|
||||
@@ -375,7 +370,7 @@ public class Context
|
||||
{
|
||||
if (events == null)
|
||||
{
|
||||
events = new ArrayList<Event>();
|
||||
events = new LinkedList<Event>();
|
||||
}
|
||||
|
||||
events.add(event);
|
||||
@@ -385,17 +380,32 @@ public class Context
|
||||
* Get the current event list. If there is a separate list of events from
|
||||
* already-committed operations combine that with current list.
|
||||
*
|
||||
* TODO WARNING: events uses an ArrayList, a class not ready for concurrency.
|
||||
* Read http://download.oracle.com/javase/6/docs/api/java/util/Collections.html#synchronizedList%28java.util.List%29
|
||||
* on how to properly synchronize the class when calling this method
|
||||
*
|
||||
* @return List of all available events.
|
||||
*/
|
||||
public List<Event> getEvents()
|
||||
public LinkedList<Event> getEvents()
|
||||
{
|
||||
return events;
|
||||
}
|
||||
|
||||
public boolean hasEvents()
|
||||
{
|
||||
return !CollectionUtils.isEmpty(events);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the first element in the events list & removes it from the list of events once retrieved
|
||||
* @return The first event of the list or <code>null</code> if the list is empty
|
||||
*/
|
||||
public Event pollEvent()
|
||||
{
|
||||
if(hasEvents())
|
||||
{
|
||||
return events.poll();
|
||||
}else{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Close the context, without committing any of the changes performed using
|
||||
* this context. The database connection is freed. No exception is thrown if
|
||||
|
@@ -7,9 +7,7 @@
|
||||
*/
|
||||
package org.dspace.event;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.log4j.Logger;
|
||||
import org.dspace.core.Context;
|
||||
@@ -72,9 +70,8 @@ public class BasicDispatcher extends Dispatcher
|
||||
{
|
||||
if (!consumers.isEmpty())
|
||||
{
|
||||
List<Event> events = Collections.synchronizedList(ctx.getEvents());
|
||||
|
||||
if (events == null)
|
||||
if (!ctx.hasEvents())
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -82,7 +79,7 @@ public class BasicDispatcher extends Dispatcher
|
||||
if (log.isDebugEnabled())
|
||||
{
|
||||
log.debug("Processing queue of "
|
||||
+ String.valueOf(events.size()) + " events.");
|
||||
+ String.valueOf(ctx.getEvents().size()) + " events.");
|
||||
}
|
||||
|
||||
// transaction identifier applies to all events created in
|
||||
@@ -90,8 +87,9 @@ public class BasicDispatcher extends Dispatcher
|
||||
// some letters so RDF readers don't mistake it for an integer.
|
||||
String tid = "TX" + Utils.generateKey();
|
||||
|
||||
for (Event event : events)
|
||||
while (ctx.hasEvents())
|
||||
{
|
||||
Event event = ctx.pollEvent();
|
||||
event.setDispatcher(getIdentifier());
|
||||
event.setTransactionID(tid);
|
||||
|
||||
|
@@ -27,13 +27,13 @@ import org.dspace.storage.rdbms.TableRowIterator;
|
||||
/**
|
||||
* Interface to the <a href="http://www.handle.net" target=_new>CNRI Handle
|
||||
* System </a>.
|
||||
*
|
||||
*
|
||||
* <p>
|
||||
* Currently, this class simply maps handles to local facilities; handles which
|
||||
* are owned by other sites (including other DSpaces) are treated as
|
||||
* non-existent.
|
||||
* </p>
|
||||
*
|
||||
*
|
||||
* @author Peter Breton
|
||||
* @version $Revision$
|
||||
*/
|
||||
@@ -52,10 +52,10 @@ public class HandleManager
|
||||
|
||||
/**
|
||||
* Return the local URL for handle, or null if handle cannot be found.
|
||||
*
|
||||
*
|
||||
* The returned URL is a (non-handle-based) location where a dissemination
|
||||
* of the object referred to by handle can be obtained.
|
||||
*
|
||||
*
|
||||
* @param context
|
||||
* DSpace context
|
||||
* @param handle
|
||||
@@ -87,17 +87,17 @@ public class HandleManager
|
||||
|
||||
/**
|
||||
* Transforms handle into the canonical form <em>hdl:handle</em>.
|
||||
*
|
||||
*
|
||||
* No attempt is made to verify that handle is in fact valid.
|
||||
*
|
||||
*
|
||||
* @param handle
|
||||
* The handle
|
||||
* @return The canonical form
|
||||
*/
|
||||
public static String getCanonicalForm(String handle)
|
||||
{
|
||||
|
||||
// Let the admin define a new prefix, if not then we'll use the
|
||||
|
||||
// Let the admin define a new prefix, if not then we'll use the
|
||||
// CNRI default. This allows the admin to use "hdl:" if they want to or
|
||||
// use a locally branded prefix handle.myuni.edu.
|
||||
String handlePrefix = ConfigurationManager.getProperty("handle.canonical.prefix");
|
||||
@@ -105,7 +105,7 @@ public class HandleManager
|
||||
{
|
||||
handlePrefix = "http://hdl.handle.net/";
|
||||
}
|
||||
|
||||
|
||||
return handlePrefix + handle;
|
||||
}
|
||||
|
||||
@@ -126,7 +126,7 @@ public class HandleManager
|
||||
|
||||
/**
|
||||
* Creates a new handle in the database.
|
||||
*
|
||||
*
|
||||
* @param context
|
||||
* DSpace context
|
||||
* @param dso
|
||||
@@ -158,7 +158,7 @@ public class HandleManager
|
||||
/**
|
||||
* Creates a handle entry, but with a handle supplied by the caller (new
|
||||
* Handle not generated)
|
||||
*
|
||||
*
|
||||
* @param context
|
||||
* DSpace context
|
||||
* @param dso
|
||||
@@ -234,21 +234,24 @@ public class HandleManager
|
||||
public static void unbindHandle(Context context, DSpaceObject dso)
|
||||
throws SQLException
|
||||
{
|
||||
TableRow row = getHandleInternal(context, dso.getType(), dso.getID());
|
||||
if (row != null)
|
||||
TableRowIterator rows = getInternalHandles(context, dso.getType(), dso.getID());
|
||||
if (rows != null)
|
||||
{
|
||||
//Only set the "resouce_id" column to null when unbinding a handle.
|
||||
// We want to keep around the "resource_type_id" value, so that we
|
||||
// can verify during a restore whether the same *type* of resource
|
||||
// is reusing this handle!
|
||||
row.setColumnNull("resource_id");
|
||||
DatabaseManager.update(context, row);
|
||||
|
||||
if(log.isDebugEnabled())
|
||||
while (rows.hasNext())
|
||||
{
|
||||
log.debug("Unbound Handle " + row.getStringColumn("handle") + " from object " + Constants.typeText[dso.getType()] + " id=" + dso.getID());
|
||||
}
|
||||
TableRow row = rows.next();
|
||||
//Only set the "resouce_id" column to null when unbinding a handle.
|
||||
// We want to keep around the "resource_type_id" value, so that we
|
||||
// can verify during a restore whether the same *type* of resource
|
||||
// is reusing this handle!
|
||||
row.setColumnNull("resource_id");
|
||||
DatabaseManager.update(context, row);
|
||||
|
||||
if(log.isDebugEnabled())
|
||||
{
|
||||
log.debug("Unbound Handle " + row.getStringColumn("handle") + " from object " + Constants.typeText[dso.getType()] + " id=" + dso.getID());
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -259,7 +262,7 @@ public class HandleManager
|
||||
/**
|
||||
* Return the object which handle maps to, or null. This is the object
|
||||
* itself, not a URL which points to it.
|
||||
*
|
||||
*
|
||||
* @param context
|
||||
* DSpace context
|
||||
* @param handle
|
||||
@@ -288,7 +291,7 @@ public class HandleManager
|
||||
}
|
||||
|
||||
// check if handle was allocated previously, but is currently not
|
||||
// associated with a DSpaceObject
|
||||
// associated with a DSpaceObject
|
||||
// (this may occur when 'unbindHandle()' is called for an obj that was removed)
|
||||
if ((dbhandle.isColumnNull("resource_type_id"))
|
||||
|| (dbhandle.isColumnNull("resource_id")))
|
||||
@@ -344,7 +347,7 @@ public class HandleManager
|
||||
|
||||
/**
|
||||
* Return the handle for an Object, or null if the Object has no handle.
|
||||
*
|
||||
*
|
||||
* @param context
|
||||
* DSpace context
|
||||
* @param dso
|
||||
@@ -356,8 +359,8 @@ public class HandleManager
|
||||
public static String findHandle(Context context, DSpaceObject dso)
|
||||
throws SQLException
|
||||
{
|
||||
TableRow row = getHandleInternal(context, dso.getType(), dso.getID());
|
||||
if (row == null)
|
||||
TableRowIterator rows = getInternalHandles(context, dso.getType(), dso.getID());
|
||||
if (rows == null || !rows.hasNext())
|
||||
{
|
||||
if (dso.getType() == Constants.SITE)
|
||||
{
|
||||
@@ -370,13 +373,27 @@ public class HandleManager
|
||||
}
|
||||
else
|
||||
{
|
||||
return row.getStringColumn("handle");
|
||||
//TODO: Move this code away from the HandleManager & into the Identifier provider
|
||||
//Attempt to retrieve a handle that does NOT look like {handle.part}/{handle.part}.{version}
|
||||
String result = rows.next().getStringColumn("handle");
|
||||
while (rows.hasNext())
|
||||
{
|
||||
TableRow row = rows.next();
|
||||
//Ensure that the handle doesn't look like this 12346/213.{version}
|
||||
//If we find a match that indicates that we have a proper handle
|
||||
if(!row.getStringColumn("handle").matches(".*/.*\\.\\d+"))
|
||||
{
|
||||
result = row.getStringColumn("handle");
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return all the handles which start with prefix.
|
||||
*
|
||||
*
|
||||
* @param context
|
||||
* DSpace context
|
||||
* @param prefix
|
||||
@@ -434,7 +451,7 @@ public class HandleManager
|
||||
|
||||
/**
|
||||
* Return the handle for an Object, or null if the Object has no handle.
|
||||
*
|
||||
*
|
||||
* @param context
|
||||
* DSpace context
|
||||
* @param type
|
||||
@@ -445,18 +462,18 @@ public class HandleManager
|
||||
* @exception SQLException
|
||||
* If a database error occurs
|
||||
*/
|
||||
private static TableRow getHandleInternal(Context context, int type, int id)
|
||||
private static TableRowIterator getInternalHandles(Context context, int type, int id)
|
||||
throws SQLException
|
||||
{
|
||||
{
|
||||
String sql = "SELECT * FROM Handle WHERE resource_type_id = ? " +
|
||||
"AND resource_id = ?";
|
||||
|
||||
return DatabaseManager.querySingleTable(context, "Handle", sql, type, id);
|
||||
return DatabaseManager.queryTable(context, "Handle", sql, type, id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the database row corresponding to handle.
|
||||
*
|
||||
*
|
||||
* @param context
|
||||
* DSpace context
|
||||
* @param handle
|
||||
|
18
dspace-api/src/main/java/org/dspace/identifier/Handle.java
Normal file
18
dspace-api/src/main/java/org/dspace/identifier/Handle.java
Normal file
@@ -0,0 +1,18 @@
|
||||
/**
|
||||
* 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.identifier;
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @author Fabio Bolognesi (fabio at atmire dot com)
|
||||
* @author Mark Diggory (markd at atmire dot com)
|
||||
* @author Ben Bosman (ben at atmire dot com)
|
||||
*/
|
||||
public class Handle implements Identifier {
|
||||
}
|
@@ -0,0 +1,448 @@
|
||||
/**
|
||||
* 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.identifier;
|
||||
|
||||
import org.apache.log4j.Logger;
|
||||
import org.dspace.authorize.AuthorizeException;
|
||||
import org.dspace.content.*;
|
||||
import org.dspace.core.ConfigurationManager;
|
||||
import org.dspace.core.Constants;
|
||||
import org.dspace.core.Context;
|
||||
import org.dspace.core.LogManager;
|
||||
import org.dspace.storage.rdbms.DatabaseManager;
|
||||
import org.dspace.storage.rdbms.TableRow;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.sql.SQLException;
|
||||
|
||||
/**
|
||||
* The old DSpace handle identifier service, used to create handles or retrieve objects based on their handle
|
||||
*
|
||||
* @author Fabio Bolognesi (fabio at atmire dot com)
|
||||
* @author Mark Diggory (markd at atmire dot com)
|
||||
* @author Ben Bosman (ben at atmire dot com)
|
||||
*/
|
||||
@Component
|
||||
public class HandleIdentifierProvider extends IdentifierProvider {
|
||||
/** log4j category */
|
||||
private static Logger log = Logger.getLogger(HandleIdentifierProvider.class);
|
||||
|
||||
/** Prefix registered to no one */
|
||||
protected static final String EXAMPLE_PREFIX = "123456789";
|
||||
|
||||
protected String[] supportedPrefixes = new String[]{"info:hdl", "hdl", "http://"};
|
||||
|
||||
@Override
|
||||
public boolean supports(Class<? extends Identifier> identifier) {
|
||||
return Handle.class.isAssignableFrom(identifier);
|
||||
}
|
||||
|
||||
public boolean supports(String identifier)
|
||||
{
|
||||
for(String prefix : supportedPrefixes){
|
||||
if(identifier.startsWith(prefix))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
String outOfUrl = retrieveHandleOutOfUrl(identifier);
|
||||
if(outOfUrl != null)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
log.error(e.getMessage(), e);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public String register(Context context, DSpaceObject dso) {
|
||||
try{
|
||||
String id = mint(context, dso);
|
||||
|
||||
// move canonical to point the latest version
|
||||
if(dso instanceof Item)
|
||||
{
|
||||
Item item = (Item)dso;
|
||||
populateHandleMetadata(item, id);
|
||||
}
|
||||
|
||||
return id;
|
||||
}catch (Exception e){
|
||||
log.error(LogManager.getHeader(context, "Error while attempting to create handle", "Item id: " + dso.getID()), e);
|
||||
throw new RuntimeException("Error while attempting to create identifier for Item id: " + dso.getID(), e);
|
||||
}
|
||||
}
|
||||
|
||||
public void register(Context context, DSpaceObject dso, String identifier) {
|
||||
try{
|
||||
createNewIdentifier(context, dso, identifier);
|
||||
if(dso instanceof Item)
|
||||
{
|
||||
Item item = (Item)dso;
|
||||
populateHandleMetadata(item, identifier);
|
||||
}
|
||||
}catch (Exception e){
|
||||
log.error(LogManager.getHeader(context, "Error while attempting to create handle", "Item id: " + dso.getID()), e);
|
||||
throw new RuntimeException("Error while attempting to create identifier for Item id: " + dso.getID(), e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void reserve(Context context, DSpaceObject dso, String identifier) {
|
||||
try{
|
||||
TableRow handle = DatabaseManager.create(context, "Handle");
|
||||
modifyHandleRecord(context, dso, handle, identifier);
|
||||
}catch(Exception e){
|
||||
log.error(LogManager.getHeader(context, "Error while attempting to create handle", "Item id: " + dso.getID()), e);
|
||||
throw new RuntimeException("Error while attempting to create identifier for Item id: " + dso.getID());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Creates a new handle in the database.
|
||||
*
|
||||
* @param context DSpace context
|
||||
* @param dso The DSpaceObject to create a handle for
|
||||
* @return The newly created handle
|
||||
* @exception java.sql.SQLException If a database error occurs
|
||||
*/
|
||||
public String mint(Context context, DSpaceObject dso) {
|
||||
if(dso.getHandle() != null)
|
||||
{
|
||||
return dso.getHandle();
|
||||
}
|
||||
|
||||
try{
|
||||
return createNewIdentifier(context, dso, null);
|
||||
}catch (Exception e){
|
||||
log.error(LogManager.getHeader(context, "Error while attempting to create handle", "Item id: " + dso.getID()), e);
|
||||
throw new RuntimeException("Error while attempting to create identifier for Item id: " + dso.getID());
|
||||
}
|
||||
}
|
||||
|
||||
public DSpaceObject resolve(Context context, String identifier, String... attributes) {
|
||||
// We can do nothing with this, return null
|
||||
try
|
||||
{
|
||||
TableRow dbhandle = findHandleInternal(context, identifier);
|
||||
|
||||
if (dbhandle == null)
|
||||
{
|
||||
//Check for an url
|
||||
identifier = retrieveHandleOutOfUrl(identifier);
|
||||
if(identifier != null)
|
||||
{
|
||||
dbhandle = findHandleInternal(context, identifier);
|
||||
}
|
||||
|
||||
if(dbhandle == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
if ((dbhandle.isColumnNull("resource_type_id")) || (dbhandle.isColumnNull("resource_id")))
|
||||
{
|
||||
throw new IllegalStateException("No associated resource type");
|
||||
}
|
||||
|
||||
// What are we looking at here?
|
||||
int handletypeid = dbhandle.getIntColumn("resource_type_id");
|
||||
int resourceID = dbhandle.getIntColumn("resource_id");
|
||||
|
||||
if (handletypeid == Constants.ITEM)
|
||||
{
|
||||
Item item = Item.find(context, resourceID);
|
||||
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Resolved handle " + identifier + " to item "
|
||||
+ ((item == null) ? (-1) : item.getID()));
|
||||
}
|
||||
|
||||
return item;
|
||||
}
|
||||
else if (handletypeid == Constants.COLLECTION)
|
||||
{
|
||||
Collection collection = Collection.find(context, resourceID);
|
||||
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Resolved handle " + identifier + " to collection "
|
||||
+ ((collection == null) ? (-1) : collection.getID()));
|
||||
}
|
||||
|
||||
return collection;
|
||||
}
|
||||
else if (handletypeid == Constants.COMMUNITY)
|
||||
{
|
||||
Community community = Community.find(context, resourceID);
|
||||
|
||||
if (log.isDebugEnabled())
|
||||
{
|
||||
log.debug("Resolved handle " + identifier + " to community "
|
||||
+ ((community == null) ? (-1) : community.getID()));
|
||||
}
|
||||
|
||||
return community;
|
||||
}
|
||||
}catch (Exception e){
|
||||
log.error(LogManager.getHeader(context, "Error while resolving handle to item", "handle: " + identifier), e);
|
||||
}
|
||||
// throw new IllegalStateException("Unsupported Handle Type "
|
||||
// + Constants.typeText[handletypeid]);
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String lookup(Context context, DSpaceObject dso) throws IdentifierNotFoundException, IdentifierNotResolvableException {
|
||||
|
||||
try
|
||||
{
|
||||
TableRow row = getHandleInternal(context, dso.getType(), dso.getID());
|
||||
if (row == null)
|
||||
{
|
||||
if (dso.getType() == Constants.SITE)
|
||||
{
|
||||
return Site.getSiteHandle();
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return row.getStringColumn("handle");
|
||||
}
|
||||
}catch(SQLException sqe){
|
||||
throw new IdentifierNotResolvableException(sqe.getMessage(),sqe);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void delete(Context context, DSpaceObject dso, String identifier) throws IdentifierException {
|
||||
delete(context, dso);
|
||||
}
|
||||
|
||||
public void delete(Context context, DSpaceObject dso) throws IdentifierException {
|
||||
try{
|
||||
TableRow row = getHandleInternal(context, dso.getType(), dso.getID());
|
||||
if (row != null)
|
||||
{
|
||||
//Only set the "resouce_id" column to null when unbinding a handle.
|
||||
// We want to keep around the "resource_type_id" value, so that we
|
||||
// can verify during a restore whether the same *type* of resource
|
||||
// is reusing this handle!
|
||||
row.setColumnNull("resource_id");
|
||||
DatabaseManager.update(context, row);
|
||||
|
||||
if(log.isDebugEnabled())
|
||||
{
|
||||
log.debug("Unbound Handle " + row.getStringColumn("handle") + " from object " + Constants.typeText[dso.getType()] + " id=" + dso.getID());
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
log.warn("Cannot find Handle entry to unbind for object " + Constants.typeText[dso.getType()] + " id=" + dso.getID());
|
||||
}
|
||||
}catch(SQLException sqe)
|
||||
{
|
||||
throw new IdentifierException(sqe.getMessage(),sqe);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static String retrieveHandleOutOfUrl(String url)
|
||||
throws SQLException {
|
||||
// We can do nothing with this, return null
|
||||
if (!url.contains("/"))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
String[] splitUrl = url.split("/");
|
||||
|
||||
return splitUrl[splitUrl.length - 2] + "/" + splitUrl[splitUrl.length - 1];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the configured Handle prefix string, or a default
|
||||
* @return configured prefix or "123456789"
|
||||
*/
|
||||
public static String getPrefix()
|
||||
{
|
||||
String prefix = ConfigurationManager.getProperty("handle.prefix");
|
||||
if (null == prefix)
|
||||
{
|
||||
prefix = EXAMPLE_PREFIX; // XXX no good way to exit cleanly
|
||||
log.error("handle.prefix is not configured; using " + prefix);
|
||||
}
|
||||
return prefix;
|
||||
}
|
||||
|
||||
protected static String getCanonicalForm(String handle)
|
||||
{
|
||||
|
||||
// Let the admin define a new prefix, if not then we'll use the
|
||||
// CNRI default. This allows the admin to use "hdl:" if they want to or
|
||||
// use a locally branded prefix handle.myuni.edu.
|
||||
String handlePrefix = ConfigurationManager.getProperty("handle.canonical.prefix");
|
||||
if (handlePrefix == null || handlePrefix.length() == 0)
|
||||
{
|
||||
handlePrefix = "http://hdl.handle.net/";
|
||||
}
|
||||
|
||||
return handlePrefix + handle;
|
||||
}
|
||||
|
||||
protected String createNewIdentifier(Context context, DSpaceObject dso, String handleId) throws SQLException {
|
||||
TableRow handle=null;
|
||||
if(handleId != null)
|
||||
{
|
||||
handle = findHandleInternal(context, handleId);
|
||||
|
||||
|
||||
if(handle!=null && !handle.isColumnNull("resource_id"))
|
||||
{
|
||||
//Check if this handle is already linked up to this specified DSpace Object
|
||||
if(handle.getIntColumn("resource_id")==dso.getID() &&
|
||||
handle.getIntColumn("resource_type_id")==dso.getType())
|
||||
{
|
||||
//This handle already links to this DSpace Object -- so, there's nothing else we need to do
|
||||
return handleId;
|
||||
}
|
||||
else
|
||||
{
|
||||
//handle found in DB table & already in use by another existing resource
|
||||
throw new IllegalStateException("Attempted to create a handle which is already in use: " + handleId);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
else if(handle!=null && !handle.isColumnNull("resource_type_id"))
|
||||
{
|
||||
//If there is a 'resource_type_id' (but 'resource_id' is empty), then the object using
|
||||
// this handle was previously unbound (see unbindHandle() method) -- likely because object was deleted
|
||||
int previousType = handle.getIntColumn("resource_type_id");
|
||||
|
||||
//Since we are restoring an object to a pre-existing handle, double check we are restoring the same *type* of object
|
||||
// (e.g. we will not allow an Item to be restored to a handle previously used by a Collection)
|
||||
if(previousType != dso.getType())
|
||||
{
|
||||
throw new IllegalStateException("Attempted to reuse a handle previously used by a " +
|
||||
Constants.typeText[previousType] + " for a new " +
|
||||
Constants.typeText[dso.getType()]);
|
||||
}
|
||||
}
|
||||
|
||||
if(handle==null){
|
||||
handle = DatabaseManager.create(context, "Handle");
|
||||
handleId = createId(handle.getIntColumn("handle_id"));
|
||||
}
|
||||
|
||||
modifyHandleRecord(context, dso, handle, handleId);
|
||||
return handleId;
|
||||
}
|
||||
|
||||
protected String modifyHandleRecord(Context context, DSpaceObject dso, TableRow handle, String handleId) throws SQLException {
|
||||
handle.setColumn("handle", handleId);
|
||||
handle.setColumn("resource_type_id", dso.getType());
|
||||
handle.setColumn("resource_id", dso.getID());
|
||||
DatabaseManager.update(context, handle);
|
||||
|
||||
if (log.isDebugEnabled())
|
||||
{
|
||||
log.debug("Created new handle for "
|
||||
+ Constants.typeText[dso.getType()] + " " + handleId);
|
||||
}
|
||||
return handleId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the handle for an Object, or null if the Object has no handle.
|
||||
*
|
||||
* @param context
|
||||
* DSpace context
|
||||
* @param type
|
||||
* The type of object
|
||||
* @param id
|
||||
* The id of object
|
||||
* @return The handle for object, or null if the object has no handle.
|
||||
* @exception java.sql.SQLException
|
||||
* If a database error occurs
|
||||
*/
|
||||
protected static TableRow getHandleInternal(Context context, int type, int id)
|
||||
throws SQLException
|
||||
{
|
||||
String sql = "SELECT * FROM Handle WHERE resource_type_id = ? " +
|
||||
"AND resource_id = ?";
|
||||
|
||||
return DatabaseManager.querySingleTable(context, "Handle", sql, type, id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the database row corresponding to handle.
|
||||
*
|
||||
* @param context DSpace context
|
||||
* @param handle The handle to resolve
|
||||
* @return The database row corresponding to the handle
|
||||
* @exception java.sql.SQLException If a database error occurs
|
||||
*/
|
||||
protected static TableRow findHandleInternal(Context context, String handle)
|
||||
throws SQLException {
|
||||
if (handle == null)
|
||||
{
|
||||
throw new IllegalArgumentException("Handle is null");
|
||||
}
|
||||
return DatabaseManager.findByUnique(context, "Handle", "handle", handle);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new handle id. The implementation uses the PK of the RDBMS
|
||||
* Handle table.
|
||||
*
|
||||
* @return A new handle id
|
||||
* @exception java.sql.SQLException
|
||||
* If a database error occurs
|
||||
*/
|
||||
protected static String createId(int id) throws SQLException
|
||||
{
|
||||
String handlePrefix = getPrefix();
|
||||
|
||||
return handlePrefix + (handlePrefix.endsWith("/") ? "" : "/") + id;
|
||||
}
|
||||
|
||||
|
||||
protected void populateHandleMetadata(Item item, String handle)
|
||||
throws SQLException, IOException, AuthorizeException
|
||||
{
|
||||
String handleref = getCanonicalForm(handle);
|
||||
|
||||
// Add handle as identifier.uri DC value.
|
||||
// First check that identifier doesn't already exist.
|
||||
boolean identifierExists = false;
|
||||
DCValue[] identifiers = item.getDC("identifier", "uri", Item.ANY);
|
||||
for (DCValue identifier : identifiers)
|
||||
{
|
||||
if (handleref.equals(identifier.value))
|
||||
{
|
||||
identifierExists = true;
|
||||
}
|
||||
}
|
||||
if (!identifierExists)
|
||||
{
|
||||
item.addDC("identifier", "uri", null, handleref);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,18 @@
|
||||
/**
|
||||
* 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.identifier;
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @author Fabio Bolognesi (fabio at atmire dot com)
|
||||
* @author Mark Diggory (markd at atmire dot com)
|
||||
* @author Ben Bosman (ben at atmire dot com)
|
||||
*/
|
||||
public interface Identifier {
|
||||
}
|
@@ -0,0 +1,33 @@
|
||||
/**
|
||||
* 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.identifier;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Fabio Bolognesi (fabio at atmire dot com)
|
||||
* @author Mark Diggory (markd at atmire dot com)
|
||||
* @author Ben Bosman (ben at atmire dot com)
|
||||
*/
|
||||
public class IdentifierException extends Exception{
|
||||
|
||||
public IdentifierException() {
|
||||
super();
|
||||
}
|
||||
|
||||
public IdentifierException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public IdentifierException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
public IdentifierException(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
}
|
@@ -0,0 +1,34 @@
|
||||
/**
|
||||
* 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.identifier;
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @author Fabio Bolognesi (fabio at atmire dot com)
|
||||
* @author Mark Diggory (markd at atmire dot com)
|
||||
* @author Ben Bosman (ben at atmire dot com)
|
||||
*/
|
||||
public class IdentifierNotFoundException extends IdentifierException {
|
||||
|
||||
public IdentifierNotFoundException() {
|
||||
super();
|
||||
}
|
||||
|
||||
public IdentifierNotFoundException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public IdentifierNotFoundException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
public IdentifierNotFoundException(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
}
|
@@ -0,0 +1,34 @@
|
||||
/**
|
||||
* 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.identifier;
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @author Fabio Bolognesi (fabio at atmire dot com)
|
||||
* @author Mark Diggory (markd at atmire dot com)
|
||||
* @author Ben Bosman (ben at atmire dot com)
|
||||
*/
|
||||
public class IdentifierNotResolvableException extends IdentifierException {
|
||||
|
||||
public IdentifierNotResolvableException() {
|
||||
super();
|
||||
}
|
||||
|
||||
public IdentifierNotResolvableException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public IdentifierNotResolvableException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
public IdentifierNotResolvableException(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
}
|
@@ -0,0 +1,58 @@
|
||||
/**
|
||||
* 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.identifier;
|
||||
|
||||
import org.dspace.content.DSpaceObject;
|
||||
import org.dspace.core.Context;
|
||||
import org.dspace.services.ConfigurationService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Required;
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @author Fabio Bolognesi (fabio at atmire dot com)
|
||||
* @author Mark Diggory (markd at atmire dot com)
|
||||
* @author Ben Bosman (ben at atmire dot com)
|
||||
*/
|
||||
public abstract class IdentifierProvider {
|
||||
|
||||
protected IdentifierService parentService;
|
||||
|
||||
protected ConfigurationService configurationService;
|
||||
|
||||
@Autowired
|
||||
@Required
|
||||
public void setConfigurationService(ConfigurationService configurationService) {
|
||||
this.configurationService = configurationService;
|
||||
}
|
||||
|
||||
public void setParentService(IdentifierService parentService) {
|
||||
this.parentService = parentService;
|
||||
}
|
||||
|
||||
public abstract boolean supports(Class<? extends Identifier> identifier);
|
||||
|
||||
public abstract boolean supports(String identifier);
|
||||
|
||||
public abstract String register(Context context, DSpaceObject item) throws IdentifierException;
|
||||
|
||||
public abstract String mint(Context context, DSpaceObject dso) throws IdentifierException;
|
||||
|
||||
public abstract DSpaceObject resolve(Context context, String identifier, String... attributes) throws IdentifierNotFoundException, IdentifierNotResolvableException;;
|
||||
|
||||
public abstract String lookup(Context context, DSpaceObject object) throws IdentifierNotFoundException, IdentifierNotResolvableException;;
|
||||
|
||||
public abstract void delete(Context context, DSpaceObject dso) throws IdentifierException;
|
||||
|
||||
public abstract void delete(Context context, DSpaceObject dso, String identifier) throws IdentifierException;
|
||||
|
||||
public abstract void reserve(Context context, DSpaceObject dso, String identifier) throws IdentifierException;
|
||||
|
||||
public abstract void register(Context context, DSpaceObject object, String identifier);
|
||||
}
|
@@ -0,0 +1,130 @@
|
||||
/**
|
||||
* 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.identifier;
|
||||
|
||||
import org.dspace.authorize.AuthorizeException;
|
||||
import org.dspace.content.DSpaceObject;
|
||||
import org.dspace.core.Context;
|
||||
|
||||
import java.sql.SQLException;
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @author Fabio Bolognesi (fabio at atmire dot com)
|
||||
* @author Mark Diggory (markd at atmire dot com)
|
||||
* @author Ben Bosman (ben at atmire dot com)
|
||||
*/
|
||||
public interface IdentifierService {
|
||||
|
||||
/**
|
||||
*
|
||||
* @param context
|
||||
* @param dso
|
||||
* @param identifier
|
||||
* @return
|
||||
*/
|
||||
String lookup(Context context, DSpaceObject dso, Class<? extends Identifier> identifier);
|
||||
|
||||
/**
|
||||
*
|
||||
* This will resolve a DSpaceObject based on a provided Identifier. The Service will interrogate the providers in
|
||||
* no particular order and return the first successful result discovered. If no resolution is successful,
|
||||
* the method will return null if no object is found.
|
||||
*
|
||||
* TODO: Verify null is returned.
|
||||
*
|
||||
* @param context
|
||||
* @param identifier
|
||||
* @return
|
||||
* @throws IdentifierNotFoundException
|
||||
* @throws IdentifierNotResolvableException
|
||||
*/
|
||||
DSpaceObject resolve(Context context, String identifier) throws IdentifierNotFoundException, IdentifierNotResolvableException;
|
||||
|
||||
/**
|
||||
*
|
||||
* Reserves any identifiers necessary based on the capabilities of all providers in the service.
|
||||
*
|
||||
* @param context
|
||||
* @param dso
|
||||
* @throws org.dspace.authorize.AuthorizeException
|
||||
* @throws java.sql.SQLException
|
||||
* @throws IdentifierException
|
||||
*/
|
||||
void reserve(Context context, DSpaceObject dso) throws AuthorizeException, SQLException, IdentifierException;
|
||||
|
||||
/**
|
||||
*
|
||||
* Used to Reserve a Specific Identifier (for example a Handle, hdl:1234.5/6) The provider is responsible for
|
||||
* Detecting and Processing the appropriate identifier, all Providers are interrogated, multiple providers
|
||||
* can process the same identifier.
|
||||
*
|
||||
* @param context
|
||||
* @param dso
|
||||
* @param identifier
|
||||
* @throws org.dspace.authorize.AuthorizeException
|
||||
* @throws java.sql.SQLException
|
||||
* @throws IdentifierException
|
||||
*/
|
||||
void reserve(Context context, DSpaceObject dso, String identifier) throws AuthorizeException, SQLException, IdentifierException;
|
||||
|
||||
/**
|
||||
*
|
||||
* @param context
|
||||
* @param dso
|
||||
* @return
|
||||
* @throws org.dspace.authorize.AuthorizeException
|
||||
* @throws java.sql.SQLException
|
||||
* @throws IdentifierException
|
||||
*/
|
||||
void register(Context context, DSpaceObject dso) throws AuthorizeException, SQLException, IdentifierException;
|
||||
|
||||
/**
|
||||
*
|
||||
* Used to Register a Specific Identifier (for example a Handle, hdl:1234.5/6) The provider is responsible for
|
||||
* Detecting and Processing the appropriate identifier, all Providers are interrogated, multiple providers
|
||||
* can process the same identifier.
|
||||
*
|
||||
* @param context
|
||||
* @param dso
|
||||
* @param identifier
|
||||
* @return
|
||||
* @throws org.dspace.authorize.AuthorizeException
|
||||
* @throws java.sql.SQLException
|
||||
* @throws IdentifierException
|
||||
*/
|
||||
void register(Context context, DSpaceObject dso, String identifier) throws AuthorizeException, SQLException, IdentifierException;
|
||||
|
||||
/**
|
||||
* Delete (Unbind) all identifiers registered for a specific DSpace item. Identifiers are "unbound" across
|
||||
* all providers in no particular order.
|
||||
*
|
||||
* @param context
|
||||
* @param dso
|
||||
* @throws org.dspace.authorize.AuthorizeException
|
||||
* @throws java.sql.SQLException
|
||||
* @throws IdentifierException
|
||||
*/
|
||||
void delete(Context context, DSpaceObject dso) throws AuthorizeException, SQLException, IdentifierException;
|
||||
|
||||
/**
|
||||
* Used to Delete a Specific Identifier (for example a Handle, hdl:1234.5/6) The provider is responsible for
|
||||
* Detecting and Processing the appropriate identifier, all Providers are interrogated, multiple providers
|
||||
* can process the same identifier.
|
||||
*
|
||||
* @param context
|
||||
* @param dso
|
||||
* @param identifier
|
||||
* @throws org.dspace.authorize.AuthorizeException
|
||||
* @throws java.sql.SQLException
|
||||
* @throws IdentifierException
|
||||
*/
|
||||
void delete(Context context, DSpaceObject dso, String identifier) throws AuthorizeException, SQLException, IdentifierException;
|
||||
|
||||
}
|
@@ -0,0 +1,165 @@
|
||||
/**
|
||||
* 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.identifier;
|
||||
|
||||
import org.apache.log4j.Logger;
|
||||
import org.dspace.authorize.AuthorizeException;
|
||||
import org.dspace.content.DSpaceObject;
|
||||
import org.dspace.core.Context;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Required;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* The main service class used to reserve, register and resolve identifiers
|
||||
*
|
||||
* @author Fabio Bolognesi (fabio at atmire dot com)
|
||||
* @author Mark Diggory (markd at atmire dot com)
|
||||
* @author Ben Bosman (ben at atmire dot com)
|
||||
*/
|
||||
public class IdentifierServiceImpl implements IdentifierService {
|
||||
|
||||
private List<IdentifierProvider> providers;
|
||||
|
||||
/** log4j category */
|
||||
private static Logger log = Logger.getLogger(IdentifierServiceImpl.class);
|
||||
|
||||
@Autowired
|
||||
@Required
|
||||
public void setProviders(List<IdentifierProvider> providers)
|
||||
{
|
||||
this.providers = providers;
|
||||
|
||||
for(IdentifierProvider p : providers)
|
||||
{
|
||||
p.setParentService(this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reserves identifiers for the item
|
||||
* @param context dspace context
|
||||
* @param dso dspace object
|
||||
*/
|
||||
public void reserve(Context context, DSpaceObject dso) throws AuthorizeException, SQLException, IdentifierException {
|
||||
for (IdentifierProvider service : providers)
|
||||
{
|
||||
service.mint(context, dso);
|
||||
}
|
||||
//Update our item
|
||||
dso.update();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reserve(Context context, DSpaceObject dso, String identifier) throws AuthorizeException, SQLException, IdentifierException {
|
||||
// Next resolve all other services
|
||||
for (IdentifierProvider service : providers)
|
||||
{
|
||||
if(service.supports(identifier))
|
||||
{
|
||||
service.reserve(context, dso, identifier);
|
||||
}
|
||||
}
|
||||
//Update our item
|
||||
dso.update();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void register(Context context, DSpaceObject dso) throws AuthorizeException, SQLException, IdentifierException {
|
||||
//We need to commit our context because one of the providers might require the handle created above
|
||||
// Next resolve all other services
|
||||
for (IdentifierProvider service : providers)
|
||||
{
|
||||
service.register(context, dso);
|
||||
}
|
||||
//Update our item
|
||||
dso.update();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void register(Context context, DSpaceObject object, String identifier) throws AuthorizeException, SQLException, IdentifierException {
|
||||
|
||||
//We need to commit our context because one of the providers might require the handle created above
|
||||
// Next resolve all other services
|
||||
for (IdentifierProvider service : providers)
|
||||
{
|
||||
service.register(context, object, identifier);
|
||||
}
|
||||
//Update our item
|
||||
object.update();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String lookup(Context context, DSpaceObject dso, Class<? extends Identifier> identifier) {
|
||||
for (IdentifierProvider service : providers)
|
||||
{
|
||||
if(service.supports(identifier))
|
||||
{
|
||||
try{
|
||||
String result = service.lookup(context, dso);
|
||||
if (result != null){
|
||||
return result;
|
||||
}
|
||||
} catch (IdentifierException e) {
|
||||
log.error(e.getMessage(),e);
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public DSpaceObject resolve(Context context, String identifier) throws IdentifierNotFoundException, IdentifierNotResolvableException{
|
||||
for (IdentifierProvider service : providers)
|
||||
{
|
||||
if(service.supports(identifier))
|
||||
{ try
|
||||
{
|
||||
DSpaceObject result = service.resolve(context, identifier);
|
||||
if (result != null)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
} catch (IdentifierException e) {
|
||||
log.error(e.getMessage(),e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void delete(Context context, DSpaceObject dso) throws AuthorizeException, SQLException, IdentifierException {
|
||||
for (IdentifierProvider service : providers)
|
||||
{
|
||||
try
|
||||
{
|
||||
service.delete(context, dso);
|
||||
} catch (IdentifierException e) {
|
||||
log.error(e.getMessage(),e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void delete(Context context, DSpaceObject dso, String identifier) throws AuthorizeException, SQLException, IdentifierException {
|
||||
for (IdentifierProvider service : providers)
|
||||
{
|
||||
try
|
||||
{
|
||||
if(service.supports(identifier))
|
||||
{
|
||||
service.delete(context, dso, identifier);
|
||||
}
|
||||
} catch (IdentifierException e) {
|
||||
log.error(e.getMessage(),e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,689 @@
|
||||
/**
|
||||
* 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.identifier;
|
||||
|
||||
import org.apache.log4j.Logger;
|
||||
import org.dspace.authorize.AuthorizeException;
|
||||
import org.dspace.content.*;
|
||||
import org.dspace.core.ConfigurationManager;
|
||||
import org.dspace.core.Constants;
|
||||
import org.dspace.core.Context;
|
||||
import org.dspace.core.LogManager;
|
||||
import org.dspace.storage.rdbms.DatabaseManager;
|
||||
import org.dspace.storage.rdbms.TableRow;
|
||||
import org.dspace.utils.DSpace;
|
||||
import org.dspace.versioning.*;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @author Fabio Bolognesi (fabio at atmire dot com)
|
||||
* @author Mark Diggory (markd at atmire dot com)
|
||||
* @author Ben Bosman (ben at atmire dot com)
|
||||
*/
|
||||
@Component
|
||||
public class VersionedHandleIdentifierProvider extends IdentifierProvider {
|
||||
/** log4j category */
|
||||
private static Logger log = Logger.getLogger(VersionedHandleIdentifierProvider.class);
|
||||
|
||||
/** Prefix registered to no one */
|
||||
static final String EXAMPLE_PREFIX = "123456789";
|
||||
|
||||
private static final char DOT = '.';
|
||||
|
||||
private String[] supportedPrefixes = new String[]{"info:hdl", "hdl", "http://"};
|
||||
|
||||
private VersionDAO versionDAO;
|
||||
private VersionHistoryDAO versionHistoryDAO;
|
||||
|
||||
@Override
|
||||
public boolean supports(Class<? extends Identifier> identifier)
|
||||
{
|
||||
return Handle.class.isAssignableFrom(identifier);
|
||||
}
|
||||
|
||||
public boolean supports(String identifier)
|
||||
{
|
||||
for(String prefix : supportedPrefixes)
|
||||
{
|
||||
if(identifier.startsWith(prefix))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
String outOfUrl = retrieveHandleOutOfUrl(identifier);
|
||||
if(outOfUrl != null)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
log.error(e.getMessage(), e);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public String register(Context context, DSpaceObject dso)
|
||||
{
|
||||
try
|
||||
{
|
||||
String id = mint(context, dso);
|
||||
|
||||
// move canonical to point the latest version
|
||||
if(dso != null && dso.getType() == Constants.ITEM)
|
||||
{
|
||||
Item item = (Item)dso;
|
||||
VersionHistory history = retrieveVersionHistory(context, (Item)dso);
|
||||
if(history!=null)
|
||||
{
|
||||
String canonical = getCanonical(item);
|
||||
// Modify Canonical: 12345/100 will point to the new item
|
||||
TableRow canonicalRecord = findHandleInternal(context, canonical);
|
||||
modifyHandleRecord(context, dso, canonicalRecord, canonical);
|
||||
|
||||
// in case of first version we have to modify the previous metadata to be xxxx.1
|
||||
Version version = history.getVersion(item);
|
||||
Version previous = history.getPrevious(version);
|
||||
if (history.isFirstVersion(previous))
|
||||
{
|
||||
modifyHandleMetadata(previous.getItem(), (canonical + DOT + 1));
|
||||
}
|
||||
// Check if our previous item hasn't got a handle anymore.
|
||||
// This only occurs when a switch has been made from the standard handle identifier provider
|
||||
// to the versioned one, in this case no "versioned handle" is reserved so we need to create one
|
||||
if(previous != null && getHandleInternal(context, Constants.ITEM, previous.getItemID()) == null){
|
||||
makeIdentifierBasedOnHistory(context, previous.getItem(), canonical, history);
|
||||
|
||||
}
|
||||
}
|
||||
populateHandleMetadata(item);
|
||||
}
|
||||
|
||||
return id;
|
||||
}catch (Exception e){
|
||||
log.error(LogManager.getHeader(context, "Error while attempting to create handle", "Item id: " + (dso != null ? dso.getID() : "")), e);
|
||||
throw new RuntimeException("Error while attempting to create identifier for Item id: " + (dso != null ? dso.getID() : ""));
|
||||
}
|
||||
}
|
||||
|
||||
public void register(Context context, DSpaceObject dso, String identifier)
|
||||
{
|
||||
try
|
||||
{
|
||||
|
||||
Item item = (Item) dso;
|
||||
|
||||
// if for this identifier is already present a record in the Handle table and the corresponding item
|
||||
// has an history someone is trying to restore the latest version for the item. When
|
||||
// trying to restore the latest version the identifier in input doesn't have the for 1234/123.latestVersion
|
||||
// it is the canonical 1234/123
|
||||
VersionHistory itemHistory = getHistory(context, identifier);
|
||||
if(!identifier.matches(".*/.*\\.\\d+") && itemHistory!=null){
|
||||
|
||||
int newVersionNumber = itemHistory.getLatestVersion().getVersionNumber()+1;
|
||||
String canonical = identifier;
|
||||
identifier = identifier.concat(".").concat("" + newVersionNumber);
|
||||
restoreItAsVersion(context, dso, identifier, item, canonical, itemHistory);
|
||||
}
|
||||
// if identifier == 1234.5/100.4 reinstate the version 4 in the version table if absent
|
||||
else if(identifier.matches(".*/.*\\.\\d+"))
|
||||
{
|
||||
// if it is a version of an item is needed to put back the record
|
||||
// in the versionitem table
|
||||
String canonical = getCanonical(identifier);
|
||||
DSpaceObject canonicalItem = this.resolve(context, canonical);
|
||||
if(canonicalItem==null){
|
||||
restoreItAsCanonical(context, dso, identifier, item, canonical);
|
||||
}
|
||||
else{
|
||||
VersionHistory history = retrieveVersionHistory(context, (Item)canonicalItem);
|
||||
if(history==null){
|
||||
restoreItAsCanonical(context, dso, identifier, item, canonical);
|
||||
}
|
||||
else
|
||||
{
|
||||
restoreItAsVersion(context, dso, identifier, item, canonical, history);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//A regular handle
|
||||
createNewIdentifier(context, dso, identifier);
|
||||
if(dso instanceof Item)
|
||||
{
|
||||
populateHandleMetadata(item);
|
||||
}
|
||||
}
|
||||
}catch (Exception e){
|
||||
log.error(LogManager.getHeader(context, "Error while attempting to create handle", "Item id: " + dso.getID()), e);
|
||||
throw new RuntimeException("Error while attempting to create identifier for Item id: " + dso.getID(), e);
|
||||
}
|
||||
}
|
||||
|
||||
private VersionHistory getHistory(Context context, String identifier)
|
||||
{
|
||||
DSpaceObject item = this.resolve(context, identifier);
|
||||
if(item!=null){
|
||||
VersionHistory history = retrieveVersionHistory(context, (Item)item);
|
||||
return history;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private void restoreItAsVersion(Context context, DSpaceObject dso, String identifier, Item item, String canonical, VersionHistory history) throws SQLException, IOException, AuthorizeException
|
||||
{
|
||||
createNewIdentifier(context, dso, identifier);
|
||||
populateHandleMetadata(item);
|
||||
|
||||
int versionNumber = Integer.parseInt(identifier.substring(identifier.lastIndexOf(".") + 1));
|
||||
createVersion(context, history, item, "Restoring from AIP Service", new Date(), versionNumber);
|
||||
Version latest = history.getLatestVersion();
|
||||
|
||||
|
||||
// if restoring the lastest version: needed to move the canonical
|
||||
if(latest.getVersionNumber() < versionNumber){
|
||||
TableRow canonicalRecord = findHandleInternal(context, canonical);
|
||||
modifyHandleRecord(context, dso, canonicalRecord, canonical);
|
||||
}
|
||||
}
|
||||
|
||||
private void restoreItAsCanonical(Context context, DSpaceObject dso, String identifier, Item item, String canonical) throws SQLException, IOException, AuthorizeException
|
||||
{
|
||||
createNewIdentifier(context, dso, identifier);
|
||||
populateHandleMetadata(item);
|
||||
|
||||
int versionNumber = Integer.parseInt(identifier.substring(identifier.lastIndexOf(".")+1));
|
||||
VersionHistory history=versionHistoryDAO.create(context);
|
||||
createVersion(context, history, item, "Restoring from AIP Service", new Date(), versionNumber);
|
||||
|
||||
TableRow canonicalRecord = findHandleInternal(context, canonical);
|
||||
modifyHandleRecord(context, dso, canonicalRecord, canonical);
|
||||
|
||||
}
|
||||
|
||||
|
||||
public void reserve(Context context, DSpaceObject dso, String identifier)
|
||||
{
|
||||
try{
|
||||
TableRow handle = DatabaseManager.create(context, "Handle");
|
||||
modifyHandleRecord(context, dso, handle, identifier);
|
||||
}catch(Exception e){
|
||||
log.error(LogManager.getHeader(context, "Error while attempting to create handle", "Item id: " + dso.getID()), e);
|
||||
throw new RuntimeException("Error while attempting to create identifier for Item id: " + dso.getID());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Creates a new handle in the database.
|
||||
*
|
||||
* @param context DSpace context
|
||||
* @param dso The DSpaceObject to create a handle for
|
||||
* @return The newly created handle
|
||||
*/
|
||||
public String mint(Context context, DSpaceObject dso)
|
||||
{
|
||||
if(dso.getHandle() != null)
|
||||
{
|
||||
return dso.getHandle();
|
||||
}
|
||||
|
||||
try{
|
||||
String handleId = null;
|
||||
VersionHistory history = null;
|
||||
if(dso instanceof Item)
|
||||
{
|
||||
history = retrieveVersionHistory(context, (Item)dso);
|
||||
}
|
||||
|
||||
if(history!=null)
|
||||
{
|
||||
handleId = makeIdentifierBasedOnHistory(context, dso, handleId, history);
|
||||
}else{
|
||||
handleId = createNewIdentifier(context, dso, null);
|
||||
}
|
||||
return handleId;
|
||||
}catch (Exception e){
|
||||
log.error(LogManager.getHeader(context, "Error while attempting to create handle", "Item id: " + dso.getID()), e);
|
||||
throw new RuntimeException("Error while attempting to create identifier for Item id: " + dso.getID());
|
||||
}
|
||||
}
|
||||
|
||||
public DSpaceObject resolve(Context context, String identifier, String... attributes)
|
||||
{
|
||||
// We can do nothing with this, return null
|
||||
try{
|
||||
TableRow dbhandle = findHandleInternal(context, identifier);
|
||||
|
||||
if (dbhandle == null)
|
||||
{
|
||||
//Check for an url
|
||||
identifier = retrieveHandleOutOfUrl(identifier);
|
||||
if(identifier != null)
|
||||
{
|
||||
dbhandle = findHandleInternal(context, identifier);
|
||||
}
|
||||
|
||||
if(dbhandle == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
if ((dbhandle.isColumnNull("resource_type_id"))
|
||||
|| (dbhandle.isColumnNull("resource_id")))
|
||||
{
|
||||
throw new IllegalStateException("No associated resource type");
|
||||
}
|
||||
|
||||
// What are we looking at here?
|
||||
int handletypeid = dbhandle.getIntColumn("resource_type_id");
|
||||
int resourceID = dbhandle.getIntColumn("resource_id");
|
||||
|
||||
if (handletypeid == Constants.ITEM)
|
||||
{
|
||||
Item item = Item.find(context, resourceID);
|
||||
|
||||
if (log.isDebugEnabled())
|
||||
{
|
||||
log.debug("Resolved handle " + identifier + " to item "
|
||||
+ ((item == null) ? (-1) : item.getID()));
|
||||
}
|
||||
|
||||
return item;
|
||||
}
|
||||
else if (handletypeid == Constants.COLLECTION)
|
||||
{
|
||||
Collection collection = Collection.find(context, resourceID);
|
||||
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Resolved handle " + identifier + " to collection "
|
||||
+ ((collection == null) ? (-1) : collection.getID()));
|
||||
}
|
||||
|
||||
return collection;
|
||||
}
|
||||
else if (handletypeid == Constants.COMMUNITY)
|
||||
{
|
||||
Community community = Community.find(context, resourceID);
|
||||
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Resolved handle " + identifier + " to community "
|
||||
+ ((community == null) ? (-1) : community.getID()));
|
||||
}
|
||||
|
||||
return community;
|
||||
}
|
||||
|
||||
|
||||
}catch (Exception e){
|
||||
log.error(LogManager.getHeader(context, "Error while resolving handle to item", "handle: " + identifier), e);
|
||||
}
|
||||
// throw new IllegalStateException("Unsupported Handle Type "
|
||||
// + Constants.typeText[handletypeid]);
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String lookup(Context context, DSpaceObject dso) throws IdentifierNotFoundException, IdentifierNotResolvableException {
|
||||
|
||||
try
|
||||
{
|
||||
TableRow row = getHandleInternal(context, dso.getType(), dso.getID());
|
||||
if (row == null)
|
||||
{
|
||||
if (dso.getType() == Constants.SITE)
|
||||
{
|
||||
return Site.getSiteHandle();
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return row.getStringColumn("handle");
|
||||
}
|
||||
}catch(SQLException sqe){
|
||||
throw new IdentifierNotResolvableException(sqe.getMessage(),sqe);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void delete(Context context, DSpaceObject dso, String identifier) throws IdentifierException {
|
||||
delete(context, dso);
|
||||
}
|
||||
|
||||
public void delete(Context context, DSpaceObject dso) throws IdentifierException {
|
||||
|
||||
try {
|
||||
if (dso instanceof Item)
|
||||
{
|
||||
Item item = (Item) dso;
|
||||
|
||||
// If it is the most current version occurs to move the canonical to the previous version
|
||||
VersionHistory history = retrieveVersionHistory(context, item);
|
||||
if(history!=null && history.getLatestVersion().getItem().equals(item) && history.size() > 1)
|
||||
{
|
||||
Item previous = history.getPrevious(history.getLatestVersion()).getItem();
|
||||
|
||||
// Modify Canonical: 12345/100 will point to the new item
|
||||
String canonical = getCanonical(previous);
|
||||
TableRow canonicalRecord = findHandleInternal(context, canonical);
|
||||
modifyHandleRecord(context, previous, canonicalRecord, canonical);
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error(LogManager.getHeader(context, "Error while attempting to register doi", "Item id: " + dso.getID()), e);
|
||||
throw new IdentifierException("Error while moving doi identifier", e);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
public static String retrieveHandleOutOfUrl(String url) throws SQLException
|
||||
{
|
||||
// We can do nothing with this, return null
|
||||
if (!url.contains("/")) return null;
|
||||
|
||||
String[] splitUrl = url.split("/");
|
||||
|
||||
return splitUrl[splitUrl.length - 2] + "/" + splitUrl[splitUrl.length - 1];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the configured Handle prefix string, or a default
|
||||
* @return configured prefix or "123456789"
|
||||
*/
|
||||
public static String getPrefix()
|
||||
{
|
||||
String prefix = ConfigurationManager.getProperty("handle.prefix");
|
||||
if (null == prefix)
|
||||
{
|
||||
prefix = EXAMPLE_PREFIX; // XXX no good way to exit cleanly
|
||||
log.error("handle.prefix is not configured; using " + prefix);
|
||||
}
|
||||
return prefix;
|
||||
}
|
||||
|
||||
protected static String getCanonicalForm(String handle)
|
||||
{
|
||||
|
||||
// Let the admin define a new prefix, if not then we'll use the
|
||||
// CNRI default. This allows the admin to use "hdl:" if they want to or
|
||||
// use a locally branded prefix handle.myuni.edu.
|
||||
String handlePrefix = ConfigurationManager.getProperty("handle.canonical.prefix");
|
||||
if (handlePrefix == null || handlePrefix.length() == 0)
|
||||
{
|
||||
handlePrefix = "http://hdl.handle.net/";
|
||||
}
|
||||
|
||||
return handlePrefix + handle;
|
||||
}
|
||||
|
||||
protected String createNewIdentifier(Context context, DSpaceObject dso, String handleId) throws SQLException {
|
||||
TableRow handle=null;
|
||||
if(handleId != null)
|
||||
{
|
||||
handle = findHandleInternal(context, handleId);
|
||||
|
||||
|
||||
if(handle!=null && !handle.isColumnNull("resource_id"))
|
||||
{
|
||||
//Check if this handle is already linked up to this specified DSpace Object
|
||||
int resourceID = handle.getIntColumn("resource_id");
|
||||
int resourceType = handle.getIntColumn("resource_type_id");
|
||||
|
||||
if(resourceID==dso.getID() && resourceType ==dso.getType())
|
||||
{
|
||||
//This handle already links to this DSpace Object -- so, there's nothing else we need to do
|
||||
return handleId;
|
||||
}
|
||||
else
|
||||
{
|
||||
//handle found in DB table & already in use by another existing resource
|
||||
throw new IllegalStateException("Attempted to create a handle which is already in use: " + handleId);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
else if(handle!=null && !handle.isColumnNull("resource_type_id"))
|
||||
{
|
||||
//If there is a 'resource_type_id' (but 'resource_id' is empty), then the object using
|
||||
// this handle was previously unbound (see unbindHandle() method) -- likely because object was deleted
|
||||
int previousType = handle.getIntColumn("resource_type_id");
|
||||
|
||||
//Since we are restoring an object to a pre-existing handle, double check we are restoring the same *type* of object
|
||||
// (e.g. we will not allow an Item to be restored to a handle previously used by a Collection)
|
||||
if(previousType != dso.getType())
|
||||
{
|
||||
throw new IllegalStateException("Attempted to reuse a handle previously used by a " +
|
||||
Constants.typeText[previousType] + " for a new " +
|
||||
Constants.typeText[dso.getType()]);
|
||||
}
|
||||
}
|
||||
|
||||
if(handle==null){
|
||||
handle = DatabaseManager.create(context, "Handle");
|
||||
handleId = createId(handle.getIntColumn("handle_id"));
|
||||
}
|
||||
|
||||
modifyHandleRecord(context, dso, handle, handleId);
|
||||
return handleId;
|
||||
}
|
||||
|
||||
protected String makeIdentifierBasedOnHistory(Context context, DSpaceObject dso, String handleId, VersionHistory history) throws AuthorizeException, SQLException
|
||||
{
|
||||
Item item = (Item)dso;
|
||||
|
||||
// FIRST time a VERSION is created 2 identifiers will be minted and the canonical will be updated to point to the newer URL:
|
||||
// - id.1-->old URL
|
||||
// - id.2-->new URL
|
||||
Version version = history.getVersion(item);
|
||||
Version previous = history.getPrevious(version);
|
||||
String canonical = getCanonical(previous.getItem());
|
||||
if (history.isFirstVersion(previous))
|
||||
{
|
||||
// add a new Identifier for previous item: 12345/100.1
|
||||
String identifierPreviousItem=canonical + DOT + 1;
|
||||
TableRow handle = DatabaseManager.create(context, "Handle");
|
||||
modifyHandleRecord(context, previous.getItem(), handle, identifierPreviousItem);
|
||||
}
|
||||
|
||||
|
||||
// add a new Identifier for this item: 12345/100.x
|
||||
String idNew = canonical + DOT + version.getVersionNumber();
|
||||
TableRow handle = DatabaseManager.create(context, "Handle");
|
||||
modifyHandleRecord(context, dso, handle, idNew);
|
||||
|
||||
return handleId;
|
||||
}
|
||||
|
||||
|
||||
protected String modifyHandleRecord(Context context, DSpaceObject dso, TableRow handle, String handleId) throws SQLException
|
||||
{
|
||||
handle.setColumn("handle", handleId);
|
||||
handle.setColumn("resource_type_id", dso.getType());
|
||||
handle.setColumn("resource_id", dso.getID());
|
||||
DatabaseManager.update(context, handle);
|
||||
|
||||
if (log.isDebugEnabled())
|
||||
{
|
||||
log.debug("Created new handle for "
|
||||
+ Constants.typeText[dso.getType()] + " " + handleId);
|
||||
}
|
||||
return handleId;
|
||||
}
|
||||
|
||||
protected String getCanonical(Item item)
|
||||
{
|
||||
String canonical = item.getHandle();
|
||||
if( canonical.lastIndexOf(DOT)!=-1)
|
||||
{
|
||||
canonical = canonical.substring(0, canonical.lastIndexOf(DOT));
|
||||
}
|
||||
|
||||
return canonical;
|
||||
}
|
||||
|
||||
protected String getCanonical(String identifier)
|
||||
{
|
||||
String canonical = identifier;
|
||||
if( canonical.lastIndexOf(DOT)!=-1)
|
||||
{
|
||||
canonical = canonical.substring(0, canonical.lastIndexOf(DOT));
|
||||
}
|
||||
|
||||
return canonical;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the database row corresponding to handle.
|
||||
*
|
||||
* @param context DSpace context
|
||||
* @param handle The handle to resolve
|
||||
* @return The database row corresponding to the handle
|
||||
* @exception java.sql.SQLException If a database error occurs
|
||||
*/
|
||||
protected static TableRow findHandleInternal(Context context, String handle)
|
||||
throws SQLException {
|
||||
if (handle == null)
|
||||
{
|
||||
throw new IllegalArgumentException("Handle is null");
|
||||
}
|
||||
|
||||
return DatabaseManager.findByUnique(context, "Handle", "handle", handle);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the handle for an Object, or null if the Object has no handle.
|
||||
*
|
||||
* @param context
|
||||
* DSpace context
|
||||
* @param type
|
||||
* The type of object
|
||||
* @param id
|
||||
* The id of object
|
||||
* @return The handle for object, or null if the object has no handle.
|
||||
* @exception java.sql.SQLException
|
||||
* If a database error occurs
|
||||
*/
|
||||
protected static TableRow getHandleInternal(Context context, int type, int id)
|
||||
throws SQLException
|
||||
{
|
||||
String sql = "SELECT * FROM Handle WHERE resource_type_id = ? AND resource_id = ?";
|
||||
|
||||
return DatabaseManager.querySingleTable(context, "Handle", sql, type, id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new handle id. The implementation uses the PK of the RDBMS
|
||||
* Handle table.
|
||||
*
|
||||
* @return A new handle id
|
||||
* @exception java.sql.SQLException
|
||||
* If a database error occurs
|
||||
*/
|
||||
protected static String createId(int id) throws SQLException
|
||||
{
|
||||
String handlePrefix = getPrefix();
|
||||
|
||||
return handlePrefix + (handlePrefix.endsWith("/") ? "" : "/") + id;
|
||||
}
|
||||
|
||||
|
||||
protected VersionHistory retrieveVersionHistory(Context c, Item item)
|
||||
{
|
||||
VersioningService versioningService = new DSpace().getSingletonService(VersioningService.class);
|
||||
return versioningService.findVersionHistory(c, item.getID());
|
||||
}
|
||||
|
||||
protected void populateHandleMetadata(Item item)
|
||||
throws SQLException, IOException, AuthorizeException
|
||||
{
|
||||
String handleref = getCanonicalForm(getCanonical(item));
|
||||
|
||||
// Add handle as identifier.uri DC value.
|
||||
// First check that identifier doesn't already exist.
|
||||
boolean identifierExists = false;
|
||||
DCValue[] identifiers = item.getDC("identifier", "uri", Item.ANY);
|
||||
for (DCValue identifier : identifiers)
|
||||
{
|
||||
if (handleref.equals(identifier.value))
|
||||
{
|
||||
identifierExists = true;
|
||||
}
|
||||
}
|
||||
if (!identifierExists)
|
||||
{
|
||||
item.addDC("identifier", "uri", null, handleref);
|
||||
}
|
||||
}
|
||||
|
||||
protected void modifyHandleMetadata(Item item, String handle)
|
||||
throws SQLException, IOException, AuthorizeException
|
||||
{
|
||||
String handleref = getCanonicalForm(handle);
|
||||
item.clearMetadata("dc", "identifier", "uri", Item.ANY);
|
||||
item.addDC("identifier", "uri", null, handleref);
|
||||
item.update();
|
||||
}
|
||||
|
||||
|
||||
protected VersionImpl createVersion(Context c, VersionHistory vh, Item item, String summary, Date date, int versionNumber) {
|
||||
try {
|
||||
VersionImpl version = versionDAO.create(c);
|
||||
|
||||
// check if an equals versionNumber is already present in the DB (at this point it should never happen).
|
||||
if(vh!=null && vh.getVersions()!=null){
|
||||
for(Version v : vh.getVersions()){
|
||||
if(v.getVersionNumber()==versionNumber){
|
||||
throw new RuntimeException("A Version for this versionNumber is already present. Impossible complete the operation.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
version.setVersionNumber(versionNumber);
|
||||
version.setVersionDate(date);
|
||||
version.setEperson(item.getSubmitter());
|
||||
version.setItemID(item.getID());
|
||||
version.setSummary(summary);
|
||||
version.setVersionHistory(vh.getVersionHistoryId());
|
||||
versionDAO.update(version);
|
||||
return version;
|
||||
} catch (SQLException e) {
|
||||
throw new RuntimeException(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
protected int getNextVersionNumer(Version latest){
|
||||
if(latest==null) return 1;
|
||||
|
||||
return latest.getVersionNumber()+1;
|
||||
}
|
||||
|
||||
public void setVersionDAO(VersionDAO versionDAO)
|
||||
{
|
||||
this.versionDAO = versionDAO;
|
||||
}
|
||||
|
||||
public void setVersionHistoryDAO(VersionHistoryDAO versionHistoryDAO)
|
||||
{
|
||||
this.versionHistoryDAO = versionHistoryDAO;
|
||||
}
|
||||
}
|
@@ -637,32 +637,38 @@ public class BitstreamStorageManager
|
||||
continue; // do not delete registered bitstreams
|
||||
}
|
||||
|
||||
boolean success = file.delete();
|
||||
|
||||
String message = ("Deleted bitstream " + bid + " (file "
|
||||
+ file.getAbsolutePath() + ") with result "
|
||||
+ success);
|
||||
if (log.isDebugEnabled())
|
||||
// Since versioning allows for multiple bitstreams, check if the internal identifier isn't used on another place
|
||||
TableRow duplicateBitRow = DatabaseManager.querySingleTable(context, "Bitstream", "SELECT * FROM Bitstream WHERE internal_id = ? AND bitstream_id <> ?", row.getStringColumn("internal_id"), bid);
|
||||
if(duplicateBitRow == null)
|
||||
{
|
||||
log.debug(message);
|
||||
}
|
||||
if (verbose)
|
||||
{
|
||||
System.out.println(message);
|
||||
boolean success = file.delete();
|
||||
|
||||
String message = ("Deleted bitstream " + bid + " (file "
|
||||
+ file.getAbsolutePath() + ") with result "
|
||||
+ success);
|
||||
if (log.isDebugEnabled())
|
||||
{
|
||||
log.debug(message);
|
||||
}
|
||||
if (verbose)
|
||||
{
|
||||
System.out.println(message);
|
||||
}
|
||||
|
||||
// if the file was deleted then
|
||||
// try deleting the parents
|
||||
// Otherwise the cleanup script is set to
|
||||
// leave the db records then the file
|
||||
// and directories have already been deleted
|
||||
// if this is turned off then it still looks like the
|
||||
// file exists
|
||||
if( success )
|
||||
{
|
||||
deleteParents(file);
|
||||
}
|
||||
}
|
||||
|
||||
// if the file was deleted then
|
||||
// try deleting the parents
|
||||
// Otherwise the cleanup script is set to
|
||||
// leave the db records then the file
|
||||
// and directories have already been deleted
|
||||
// if this is turned off then it still looks like the
|
||||
// file exists
|
||||
if( success )
|
||||
{
|
||||
deleteParents(file);
|
||||
}
|
||||
|
||||
// Make sure to commit our outstanding work every 100
|
||||
// iterations. Otherwise you risk losing the entire transaction
|
||||
// if we hit an exception, which isn't useful at all for large
|
||||
@@ -701,6 +707,22 @@ public class BitstreamStorageManager
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param context
|
||||
* @param id of the bitstream to clone
|
||||
* @return
|
||||
* @throws SQLException
|
||||
*/
|
||||
public static int clone(Context context, int id) throws SQLException
|
||||
{
|
||||
TableRow row = DatabaseManager.find(context, "bitstream", id);
|
||||
row.setColumn("bitstream_id", -1);
|
||||
DatabaseManager.insert(context, row);
|
||||
return row.getIntColumn("bitstream_id");
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////
|
||||
// Internal methods
|
||||
////////////////////////////////////////
|
||||
|
@@ -0,0 +1,70 @@
|
||||
/**
|
||||
* 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.versioning;
|
||||
|
||||
import org.dspace.authorize.AuthorizeException;
|
||||
import org.dspace.content.*;
|
||||
import org.dspace.core.Context;
|
||||
import org.dspace.storage.bitstore.BitstreamStorageManager;
|
||||
|
||||
import java.sql.SQLException;
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @author Fabio Bolognesi (fabio at atmire dot com)
|
||||
* @author Mark Diggory (markd at atmire dot com)
|
||||
* @author Ben Bosman (ben at atmire dot com)
|
||||
*/
|
||||
public abstract class AbstractVersionProvider {
|
||||
|
||||
|
||||
protected void copyMetadata(Item itemNew, Item nativeItem){
|
||||
DCValue[] md = nativeItem.getMetadata(Item.ANY, Item.ANY, Item.ANY, Item.ANY);
|
||||
for (DCValue aMd : md) {
|
||||
if ((aMd.schema.equals(MetadataSchema.DC_SCHEMA) && aMd.element.equals("relation") && (aMd.qualifier != null && aMd.qualifier.equals("haspart")))
|
||||
|| (aMd.schema.equals(MetadataSchema.DC_SCHEMA) && aMd.element.equals("relation") && (aMd.qualifier != null && aMd.qualifier.equals("ispartof")))
|
||||
|| (aMd.schema.equals(MetadataSchema.DC_SCHEMA) && aMd.element.equals("identifier"))
|
||||
|| (aMd.schema.equals(MetadataSchema.DC_SCHEMA) && aMd.element.equals("relation") && (aMd.qualifier != null && aMd.qualifier.equals("isversionof")))
|
||||
|| (aMd.schema.equals(MetadataSchema.DC_SCHEMA) && aMd.element.equals("date") && (aMd.qualifier != null && aMd.qualifier.equals("accessioned")))
|
||||
|| (aMd.schema.equals(MetadataSchema.DC_SCHEMA) && aMd.element.equals("date") && (aMd.qualifier != null && aMd.qualifier.equals("available")))
|
||||
|| (aMd.schema.equals(MetadataSchema.DC_SCHEMA) && aMd.element.equals("description") && (aMd.qualifier != null && aMd.qualifier.equals("provenance"))))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
itemNew.addMetadata(aMd.schema, aMd.element, aMd.qualifier, aMd.language, aMd.value);
|
||||
}
|
||||
}
|
||||
|
||||
protected void createBundlesAndAddBitstreams(Context c, Item itemNew, Item nativeItem) throws SQLException, AuthorizeException {
|
||||
for(Bundle nativeBundle : nativeItem.getBundles())
|
||||
{
|
||||
Bundle bundleNew = itemNew.createBundle(nativeBundle.getName());
|
||||
|
||||
for(Bitstream nativeBitstream : nativeBundle.getBitstreams())
|
||||
{
|
||||
|
||||
Bitstream bitstreamNew = createBitstream(c, nativeBitstream);
|
||||
bundleNew.addBitstream(bitstreamNew);
|
||||
|
||||
if(nativeBundle.getPrimaryBitstreamID() == nativeBitstream.getID())
|
||||
{
|
||||
bundleNew.setPrimaryBitstreamID(bitstreamNew.getID());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected Bitstream createBitstream(Context context, Bitstream nativeBitstream) throws AuthorizeException, SQLException {
|
||||
int idNew = BitstreamStorageManager.clone(context, nativeBitstream.getID());
|
||||
return Bitstream.find(context, idNew);
|
||||
}
|
||||
}
|
@@ -0,0 +1,95 @@
|
||||
/**
|
||||
* 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.versioning;
|
||||
|
||||
import org.dspace.authorize.AuthorizeException;
|
||||
import org.dspace.content.Item;
|
||||
import org.dspace.content.WorkspaceItem;
|
||||
import org.dspace.core.Context;
|
||||
import org.dspace.identifier.IdentifierException;
|
||||
import org.dspace.identifier.IdentifierService;
|
||||
import org.dspace.utils.DSpace;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.sql.SQLException;
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @author Fabio Bolognesi (fabio at atmire dot com)
|
||||
* @author Mark Diggory (markd at atmire dot com)
|
||||
* @author Ben Bosman (ben at atmire dot com)
|
||||
*/
|
||||
public class DefaultItemVersionProvider extends AbstractVersionProvider implements ItemVersionProvider
|
||||
{
|
||||
|
||||
public Item createNewItemAndAddItInWorkspace(Context context, Item nativeItem) {
|
||||
try
|
||||
{
|
||||
WorkspaceItem workspaceItem = WorkspaceItem.create(context, nativeItem.getOwningCollection(), false);
|
||||
Item itemNew = workspaceItem.getItem();
|
||||
itemNew.update();
|
||||
return itemNew;
|
||||
}catch (SQLException e) {
|
||||
throw new RuntimeException(e.getMessage(), e);
|
||||
}catch (AuthorizeException e) {
|
||||
throw new RuntimeException(e.getMessage(), e);
|
||||
}catch (IOException e) {
|
||||
throw new RuntimeException(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
public void deleteVersionedItem(Context c, Version versionToDelete, VersionHistory history)
|
||||
{
|
||||
try
|
||||
{
|
||||
// if versionToDelete is the current version we have to reinstate the previous version
|
||||
// and reset canonical
|
||||
if(history.isLastVersion(versionToDelete) && history.size() > 1)
|
||||
{
|
||||
// reset the previous version to archived
|
||||
Item item = history.getPrevious(versionToDelete).getItem();
|
||||
item.setArchived(true);
|
||||
item.update();
|
||||
}
|
||||
|
||||
// assign tombstone to the Identifier and reset canonical to the previous version only if there is a previous version
|
||||
IdentifierService identifierService = new DSpace().getSingletonService(IdentifierService.class);
|
||||
Item itemToDelete=versionToDelete.getItem();
|
||||
identifierService.delete(c, itemToDelete);
|
||||
} catch (SQLException e) {
|
||||
throw new RuntimeException(e.getMessage(), e);
|
||||
} catch (AuthorizeException e) {
|
||||
throw new RuntimeException(e.getMessage(), e);
|
||||
} catch (IdentifierException e) {
|
||||
throw new RuntimeException(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
public Item updateItemState(Context c, Item itemNew, Item previousItem)
|
||||
{
|
||||
try
|
||||
{
|
||||
copyMetadata(itemNew, previousItem);
|
||||
createBundlesAndAddBitstreams(c, itemNew, previousItem);
|
||||
IdentifierService identifierService = new DSpace().getSingletonService(IdentifierService.class);
|
||||
try
|
||||
{
|
||||
identifierService.reserve(c, itemNew);
|
||||
} catch (IdentifierException e) {
|
||||
throw new RuntimeException("Can't create Identifier!");
|
||||
}
|
||||
itemNew.update();
|
||||
return itemNew;
|
||||
}catch (SQLException e) {
|
||||
throw new RuntimeException(e.getMessage(), e);
|
||||
} catch (AuthorizeException e) {
|
||||
throw new RuntimeException(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,24 @@
|
||||
/**
|
||||
* 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.versioning;
|
||||
|
||||
import org.dspace.content.Item;
|
||||
import org.dspace.core.Context;
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @author Fabio Bolognesi (fabio at atmire dot com)
|
||||
* @author Mark Diggory (markd at atmire dot com)
|
||||
* @author Ben Bosman (ben at atmire dot com)
|
||||
*/
|
||||
public interface ItemVersionProvider {
|
||||
public Item createNewItemAndAddItInWorkspace(Context c, Item item);
|
||||
public void deleteVersionedItem(Context c, Version versionToDelete, VersionHistory history);
|
||||
public Item updateItemState(Context c, Item itemNew, Item previousItem);
|
||||
}
|
33
dspace-api/src/main/java/org/dspace/versioning/Version.java
Normal file
33
dspace-api/src/main/java/org/dspace/versioning/Version.java
Normal file
@@ -0,0 +1,33 @@
|
||||
/**
|
||||
* 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.versioning;
|
||||
|
||||
import org.dspace.content.Item;
|
||||
import org.dspace.eperson.EPerson;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @author Fabio Bolognesi (fabio at atmire dot com)
|
||||
* @author Mark Diggory (markd at atmire dot com)
|
||||
* @author Ben Bosman (ben at atmire dot com)
|
||||
*/
|
||||
public interface Version
|
||||
{
|
||||
public EPerson getEperson();
|
||||
public int getItemID();
|
||||
public Date getVersionDate();
|
||||
public int getVersionNumber();
|
||||
public String getSummary();
|
||||
public int getVersionHistoryID();
|
||||
public int getVersionId();
|
||||
public Item getItem();
|
||||
}
|
||||
|
169
dspace-api/src/main/java/org/dspace/versioning/VersionDAO.java
Normal file
169
dspace-api/src/main/java/org/dspace/versioning/VersionDAO.java
Normal file
@@ -0,0 +1,169 @@
|
||||
/**
|
||||
* 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.versioning;
|
||||
|
||||
import org.dspace.content.Item;
|
||||
import org.dspace.core.Context;
|
||||
import org.dspace.storage.rdbms.DatabaseManager;
|
||||
import org.dspace.storage.rdbms.TableRow;
|
||||
import org.dspace.storage.rdbms.TableRowIterator;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @author Fabio Bolognesi (fabio at atmire dot com)
|
||||
* @author Mark Diggory (markd at atmire dot com)
|
||||
* @author Ben Bosman (ben at atmire dot com)
|
||||
*/
|
||||
public class VersionDAO
|
||||
{
|
||||
|
||||
protected final static String TABLE_NAME = "versionitem";
|
||||
protected final static String VERSION_ID = "versionitem_id";
|
||||
protected final static String ITEM_ID = "item_id";
|
||||
protected final static String VERSION_NUMBER = "version_number";
|
||||
protected final static String EPERSON_ID = "eperson_id";
|
||||
protected final static String VERSION_DATE = "version_date";
|
||||
protected final static String VERSION_SUMMARY = "version_summary";
|
||||
protected final static String HISTORY_ID = "versionhistory_id";
|
||||
|
||||
|
||||
public VersionImpl find(Context context, int id) {
|
||||
try
|
||||
{
|
||||
TableRow row = DatabaseManager.findByUnique(context, TABLE_NAME, VERSION_ID, id);
|
||||
|
||||
if (row == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return new VersionImpl(context, row);
|
||||
} catch (SQLException e) {
|
||||
throw new RuntimeException(e.getMessage(), e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public VersionImpl findByItem(Context c, Item item) {
|
||||
return findByItemId(c, item.getID());
|
||||
}
|
||||
|
||||
public VersionImpl findByItemId(Context context, int itemId) {
|
||||
try {
|
||||
if (itemId == 0 || itemId == -1)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
VersionImpl fromCache = (VersionImpl) context.fromCache(VersionImpl.class, itemId);
|
||||
if (fromCache != null)
|
||||
{
|
||||
return fromCache;
|
||||
}
|
||||
|
||||
TableRow row = DatabaseManager.findByUnique(context, TABLE_NAME, ITEM_ID, itemId);
|
||||
if (row == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return new VersionImpl(context, row);
|
||||
} catch (SQLException e) {
|
||||
throw new RuntimeException(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public List<Version> findByVersionHistory(Context context, int versionHistoryId) {
|
||||
TableRowIterator tri = null;
|
||||
try {
|
||||
tri = DatabaseManager.query(context, "SELECT * FROM " + TABLE_NAME + " where " + HISTORY_ID + "=" + versionHistoryId + " order by " + VERSION_NUMBER + " desc");
|
||||
|
||||
List<Version> versions = new ArrayList<Version>();
|
||||
while (tri.hasNext())
|
||||
{
|
||||
TableRow tr = tri.next();
|
||||
|
||||
VersionImpl fromCache = (VersionImpl) context.fromCache(VersionImpl.class, tr.getIntColumn(VERSION_ID));
|
||||
|
||||
if (fromCache != null)
|
||||
{
|
||||
versions.add(fromCache);
|
||||
}else{
|
||||
versions.add(new VersionImpl(context, tr));
|
||||
}
|
||||
}
|
||||
return versions;
|
||||
} catch (SQLException e) {
|
||||
throw new RuntimeException(e.getMessage(), e);
|
||||
} finally {
|
||||
if (tri != null)
|
||||
{
|
||||
tri.close();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
public VersionImpl create(Context context) {
|
||||
try {
|
||||
TableRow row = DatabaseManager.create(context, TABLE_NAME);
|
||||
VersionImpl v = new VersionImpl(context, row);
|
||||
|
||||
//TODO Do I have to manage the event?
|
||||
//context.addEvent(new Event(Event.CREATE, Constants.VERSION, e.getID(), null));
|
||||
|
||||
return v;
|
||||
} catch (SQLException e) {
|
||||
throw new RuntimeException(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void delete(Context c, int versionID) {
|
||||
try {
|
||||
//TODO Do I have to manage the event?
|
||||
//context.addEvent(new Event(Event.DELETE, Constants.VERSION, getID(), getEmail()));
|
||||
|
||||
// Remove ourself
|
||||
VersionImpl version = find(c, versionID);
|
||||
if(version!=null){
|
||||
//Remove ourself from our cache first !
|
||||
c.removeCached(version, version.getVersionId());
|
||||
|
||||
DatabaseManager.delete(c, version.getMyRow());
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
throw new RuntimeException(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void update(VersionImpl version) {
|
||||
try {
|
||||
//TODO Do I have to manage the event?
|
||||
DatabaseManager.update(version.getMyContext(), version.getMyRow());
|
||||
|
||||
|
||||
// if (modified)
|
||||
// {
|
||||
// myContext.addEvent(new Event(Event.MODIFY, Constants.EPERSON, getID(), null));
|
||||
// modified = false;
|
||||
// }
|
||||
} catch (SQLException e) {
|
||||
throw new RuntimeException(e.getMessage(), e);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@@ -0,0 +1,36 @@
|
||||
/**
|
||||
* 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.versioning;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @author Fabio Bolognesi (fabio at atmire dot com)
|
||||
* @author Mark Diggory (markd at atmire dot com)
|
||||
* @author Ben Bosman (ben at atmire dot com)
|
||||
*/
|
||||
public interface VersionHistory {
|
||||
|
||||
public Version getLatestVersion();
|
||||
public Version getFirstVersion();
|
||||
public List<Version> getVersions();
|
||||
public int getVersionHistoryId();
|
||||
public Version getPrevious(Version version);
|
||||
public Version getNext(Version version);
|
||||
public boolean hasNext(Version version);
|
||||
public void add(Version version);
|
||||
public Version getVersion(org.dspace.content.Item item);
|
||||
public boolean hasNext(org.dspace.content.Item item);
|
||||
public boolean isFirstVersion(Version version);
|
||||
public boolean isLastVersion(Version version);
|
||||
public void remove(Version version);
|
||||
public boolean isEmpty();
|
||||
public int size();
|
||||
}
|
@@ -0,0 +1,115 @@
|
||||
/**
|
||||
* 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.versioning;
|
||||
|
||||
import org.dspace.core.Context;
|
||||
import org.dspace.storage.rdbms.DatabaseManager;
|
||||
import org.dspace.storage.rdbms.TableRow;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @author Fabio Bolognesi (fabio at atmire dot com)
|
||||
* @author Mark Diggory (markd at atmire dot com)
|
||||
* @author Ben Bosman (ben at atmire dot com)
|
||||
*/
|
||||
public class VersionHistoryDAO
|
||||
{
|
||||
|
||||
protected final static String TABLE_NAME="versionhistory";
|
||||
protected final static String VERSION_HISTORY_ID = "versionhistory_id";
|
||||
|
||||
|
||||
public VersionHistoryImpl create(Context context)
|
||||
{
|
||||
try {
|
||||
TableRow row = DatabaseManager.create(context, TABLE_NAME);
|
||||
VersionHistoryImpl vh = new VersionHistoryImpl(context, row);
|
||||
|
||||
//TODO Do I have to manage the event?
|
||||
//context.addEvent(new Event(Event.CREATE, Constants.EPERSON, e.getID(), null));
|
||||
|
||||
return vh;
|
||||
|
||||
} catch (SQLException e) {
|
||||
throw new RuntimeException(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
public VersionHistoryImpl find(Context context, int itemID, VersionDAO versionDAO)
|
||||
{
|
||||
try {
|
||||
|
||||
Version version = versionDAO.findByItemId(context, itemID);
|
||||
|
||||
if(version==null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
VersionHistoryImpl fromCache = (VersionHistoryImpl) context.fromCache(VersionHistoryImpl.class, version.getVersionHistoryID());
|
||||
if (fromCache != null)
|
||||
{
|
||||
return fromCache;
|
||||
}
|
||||
|
||||
TableRow row = DatabaseManager.find(context, TABLE_NAME, version.getVersionHistoryID());
|
||||
|
||||
VersionHistoryImpl vh = new VersionHistoryImpl(context, row);
|
||||
List<Version> versions= versionDAO.findByVersionHistory(context, vh.getVersionHistoryId());
|
||||
vh.setVersions(versions);
|
||||
return vh;
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e.getMessage(), e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public VersionHistoryImpl findById(Context context, int id, VersionDAO versionDAO)
|
||||
{
|
||||
|
||||
try {
|
||||
TableRow row = DatabaseManager.find(context, TABLE_NAME, id);
|
||||
|
||||
if (row == null) return null;
|
||||
|
||||
VersionHistoryImpl fromCache = (VersionHistoryImpl) context.fromCache(VersionHistoryImpl.class, row.getIntColumn(VERSION_HISTORY_ID));
|
||||
|
||||
if (fromCache != null)
|
||||
{
|
||||
return fromCache;
|
||||
}
|
||||
|
||||
VersionHistoryImpl versionHistoryImpl = new VersionHistoryImpl(context, row);
|
||||
|
||||
List<Version> versions= versionDAO.findByVersionHistory(context, versionHistoryImpl.getVersionHistoryId());
|
||||
versionHistoryImpl.setVersions(versions);
|
||||
return versionHistoryImpl;
|
||||
} catch (SQLException e) {
|
||||
throw new RuntimeException(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void delete(Context c, int versionHistoryID, VersionDAO versionDAO)
|
||||
{
|
||||
try {
|
||||
VersionHistoryImpl history = findById(c, versionHistoryID, versionDAO);
|
||||
DatabaseManager.delete(c, history.getMyRow());
|
||||
} catch (SQLException e) {
|
||||
throw new RuntimeException(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
@@ -0,0 +1,192 @@
|
||||
/**
|
||||
* 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.versioning;
|
||||
|
||||
import org.dspace.content.Item;
|
||||
import org.dspace.core.Context;
|
||||
import org.dspace.storage.rdbms.TableRow;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @author Fabio Bolognesi (fabio at atmire dot com)
|
||||
* @author Mark Diggory (markd at atmire dot com)
|
||||
* @author Ben Bosman (ben at atmire dot com)
|
||||
*/
|
||||
public class VersionHistoryImpl implements VersionHistory
|
||||
{
|
||||
|
||||
private int versionHistoryId;
|
||||
private List<Version>versions;
|
||||
|
||||
private Context myContext;
|
||||
private TableRow myRow;
|
||||
|
||||
|
||||
protected VersionHistoryImpl(VersionHistoryDAO vhDAO){
|
||||
|
||||
}
|
||||
|
||||
|
||||
protected VersionHistoryImpl(Context c, TableRow row)
|
||||
{
|
||||
myContext = c;
|
||||
myRow = row;
|
||||
|
||||
c.cache(this, row.getIntColumn(VersionHistoryDAO.VERSION_HISTORY_ID));
|
||||
}
|
||||
|
||||
public int getVersionHistoryId() {
|
||||
return myRow.getIntColumn(VersionHistoryDAO.VERSION_HISTORY_ID);
|
||||
}
|
||||
|
||||
// LIST order: descending
|
||||
public Version getPrevious(Version version) {
|
||||
int index = versions.indexOf(version);
|
||||
|
||||
if( (index+1)==versions.size()) return null;
|
||||
|
||||
return versions.get(index+1);
|
||||
}
|
||||
|
||||
// LIST order: descending
|
||||
public Version getNext(Version version)
|
||||
{
|
||||
|
||||
int index = versions.indexOf(version);
|
||||
|
||||
if(index==0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return versions.get(index-1);
|
||||
}
|
||||
|
||||
public Version getVersion(Item item) {
|
||||
for(Version v : versions)
|
||||
{
|
||||
if(v.getItem().getID()==item.getID())
|
||||
{
|
||||
return v;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean hasNext(Item item)
|
||||
{
|
||||
Version version = getVersion(item);
|
||||
return hasNext(version);
|
||||
}
|
||||
|
||||
public boolean hasNext(Version version)
|
||||
{
|
||||
return getNext(version)!=null;
|
||||
}
|
||||
|
||||
public List<Version> getVersions()
|
||||
{
|
||||
return versions;
|
||||
}
|
||||
|
||||
public void setVersions(List<Version> versions)
|
||||
{
|
||||
this.versions = versions;
|
||||
}
|
||||
|
||||
public void add(Version version)
|
||||
{
|
||||
if(versions==null) versions=new ArrayList<Version>();
|
||||
versions.add(0, version);
|
||||
}
|
||||
|
||||
public Version getLatestVersion()
|
||||
{
|
||||
if(versions==null || versions.size()==0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return versions.get(0);
|
||||
}
|
||||
|
||||
public Version getFirstVersion()
|
||||
{
|
||||
if(versions==null || versions.size()==0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return versions.get(versions.size()-1);
|
||||
}
|
||||
|
||||
|
||||
public boolean isFirstVersion(Version version)
|
||||
{
|
||||
Version first = versions.get(versions.size()-1);
|
||||
return first.equals(version);
|
||||
}
|
||||
|
||||
public boolean isLastVersion(Version version)
|
||||
{
|
||||
Version last = versions.get(0);
|
||||
return last.equals(version);
|
||||
}
|
||||
|
||||
public void remove(Version version)
|
||||
{
|
||||
versions.remove(version);
|
||||
}
|
||||
|
||||
public boolean isEmpty()
|
||||
{
|
||||
return versions.size()==0;
|
||||
}
|
||||
|
||||
public int size()
|
||||
{
|
||||
return versions.size();
|
||||
}
|
||||
|
||||
protected TableRow getMyRow()
|
||||
{
|
||||
return myRow;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o)
|
||||
{
|
||||
if (this == o)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (o == null || getClass() != o.getClass())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
VersionHistoryImpl that = (VersionHistoryImpl) o;
|
||||
return versionHistoryId == that.versionHistoryId;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode()
|
||||
{
|
||||
int hash=7;
|
||||
hash=79*hash+ (this.getVersionHistoryId() ^ (this.getVersionHistoryId() >>> 32));
|
||||
return hash;
|
||||
}
|
||||
}
|
168
dspace-api/src/main/java/org/dspace/versioning/VersionImpl.java
Normal file
168
dspace-api/src/main/java/org/dspace/versioning/VersionImpl.java
Normal file
@@ -0,0 +1,168 @@
|
||||
/**
|
||||
* 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.versioning;
|
||||
|
||||
import org.dspace.content.Item;
|
||||
import org.dspace.core.Context;
|
||||
import org.dspace.eperson.EPerson;
|
||||
import org.dspace.storage.rdbms.TableRow;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @author Fabio Bolognesi (fabio at atmire dot com)
|
||||
* @author Mark Diggory (markd at atmire dot com)
|
||||
* @author Ben Bosman (ben at atmire dot com)
|
||||
*/
|
||||
public class VersionImpl implements Version {
|
||||
|
||||
private int versionId;
|
||||
private EPerson eperson;
|
||||
private int itemID=-1;
|
||||
|
||||
private Date versionDate;
|
||||
private int versionNumber;
|
||||
private String summary;
|
||||
private int versionHistoryID;
|
||||
private Context myContext;
|
||||
private TableRow myRow;
|
||||
|
||||
protected VersionImpl(Context c, TableRow row)
|
||||
{
|
||||
myContext = c;
|
||||
myRow = row;
|
||||
|
||||
c.cache(this, row.getIntColumn(VersionDAO.VERSION_ID));
|
||||
}
|
||||
|
||||
|
||||
public int getVersionId()
|
||||
{
|
||||
return myRow.getIntColumn(VersionDAO.VERSION_ID);
|
||||
}
|
||||
|
||||
protected void setVersionId(int versionId)
|
||||
{
|
||||
this.versionId = versionId;
|
||||
}
|
||||
|
||||
public EPerson getEperson(){
|
||||
try {
|
||||
if (eperson == null)
|
||||
{
|
||||
return EPerson.find(myContext, myRow.getIntColumn(VersionDAO.EPERSON_ID));
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
throw new RuntimeException(e.getMessage(), e);
|
||||
}
|
||||
return eperson;
|
||||
}
|
||||
|
||||
public void setEperson(EPerson ePerson) {
|
||||
this.eperson = ePerson;
|
||||
myRow.setColumn(VersionDAO.EPERSON_ID, ePerson.getID());
|
||||
}
|
||||
|
||||
public int getItemID() {
|
||||
return myRow.getIntColumn(VersionDAO.ITEM_ID);
|
||||
}
|
||||
|
||||
|
||||
public Item getItem(){
|
||||
try{
|
||||
if(getItemID()==-1)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return Item.find(myContext, getItemID());
|
||||
|
||||
}catch(SQLException e){
|
||||
throw new RuntimeException(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
public void setItemID(int itemID)
|
||||
{
|
||||
this.itemID = itemID;
|
||||
myRow.setColumn(VersionDAO.ITEM_ID, itemID);
|
||||
}
|
||||
|
||||
public Date getVersionDate() {
|
||||
return myRow.getDateColumn(VersionDAO.VERSION_DATE);
|
||||
}
|
||||
|
||||
public void setVersionDate(Date versionDate) {
|
||||
this.versionDate = versionDate;
|
||||
myRow.setColumn(VersionDAO.VERSION_DATE, versionDate);
|
||||
}
|
||||
|
||||
public int getVersionNumber() {
|
||||
return myRow.getIntColumn(VersionDAO.VERSION_NUMBER);
|
||||
}
|
||||
|
||||
public void setVersionNumber(int versionNumber) {
|
||||
this.versionNumber = versionNumber;
|
||||
myRow.setColumn(VersionDAO.VERSION_NUMBER, versionNumber);
|
||||
}
|
||||
|
||||
public String getSummary() {
|
||||
return myRow.getStringColumn(VersionDAO.VERSION_SUMMARY);
|
||||
}
|
||||
|
||||
public void setSummary(String summary) {
|
||||
this.summary = summary;
|
||||
myRow.setColumn(VersionDAO.VERSION_SUMMARY, summary);
|
||||
}
|
||||
|
||||
|
||||
public int getVersionHistoryID() {
|
||||
return myRow.getIntColumn(VersionDAO.HISTORY_ID);
|
||||
}
|
||||
|
||||
public void setVersionHistory(int versionHistoryID) {
|
||||
this.versionHistoryID = versionHistoryID;
|
||||
myRow.setColumn(VersionDAO.HISTORY_ID, versionHistoryID);
|
||||
}
|
||||
|
||||
|
||||
public Context getMyContext(){
|
||||
return myContext;
|
||||
}
|
||||
|
||||
protected TableRow getMyRow(){
|
||||
return myRow;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
VersionImpl version = (VersionImpl) o;
|
||||
|
||||
return getVersionId() == version.getVersionId();
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int hash=7;
|
||||
hash=79*hash+(int) (this.getVersionId() ^ (this.getVersionId() >>> 32));
|
||||
return hash;
|
||||
}
|
||||
}
|
@@ -0,0 +1,86 @@
|
||||
/**
|
||||
* 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.versioning;
|
||||
|
||||
import org.dspace.content.Item;
|
||||
import org.dspace.core.Constants;
|
||||
import org.dspace.core.Context;
|
||||
import org.dspace.event.Consumer;
|
||||
import org.dspace.event.Event;
|
||||
import org.dspace.utils.DSpace;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @author Fabio Bolognesi (fabio at atmire dot com)
|
||||
* @author Mark Diggory (markd at atmire dot com)
|
||||
* @author Ben Bosman (ben at atmire dot com)
|
||||
*/
|
||||
public class VersioningConsumer implements Consumer {
|
||||
|
||||
private static Set<Item> itemsToProcess;
|
||||
|
||||
public void initialize() throws Exception {}
|
||||
|
||||
public void finish(Context ctx) throws Exception {}
|
||||
|
||||
public void consume(Context ctx, Event event) throws Exception {
|
||||
if(itemsToProcess == null){
|
||||
itemsToProcess = new HashSet<Item>();
|
||||
}
|
||||
|
||||
int st = event.getSubjectType();
|
||||
int et = event.getEventType();
|
||||
|
||||
if(st == Constants.ITEM && et == Event.INSTALL){
|
||||
Item item = (Item) event.getSubject(ctx);
|
||||
if (item != null && item.isArchived()) {
|
||||
VersionHistory history = retrieveVersionHistory(ctx, item);
|
||||
if (history != null) {
|
||||
Version latest = history.getLatestVersion();
|
||||
Version previous = history.getPrevious(latest);
|
||||
if(previous != null){
|
||||
Item previousItem = previous.getItem();
|
||||
if(previousItem != null){
|
||||
itemsToProcess.add(previousItem);
|
||||
//Fire a new modify event for our previous item
|
||||
//Due to the need to reindex the item in the search & browse index we need to fire a new event
|
||||
ctx.addEvent(new Event(Event.MODIFY, previousItem.getType(), previousItem.getID(), null));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void end(Context ctx) throws Exception {
|
||||
if(itemsToProcess != null){
|
||||
for(Item item : itemsToProcess){
|
||||
ctx.turnOffAuthorisationSystem();
|
||||
try {
|
||||
item.setArchived(false);
|
||||
item.update();
|
||||
} finally {
|
||||
ctx.restoreAuthSystemState();
|
||||
}
|
||||
}
|
||||
ctx.getDBConnection().commit();
|
||||
}
|
||||
|
||||
itemsToProcess = null;
|
||||
}
|
||||
|
||||
|
||||
private static org.dspace.versioning.VersionHistory retrieveVersionHistory(Context c, Item item) {
|
||||
VersioningService versioningService = new DSpace().getSingletonService(VersioningService.class);
|
||||
return versioningService.findVersionHistory(c, item.getID());
|
||||
}
|
||||
}
|
@@ -0,0 +1,41 @@
|
||||
/**
|
||||
* 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.versioning;
|
||||
|
||||
import org.dspace.content.Item;
|
||||
import org.dspace.core.Context;
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @author Fabio Bolognesi (fabio at atmire dot com)
|
||||
* @author Mark Diggory (markd at atmire dot com)
|
||||
* @author Ben Bosman (ben at atmire dot com)
|
||||
*/
|
||||
public interface VersioningService {
|
||||
|
||||
Version createNewVersion(Context c, int itemId);
|
||||
|
||||
Version createNewVersion(Context c, int itemId, String summary);
|
||||
|
||||
void removeVersion(Context c, int versionID);
|
||||
|
||||
void removeVersion(Context c, Item item);
|
||||
|
||||
Version getVersion(Context c, int versionID);
|
||||
|
||||
Version restoreVersion(Context c, int versionID);
|
||||
|
||||
Version restoreVersion(Context c, int versionID, String summary);
|
||||
|
||||
VersionHistory findVersionHistory(Context c, int itemId);
|
||||
|
||||
Version updateVersion(Context c, int itemId, String summary);
|
||||
|
||||
Version getVersion(Context c, Item item);
|
||||
}
|
@@ -0,0 +1,188 @@
|
||||
/**
|
||||
* 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.versioning;
|
||||
|
||||
import org.dspace.content.Collection;
|
||||
import org.dspace.content.DCDate;
|
||||
import org.dspace.content.DCValue;
|
||||
import org.dspace.content.Item;
|
||||
import org.dspace.core.Context;
|
||||
import org.springframework.beans.factory.annotation.Required;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @author Fabio Bolognesi (fabio at atmire dot com)
|
||||
* @author Mark Diggory (markd at atmire dot com)
|
||||
* @author Ben Bosman (ben at atmire dot com)
|
||||
*/
|
||||
public class VersioningServiceImpl implements VersioningService{
|
||||
|
||||
private VersionHistoryDAO versionHistoryDAO;
|
||||
private VersionDAO versionDAO;
|
||||
private DefaultItemVersionProvider provider;
|
||||
|
||||
|
||||
/** Service Methods */
|
||||
public Version createNewVersion(Context c, int itemId){
|
||||
return createNewVersion(c, itemId, null);
|
||||
}
|
||||
|
||||
public Version createNewVersion(Context c, int itemId, String summary) {
|
||||
try{
|
||||
Item item = Item.find(c, itemId);
|
||||
VersionHistory vh = versionHistoryDAO.find(c, item.getID(), versionDAO);
|
||||
if(vh==null)
|
||||
{
|
||||
// first time: create 2 versions, .1(old version) and .2(new version)
|
||||
vh=versionHistoryDAO.create(c);
|
||||
|
||||
// get dc:date.accessioned to be set as first version date...
|
||||
DCValue[] values = item.getMetadata("dc", "date", "accessioned", Item.ANY);
|
||||
Date versionDate = new Date();
|
||||
if(values!=null && values.length > 0){
|
||||
String date = values[0].value;
|
||||
versionDate = new DCDate(date).toDate();
|
||||
}
|
||||
createVersion(c, vh, item, "", versionDate);
|
||||
}
|
||||
// Create new Item
|
||||
Item itemNew = provider.createNewItemAndAddItInWorkspace(c, item);
|
||||
|
||||
// create new version
|
||||
Version version = createVersion(c, vh, itemNew, summary, new Date());
|
||||
|
||||
// Complete any update of the Item and new Identifier generation that needs to happen
|
||||
provider.updateItemState(c, itemNew, item);
|
||||
|
||||
return version;
|
||||
}catch (Exception e) {
|
||||
throw new RuntimeException(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
public void removeVersion(Context c, int versionID) {
|
||||
Version version = versionDAO.find(c, versionID);
|
||||
if(version!=null){
|
||||
removeVersion(c, version);
|
||||
}
|
||||
}
|
||||
|
||||
public void removeVersion(Context c, Item item) {
|
||||
Version version = versionDAO.findByItem(c, item);
|
||||
if(version!=null){
|
||||
removeVersion(c, version);
|
||||
}
|
||||
}
|
||||
|
||||
protected void removeVersion(Context c, Version version) {
|
||||
try{
|
||||
VersionHistory history = versionHistoryDAO.findById(c, version.getVersionHistoryID(), versionDAO);
|
||||
provider.deleteVersionedItem(c, version, history);
|
||||
versionDAO.delete(c, version.getVersionId());
|
||||
|
||||
history.remove(version);
|
||||
|
||||
if(history.isEmpty()){
|
||||
versionHistoryDAO.delete(c, version.getVersionHistoryID(), versionDAO);
|
||||
}
|
||||
//Delete the item linked to the version
|
||||
Item item = version.getItem();
|
||||
Collection[] collections = item.getCollections();
|
||||
|
||||
// Remove item from all the collections it's in (so our item is also deleted)
|
||||
for (Collection collection : collections)
|
||||
{
|
||||
collection.removeItem(item);
|
||||
}
|
||||
}catch (Exception e) {
|
||||
c.abort();
|
||||
throw new RuntimeException(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
public Version getVersion(Context c, int versionID) {
|
||||
return versionDAO.find(c, versionID);
|
||||
}
|
||||
|
||||
|
||||
public Version restoreVersion(Context c, int versionID){
|
||||
return restoreVersion(c, versionID, null);
|
||||
}
|
||||
|
||||
public Version restoreVersion(Context c, int versionID, String summary) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public VersionHistory findVersionHistory(Context c, int itemId){
|
||||
return versionHistoryDAO.find(c, itemId, versionDAO);
|
||||
}
|
||||
|
||||
public Version updateVersion(Context c, int itemId, String summary) {
|
||||
VersionImpl version = versionDAO.findByItemId(c, itemId);
|
||||
version.setSummary(summary);
|
||||
versionDAO.update(version);
|
||||
return version;
|
||||
}
|
||||
|
||||
public Version getVersion(Context c, Item item){
|
||||
return versionDAO.findByItemId(c, item.getID());
|
||||
}
|
||||
|
||||
// **** PROTECTED METHODS!!
|
||||
|
||||
protected VersionImpl createVersion(Context c, VersionHistory vh, Item item, String summary, Date date) {
|
||||
try {
|
||||
VersionImpl version = versionDAO.create(c);
|
||||
|
||||
version.setVersionNumber(getNextVersionNumer(vh.getLatestVersion()));
|
||||
version.setVersionDate(date);
|
||||
version.setEperson(item.getSubmitter());
|
||||
version.setItemID(item.getID());
|
||||
version.setSummary(summary);
|
||||
version.setVersionHistory(vh.getVersionHistoryId());
|
||||
versionDAO.update(version);
|
||||
vh.add(version);
|
||||
return version;
|
||||
} catch (SQLException e) {
|
||||
throw new RuntimeException(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
protected int getNextVersionNumer(Version latest){
|
||||
if(latest==null) return 1;
|
||||
|
||||
return latest.getVersionNumber()+1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public VersionHistoryDAO getVersionHistoryDAO() {
|
||||
return versionHistoryDAO;
|
||||
}
|
||||
|
||||
public void setVersionHistoryDAO(VersionHistoryDAO versionHistoryDAO) {
|
||||
this.versionHistoryDAO = versionHistoryDAO;
|
||||
}
|
||||
|
||||
public VersionDAO getVersionDAO() {
|
||||
return versionDAO;
|
||||
}
|
||||
|
||||
public void setVersionDAO(VersionDAO versionDAO) {
|
||||
this.versionDAO = versionDAO;
|
||||
}
|
||||
|
||||
@Required
|
||||
public void setProvider(DefaultItemVersionProvider provider) {
|
||||
this.provider = provider;
|
||||
}
|
||||
}
|
@@ -355,7 +355,7 @@ public class WorkflowItem implements InProgressSubmission
|
||||
/**
|
||||
* Update the workflow item, including the unarchived item.
|
||||
*/
|
||||
public void update() throws SQLException, IOException, AuthorizeException
|
||||
public void update() throws SQLException, AuthorizeException
|
||||
{
|
||||
// FIXME check auth
|
||||
log.info(LogManager.getHeader(ourContext, "update_workflow_item",
|
||||
|
@@ -63,7 +63,7 @@ public class XmlWorkflowItem implements InProgressSubmission {
|
||||
*/
|
||||
// private ArrayList<StepRecord> activeSteps;
|
||||
|
||||
XmlWorkflowItem(Context context, TableRow row) throws SQLException {
|
||||
XmlWorkflowItem(Context context, TableRow row) throws SQLException, AuthorizeException, IOException {
|
||||
ourContext = context;
|
||||
wfRow = row;
|
||||
// activeSteps = new ArrayList<StepRecord>();
|
||||
@@ -360,35 +360,36 @@ public class XmlWorkflowItem implements InProgressSubmission {
|
||||
|
||||
/**
|
||||
* Check to see if a particular item is currently under Workflow.
|
||||
* If so, its XmlWorkflowItem is returned. If not, null is returned
|
||||
* If so, its WorkflowItem is returned. If not, null is returned
|
||||
*
|
||||
* @param context
|
||||
* the context object
|
||||
* @param i
|
||||
* @param item
|
||||
* the item
|
||||
*
|
||||
* @return XmlWorkflow item corresponding to the item, or null
|
||||
* @return workflow item corresponding to the item, or null
|
||||
*/
|
||||
public static XmlWorkflowItem findByItem(Context context, Item i)
|
||||
throws SQLException
|
||||
{
|
||||
// Look for the unique workflowitem entry where 'item_id' references this item
|
||||
TableRow row = DatabaseManager.findByUnique(context, "cwf_workflowitem", "item_id", i.getID());
|
||||
public static XmlWorkflowItem findByItem(Context context, Item item) throws SQLException {
|
||||
TableRow row = DatabaseManager.findByUnique(context, "cwf_workflowitem", "item_id", item.getID());
|
||||
|
||||
if (row == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
else
|
||||
{
|
||||
return new XmlWorkflowItem(context, row);
|
||||
XmlWorkflowItem wi = null;
|
||||
if(row != null){
|
||||
// Check the cache
|
||||
wi = (XmlWorkflowItem) context.fromCache(XmlWorkflowItem.class, row.getIntColumn("workflowitem_id"));
|
||||
|
||||
// not in cache? turn row into workflowitem
|
||||
if (wi == null)
|
||||
{
|
||||
wi = new XmlWorkflowItem(context, row);
|
||||
}
|
||||
}
|
||||
return wi;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the workflow item, including the unarchived item.
|
||||
*/
|
||||
public void update() throws SQLException, IOException, AuthorizeException {
|
||||
public void update() throws SQLException, AuthorizeException {
|
||||
// FIXME check auth
|
||||
log.info(LogManager.getHeader(ourContext, "update_workflow_item",
|
||||
"workflowitem_id=" + getID()));
|
||||
|
@@ -0,0 +1,65 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
|
||||
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/
|
||||
|
||||
-->
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans
|
||||
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
|
||||
|
||||
|
||||
<!-- Identifier Service Application Interface. Will be autowired with
|
||||
any Identifier Providers present in Spring context.
|
||||
-->
|
||||
<bean id="org.dspace.identifier.IdentifierService"
|
||||
class="org.dspace.identifier.IdentifierServiceImpl"
|
||||
autowire="byType"
|
||||
scope="singleton"/>
|
||||
|
||||
<!-- provider for exposing default Handle services implementaion. -->
|
||||
<!--bean id="org.dspace.identifier.HandleIdentifierProvider" class="org.dspace.identifier.HandleIdentifierProvider"
|
||||
scope="singleton">
|
||||
<property name="configurationService" ref="org.dspace.services.ConfigurationService"/>
|
||||
</bean-->
|
||||
|
||||
<bean id="org.dspace.identifier.VersionedHandleIdentifierProvider" class="org.dspace.identifier.VersionedHandleIdentifierProvider"
|
||||
scope="singleton">
|
||||
<property name="configurationService" ref="org.dspace.services.ConfigurationService"/>
|
||||
<property name="versionDAO">
|
||||
<bean class="org.dspace.versioning.VersionDAO"/>
|
||||
</property>
|
||||
<property name="versionHistoryDAO">
|
||||
<bean class="org.dspace.versioning.VersionHistoryDAO"/>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
|
||||
<!-- !!!!!!!!!!!!!!!!!!!!! ITEM LEVEL VERSIONING SERVICES !!!!!!!!!!!!!!!!!!!!! -->
|
||||
|
||||
<!-- Versioning Service Application Interface for DSpace Will be autowired with
|
||||
a Versioning Provider present in Spring context.-->
|
||||
<bean id="org.dspace.versioning.VersioningService"
|
||||
class="org.dspace.versioning.VersioningServiceImpl"
|
||||
autowire="byType"
|
||||
scope="singleton">
|
||||
<property name="versionDAO">
|
||||
<bean class="org.dspace.versioning.VersionDAO"/>
|
||||
</property>
|
||||
<property name="versionHistoryDAO">
|
||||
<bean class="org.dspace.versioning.VersionHistoryDAO"/>
|
||||
</property>
|
||||
<property name="provider">
|
||||
<!-- Default Item Versioning Provider, defines behavior for replicating
|
||||
Item, Metadata, BUndles and Bitstreams. Autowired at this time. -->
|
||||
<bean class="org.dspace.versioning.DefaultItemVersionProvider"/>
|
||||
</property>
|
||||
|
||||
</bean>
|
||||
|
||||
</beans>
|
@@ -10,11 +10,8 @@ package org.dspace;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.nio.channels.FileChannel;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Properties;
|
||||
import java.util.TimeZone;
|
||||
@@ -38,6 +35,8 @@ import org.dspace.core.ConfigurationManager;
|
||||
import org.dspace.core.Context;
|
||||
import org.dspace.eperson.EPerson;
|
||||
import org.dspace.search.DSIndexer;
|
||||
import org.dspace.servicemanager.DSpaceKernelImpl;
|
||||
import org.dspace.servicemanager.DSpaceKernelInit;
|
||||
import org.dspace.storage.rdbms.MockDatabaseManager;
|
||||
import org.junit.After;
|
||||
import org.junit.AfterClass;
|
||||
@@ -78,6 +77,7 @@ public class AbstractUnitTest
|
||||
*/
|
||||
protected static EPerson eperson;
|
||||
|
||||
protected static DSpaceKernelImpl kernelImpl;
|
||||
|
||||
/**
|
||||
* This method will be run before the first test as per @BeforeClass. It will
|
||||
@@ -111,6 +111,13 @@ public class AbstractUnitTest
|
||||
//load the test configuration file
|
||||
ConfigurationManager.loadConfig(null);
|
||||
|
||||
// Initialise the service manager kernel
|
||||
kernelImpl = DSpaceKernelInit.getKernel(null);
|
||||
if (!kernelImpl.isRunning())
|
||||
{
|
||||
kernelImpl.start(ConfigurationManager.getProperty("dspace.dir"));
|
||||
}
|
||||
|
||||
// Load the default registries. This assumes the temporary
|
||||
// filesystem is working and the in-memory DB in place.
|
||||
Context ctx = new Context();
|
||||
|
139
dspace-api/src/test/java/org/dspace/content/VersioningTest.java
Normal file
139
dspace-api/src/test/java/org/dspace/content/VersioningTest.java
Normal file
@@ -0,0 +1,139 @@
|
||||
/**
|
||||
* 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;
|
||||
|
||||
import org.apache.log4j.Logger;
|
||||
import org.dspace.AbstractUnitTest;
|
||||
import org.dspace.authorize.AuthorizeException;
|
||||
import org.dspace.handle.HandleManager;
|
||||
import org.dspace.utils.DSpace;
|
||||
import org.dspace.versioning.Version;
|
||||
import org.dspace.versioning.VersionHistory;
|
||||
import org.dspace.versioning.VersioningService;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.sql.SQLException;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.*;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
|
||||
/**
|
||||
* Unit Tests for versioning
|
||||
*
|
||||
* @author Fabio Bolognesi (fabio at atmire dot com)
|
||||
* @author Mark Diggory (markd at atmire dot com)
|
||||
* @author Ben Bosman (ben at atmire dot com)
|
||||
*/
|
||||
public class VersioningTest extends AbstractUnitTest {
|
||||
|
||||
private static final Logger log = Logger.getLogger(VersioningTest.class);
|
||||
|
||||
private Item originalItem;
|
||||
private Item versionedItem;
|
||||
private String summary = "Unit test version";
|
||||
private DSpace dspace = new DSpace();
|
||||
private VersioningService versioningService = dspace.getSingletonService(VersioningService.class);
|
||||
|
||||
|
||||
/**
|
||||
* This method will be run before every test as per @Before. It will
|
||||
* initialize resources required for the tests.
|
||||
*
|
||||
* Other methods can be annotated with @Before here or in subclasses
|
||||
* but no execution order is guaranteed
|
||||
*/
|
||||
@Before
|
||||
@Override
|
||||
public void init()
|
||||
{
|
||||
super.init();
|
||||
try
|
||||
{
|
||||
context.turnOffAuthorisationSystem();
|
||||
Collection col = Collection.create(context);
|
||||
WorkspaceItem is = WorkspaceItem.create(context, col, false);
|
||||
|
||||
originalItem = InstallItem.installItem(context, is);
|
||||
|
||||
Version version = versioningService.createNewVersion(context, originalItem.getID(), summary);
|
||||
WorkspaceItem wsi = WorkspaceItem.findByItem(context, version.getItem());
|
||||
|
||||
versionedItem = InstallItem.installItem(context, wsi);
|
||||
context.restoreAuthSystemState();
|
||||
context.commit();
|
||||
}
|
||||
catch (AuthorizeException ex)
|
||||
{
|
||||
log.error("Authorization Error in init", ex);
|
||||
fail("Authorization Error in init");
|
||||
}
|
||||
catch (SQLException ex)
|
||||
{
|
||||
log.error("SQL Error in init", ex);
|
||||
fail("SQL Error in init");
|
||||
} catch (IOException ex) {
|
||||
log.error("IO Error in init", ex);
|
||||
fail("IO Error in init");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* This method will be run after every test as per @After. It will
|
||||
* clean resources initialized by the @Before methods.
|
||||
*
|
||||
* Other methods can be annotated with @After here or in subclasses
|
||||
* but no execution order is guaranteed
|
||||
*/
|
||||
@After
|
||||
@Override
|
||||
public void destroy()
|
||||
{
|
||||
super.destroy();
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testVersionFind(){
|
||||
VersionHistory versionHistory = versioningService.findVersionHistory(context, originalItem.getID());
|
||||
assertThat("testFindVersionHistory", versionHistory, notNullValue());
|
||||
Version version = versionHistory.getVersion(versionedItem);
|
||||
assertThat("testFindVersion", version, notNullValue());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test of installItem method, of class InstallItem.
|
||||
*/
|
||||
@Test
|
||||
public void testVersionSummary() throws Exception
|
||||
{
|
||||
//Start by creating a new item !
|
||||
VersionHistory versionHistory = versioningService.findVersionHistory(context, originalItem.getID());
|
||||
Version version = versionHistory.getVersion(versionedItem);
|
||||
assertThat("Test_version_summary", summary, equalTo(version.getSummary()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testVersionHandle() throws Exception {
|
||||
assertThat("Test_version_handle", versionedItem.getHandle(), notNullValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testVersionDelete() throws Exception {
|
||||
context.turnOffAuthorisationSystem();
|
||||
versioningService.removeVersion(context, versionedItem);
|
||||
assertThat("Test_version_delete", Item.find(context, versionedItem.getID()), nullValue());
|
||||
assertThat("Test_version_handle_delete", HandleManager.resolveToObject(context, versionedItem.getHandle()), nullValue());
|
||||
context.restoreAuthSystemState();
|
||||
}
|
||||
}
|
@@ -116,6 +116,8 @@ CREATE SEQUENCE group2group_seq;
|
||||
CREATE SEQUENCE group2groupcache_seq;
|
||||
CREATE SEQUENCE harvested_collection_seq;
|
||||
CREATE SEQUENCE harvested_item_seq;
|
||||
CREATE SEQUENCE versionitem_seq;
|
||||
CREATE SEQUENCE versionhistory_seq;
|
||||
|
||||
-------------------------------------------------------
|
||||
-- BitstreamFormatRegistry table
|
||||
@@ -787,6 +789,24 @@ CREATE INDEX harvested_item_fk_idx ON harvested_item(item_id);
|
||||
|
||||
|
||||
|
||||
CREATE TABLE versionhistory
|
||||
(
|
||||
versionhistory_id INTEGER NOT NULL PRIMARY KEY
|
||||
);
|
||||
|
||||
CREATE TABLE versionitem
|
||||
(
|
||||
versionitem_id INTEGER NOT NULL PRIMARY KEY,
|
||||
item_id INTEGER REFERENCES Item(item_id),
|
||||
version_number INTEGER,
|
||||
eperson_id INTEGER REFERENCES EPerson(eperson_id),
|
||||
version_date TIMESTAMP,
|
||||
version_summary VARCHAR(255),
|
||||
versionhistory_id INTEGER REFERENCES VersionHistory(versionhistory_id)
|
||||
);
|
||||
|
||||
CREATE SEQUENCE versionitem_seq;
|
||||
CREATE SEQUENCE versionhistory_seq;
|
||||
|
||||
|
||||
|
||||
|
@@ -82,6 +82,13 @@
|
||||
<artifactId>gson</artifactId>
|
||||
<version>2.2.1</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-webmvc</artifactId>
|
||||
<version>3.0.5.RELEASE</version>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
|
@@ -0,0 +1,144 @@
|
||||
/**
|
||||
* 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.app.xmlui.aspect.versioning;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.dspace.app.xmlui.cocoon.AbstractDSpaceTransformer;
|
||||
import org.dspace.app.xmlui.wing.Message;
|
||||
import org.dspace.app.xmlui.wing.WingException;
|
||||
import org.dspace.app.xmlui.wing.element.*;
|
||||
import org.dspace.authorize.AuthorizeException;
|
||||
import org.dspace.content.DCDate;
|
||||
import org.dspace.content.DCValue;
|
||||
import org.dspace.content.MetadataSchema;
|
||||
import org.dspace.eperson.EPerson;
|
||||
import org.dspace.utils.DSpace;
|
||||
import org.dspace.versioning.Version;
|
||||
import org.dspace.versioning.VersioningService;
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @author Fabio Bolognesi (fabio at atmire dot com)
|
||||
* @author Mark Diggory (markd at atmire dot com)
|
||||
* @author Ben Bosman (ben at atmire dot com)
|
||||
*/
|
||||
public class DeleteVersionsConfirm extends AbstractDSpaceTransformer {
|
||||
|
||||
/** Language strings */
|
||||
private static final Message T_dspace_home = message("xmlui.general.dspace_home");
|
||||
|
||||
private static final Message T_title = message("xmlui.aspect.versioning.DeleteVersionsConfirm.title");
|
||||
private static final Message T_trail = message("xmlui.aspect.versioning.DeleteVersionsConfirm.trail");
|
||||
private static final Message T_head1 = message("xmlui.aspect.versioning.DeleteVersionsConfirm.head1");
|
||||
private static final Message T_para1 = message("xmlui.aspect.versioning.DeleteVersionsConfirm.para1");
|
||||
private static final Message T_para2 = message("xmlui.aspect.versioning.DeleteVersionsConfirm.para2");
|
||||
private static final Message T_column1 = message("xmlui.aspect.versioning.DeleteVersionsConfirm.column1");
|
||||
private static final Message T_column2 = message("xmlui.aspect.versioning.DeleteVersionsConfirm.column2");
|
||||
private static final Message T_column3 = message("xmlui.aspect.versioning.DeleteVersionsConfirm.column3");
|
||||
private static final Message T_column4 = message("xmlui.aspect.versioning.DeleteVersionsConfirm.column4");
|
||||
private static final Message T_column5 = message("xmlui.aspect.versioning.DeleteVersionsConfirm.column5");
|
||||
|
||||
|
||||
private static final Message T_submit_delete = message("xmlui.general.delete");
|
||||
private static final Message T_submit_cancel = message("xmlui.general.cancel");
|
||||
|
||||
|
||||
public void addPageMeta(PageMeta pageMeta) throws WingException {
|
||||
pageMeta.addMetadata("title").addContent(T_title);
|
||||
|
||||
pageMeta.addTrailLink(contextPath + "/", T_dspace_home);
|
||||
//pageMeta.addTrailLink(contextPath + "/admin/item",T_item_trail);
|
||||
pageMeta.addTrail().addContent(T_trail);
|
||||
}
|
||||
|
||||
public void addBody(Body body) throws WingException, AuthorizeException {
|
||||
Division main = createMainDivision(body);
|
||||
|
||||
createTable(main);
|
||||
|
||||
addButtons(main);
|
||||
|
||||
main.addHidden("versioning-continue").setValue(knot.getId());
|
||||
}
|
||||
|
||||
|
||||
private Division createMainDivision(Body body) throws WingException {
|
||||
Division main = body.addInteractiveDivision("versions-confirm-delete", contextPath+"/item/versionhistory", Division.METHOD_POST, "delete version");
|
||||
main.setHead(T_head1);
|
||||
Para helpPara = main.addPara();
|
||||
helpPara.addContent(T_para1);
|
||||
helpPara.addHighlight("bold").addContent(T_para2);
|
||||
return main;
|
||||
}
|
||||
|
||||
|
||||
private void createTable(Division main) throws WingException {
|
||||
// Get all our parameters
|
||||
String idsString = parameters.getParameter("versionIDs", null);
|
||||
|
||||
Table table = main.addTable("versions-confirm-delete", 1, 1);
|
||||
|
||||
Row header = table.addRow(Row.ROLE_HEADER);
|
||||
header.addCellContent(T_column1);
|
||||
header.addCellContent(T_column2);
|
||||
header.addCellContent(T_column3);
|
||||
header.addCellContent(T_column4);
|
||||
header.addCellContent(T_column5);
|
||||
|
||||
|
||||
for (String id : idsString.split(","))
|
||||
{
|
||||
VersioningService versioningService = new DSpace().getSingletonService(VersioningService.class);
|
||||
Version version = null;
|
||||
|
||||
if(StringUtils.isNotBlank(id))
|
||||
{
|
||||
version = versioningService.getVersion(context, Integer.parseInt(id));
|
||||
}
|
||||
|
||||
if(version!=null)
|
||||
{
|
||||
Row row = table.addRow();
|
||||
row.addCell().addContent(version.getVersionNumber());
|
||||
addItemIdentifier(row.addCell(), version.getItem());
|
||||
|
||||
EPerson editor = version.getEperson();
|
||||
row.addCell().addXref("mailto:" + editor.getEmail(), editor.getFullName());
|
||||
row.addCell().addContent(new DCDate(version.getVersionDate()).toString());
|
||||
row.addCell().addContent(version.getSummary());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void addButtons(Division main) throws WingException {
|
||||
Para buttons = main.addPara();
|
||||
buttons.addButton("submit_confirm").setValue(T_submit_delete);
|
||||
buttons.addButton("submit_cancel").setValue(T_submit_cancel);
|
||||
}
|
||||
|
||||
private void addItemIdentifier(Cell cell, org.dspace.content.Item item) throws WingException {
|
||||
String itemHandle = item.getHandle();
|
||||
|
||||
DCValue[] identifiers = item.getMetadata(MetadataSchema.DC_SCHEMA, "identifier", null, org.dspace.content.Item.ANY);
|
||||
String itemIdentifier=null;
|
||||
if(identifiers!=null && identifiers.length > 0)
|
||||
{
|
||||
itemIdentifier = identifiers[0].value;
|
||||
}
|
||||
|
||||
if(itemIdentifier!=null)
|
||||
{
|
||||
cell.addXref(contextPath + "/resource/" + itemIdentifier, itemIdentifier);
|
||||
}else{
|
||||
cell.addXref(contextPath + "/handle/" + itemHandle, itemHandle);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1,220 @@
|
||||
/**
|
||||
* 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.app.xmlui.aspect.versioning;
|
||||
|
||||
import org.apache.cocoon.caching.CacheableProcessingComponent;
|
||||
import org.apache.cocoon.environment.ObjectModelHelper;
|
||||
import org.apache.cocoon.environment.Request;
|
||||
import org.apache.cocoon.util.HashUtil;
|
||||
import org.apache.excalibur.source.SourceValidity;
|
||||
import org.apache.excalibur.source.impl.validity.NOPValidity;
|
||||
import org.dspace.app.util.Util;
|
||||
import org.dspace.app.xmlui.cocoon.AbstractDSpaceTransformer;
|
||||
import org.dspace.app.xmlui.utils.DSpaceValidity;
|
||||
import org.dspace.app.xmlui.utils.HandleUtil;
|
||||
import org.dspace.app.xmlui.utils.UIException;
|
||||
import org.dspace.app.xmlui.wing.Message;
|
||||
import org.dspace.app.xmlui.wing.WingException;
|
||||
import org.dspace.app.xmlui.wing.element.List;
|
||||
import org.dspace.app.xmlui.wing.element.Options;
|
||||
import org.dspace.authorize.AuthorizeException;
|
||||
import org.dspace.authorize.AuthorizeManager;
|
||||
import org.dspace.content.DSpaceObject;
|
||||
import org.dspace.content.Item;
|
||||
import org.dspace.core.Constants;
|
||||
import org.dspace.eperson.Group;
|
||||
import org.dspace.utils.DSpace;
|
||||
import org.dspace.versioning.VersioningService;
|
||||
import org.xml.sax.SAXException;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Serializable;
|
||||
import java.sql.SQLException;
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* Navigation for Versioning of Items.
|
||||
*
|
||||
*
|
||||
* @author Fabio Bolognesi (fabio at atmire dot com)
|
||||
* @author Mark Diggory (markd at atmire dot com)
|
||||
* @author Ben Bosman (ben at atmire dot com)
|
||||
*/
|
||||
public class Navigation extends AbstractDSpaceTransformer implements CacheableProcessingComponent
|
||||
{
|
||||
private static final Message T_context_head = message("xmlui.administrative.Navigation.context_head");
|
||||
private static final Message T_context_create_version= message("xmlui.aspect.versioning.VersioningNavigation.context_create_version");
|
||||
private static final Message T_context_show_version_history= message("xmlui.aspect.versioning.VersioningNavigation.context_show_version_history");
|
||||
|
||||
/** Cached validity object */
|
||||
private SourceValidity validity;
|
||||
|
||||
/**
|
||||
* Generate the unique cache key.
|
||||
*
|
||||
* @return The generated key hashes the src
|
||||
*/
|
||||
public Serializable getKey()
|
||||
{
|
||||
Request request = ObjectModelHelper.getRequest(objectModel);
|
||||
|
||||
// Special case, don't cache anything if the user is logging
|
||||
// in. The problem occures because of timming, this cache key
|
||||
// is generated before we know whether the operation has
|
||||
// succeded or failed. So we don't know whether to cache this
|
||||
// under the user's specific cache or under the anonymous user.
|
||||
if (request.getParameter("login_email") != null ||
|
||||
request.getParameter("login_password") != null ||
|
||||
request.getParameter("login_realm") != null )
|
||||
{
|
||||
return "0";
|
||||
}
|
||||
|
||||
String key;
|
||||
if (context.getCurrentUser() != null)
|
||||
{
|
||||
key = context.getCurrentUser().getEmail();
|
||||
}
|
||||
else
|
||||
key = "anonymous";
|
||||
|
||||
return HashUtil.hash(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the validity object.
|
||||
*
|
||||
* @return The generated validity object or <code>null</code> if the
|
||||
* component is currently not cacheable.
|
||||
*/
|
||||
public SourceValidity getValidity()
|
||||
{
|
||||
if (this.validity == null)
|
||||
{
|
||||
// Only use the DSpaceValidity object is someone is logged in.
|
||||
if (context.getCurrentUser() != null)
|
||||
{
|
||||
try {
|
||||
DSpaceValidity validity = new DSpaceValidity();
|
||||
|
||||
validity.add(eperson);
|
||||
|
||||
Group[] groups = Group.allMemberGroups(context, eperson);
|
||||
for (Group group : groups)
|
||||
{
|
||||
validity.add(group);
|
||||
}
|
||||
|
||||
DSpaceObject dso = HandleUtil.obtainHandle(objectModel);
|
||||
if(dso != null)
|
||||
{
|
||||
validity.add(dso);
|
||||
}
|
||||
|
||||
this.validity = validity.complete();
|
||||
}
|
||||
catch (SQLException sqle)
|
||||
{
|
||||
// Just ignore it and return invalid.
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
this.validity = NOPValidity.SHARED_INSTANCE;
|
||||
}
|
||||
}
|
||||
return this.validity;
|
||||
}
|
||||
|
||||
public void addOptions(Options options) throws SAXException, WingException,
|
||||
UIException, SQLException, IOException, AuthorizeException {
|
||||
/* Create skeleton menu structure to ensure consistent order between aspects,
|
||||
* even if they are never used
|
||||
*/
|
||||
options.addList("browse");
|
||||
options.addList("account");
|
||||
|
||||
List context = options.addList("context");
|
||||
|
||||
|
||||
// Context Administrative options for Versioning
|
||||
DSpaceObject dso = HandleUtil.obtainHandle(objectModel);
|
||||
|
||||
|
||||
if(dso==null)
|
||||
{
|
||||
// case: internal-item http://localhost:8100/internal-item?itemID=3085
|
||||
// case: admin http://localhost:8100/admin/item?itemID=3340
|
||||
// retrieve the object from the DB
|
||||
dso = getItemById();
|
||||
}
|
||||
|
||||
if (dso != null && dso.getType() == Constants.ITEM)
|
||||
{
|
||||
Item item = (Item) dso;
|
||||
if(AuthorizeManager.isAdmin(this.context, item.getOwningCollection()))
|
||||
{
|
||||
boolean headAdded=false;
|
||||
if(isLatest(item) && item.isArchived())
|
||||
{
|
||||
context.setHead(T_context_head);
|
||||
headAdded=true;
|
||||
context.addItem().addXref(contextPath+"/item/version?itemID="+item.getID(), T_context_create_version);
|
||||
}
|
||||
|
||||
if(hasVersionHistory(item))
|
||||
{
|
||||
if(!headAdded)
|
||||
{
|
||||
context.setHead(T_context_head);
|
||||
}
|
||||
context.addItem().addXref(contextPath+"/item/versionhistory?itemID="+item.getID(), T_context_show_version_history);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private Item getItemById() throws SQLException
|
||||
{
|
||||
Request request = ObjectModelHelper.getRequest(objectModel);
|
||||
Item item = null;
|
||||
int itemId = Util.getIntParameter(request, "itemID");
|
||||
if (itemId != -1)
|
||||
{
|
||||
item = Item.find(this.context, itemId);
|
||||
}
|
||||
return item;
|
||||
}
|
||||
|
||||
/**
|
||||
* recycle
|
||||
*/
|
||||
public void recycle()
|
||||
{
|
||||
this.validity = null;
|
||||
super.recycle();
|
||||
}
|
||||
|
||||
private boolean isLatest(Item item)
|
||||
{
|
||||
VersioningService versioningService = new DSpace().getSingletonService(VersioningService.class);
|
||||
org.dspace.versioning.VersionHistory history = versioningService.findVersionHistory(context, item.getID());
|
||||
return (history==null || history.getLatestVersion().getItem().getID() == item.getID());
|
||||
}
|
||||
|
||||
|
||||
private boolean hasVersionHistory(Item item)
|
||||
{
|
||||
VersioningService versioningService = new DSpace().getSingletonService(VersioningService.class);
|
||||
org.dspace.versioning.VersionHistory history = versioningService.findVersionHistory(context, item.getID());
|
||||
return (history!=null);
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,109 @@
|
||||
/**
|
||||
* 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.app.xmlui.aspect.versioning;
|
||||
|
||||
import org.dspace.app.xmlui.cocoon.AbstractDSpaceTransformer;
|
||||
import org.dspace.app.xmlui.wing.Message;
|
||||
import org.dspace.app.xmlui.wing.WingException;
|
||||
import org.dspace.app.xmlui.wing.element.*;
|
||||
import org.dspace.authorize.AuthorizeException;
|
||||
import org.dspace.content.DCDate;
|
||||
import org.dspace.utils.DSpace;
|
||||
import org.dspace.versioning.Version;
|
||||
import org.dspace.versioning.VersioningService;
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @author Fabio Bolognesi (fabio at atmire dot com)
|
||||
* @author Mark Diggory (markd at atmire dot com)
|
||||
* @author Ben Bosman (ben at atmire dot com)
|
||||
*/
|
||||
public class RestoreVersionForm extends AbstractDSpaceTransformer
|
||||
{
|
||||
/** Language strings */
|
||||
private static final Message T_dspace_home = message("xmlui.general.dspace_home");
|
||||
private static final Message T_item_trail = message("xmlui.administrative.item.general.item_trail");
|
||||
|
||||
private static final Message T_title = message("xmlui.aspect.versioning.RestoreVersionForm.title");
|
||||
private static final Message T_trail = message("xmlui.aspect.versioning.RestoreVersionForm.trail");
|
||||
private static final Message T_head1 = message("xmlui.aspect.versioning.RestoreVersionForm.head1");
|
||||
private static final Message T_para1 = message("xmlui.aspect.versioning.RestoreVersionForm.para1");
|
||||
private static final Message T_column1 = message("xmlui.aspect.versioning.RestoreVersionForm.column1");
|
||||
private static final Message T_column2 = message("xmlui.aspect.versioning.RestoreVersionForm.column2");
|
||||
private static final Message T_column3 = message("xmlui.aspect.versioning.RestoreVersionForm.column3");
|
||||
private static final Message T_column4 = message("xmlui.aspect.versioning.RestoreVersionForm.column4");
|
||||
|
||||
private static final Message T_submit_restore = message("xmlui.aspect.versioning.RestoreVersionForm.restore");
|
||||
private static final Message T_submit_cancel = message("xmlui.general.cancel");
|
||||
|
||||
|
||||
public void addPageMeta(PageMeta pageMeta) throws WingException
|
||||
{
|
||||
pageMeta.addMetadata("title").addContent(T_title);
|
||||
|
||||
pageMeta.addTrailLink(contextPath + "/", T_dspace_home);
|
||||
pageMeta.addTrailLink(contextPath + "/admin/item",T_item_trail);
|
||||
pageMeta.addTrail().addContent(T_trail);
|
||||
}
|
||||
|
||||
public void addBody(Body body) throws WingException, AuthorizeException
|
||||
{
|
||||
Division main = createMainDivision(body);
|
||||
createTable(main);
|
||||
addButtons(main);
|
||||
main.addHidden("versioning-continue").setValue(knot.getId());
|
||||
}
|
||||
|
||||
|
||||
private Division createMainDivision(Body body) throws WingException
|
||||
{
|
||||
Division main = body.addInteractiveDivision("restore-version", contextPath+"/item/versionhistory", Division.METHOD_POST, "restore version");
|
||||
main.setHead(T_head1);
|
||||
main.addPara(T_para1);
|
||||
return main;
|
||||
}
|
||||
|
||||
|
||||
private void createTable(Division main) throws WingException
|
||||
{
|
||||
// Get all our parameters
|
||||
String id = parameters.getParameter("versionID", null);
|
||||
|
||||
Table table = main.addTable("version", 1, 1);
|
||||
|
||||
Row header = table.addRow(Row.ROLE_HEADER);
|
||||
header.addCellContent(T_column1);
|
||||
header.addCellContent(T_column2);
|
||||
header.addCellContent(T_column3);
|
||||
header.addCellContent(T_column4);
|
||||
|
||||
VersioningService versioningService = new DSpace().getSingletonService(VersioningService.class);
|
||||
Version version = versioningService.getVersion(context, Integer.parseInt(id));
|
||||
|
||||
Row row = table.addRow();
|
||||
row.addCell().addContent(version.getVersionNumber());
|
||||
row.addCell().addContent(version.getEperson().getEmail());
|
||||
row.addCell().addContent(new DCDate(version.getVersionDate()).toString());
|
||||
row.addCell().addContent(version.getSummary());
|
||||
|
||||
|
||||
List fields = main.addList("fields", List.TYPE_FORM);
|
||||
Composite addComposite = fields.addItem().addComposite("summary");
|
||||
addComposite.setLabel(T_column4);
|
||||
addComposite.addTextArea("summary");
|
||||
}
|
||||
|
||||
private void addButtons(Division main) throws WingException
|
||||
{
|
||||
Para buttons = main.addPara();
|
||||
buttons.addButton("submit_restore").setValue(T_submit_restore);
|
||||
buttons.addButton("submit_cancel").setValue(T_submit_cancel);
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1,253 @@
|
||||
/**
|
||||
* 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.app.xmlui.aspect.versioning;
|
||||
|
||||
import org.dspace.app.xmlui.cocoon.AbstractDSpaceTransformer;
|
||||
import org.dspace.app.xmlui.utils.HandleUtil;
|
||||
import org.dspace.app.xmlui.wing.Message;
|
||||
import org.dspace.app.xmlui.wing.WingException;
|
||||
import org.dspace.app.xmlui.wing.element.*;
|
||||
import org.dspace.authorize.AuthorizeException;
|
||||
import org.dspace.authorize.AuthorizeManager;
|
||||
import org.dspace.content.*;
|
||||
import org.dspace.content.Item;
|
||||
import org.dspace.core.ConfigurationManager;
|
||||
import org.dspace.eperson.EPerson;
|
||||
import org.dspace.utils.DSpace;
|
||||
import org.dspace.versioning.Version;
|
||||
import org.dspace.versioning.VersionHistory;
|
||||
import org.dspace.versioning.VersioningService;
|
||||
import org.dspace.workflow.WorkflowItem;
|
||||
import org.dspace.xmlworkflow.storedcomponents.XmlWorkflowItem;
|
||||
|
||||
import java.sql.SQLException;
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @author Fabio Bolognesi (fabio at atmire dot com)
|
||||
* @author Mark Diggory (markd at atmire dot com)
|
||||
* @author Ben Bosman (ben at atmire dot com)
|
||||
*/
|
||||
public class VersionHistoryForm extends AbstractDSpaceTransformer {
|
||||
/** Language strings */
|
||||
private static final Message T_dspace_home = message("xmlui.general.dspace_home");
|
||||
|
||||
private static final Message T_head2 = message("xmlui.aspect.versioning.VersionHistoryForm.head2");
|
||||
private static final Message T_column1 = message("xmlui.aspect.versioning.VersionHistoryForm.column1");
|
||||
private static final Message T_column2 = message("xmlui.aspect.versioning.VersionHistoryForm.column2");
|
||||
private static final Message T_column3 = message("xmlui.aspect.versioning.VersionHistoryForm.column3");
|
||||
private static final Message T_column4 = message("xmlui.aspect.versioning.VersionHistoryForm.column4");
|
||||
private static final Message T_column5 = message("xmlui.aspect.versioning.VersionHistoryForm.column5");
|
||||
private static final Message T_column6 = message("xmlui.aspect.versioning.VersionHistoryForm.column6");
|
||||
private static final Message T_title = message("xmlui.aspect.versioning.VersionHistoryForm.title");
|
||||
private static final Message T_trail = message("xmlui.aspect.versioning.VersionHistoryForm.trail");
|
||||
private static final Message T_submit_update = message("xmlui.aspect.versioning.VersionHistoryForm.update");
|
||||
private static final Message T_submit_cancel = message("xmlui.aspect.versioning.VersionHistoryForm.return");
|
||||
private static final Message T_submit_delete = message("xmlui.aspect.versioning.VersionHistoryForm.delete");
|
||||
private static final Message T_legend = message("xmlui.aspect.versioning.VersionHistoryForm.legend");
|
||||
|
||||
|
||||
public void addPageMeta(PageMeta pageMeta) throws WingException, SQLException
|
||||
{
|
||||
pageMeta.addMetadata("title").addContent(T_title);
|
||||
pageMeta.addTrailLink(contextPath + "/", T_dspace_home);
|
||||
|
||||
Item item = getItem();
|
||||
if(item != null)
|
||||
{
|
||||
HandleUtil.buildHandleTrail(item, pageMeta, contextPath);
|
||||
pageMeta.addTrailLink(contextPath + "/handle/" + item.getHandle(), item.getName());
|
||||
}
|
||||
pageMeta.addTrail().addContent(T_trail);
|
||||
}
|
||||
|
||||
|
||||
public void addBody(Body body) throws WingException, SQLException, AuthorizeException
|
||||
{
|
||||
boolean isItemView=parameters.getParameterAsInteger("itemID",-1) == -1;
|
||||
Item item = getItem();
|
||||
|
||||
if(item==null || !AuthorizeManager.isAdmin(this.context, item.getOwningCollection()))
|
||||
{
|
||||
if(isItemView)
|
||||
{
|
||||
//Check if only administrators can view the item history
|
||||
if(new DSpace().getConfigurationService().getPropertyAsType("versioning.item.history.view.admin", false))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}else{
|
||||
//Only admins can delete versions
|
||||
throw new AuthorizeException();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
VersionHistory versionHistory = retrieveVersionHistory(item);
|
||||
if(versionHistory!=null)
|
||||
{
|
||||
Division main = createMain(body);
|
||||
createTable(main, versionHistory, isItemView, item);
|
||||
|
||||
if(!isItemView)
|
||||
{
|
||||
addButtons(main, versionHistory);
|
||||
main.addHidden("versioning-continue").setValue(knot.getId());
|
||||
}
|
||||
|
||||
Para note = main.addPara();
|
||||
note.addContent(T_legend);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private Item getItem() throws WingException
|
||||
{
|
||||
try
|
||||
{
|
||||
if(parameters.getParameterAsInteger("itemID",-1) == -1)
|
||||
{
|
||||
DSpaceObject dso;
|
||||
dso = HandleUtil.obtainHandle(objectModel);
|
||||
if (!(dso instanceof Item))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
return (Item) dso;
|
||||
}else{
|
||||
return Item.find(context, parameters.getParameterAsInteger("itemID", -1));
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
throw new WingException(e);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
private VersionHistory retrieveVersionHistory(Item item) throws WingException
|
||||
{
|
||||
VersioningService versioningService = new DSpace().getSingletonService(VersioningService.class);
|
||||
return versioningService.findVersionHistory(context, item.getID());
|
||||
}
|
||||
|
||||
|
||||
private Division createMain(Body body) throws WingException
|
||||
{
|
||||
Division main = body.addInteractiveDivision("view-verion-history", contextPath+"/item/versionhistory", Division.METHOD_POST, "view version history");
|
||||
main.setHead(T_head2);
|
||||
return main;
|
||||
}
|
||||
|
||||
private void createTable(Division main, VersionHistory history, boolean isItemView, Item item) throws WingException, SQLException
|
||||
{
|
||||
Table table = main.addTable("versionhistory", 1, 1);
|
||||
|
||||
Row header = table.addRow(Row.ROLE_HEADER);
|
||||
if(!isItemView)
|
||||
{
|
||||
header.addCell().addContent("");
|
||||
}
|
||||
header.addCell().addContent(T_column1);
|
||||
header.addCell().addContent(T_column2);
|
||||
header.addCell().addContent(T_column3);
|
||||
header.addCell().addContent(T_column4);
|
||||
header.addCell().addContent(T_column5);
|
||||
|
||||
if(!isItemView)
|
||||
{
|
||||
header.addCell().addContent(T_column6);
|
||||
}
|
||||
|
||||
if(history != null)
|
||||
{
|
||||
for(Version version : history.getVersions())
|
||||
{
|
||||
|
||||
//Skip items currently in submission
|
||||
if(isItemInSubmission(version.getItem()))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
Row row = table.addRow(null, Row.ROLE_DATA,"metadata-value");
|
||||
if(!isItemView)
|
||||
{
|
||||
CheckBox remove = row.addCell().addCheckBox("remove");
|
||||
remove.setLabel("remove");
|
||||
remove.addOption(version.getVersionId());
|
||||
}
|
||||
|
||||
row.addCell().addContent(version.getVersionNumber());
|
||||
addItemIdentifier(row.addCell(), item, version);
|
||||
|
||||
EPerson editor = version.getEperson();
|
||||
row.addCell().addXref("mailto:" + editor.getEmail(), editor.getFullName());
|
||||
row.addCell().addContent(new DCDate(version.getVersionDate()).toString());
|
||||
row.addCell().addContent(version.getSummary());
|
||||
|
||||
|
||||
if(!isItemView)
|
||||
{
|
||||
row.addCell().addXref(contextPath + "/item/versionhistory?versioning-continue="+knot.getId()+"&versionID="+version.getVersionId() +"&itemID="+ version.getItem().getID() + "&submit_update", T_submit_update);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private boolean isItemInSubmission(Item item) throws SQLException
|
||||
{
|
||||
WorkspaceItem workspaceItem = WorkspaceItem.findByItem(context, item);
|
||||
InProgressSubmission workflowItem;
|
||||
if(ConfigurationManager.getProperty("workflow", "workflow.framework").equals("xmlworkflow"))
|
||||
{
|
||||
workflowItem = XmlWorkflowItem.findByItem(context, item);
|
||||
}else{
|
||||
workflowItem = WorkflowItem.findByItem(context, item);
|
||||
}
|
||||
|
||||
return workspaceItem != null || workflowItem != null;
|
||||
}
|
||||
|
||||
private void addItemIdentifier(Cell cell, Item item, Version version) throws WingException
|
||||
{
|
||||
String itemHandle = version.getItem().getHandle();
|
||||
|
||||
DCValue[] identifiers = version.getItem().getMetadata(MetadataSchema.DC_SCHEMA, "identifier", null, Item.ANY);
|
||||
String itemIdentifier=null;
|
||||
if(identifiers!=null && identifiers.length > 0)
|
||||
{
|
||||
itemIdentifier = identifiers[0].value;
|
||||
}
|
||||
|
||||
if(itemIdentifier!=null)
|
||||
{
|
||||
cell.addXref(contextPath + "/resource/" + itemIdentifier, itemIdentifier);
|
||||
}else{
|
||||
cell.addXref(contextPath + "/handle/" + itemHandle, itemHandle);
|
||||
}
|
||||
|
||||
if(item.getID()==version.getItemID())
|
||||
{
|
||||
cell.addContent("*");
|
||||
}
|
||||
}
|
||||
|
||||
private void addButtons(Division main, VersionHistory history) throws WingException {
|
||||
Para actions = main.addPara();
|
||||
|
||||
if(history!=null && history.getVersions().size() > 0)
|
||||
{
|
||||
actions.addButton("submit_delete").setValue(T_submit_delete);
|
||||
}
|
||||
|
||||
actions.addButton("submit_cancel").setValue(T_submit_cancel);
|
||||
}
|
||||
}
|
@@ -0,0 +1,120 @@
|
||||
/**
|
||||
* 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.app.xmlui.aspect.versioning;
|
||||
|
||||
import org.apache.avalon.framework.parameters.ParameterException;
|
||||
import org.dspace.app.xmlui.cocoon.AbstractDSpaceTransformer;
|
||||
import org.dspace.app.xmlui.utils.HandleUtil;
|
||||
import org.dspace.app.xmlui.wing.Message;
|
||||
import org.dspace.app.xmlui.wing.WingException;
|
||||
import org.dspace.app.xmlui.wing.element.*;
|
||||
import org.dspace.authorize.AuthorizeException;
|
||||
import org.dspace.authorize.AuthorizeManager;
|
||||
import org.dspace.content.Item;
|
||||
import org.dspace.utils.DSpace;
|
||||
import org.dspace.versioning.VersioningService;
|
||||
|
||||
import java.sql.SQLException;
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @author Fabio Bolognesi (fabio at atmire dot com)
|
||||
* @author Mark Diggory (markd at atmire dot com)
|
||||
* @author Ben Bosman (ben at atmire dot com)
|
||||
*/
|
||||
|
||||
// Versioning
|
||||
public class VersionItemForm extends AbstractDSpaceTransformer {
|
||||
|
||||
/** Language strings */
|
||||
private static final Message T_dspace_home = message("xmlui.general.dspace_home");
|
||||
private static final Message T_submit_cancel = message("xmlui.general.cancel");
|
||||
|
||||
private static final Message T_title = message("xmlui.aspect.versioning.VersionItemForm.title");
|
||||
private static final Message T_trail = message("xmlui.aspect.versioning.VersionItemForm.trail");
|
||||
private static final Message T_head1 = message("xmlui.aspect.versioning.VersionItemForm.head1");
|
||||
private static final Message T_submit_version= message("xmlui.aspect.versioning.VersionItemForm.submit_version");
|
||||
private static final Message T_submit_update_version= message("xmlui.aspect.versioning.VersionItemForm.submit_update_version");
|
||||
private static final Message T_summary = message("xmlui.aspect.versioning.VersionItemForm.summary");
|
||||
|
||||
|
||||
public void addPageMeta(PageMeta pageMeta) throws WingException, SQLException {
|
||||
pageMeta.addMetadata("title").addContent(T_title);
|
||||
pageMeta.addTrailLink(contextPath + "/", T_dspace_home);
|
||||
//pageMeta.addTrailLink(contextPath+"/admin/item", T_item_trail);
|
||||
Item item = getItem();
|
||||
if(item != null)
|
||||
{
|
||||
HandleUtil.buildHandleTrail(item, pageMeta, contextPath);
|
||||
pageMeta.addTrailLink(contextPath + "/handle/" + item.getHandle(), item.getName());
|
||||
}
|
||||
pageMeta.addTrail().addContent(T_trail);
|
||||
}
|
||||
|
||||
public void addBody(Body body) throws WingException, SQLException, AuthorizeException {
|
||||
|
||||
// Get our parameters and state
|
||||
Item item = getItem();
|
||||
|
||||
//Only (collection) admins should be able to create a new version
|
||||
if(!AuthorizeManager.isAdmin(context, item.getOwningCollection())){
|
||||
throw new AuthorizeException();
|
||||
}
|
||||
|
||||
String summary;
|
||||
try {
|
||||
summary = parameters.getParameter("summary");
|
||||
} catch (ParameterException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
// DIVISION: Main
|
||||
Division main = body.addInteractiveDivision("version-item", contextPath+"/item/version", Division.METHOD_POST, "primary administrative version");
|
||||
main.setHead(T_head1.parameterize(item.getHandle()));
|
||||
|
||||
// Fields
|
||||
List fields = main.addList("fields", List.TYPE_FORM);
|
||||
Composite addComposite = fields.addItem().addComposite("summary");
|
||||
addComposite.setLabel(T_summary);
|
||||
TextArea addValue = addComposite.addTextArea("summary");
|
||||
if(summary!=null)
|
||||
{
|
||||
addValue.setValue(summary);
|
||||
}
|
||||
|
||||
|
||||
// Buttons
|
||||
Para actions = main.addPara();
|
||||
|
||||
org.dspace.versioning.VersionHistory history = retrieveVersionHistory(item);
|
||||
if(history!=null && history.hasNext(item))
|
||||
{
|
||||
actions.addButton("submit_update_version").setValue(T_submit_update_version);
|
||||
}
|
||||
else
|
||||
{
|
||||
actions.addButton("submit_version").setValue(T_submit_version);
|
||||
}
|
||||
|
||||
actions.addButton("submit_cancel").setValue(T_submit_cancel);
|
||||
|
||||
main.addHidden("versioning-continue").setValue(knot.getId());
|
||||
}
|
||||
|
||||
private Item getItem() throws SQLException {
|
||||
int itemID = parameters.getParameterAsInteger("itemID",-1);
|
||||
return Item.find(context, itemID);
|
||||
}
|
||||
|
||||
|
||||
private org.dspace.versioning.VersionHistory retrieveVersionHistory(Item item){
|
||||
VersioningService versioningService = new DSpace().getSingletonService(VersioningService.class);
|
||||
return versioningService.findVersionHistory(context, item.getID());
|
||||
}
|
||||
}
|
@@ -0,0 +1,179 @@
|
||||
/**
|
||||
* 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.app.xmlui.aspect.versioning;
|
||||
|
||||
import org.dspace.app.xmlui.aspect.administrative.FlowResult;
|
||||
import org.dspace.app.xmlui.utils.UIException;
|
||||
import org.dspace.app.xmlui.wing.Message;
|
||||
import org.dspace.authorize.AuthorizeException;
|
||||
import org.dspace.authorize.AuthorizeManager;
|
||||
import org.dspace.content.Item;
|
||||
import org.dspace.content.WorkspaceItem;
|
||||
import org.dspace.core.Context;
|
||||
import org.dspace.utils.DSpace;
|
||||
import org.dspace.versioning.Version;
|
||||
import org.dspace.versioning.VersionHistory;
|
||||
import org.dspace.versioning.VersioningService;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.sql.SQLException;
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @author Fabio Bolognesi (fabio at atmire dot com)
|
||||
* @author Mark Diggory (markd at atmire dot com)
|
||||
* @author Ben Bosman (ben at atmire dot com)
|
||||
*/
|
||||
public class VersionManager {
|
||||
|
||||
private static final Message T_version_created = new Message("default", "The new version has been created.");
|
||||
private static final Message T_version_delete = new Message("default", "The selected version(s) have been deleted.");
|
||||
private static final Message T_version_updated = new Message("default", "The version has been updated.");
|
||||
private static final Message T_version_restored = new Message("default", "The version has been restored.");
|
||||
|
||||
|
||||
/**
|
||||
* Create a new version of the specified item
|
||||
*
|
||||
* @param context The DSpace context
|
||||
* @param itemID The id of the to-be-versioned item
|
||||
* @return A result object
|
||||
*/
|
||||
// Versioning
|
||||
public static FlowResult processCreateNewVersion(Context context, int itemID, String summary) throws SQLException, AuthorizeException, IOException {
|
||||
FlowResult result = new FlowResult();
|
||||
try {
|
||||
result.setContinue(false);
|
||||
|
||||
Item item = Item.find(context, itemID);
|
||||
|
||||
if (AuthorizeManager.isAdmin(context, item) || item.canEdit()) {
|
||||
VersioningService versioningService = new DSpace().getSingletonService(VersioningService.class);
|
||||
Version version = versioningService.createNewVersion(context, itemID, summary);
|
||||
WorkspaceItem wsi = WorkspaceItem.findByItem(context, version.getItem());
|
||||
|
||||
context.commit();
|
||||
|
||||
result.setParameter("wsid", wsi.getID());
|
||||
result.setOutcome(true);
|
||||
result.setContinue(true);
|
||||
result.setMessage(T_version_created);
|
||||
result.setParameter("summary", summary);
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
context.abort();
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Modify latest version
|
||||
*
|
||||
* @param context The DSpace context
|
||||
* @param itemID The id of the to-be-versioned item
|
||||
* @return A result object
|
||||
*/
|
||||
// Versioning
|
||||
public static FlowResult processUpdateVersion(Context context, int itemID, String summary) throws SQLException, AuthorizeException, IOException {
|
||||
|
||||
FlowResult result = new FlowResult();
|
||||
try {
|
||||
result.setContinue(false);
|
||||
|
||||
Item item = Item.find(context, itemID);
|
||||
|
||||
if (AuthorizeManager.isAdmin(context, item)) {
|
||||
VersioningService versioningService = new DSpace().getSingletonService(VersioningService.class);
|
||||
versioningService.updateVersion(context, itemID, summary);
|
||||
|
||||
context.commit();
|
||||
|
||||
result.setOutcome(true);
|
||||
result.setContinue(true);
|
||||
result.setMessage(T_version_updated);
|
||||
result.setParameter("summary", summary);
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
context.abort();
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Restore a version
|
||||
*
|
||||
* @param versionID id of the version to restore
|
||||
* @param context The DSpace context
|
||||
* @return A result object
|
||||
*/
|
||||
// Versioning
|
||||
public static FlowResult processRestoreVersion(Context context, int versionID, String summary) throws SQLException, AuthorizeException, IOException {
|
||||
FlowResult result = new FlowResult();
|
||||
try {
|
||||
result.setContinue(false);
|
||||
|
||||
VersioningService versioningService = new DSpace().getSingletonService(VersioningService.class);
|
||||
versioningService.restoreVersion(context, versionID, summary);
|
||||
|
||||
context.commit();
|
||||
|
||||
result.setOutcome(true);
|
||||
result.setContinue(true);
|
||||
result.setMessage(T_version_restored);
|
||||
} catch (Exception ex) {
|
||||
context.abort();
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Delete version(s)
|
||||
*
|
||||
* @param context The DSpace context
|
||||
* @param versionIDs list of versionIDs to delete
|
||||
* @return A result object
|
||||
*/
|
||||
// Versioning
|
||||
public static FlowResult processDeleteVersions(Context context, int itemId, String[] versionIDs) throws SQLException, AuthorizeException, IOException, UIException {
|
||||
FlowResult result = new FlowResult();
|
||||
try {
|
||||
result.setContinue(false);
|
||||
|
||||
VersioningService versioningService = new DSpace().getSingletonService(VersioningService.class);
|
||||
|
||||
VersionHistory versionHistory = versioningService.findVersionHistory(context, itemId);
|
||||
|
||||
for (String id : versionIDs) {
|
||||
versioningService.removeVersion(context, Integer.parseInt(id));
|
||||
}
|
||||
context.commit();
|
||||
|
||||
//Retrieve the latest version of our history (IF any is even present)
|
||||
Version latestVersion = versionHistory.getLatestVersion();
|
||||
if(latestVersion == null){
|
||||
result.setParameter("itemID", null);
|
||||
}else{
|
||||
result.setParameter("itemID", latestVersion.getItemID());
|
||||
}
|
||||
result.setContinue(true);
|
||||
result.setOutcome(true);
|
||||
result.setMessage(T_version_delete);
|
||||
|
||||
} catch (Exception ex) {
|
||||
context.abort();
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
@@ -0,0 +1,125 @@
|
||||
/**
|
||||
* 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.app.xmlui.aspect.versioning;
|
||||
|
||||
import org.apache.cocoon.ProcessingException;
|
||||
import org.dspace.app.xmlui.cocoon.AbstractDSpaceTransformer;
|
||||
import org.dspace.app.xmlui.utils.HandleUtil;
|
||||
import org.dspace.app.xmlui.wing.Message;
|
||||
import org.dspace.app.xmlui.wing.WingException;
|
||||
import org.dspace.app.xmlui.wing.element.Body;
|
||||
import org.dspace.app.xmlui.wing.element.Division;
|
||||
import org.dspace.app.xmlui.wing.element.Para;
|
||||
import org.dspace.authorize.AuthorizeException;
|
||||
import org.dspace.authorize.AuthorizeManager;
|
||||
import org.dspace.content.DSpaceObject;
|
||||
import org.dspace.content.Item;
|
||||
import org.dspace.handle.HandleManager;
|
||||
import org.dspace.utils.DSpace;
|
||||
import org.dspace.versioning.Version;
|
||||
import org.dspace.versioning.VersionHistory;
|
||||
import org.dspace.versioning.VersioningService;
|
||||
import org.xml.sax.SAXException;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.sql.SQLException;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Adds a notice to item page in the following conditions
|
||||
* A new version of an item is available
|
||||
* If the person is an admin an message will also be shown if the item has a new version in the workflow
|
||||
*
|
||||
* @author Fabio Bolognesi (fabio at atmire dot com)
|
||||
* @author Mark Diggory (markd at atmire dot com)
|
||||
* @author Ben Bosman (ben at atmire dot com)
|
||||
*
|
||||
*/
|
||||
public class VersionNoticeTransformer extends AbstractDSpaceTransformer {
|
||||
|
||||
private static final Message T_new_version_head = message("xmlui.aspect.versioning.VersionNoticeTransformer.notice.new_version_head");
|
||||
private static final Message T_new_version_help = message("xmlui.aspect.versioning.VersionNoticeTransformer.notice.new_version_help");
|
||||
private static final Message T_workflow_version_head = message("xmlui.aspect.versioning.VersionNoticeTransformer.notice.workflow_version_head");
|
||||
private static final Message T_workflow_version_help = message("xmlui.aspect.versioning.VersionNoticeTransformer.notice.workflow_version_help");
|
||||
|
||||
@Override
|
||||
public void addBody(Body body) throws SAXException, WingException, SQLException, IOException, AuthorizeException, ProcessingException {
|
||||
DSpaceObject dso = HandleUtil.obtainHandle(objectModel);
|
||||
if (!(dso instanceof Item))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Item item = (Item) dso;
|
||||
|
||||
if(item.isWithdrawn())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
//Always add a placeholder in which the item information can be added !
|
||||
Division mainDivision = body.addDivision("item-view","primary");
|
||||
String title = item.getName();
|
||||
if(title != null)
|
||||
{
|
||||
mainDivision.setHead(title);
|
||||
}else{
|
||||
mainDivision.setHead(item.getHandle());
|
||||
}
|
||||
|
||||
|
||||
//Check if we have a history for the item
|
||||
VersioningService versioningService = new DSpace().getSingletonService(VersioningService.class);
|
||||
VersionHistory history = versioningService.findVersionHistory(context, item.getID());
|
||||
|
||||
if(history != null){
|
||||
Version latestVersion = retrieveLatestVersion(history, item);
|
||||
if(latestVersion != null && latestVersion.getItemID() != item.getID())
|
||||
{
|
||||
//We have a newer version
|
||||
Item latestVersionItem = latestVersion.getItem();
|
||||
if(latestVersionItem.isArchived())
|
||||
{
|
||||
//Available, add a link for the user alerting him that a new version is available
|
||||
addVersionNotice(mainDivision, latestVersionItem, T_new_version_head, T_new_version_help, true);
|
||||
}else{
|
||||
//We might be dealing with a workflow/workspace item
|
||||
addVersionNotice(mainDivision, latestVersionItem, T_workflow_version_head, T_workflow_version_help, false);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private Version retrieveLatestVersion(VersionHistory history, Item item) throws SQLException {
|
||||
//Attempt to retrieve the latest version
|
||||
List<Version> allVersions = history.getVersions();
|
||||
for (Version version : allVersions) {
|
||||
if (version.getItem().isArchived() || AuthorizeManager.isAdmin(context, item.getOwningCollection()))
|
||||
{
|
||||
return version;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
protected void addVersionNotice(Division division, Item item, Message head, Message content, boolean addItemUrl) throws WingException, SQLException
|
||||
{
|
||||
Division noticeDiv = division.addDivision("general-message", "version-notice notice neutral");
|
||||
noticeDiv.setHead(head);
|
||||
|
||||
Para para = noticeDiv.addPara();
|
||||
para.addContent(content);
|
||||
if(addItemUrl)
|
||||
{
|
||||
String url = HandleManager.resolveToURL(context, item.getHandle());
|
||||
para.addXref(url, url);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,80 @@
|
||||
/**
|
||||
* 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.app.xmlui.aspect.versioning;
|
||||
|
||||
import org.dspace.app.xmlui.cocoon.AbstractDSpaceTransformer;
|
||||
import org.dspace.app.xmlui.wing.Message;
|
||||
import org.dspace.app.xmlui.wing.WingException;
|
||||
import org.dspace.app.xmlui.wing.element.*;
|
||||
import org.dspace.content.Item;
|
||||
import org.dspace.utils.DSpace;
|
||||
import org.dspace.versioning.VersioningService;
|
||||
|
||||
import java.sql.SQLException;
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @author Fabio Bolognesi (fabio at atmire dot com)
|
||||
* @author Mark Diggory (markd at atmire dot com)
|
||||
* @author Ben Bosman (ben at atmire dot com)
|
||||
*/
|
||||
|
||||
// Versioning
|
||||
public class VersionUpdateForm extends AbstractDSpaceTransformer {
|
||||
|
||||
/** Language strings */
|
||||
private static final Message T_dspace_home = message("xmlui.general.dspace_home");
|
||||
private static final Message T_submit_cancel = message("xmlui.general.cancel");
|
||||
|
||||
private static final Message T_title = message("xmlui.aspect.versioning.VersionUpdateForm.title");
|
||||
private static final Message T_trail = message("xmlui.aspect.versioning.VersionUpdateForm.trail");
|
||||
private static final Message T_head1 = message("xmlui.aspect.versioning.VersionUpdateForm.head1");
|
||||
private static final Message T_submit_version= message("xmlui.aspect.versioning.VersionUpdateForm.submit_version");
|
||||
private static final Message T_submit_update_version= message("xmlui.aspect.versioning.VersionUpdateForm.submit_update_version");
|
||||
private static final Message T_summary = message("xmlui.aspect.versioning.VersionUpdateForm.summary");
|
||||
|
||||
|
||||
public void addPageMeta(PageMeta pageMeta) throws WingException {
|
||||
pageMeta.addMetadata("title").addContent(T_title);
|
||||
pageMeta.addTrailLink(contextPath + "/", T_dspace_home);
|
||||
pageMeta.addTrail().addContent(T_trail);
|
||||
}
|
||||
|
||||
public void addBody(Body body) throws WingException, SQLException{
|
||||
int versionID = parameters.getParameterAsInteger("versionID",-1);
|
||||
org.dspace.versioning.Version version = getVersion(versionID);
|
||||
|
||||
Item item = version.getItem();
|
||||
|
||||
// DIVISION: Main
|
||||
Division main = body.addInteractiveDivision("version-item", contextPath+"/item/versionhistory", Division.METHOD_POST, "primary administrative version");
|
||||
main.setHead(T_head1.parameterize(item.getHandle()));
|
||||
|
||||
// Fields
|
||||
List fields = main.addList("fields", List.TYPE_FORM);
|
||||
Composite addComposite = fields.addItem().addComposite("summary");
|
||||
addComposite.setLabel(T_summary);
|
||||
TextArea addValue = addComposite.addTextArea("summary");
|
||||
addValue.setValue(version.getSummary());
|
||||
|
||||
|
||||
// Buttons
|
||||
Para actions = main.addPara();
|
||||
|
||||
actions.addButton("submit_update").setValue(T_submit_update_version);
|
||||
actions.addButton("submit_cancel").setValue(T_submit_cancel);
|
||||
main.addHidden("versioning-continue").setValue(knot.getId());
|
||||
}
|
||||
|
||||
|
||||
private org.dspace.versioning.Version getVersion(int versionID){
|
||||
VersioningService versioningService = new DSpace().getSingletonService(VersioningService.class);
|
||||
return versioningService.getVersion(context, versionID);
|
||||
}
|
||||
}
|
@@ -0,0 +1,216 @@
|
||||
/**
|
||||
* 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.springmvc;
|
||||
|
||||
|
||||
import org.dspace.content.DCValue;
|
||||
import org.dspace.content.DSpaceObject;
|
||||
import org.dspace.content.Item;
|
||||
import org.dspace.core.Context;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.web.servlet.View;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.io.PrintWriter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.StringTokenizer;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* @author Fabio Bolognesi (fabio at atmire dot com)
|
||||
* @author Mark Diggory (markd at atmire dot com)
|
||||
* @author Ben Bosman (ben at atmire dot com)
|
||||
*/
|
||||
|
||||
public class BibTexView implements View {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(BibTexView.class);
|
||||
private static final String EOL = "\r\n";
|
||||
|
||||
private String resourceIdentifier=null;
|
||||
|
||||
public String getContentType() {
|
||||
|
||||
return "text/plain;charset=utf-8";
|
||||
}
|
||||
|
||||
public BibTexView(String resourceIdentifier)
|
||||
{
|
||||
this.resourceIdentifier = resourceIdentifier;
|
||||
}
|
||||
|
||||
public void render(Map<String, ?> model, HttpServletRequest request, HttpServletResponse response) throws Exception {
|
||||
|
||||
DSpaceObject item = (DSpaceObject)request.getAttribute(ResourceIdentifierController.DSPACE_OBJECT);
|
||||
|
||||
Context context = new Context();
|
||||
context.turnOffAuthorisationSystem();
|
||||
|
||||
String fileName = getFileName(item);
|
||||
|
||||
write(response, getBibTex((Item) item, resourceIdentifier), fileName);
|
||||
|
||||
OutputStream aOutputStream = response.getOutputStream();
|
||||
aOutputStream.close();
|
||||
|
||||
}
|
||||
|
||||
private void write(HttpServletResponse aResponse, String aContent, String aFileName) throws IOException {
|
||||
aResponse.setContentType("text/plain;charset=utf-8");
|
||||
aResponse.setContentLength(aContent.length());
|
||||
aResponse.setHeader("Content-Disposition", "attachment; filename=\""
|
||||
+ aFileName + "\"");
|
||||
|
||||
// It's all over but the writing...
|
||||
PrintWriter writer = aResponse.getWriter();
|
||||
writer.print(aContent);
|
||||
writer.close();
|
||||
}
|
||||
|
||||
|
||||
private String getFileName(DSpaceObject item)
|
||||
{
|
||||
String fileName = resourceIdentifier;
|
||||
if(resourceIdentifier.lastIndexOf("/") !=-1)
|
||||
{
|
||||
fileName = resourceIdentifier.replaceAll("/", "_") + ".bib";
|
||||
}
|
||||
|
||||
return fileName;
|
||||
}
|
||||
|
||||
|
||||
private String getBibTex(Item item, String resourceIdentifier) {
|
||||
// No standardized format for data so using 'misc' for now
|
||||
StringBuilder builder = new StringBuilder("@misc{");
|
||||
|
||||
String[] authors = getAuthors(item);
|
||||
String year = getYear(item);
|
||||
String title = getMetadataValue(item, "dc.title");
|
||||
|
||||
builder.append(resourceIdentifier).append(',').append(EOL);
|
||||
|
||||
if (title != null) {
|
||||
builder.append(" title = {").append(title).append("},");
|
||||
builder.append(EOL);
|
||||
}
|
||||
|
||||
if (authors.length > 0) {
|
||||
builder.append(" author = {");
|
||||
|
||||
// Bibtex needs the comma... do we want full names here?
|
||||
for (int index = 0; index < authors.length; index++) {
|
||||
if (index + 1 >= authors.length) { // last one
|
||||
builder.append(authors[index].replace(" ", ", "));
|
||||
}
|
||||
else if (index + 1 < authors.length) { // not last one
|
||||
builder.append(authors[index].replace(" ", ", "));
|
||||
builder.append(" and ");
|
||||
}
|
||||
}
|
||||
|
||||
builder.append("},").append(EOL);
|
||||
}
|
||||
|
||||
if (year != null) {
|
||||
builder.append(" year = {").append(year).append("},").append(EOL);
|
||||
}
|
||||
|
||||
return builder.append("}").append(EOL).toString();
|
||||
}
|
||||
|
||||
private String getMetadataValue(Item item, String metadatafield)
|
||||
{
|
||||
for (DCValue value : item.getMetadata(metadatafield))
|
||||
{
|
||||
return value.value;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
private String[] getAuthors(Item aItem)
|
||||
{
|
||||
ArrayList<String> authors = new ArrayList<String>();
|
||||
|
||||
authors.addAll(getAuthors(aItem.getMetadata("dc.contributor.author")));
|
||||
authors.addAll(getAuthors(aItem.getMetadata("dc.creator")));
|
||||
authors.addAll(getAuthors(aItem.getMetadata("dc.contributor")));
|
||||
|
||||
return authors.toArray(new String[authors.size()]);
|
||||
}
|
||||
|
||||
private String getYear(Item aItem)
|
||||
{
|
||||
for (DCValue date : aItem.getMetadata("dc.date.issued"))
|
||||
{
|
||||
return date.value.substring(0, 4);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private List<String> getAuthors(DCValue[] aMetadata)
|
||||
{
|
||||
ArrayList<String> authors = new ArrayList<String>();
|
||||
StringTokenizer tokenizer;
|
||||
|
||||
for (DCValue metadata : aMetadata)
|
||||
{
|
||||
StringBuilder builder = new StringBuilder();
|
||||
|
||||
if (metadata.value.indexOf(",") != -1)
|
||||
{
|
||||
String[] parts = metadata.value.split(",");
|
||||
|
||||
if (parts.length > 1)
|
||||
{
|
||||
tokenizer = new StringTokenizer(parts[1], ". ");
|
||||
builder.append(parts[0]).append(" ");
|
||||
|
||||
while (tokenizer.hasMoreTokens())
|
||||
{
|
||||
builder.append(tokenizer.nextToken().charAt(0));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
builder.append(metadata.value);
|
||||
}
|
||||
|
||||
authors.add(builder.toString());
|
||||
}
|
||||
// Now the minority case (as we've cleaned up data and input method)
|
||||
else
|
||||
{
|
||||
String[] parts = metadata.value.split("\\s+|\\.");
|
||||
String name = parts[parts.length - 1].replace("\\s+|\\.", "");
|
||||
|
||||
builder.append(name).append(" ");
|
||||
|
||||
for (int index = 0; index < parts.length - 1; index++)
|
||||
{
|
||||
if (parts[index].length() > 0)
|
||||
{
|
||||
name = parts[index].replace("\\s+|\\.", "");
|
||||
builder.append(name.charAt(0));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return authors;
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,41 @@
|
||||
/**
|
||||
* 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.springmvc;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.servlet.ModelAndView;
|
||||
import org.springframework.web.servlet.View;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.sql.SQLException;
|
||||
import java.util.*;
|
||||
|
||||
|
||||
/**
|
||||
* @author Fabio Bolognesi (fabio at atmire dot com)
|
||||
* @author Mark Diggory (markd at atmire dot com)
|
||||
* @author Ben Bosman (ben at atmire dot com)
|
||||
*/
|
||||
|
||||
@Controller(value = "cocoonForwardController")
|
||||
public class CocoonForwardController {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(CocoonForwardController.class);
|
||||
|
||||
@RequestMapping
|
||||
public ModelAndView forwardRequest(HttpServletRequest request, HttpServletResponse response) throws SQLException {
|
||||
log.debug("CocoonForwardController!!!!!");
|
||||
return new ModelAndView(new CocoonView());
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,136 @@
|
||||
/**
|
||||
* 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.springmvc;
|
||||
|
||||
import org.apache.cocoon.servletservice.DynamicProxyRequestHandler;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.web.context.support.WebApplicationContextUtils;
|
||||
import org.springframework.web.servlet.View;
|
||||
|
||||
import javax.servlet.Servlet;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.lang.reflect.Proxy;
|
||||
import java.util.Arrays;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @author Fabio Bolognesi (fabio at atmire dot com)
|
||||
* @author Mark Diggory (markd at atmire dot com)
|
||||
* @author Ben Bosman (ben at atmire dot com)
|
||||
*/
|
||||
|
||||
|
||||
public class CocoonView implements View
|
||||
{
|
||||
/**
|
||||
* The startup date of the Spring application context used to setup the {@link #blockServletCollector}.
|
||||
*/
|
||||
long applicationContextStartDate;
|
||||
/**
|
||||
* The servlet collector bean
|
||||
*/
|
||||
Map blockServletCollector;
|
||||
|
||||
public CocoonView()
|
||||
{
|
||||
}
|
||||
|
||||
void getInterfaces(Set interfaces, Class clazz)
|
||||
{
|
||||
Class[] clazzInterfaces = clazz.getInterfaces();
|
||||
for (int i = 0; i < clazzInterfaces.length; i++)
|
||||
{
|
||||
//add all interfaces extended by this interface or directly
|
||||
//implemented by this class
|
||||
getInterfaces(interfaces, clazzInterfaces[i]);
|
||||
}
|
||||
|
||||
// the superclazz is null if class is instanceof Object, is
|
||||
// an interface, a primitive type or void
|
||||
Class superclazz = clazz.getSuperclass();
|
||||
if (superclazz != null)
|
||||
{
|
||||
//add all interfaces of the superclass to the list
|
||||
getInterfaces(interfaces, superclazz);
|
||||
}
|
||||
|
||||
interfaces.addAll(Arrays.asList(clazzInterfaces));
|
||||
}
|
||||
|
||||
public String getContentType()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public void render(Map<String, ?> model, HttpServletRequest request, HttpServletResponse response) throws Exception
|
||||
{
|
||||
|
||||
final Map mountableServlets = getBlockServletMap(request);
|
||||
|
||||
String path = request.getPathInfo();
|
||||
|
||||
if (path == null)
|
||||
{
|
||||
path = "";
|
||||
}
|
||||
|
||||
// find the servlet which mount path is the longest prefix of the path info
|
||||
int index = path.length();
|
||||
Servlet servlet = null;
|
||||
while (servlet == null && index != -1)
|
||||
{
|
||||
path = path.substring(0, index);
|
||||
servlet = (Servlet) mountableServlets.get(path);
|
||||
index = path.lastIndexOf('/');
|
||||
}
|
||||
//case when servlet is mounted at "/" must be handled separately
|
||||
servlet = servlet == null ? (Servlet) mountableServlets.get("/") : servlet;
|
||||
if (servlet == null)
|
||||
{
|
||||
String message = "No block for " + request.getPathInfo();
|
||||
response.sendError(HttpServletResponse.SC_NOT_FOUND, message);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Create a dynamic proxy class that overwrites the getServletPath and
|
||||
// getPathInfo methods to provide reasonable values in the called servlet
|
||||
// the dynamic proxy implements all interfaces of the original request
|
||||
HttpServletRequest prequest = (HttpServletRequest) Proxy.newProxyInstance(
|
||||
request.getClass().getClassLoader(),
|
||||
getInterfaces(request.getClass()),
|
||||
new DynamicProxyRequestHandler(request, path));
|
||||
|
||||
servlet.service(prequest, response);
|
||||
|
||||
}
|
||||
|
||||
Class[] getInterfaces(final Class clazz)
|
||||
{
|
||||
Set interfaces = new LinkedHashSet();
|
||||
getInterfaces(interfaces, clazz);
|
||||
return (Class[]) interfaces.toArray(new Class[interfaces.size()]);
|
||||
}
|
||||
|
||||
public Map getBlockServletMap(HttpServletRequest request)
|
||||
{
|
||||
ApplicationContext applicationContext = WebApplicationContextUtils.getRequiredWebApplicationContext(request.getSession(true).getServletContext());
|
||||
|
||||
if (this.blockServletCollector == null || applicationContext.getStartupDate() != this.applicationContextStartDate)
|
||||
{
|
||||
this.applicationContextStartDate = applicationContext.getStartupDate();
|
||||
this.blockServletCollector = (Map) applicationContext.getBean("org.apache.cocoon.servletservice.spring.BlockServletMap");
|
||||
}
|
||||
|
||||
return blockServletCollector;
|
||||
}
|
||||
}
|
@@ -0,0 +1,219 @@
|
||||
/**
|
||||
* 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.springmvc;
|
||||
|
||||
import org.dspace.app.xmlui.utils.ContextUtil;
|
||||
import org.dspace.content.DSpaceObject;
|
||||
import org.dspace.content.Item;
|
||||
|
||||
import org.dspace.core.Context;
|
||||
import org.dspace.identifier.IdentifierNotFoundException;
|
||||
import org.dspace.identifier.IdentifierNotResolvableException;
|
||||
import org.dspace.identifier.IdentifierService;
|
||||
import org.dspace.utils.DSpace;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.servlet.ModelAndView;
|
||||
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.sql.SQLException;
|
||||
|
||||
|
||||
/**
|
||||
* @author Fabio Bolognesi (fabio at atmire dot com)
|
||||
* @author Mark Diggory (markd at atmire dot com)
|
||||
* @author Ben Bosman (ben at atmire dot com)
|
||||
*/
|
||||
|
||||
@Controller
|
||||
@RequestMapping(value={"/handle","/resource"})
|
||||
|
||||
public class ResourceIdentifierController {
|
||||
|
||||
public static final String DSPACE_OBJECT = "dspace.object";
|
||||
private static final String RESOURCE = "/resource";
|
||||
private static final String METS = "mets";
|
||||
private static final String DRI = "DRI";
|
||||
|
||||
private static final int STATUS_OK=200;
|
||||
private static final int STATUS_FORBIDDEN=400;
|
||||
|
||||
@RequestMapping(method = {RequestMethod.GET, RequestMethod.HEAD},value={"/{prefix:.*}"})
|
||||
public String processHandle(HttpServletRequest request, @PathVariable String prefix) {
|
||||
//String resourceIdentifier=null;
|
||||
try {
|
||||
|
||||
//String requestUri = request.getRequestURI().toString();
|
||||
|
||||
//resourceIdentifier = requestUri.substring(requestUri.indexOf(RESOURCE) + RESOURCE.length() + 1);
|
||||
|
||||
Context context = ContextUtil.obtainContext(request);
|
||||
|
||||
IdentifierService dis = new DSpace().getSingletonService(IdentifierService.class);
|
||||
|
||||
if (dis == null)
|
||||
throw new RuntimeException("Cannot instantiate IdentifierService. Problem with spring configuration!");
|
||||
|
||||
DSpaceObject dso = dis.resolve(context, prefix);
|
||||
|
||||
if (dso == null) throw new RuntimeException("Cannot find Item!");
|
||||
|
||||
request.setAttribute(DSPACE_OBJECT, dso);
|
||||
|
||||
/** TODO: This is a temporary solution until we can adjust cocoon to not have a /handle URI */
|
||||
return "forward:/handle/" + dso.getHandle();
|
||||
|
||||
} catch (SQLException e) {
|
||||
return "forward:/error";
|
||||
|
||||
} catch (IdentifierNotResolvableException e) {
|
||||
return "forward:/tombstone";
|
||||
|
||||
} catch (IdentifierNotFoundException e) {
|
||||
request.setAttribute("identifier", prefix);
|
||||
return "forward:/identifier-not-found";
|
||||
}
|
||||
}
|
||||
|
||||
@RequestMapping("/**/mets.xml")
|
||||
public String processMETSHandle(HttpServletRequest request) {
|
||||
try {
|
||||
|
||||
String requestUri = request.getRequestURI().toString();
|
||||
|
||||
String resourceIdentifier = requestUri.substring(requestUri.indexOf(RESOURCE) + RESOURCE.length() + 1);
|
||||
resourceIdentifier = resourceIdentifier.substring(0, resourceIdentifier.indexOf(METS) - 1);
|
||||
|
||||
Context context = ContextUtil.obtainContext(request);
|
||||
|
||||
IdentifierService dis = new DSpace().getSingletonService(IdentifierService.class);
|
||||
|
||||
DSpaceObject dso = dis.resolve(context, resourceIdentifier);
|
||||
|
||||
if (dso == null) return null;
|
||||
|
||||
request.setAttribute(DSPACE_OBJECT, dso);
|
||||
|
||||
return "forward:/metadata/handle/" + dso.getHandle() + "/mets.xml";
|
||||
|
||||
} catch (SQLException e) {
|
||||
return "forward:/error";
|
||||
} catch (IdentifierNotResolvableException e) {
|
||||
return "forward:/tombstone";
|
||||
|
||||
} catch (IdentifierNotFoundException e) {
|
||||
return "forward:/identifier-not-found";
|
||||
}
|
||||
}
|
||||
|
||||
@RequestMapping("/**/DRI")
|
||||
public String processDRIHandle(HttpServletRequest request) {
|
||||
try {
|
||||
|
||||
String requestUri = request.getRequestURI().toString();
|
||||
|
||||
String resourceIdentifier = requestUri.substring(requestUri.indexOf(RESOURCE) + RESOURCE.length() + 1);
|
||||
resourceIdentifier = resourceIdentifier.substring(0, resourceIdentifier.indexOf(DRI) - 1);
|
||||
|
||||
Context context = ContextUtil.obtainContext(request);
|
||||
|
||||
IdentifierService dis = new DSpace().getSingletonService(IdentifierService.class);
|
||||
|
||||
DSpaceObject dso = dis.resolve(context, resourceIdentifier);
|
||||
|
||||
if (dso == null) return null;
|
||||
|
||||
request.setAttribute(DSPACE_OBJECT, dso);
|
||||
|
||||
return "forward:/DRI/handle/" + dso.getHandle();
|
||||
} catch (SQLException e) {
|
||||
return "forward:/error";
|
||||
|
||||
} catch (IdentifierNotResolvableException e) {
|
||||
return "forward:/tombstone";
|
||||
|
||||
} catch (IdentifierNotFoundException e) {
|
||||
return "forward:/identifier-not-found";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@RequestMapping("/{prefix}/{suffix}/citation/ris")
|
||||
public ModelAndView genRisRepresentation(@PathVariable String prefix, @PathVariable String suffix, HttpServletRequest request, HttpServletResponse response) {
|
||||
String resourceIdentifier = prefix + "/" + suffix;
|
||||
request.setAttribute(DSPACE_OBJECT, getDSO(request, resourceIdentifier));
|
||||
return new ModelAndView(new RisView(resourceIdentifier));
|
||||
}
|
||||
|
||||
@RequestMapping("/{prefix}/{suffix}/citation/bib")
|
||||
public ModelAndView genBibTexRepresentation(@PathVariable String prefix, @PathVariable String suffix, HttpServletRequest request, HttpServletResponse response) {
|
||||
String resourceIdentifier = prefix + "/" + suffix;
|
||||
request.setAttribute(DSPACE_OBJECT, getDSO(request, resourceIdentifier) );
|
||||
return new ModelAndView(new BibTexView(resourceIdentifier));
|
||||
}
|
||||
|
||||
|
||||
private DSpaceObject getDSO(HttpServletRequest request, String resourceIdentifier) {
|
||||
DSpaceObject dso=null;
|
||||
IdentifierService identifierService = new DSpace().getSingletonService(IdentifierService.class);
|
||||
Context context =null;
|
||||
try {
|
||||
context = new Context();
|
||||
context.turnOffAuthorisationSystem();
|
||||
dso = identifierService.resolve(context, resourceIdentifier);
|
||||
if(dso==null) throw new RuntimeException("Invalid DOI! " + resourceIdentifier);
|
||||
|
||||
return dso;
|
||||
}catch (IdentifierNotFoundException e) {
|
||||
throw new RuntimeException(e);
|
||||
|
||||
} catch (IdentifierNotResolvableException e) {
|
||||
throw new RuntimeException(e);
|
||||
} catch (SQLException e) {
|
||||
throw new RuntimeException(e);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private int validate(String resourceID, HttpServletRequest request){
|
||||
String token = request.getParameter("token");
|
||||
|
||||
if(token==null || "".equals(token)) return STATUS_FORBIDDEN;
|
||||
|
||||
if(resourceID==null || "".equals(resourceID)) return STATUS_FORBIDDEN;
|
||||
|
||||
// try to resolve DOI
|
||||
DSpaceObject dso=null;
|
||||
IdentifierService identifierService = new DSpace().getSingletonService(IdentifierService.class);
|
||||
Context context =null;
|
||||
try {
|
||||
context = new Context();
|
||||
context.turnOffAuthorisationSystem();
|
||||
dso = identifierService.resolve(context, resourceID);
|
||||
request.setAttribute(DSPACE_OBJECT, dso);
|
||||
|
||||
if(!(dso instanceof Item)) return STATUS_FORBIDDEN;
|
||||
|
||||
return STATUS_OK;
|
||||
|
||||
}catch (SQLException e) {
|
||||
return STATUS_FORBIDDEN;
|
||||
}catch (IdentifierNotFoundException e) {
|
||||
return STATUS_FORBIDDEN;
|
||||
|
||||
} catch (IdentifierNotResolvableException e) {
|
||||
return STATUS_FORBIDDEN;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,272 @@
|
||||
/**
|
||||
* 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.springmvc;
|
||||
|
||||
|
||||
import org.dspace.content.DCValue;
|
||||
import org.dspace.content.DSpaceObject;
|
||||
import org.dspace.content.Item;
|
||||
import org.dspace.core.Context;
|
||||
import org.dspace.identifier.IdentifierService;
|
||||
import org.dspace.utils.DSpace;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.web.servlet.View;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.io.PrintWriter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.StringTokenizer;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* @author Fabio Bolognesi (fabio at atmire dot com)
|
||||
* @author Mark Diggory (markd at atmire dot com)
|
||||
* @author Ben Bosman (ben at atmire dot com)
|
||||
*/
|
||||
|
||||
public class RisView implements View {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(RisView.class);
|
||||
private static final String EOL = "\r\n";
|
||||
|
||||
private String resourceIdentifier=null;
|
||||
|
||||
public RisView(String resourceIdentifier)
|
||||
{
|
||||
this.resourceIdentifier = resourceIdentifier;
|
||||
}
|
||||
|
||||
public String getContentType()
|
||||
{
|
||||
|
||||
return "text/plain;charset=utf-8";
|
||||
}
|
||||
|
||||
public void render(Map<String, ?> model, HttpServletRequest request, HttpServletResponse response) throws Exception {
|
||||
|
||||
DSpaceObject item = (DSpaceObject)request.getAttribute(ResourceIdentifierController.DSPACE_OBJECT);
|
||||
|
||||
Context context = new Context();
|
||||
context.turnOffAuthorisationSystem();
|
||||
|
||||
String fileName = getFileName(item);
|
||||
|
||||
write(response, getRIS((Item) item, resourceIdentifier), fileName);
|
||||
OutputStream aOutputStream = response.getOutputStream();
|
||||
aOutputStream.close();
|
||||
}
|
||||
|
||||
private String getFileName(DSpaceObject item)
|
||||
{
|
||||
String fileName = resourceIdentifier;
|
||||
if(resourceIdentifier.indexOf("/") !=-1)
|
||||
{
|
||||
fileName = resourceIdentifier.replaceAll("/", "_") + ".ris";
|
||||
}
|
||||
return fileName;
|
||||
}
|
||||
|
||||
private void write(HttpServletResponse aResponse, String aContent, String aFileName) throws IOException
|
||||
{
|
||||
aResponse.setContentType("text/plain;charset=utf-8");
|
||||
aResponse.setContentLength(aContent.length());
|
||||
aResponse.setHeader("Content-Disposition", "attachment; filename=\"" + aFileName + "\"");
|
||||
|
||||
// It's all over but the writing...
|
||||
PrintWriter writer = aResponse.getWriter();
|
||||
writer.print(aContent);
|
||||
writer.close();
|
||||
}
|
||||
|
||||
|
||||
private String getRIS(Item item, String resourceIdentifier)
|
||||
{
|
||||
StringBuilder builder = new StringBuilder("TY - DATA").append(EOL);
|
||||
|
||||
String[] dateParts = getDate(item);
|
||||
String title = getMetadataValue(item, "dc.title");
|
||||
String description = getMetadataValue(item, "dc.description");
|
||||
|
||||
String[] keywords = getKeywords(item);
|
||||
|
||||
|
||||
if (resourceIdentifier != null)
|
||||
{
|
||||
builder.append("ID - ").append(resourceIdentifier).append(EOL);
|
||||
}
|
||||
|
||||
if (title != null)
|
||||
{
|
||||
builder.append("T1 - ").append(title).append(EOL);
|
||||
}
|
||||
|
||||
for (String author : getAuthors(item)) {
|
||||
builder.append("AU - ").append(author).append(EOL);
|
||||
}
|
||||
|
||||
// Date for data package
|
||||
if (dateParts.length > 0)
|
||||
{
|
||||
int count = 3;
|
||||
|
||||
builder.append("Y1 - ");
|
||||
|
||||
if (dateParts.length < 3)
|
||||
{
|
||||
count = dateParts.length;
|
||||
}
|
||||
|
||||
for (int index = 0; index < count; index++) {
|
||||
builder.append(dateParts[index]).append("/");
|
||||
}
|
||||
|
||||
for (; count < 3; count++)
|
||||
{
|
||||
builder.append('/');
|
||||
}
|
||||
|
||||
builder.append(EOL);
|
||||
}
|
||||
|
||||
if (description != null)
|
||||
{
|
||||
builder.append("N2 - ").append(description).append(EOL);
|
||||
}
|
||||
|
||||
for (String keyword : keywords)
|
||||
{
|
||||
builder.append("KW - ").append(keyword).append(EOL);
|
||||
}
|
||||
|
||||
return builder.append("ER - ").append(EOL).toString();
|
||||
}
|
||||
|
||||
|
||||
private String[] getAuthors(Item aItem)
|
||||
{
|
||||
ArrayList<String> authors = new ArrayList<String>();
|
||||
|
||||
authors.addAll(getAuthors(aItem.getMetadata("dc.contributor.author")));
|
||||
authors.addAll(getAuthors(aItem.getMetadata("dc.creator")));
|
||||
authors.addAll(getAuthors(aItem.getMetadata("dc.contributor")));
|
||||
|
||||
return authors.toArray(new String[authors.size()]);
|
||||
}
|
||||
|
||||
private String[] getKeywords(Item aItem)
|
||||
{
|
||||
ArrayList<String> keywordList = new ArrayList<String>();
|
||||
|
||||
for (DCValue keyword : aItem.getMetadata("dc.subject"))
|
||||
{
|
||||
if (keyword.value.length() < 255)
|
||||
{
|
||||
keywordList.add(keyword.value);
|
||||
}
|
||||
}
|
||||
|
||||
for (DCValue keyword : aItem.getMetadata("dwc.ScientificName"))
|
||||
{
|
||||
if (keyword.value.length() < 255)
|
||||
{
|
||||
keywordList.add(keyword.value);
|
||||
}
|
||||
}
|
||||
|
||||
return keywordList.toArray(new String[keywordList.size()]);
|
||||
}
|
||||
|
||||
private String[] getDate(Item item)
|
||||
{
|
||||
StringTokenizer tokenizer;
|
||||
|
||||
for (DCValue date : item.getMetadata("dc.date.issued"))
|
||||
{
|
||||
tokenizer = new StringTokenizer(date.value, "-/ T");
|
||||
String[] dateParts = new String[tokenizer.countTokens()];
|
||||
|
||||
for (int index = 0; index < dateParts.length; index++)
|
||||
{
|
||||
dateParts[index] = tokenizer.nextToken();
|
||||
}
|
||||
|
||||
return dateParts;
|
||||
}
|
||||
|
||||
return new String[0];
|
||||
}
|
||||
|
||||
private String getMetadataValue(Item item, String metadatafield)
|
||||
{
|
||||
for (DCValue value : item.getMetadata(metadatafield))
|
||||
{
|
||||
return value.value;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private List<String> getAuthors(DCValue[] aMetadata)
|
||||
{
|
||||
ArrayList<String> authors = new ArrayList<String>();
|
||||
StringTokenizer tokenizer;
|
||||
|
||||
for (DCValue metadata : aMetadata)
|
||||
{
|
||||
StringBuilder builder = new StringBuilder();
|
||||
|
||||
if (metadata.value.indexOf(",") != -1)
|
||||
{
|
||||
String[] parts = metadata.value.split(",");
|
||||
|
||||
if (parts.length > 1)
|
||||
{
|
||||
tokenizer = new StringTokenizer(parts[1], ". ");
|
||||
builder.append(parts[0]).append(" ");
|
||||
|
||||
while (tokenizer.hasMoreTokens())
|
||||
{
|
||||
builder.append(tokenizer.nextToken().charAt(0));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
builder.append(metadata.value);
|
||||
}
|
||||
|
||||
authors.add(builder.toString());
|
||||
}
|
||||
// Now the minority case (as we've cleaned up data and input method)
|
||||
else
|
||||
{
|
||||
String[] parts = metadata.value.split("\\s+|\\.");
|
||||
String name = parts[parts.length - 1].replace("\\s+|\\.", "");
|
||||
|
||||
builder.append(name).append(" ");
|
||||
|
||||
for (int index = 0; index < parts.length - 1; index++)
|
||||
{
|
||||
if (parts[index].length() > 0)
|
||||
{
|
||||
name = parts[index].replace("\\s+|\\.", "");
|
||||
builder.append(name.charAt(0));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return authors;
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,141 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
|
||||
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/
|
||||
|
||||
-->
|
||||
|
||||
|
||||
<map:sitemap xmlns:map="http://apache.org/cocoon/sitemap/1.0">
|
||||
|
||||
<map:components>
|
||||
|
||||
<map:transformers>
|
||||
<map:transformer name="VersionHistoryForm" src="org.dspace.app.xmlui.aspect.versioning.VersionHistoryForm"/>
|
||||
<map:transformer name="VersionItemForm" src="org.dspace.app.xmlui.aspect.versioning.VersionItemForm"/>
|
||||
<map:transformer name="DeleteVersionsConfirm"
|
||||
src="org.dspace.app.xmlui.aspect.versioning.DeleteVersionsConfirm"/>
|
||||
<map:transformer name="RestoreVersionForm" src="org.dspace.app.xmlui.aspect.versioning.RestoreVersionForm"/>
|
||||
<map:transformer name="Navigation"
|
||||
src="org.dspace.app.xmlui.aspect.versioning.Navigation"/>
|
||||
<map:transformer name="VersionUpdateForm" src="org.dspace.app.xmlui.aspect.versioning.VersionUpdateForm"/>
|
||||
<map:transformer name="VersionNoticeTransformer" src="org.dspace.app.xmlui.aspect.versioning.VersionNoticeTransformer"/>
|
||||
</map:transformers>
|
||||
|
||||
<map:matchers default="wildcard">
|
||||
<map:matcher name="HandleTypeMatcher" src="org.dspace.app.xmlui.aspect.general.HandleTypeMatcher"/>
|
||||
<map:matcher name="HandleAuthorizedMatcher" src="org.dspace.app.xmlui.aspect.general.HandleAuthorizedMatcher"/>
|
||||
</map:matchers>
|
||||
|
||||
<map:selectors>
|
||||
<map:selector name="AuthenticatedSelector" src="org.dspace.app.xmlui.aspect.general.AuthenticatedSelector"/>
|
||||
</map:selectors>
|
||||
</map:components>
|
||||
|
||||
|
||||
<map:flow language="javascript">
|
||||
<map:script src="versioning.js"/>
|
||||
</map:flow>
|
||||
|
||||
<map:pipelines>
|
||||
|
||||
<map:pipeline>
|
||||
|
||||
|
||||
<map:select type="AuthenticatedSelector">
|
||||
<map:when test="eperson">
|
||||
<map:match pattern="item/version">
|
||||
<map:match type="request" pattern="versioning-continue">
|
||||
<map:call continuation="{1}"/>
|
||||
</map:match>
|
||||
|
||||
<map:match type="request" pattern="itemID">
|
||||
<map:call function="startCreateNewVersionItem"/>
|
||||
</map:match>
|
||||
</map:match>
|
||||
|
||||
<map:match pattern="item/versionhistory">
|
||||
<map:match type="request" pattern="versioning-continue">
|
||||
<map:call continuation="{1}"/>
|
||||
</map:match>
|
||||
|
||||
<map:match type="request" pattern="itemID">
|
||||
<map:call function="startVersionHistoryItem"/>
|
||||
</map:match>
|
||||
</map:match>
|
||||
</map:when>
|
||||
<map:otherwise>
|
||||
<map:match pattern="item/version">
|
||||
<map:act type="StartAuthentication"/>
|
||||
</map:match>
|
||||
|
||||
<map:match pattern="item/versionhistory">
|
||||
<map:act type="StartAuthentication"/>
|
||||
</map:match>
|
||||
</map:otherwise>
|
||||
</map:select>
|
||||
|
||||
<map:generate/>
|
||||
|
||||
<map:select type="AuthenticatedSelector">
|
||||
<map:when test="eperson">
|
||||
<map:transform type="Navigation"/>
|
||||
|
||||
<map:match pattern="item/version/create">
|
||||
<map:transform type="VersionItemForm">
|
||||
<map:parameter name="itemID" value="{flow-attribute:itemID}"/>
|
||||
<map:parameter name="summary" value="{flow-attribute:summary}"/>
|
||||
</map:transform>
|
||||
</map:match>
|
||||
|
||||
|
||||
<map:match pattern="item/versionhistory/show">
|
||||
<map:transform type="VersionHistoryForm">
|
||||
<map:parameter name="itemID" value="{flow-attribute:itemID}"/>
|
||||
</map:transform>
|
||||
</map:match>
|
||||
|
||||
<map:match pattern="item/versionhistory/delete">
|
||||
<map:transform type="DeleteVersionsConfirm">
|
||||
<map:parameter name="versionIDs" value="{flow-attribute:versionIDs}"/>
|
||||
</map:transform>
|
||||
</map:match>
|
||||
|
||||
<map:match pattern="item/versionhistory/restore">
|
||||
<map:transform type="RestoreVersionForm">
|
||||
<map:parameter name="itemID" value="{flow-attribute:itemID}"/>
|
||||
<map:parameter name="versionID" value="{flow-attribute:versionID}"/>
|
||||
</map:transform>
|
||||
</map:match>
|
||||
|
||||
<map:match pattern="item/versionhistory/update">
|
||||
<map:transform type="VersionUpdateForm">
|
||||
<map:parameter name="itemID" value="{flow-attribute:itemID}"/>
|
||||
<map:parameter name="versionID" value="{flow-attribute:versionID}"/>
|
||||
</map:transform>
|
||||
</map:match>
|
||||
</map:when>
|
||||
</map:select>
|
||||
|
||||
<map:match pattern="handle/*/*">
|
||||
<map:match type="HandleAuthorizedMatcher" pattern="READ">
|
||||
<map:match type="HandleTypeMatcher" pattern="item">
|
||||
<map:transform type="VersionNoticeTransformer" />
|
||||
|
||||
<map:transform type="VersionHistoryForm"/>
|
||||
</map:match>
|
||||
</map:match>
|
||||
</map:match>
|
||||
|
||||
|
||||
<map:serialize type="xml"/>
|
||||
</map:pipeline>
|
||||
|
||||
|
||||
</map:pipelines>
|
||||
|
||||
</map:sitemap>
|
@@ -0,0 +1,359 @@
|
||||
/*
|
||||
* 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/
|
||||
*/
|
||||
|
||||
importClass(Packages.java.lang.Class);
|
||||
importClass(Packages.java.lang.ClassLoader);
|
||||
|
||||
importClass(Packages.org.dspace.app.xmlui.utils.FlowscriptUtils);
|
||||
|
||||
importClass(Packages.org.dspace.app.xmlui.aspect.administrative.FlowResult);
|
||||
|
||||
importClass(Packages.org.apache.cocoon.environment.http.HttpEnvironment);
|
||||
importClass(Packages.org.apache.cocoon.servlet.multipart.Part);
|
||||
importClass(Packages.org.dspace.content.Item);
|
||||
|
||||
importClass(Packages.org.dspace.handle.HandleManager);
|
||||
importClass(Packages.org.dspace.core.Constants);
|
||||
importClass(Packages.org.dspace.authorize.AuthorizeManager);
|
||||
importClass(Packages.org.dspace.license.CreativeCommons);
|
||||
|
||||
importClass(Packages.org.dspace.app.xmlui.utils.ContextUtil);
|
||||
importClass(Packages.org.dspace.app.xmlui.cocoon.HttpServletRequestCocoonWrapper);
|
||||
importClass(Packages.org.dspace.app.xmlui.aspect.versioning.VersionManager);
|
||||
|
||||
importClass(Packages.org.dspace.submit.AbstractProcessingStep);
|
||||
|
||||
|
||||
|
||||
/* Global variable which stores a comma-separated list of all fields
|
||||
* which errored out during processing of the last step.
|
||||
*/
|
||||
var ERROR_FIELDS = null;
|
||||
|
||||
/**
|
||||
* Simple access method to access the current cocoon object model.
|
||||
*/
|
||||
function getObjectModel()
|
||||
{
|
||||
return FlowscriptUtils.getObjectModel(cocoon);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the DSpace context for this request since each HTTP request generates
|
||||
* a new context this object should never be stored and instead allways accessed
|
||||
* through this method so you are ensured that it is the correct one.
|
||||
*/
|
||||
function getDSContext()
|
||||
{
|
||||
return ContextUtil.obtainContext(getObjectModel());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the HTTP Request object for this request
|
||||
*/
|
||||
function getHttpRequest()
|
||||
{
|
||||
//return getObjectModel().get(HttpEnvironment.HTTP_REQUEST_OBJECT)
|
||||
|
||||
// Cocoon's request object handles form encoding, thus if the users enters
|
||||
// non-ascii characters such as those found in foriegn languages they will
|
||||
// come through corruped if they are not obtained through the cocoon request
|
||||
// object. However, since the dspace-api is built to accept only HttpServletRequest
|
||||
// a wrapper class HttpServletRequestCocoonWrapper has bee built to translate
|
||||
// the cocoon request back into a servlet request. This is not a fully complete
|
||||
// translation as some methods are unimplemeted. But it is enough for our
|
||||
// purposes here.
|
||||
return new HttpServletRequestCocoonWrapper(getObjectModel());
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the HTTP Response object for the response
|
||||
* (used for compatibility with DSpace configurable submission system)
|
||||
*/
|
||||
function getHttpResponse()
|
||||
{
|
||||
return getObjectModel().get(HttpEnvironment.HTTP_RESPONSE_OBJECT);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Start editing an individual item.
|
||||
*/
|
||||
function startCreateNewVersionItem(){
|
||||
var itemID = cocoon.request.get("itemID");
|
||||
|
||||
assertEditItem(itemID);
|
||||
|
||||
var result= new FlowResult();
|
||||
do{
|
||||
result = doCreateNewVersion(itemID, result);
|
||||
}while(result!=null);
|
||||
|
||||
var item = Item.find(getDSContext(),itemID);
|
||||
|
||||
//Send us back to the item page if we cancel !
|
||||
cocoon.redirectTo(cocoon.request.getContextPath() + "/handle/" + item.getHandle(), true);
|
||||
getDSContext().complete();
|
||||
item = null;
|
||||
cocoon.exit();
|
||||
}
|
||||
|
||||
/*
|
||||
* Move this item to another collection
|
||||
*/
|
||||
function doCreateNewVersion(itemID, result){
|
||||
assertEditItem(itemID);
|
||||
do {
|
||||
sendPageAndWait("item/version/create",{"itemID":itemID, "summary":result.getParameter("summary")}, result);
|
||||
|
||||
if (cocoon.request.get("submit_cancel")){
|
||||
return null;
|
||||
}
|
||||
else if (cocoon.request.get("submit_version")){
|
||||
var summary = cocoon.request.get("summary");
|
||||
assertEditItem(itemID);
|
||||
result = VersionManager.processCreateNewVersion(getDSContext(),itemID, summary);
|
||||
|
||||
var wsid = result.getParameter("wsid");
|
||||
cocoon.redirectTo(cocoon.request.getContextPath()+"/submit?workspaceID=" + wsid,true);
|
||||
cocoon.exit();
|
||||
}
|
||||
else if (cocoon.request.get("submit_update_version")){
|
||||
var summary = cocoon.request.get("summary");
|
||||
assertEditItem(itemID);
|
||||
result = VersionManager.processUpdateVersion(getDSContext(),itemID, summary);
|
||||
}
|
||||
} while (result == null || !result.getContinue());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Start editing an individual item.
|
||||
*/
|
||||
function startVersionHistoryItem(){
|
||||
var itemID = cocoon.request.get("itemID");
|
||||
|
||||
assertEditItem(itemID);
|
||||
|
||||
var result= new FlowResult();
|
||||
do{
|
||||
result=doVersionHistoryItem(itemID, result);
|
||||
}while(result!=null);
|
||||
}
|
||||
|
||||
function doVersionHistoryItem(itemID, result){
|
||||
//var result;
|
||||
do {
|
||||
sendPageAndWait("item/versionhistory/show",{"itemID":itemID},result);
|
||||
assertEditItem(itemID);
|
||||
result = null;
|
||||
|
||||
if (cocoon.request.get("submit_cancel")){
|
||||
//Pressed the cancel button, redirect us to the item page
|
||||
var item = Item.find(getDSContext(),itemID);
|
||||
|
||||
cocoon.redirectTo(cocoon.request.getContextPath()+"/handle/"+item.getHandle(),true);
|
||||
getDSContext().complete();
|
||||
item = null;
|
||||
cocoon.exit();
|
||||
}
|
||||
else if (cocoon.request.get("submit_delete") && cocoon.request.get("remove")){
|
||||
var versionIDs = cocoon.request.getParameterValues("remove");
|
||||
result = doDeleteVersions(itemID, versionIDs);
|
||||
if(result != null){
|
||||
if(result.getParameter("itemID") == null){
|
||||
// We have removed everything, redirect us to the home page !
|
||||
cocoon.redirectTo(cocoon.request.getContextPath(), true);
|
||||
getDSContext().complete();
|
||||
cocoon.exit();
|
||||
}else{
|
||||
//Perhaps we have a new item (if we deleted the current version)
|
||||
itemID = result.getParameter("itemID");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
else if (cocoon.request.get("submit_restore") && cocoon.request.get("versionID")){
|
||||
var versionID = cocoon.request.get("versionID");
|
||||
itemID = cocoon.request.get("itemID");
|
||||
|
||||
result = doRestoreVersion(itemID, versionID);
|
||||
}
|
||||
else if (cocoon.request.get("submit_update") && cocoon.request.get("versionID")){
|
||||
var versionID = cocoon.request.get("versionID");
|
||||
itemID = cocoon.request.get("itemID");
|
||||
result = doUpdateVersion(itemID, versionID);
|
||||
}
|
||||
} while (true)
|
||||
}
|
||||
|
||||
/**
|
||||
* Confirm and delete the given version(s)
|
||||
*/
|
||||
function doDeleteVersions(itemID, versionIDs){
|
||||
|
||||
sendPageAndWait("item/versionhistory/delete",{"itemID":itemID,"versionIDs":versionIDs.join(',')});
|
||||
|
||||
if (cocoon.request.get("submit_cancel")){
|
||||
return null;
|
||||
}
|
||||
else if (cocoon.request.get("submit_confirm")){
|
||||
return VersionManager.processDeleteVersions(getDSContext(), itemID, versionIDs);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Restore the given version
|
||||
*/
|
||||
function doRestoreVersion(itemID, versionID){
|
||||
var result;
|
||||
do {
|
||||
sendPageAndWait("item/versionhistory/restore", {"itemID":itemID,"versionID":versionID}, result);
|
||||
result = null;
|
||||
if (cocoon.request.get("submit_cancel"))
|
||||
return null;
|
||||
|
||||
else if (cocoon.request.get("submit_restore")){
|
||||
var summary = cocoon.request.get("summary");
|
||||
result = VersionManager.processRestoreVersion(getDSContext(),versionID, summary);
|
||||
}
|
||||
|
||||
|
||||
} while (result == null || ! result.getContinue())
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Update the given version
|
||||
*/
|
||||
function doUpdateVersion(itemID, versionID){
|
||||
var result;
|
||||
do {
|
||||
sendPageAndWait("item/versionhistory/update", {"itemID":itemID,"versionID":versionID}, result);
|
||||
result = null;
|
||||
if (cocoon.request.get("submit_cancel")){
|
||||
return null;
|
||||
}
|
||||
else if (cocoon.request.get("submit_update")){
|
||||
var summary = cocoon.request.get("summary");
|
||||
result = VersionManager.processUpdateVersion(getDSContext(),itemID, summary);
|
||||
}
|
||||
|
||||
|
||||
} while (result == null || ! result.getContinue())
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Assert that the currently authenticated eperson can edit this item, if they can
|
||||
* not then this method will never return.
|
||||
*/
|
||||
function assertEditItem(itemID) {
|
||||
|
||||
if ( ! canEditItem(itemID)) {
|
||||
sendPage("admin/not-authorized");
|
||||
cocoon.exit();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return weather the currently authenticated eperson can edit the identified item.
|
||||
*/
|
||||
function canEditItem(itemID)
|
||||
{
|
||||
// Navigation already deals with loading the right operation. return always true.
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
function sendPageAndWait(uri,bizData,result)
|
||||
{
|
||||
if (bizData == null)
|
||||
bizData = {};
|
||||
|
||||
if (result != null)
|
||||
{
|
||||
var outcome = result.getOutcome();
|
||||
var header = result.getHeader();
|
||||
var message = result.getMessage();
|
||||
var characters = result.getCharacters();
|
||||
|
||||
if (message != null || characters != null)
|
||||
{
|
||||
bizData["notice"] = "true";
|
||||
bizData["outcome"] = outcome;
|
||||
bizData["header"] = header;
|
||||
bizData["message"] = message;
|
||||
bizData["characters"] = characters;
|
||||
}
|
||||
|
||||
var errors = result.getErrorString();
|
||||
if (errors != null)
|
||||
{
|
||||
bizData["errors"] = errors;
|
||||
}
|
||||
}
|
||||
|
||||
// just to remember where we came from.
|
||||
bizData["flow"] = "true";
|
||||
cocoon.sendPageAndWait(uri,bizData);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send the given page and DO NOT wait for the flow to be continued. Excution will
|
||||
* proccede as normal. This method will preform two usefull actions: set the flow
|
||||
* parameter & add result information.
|
||||
*
|
||||
* The flow parameter is used by the sitemap to seperate requests comming from a
|
||||
* flow script from just normal urls.
|
||||
*
|
||||
* The result object could potentialy contain a notice message and a list of
|
||||
* errors. If either of these are present then they are added to the sitemap's
|
||||
* parameters.
|
||||
*/
|
||||
function sendPage(uri,bizData,result)
|
||||
{
|
||||
if (bizData == null)
|
||||
bizData = {};
|
||||
|
||||
if (result != null)
|
||||
{
|
||||
var outcome = result.getOutcome();
|
||||
var header = result.getHeader();
|
||||
var message = result.getMessage();
|
||||
var characters = result.getCharacters();
|
||||
|
||||
if (message != null || characters != null)
|
||||
{
|
||||
bizData["notice"] = "true";
|
||||
bizData["outcome"] = outcome;
|
||||
bizData["header"] = header;
|
||||
bizData["message"] = message;
|
||||
bizData["characters"] = characters;
|
||||
}
|
||||
|
||||
var errors = result.getErrorString();
|
||||
if (errors != null)
|
||||
{
|
||||
bizData["errors"] = errors;
|
||||
}
|
||||
}
|
||||
|
||||
// just to remember where we came from.
|
||||
bizData["flow"] = "true";
|
||||
cocoon.sendPage(uri,bizData);
|
||||
}
|
@@ -0,0 +1,65 @@
|
||||
<?xml version="1.0" encoding="windows-1252"?>
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:p="http://www.springframework.org/schema/p"
|
||||
xmlns:context="http://www.springframework.org/schema/context"
|
||||
xmlns:mvc="http://www.springframework.org/schema/mvc"
|
||||
xmlns:aop="http://www.springframework.org/schema/aop"
|
||||
xmlns:tx="http://www.springframework.org/schema/tx"
|
||||
xsi:schemaLocation="
|
||||
http://www.springframework.org/schema/beans
|
||||
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
|
||||
http://www.springframework.org/schema/context
|
||||
http://www.springframework.org/schema/context/spring-context-3.0.xsd
|
||||
http://www.springframework.org/schema/mvc
|
||||
http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd
|
||||
http://www.springframework.org/schema/aop
|
||||
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
|
||||
http://www.springframework.org/schema/tx
|
||||
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">
|
||||
|
||||
<!-- Use @Component annotations for bean definitions -->
|
||||
<context:component-scan base-package="org.dspace.springmvc"/>
|
||||
|
||||
<!-- Use @Controller annotations for MVC controller definitions -->
|
||||
<mvc:annotation-driven />
|
||||
|
||||
<!-- Add JPA support -->
|
||||
<!--bean id="emf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
|
||||
<property name="loadTimeWeaver">
|
||||
<bean class="org.springframework.instrument.classloading.InstrumentationLoadTimeWeaver"/>
|
||||
</property>
|
||||
</bean-->
|
||||
|
||||
<!-- Add Transaction support -->
|
||||
<!--bean id="myTxManager" class="org.springframework.orm.jpa.JpaTransactionManager">
|
||||
<property name="entityManagerFactory" ref="emf"/>
|
||||
</bean-->
|
||||
|
||||
<!-- Use @Transaction annotations for managing transactions -->
|
||||
<!--tx:annotation-driven transaction-manager="myTxManager" /-->
|
||||
|
||||
<!-- View resolver
|
||||
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
|
||||
<property name="prefix" value="/WEB-INF/"/>
|
||||
</bean>
|
||||
-->
|
||||
|
||||
<!--
|
||||
Map standard URLs to Spring WebMVC Controllers.
|
||||
|
||||
<bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
|
||||
<property name="alwaysUseFullPath">
|
||||
<value>true</value>
|
||||
</property>
|
||||
</bean>
|
||||
-->
|
||||
<!-- Default to DefaultSpringController -->
|
||||
<bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping">
|
||||
<property name="defaultHandler" ref="cocoonForwardController"/>
|
||||
</bean>
|
||||
|
||||
|
||||
|
||||
|
||||
</beans>
|
@@ -127,17 +127,17 @@
|
||||
-->
|
||||
<filter-mapping>
|
||||
<filter-name>CocoonMultipartFilter</filter-name>
|
||||
<servlet-name>Cocoon</servlet-name>
|
||||
<servlet-name>spring</servlet-name>
|
||||
</filter-mapping>
|
||||
|
||||
<filter-mapping>
|
||||
<filter-name>DSpaceCocoonServletFilter</filter-name>
|
||||
<servlet-name>Cocoon</servlet-name>
|
||||
<servlet-name>spring</servlet-name>
|
||||
</filter-mapping>
|
||||
|
||||
<filter-mapping>
|
||||
<filter-name>SetCharacterEncoding</filter-name>
|
||||
<servlet-name>Cocoon</servlet-name>
|
||||
<servlet-name>spring</servlet-name>
|
||||
</filter-mapping>
|
||||
|
||||
<!--
|
||||
@@ -188,15 +188,23 @@
|
||||
Servlet Configuration ==========================================
|
||||
-->
|
||||
|
||||
<servlet>
|
||||
<!--servlet>
|
||||
<description>Cocoon</description>
|
||||
<display-name>Cocoon</display-name>
|
||||
<servlet-name>Cocoon</servlet-name>
|
||||
<servlet-class>org.apache.cocoon.servletservice.DispatcherServlet</servlet-class>
|
||||
<servlet-class>org.apache.cocoon.servletservice.DispatcherServlet</servlet-class-->
|
||||
<!--
|
||||
This parameter allows you to startup Cocoon2 immediately after startup
|
||||
of your servlet engine.
|
||||
-->
|
||||
<!--load-on-startup>1</load-on-startup>
|
||||
</servlet-->
|
||||
|
||||
|
||||
<!-- Spring Servlet -->
|
||||
<servlet>
|
||||
<servlet-name>spring</servlet-name>
|
||||
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
|
||||
<load-on-startup>1</load-on-startup>
|
||||
</servlet>
|
||||
|
||||
@@ -209,7 +217,7 @@
|
||||
to change this parameter.
|
||||
-->
|
||||
<servlet-mapping>
|
||||
<servlet-name>Cocoon</servlet-name>
|
||||
<servlet-name>spring</servlet-name>
|
||||
<url-pattern>/*</url-pattern>
|
||||
</servlet-mapping>
|
||||
|
||||
@@ -218,7 +226,7 @@
|
||||
by '/' mapping, but must be overriden explicitly.
|
||||
-->
|
||||
<servlet-mapping>
|
||||
<servlet-name>Cocoon</servlet-name>
|
||||
<servlet-name>spring</servlet-name>
|
||||
<url-pattern>*.jsp</url-pattern>
|
||||
</servlet-mapping>
|
||||
<!--
|
||||
@@ -226,7 +234,7 @@
|
||||
by '/' mapping, but must be overriden explicitly.
|
||||
-->
|
||||
<servlet-mapping>
|
||||
<servlet-name>Cocoon</servlet-name>
|
||||
<servlet-name>spring</servlet-name>
|
||||
<url-pattern>*.html</url-pattern>
|
||||
</servlet-mapping>
|
||||
|
||||
|
@@ -2163,4 +2163,68 @@
|
||||
<message key="xmlui.mobile.items_in_google_scholar">Items in Google Scholar</message>
|
||||
<message key="xmlui.mobile.download">Download</message>
|
||||
|
||||
|
||||
<!-- Versioning -->
|
||||
<message key="xmlui.aspect.versioning.VersioningNavigation.context_create_version">Create version of this item</message>
|
||||
<message key="xmlui.aspect.versioning.VersioningNavigation.context_show_version_history">Show version history</message>
|
||||
|
||||
<message key="xmlui.aspect.versioning.VersionItemForm.title">Create Version</message>
|
||||
<message key="xmlui.aspect.versioning.VersionItemForm.trail">Version</message>
|
||||
<message key="xmlui.aspect.versioning.VersionItemForm.head1">Create new version of item: {0}</message>
|
||||
<message key="xmlui.aspect.versioning.VersionItemForm.submit_version">Version</message>
|
||||
<message key="xmlui.aspect.versioning.VersionItemForm.submit_update_version">Update Version</message>
|
||||
<message key="xmlui.aspect.versioning.VersionItemForm.summary">Reason for creating new version</message>
|
||||
|
||||
<message key="xmlui.aspect.versioning.VersionUpdateForm.title">Update Version</message>
|
||||
<message key="xmlui.aspect.versioning.VersionUpdateForm.trail">Version</message>
|
||||
<message key="xmlui.aspect.versioning.VersionUpdateForm.head1">Update version of item: {0}</message>
|
||||
<message key="xmlui.aspect.versioning.VersionUpdateForm.submit_version">Version</message>
|
||||
<message key="xmlui.aspect.versioning.VersionUpdateForm.submit_update_version">Update Version</message>
|
||||
<message key="xmlui.aspect.versioning.VersionUpdateForm.summary">Summary</message>
|
||||
|
||||
|
||||
<message key="xmlui.aspect.versioning.DeleteVersionsConfirm.title">Confirm Deletion</message>
|
||||
<message key="xmlui.aspect.versioning.DeleteVersionsConfirm.trail">Confirm deletion</message>
|
||||
<message key="xmlui.aspect.versioning.DeleteVersionsConfirm.head1">Confirm Deletion(s)</message>
|
||||
<message key="xmlui.aspect.versioning.DeleteVersionsConfirm.para1">Are you sure you want to delete these versions. </message>
|
||||
<message key="xmlui.aspect.versioning.DeleteVersionsConfirm.para2">PLEASE NOTE: That by deleting these versions, the associated items will no longer be accessible.</message>
|
||||
<message key="xmlui.aspect.versioning.DeleteVersionsConfirm.column1">Version</message>
|
||||
<message key="xmlui.aspect.versioning.DeleteVersionsConfirm.column2">Item</message>
|
||||
<message key="xmlui.aspect.versioning.DeleteVersionsConfirm.column3">Editor</message>
|
||||
<message key="xmlui.aspect.versioning.DeleteVersionsConfirm.column4">Date</message>
|
||||
<message key="xmlui.aspect.versioning.DeleteVersionsConfirm.column5">Summary</message>
|
||||
|
||||
|
||||
<message key="xmlui.aspect.versioning.RestoreVersionForm.title">Restore Version</message>
|
||||
<message key="xmlui.aspect.versioning.RestoreVersionForm.trail">Restore Version</message>
|
||||
<message key="xmlui.aspect.versioning.RestoreVersionForm.head1">Restore Version</message>
|
||||
<message key="xmlui.aspect.versioning.RestoreVersionForm.para1">Are you sure you want to restore this version:</message>
|
||||
<message key="xmlui.aspect.versioning.RestoreVersionForm.column1">Version</message>
|
||||
<message key="xmlui.aspect.versioning.RestoreVersionForm.column2">Editor</message>
|
||||
<message key="xmlui.aspect.versioning.RestoreVersionForm.column3">Date</message>
|
||||
<message key="xmlui.aspect.versioning.RestoreVersionForm.column4">Summary</message>
|
||||
<message key="xmlui.aspect.versioning.RestoreVersionForm.restore">Restore</message>
|
||||
|
||||
<message key="xmlui.aspect.versioning.VersionHistoryForm.title">Version History</message>
|
||||
<message key="xmlui.aspect.versioning.VersionHistoryForm.trail">Version history</message>
|
||||
<message key="xmlui.aspect.versioning.VersionHistoryForm.head2">Version History</message>
|
||||
<message key="xmlui.aspect.versioning.VersionHistoryForm.column1">Version</message>
|
||||
<message key="xmlui.aspect.versioning.VersionHistoryForm.column2">Item</message>
|
||||
<message key="xmlui.aspect.versioning.VersionHistoryForm.column3">Editor</message>
|
||||
<message key="xmlui.aspect.versioning.VersionHistoryForm.column4">Date</message>
|
||||
<message key="xmlui.aspect.versioning.VersionHistoryForm.column5">Summary</message>
|
||||
<message key="xmlui.aspect.versioning.VersionHistoryForm.column6">Actions</message>
|
||||
<message key="xmlui.aspect.versioning.VersionHistoryForm.restore">Restore</message>
|
||||
<message key="xmlui.aspect.versioning.VersionHistoryForm.update">Update</message>
|
||||
<message key="xmlui.aspect.versioning.VersionHistoryForm.legend">*Selected version</message>
|
||||
<message key="xmlui.aspect.versioning.VersionHistoryForm.delete">Delete Versions</message>
|
||||
<message key="xmlui.aspect.versioning.VersionHistoryForm.return">Return</message>
|
||||
<message key="xmlui.aspect.versioning.VersionHistoryForm.collection_admins_only">(collection administrators only)</message>
|
||||
|
||||
<message key="xmlui.aspect.versioning.VersionNoticeTransformer.notice.new_version_head">Notice</message>
|
||||
<message key="xmlui.aspect.versioning.VersionNoticeTransformer.notice.new_version_help">This is not the latest version of this item. The latest version can be found at: </message>
|
||||
<message key="xmlui.aspect.versioning.VersionNoticeTransformer.notice.workflow_version_head">Notice</message>
|
||||
<message key="xmlui.aspect.versioning.VersionNoticeTransformer.notice.workflow_version_help">A more recent version of this item is in the Workflow.</message>
|
||||
|
||||
<!-- End Versioning -->
|
||||
</catalogue>
|
||||
|
@@ -631,9 +631,9 @@ event.dispatcher.default.class = org.dspace.event.BasicDispatcher
|
||||
|
||||
#
|
||||
# uncomment below and comment out original property to enable discovery indexing
|
||||
# event.dispatcher.default.consumers = search, browse, discovery, eperson, harvester
|
||||
# event.dispatcher.default.consumers = versioning, search, browse, discovery, eperson, harvester
|
||||
#
|
||||
event.dispatcher.default.consumers = search, browse, eperson, harvester
|
||||
event.dispatcher.default.consumers = versioning, search, browse, eperson, harvester
|
||||
|
||||
# The noindex dispatcher will not create search or browse indexes (useful for batch item imports)
|
||||
event.dispatcher.noindex.class = org.dspace.event.BasicDispatcher
|
||||
@@ -663,6 +663,10 @@ event.consumer.harvester.filters = Item+Delete
|
||||
#event.consumer.test.class = org.dspace.event.TestConsumer
|
||||
#event.consumer.test.filters = All+All
|
||||
|
||||
# consumer to maintain versions
|
||||
event.consumer.versioning.class = org.dspace.versioning.VersioningConsumer
|
||||
event.consumer.versioning.filters = Item+Install
|
||||
|
||||
# ...set to true to enable testConsumer messages to standard output
|
||||
#testConsumer.verbose = true
|
||||
|
||||
|
10
dspace/config/modules/versioning.cfg
Normal file
10
dspace/config/modules/versioning.cfg
Normal file
@@ -0,0 +1,10 @@
|
||||
#---------------------------------------------------#
|
||||
#------------ VERSIONING CONFIGURATIONS ------------#
|
||||
#---------------------------------------------------#
|
||||
# These configs are used by the versioning system #
|
||||
#---------------------------------------------------#
|
||||
|
||||
# Control if the history overview of an item should only be shown to administrators
|
||||
# If enabled only the administrators for the item will be able to view the versioning history
|
||||
# If disabled anyone with READ permissions on the item will be able to view the versioning history
|
||||
item.history.view.admin=false
|
31
dspace/config/spring/api/identifier-service.xml
Normal file
31
dspace/config/spring/api/identifier-service.xml
Normal file
@@ -0,0 +1,31 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
|
||||
Copyright (c) 2002-2010, DuraSpace. All rights reserved
|
||||
Licensed under the DuraSpace License.
|
||||
|
||||
A copy of the DuraSpace License has been included in this
|
||||
distribution and is available at: http://www.dspace.org/license
|
||||
|
||||
-->
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans
|
||||
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
|
||||
|
||||
<!-- Identifier Service Application Interface. Will be autowired with
|
||||
any Identifier Providers present in Spring context.
|
||||
-->
|
||||
<bean id="org.dspace.identifier.IdentifierService"
|
||||
class="org.dspace.identifier.IdentifierServiceImpl"
|
||||
autowire="byType"
|
||||
scope="singleton"/>
|
||||
|
||||
|
||||
<!-- provider for using the versioned handle identifier instead of the default one. -->
|
||||
<!--<bean id="org.dspace.identifier.HandleIdentifierProvider" class="org.dspace.identifier.VersionedHandleIdentifierProvider"-->
|
||||
<!--scope="singleton">-->
|
||||
<!--<property name="configurationService" ref="org.dspace.services.ConfigurationService"/>-->
|
||||
<!--</bean>-->
|
||||
|
||||
</beans>
|
39
dspace/config/spring/api/versioning-service.xml
Normal file
39
dspace/config/spring/api/versioning-service.xml
Normal file
@@ -0,0 +1,39 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
|
||||
Copyright (c) 2002-2010, DuraSpace. All rights reserved
|
||||
Licensed under the DuraSpace License.
|
||||
|
||||
A copy of the DuraSpace License has been included in this
|
||||
distribution and is available at: http://www.dspace.org/license
|
||||
|
||||
-->
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans
|
||||
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
|
||||
|
||||
|
||||
<!-- Versioning Service Application Interface for DSpace Will be autowired with
|
||||
a Versioning Provider present in Spring context.
|
||||
Default Item Versioning Provider, defines behavior for replicating
|
||||
Item, Metadata, BUndles and Bitstreams. Autowired at this time.
|
||||
|
||||
<bean id="org.dspace.versioning.VersioningService"
|
||||
class="org.dspace.versioning.VersioningServiceImpl"
|
||||
autowire="byType"
|
||||
scope="singleton">
|
||||
<property name="versionDAO">
|
||||
<bean class="org.dspace.versioning.VersionDAO"/>
|
||||
</property>
|
||||
<property name="versionHistoryDAO">
|
||||
<bean class="org.dspace.versioning.VersionHistoryDAO"/>
|
||||
</property>
|
||||
<property name="provider">
|
||||
|
||||
<bean class="org.dspace.versioning.DefaultItemVersionProvider"/>
|
||||
</property>
|
||||
|
||||
</bean>
|
||||
-->
|
||||
</beans>
|
@@ -64,6 +64,7 @@
|
||||
BrowseArtifacts, SearchArtifacts
|
||||
<aspect name="Artifact Browser" path="resource://aspects/ArtifactBrowser/" />
|
||||
-->
|
||||
<aspect name="Versioning Aspect" path="resource://aspects/Versioning/" />
|
||||
<aspect name="Displaying Artifacts" path="resource://aspects/ViewArtifacts/" />
|
||||
<aspect name="Browsing Artifacts" path="resource://aspects/BrowseArtifacts/" />
|
||||
<aspect name="Searching Artifacts" path="resource://aspects/SearchArtifacts/" />
|
||||
|
@@ -788,6 +788,25 @@ CREATE TABLE harvested_item
|
||||
CREATE INDEX harvested_item_fk_idx ON harvested_item(item_id);
|
||||
|
||||
|
||||
CREATE TABLE versionhistory
|
||||
(
|
||||
versionhistory_id INTEGER NOT NULL PRIMARY KEY
|
||||
);
|
||||
|
||||
CREATE TABLE versionitem
|
||||
(
|
||||
versionitem_id INTEGER NOT NULL PRIMARY KEY,
|
||||
item_id INTEGER REFERENCES Item(item_id),
|
||||
version_number INTEGER,
|
||||
eperson_id INTEGER REFERENCES EPerson(eperson_id),
|
||||
version_date TIMESTAMP,
|
||||
version_summary VARCHAR(255),
|
||||
versionhistory_id INTEGER REFERENCES VersionHistory(versionhistory_id)
|
||||
);
|
||||
|
||||
CREATE SEQUENCE versionitem_seq;
|
||||
CREATE SEQUENCE versionhistory_seq;
|
||||
|
||||
|
||||
|
||||
|
||||
|
@@ -70,6 +70,8 @@ CREATE SEQUENCE group2group_seq;
|
||||
CREATE SEQUENCE group2groupcache_seq;
|
||||
CREATE SEQUENCE harvested_collection_seq;
|
||||
CREATE SEQUENCE harvested_item_seq;
|
||||
CREATE SEQUENCE versionitem_seq;
|
||||
CREATE SEQUENCE versionhistory_seq;
|
||||
|
||||
-------------------------------------------------------
|
||||
-- BitstreamFormatRegistry table
|
||||
@@ -739,3 +741,19 @@ CREATE TABLE harvested_item
|
||||
);
|
||||
|
||||
CREATE INDEX harvested_item_fk_idx ON harvested_item(item_id);
|
||||
|
||||
CREATE TABLE versionhistory
|
||||
(
|
||||
versionhistory_id INTEGER NOT NULL PRIMARY KEY
|
||||
);
|
||||
|
||||
CREATE TABLE versionitem
|
||||
(
|
||||
versionitem_id INTEGER NOT NULL PRIMARY KEY,
|
||||
item_id INTEGER REFERENCES Item(item_id),
|
||||
version_number INTEGER,
|
||||
eperson_id INTEGER REFERENCES EPerson(eperson_id),
|
||||
version_date TIMESTAMP,
|
||||
version_summary VARCHAR2(255),
|
||||
versionhistory_id INTEGER REFERENCES VersionHistory(versionhistory_id)
|
||||
);
|
||||
|
@@ -30,3 +30,22 @@ ALTER TABLE resourcepolicy
|
||||
|
||||
|
||||
ALTER TABLE item ADD discoverable NUMBER(1);
|
||||
|
||||
CREATE TABLE versionhistory
|
||||
(
|
||||
versionhistory_id INTEGER NOT NULL PRIMARY KEY
|
||||
);
|
||||
|
||||
CREATE TABLE versionitem
|
||||
(
|
||||
versionitem_id INTEGER NOT NULL PRIMARY KEY,
|
||||
item_id INTEGER REFERENCES Item(item_id),
|
||||
version_number INTEGER,
|
||||
eperson_id INTEGER REFERENCES EPerson(eperson_id),
|
||||
version_date TIMESTAMP,
|
||||
version_summary VARCHAR2(255),
|
||||
versionhistory_id INTEGER REFERENCES VersionHistory(versionhistory_id)
|
||||
);
|
||||
|
||||
CREATE SEQUENCE versionitem_seq;
|
||||
CREATE SEQUENCE versionhistory_seq;
|
||||
|
@@ -107,6 +107,8 @@ CREATE SEQUENCE group2group_seq;
|
||||
CREATE SEQUENCE group2groupcache_seq;
|
||||
CREATE SEQUENCE harvested_collection_seq;
|
||||
CREATE SEQUENCE harvested_item_seq;
|
||||
CREATE SEQUENCE versionitem_seq;
|
||||
CREATE SEQUENCE versionhistory_seq;
|
||||
|
||||
-------------------------------------------------------
|
||||
-- BitstreamFormatRegistry table
|
||||
@@ -780,6 +782,24 @@ CREATE INDEX harvested_item_fk_idx ON harvested_item(item_id);
|
||||
|
||||
|
||||
|
||||
CREATE TABLE versionhistory
|
||||
(
|
||||
versionhistory_id INTEGER NOT NULL PRIMARY KEY
|
||||
);
|
||||
|
||||
CREATE TABLE versionitem
|
||||
(
|
||||
versionitem_id INTEGER NOT NULL PRIMARY KEY,
|
||||
item_id INTEGER REFERENCES Item(item_id),
|
||||
version_number INTEGER,
|
||||
eperson_id INTEGER REFERENCES EPerson(eperson_id),
|
||||
version_date TIMESTAMP,
|
||||
version_summary VARCHAR(255),
|
||||
versionhistory_id INTEGER REFERENCES VersionHistory(versionhistory_id)
|
||||
);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@@ -31,8 +31,32 @@ ALTER TABLE resourcepolicy ADD rpdescription VARCHAR(100);
|
||||
|
||||
ALTER TABLE item ADD discoverable BOOLEAN;
|
||||
|
||||
|
||||
update item set discoverable=true;
|
||||
|
||||
-------------------------------------------
|
||||
-- Item Level Versioning Tables
|
||||
-------------------------------------------
|
||||
|
||||
CREATE TABLE versionhistory
|
||||
(
|
||||
versionhistory_id INTEGER NOT NULL PRIMARY KEY
|
||||
);
|
||||
|
||||
CREATE TABLE versionitem
|
||||
(
|
||||
versionitem_id INTEGER NOT NULL PRIMARY KEY,
|
||||
item_id INTEGER REFERENCES Item(item_id),
|
||||
version_number INTEGER,
|
||||
eperson_id INTEGER REFERENCES EPerson(eperson_id),
|
||||
version_date TIMESTAMP,
|
||||
version_summary VARCHAR(255),
|
||||
versionhistory_id INTEGER REFERENCES VersionHistory(versionhistory_id)
|
||||
);
|
||||
|
||||
CREATE SEQUENCE versionitem_seq;
|
||||
CREATE SEQUENCE versionhistory_seq;
|
||||
|
||||
|
||||
-------------------------------------------
|
||||
-- New columns and longer hash for salted password hashing DS-861 --
|
||||
|
Reference in New Issue
Block a user