[Task 64334] implemented the scripts prototype

This commit is contained in:
Raf Ponsaerts
2019-08-13 12:33:35 +02:00
parent d896fed7a7
commit c890570b12
37 changed files with 2186 additions and 0 deletions

View File

@@ -0,0 +1,201 @@
/**
* 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 java.util.Date;
import java.util.List;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.ManyToOne;
import javax.persistence.SequenceGenerator;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;
import org.dspace.core.ReloadableEntity;
import org.dspace.eperson.EPerson;
@Entity
@Table(name = "process")
public class Process implements ReloadableEntity<Integer> {
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "process_id_seq")
@SequenceGenerator(name = "process_id_seq", sequenceName = "process_id_seq", allocationSize = 1)
@Column(name = "process_id", unique = true, nullable = false)
private Integer processId;
@ManyToOne
@JoinColumn(name = "user_id", nullable = false)
private EPerson ePerson;
@Column(name = "start_time")
@Temporal(TemporalType.TIMESTAMP)
private Date startTime;
@Column(name = "finished_time")
@Temporal(TemporalType.TIMESTAMP)
private Date finishedTime;
@Column(name = "script", nullable = false)
private String name;
@Column(name = "status")
@Enumerated(EnumType.STRING)
private ProcessStatus processStatus;
@Column(name = "parameters")
private String parameters;
@ManyToMany(fetch = FetchType.LAZY)
@JoinTable(
name = "process2bitstream",
joinColumns = {@JoinColumn(name = "process_id")},
inverseJoinColumns = {@JoinColumn(name = "bitstream_id")}
)
private List<Bitstream> bitstreams;
@Column(name = "creation_time", nullable = false)
@Temporal(TemporalType.TIMESTAMP)
private Date creationTime;
protected Process() {
}
public Integer getID() {
return processId;
}
public void setProcessId(Integer processId) {
this.processId = processId;
}
public EPerson getEPerson() {
return ePerson;
}
public void setePerson(EPerson ePerson) {
this.ePerson = ePerson;
}
public Date getStartTime() {
return startTime;
}
public void setStartTime(Date startTime) {
this.startTime = startTime;
}
public Date getFinishedTime() {
return finishedTime;
}
public void setFinishedTime(Date finishedTime) {
this.finishedTime = finishedTime;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public ProcessStatus getProcessStatus() {
return processStatus;
}
public void setProcessStatus(ProcessStatus processStatus) {
this.processStatus = processStatus;
}
/**
* To get the parameters, use ProcessService.getParameters() to get a parsed list of DSpaceCommandLineParameters
*/
protected String getParameters() {
return parameters;
}
public void setParameters(String parameters) {
this.parameters = parameters;
}
public List<Bitstream> getBitstreams() {
return bitstreams;
}
public void setBitstreams(List<Bitstream> bitstreams) {
this.bitstreams = bitstreams;
}
public void removeBitstream(Bitstream bitstream) {
getBitstreams().remove(bitstream);
}
public void addBitstream(Bitstream bitstream) {
getBitstreams().add(bitstream);
}
public void setCreationTime(Date creationTime) {
this.creationTime = creationTime;
}
public Date getCreationTime() {
return creationTime;
}
/**
* Return <code>true</code> if <code>other</code> is the same Bitstream
* as this object, <code>false</code> otherwise
*
* @param other object to compare to
* @return <code>true</code> if object passed in represents the same
* collection as this object
*/
@Override
public boolean equals(Object other) {
return (other instanceof Process &&
new EqualsBuilder().append(this.getID(), ((Process) other).getID())
.append(this.getName(), ((Process) other).getName())
.append(this.getBitstreams(), ((Process) other).getBitstreams())
.append(this.getProcessStatus(), ((Process) other).getProcessStatus())
.append(this.getFinishedTime(), ((Process) other).getFinishedTime())
.append(this.getStartTime(), ((Process) other).getStartTime())
.append(this.getParameters(), ((Process) other).getParameters())
.append(this.getCreationTime(), ((Process) other).getCreationTime())
.append(this.getEPerson(), ((Process) other).getEPerson())
.isEquals());
}
@Override
public int hashCode() {
return new HashCodeBuilder(17, 37)
.append(this.getID())
.append(this.getName())
.append(this.getBitstreams())
.append(this.getProcessStatus())
.append(this.getFinishedTime())
.append(this.getStartTime())
.append(this.getParameters())
.append(this.getCreationTime())
.append(this.getEPerson())
.toHashCode();
}
}

View File

