mirror of
https://github.com/DSpace/DSpace.git
synced 2025-10-11 12:03:09 +00:00
Atmire dspace 3.0 versioning contribution
Versioning : Add Spring WebMVC Control Versioning : AIP Prototype Test Improvements.
This commit is contained in:
@@ -106,13 +106,35 @@
|
|||||||
</execution>
|
</execution>
|
||||||
</executions>
|
</executions>
|
||||||
</plugin>
|
</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>
|
<plugin>
|
||||||
<artifactId>maven-surefire-plugin</artifactId>
|
<artifactId>maven-surefire-plugin</artifactId>
|
||||||
<configuration>
|
<configuration>
|
||||||
<systemPropertyVariables>
|
<systemPropertyVariables>
|
||||||
<dspace.dir>${project.build.directory}/testing/dspace</dspace.dir>
|
<dspace.dir>${project.build.directory}/testing/dspace</dspace.dir>
|
||||||
<dspace.dir.static>${basedir}/src/test/data/dspaceFolder</dspace.dir.static>
|
<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>
|
<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>
|
<dspace.log.init.disable>true</dspace.log.init.disable>
|
||||||
</systemPropertyVariables>
|
</systemPropertyVariables>
|
||||||
|
@@ -73,7 +73,7 @@ public class BrowseConsumer implements Consumer
|
|||||||
|
|
||||||
// If an Item is created or its metadata is modified..
|
// If an Item is created or its metadata is modified..
|
||||||
case Constants.ITEM:
|
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);
|
Item subj = (Item)event.getSubject(ctx);
|
||||||
if (subj != null)
|
if (subj != null)
|
||||||
|
@@ -8,6 +8,7 @@
|
|||||||
package org.dspace.browse;
|
package org.dspace.browse;
|
||||||
|
|
||||||
import org.apache.log4j.Logger;
|
import org.apache.log4j.Logger;
|
||||||
|
import org.dspace.authorize.AuthorizeException;
|
||||||
import org.dspace.authorize.AuthorizeManager;
|
import org.dspace.authorize.AuthorizeManager;
|
||||||
import org.dspace.content.*;
|
import org.dspace.content.*;
|
||||||
import org.dspace.core.Constants;
|
import org.dspace.core.Constants;
|
||||||
@@ -384,6 +385,12 @@ public class BrowseItem extends DSpaceObject
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void update() throws SQLException, AuthorizeException
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void updateLastModified()
|
public void updateLastModified()
|
||||||
{
|
{
|
||||||
|
@@ -321,7 +321,7 @@ public class IndexBrowse
|
|||||||
{
|
{
|
||||||
indexItem(new ItemMetadataProxy(item), addingNewItem);
|
indexItem(new ItemMetadataProxy(item), addingNewItem);
|
||||||
}
|
}
|
||||||
else if (item.isWithdrawn())
|
else if (item.isWithdrawn() || !item.isArchived())
|
||||||
{
|
{
|
||||||
indexItem(new ItemMetadataProxy(item), false);
|
indexItem(new ItemMetadataProxy(item), false);
|
||||||
}
|
}
|
||||||
|
@@ -974,7 +974,7 @@ public class Collection extends DSpaceObject
|
|||||||
* @throws IOException
|
* @throws IOException
|
||||||
* @throws AuthorizeException
|
* @throws AuthorizeException
|
||||||
*/
|
*/
|
||||||
public void update() throws SQLException, IOException, AuthorizeException
|
public void update() throws SQLException, AuthorizeException
|
||||||
{
|
{
|
||||||
// Check authorisation
|
// Check authorisation
|
||||||
canEdit(true);
|
canEdit(true);
|
||||||
|
@@ -509,7 +509,7 @@ public class Community extends DSpaceObject
|
|||||||
/**
|
/**
|
||||||
* Update the community metadata (including logo) to the database.
|
* Update the community metadata (including logo) to the database.
|
||||||
*/
|
*/
|
||||||
public void update() throws SQLException, IOException, AuthorizeException
|
public void update() throws SQLException, AuthorizeException
|
||||||
{
|
{
|
||||||
// Check authorisation
|
// Check authorisation
|
||||||
canEdit();
|
canEdit();
|
||||||
|
@@ -7,13 +7,14 @@
|
|||||||
*/
|
*/
|
||||||
package org.dspace.content;
|
package org.dspace.content;
|
||||||
|
|
||||||
|
import java.sql.SQLException;
|
||||||
|
|
||||||
|
import org.dspace.authorize.AuthorizeException;
|
||||||
import org.dspace.core.Constants;
|
import org.dspace.core.Constants;
|
||||||
import org.dspace.core.Context;
|
import org.dspace.core.Context;
|
||||||
import org.dspace.eperson.EPerson;
|
import org.dspace.eperson.EPerson;
|
||||||
import org.dspace.eperson.Group;
|
import org.dspace.eperson.Group;
|
||||||
|
|
||||||
import java.sql.SQLException;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Abstract base class for DSpace objects
|
* Abstract base class for DSpace objects
|
||||||
*/
|
*/
|
||||||
@@ -171,5 +172,7 @@ public abstract class DSpaceObject
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public abstract void update() throws SQLException, AuthorizeException;
|
||||||
|
|
||||||
public abstract void updateLastModified();
|
public abstract void updateLastModified();
|
||||||
}
|
}
|
||||||
|
@@ -37,7 +37,7 @@ public interface InProgressSubmission
|
|||||||
/**
|
/**
|
||||||
* Update the submission, including the unarchived item.
|
* Update the submission, including the unarchived item.
|
||||||
*/
|
*/
|
||||||
void update() throws SQLException, IOException, AuthorizeException;
|
void update() throws SQLException, AuthorizeException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the incomplete item object
|
* Get the incomplete item object
|
||||||
|
@@ -15,7 +15,9 @@ import org.dspace.core.Constants;
|
|||||||
import org.dspace.core.Context;
|
import org.dspace.core.Context;
|
||||||
import org.dspace.embargo.EmbargoManager;
|
import org.dspace.embargo.EmbargoManager;
|
||||||
import org.dspace.event.Event;
|
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.
|
* Support to install an Item in the archive.
|
||||||
@@ -58,21 +60,18 @@ public class InstallItem
|
|||||||
IOException, AuthorizeException
|
IOException, AuthorizeException
|
||||||
{
|
{
|
||||||
Item item = is.getItem();
|
Item item = is.getItem();
|
||||||
String handle;
|
IdentifierService identifierService = new DSpace().getSingletonService(IdentifierService.class);
|
||||||
|
try {
|
||||||
// if no previous handle supplied, create one
|
if(suppliedHandle == null)
|
||||||
if (suppliedHandle == null)
|
|
||||||
{
|
{
|
||||||
// create a new handle for this item
|
identifierService.register(c, item);
|
||||||
handle = HandleManager.createHandle(c, item);
|
}else{
|
||||||
|
identifierService.register(c, item, suppliedHandle);
|
||||||
}
|
}
|
||||||
else
|
} catch (IdentifierException e) {
|
||||||
{
|
throw new RuntimeException("Can't create an Identifier!");
|
||||||
// assign the supplied handle to this item
|
|
||||||
handle = HandleManager.createHandle(c, item, suppliedHandle);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
populateHandleMetadata(item, handle);
|
|
||||||
|
|
||||||
populateMetadata(c, item);
|
populateMetadata(c, item);
|
||||||
|
|
||||||
@@ -102,21 +101,17 @@ public class InstallItem
|
|||||||
throws SQLException, IOException, AuthorizeException
|
throws SQLException, IOException, AuthorizeException
|
||||||
{
|
{
|
||||||
Item item = is.getItem();
|
Item item = is.getItem();
|
||||||
String handle;
|
|
||||||
|
|
||||||
// if no handle supplied
|
IdentifierService identifierService = new DSpace().getSingletonService(IdentifierService.class);
|
||||||
if (suppliedHandle == null)
|
try {
|
||||||
|
if(suppliedHandle == null)
|
||||||
{
|
{
|
||||||
// create a new handle for this item
|
identifierService.register(c, item);
|
||||||
handle = HandleManager.createHandle(c, item);
|
}else{
|
||||||
//only populate handle metadata for new handles
|
identifierService.register(c, item, suppliedHandle);
|
||||||
// (existing handles should already be in the metadata -- as it was restored by ingest process)
|
|
||||||
populateHandleMetadata(item, handle);
|
|
||||||
}
|
}
|
||||||
else
|
} catch (IdentifierException e) {
|
||||||
{
|
throw new RuntimeException("Can't create an Identifier!");
|
||||||
// assign the supplied handle to this item
|
|
||||||
handle = HandleManager.createHandle(c, item, suppliedHandle);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Even though we are restoring an item it may not have the proper dates. So let's
|
// 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);
|
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)
|
private static void populateMetadata(Context c, Item item)
|
||||||
throws SQLException, IOException, AuthorizeException
|
throws SQLException, IOException, AuthorizeException
|
||||||
|
@@ -38,9 +38,13 @@ import org.dspace.event.Event;
|
|||||||
import org.dspace.eperson.EPerson;
|
import org.dspace.eperson.EPerson;
|
||||||
import org.dspace.eperson.Group;
|
import org.dspace.eperson.Group;
|
||||||
import org.dspace.handle.HandleManager;
|
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.DatabaseManager;
|
||||||
import org.dspace.storage.rdbms.TableRow;
|
import org.dspace.storage.rdbms.TableRow;
|
||||||
import org.dspace.storage.rdbms.TableRowIterator;
|
import org.dspace.storage.rdbms.TableRowIterator;
|
||||||
|
import org.dspace.utils.DSpace;
|
||||||
|
import org.dspace.versioning.VersioningService;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class representing an item in DSpace.
|
* Class representing an item in DSpace.
|
||||||
@@ -2039,10 +2043,30 @@ public class Item extends DSpaceObject
|
|||||||
// Remove any Handle
|
// Remove any Handle
|
||||||
HandleManager.unbindHandle(ourContext, this);
|
HandleManager.unbindHandle(ourContext, this);
|
||||||
|
|
||||||
|
// remove version attached to the item
|
||||||
|
removeVersion();
|
||||||
|
|
||||||
|
|
||||||
// Finally remove item row
|
// Finally remove item row
|
||||||
DatabaseManager.delete(ourContext, itemRow);
|
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.
|
* Remove item and all its sub-structure from the context cache.
|
||||||
* Useful in batch processes where a single context has a long,
|
* Useful in batch processes where a single context has a long,
|
||||||
|
@@ -96,7 +96,7 @@ public class Site extends DSpaceObject
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void update()
|
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.
|
* 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
|
// Authorisation is checked by the item.update() method below
|
||||||
|
|
||||||
|
@@ -9,13 +9,7 @@ package org.dspace.core;
|
|||||||
|
|
||||||
import java.sql.Connection;
|
import java.sql.Connection;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
import java.util.ArrayList;
|
import java.util.*;
|
||||||
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 org.apache.log4j.Logger;
|
import org.apache.log4j.Logger;
|
||||||
import org.dspace.eperson.EPerson;
|
import org.dspace.eperson.EPerson;
|
||||||
@@ -24,6 +18,7 @@ import org.dspace.event.Dispatcher;
|
|||||||
import org.dspace.event.Event;
|
import org.dspace.event.Event;
|
||||||
import org.dspace.event.EventManager;
|
import org.dspace.event.EventManager;
|
||||||
import org.dspace.storage.rdbms.DatabaseManager;
|
import org.dspace.storage.rdbms.DatabaseManager;
|
||||||
|
import org.springframework.util.CollectionUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class representing the context of a particular DSpace operation. This stores
|
* Class representing the context of a particular DSpace operation. This stores
|
||||||
@@ -77,7 +72,7 @@ public class Context
|
|||||||
private List<Integer> specialGroups;
|
private List<Integer> specialGroups;
|
||||||
|
|
||||||
/** Content events */
|
/** Content events */
|
||||||
private List<Event> events = null;
|
private LinkedList<Event> events = null;
|
||||||
|
|
||||||
/** Event dispatcher name */
|
/** Event dispatcher name */
|
||||||
private String dispName = null;
|
private String dispName = null;
|
||||||
@@ -375,7 +370,7 @@ public class Context
|
|||||||
{
|
{
|
||||||
if (events == null)
|
if (events == null)
|
||||||
{
|
{
|
||||||
events = new ArrayList<Event>();
|
events = new LinkedList<Event>();
|
||||||
}
|
}
|
||||||
|
|
||||||
events.add(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
|
* Get the current event list. If there is a separate list of events from
|
||||||
* already-committed operations combine that with current list.
|
* 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.
|
* @return List of all available events.
|
||||||
*/
|
*/
|
||||||
public List<Event> getEvents()
|
public LinkedList<Event> getEvents()
|
||||||
{
|
{
|
||||||
return events;
|
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
|
* Close the context, without committing any of the changes performed using
|
||||||
* this context. The database connection is freed. No exception is thrown if
|
* this context. The database connection is freed. No exception is thrown if
|
||||||
|
@@ -7,9 +7,7 @@
|
|||||||
*/
|
*/
|
||||||
package org.dspace.event;
|
package org.dspace.event;
|
||||||
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import org.apache.log4j.Logger;
|
import org.apache.log4j.Logger;
|
||||||
import org.dspace.core.Context;
|
import org.dspace.core.Context;
|
||||||
@@ -72,9 +70,8 @@ public class BasicDispatcher extends Dispatcher
|
|||||||
{
|
{
|
||||||
if (!consumers.isEmpty())
|
if (!consumers.isEmpty())
|
||||||
{
|
{
|
||||||
List<Event> events = Collections.synchronizedList(ctx.getEvents());
|
|
||||||
|
|
||||||
if (events == null)
|
if (!ctx.hasEvents())
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -82,7 +79,7 @@ public class BasicDispatcher extends Dispatcher
|
|||||||
if (log.isDebugEnabled())
|
if (log.isDebugEnabled())
|
||||||
{
|
{
|
||||||
log.debug("Processing queue of "
|
log.debug("Processing queue of "
|
||||||
+ String.valueOf(events.size()) + " events.");
|
+ String.valueOf(ctx.getEvents().size()) + " events.");
|
||||||
}
|
}
|
||||||
|
|
||||||
// transaction identifier applies to all events created in
|
// 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.
|
// some letters so RDF readers don't mistake it for an integer.
|
||||||
String tid = "TX" + Utils.generateKey();
|
String tid = "TX" + Utils.generateKey();
|
||||||
|
|
||||||
for (Event event : events)
|
while (ctx.hasEvents())
|
||||||
{
|
{
|
||||||
|
Event event = ctx.pollEvent();
|
||||||
event.setDispatcher(getIdentifier());
|
event.setDispatcher(getIdentifier());
|
||||||
event.setTransactionID(tid);
|
event.setTransactionID(tid);
|
||||||
|
|
||||||
|
@@ -234,9 +234,12 @@ public class HandleManager
|
|||||||
public static void unbindHandle(Context context, DSpaceObject dso)
|
public static void unbindHandle(Context context, DSpaceObject dso)
|
||||||
throws SQLException
|
throws SQLException
|
||||||
{
|
{
|
||||||
TableRow row = getHandleInternal(context, dso.getType(), dso.getID());
|
TableRowIterator rows = getInternalHandles(context, dso.getType(), dso.getID());
|
||||||
if (row != null)
|
if (rows != null)
|
||||||
{
|
{
|
||||||
|
while (rows.hasNext())
|
||||||
|
{
|
||||||
|
TableRow row = rows.next();
|
||||||
//Only set the "resouce_id" column to null when unbinding a handle.
|
//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
|
// We want to keep around the "resource_type_id" value, so that we
|
||||||
// can verify during a restore whether the same *type* of resource
|
// can verify during a restore whether the same *type* of resource
|
||||||
@@ -248,7 +251,7 @@ public class HandleManager
|
|||||||
{
|
{
|
||||||
log.debug("Unbound Handle " + row.getStringColumn("handle") + " from object " + Constants.typeText[dso.getType()] + " id=" + dso.getID());
|
log.debug("Unbound Handle " + row.getStringColumn("handle") + " from object " + Constants.typeText[dso.getType()] + " id=" + dso.getID());
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -356,8 +359,8 @@ public class HandleManager
|
|||||||
public static String findHandle(Context context, DSpaceObject dso)
|
public static String findHandle(Context context, DSpaceObject dso)
|
||||||
throws SQLException
|
throws SQLException
|
||||||
{
|
{
|
||||||
TableRow row = getHandleInternal(context, dso.getType(), dso.getID());
|
TableRowIterator rows = getInternalHandles(context, dso.getType(), dso.getID());
|
||||||
if (row == null)
|
if (rows == null || !rows.hasNext())
|
||||||
{
|
{
|
||||||
if (dso.getType() == Constants.SITE)
|
if (dso.getType() == Constants.SITE)
|
||||||
{
|
{
|
||||||
@@ -370,7 +373,21 @@ public class HandleManager
|
|||||||
}
|
}
|
||||||
else
|
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -445,13 +462,13 @@ public class HandleManager
|
|||||||
* @exception SQLException
|
* @exception SQLException
|
||||||
* If a database error occurs
|
* 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
|
throws SQLException
|
||||||
{
|
{
|
||||||
String sql = "SELECT * FROM Handle WHERE resource_type_id = ? " +
|
String sql = "SELECT * FROM Handle WHERE resource_type_id = ? " +
|
||||||
"AND resource_id = ?";
|
"AND resource_id = ?";
|
||||||
|
|
||||||
return DatabaseManager.querySingleTable(context, "Handle", sql, type, id);
|
return DatabaseManager.queryTable(context, "Handle", sql, type, id);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
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,6 +637,11 @@ public class BitstreamStorageManager
|
|||||||
continue; // do not delete registered bitstreams
|
continue; // do not delete registered bitstreams
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 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)
|
||||||
|
{
|
||||||
boolean success = file.delete();
|
boolean success = file.delete();
|
||||||
|
|
||||||
String message = ("Deleted bitstream " + bid + " (file "
|
String message = ("Deleted bitstream " + bid + " (file "
|
||||||
@@ -662,6 +667,7 @@ public class BitstreamStorageManager
|
|||||||
{
|
{
|
||||||
deleteParents(file);
|
deleteParents(file);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Make sure to commit our outstanding work every 100
|
// Make sure to commit our outstanding work every 100
|
||||||
// iterations. Otherwise you risk losing the entire transaction
|
// iterations. Otherwise you risk losing the entire transaction
|
||||||
@@ -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
|
// 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.
|
* Update the workflow item, including the unarchived item.
|
||||||
*/
|
*/
|
||||||
public void update() throws SQLException, IOException, AuthorizeException
|
public void update() throws SQLException, AuthorizeException
|
||||||
{
|
{
|
||||||
// FIXME check auth
|
// FIXME check auth
|
||||||
log.info(LogManager.getHeader(ourContext, "update_workflow_item",
|
log.info(LogManager.getHeader(ourContext, "update_workflow_item",
|
||||||
|
@@ -63,7 +63,7 @@ public class XmlWorkflowItem implements InProgressSubmission {
|
|||||||
*/
|
*/
|
||||||
// private ArrayList<StepRecord> activeSteps;
|
// private ArrayList<StepRecord> activeSteps;
|
||||||
|
|
||||||
XmlWorkflowItem(Context context, TableRow row) throws SQLException {
|
XmlWorkflowItem(Context context, TableRow row) throws SQLException, AuthorizeException, IOException {
|
||||||
ourContext = context;
|
ourContext = context;
|
||||||
wfRow = row;
|
wfRow = row;
|
||||||
// activeSteps = new ArrayList<StepRecord>();
|
// activeSteps = new ArrayList<StepRecord>();
|
||||||
@@ -360,35 +360,36 @@ public class XmlWorkflowItem implements InProgressSubmission {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Check to see if a particular item is currently under Workflow.
|
* 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
|
* @param context
|
||||||
* the context object
|
* the context object
|
||||||
* @param i
|
* @param item
|
||||||
* the 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)
|
public static XmlWorkflowItem findByItem(Context context, Item item) throws SQLException {
|
||||||
throws SQLException
|
TableRow row = DatabaseManager.findByUnique(context, "cwf_workflowitem", "item_id", item.getID());
|
||||||
{
|
|
||||||
// Look for the unique workflowitem entry where 'item_id' references this item
|
|
||||||
TableRow row = DatabaseManager.findByUnique(context, "cwf_workflowitem", "item_id", i.getID());
|
|
||||||
|
|
||||||
if (row == null)
|
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)
|
||||||
{
|
{
|
||||||
return null;
|
wi = new XmlWorkflowItem(context, row);
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
return new XmlWorkflowItem(context, row);
|
|
||||||
}
|
}
|
||||||
|
return wi;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update the workflow item, including the unarchived item.
|
* Update the workflow item, including the unarchived item.
|
||||||
*/
|
*/
|
||||||
public void update() throws SQLException, IOException, AuthorizeException {
|
public void update() throws SQLException, AuthorizeException {
|
||||||
// FIXME check auth
|
// FIXME check auth
|
||||||
log.info(LogManager.getHeader(ourContext, "update_workflow_item",
|
log.info(LogManager.getHeader(ourContext, "update_workflow_item",
|
||||||
"workflowitem_id=" + getID()));
|
"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 static org.junit.Assert.fail;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileInputStream;
|
|
||||||
import java.io.FileOutputStream;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.nio.channels.FileChannel;
|
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
import java.util.TimeZone;
|
import java.util.TimeZone;
|
||||||
@@ -38,6 +35,8 @@ import org.dspace.core.ConfigurationManager;
|
|||||||
import org.dspace.core.Context;
|
import org.dspace.core.Context;
|
||||||
import org.dspace.eperson.EPerson;
|
import org.dspace.eperson.EPerson;
|
||||||
import org.dspace.search.DSIndexer;
|
import org.dspace.search.DSIndexer;
|
||||||
|
import org.dspace.servicemanager.DSpaceKernelImpl;
|
||||||
|
import org.dspace.servicemanager.DSpaceKernelInit;
|
||||||
import org.dspace.storage.rdbms.MockDatabaseManager;
|
import org.dspace.storage.rdbms.MockDatabaseManager;
|
||||||
import org.junit.After;
|
import org.junit.After;
|
||||||
import org.junit.AfterClass;
|
import org.junit.AfterClass;
|
||||||
@@ -78,6 +77,7 @@ public class AbstractUnitTest
|
|||||||
*/
|
*/
|
||||||
protected static EPerson eperson;
|
protected static EPerson eperson;
|
||||||
|
|
||||||
|
protected static DSpaceKernelImpl kernelImpl;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method will be run before the first test as per @BeforeClass. It will
|
* 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
|
//load the test configuration file
|
||||||
ConfigurationManager.loadConfig(null);
|
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
|
// Load the default registries. This assumes the temporary
|
||||||
// filesystem is working and the in-memory DB in place.
|
// filesystem is working and the in-memory DB in place.
|
||||||
Context ctx = new Context();
|
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 group2groupcache_seq;
|
||||||
CREATE SEQUENCE harvested_collection_seq;
|
CREATE SEQUENCE harvested_collection_seq;
|
||||||
CREATE SEQUENCE harvested_item_seq;
|
CREATE SEQUENCE harvested_item_seq;
|
||||||
|
CREATE SEQUENCE versionitem_seq;
|
||||||
|
CREATE SEQUENCE versionhistory_seq;
|
||||||
|
|
||||||
-------------------------------------------------------
|
-------------------------------------------------------
|
||||||
-- BitstreamFormatRegistry table
|
-- 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>
|
<artifactId>gson</artifactId>
|
||||||
<version>2.2.1</version>
|
<version>2.2.1</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework</groupId>
|
||||||
|
<artifactId>spring-webmvc</artifactId>
|
||||||
|
<version>3.0.5.RELEASE</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
</project>
|
</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-mapping>
|
||||||
<filter-name>CocoonMultipartFilter</filter-name>
|
<filter-name>CocoonMultipartFilter</filter-name>
|
||||||
<servlet-name>Cocoon</servlet-name>
|
<servlet-name>spring</servlet-name>
|
||||||
</filter-mapping>
|
</filter-mapping>
|
||||||
|
|
||||||
<filter-mapping>
|
<filter-mapping>
|
||||||
<filter-name>DSpaceCocoonServletFilter</filter-name>
|
<filter-name>DSpaceCocoonServletFilter</filter-name>
|
||||||
<servlet-name>Cocoon</servlet-name>
|
<servlet-name>spring</servlet-name>
|
||||||
</filter-mapping>
|
</filter-mapping>
|
||||||
|
|
||||||
<filter-mapping>
|
<filter-mapping>
|
||||||
<filter-name>SetCharacterEncoding</filter-name>
|
<filter-name>SetCharacterEncoding</filter-name>
|
||||||
<servlet-name>Cocoon</servlet-name>
|
<servlet-name>spring</servlet-name>
|
||||||
</filter-mapping>
|
</filter-mapping>
|
||||||
|
|
||||||
<!--
|
<!--
|
||||||
@@ -188,15 +188,23 @@
|
|||||||
Servlet Configuration ==========================================
|
Servlet Configuration ==========================================
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<servlet>
|
<!--servlet>
|
||||||
<description>Cocoon</description>
|
<description>Cocoon</description>
|
||||||
<display-name>Cocoon</display-name>
|
<display-name>Cocoon</display-name>
|
||||||
<servlet-name>Cocoon</servlet-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
|
This parameter allows you to startup Cocoon2 immediately after startup
|
||||||
of your servlet engine.
|
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>
|
<load-on-startup>1</load-on-startup>
|
||||||
</servlet>
|
</servlet>
|
||||||
|
|
||||||
@@ -209,7 +217,7 @@
|
|||||||
to change this parameter.
|
to change this parameter.
|
||||||
-->
|
-->
|
||||||
<servlet-mapping>
|
<servlet-mapping>
|
||||||
<servlet-name>Cocoon</servlet-name>
|
<servlet-name>spring</servlet-name>
|
||||||
<url-pattern>/*</url-pattern>
|
<url-pattern>/*</url-pattern>
|
||||||
</servlet-mapping>
|
</servlet-mapping>
|
||||||
|
|
||||||
@@ -218,7 +226,7 @@
|
|||||||
by '/' mapping, but must be overriden explicitly.
|
by '/' mapping, but must be overriden explicitly.
|
||||||
-->
|
-->
|
||||||
<servlet-mapping>
|
<servlet-mapping>
|
||||||
<servlet-name>Cocoon</servlet-name>
|
<servlet-name>spring</servlet-name>
|
||||||
<url-pattern>*.jsp</url-pattern>
|
<url-pattern>*.jsp</url-pattern>
|
||||||
</servlet-mapping>
|
</servlet-mapping>
|
||||||
<!--
|
<!--
|
||||||
@@ -226,7 +234,7 @@
|
|||||||
by '/' mapping, but must be overriden explicitly.
|
by '/' mapping, but must be overriden explicitly.
|
||||||
-->
|
-->
|
||||||
<servlet-mapping>
|
<servlet-mapping>
|
||||||
<servlet-name>Cocoon</servlet-name>
|
<servlet-name>spring</servlet-name>
|
||||||
<url-pattern>*.html</url-pattern>
|
<url-pattern>*.html</url-pattern>
|
||||||
</servlet-mapping>
|
</servlet-mapping>
|
||||||
|
|
||||||
|
@@ -2163,4 +2163,68 @@
|
|||||||
<message key="xmlui.mobile.items_in_google_scholar">Items in Google Scholar</message>
|
<message key="xmlui.mobile.items_in_google_scholar">Items in Google Scholar</message>
|
||||||
<message key="xmlui.mobile.download">Download</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>
|
</catalogue>
|
||||||
|
@@ -631,9 +631,9 @@ event.dispatcher.default.class = org.dspace.event.BasicDispatcher
|
|||||||
|
|
||||||
#
|
#
|
||||||
# uncomment below and comment out original property to enable discovery indexing
|
# 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)
|
# The noindex dispatcher will not create search or browse indexes (useful for batch item imports)
|
||||||
event.dispatcher.noindex.class = org.dspace.event.BasicDispatcher
|
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.class = org.dspace.event.TestConsumer
|
||||||
#event.consumer.test.filters = All+All
|
#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
|
# ...set to true to enable testConsumer messages to standard output
|
||||||
#testConsumer.verbose = true
|
#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
|
BrowseArtifacts, SearchArtifacts
|
||||||
<aspect name="Artifact Browser" path="resource://aspects/ArtifactBrowser/" />
|
<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="Displaying Artifacts" path="resource://aspects/ViewArtifacts/" />
|
||||||
<aspect name="Browsing Artifacts" path="resource://aspects/BrowseArtifacts/" />
|
<aspect name="Browsing Artifacts" path="resource://aspects/BrowseArtifacts/" />
|
||||||
<aspect name="Searching Artifacts" path="resource://aspects/SearchArtifacts/" />
|
<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 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 group2groupcache_seq;
|
||||||
CREATE SEQUENCE harvested_collection_seq;
|
CREATE SEQUENCE harvested_collection_seq;
|
||||||
CREATE SEQUENCE harvested_item_seq;
|
CREATE SEQUENCE harvested_item_seq;
|
||||||
|
CREATE SEQUENCE versionitem_seq;
|
||||||
|
CREATE SEQUENCE versionhistory_seq;
|
||||||
|
|
||||||
-------------------------------------------------------
|
-------------------------------------------------------
|
||||||
-- BitstreamFormatRegistry table
|
-- BitstreamFormatRegistry table
|
||||||
@@ -739,3 +741,19 @@ CREATE TABLE harvested_item
|
|||||||
);
|
);
|
||||||
|
|
||||||
CREATE INDEX harvested_item_fk_idx ON harvested_item(item_id);
|
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);
|
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 group2groupcache_seq;
|
||||||
CREATE SEQUENCE harvested_collection_seq;
|
CREATE SEQUENCE harvested_collection_seq;
|
||||||
CREATE SEQUENCE harvested_item_seq;
|
CREATE SEQUENCE harvested_item_seq;
|
||||||
|
CREATE SEQUENCE versionitem_seq;
|
||||||
|
CREATE SEQUENCE versionhistory_seq;
|
||||||
|
|
||||||
-------------------------------------------------------
|
-------------------------------------------------------
|
||||||
-- BitstreamFormatRegistry table
|
-- 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;
|
ALTER TABLE item ADD discoverable BOOLEAN;
|
||||||
|
|
||||||
|
|
||||||
update item set discoverable=true;
|
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 --
|
-- New columns and longer hash for salted password hashing DS-861 --
|
||||||
|
Reference in New Issue
Block a user