@@ -0,0 +1,146 @@
/**
* 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 java.io.IOException;
import java.io.InputStream;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
import java.util.regex.Pattern;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.Logger;
import org.dspace.authorize.AuthorizeException;
import org.dspace.content.dao.ProcessDAO;
import org.dspace.content.service.BitstreamService;
import org.dspace.content.service.ProcessService;
import org.dspace.core.Context;
import org.dspace.eperson.EPerson;
import org.dspace.scripts.DSpaceCommandLineParameter;
import org.springframework.beans.factory.annotation.Autowired;
public class ProcessServiceImpl implements ProcessService {
private static final Logger log = org.apache.logging.log4j.LogManager.getLogger(ProcessService.class);
@Autowired
private ProcessDAO processDAO;
@Autowired
private BitstreamService bitstreamService;
@Override
public Process create(Context context, EPerson ePerson, String scriptName,
List<DSpaceCommandLineParameter> parameters) throws SQLException {
Process process = new Process();
process.setePerson(ePerson);
process.setName(scriptName);
process.setParameters(DSpaceCommandLineParameter.concatenate(parameters));
process.setCreationTime(new Date());
Process createdProcess = processDAO.create(context, process);
log.info("Process has been created for eperson with email: " + ePerson.getEmail() + " with ID: "
+ createdProcess.getID() + " and scriptName: " + scriptName + " and parameters: " + parameters);
return createdProcess;
}
@Override
public Process find(Context context, int processId) throws SQLException {
return processDAO.findByID(context, Process.class, processId);
}
@Override
public List<Process> findAll(Context context) throws SQLException {
return processDAO.findAll(context, Process.class);
}
@Override
public List<Process> findAllSortByScript(Context context) throws SQLException {
return processDAO.findAllSortByScript(context);
}
@Override
public List<Process> findAllSortByStartTime(Context context) throws SQLException {
List<Process> processes = findAll(context);
Comparator<Process> comparing = Comparator
.comparing(Process::getStartTime, Comparator.nullsLast(Comparator.naturalOrder()));
comparing = comparing.thenComparing(Process::getID);
processes.sort(comparing);
return processes;
}
@Override
public void start(Context context, Process process) throws SQLException {
process.setProcessStatus(ProcessStatus.RUNNING);
process.setStartTime(new Date());
update(context, process);
log.info("Process with ID: " + process.getID() + " and name: " + process.getName() + " has started");
}
@Override
public void fail(Context context, Process process) throws SQLException {
process.setProcessStatus(ProcessStatus.FAILED);
process.setFinishedTime(new Date());
update(context, process);
log.info("Process with ID: " + process.getID() + " and name: " + process.getName() + " has failed");
}
@Override
public void complete(Context context, Process process) throws SQLException {
process.setProcessStatus(ProcessStatus.COMPLETED);
process.setFinishedTime(new Date());
update(context, process);
log.info("Process with ID: " + process.getID() + " and name: " + process.getName() + " has been completed");
}
@Override
public void appendFile(Context context, Process process, InputStream is, String type)
throws IOException, SQLException, AuthorizeException {
Bitstream bitstream = bitstreamService.create(context, is);
bitstream.setName(context, "process-" + process.getID() + ".log");
bitstreamService.addMetadata(context, bitstream, "process", "type", null, null, type);
bitstreamService.update(context, bitstream);
process.addBitstream(bitstream);
update(context, process);
}
@Override
public void delete(Context context, Process process) throws SQLException {
processDAO.delete(context, process);
log.info("Process with ID: " + process.getID() + " and name: " + process.getName() + " has been deleted");
}
@Override
public void update(Context context, Process process) throws SQLException {
processDAO.save(context, process);
}
public List<DSpaceCommandLineParameter> getParameters(Process process) {
if (StringUtils.isBlank(process.getParameters())) {
return Collections.emptyList();
}
String[] parameterArray = process.getParameters().split(Pattern.quote(DSpaceCommandLineParameter.SEPARATOR));
List<DSpaceCommandLineParameter> parameterList = new ArrayList<>();
for (String parameter : parameterArray) {
parameterList.add(new DSpaceCommandLineParameter(parameter));
}
return parameterList;
}
}

View File

@@ -0,0 +1,16 @@
/**
* 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;
public enum ProcessStatus {
SCHEDULED,
RUNNING,
COMPLETED,
FAILED
}

View File

@@ -0,0 +1,21 @@
/**
* 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.dao;
import java.sql.SQLException;
import java.util.List;
import org.dspace.content.Process;
import org.dspace.core.Context;
import org.dspace.core.GenericDAO;
public interface ProcessDAO extends GenericDAO<Process> {
public List<Process> findAllSortByScript(Context context) throws SQLException;
public List<Process> findAllSortByStartTime(Context context) throws SQLException;
}

View File

@@ -0,0 +1,48 @@
/**
* 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.dao.impl;
import java.sql.SQLException;
import java.util.List;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Root;
import org.dspace.content.Process;
import org.dspace.content.Process_;
import org.dspace.content.dao.ProcessDAO;
import org.dspace.core.AbstractHibernateDAO;
import org.dspace.core.Context;
public class ProcessDAOImpl extends AbstractHibernateDAO<Process> implements ProcessDAO {
@Override
public List<Process> findAllSortByScript(Context context) throws SQLException {
CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context);
CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, Process.class);
Root<Process> processRoot = criteriaQuery.from(Process.class);
criteriaQuery.select(processRoot);
criteriaQuery.orderBy(criteriaBuilder.asc(processRoot.get(Process_.name)));
return list(context, criteriaQuery, false, Process.class, -1, -1);
}
@Override
public List<Process> findAllSortByStartTime(Context context) throws SQLException {
CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context);
CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, Process.class);
Root<Process> processRoot = criteriaQuery.from(Process.class);
criteriaQuery.select(processRoot);
criteriaQuery.orderBy(criteriaBuilder.desc(processRoot.get(Process_.startTime)),
criteriaBuilder.desc(processRoot.get(Process_.processId)));
return list(context, criteriaQuery, false, Process.class, -1, -1);
}
}

View File

@@ -0,0 +1,21 @@
/**
* 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.factory;
import org.dspace.content.service.ProcessService;
import org.dspace.services.factory.DSpaceServicesFactory;
public abstract class ProcessServiceFactory {
public abstract ProcessService getProcessService();
public static ProcessServiceFactory getInstance() {
return DSpaceServicesFactory.getInstance().getServiceManager()
.getServiceByName("processServiceFactory", ProcessServiceFactory.class);
}
}

View File

@@ -0,0 +1,22 @@
/**
* 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.factory.impl;
import org.dspace.content.factory.ProcessServiceFactory;
import org.dspace.content.service.ProcessService;
import org.springframework.beans.factory.annotation.Autowired;
public class ProcessServiceFactoryImpl extends ProcessServiceFactory {
@Autowired(required = true)
private ProcessService processService;
public ProcessService getProcessService() {
return processService;
}
}

View File

@@ -0,0 +1,48 @@
/**
* 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.service;
import java.io.IOException;
import java.io.InputStream;
import java.sql.SQLException;
import java.util.List;
import org.dspace.authorize.AuthorizeException;
import org.dspace.content.Process;
import org.dspace.core.Context;
import org.dspace.eperson.EPerson;
import org.dspace.scripts.DSpaceCommandLineParameter;
public interface ProcessService {
public Process create(Context context, EPerson ePerson, String scriptName,
List<DSpaceCommandLineParameter> parameters) throws SQLException;
public Process find(Context context, int processId) throws SQLException;
public List<Process> findAll(Context context) throws SQLException;
public List<Process> findAllSortByScript(Context context) throws SQLException;
public List<Process> findAllSortByStartTime(Context context) throws SQLException;
public void start(Context context, Process process) throws SQLException;
public void fail(Context context, Process process) throws SQLException;
public void complete(Context context, Process process) throws SQLException;
public void appendFile(Context context, Process process, InputStream is, String type)
throws IOException, SQLException, AuthorizeException;
public void delete(Context context, Process process) throws SQLException;
public void update(Context context, Process process) throws SQLException;
public List<DSpaceCommandLineParameter> getParameters(Process process);
}

View File

@@ -0,0 +1,78 @@
/**
* 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.scripts;
import java.util.List;
import java.util.stream.Collectors;
import org.apache.commons.lang3.StringUtils;
public class DSpaceCommandLineParameter {
private String name;
private String value;
public static String SEPARATOR = "|||";
public DSpaceCommandLineParameter(String key, String value) {
this.name = key;
if (StringUtils.isBlank(value)) {
this.value = null;
} else {
this.value = value;
}
}
public DSpaceCommandLineParameter(String parameter) {
this(StringUtils.substringBefore(parameter, " "), StringUtils.substringAfter(parameter, " "));
}
public String getName() {
return name;
}
public void setName(String key) {
this.name = key;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
public String toString() {
String stringToReturn = "";
stringToReturn += getName();
if (StringUtils.isNotBlank(getValue())) {
stringToReturn += " ";
stringToReturn += getValue();
}
return stringToReturn;
}
public static String concatenate(List<DSpaceCommandLineParameter> parameterList) {
if (parameterList.isEmpty()) {
return null;
}
return parameterList.stream().map(parameter -> parameter.toString()).collect(Collectors.joining(SEPARATOR));
}
public boolean equals(Object other) {
if (other == null) {
return false;
}
if (other.getClass() != DSpaceCommandLineParameter.class) {
return false;
}
return StringUtils.equals(this.getName(), ((DSpaceCommandLineParameter) other).getName()) && StringUtils
.equals(this.getValue(), ((DSpaceCommandLineParameter) other).getValue());
}
}

View File

@@ -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.scripts;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.DefaultParser;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;
import org.dspace.scripts.handler.DSpaceRunnableHandler;
import org.springframework.beans.factory.annotation.Required;
public abstract class DSpaceRunnable implements Runnable {
private String name;
private String description;
protected CommandLine commandLine;
protected Options options;
protected DSpaceRunnableHandler handler;
public String getName() {
return name;
}
@Required
public void setName(String name) {
this.name = name;
}
public String getDescription() {
return description;
}
@Required
public void setDescription(String description) {
this.description = description;
}
public Options getOptions() {
return options;
}
private void parse(String[] args) throws ParseException {
commandLine = new DefaultParser().parse(getOptions(), args);
setup();
}
public void printHelp() {
handler.printHelp(options, name);
}
@Override
public void run() {
try {
handler.start();
internalRun();
handler.handleCompletion();
} catch (Exception e) {
handler.handleException(e);
}
}
private void setHandler(DSpaceRunnableHandler dSpaceRunnableHandler) {
this.handler = dSpaceRunnableHandler;
}
public void initialize(String[] args, DSpaceRunnableHandler dSpaceRunnableHandler) throws ParseException {
this.setHandler(dSpaceRunnableHandler);
this.parse(args);
}
public abstract void internalRun() throws Exception;
public abstract void setup() throws ParseException;
}

View File

@@ -0,0 +1,63 @@
/**
* 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.scripts;
import org.apache.commons.cli.CommandLine;
public enum IndexClientOptions {
REMOVE,
CLEAN,
FORCECLEAN,
BUILD,
BUILDANDSPELLCHECK,
OPTIMIZE,
SPELLCHECK,
INDEX,
UPDATE,
FORCEUPDATE,
UPDATEANDSPELLCHECK,
FORCEUPDATEANDSPELLCHECK,
HELP;
public static IndexClientOptions getIndexClientOption(CommandLine commandLine) {
if (commandLine.hasOption("h")) {
return IndexClientOptions.HELP;
} else if (commandLine.hasOption("r")) {
return IndexClientOptions.REMOVE;
} else if (commandLine.hasOption("c")) {
if (commandLine.hasOption("f")) {
return IndexClientOptions.FORCECLEAN;
} else {
return IndexClientOptions.CLEAN;
}
} else if (commandLine.hasOption("b")) {
if (commandLine.hasOption("s")) {
return IndexClientOptions.BUILDANDSPELLCHECK;
} else {
return IndexClientOptions.BUILD;
}
} else if (commandLine.hasOption("o")) {
return IndexClientOptions.OPTIMIZE;
} else if (commandLine.hasOption("s")) {
return IndexClientOptions.SPELLCHECK;
} else if (commandLine.hasOption("i")) {
return IndexClientOptions.INDEX;
} else {
if (commandLine.hasOption("f") && commandLine.hasOption("s")) {
return IndexClientOptions.FORCEUPDATEANDSPELLCHECK;
} else if (commandLine.hasOption("f")) {
return IndexClientOptions.FORCEUPDATE;
} else if (commandLine.hasOption("s")) {
return IndexClientOptions.UPDATEANDSPELLCHECK;
} else {
return IndexClientOptions.UPDATE;
}
}
}
}

View File

@@ -0,0 +1,35 @@
/**
* 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.scripts.handler;
import java.sql.SQLException;
import org.apache.commons.cli.Options;
public interface DSpaceRunnableHandler {
public void start() throws SQLException;
public void handleCompletion() throws SQLException;
public void handleException(Exception e);
public void handleException(String message);
public void handleException(String message, Exception e);
public void logDebug(String message);
public void logInfo(String message);
public void logWarning(String message);
public void logError(String message);
public void printHelp(Options options, String name);
}

View File

@@ -0,0 +1,83 @@
/**
* 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.scripts.handler.impl;
import org.apache.commons.cli.HelpFormatter;
import org.apache.commons.cli.Options;
import org.apache.logging.log4j.Logger;
import org.dspace.scripts.handler.DSpaceRunnableHandler;
public class CommandLineDSpaceRunnableHandler implements DSpaceRunnableHandler {
private static final Logger log = org.apache.logging.log4j.LogManager
.getLogger(CommandLineDSpaceRunnableHandler.class);
@Override
public void start() {
System.out.println("The script has started");
}
@Override
public void handleCompletion() {
System.out.println("The script has completed");
}
@Override
public void handleException(Exception e) {
handleException(null, e);
}
@Override
public void handleException(String message) {
handleException(message, null);
}
@Override
public void handleException(String message, Exception e) {
if (message != null) {
System.err.println(message);
log.error(message);
}
if (e != null) {
e.printStackTrace();
log.error(e.getMessage(), e);
}
System.exit(1);
}
@Override
public void logDebug(String message) {
log.debug(message);
}
@Override
public void logInfo(String message) {
System.out.println(message);
log.info(message);
}
@Override
public void logWarning(String message) {
System.out.println(message);
log.warn(message);
}
@Override
public void logError(String message) {
System.err.println(message);
log.error(message);
}
@Override
public void printHelp(Options options, String name) {
if (options != null) {
HelpFormatter formatter = new HelpFormatter();
formatter.printHelp(name, options);
}
}
}

View File

@@ -0,0 +1,258 @@
/**
* 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.scripts.impl;
import java.io.IOException;
import java.sql.SQLException;
import java.util.Iterator;
import java.util.UUID;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;
import org.dspace.content.Collection;
import org.dspace.content.Community;
import org.dspace.content.Item;
import org.dspace.content.factory.ContentServiceFactory;
import org.dspace.content.service.ItemService;
import org.dspace.core.Constants;
import org.dspace.core.Context;
import org.dspace.discovery.IndexableObject;
import org.dspace.discovery.IndexingService;
import org.dspace.discovery.SearchServiceException;
import org.dspace.handle.factory.HandleServiceFactory;
import org.dspace.scripts.DSpaceRunnable;
import org.dspace.scripts.IndexClientOptions;
import org.springframework.beans.factory.annotation.Autowired;
public class IndexClient extends DSpaceRunnable {
private Context context;
@Autowired
private IndexingService indexer;
private IndexClientOptions indexClientOptions;
@Override
public void internalRun() throws Exception {
if (indexClientOptions == IndexClientOptions.HELP) {
printHelp();
return;
}
/** Acquire from dspace-services in future */
/**
* new DSpace.getServiceManager().getServiceByName("org.dspace.discovery.SolrIndexer");
*/
if (indexClientOptions == IndexClientOptions.REMOVE) {
handler.logInfo("Removing " + commandLine.getOptionValue("r") + " from Index");
indexer.unIndexContent(context, commandLine.getOptionValue("r"));
} else if (indexClientOptions == IndexClientOptions.CLEAN) {
handler.logInfo("Cleaning Index");
indexer.cleanIndex(false);
} else if (indexClientOptions == IndexClientOptions.FORCECLEAN) {
handler.logInfo("Cleaning Index");
indexer.cleanIndex(true);
} else if (indexClientOptions == IndexClientOptions.BUILD ||
indexClientOptions == IndexClientOptions.BUILDANDSPELLCHECK) {
handler.logInfo("(Re)building index from scratch.");
indexer.createIndex(context);
if (indexClientOptions == IndexClientOptions.BUILDANDSPELLCHECK) {
checkRebuildSpellCheck(commandLine, indexer);
}
} else if (indexClientOptions == IndexClientOptions.OPTIMIZE) {
handler.logInfo("Optimizing search core.");
indexer.optimize();
} else if (indexClientOptions == IndexClientOptions.SPELLCHECK) {
checkRebuildSpellCheck(commandLine, indexer);
} else if (indexClientOptions == IndexClientOptions.INDEX) {
final String param = commandLine.getOptionValue('i');
UUID uuid = null;
try {
uuid = UUID.fromString(param);
} catch (Exception e) {
// nothing to do, it should be an handle
}
IndexableObject dso = null;
if (uuid != null) {
dso = ContentServiceFactory.getInstance().getItemService().find(context, uuid);
if (dso == null) {
// it could be a community
dso = ContentServiceFactory.getInstance().getCommunityService().find(context, uuid);
if (dso == null) {
// it could be a collection
dso = ContentServiceFactory.getInstance().getCollectionService().find(context, uuid);
}
}
} else {
dso = (IndexableObject) HandleServiceFactory.getInstance()
.getHandleService().resolveToObject(context, param);
}
if (dso == null) {
throw new IllegalArgumentException("Cannot resolve " + param + " to a DSpace object");
}
handler.logInfo("Indexing " + param + " force " + commandLine.hasOption("f"));
final long startTimeMillis = System.currentTimeMillis();
final long count = indexAll(indexer, ContentServiceFactory.getInstance().getItemService(), context,
dso);
final long seconds = (System.currentTimeMillis() - startTimeMillis) / 1000;
handler.logInfo("Indexed " + count + " object" + (count > 1 ? "s" : "") + " in " + seconds + " seconds");
} else if (indexClientOptions == IndexClientOptions.UPDATE ||
indexClientOptions == IndexClientOptions.UPDATEANDSPELLCHECK) {
handler.logInfo("Updating and Cleaning Index");
indexer.cleanIndex(false);
indexer.updateIndex(context, false);
if (indexClientOptions == IndexClientOptions.UPDATEANDSPELLCHECK) {
checkRebuildSpellCheck(commandLine, indexer);
}
} else if (indexClientOptions == IndexClientOptions.FORCEUPDATE ||
indexClientOptions == IndexClientOptions.FORCEUPDATEANDSPELLCHECK) {
handler.logInfo("Updating and Cleaning Index");
indexer.cleanIndex(true);
indexer.updateIndex(context, true);
if (indexClientOptions == IndexClientOptions.FORCEUPDATEANDSPELLCHECK) {
checkRebuildSpellCheck(commandLine, indexer);
}
}
handler.logInfo("Done with indexing");
}
public void setup() throws ParseException {
try {
context = new Context(Context.Mode.READ_ONLY);
context.turnOffAuthorisationSystem();
} catch (Exception e) {
throw new ParseException("Unable to create a new DSpace Context: " + e.getMessage());
}
indexClientOptions = IndexClientOptions.getIndexClientOption(commandLine);
}
private IndexClient() {
Options options = constructOptions();
this.options = options;
}
private Options constructOptions() {
Options options = new Options();
options
.addOption("r", "remove", true, "remove an Item, Collection or Community from index based on its handle");
options.getOption("r").setType(String.class);
options.addOption("i", "index", true,
"add or update an Item, Collection or Community based on its handle or uuid");
options.getOption("i").setType(boolean.class);
options.addOption("c", "clean", false,
"clean existing index removing any documents that no longer exist in the db");
options.getOption("c").setType(boolean.class);
options.addOption("b", "build", false, "(re)build index, wiping out current one if it exists");
options.getOption("b").setType(boolean.class);
options.addOption("s", "spellchecker", false, "Rebuild the spellchecker, can be combined with -b and -f.");
options.getOption("s").setType(boolean.class);
options.addOption("f", "force", false,
"if updating existing index, force each handle to be reindexed even if uptodate");
options.getOption("f").setType(boolean.class);
options.addOption("h", "help", false, "print this help message");
options.getOption("h").setType(boolean.class);
return options;
}
/**
* Indexes the given object and all children, if applicable.
*
* @param indexingService
* @param itemService
* @param context The relevant DSpace Context.
* @param dso DSpace object to index recursively
* @throws IOException A general class of exceptions produced by failed or interrupted I/O operations.
* @throws SearchServiceException in case of a solr exception
* @throws SQLException An exception that provides information on a database access error or other errors.
*/
private static long indexAll(final IndexingService indexingService,
final ItemService itemService,
final Context context,
final IndexableObject dso)
throws IOException, SearchServiceException, SQLException {
long count = 0;
indexingService.indexContent(context, dso, true, true);
count++;
if (dso.getType() == Constants.COMMUNITY) {
final Community community = (Community) dso;
final String communityHandle = community.getHandle();
for (final Community subcommunity : community.getSubcommunities()) {
count += indexAll(indexingService, itemService, context, subcommunity);
//To prevent memory issues, discard an object from the cache after processing
context.uncacheEntity(subcommunity);
}
final Community reloadedCommunity = (Community) HandleServiceFactory.getInstance().getHandleService()
.resolveToObject(context,
communityHandle);
for (final Collection collection : reloadedCommunity.getCollections()) {
count++;
indexingService.indexContent(context, collection, true, true);
count += indexItems(indexingService, itemService, context, collection);
//To prevent memory issues, discard an object from the cache after processing
context.uncacheEntity(collection);
}
} else if (dso.getType() == Constants.COLLECTION) {
count += indexItems(indexingService, itemService, context, (Collection) dso);
}
return count;
}
/**
* Indexes all items in the given collection.
*
* @param indexingService
* @param itemService
* @param context The relevant DSpace Context.
* @param collection collection to index
* @throws IOException A general class of exceptions produced by failed or interrupted I/O operations.
* @throws SearchServiceException in case of a solr exception
* @throws SQLException An exception that provides information on a database access error or other errors.
*/
private static long indexItems(final IndexingService indexingService,
final ItemService itemService,
final Context context,
final Collection collection)
throws IOException, SearchServiceException, SQLException {
long count = 0;
final Iterator<Item> itemIterator = itemService.findByCollection(context, collection);
while (itemIterator.hasNext()) {
Item item = itemIterator.next();
indexingService.indexContent(context, item, true, false);
count++;
//To prevent memory issues, discard an object from the cache after processing
context.uncacheEntity(item);
}
indexingService.commit();
return count;
}
/**
* Check the command line options and rebuild the spell check if active.
*
* @param line the command line options
* @param indexer the solr indexer
* @throws SearchServiceException in case of a solr exception
* @throws IOException passed through
*/
protected void checkRebuildSpellCheck(CommandLine line, IndexingService indexer)
throws SearchServiceException, IOException {
handler.logInfo("Rebuilding spell checker.");
indexer.buildSpellCheck();
}
}

View File

@@ -0,0 +1,40 @@
--
-- 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/
--
-- ===============================================================
-- WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
--
-- DO NOT MANUALLY RUN THIS DATABASE MIGRATION. IT WILL BE EXECUTED
-- AUTOMATICALLY (IF NEEDED) BY "FLYWAY" WHEN YOU STARTUP DSPACE.
-- http://flywaydb.org/
-- ===============================================================
CREATE SEQUENCE process_id_seq;
CREATE TABLE process
(
process_id INTEGER NOT NULL PRIMARY KEY,
user_id UUID NOT NULL,
start_time TIMESTAMP,
finished_time TIMESTAMP,
creation_time TIMESTAMP NOT NULL,
script VARCHAR(256) NOT NULL,
status VARCHAR(32),
parameters VARCHAR (512)
);
CREATE TABLE process2bitstream
(
process_id INTEGER REFERENCES process(process_id),
bitstream_id UUID REFERENCES bitstream(uuid),
CONSTRAINT PK_process2bitstream PRIMARY KEY (process_id, bitstream_id)
);
CREATE INDEX process_user_id_idx ON process(user_id);
CREATE INDEX process_status_idx ON process(status);
CREATE INDEX process_name_idx on process(script);
CREATE INDEX process_start_time_idx on process(start_time);

View File

@@ -0,0 +1,90 @@
/**
* 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.rest;
import java.sql.SQLException;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.dspace.app.rest.link.HalLinkService;
import org.dspace.app.rest.model.ProcessRest;
import org.dspace.app.rest.model.hateoas.EmbeddedPage;
import org.dspace.app.rest.model.hateoas.ProcessResource;
import org.dspace.app.rest.repository.ProcessRestRepository;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import org.springframework.hateoas.Link;
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.bind.annotation.RestController;
@RestController
@RequestMapping("/api/" + ProcessRest.CATEGORY + "/" + ProcessRest.PLURAL_NAME)
public class ProcessRestController implements InitializingBean {
private static final Logger log = LogManager.getLogger();
@Autowired
HalLinkService linkService;
@Autowired
private DiscoverableEndpointsService discoverableEndpointsService;
@Autowired
private ProcessRestRepository processRestRepository;
@Override
public void afterPropertiesSet() throws Exception {
discoverableEndpointsService
.register(this, Arrays.asList(
new Link("/api/" + ProcessRest.CATEGORY + "/" + ProcessRest.PLURAL_NAME, ProcessRest.PLURAL_NAME)));
}
@RequestMapping(method = RequestMethod.GET)
public EmbeddedPage getProcesses(Pageable pageable) throws Exception {
if (log.isTraceEnabled()) {
log.trace("Retrieving processes");
}
List<ProcessRest> processRestList = processRestRepository.getAllProcesses();
List<ProcessResource> processResources = new LinkedList<>();
for (ProcessRest processRest : processRestList) {
ProcessResource processResource = new ProcessResource(processRest);
linkService.addLinks(processResource);
processResources.add(processResource);
}
Page page = new PageImpl<>(processResources, pageable, processRestList.size());
// SearchResultsResourceHalLinkFactory linkFactory = new SearchResultsResourceHalLinkFactory();
EmbeddedPage embeddedPage = new EmbeddedPage("test",
page, processResources, "scripts");
return embeddedPage;
}
@RequestMapping(method = RequestMethod.GET, value = "/{processId}")
public ProcessResource getProcessById(@PathVariable(name = "processId") Integer processId) throws SQLException {
if (log.isTraceEnabled()) {
log.trace("Retrieving Process with ID: " + processId);
}
ProcessRest processRest = processRestRepository.getProcessById(processId);
ProcessResource processResource = new ProcessResource(processRest);
linkService.addLinks(processResource);
return processResource;
}
}

View File

@@ -0,0 +1,47 @@
/**
* 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.rest;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.dspace.app.rest.model.ProcessRest;
import org.dspace.app.rest.model.ScriptRest;
import org.dspace.app.rest.model.hateoas.ProcessResource;
import org.dspace.app.rest.repository.ScriptRestRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
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.bind.annotation.RestController;
@RestController
@RequestMapping("/api/" + ScriptRest.CATEGORY + "/" + ScriptRest.PLURAL_NAME)
public class ScriptRestController {
private static final Logger log = LogManager.getLogger();
@Autowired
private DiscoverableEndpointsService discoverableEndpointsService;
@Autowired
private ScriptRestRepository scriptRestRepository;
@RequestMapping(method = RequestMethod.POST, value = "/{name}/processes")
@PreAuthorize("hasAuthority('ADMIN')")
public ProcessResource startProcess(@PathVariable(name = "name") String scriptName) throws Exception {
if (log.isTraceEnabled()) {
log.trace("Starting Process for Script with name: " + scriptName);
}
ProcessRest processRest = scriptRestRepository.startProcess(scriptName);
ProcessResource processResource = new ProcessResource(processRest);
return processResource;
}
}

View File

@@ -0,0 +1,28 @@
/**
* 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.rest.converter;
import org.dspace.app.rest.model.ParameterValueRest;
import org.dspace.scripts.DSpaceCommandLineParameter;
import org.springframework.stereotype.Component;
@Component
public class DSpaceRunnableParameterConverter
implements DSpaceConverter<DSpaceCommandLineParameter, ParameterValueRest> {
public ParameterValueRest fromModel(DSpaceCommandLineParameter dSpaceCommandLineParameter) {
ParameterValueRest parameterValueRest = new ParameterValueRest();
parameterValueRest.setName(dSpaceCommandLineParameter.getName());
parameterValueRest.setValue(dSpaceCommandLineParameter.getValue());
return parameterValueRest;
}
public DSpaceCommandLineParameter toModel(ParameterValueRest parameterValueRest) {
return new DSpaceCommandLineParameter(parameterValueRest.getName(), parameterValueRest.getValue());
}
}

View File

@@ -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.app.rest.converter;
import org.dspace.app.rest.converter.processes.ParameterConverter;
import org.dspace.app.rest.model.ScriptRest;
import org.dspace.scripts.DSpaceRunnable;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class ScriptConverter implements DSpaceConverter<DSpaceRunnable, ScriptRest> {
@Autowired
private ParameterConverter parameterConverter;
public ScriptRest fromModel(DSpaceRunnable script) {
ScriptRest scriptRest = new ScriptRest();
scriptRest.setDescription(script.getDescription());
scriptRest.setId(script.getName());
scriptRest.setName(script.getName());
scriptRest.setParameterRestList(parameterConverter.convertOptionsToParameterRestList(script.getOptions()));
return scriptRest;
}
public DSpaceRunnable toModel(ScriptRest obj) {
return null;
}
}

View File

@@ -0,0 +1,35 @@
/**
* 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.rest.converter.processes;
import java.util.LinkedList;
import java.util.List;
import org.apache.commons.cli.Option;
import org.apache.commons.cli.Options;
import org.apache.commons.collections4.CollectionUtils;
import org.dspace.app.rest.model.ParameterRest;
import org.springframework.stereotype.Component;
@Component
public class ParameterConverter {
public List<ParameterRest> convertOptionsToParameterRestList(Options options) {
List<ParameterRest> listToReturn = new LinkedList<>();
for (Option option : CollectionUtils.emptyIfNull(options.getOptions())) {
ParameterRest parameterRest = new ParameterRest();
parameterRest.setDescription(option.getDescription());
parameterRest.setName(option.getOpt());
parameterRest.setType(((Class) option.getType()).getSimpleName());
listToReturn.add(parameterRest);
}
return listToReturn;
}
}

View File

@@ -0,0 +1,45 @@
/**
* 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.rest.converter.processes;
import java.util.stream.Collectors;
import org.dspace.app.rest.converter.DSpaceConverter;
import org.dspace.app.rest.converter.DSpaceRunnableParameterConverter;
import org.dspace.app.rest.model.ProcessRest;
import org.dspace.content.Process;
import org.dspace.content.service.ProcessService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class ProcessConverter implements DSpaceConverter<Process, ProcessRest> {
@Autowired
private ProcessService processService;
@Autowired
private DSpaceRunnableParameterConverter dSpaceRunnableParameterConverter;
public ProcessRest fromModel(Process process) {
ProcessRest processRest = new ProcessRest();
processRest.setScriptName(process.getName());
processRest.setProcessId(process.getID());
processRest.setUserId(process.getEPerson().getID());
processRest.setProcessStatus(process.getProcessStatus());
processRest.setStartTime(process.getStartTime());
processRest.setParameterRestList(
processService.getParameters(process).stream().map(x -> dSpaceRunnableParameterConverter.fromModel(x))
.collect(Collectors.toList()));
return processRest;
}
public Process toModel(ProcessRest obj) {
return null;
}
}

View File

@@ -0,0 +1,47 @@
/**
* 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.rest.link.process;
import java.util.LinkedList;
import org.dspace.app.rest.ProcessRestController;
import org.dspace.app.rest.link.HalLinkFactory;
import org.dspace.app.rest.model.hateoas.ProcessResource;
import org.dspace.services.ConfigurationService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Pageable;
import org.springframework.hateoas.Link;
import org.springframework.stereotype.Component;
@Component
public class ProcessHalLinkFactory extends HalLinkFactory<ProcessResource, ProcessRestController> {
@Autowired
private ConfigurationService configurationService;
protected void addLinks(ProcessResource halResource, Pageable pageable, LinkedList<Link> list) throws Exception {
String dspaceRestUrl = configurationService.getProperty("dspace.restUrl");
list.add(buildLink(Link.REL_SELF, getMethodOn().getProcessById(halResource.getContent().getProcessId())));
list.add(
buildLink("script", dspaceRestUrl + "/api/system/scripts/" + halResource.getContent().getScriptName()));
// TODO Replace the bottom two with getMethodOn() when the Controller methods are created
list.add(buildLink("output", dspaceRestUrl + "/api/system/processes/" + halResource.getContent()
.getProcessId() + "/output"
));
list.add(buildLink("files", dspaceRestUrl + "/api/system/processes/" + halResource.getContent()
.getProcessId() + "/files"));
}
protected Class<ProcessRestController> getControllerClass() {
return ProcessRestController.class;
}
protected Class<ProcessResource> getResourceClass() {
return ProcessResource.class;
}
}

View File

@@ -0,0 +1,39 @@
/**
* 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.rest.model;
public class ParameterRest {
private String name;
private String description;
private String type;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
}

View File

@@ -0,0 +1,42 @@
/**
* 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.rest.model;
import org.apache.commons.lang3.StringUtils;
public class ParameterValueRest {
private String name;
private String value;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
public String toString() {
String stringToReturn = "";
stringToReturn += getName();
if (StringUtils.isNotBlank(getValue())) {
stringToReturn += " ";
stringToReturn += getValue();
}
return stringToReturn;
}
}

View File

@@ -0,0 +1,96 @@
/**
* 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.rest.model;
import java.util.Date;
import java.util.List;
import java.util.UUID;
import com.fasterxml.jackson.annotation.JsonIgnore;
import org.dspace.app.rest.ProcessRestController;
import org.dspace.content.ProcessStatus;
public class ProcessRest extends BaseObjectRest<UUID> {
public static final String NAME = "process";
public static final String PLURAL_NAME = "processes";
public static final String CATEGORY = RestAddressableModel.SYSTEM;
public String getCategory() {
return CATEGORY;
}
public Class getController() {
return ProcessRestController.class;
}
public String getType() {
return NAME;
}
private String scriptName;
private UUID userId;
private Integer processId;
private Date startTime;
private ProcessStatus processStatus;
private List<ParameterValueRest> parameterRestList;
public UUID getUserId() {
return userId;
}
public void setUserId(UUID userId) {
this.userId = userId;
}
public Integer getProcessId() {
return processId;
}
public void setProcessId(Integer processId) {
this.processId = processId;
}
public ProcessStatus getProcessStatus() {
return processStatus;
}
public void setProcessStatus(ProcessStatus processStatus) {
this.processStatus = processStatus;
}
public List<ParameterValueRest> getParameterRestList() {
return parameterRestList;
}
public void setParameterRestList(List<ParameterValueRest> parameterRestList) {
this.parameterRestList = parameterRestList;
}
public Date getStartTime() {
return startTime;
}
public void setStartTime(Date startTime) {
this.startTime = startTime;
}
public String getScriptName() {
return scriptName;
}
public void setScriptName(String scriptName) {
this.scriptName = scriptName;
}
@JsonIgnore
@Override
public UUID getId() {
return id;
}
}

View File

@@ -27,6 +27,7 @@ public interface RestModel extends Serializable {
public static final String CONFIGURATION = "config"; public static final String CONFIGURATION = "config";
public static final String INTEGRATION = "integration"; public static final String INTEGRATION = "integration";
public static final String SUBMISSION = "submission"; public static final String SUBMISSION = "submission";
public static final String SYSTEM = "system";
public static final String WORKFLOW = "workflow"; public static final String WORKFLOW = "workflow";
public static final String AUTHORIZATION = "authz"; public static final String AUTHORIZATION = "authz";

View File

@@ -0,0 +1,73 @@
/**
* 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.rest.model;
import java.util.LinkedList;
import java.util.List;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;
import org.dspace.app.rest.RestResourceController;
public class ScriptRest extends BaseObjectRest<String> {
public static final String NAME = "script";
public static final String PLURAL_NAME = "scripts";
public static final String CATEGORY = RestAddressableModel.SYSTEM;
private String name;
private String description;
@JsonProperty(value = "parameters")
private List<ParameterRest> parameterRestList = new LinkedList<>();
public String getCategory() {
return CATEGORY;
}
public Class getController() {
return RestResourceController.class;
}
public String getType() {
return NAME;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public List<ParameterRest> getParameterRestList() {
return parameterRestList;
}
public void setParameterRestList(List<ParameterRest> parameterRestList) {
this.parameterRestList = parameterRestList;
}
public void addToParameterRestList(ParameterRest parameter) {
parameterRestList.add(parameter);
}
@JsonIgnore
public String getId() {
return id;
}
}

View 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.app.rest.model.hateoas;
import org.dspace.app.rest.model.ProcessRest;
import org.dspace.app.rest.model.hateoas.annotations.RelNameDSpaceResource;
@RelNameDSpaceResource(ProcessRest.NAME)
public class ProcessResource extends HALResource<ProcessRest> {
public ProcessResource(ProcessRest content) {
super(content);
}
}

View File

@@ -0,0 +1,19 @@
/**
* 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.rest.model.hateoas;
import org.dspace.app.rest.model.ScriptRest;
import org.dspace.app.rest.model.hateoas.annotations.RelNameDSpaceResource;
import org.dspace.app.rest.utils.Utils;
@RelNameDSpaceResource(ScriptRest.NAME)
public class ScriptResource extends DSpaceResource<ScriptRest> {
public ScriptResource(ScriptRest data, Utils utils, String... rels) {
super(data, utils, rels);
}
}

View File

@@ -0,0 +1,48 @@
/**
* 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.rest.repository;
import java.sql.SQLException;
import java.util.LinkedList;
import java.util.List;
import org.dspace.app.rest.converter.processes.ProcessConverter;
import org.dspace.app.rest.model.ProcessRest;
import org.dspace.content.Process;
import org.dspace.content.service.ProcessService;
import org.dspace.core.Context;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component(ProcessRest.CATEGORY + "." + ProcessRest.NAME)
public class ProcessRestRepository extends AbstractDSpaceRestRepository {
@Autowired
private ProcessService processService;
@Autowired
private ProcessConverter processConverter;
public List<ProcessRest> getAllProcesses() throws SQLException {
Context context = obtainContext();
List<Process> list = processService.findAll(context);
List<ProcessRest> listToReturn = new LinkedList<>();
for (Process process : list) {
listToReturn.add(processConverter.fromModel(process));
}
return listToReturn;
}
public ProcessRest getProcessById(Integer processId) throws SQLException {
Context context = obtainContext();
Process process = processService.find(context, processId);
return processConverter.fromModel(process);
}
}

View File

@@ -0,0 +1,140 @@
/**
* 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.rest.repository;
import java.io.IOException;
import java.sql.SQLException;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import java.util.stream.Collectors;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.commons.cli.ParseException;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.dspace.app.rest.converter.DSpaceRunnableParameterConverter;
import org.dspace.app.rest.converter.ScriptConverter;
import org.dspace.app.rest.converter.processes.ProcessConverter;
import org.dspace.app.rest.exception.DSpaceBadRequestException;
import org.dspace.app.rest.model.ParameterValueRest;
import org.dspace.app.rest.model.ProcessRest;
import org.dspace.app.rest.model.ScriptRest;
import org.dspace.app.rest.model.hateoas.DSpaceResource;
import org.dspace.app.rest.model.hateoas.ScriptResource;
import org.dspace.app.rest.scripts.handler.impl.RestDSpaceRunnableHandler;
import org.dspace.content.service.ProcessService;
import org.dspace.core.Context;
import org.dspace.scripts.DSpaceCommandLineParameter;
import org.dspace.scripts.DSpaceRunnable;
import org.dspace.utils.DSpace;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Component;
@Component(ScriptRest.CATEGORY + "." + ScriptRest.NAME)
public class ScriptRestRepository extends DSpaceRestRepository<ScriptRest, String> {
private static final Logger log = LogManager.getLogger();
@Autowired
private List<DSpaceRunnable> dspaceRunnables;
@Autowired
private ScriptConverter scriptConverter;
@Autowired
private ProcessService processService;
@Autowired
private ProcessConverter processConverter;
@Autowired
private DSpaceRunnableParameterConverter dSpaceRunnableParameterConverter;
@Override
public ScriptRest findOne(Context context, String name) {
for (DSpaceRunnable dSpaceRunnable : dspaceRunnables) {
if (StringUtils.equalsIgnoreCase(dSpaceRunnable.getName(), name)) {
return scriptConverter.fromModel(dSpaceRunnable);
}
}
throw new DSpaceBadRequestException("The script with name: " + name + " could not be found");
}
@Override
public Page<ScriptRest> findAll(Context context, Pageable pageable) {
List list = dspaceRunnables.stream().skip(pageable.getOffset()).limit(pageable.getPageSize())
.collect(Collectors.toList());
Page<ScriptRest> scriptRestPage = new PageImpl<>(list, pageable, dspaceRunnables.size()).map(scriptConverter);
return scriptRestPage;
}
public Class<ScriptRest> getDomainClass() {
return ScriptRest.class;
}
public DSpaceResource<ScriptRest> wrapResource(ScriptRest model, String... rels) {
return new ScriptResource(model, utils, rels);
}
public ProcessRest startProcess(String scriptName) throws SQLException, IOException {
Context context = obtainContext();
List<ParameterValueRest> parameterValueRestList = new LinkedList<>();
ObjectMapper objectMapper = new ObjectMapper();
String propertiesJson = requestService.getCurrentRequest().getServletRequest().getParameter("properties");
if (StringUtils.isNotBlank(propertiesJson)) {
try {
parameterValueRestList = Arrays
.asList(objectMapper.readValue(propertiesJson, ParameterValueRest[].class));
} catch (IOException e) {
log.error(
"Couldn't convert the given properties to proper ParameterValueRest objects: " + propertiesJson, e);
throw e;
}
}
List<DSpaceCommandLineParameter> dSpaceCommandLineParameters = new LinkedList<>();
dSpaceCommandLineParameters.addAll(
parameterValueRestList.stream().map(x -> dSpaceRunnableParameterConverter.toModel(x))
.collect(Collectors.toList()));
try {
RestDSpaceRunnableHandler restDSpaceRunnableHandler = new RestDSpaceRunnableHandler(
context.getCurrentUser(), scriptName, dSpaceCommandLineParameters);
runDSpaceScriptWithArgs(dSpaceCommandLineParameters.stream().map(x -> x.toString()).toArray(String[]::new),
restDSpaceRunnableHandler, scriptName);
context.complete();
return processConverter.fromModel(restDSpaceRunnableHandler.getProcess());
} catch (SQLException e) {
log.error("Failed to create a process with user: " + context.getCurrentUser() +
" scriptname: " + scriptName + " and parameters " + DSpaceCommandLineParameter
.concatenate(dSpaceCommandLineParameters), e);
}
return null;
}
private void runDSpaceScriptWithArgs(String[] args, RestDSpaceRunnableHandler dSpaceRunnableHandler,
String scriptName) {
List<DSpaceRunnable> scripts = new DSpace().getServiceManager().getServicesByType(DSpaceRunnable.class);
for (DSpaceRunnable script : scripts) {
if (StringUtils.equalsIgnoreCase(script.getName(), scriptName)) {
try {
script.initialize(args, dSpaceRunnableHandler);
dSpaceRunnableHandler.schedule(script);
} catch (ParseException e) {
script.printHelp();
dSpaceRunnableHandler.handleException("Failed to parse the arguments given to the script with name: " + scriptName
+ " and args: " + Arrays.toString(args), e);
}
}
}
}
}

View File

@@ -0,0 +1,202 @@
/**
* 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.rest.scripts.handler.impl;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.sql.SQLException;
import java.util.List;
import org.apache.commons.cli.HelpFormatter;
import org.apache.commons.cli.Options;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.apache.logging.log4j.Logger;
import org.dspace.content.Process;
import org.dspace.content.ProcessStatus;
import org.dspace.content.factory.ProcessServiceFactory;
import org.dspace.content.service.ProcessService;
import org.dspace.core.Context;
import org.dspace.eperson.EPerson;
import org.dspace.scripts.DSpaceCommandLineParameter;
import org.dspace.scripts.DSpaceRunnable;
import org.dspace.scripts.handler.DSpaceRunnableHandler;
import org.dspace.utils.DSpace;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
public class RestDSpaceRunnableHandler implements DSpaceRunnableHandler {
private static final Logger log = org.apache.logging.log4j.LogManager
.getLogger(RestDSpaceRunnableHandler.class);
private ProcessService processService = ProcessServiceFactory.getInstance().getProcessService();
private Integer processId;
private String scriptName;
public RestDSpaceRunnableHandler(EPerson ePerson, String scriptName, List<DSpaceCommandLineParameter> parameters) {
Context context = new Context();
try {
Process process = processService.create(context, ePerson, scriptName, parameters);
processId = process.getID();
this.scriptName = process.getName();
context.complete();
} catch (SQLException e) {
log.error("RestDSpaceRunnableHandler with ePerson: " + ePerson
.getEmail() + " for Script with name: " + scriptName +
" and parameters: " + parameters + " could nto be created", e);
} finally {
if (context.isValid()) {
context.abort();
}
}
}
@Override
public void start() {
Context context = new Context();
try {
Process process = processService.find(context, processId);
processService.start(context, process);
context.complete();
logInfo("The script has started");
} catch (SQLException e) {
log.error("RestDSpaceRunnableHandler with process: " + processId + " could not be started", e);
} finally {
if (context.isValid()) {
context.abort();
}
}
}
@Override
public void handleCompletion() {
Context context = new Context();
try {
Process process = processService.find(context, processId);
processService.complete(context, process);
context.complete();
logInfo("The script has completed");
} catch (SQLException e) {
log.error("RestDSpaceRunnableHandler with process: " + processId + " could not be completed", e);
} finally {
if (context.isValid()) {
context.abort();
}
}
}
@Override
public void handleException(Exception e) {
handleException(null, e);
}
@Override
public void handleException(String message) {
handleException(message, null);
}
@Override
public void handleException(String message, Exception e) {
if (message != null) {
logError(message);
}
if (e != null) {
logError(ExceptionUtils.getStackTrace(e));
}
Context context = new Context();
try {
Process process = processService.find(context, processId);
processService.fail(context, process);
context.complete();
} catch (SQLException sqlException) {
log.error("SQL exception while handling another exception", e);
} finally {
if (context.isValid()) {
context.abort();
}
}
}
@Override
public void logDebug(String message) {
String logMessage = getLogMessage(message);
log.debug(logMessage);
}
private String getLogMessage(String message) {
return String
.format("Process id: %d, script name: %s, message: %s", processId, scriptName, message);
}
@Override
public void logInfo(String message) {
String logMessage = getLogMessage(message);
log.info(logMessage);
}
@Override
public void logWarning(String message) {
String logMessage = getLogMessage(message);
log.warn(logMessage);
}
@Override
public void logError(String message) {
String logMessage = getLogMessage(message);
log.error(logMessage);
}
@Override
public void printHelp(Options options, String name) {
if (options != null) {
HelpFormatter formatter = new HelpFormatter();
StringWriter out = new StringWriter();
PrintWriter pw = new PrintWriter(out);
formatter.printUsage(pw, 1000, name, options);
pw.flush();
String helpString = out.toString();
logInfo(helpString);
}
}
public Process getProcess() {
Context context = new Context();
try {
return processService.find(context, processId);
} catch (SQLException e) {
log.error("RestDSpaceRunnableHandler with process: " + processId + " could not be found", e);
} finally {
if (context.isValid()) {
context.abort();
}
}
return null;
}
public void schedule(DSpaceRunnable script) {
Context context = new Context();
try {
Process process = processService.find(context, processId);
process.setProcessStatus(ProcessStatus.SCHEDULED);
processService.update(context, process);
context.complete();
} catch (SQLException e) {
log.error("RestDSpaceRunnableHandler with process: " + processId + " ran into an SQLException", e);
} finally {
if (context.isValid()) {
context.abort();
}
}
script.run();
}
}

View File

@@ -48,6 +48,8 @@
<mapping class="org.dspace.content.RelationshipType"/> <mapping class="org.dspace.content.RelationshipType"/>
<mapping class="org.dspace.content.EntityType"/> <mapping class="org.dspace.content.EntityType"/>
<mapping class="org.dspace.content.Process"/>
<mapping class="org.dspace.content.MetadataField"/> <mapping class="org.dspace.content.MetadataField"/>
<mapping class="org.dspace.content.MetadataSchema"/> <mapping class="org.dspace.content.MetadataSchema"/>
<mapping class="org.dspace.content.MetadataValue"/> <mapping class="org.dspace.content.MetadataValue"/>

View File

@@ -32,6 +32,8 @@
<bean class="org.dspace.content.dao.impl.EntityTypeDAOImpl"/> <bean class="org.dspace.content.dao.impl.EntityTypeDAOImpl"/>
<bean class="org.dspace.content.dao.impl.RelationshipTypeDAOImpl"/> <bean class="org.dspace.content.dao.impl.RelationshipTypeDAOImpl"/>
<bean class="org.dspace.content.dao.impl.ProcessDAOImpl"/>
<bean class="org.dspace.eperson.dao.impl.EPersonDAOImpl"/> <bean class="org.dspace.eperson.dao.impl.EPersonDAOImpl"/>
<bean class="org.dspace.eperson.dao.impl.Group2GroupCacheDAOImpl"/> <bean class="org.dspace.eperson.dao.impl.Group2GroupCacheDAOImpl"/>
<bean class="org.dspace.eperson.dao.impl.GroupDAOImpl"/> <bean class="org.dspace.eperson.dao.impl.GroupDAOImpl"/>

View File

@@ -22,6 +22,7 @@
<bean id="authorizeServiceFactory" class="org.dspace.authorize.factory.AuthorizeServiceFactoryImpl"/> <bean id="authorizeServiceFactory" class="org.dspace.authorize.factory.AuthorizeServiceFactoryImpl"/>
<bean id="checkerServiceFactory" class="org.dspace.checker.factory.CheckerServiceFactoryImpl"/> <bean id="checkerServiceFactory" class="org.dspace.checker.factory.CheckerServiceFactoryImpl"/>
<bean id="contentServiceFactory" class="org.dspace.content.factory.ContentServiceFactoryImpl"/> <bean id="contentServiceFactory" class="org.dspace.content.factory.ContentServiceFactoryImpl"/>
<bean id="processServiceFactory" class="org.dspace.content.factory.impl.ProcessServiceFactoryImpl"/>
<bean id="coreServiceFactory" class="org.dspace.core.factory.CoreServiceFactoryImpl"/> <bean id="coreServiceFactory" class="org.dspace.core.factory.CoreServiceFactoryImpl"/>
<bean id="curateServiceFactory" class="org.dspace.curate.factory.CurateServiceFactoryImpl"/> <bean id="curateServiceFactory" class="org.dspace.curate.factory.CurateServiceFactoryImpl"/>

View File

@@ -55,6 +55,8 @@
<bean class="org.dspace.content.EntityServiceImpl"/> <bean class="org.dspace.content.EntityServiceImpl"/>
<bean class="org.dspace.content.RelationshipTypeServiceImpl"/> <bean class="org.dspace.content.RelationshipTypeServiceImpl"/>
<bean class="org.dspace.content.ProcessServiceImpl"/>
<bean class="org.dspace.content.authority.ChoiceAuthorityServiceImpl"/> <bean class="org.dspace.content.authority.ChoiceAuthorityServiceImpl"/>
<bean class="org.dspace.content.authority.MetadataAuthorityServiceImpl" lazy-init="true"/> <bean class="org.dspace.content.authority.MetadataAuthorityServiceImpl" lazy-init="true"/>
@@ -112,5 +114,7 @@
<bean class="org.dspace.xmlworkflow.XmlWorkflowServiceImpl"/> <bean class="org.dspace.xmlworkflow.XmlWorkflowServiceImpl"/>
<bean class="org.dspace.xmlworkflow.WorkflowRequirementsServiceImpl"/> <bean class="org.dspace.xmlworkflow.WorkflowRequirementsServiceImpl"/>
<bean class="org.dspace.xmlworkflow.XmlWorkflowFactoryImpl"/> <bean class="org.dspace.xmlworkflow.XmlWorkflowFactoryImpl"/>
</beans> </beans>

View File

@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<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">
<bean id="indexClient" class="org.dspace.scripts.impl.IndexClient" scope="prototype">
<property name="name" value="index-discovery"/>
<property name="description" value="Update Discovery Solr Search Index"/>
</bean>
</beans>