added dnet-information-serice, which embeds old cnr-xmldb, cnr-enabling-services
This commit is contained in:
parent
c121531bdc
commit
103acc089e
|
@ -65,12 +65,6 @@
|
|||
<artifactId>gson</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>log4j</groupId>
|
||||
<artifactId>log4j</artifactId>
|
||||
|
|
|
@ -0,0 +1,152 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>eu.dnetlib</groupId>
|
||||
<artifactId>dnet-core</artifactId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>dnet-information-service</artifactId>
|
||||
<groupId>eu.dnetlib</groupId>
|
||||
<packaging>jar</packaging>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>eu.dnetlib</groupId>
|
||||
<artifactId>dnet-core-components</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>eu.dnetlib</groupId>
|
||||
<artifactId>dnet-core-services</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Spring -->
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-orm</artifactId>
|
||||
</dependency>
|
||||
|
||||
|
||||
|
||||
<!-- Exist XmlDB -->
|
||||
<dependency>
|
||||
<groupId>org.exist-db</groupId>
|
||||
<artifactId>exist-core</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.exist-db</groupId>
|
||||
<artifactId>exist-start</artifactId>
|
||||
</dependency>
|
||||
|
||||
|
||||
|
||||
<dependency>
|
||||
<groupId>org.postgresql</groupId>
|
||||
<artifactId>postgresql</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.xerial</groupId>
|
||||
<artifactId>sqlite-jdbc</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.hibernate</groupId>
|
||||
<artifactId>hibernate-core</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>commons-collections</groupId>
|
||||
<artifactId>commons-collections</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>commons-dbcp</groupId>
|
||||
<artifactId>commons-dbcp</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.sun.xml.messaging.saaj</groupId>
|
||||
<artifactId>saaj-impl</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>jaxen</groupId>
|
||||
<artifactId>jaxen</artifactId>
|
||||
</dependency>
|
||||
|
||||
|
||||
|
||||
<dependency>
|
||||
<groupId>xerces</groupId>
|
||||
<artifactId>xercesImpl</artifactId>
|
||||
<!-- scope needed for both compile and test -->
|
||||
<!-- <scope>compile</scope> -->
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.aspectj</groupId>
|
||||
<artifactId>aspectjrt</artifactId>
|
||||
<!-- scope needed for both compile and test -->
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>commons-codec</groupId>
|
||||
<artifactId>commons-codec</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>commons-beanutils</groupId>
|
||||
<artifactId>commons-beanutils</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.cxf</groupId>
|
||||
<artifactId>cxf-rt-frontend-jaxws</artifactId>
|
||||
</dependency>
|
||||
|
||||
|
||||
<!-- Test deps -->
|
||||
<dependency>
|
||||
<groupId>hsqldb</groupId>
|
||||
<artifactId>hsqldb</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.aspectj</groupId>
|
||||
<artifactId>aspectjweaver</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.hibernate</groupId>
|
||||
<artifactId>hibernate-annotations</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-webmvc</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.cxf</groupId>
|
||||
<artifactId>cxf-rt-ws-policy</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.cxf</groupId>
|
||||
<artifactId>cxf-rt-frontend-jaxrs</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.cxf</groupId>
|
||||
<artifactId>cxf-rt-transports-local</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.cxf</groupId>
|
||||
<artifactId>cxf-rt-ws-rm</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
</project>
|
|
@ -0,0 +1,394 @@
|
|||
package eu.dnetlib.enabling.is.lookup;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.StringReader;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import javax.jws.WebService;
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
import javax.xml.xpath.XPathExpressionException;
|
||||
|
||||
import com.sun.xml.messaging.saaj.util.Base64;
|
||||
import eu.dnetlib.enabling.is.lookup.rmi.ISLookUpDocumentNotFoundException;
|
||||
import eu.dnetlib.enabling.is.lookup.rmi.ISLookUpException;
|
||||
import eu.dnetlib.enabling.is.lookup.rmi.ISLookUpService;
|
||||
import eu.dnetlib.enabling.is.store.rmi.ISStoreException;
|
||||
import eu.dnetlib.enabling.is.store.rmi.ISStoreService;
|
||||
import eu.dnetlib.enabling.tools.*;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.dom4j.Document;
|
||||
import org.dom4j.Element;
|
||||
import org.dom4j.io.SAXReader;
|
||||
import org.springframework.beans.factory.annotation.Required;
|
||||
import org.xml.sax.SAXException;
|
||||
|
||||
/**
|
||||
* ISLookUpService implementation.
|
||||
*
|
||||
* @author marko
|
||||
* @author michele
|
||||
*
|
||||
*/
|
||||
@WebService(targetNamespace = "http://services.dnetlib.eu/")
|
||||
public class ISLookUpServiceImpl extends AbstractBaseService implements ISLookUpService { // NOPMD
|
||||
|
||||
/**
|
||||
* error message when the given collection cannot be fetched.
|
||||
*/
|
||||
private static final String COLLECTION_ERROR = "cannot get collection";
|
||||
|
||||
/**
|
||||
* base xmldb directory.
|
||||
*/
|
||||
private static final String DB_BASE_DIR = "/db/DRIVER";
|
||||
|
||||
/**
|
||||
* error message when the profile is not present in the db.
|
||||
*/
|
||||
private static final String PROFILE_NOT_FOUND = "Profile not found";
|
||||
|
||||
private ISStoreService isStore;
|
||||
|
||||
// NOPMD by marko on 11/24/08
|
||||
// 5:02 PM
|
||||
/**
|
||||
* logger.
|
||||
*/
|
||||
public static final Log log = LogFactory.getLog(ISLookUpServiceImpl.class); // NOPMD by marko on 11/24/08 5:02 PM
|
||||
|
||||
/**
|
||||
* resource identifier resolver. Resolves identifiers to xmldb file and collection names.
|
||||
*/
|
||||
private ResourceIdentifierResolver resIdManager = new CompatResourceIdentifierResolverImpl();
|
||||
|
||||
/**
|
||||
* xquery utils. Used to obtain the xmldb collection mapping for resources.
|
||||
*/
|
||||
private XQueryUtils xqueryUtils;
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @see eu.dnetlib.enabling.is.lookup.rmi.ISLookUpService#flushCachedResultSets()
|
||||
*/
|
||||
@Override
|
||||
public Boolean flushCachedResultSets() {
|
||||
// TODO Auto-generated method stub
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @see eu.dnetlib.enabling.is.lookup.rmi.ISLookUpService#retrieveCollection(java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public String retrieveCollection(final String profId) throws ISLookUpException {
|
||||
try {
|
||||
String profile = this.getResourceProfile(profId);
|
||||
final List<String> list = quickSearchProfile("for $x in collection('/db/DRIVER/CollectionDSResources') where $x//FATHER/@id = '" + profId
|
||||
+ "' return $x//RESOURCE_IDENTIFIER/@value/string()");
|
||||
|
||||
if (!list.isEmpty()) {
|
||||
final SAXReader reader = new SAXReader();
|
||||
final Document doc = reader.read(new StringReader(profile));
|
||||
final Element childrenNode = (Element) doc.selectSingleNode("//CHILDREN"); // NOPMD
|
||||
for (final String idC : list) {
|
||||
childrenNode.addElement("CHILD").addAttribute("id", idC);
|
||||
}
|
||||
profile = doc.asXML();
|
||||
}
|
||||
|
||||
return profile;
|
||||
} catch (final Exception e) {
|
||||
throw new ISLookUpException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @see eu.dnetlib.enabling.is.lookup.rmi.ISLookUpService#getCollection(java.lang.String, java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public String getCollection(final String profId, final String format) throws ISLookUpException {
|
||||
OpaqueResource prof;
|
||||
try {
|
||||
prof = new StringOpaqueResource(profId);
|
||||
|
||||
final StringBuilder query = new StringBuilder();
|
||||
if (format != null && format.equals("ui")) {
|
||||
query.append("doc('");
|
||||
query.append(xqueryUtils.getCollectionAbsPath(prof));
|
||||
query.append('/');
|
||||
query.append(prof.getResourceId().split("_")[0]);
|
||||
query.append("')");
|
||||
} else {
|
||||
query.append("let $x := doc('");
|
||||
query.append(xqueryUtils.getCollectionAbsPath(prof));
|
||||
query.append('/');
|
||||
query.append(prof.getResourceId().split("_")[0]);
|
||||
query.append("') return <COLLECTION name='{$x//NAME}' id='{$x//RESOURCE_IDENTIFIER/@value/string()}'>");
|
||||
query.append("<STATUS private='{$x//PRIVATE}' visible='{$x//VISIBLE}' container='{$x//CONTAINER}'");
|
||||
query.append("count_docs='{$x//COUNT_DOCS/@number/string()}' last_update='{$x//COUNT_DOCS/@last_update/string()}' />");
|
||||
query.append("{$x//IMAGE_URL}{$x//DESCRIPTION}{$x//OWNER}{$x//FATHER}{$x//SUBJECT}{$x//CHILDREN}{$x//MEMBERSHIP_CONDITION}{$x//RETRIEVAL_CONDITION}</COLLECTION>");
|
||||
}
|
||||
|
||||
return isStore.getXMLbyQuery(query.toString());
|
||||
} catch (final ISStoreException e) {
|
||||
throw new ISLookUpException(e);
|
||||
} catch (final XPathExpressionException e) {
|
||||
throw new ISLookUpException(COLLECTION_ERROR, e);
|
||||
} catch (final SAXException e) {
|
||||
throw new ISLookUpException(COLLECTION_ERROR, e);
|
||||
} catch (final IOException e) {
|
||||
throw new ISLookUpException(COLLECTION_ERROR, e);
|
||||
} catch (final ParserConfigurationException e) {
|
||||
throw new ISLookUpException(COLLECTION_ERROR, e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @see eu.dnetlib.enabling.is.lookup.rmi.ISLookUpService#getResourceProfile(java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public String getResourceProfile(final String profId) throws ISLookUpException {
|
||||
if (profId == null || profId.isEmpty()) { throw new ISLookUpException("Invalid null profile ID: " + profId); }
|
||||
|
||||
try {
|
||||
final String res = isStore.getXML(getFileNameForId(profId),
|
||||
xqueryUtils.getRootCollection() + getFileCollForId(profId));
|
||||
if (res == null) { throw new ISLookUpDocumentNotFoundException("document " + profId + " not found"); }
|
||||
return res;
|
||||
} catch (final ISStoreException e) {
|
||||
throw new ISLookUpException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* obtain the xmldb file name from the profile identifier.
|
||||
*
|
||||
* @param profId
|
||||
* profile id
|
||||
* @return xml db file name
|
||||
*/
|
||||
String getFileNameForId(final String profId) {
|
||||
return resIdManager.getFileName(profId);
|
||||
}
|
||||
|
||||
/**
|
||||
* obtain the xmldb collection name from the profile identifier.
|
||||
*
|
||||
* @param profId
|
||||
* profile id
|
||||
* @return plaintext xmldb collection name
|
||||
*/
|
||||
String getFileCollForId(final String profId) {
|
||||
return resIdManager.getCollectionName(profId);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @see eu.dnetlib.enabling.is.lookup.rmi.ISLookUpService#getResourceProfileByQuery(java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public String getResourceProfileByQuery(final String xquery) throws ISLookUpException {
|
||||
String resource;
|
||||
//TODO remove following hack as soon as https://issue.openaire.research-infrastructures.eu/issues/2774 is closed.
|
||||
if (StringUtils.isNotBlank(xquery) && xquery.trim().startsWith("//*[local-name() = 'complexType'")) {
|
||||
final Pattern p = Pattern.compile(".*value = '([a-zA-z]+)']");
|
||||
final Matcher m = p.matcher(xquery);
|
||||
if (m.matches()) {
|
||||
final String serviceName = m.group(1);
|
||||
log.debug(String.format("found service '%s', hacking response for xquery: %s", serviceName, xquery));
|
||||
return getResourceTypeSchema(serviceName);
|
||||
}
|
||||
}
|
||||
try {
|
||||
resource = isStore.getXMLbyQuery(xquery);
|
||||
if (resource == null || resource.isEmpty()) { throw new ISLookUpDocumentNotFoundException(PROFILE_NOT_FOUND); }
|
||||
return resource;
|
||||
} catch (final ISStoreException e) {
|
||||
throw new ISLookUpException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @see eu.dnetlib.enabling.is.lookup.rmi.ISLookUpService#getResourceQoSParams(java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public String getResourceQoSParams(final String profId) throws ISLookUpException {
|
||||
final String query = "for $x in collection('/db/DRIVER/ServiceResources') where $x//RESOURCE_IDENTIFIER/@value = '" + profId + "' return $x//QOS";
|
||||
return getResourceProfileByQuery(query);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @see eu.dnetlib.enabling.is.lookup.rmi.ISLookUpService#getResourceTypeSchema(java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public String getResourceTypeSchema(final String resourceType) throws ISLookUpException, ISLookUpDocumentNotFoundException {
|
||||
if (resourceType == null || resourceType.isEmpty()) { throw new ISLookUpException("Invalid resourceType"); }
|
||||
|
||||
try {
|
||||
final String resource = isStore.getXML(resourceType, xqueryUtils.getRootCollection() + ResourceType.RESOURCE_TYPES);
|
||||
if (resource == null || resource.isEmpty()) { throw new ISLookUpDocumentNotFoundException(PROFILE_NOT_FOUND); }
|
||||
return resource;
|
||||
} catch (final ISStoreException e) {
|
||||
throw new ISLookUpException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @see eu.dnetlib.enabling.is.lookup.rmi.ISLookUpService#listCollections(java.lang.String, java.lang.String, java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public List<String> listCollections(final String format, final String idfatherParam, final String owner) throws ISLookUpException {
|
||||
String idfather = idfatherParam; // PMD
|
||||
if (idfather == null || idfather.length() == 0) {
|
||||
idfather = "InfoSpace";
|
||||
}
|
||||
final String fileColl = xqueryUtils.getRootCollection() + "CollectionDSResources/CollectionDSResourceType";
|
||||
|
||||
final StringBuilder query = new StringBuilder();
|
||||
query.append("for $x in collection('" + fileColl + "') where $x//FATHER[@id='" + idfather + "'] "); // NOPMD
|
||||
if (owner != null && owner.length() > 0) {
|
||||
query.append("and $x//OWNER[@id='" + owner + "'] ");
|
||||
}
|
||||
if (format != null && format.equals("short")) {
|
||||
query.append("return $x//RESOURCE_IDENTIFIER/@value/string()");
|
||||
} else {
|
||||
query.append("return $x");
|
||||
}
|
||||
|
||||
return quickSearchProfile(query.toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @see eu.dnetlib.enabling.is.lookup.rmi.ISLookUpService#listDHNIDs()
|
||||
*/
|
||||
@Override
|
||||
public List<String> listDHNIDs() throws ISLookUpException {
|
||||
final String fileColl = DB_BASE_DIR + "/InfrastructureResources/DRIVERHostingNodeDSResourceType";
|
||||
|
||||
final ArrayList<String> ret = new ArrayList<String>();
|
||||
try {
|
||||
for (final String i : isStore.getFileNames(fileColl)) {
|
||||
ret.add(i + ":" + fileColl);
|
||||
}
|
||||
return ret;
|
||||
} catch (final ISStoreException e) {
|
||||
throw new ISLookUpException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @see eu.dnetlib.enabling.is.lookup.rmi.ISLookUpService#listResourceTypes()
|
||||
*/
|
||||
@Override
|
||||
public List<String> listResourceTypes() throws ISLookUpException {
|
||||
try {
|
||||
return isStore.getFileNames(DB_BASE_DIR + "/" + ResourceType.RESOURCE_TYPES);
|
||||
} catch (final ISStoreException e) {
|
||||
throw new ISLookUpException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @see eu.dnetlib.enabling.is.lookup.rmi.ISLookUpService#listServiceIDs(java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public List<String> listServiceIDs(final String serviceType) throws ISLookUpException {
|
||||
final String fileColl = "ServiceResources/" + serviceType;
|
||||
final String encodedColl = "_" + new String(Base64.encode(fileColl.getBytes())); // NOPMD
|
||||
|
||||
final List<String> ret = new ArrayList<String>();
|
||||
try {
|
||||
for (final String i : isStore.getFileNames(DB_BASE_DIR + "/" + fileColl)) {
|
||||
ret.add(i + encodedColl);
|
||||
}
|
||||
return ret;
|
||||
} catch (final ISStoreException e) {
|
||||
throw new ISLookUpException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @see eu.dnetlib.enabling.is.lookup.rmi.ISLookUpService#listServiceTypes()
|
||||
*/
|
||||
@Override
|
||||
public List<String> listServiceTypes() throws ISLookUpException {
|
||||
final List<String> ret = new ArrayList<String>();
|
||||
try {
|
||||
for (final String i : isStore.getFileColls()) {
|
||||
if (i.startsWith("ServiceResources/")) {
|
||||
ret.add(i.substring("ServiceResources/".length()));
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
} catch (final ISStoreException e) {
|
||||
throw new ISLookUpException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @see eu.dnetlib.enabling.is.lookup.rmi.ISLookUpService#quickSearchProfile(java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public List<String> quickSearchProfile(final String xquery) throws ISLookUpException {
|
||||
try {
|
||||
return isStore.quickSearchXML(xquery);
|
||||
} catch (final ISStoreException e) {
|
||||
throw new ISLookUpException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public ResourceIdentifierResolver getResIdManager() {
|
||||
return resIdManager;
|
||||
}
|
||||
|
||||
public void setResIdManager(final ResourceIdentifierResolver resIdManager) {
|
||||
this.resIdManager = resIdManager;
|
||||
}
|
||||
|
||||
@Required
|
||||
public void setXqueryUtils(final XQueryUtils xqueryUtils) {
|
||||
this.xqueryUtils = xqueryUtils;
|
||||
}
|
||||
|
||||
public XQueryUtils getXqueryUtils() {
|
||||
return xqueryUtils;
|
||||
}
|
||||
|
||||
public ISStoreService getIsStore() {
|
||||
return isStore;
|
||||
}
|
||||
|
||||
@Required
|
||||
public void setIsStore(final ISStoreService isStore) {
|
||||
this.isStore = isStore;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,77 @@
|
|||
package eu.dnetlib.enabling.is.registry;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.xml.parsers.DocumentBuilderFactory;
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
import javax.xml.xpath.XPath;
|
||||
import javax.xml.xpath.XPathExpressionException;
|
||||
import javax.xml.xpath.XPathFactory;
|
||||
|
||||
import org.w3c.dom.Document;
|
||||
import org.xml.sax.SAXException;
|
||||
|
||||
/**
|
||||
* Resolves resource kinds (pending and normal from the application profile xml file).
|
||||
*
|
||||
* @author marko
|
||||
*
|
||||
*/
|
||||
public class ApplicationProfileResourceKindResolver implements ResourceKindResolver {
|
||||
|
||||
/**
|
||||
* information space application profile. Contains, among others, mappings for the.. TODO: move to a DAO.
|
||||
*
|
||||
*/
|
||||
private Document appProfile;
|
||||
|
||||
public ApplicationProfileResourceKindResolver() {
|
||||
try {
|
||||
appProfile = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(
|
||||
getClass().getResourceAsStream("DRIVERInformationSpaceApplicationProfile.xml"));
|
||||
} catch (SAXException e) {
|
||||
throw new IllegalStateException("cannot parse information space application profile", e);
|
||||
} catch (IOException e) {
|
||||
throw new IllegalStateException("cannot parse information space application profile", e);
|
||||
} catch (ParserConfigurationException e) {
|
||||
throw new IllegalStateException("cannot parse information space application profile", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* get the default resource kind associated with a given resource type.
|
||||
*
|
||||
* @param resourceType
|
||||
* resource type
|
||||
* @return resourceType
|
||||
* @throws XPathExpressionException
|
||||
* happens?
|
||||
*/
|
||||
@Override
|
||||
public String getNormalKindForType(final String resourceType) throws XPathExpressionException {
|
||||
final XPath xpath = XPathFactory.newInstance().newXPath();
|
||||
final String res = xpath.evaluate("//RESOURCE_TYPE[text() = '" + resourceType + "']/../../RESOURCE_KIND", appProfile);
|
||||
if (res.isEmpty())
|
||||
return null;
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* find the associated pending typology for a given resource type.
|
||||
*
|
||||
* @param resourceType
|
||||
* resource type
|
||||
* @return pending resource kind
|
||||
* @throws XPathExpressionException
|
||||
* shouldn't happen
|
||||
*/
|
||||
@Override
|
||||
public String getPendingKindForType(final String resourceType) throws XPathExpressionException {
|
||||
final XPath xpath = XPathFactory.newInstance().newXPath();
|
||||
final String res = xpath.evaluate("//RESOURCE_TYPE[text() = '" + resourceType + "']/../../PENDING_TYPOLOGY", appProfile);
|
||||
if (res.isEmpty())
|
||||
throw new NoSuchPendingCategoryException("no pending category for " + resourceType);
|
||||
return res;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,141 @@
|
|||
package eu.dnetlib.enabling.is.registry;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.xml.xpath.XPathExpressionException;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Required;
|
||||
|
||||
import eu.dnetlib.enabling.is.registry.rmi.ISRegistryException;
|
||||
import eu.dnetlib.enabling.is.registry.rmi.ISRegistryService;
|
||||
import eu.dnetlib.enabling.is.registry.schema.ValidationException;
|
||||
import eu.dnetlib.enabling.is.registry.validation.ProfileValidationStrategy;
|
||||
import eu.dnetlib.enabling.is.registry.validation.RegistrationPhase;
|
||||
import eu.dnetlib.enabling.tools.OpaqueResource;
|
||||
|
||||
/**
|
||||
* implement the compatibility pending profile policy.
|
||||
*
|
||||
* <p>
|
||||
* pending profiles receive their own special resource kind and are 'moved' to a different collection
|
||||
* </p>
|
||||
*
|
||||
* @author marko
|
||||
*
|
||||
*/
|
||||
public class CompatPendingResourceManagerImpl implements PendingResourceManager, ResourceKindResolver {
|
||||
|
||||
/**
|
||||
* IS Registry
|
||||
*/
|
||||
private ISRegistryService isRegistry;
|
||||
|
||||
/**
|
||||
* This bean resolver
|
||||
*/
|
||||
private ResourceKindResolver resourceKindResolver;
|
||||
|
||||
/**
|
||||
* used to validate resources w.r.t. a set of defined properties.
|
||||
*/
|
||||
@Resource
|
||||
private ProfileValidationStrategy profileValidationStrategy;
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @see eu.dnetlib.enabling.is.registry.PendingResourceManager#setPending(eu.dnetlib.enabling.tools.OpaqueResource)
|
||||
*/
|
||||
@Override
|
||||
public void setPending(final OpaqueResource resource, final boolean local) {
|
||||
try {
|
||||
resource.setResourceKind(getPendingKindForType(resource.getResourceType()));
|
||||
|
||||
if (!local) {
|
||||
isRegistry.deleteProfile(resource.getResourceId());
|
||||
final String newId = isRegistry.registerProfile(resource.asString());
|
||||
resource.setResourceId(newId);
|
||||
}
|
||||
|
||||
} catch (XPathExpressionException e) {
|
||||
throw new IllegalStateException(e);
|
||||
} catch (ISRegistryException e) {
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @see eu.dnetlib.enabling.is.registry.PendingResourceManager#setPending(eu.dnetlib.enabling.tools.OpaqueResource)
|
||||
*/
|
||||
@Override
|
||||
public void setPending(final OpaqueResource resource) {
|
||||
setPending(resource, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @see eu.dnetlib.enabling.is.registry.PendingResourceManager#setValid(eu.dnetlib.enabling.tools.OpaqueResource)
|
||||
*/
|
||||
@Override
|
||||
public void setValid(final OpaqueResource resource) {
|
||||
try {
|
||||
if (resource.getResourceKind() != null && resource.getResourceKind().equals(getNormalKindForType(resource.getResourceType()))) { throw new IllegalArgumentException(
|
||||
"trying to validate an already valid resource"); }
|
||||
|
||||
profileValidationStrategy.accept(resource, RegistrationPhase.Validate);
|
||||
|
||||
resource.setResourceKind(getNormalKindForType(resource.getResourceType()));
|
||||
|
||||
isRegistry.deleteProfile(resource.getResourceId());
|
||||
|
||||
final String newId = isRegistry.registerProfile(resource.asString());
|
||||
resource.setResourceId(newId);
|
||||
|
||||
} catch (XPathExpressionException e) {
|
||||
throw new IllegalStateException(e);
|
||||
} catch (ISRegistryException e) {
|
||||
throw new IllegalStateException(e);
|
||||
} catch (ValidationException e) {
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getNormalKindForType(final String resourceType) throws XPathExpressionException {
|
||||
return resourceKindResolver.getNormalKindForType(resourceType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPendingKindForType(final String resourceType) throws XPathExpressionException {
|
||||
return resourceKindResolver.getPendingKindForType(resourceType);
|
||||
}
|
||||
|
||||
public ResourceKindResolver getResourceKindResolver() {
|
||||
return resourceKindResolver;
|
||||
}
|
||||
|
||||
@Required
|
||||
public void setResourceKindResolver(final ResourceKindResolver resourceKindResolver) {
|
||||
this.resourceKindResolver = resourceKindResolver;
|
||||
}
|
||||
|
||||
public ProfileValidationStrategy getProfileValidationStrategy() {
|
||||
return profileValidationStrategy;
|
||||
}
|
||||
|
||||
public void setProfileValidationStrategy(final ProfileValidationStrategy profileValidationStrategy) {
|
||||
this.profileValidationStrategy = profileValidationStrategy;
|
||||
}
|
||||
|
||||
public ISRegistryService getIsRegistry() {
|
||||
return isRegistry;
|
||||
}
|
||||
|
||||
@Required
|
||||
public void setIsRegistry(final ISRegistryService isRegistry) {
|
||||
this.isRegistry = isRegistry;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,595 @@
|
|||
package eu.dnetlib.enabling.is.registry; // NOPMD
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.jws.WebService;
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
import javax.xml.xpath.XPath;
|
||||
import javax.xml.xpath.XPathConstants;
|
||||
import javax.xml.xpath.XPathExpressionException;
|
||||
import javax.xml.xpath.XPathFactory;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.beans.factory.annotation.Required;
|
||||
import org.w3c.dom.Element;
|
||||
import org.xml.sax.SAXException;
|
||||
|
||||
import com.sun.xml.messaging.saaj.util.Base64;
|
||||
|
||||
import eu.dnetlib.common.rmi.APIDeprecatedException;
|
||||
import eu.dnetlib.common.rmi.UnimplementedException;
|
||||
import eu.dnetlib.enabling.is.lookup.rmi.ISLookUpDocumentNotFoundException;
|
||||
import eu.dnetlib.enabling.is.lookup.rmi.ISLookUpException;
|
||||
import eu.dnetlib.enabling.is.lookup.rmi.ISLookUpService;
|
||||
import eu.dnetlib.enabling.is.registry.rmi.ISRegistryException;
|
||||
import eu.dnetlib.enabling.is.registry.rmi.ISRegistryService;
|
||||
import eu.dnetlib.enabling.is.registry.schema.OpaqueResourceValidator;
|
||||
import eu.dnetlib.enabling.is.registry.schema.ValidationException;
|
||||
import eu.dnetlib.enabling.is.registry.validation.ProfileValidationStrategy;
|
||||
import eu.dnetlib.enabling.is.registry.validation.RegistrationPhase;
|
||||
import eu.dnetlib.enabling.is.store.rmi.ISStoreException;
|
||||
import eu.dnetlib.enabling.is.store.rmi.ISStoreService;
|
||||
import eu.dnetlib.enabling.tools.AbstractBaseService;
|
||||
import eu.dnetlib.enabling.tools.CompatResourceIdentifierResolverImpl;
|
||||
import eu.dnetlib.enabling.tools.OpaqueResource;
|
||||
import eu.dnetlib.enabling.tools.ResourceIdentifierResolver;
|
||||
import eu.dnetlib.enabling.tools.ResourceType;
|
||||
import eu.dnetlib.enabling.tools.StringOpaqueResource;
|
||||
import eu.dnetlib.enabling.tools.UniqueIdentifierGenerator;
|
||||
import eu.dnetlib.enabling.tools.UniqueIdentifierGeneratorImpl;
|
||||
import eu.dnetlib.enabling.tools.XQueryUtils;
|
||||
|
||||
/**
|
||||
* Registry service implementation.
|
||||
*
|
||||
* @author marko
|
||||
*
|
||||
*/
|
||||
@WebService(targetNamespace = "http://services.dnetlib.eu/")
|
||||
public class ISRegistryServiceImpl extends AbstractBaseService implements ISRegistryService { // NOPMD by marko on
|
||||
|
||||
/**
|
||||
* logger.
|
||||
*/
|
||||
private static final Log log = LogFactory.getLog(ISRegistryServiceImpl.class); // NOPMD by marko on 11/24/08 5:02 PM
|
||||
|
||||
/**
|
||||
* error message: secure profile registration.
|
||||
*/
|
||||
private static final String ERROR_SEC_PROFILE = "cannot register secure profile";
|
||||
|
||||
/**
|
||||
* error message: trying to retrieve the current stored version of the resource profile.
|
||||
*/
|
||||
private static final String CANT_FETCH = "cannot fetch original profile";
|
||||
|
||||
/**
|
||||
* error message: cannot create a resource.
|
||||
*/
|
||||
private static final String CANT_CREATE = "cannot create resource";
|
||||
|
||||
/**
|
||||
* IS Store
|
||||
*/
|
||||
private ISStoreService isStore;
|
||||
|
||||
/**
|
||||
* IS Lookup
|
||||
*/
|
||||
private ISLookUpService isLookup;
|
||||
|
||||
/**
|
||||
* uuid generator.
|
||||
*/
|
||||
@Resource
|
||||
private UniqueIdentifierGenerator uuidGenerator = new UniqueIdentifierGeneratorImpl();
|
||||
|
||||
/**
|
||||
* manages the pending state of resource. Different implementations can be plugged in.
|
||||
*/
|
||||
private PendingResourceManager pendingManager = new CompatPendingResourceManagerImpl();
|
||||
|
||||
/**
|
||||
* manages resource identifier mappings with the abstract xmldb namespace (files/collections).
|
||||
*/
|
||||
@Resource
|
||||
private ResourceIdentifierResolver resIdResolver = new CompatResourceIdentifierResolverImpl();
|
||||
|
||||
/**
|
||||
* used to validate resources.
|
||||
*/
|
||||
private OpaqueResourceValidator resourceValidator;
|
||||
|
||||
/**
|
||||
* used to validate resources w.r.t. a set of defined properties.
|
||||
*/
|
||||
@Resource
|
||||
private ProfileValidationStrategy profileValidationStrategy;
|
||||
|
||||
/**
|
||||
* query utils. Used to obtain xmldb collection names and other things useful for interacting with the IS_Store.
|
||||
*/
|
||||
private XQueryUtils xqueryUtils;
|
||||
|
||||
/**
|
||||
* the blackboard management stuff is factored out here.
|
||||
*/
|
||||
@Resource
|
||||
private RegistryBlackboardManager blackboardManager;
|
||||
|
||||
@Override
|
||||
public void start() {
|
||||
super.start();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @see eu.dnetlib.enabling.is.registry.rmi.ISRegistryService#addBlackBoardMessage(java.lang.String, java.lang.String, java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public void addBlackBoardMessage(final String profId, final String messageId, final String message) throws ISRegistryException {
|
||||
blackboardManager.addMessage(profId, messageId, message);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @see eu.dnetlib.enabling.is.registry.rmi.ISRegistryService#addOrUpdateResourceType(java.lang.String, java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public boolean addOrUpdateResourceType(final String resourceType, final String resourceSchema) throws ISRegistryException {
|
||||
return addResourceType(resourceType, resourceSchema);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @see eu.dnetlib.enabling.is.registry.rmi.ISRegistryService#addProfileNode(java.lang.String, java.lang.String, java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public boolean addProfileNode(final String profId, final String xpath, final String node) throws ISRegistryException {
|
||||
// TODO Auto-generated method stub
|
||||
throw new UnimplementedException();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @see eu.dnetlib.enabling.is.registry.rmi.ISRegistryService#addResourceType(java.lang.String, java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public boolean addResourceType(final String resourceType, final String resourceSchema) throws ISRegistryException {
|
||||
try {
|
||||
return isStore.insertXML(resourceType, xqueryUtils.getRootCollection() + ResourceType.RESOURCE_TYPES,
|
||||
resourceSchema);
|
||||
} catch (ISStoreException e) {
|
||||
throw new ISRegistryException("cannot add resource type", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @see eu.dnetlib.enabling.is.registry.rmi.ISRegistryService#deleteBlackBoardMessage(java.lang.String, java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public void deleteBlackBoardMessage(final String profId, final String messageId) throws ISRegistryException {
|
||||
blackboardManager.deleteMessage(profId, messageId);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @see eu.dnetlib.enabling.is.registry.rmi.ISRegistryService#deleteProfile(java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public boolean deleteProfile(final String resId) throws ISRegistryException {
|
||||
try {
|
||||
final boolean res = isStore.deleteXML(resIdResolver.getFileName(resId),
|
||||
"/db/DRIVER/" + resIdResolver.getCollectionName(resId));
|
||||
if (!res) { throw new ISRegistryDocumentNotFoundException("document " + resId + " not found"); }
|
||||
|
||||
return true;
|
||||
} catch (ISStoreException e) {
|
||||
throw new ISRegistryException("cannot delete profile " + resId, e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @see eu.dnetlib.enabling.is.registry.rmi.ISRegistryService#deleteProfiles(java.util.List)
|
||||
*/
|
||||
@Override
|
||||
public boolean deleteProfiles(final List<String> arrayprofId) throws ISRegistryException {
|
||||
throw new APIDeprecatedException();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @see eu.dnetlib.enabling.is.registry.rmi.ISRegistryService#deleteResourceType(java.lang.String, java.lang.Boolean)
|
||||
*/
|
||||
@Override
|
||||
public boolean deleteResourceType(final String resourceType, final Boolean hierarchical) throws ISRegistryException {
|
||||
try {
|
||||
return isStore.deleteXML(resourceType, xqueryUtils.getRootCollection() + ResourceType.RESOURCE_TYPES);
|
||||
} catch (ISStoreException e) {
|
||||
throw new ISRegistryException("error deleting resource type " + resourceType, e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @see eu.dnetlib.enabling.is.registry.rmi.ISRegistryService#executeXUpdate(java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public boolean executeXUpdate(final String xquery) throws ISRegistryException {
|
||||
try {
|
||||
return isStore.executeXUpdate(xquery);
|
||||
} catch (ISStoreException e) {
|
||||
throw new ISRegistryException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @see eu.dnetlib.enabling.is.registry.rmi.ISRegistryService#insertProfileForValidation(java.lang.String, java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public String insertProfileForValidation(final String resourceType, final String resourceProfile) throws ISRegistryException {
|
||||
try {
|
||||
final OpaqueResource resource = new StringOpaqueResource(resourceProfile);
|
||||
if (!resourceType.equals(resource.getResourceType())) { throw new ISRegistryException("expected resource type doesn't match to resource"); }
|
||||
|
||||
pendingManager.setPending(resource, true);
|
||||
|
||||
return registerProfile(resource.asString());
|
||||
} catch (XPathExpressionException e) {
|
||||
throw new ISRegistryException(e);
|
||||
} catch (SAXException e) {
|
||||
throw new ISRegistryException(e);
|
||||
} catch (IOException e) {
|
||||
throw new ISRegistryException(e);
|
||||
} catch (ParserConfigurationException e) {
|
||||
throw new ISRegistryException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @see eu.dnetlib.enabling.is.registry.rmi.ISRegistryService#refreshProfile(java.lang.String, java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public boolean refreshProfile(final String profId, final String resourceType) throws ISRegistryException {
|
||||
// TODO Auto-generated method stub
|
||||
throw new UnimplementedException();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @see eu.dnetlib.enabling.is.registry.rmi.ISRegistryService#registerProfile(java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public String registerProfile(final String resourceProfile) throws ISRegistryException {
|
||||
log.debug("registering profile");
|
||||
|
||||
try {
|
||||
final OpaqueResource resource = new StringOpaqueResource(resourceProfile);
|
||||
|
||||
// TODO: factor this out (possibly not within the OpaqueResource class)
|
||||
final String coll = xqueryUtils.getCollectionPath(resource);
|
||||
final String fileName = uuidGenerator.generateIdentifier();
|
||||
final String newId = fileName + "_" + new String(Base64.encode(coll.getBytes()));
|
||||
resource.setResourceId(newId);
|
||||
|
||||
resource.setModificationDate(new Date());
|
||||
|
||||
// log.info("validating to xml schema: " + resource.asString());
|
||||
resourceValidator.validate(resource);
|
||||
|
||||
profileValidationStrategy.accept(resource, RegistrationPhase.Register);
|
||||
|
||||
// TODO: factor out ResourceType class
|
||||
isStore.insertXML(fileName, xqueryUtils.getRootCollection() + coll, resource.asString());
|
||||
|
||||
return resource.getResourceId();
|
||||
} catch (XPathExpressionException e) {
|
||||
throw new ISRegistryException(e);
|
||||
} catch (SAXException e) {
|
||||
throw new ISRegistryException(e);
|
||||
} catch (IOException e) {
|
||||
throw new ISRegistryException(e);
|
||||
} catch (ParserConfigurationException e) {
|
||||
throw new ISRegistryException(e);
|
||||
} catch (ISStoreException e) {
|
||||
throw new ISRegistryException(e);
|
||||
} catch (ValidationException e) {
|
||||
throw new ISRegistryException("profile is not conforming to the schema: " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @see eu.dnetlib.enabling.is.registry.rmi.ISRegistryService#registerSecureProfile(java.lang.String, java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public String registerSecureProfile(final String resourceProfId, final String secureProfId) throws ISRegistryException {
|
||||
try {
|
||||
synchronized (this) {
|
||||
final String secureProfSrc;
|
||||
try {
|
||||
secureProfSrc = isLookup.getResourceProfile(secureProfId); // NOPMD
|
||||
} catch (ISLookUpDocumentNotFoundException e) {
|
||||
throw new ISRegistryException("cannot register secure profile, the given secure profile doesn't exist", e);
|
||||
}
|
||||
final OpaqueResource secureProf = new StringOpaqueResource(secureProfSrc);
|
||||
|
||||
final String profId = validateProfile(resourceProfId);
|
||||
|
||||
final XPath xpath = XPathFactory.newInstance().newXPath();
|
||||
final Element idEl = (Element) xpath.evaluate("/RESOURCE_PROFILE/BODY/CONFIGURATION/resourceId", secureProf.asDom(), XPathConstants.NODE);
|
||||
idEl.setTextContent(profId);
|
||||
|
||||
if (!updateProfile(secureProfId, secureProf.asString(), secureProf.getResourceType())) { throw new ISRegistryException(
|
||||
"cannot update security profile (updateProfile returned false)"); }
|
||||
|
||||
return profId;
|
||||
}
|
||||
} catch (XPathExpressionException e) {
|
||||
throw new ISRegistryException(ERROR_SEC_PROFILE, e);
|
||||
} catch (SAXException e) {
|
||||
throw new ISRegistryException(ERROR_SEC_PROFILE, e);
|
||||
} catch (IOException e) {
|
||||
throw new ISRegistryException(ERROR_SEC_PROFILE, e);
|
||||
} catch (ParserConfigurationException e) {
|
||||
throw new ISRegistryException(ERROR_SEC_PROFILE, e);
|
||||
} catch (ISLookUpException e) {
|
||||
throw new ISRegistryException("cannot register secure profile, problem fetching the given secure profile", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @see eu.dnetlib.enabling.is.registry.rmi.ISRegistryService#removeProfileNode(java.lang.String, java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public boolean removeProfileNode(final String profId, final String nodeId) throws ISRegistryException {
|
||||
// TODO Auto-generated method stub
|
||||
throw new UnimplementedException();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @see eu.dnetlib.enabling.is.registry.rmi.ISRegistryService#replyBlackBoardMessage(java.lang.String, java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public void replyBlackBoardMessage(final String profId, final String message) throws ISRegistryException {
|
||||
blackboardManager.replyMessage(profId, message);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @see eu.dnetlib.enabling.is.registry.rmi.ISRegistryService#updateProfile(java.lang.String, java.lang.String, java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public boolean updateProfile(final String resId, final String resourceProfile, final String resourceType) throws ISRegistryException {
|
||||
try {
|
||||
final String fileName = resIdResolver.getFileName(resId);
|
||||
final String fileColl = "/db/DRIVER/" + resIdResolver.getCollectionName(resId);
|
||||
|
||||
final String oldProfileSrc = isStore.getXML(fileName, fileColl);
|
||||
|
||||
if (oldProfileSrc == null) { throw new ISRegistryException("cannot update a non existing profile " + resId); }
|
||||
|
||||
final OpaqueResource oldResource = new StringOpaqueResource(oldProfileSrc);
|
||||
|
||||
final StringOpaqueResource newResource = new StringOpaqueResource(resourceProfile);
|
||||
newResource.setResourceId(oldResource.getResourceId());
|
||||
newResource.setResourceKind(oldResource.getResourceKind());
|
||||
newResource.setResourceType(oldResource.getResourceType());
|
||||
newResource.setModificationDate(new Date());
|
||||
|
||||
getResourceValidator().validate(newResource);
|
||||
|
||||
return isStore.updateXML(fileName, fileColl, newResource.asString());
|
||||
} catch (ISStoreException e) {
|
||||
throw new ISRegistryException(e);
|
||||
} catch (XPathExpressionException e) {
|
||||
throw new ISRegistryException(e);
|
||||
} catch (ValidationException e) {
|
||||
throw new ISRegistryException("profile not conforming to xml schema", e);
|
||||
} catch (SAXException e) {
|
||||
throw new ISRegistryException(e);
|
||||
} catch (IOException e) {
|
||||
throw new ISRegistryException(e);
|
||||
} catch (ParserConfigurationException e) {
|
||||
throw new ISRegistryException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @see eu.dnetlib.enabling.is.registry.rmi.ISRegistryService#updateProfileDHN(java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public String updateProfileDHN(final String resourceProfile) throws ISRegistryException {
|
||||
// TODO Auto-generated method stub
|
||||
throw new UnimplementedException();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @see eu.dnetlib.enabling.is.registry.rmi.ISRegistryService#updateProfileNode(java.lang.String, java.lang.String, java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public boolean updateProfileNode(final String profId, final String xpath, final String node) throws ISRegistryException {
|
||||
return executeXUpdate("for $x in collection('/db/DRIVER')//RESOURCE_PROFILE[.//RESOURCE_IDENTIFIER/@value eq '" + profId + "']" + xpath
|
||||
+ " return update replace $x with " + node);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @see eu.dnetlib.enabling.is.registry.rmi.ISRegistryService#updateRegionDescription(java.lang.String, java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public boolean updateRegionDescription(final String profId, final String resourceProfile) throws ISRegistryException {
|
||||
// TODO Auto-generated method stub
|
||||
throw new UnimplementedException();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @see eu.dnetlib.enabling.is.registry.rmi.ISRegistryService#validateProfile(java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public String validateProfile(final String profId) throws ISRegistryException {
|
||||
try {
|
||||
final String resourceProfile = isLookup.getResourceProfile(profId);
|
||||
final OpaqueResource resource = new StringOpaqueResource(resourceProfile);
|
||||
pendingManager.setValid(resource);
|
||||
|
||||
return resource.getResourceId();
|
||||
} catch (ISLookUpException e) {
|
||||
throw new ISRegistryException(CANT_FETCH, e);
|
||||
} catch (XPathExpressionException e) {
|
||||
throw new ISRegistryException(CANT_CREATE, e);
|
||||
} catch (SAXException e) {
|
||||
throw new ISRegistryException(CANT_CREATE, e);
|
||||
} catch (IOException e) {
|
||||
throw new ISRegistryException(CANT_CREATE, e);
|
||||
} catch (ParserConfigurationException e) {
|
||||
throw new ISRegistryException(CANT_CREATE, e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @see eu.dnetlib.enabling.is.registry.rmi.ISRegistryService#invalidateProfile(java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public String invalidateProfile(final String profId) throws ISRegistryException {
|
||||
try {
|
||||
final String resourceProfile = isLookup.getResourceProfile(profId);
|
||||
final OpaqueResource resource = new StringOpaqueResource(resourceProfile);
|
||||
pendingManager.setPending(resource);
|
||||
|
||||
return resource.getResourceId();
|
||||
} catch (ISLookUpException e) {
|
||||
throw new ISRegistryException(CANT_FETCH, e);
|
||||
} catch (XPathExpressionException e) {
|
||||
throw new ISRegistryException(CANT_CREATE, e);
|
||||
} catch (SAXException e) {
|
||||
throw new ISRegistryException(CANT_CREATE, e);
|
||||
} catch (IOException e) {
|
||||
throw new ISRegistryException(CANT_CREATE, e);
|
||||
} catch (ParserConfigurationException e) {
|
||||
throw new ISRegistryException(CANT_CREATE, e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @see eu.dnetlib.enabling.is.registry.rmi.ISRegistryService#validateProfiles(java.util.List)
|
||||
*/
|
||||
@Override
|
||||
public List<String> validateProfiles(final List<String> profIds) throws ISRegistryException {
|
||||
throw new APIDeprecatedException();
|
||||
}
|
||||
|
||||
public UniqueIdentifierGenerator getUuidGenerator() {
|
||||
return uuidGenerator;
|
||||
}
|
||||
|
||||
public void setUuidGenerator(final UniqueIdentifierGenerator uuidGenerator) {
|
||||
this.uuidGenerator = uuidGenerator;
|
||||
}
|
||||
|
||||
public PendingResourceManager getPendingManager() {
|
||||
return pendingManager;
|
||||
}
|
||||
|
||||
public void setPendingManager(final PendingResourceManager pendingManager) {
|
||||
this.pendingManager = pendingManager;
|
||||
}
|
||||
|
||||
public ResourceIdentifierResolver getResIdResolver() {
|
||||
return resIdResolver;
|
||||
}
|
||||
|
||||
public void setResIdResolver(final ResourceIdentifierResolver resIdResolver) {
|
||||
this.resIdResolver = resIdResolver;
|
||||
}
|
||||
|
||||
public OpaqueResourceValidator getResourceValidator() {
|
||||
return resourceValidator;
|
||||
}
|
||||
|
||||
@Required
|
||||
public void setResourceValidator(final OpaqueResourceValidator resourceValidator) {
|
||||
this.resourceValidator = resourceValidator;
|
||||
}
|
||||
|
||||
@Required
|
||||
public void setXqueryUtils(final XQueryUtils xqueryUtils) {
|
||||
this.xqueryUtils = xqueryUtils;
|
||||
}
|
||||
|
||||
public XQueryUtils getXqueryUtils() {
|
||||
return xqueryUtils;
|
||||
}
|
||||
|
||||
public RegistryBlackboardManager getBlackboardManager() {
|
||||
return blackboardManager;
|
||||
}
|
||||
|
||||
public void setBlackboardManager(final RegistryBlackboardManager blackboardManager) {
|
||||
this.blackboardManager = blackboardManager;
|
||||
}
|
||||
|
||||
public ProfileValidationStrategy getProfileValidationStrategy() {
|
||||
return profileValidationStrategy;
|
||||
}
|
||||
|
||||
public void setProfileValidationStrategy(final ProfileValidationStrategy profileValidationStrategy) {
|
||||
this.profileValidationStrategy = profileValidationStrategy;
|
||||
}
|
||||
|
||||
public ISStoreService getIsStore() {
|
||||
return isStore;
|
||||
}
|
||||
|
||||
@Required
|
||||
public void setIsStore(final ISStoreService isStore) {
|
||||
this.isStore = isStore;
|
||||
}
|
||||
|
||||
public ISLookUpService getIsLookup() {
|
||||
return isLookup;
|
||||
}
|
||||
|
||||
@Required
|
||||
public void setIsLookup(final ISLookUpService isLookup) {
|
||||
this.isLookup = isLookup;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,209 @@
|
|||
package eu.dnetlib.enabling.is.registry;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.xml.xpath.XPathExpressionException;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Required;
|
||||
|
||||
import eu.dnetlib.enabling.is.registry.rmi.ISRegistryException;
|
||||
import eu.dnetlib.enabling.is.registry.rmi.ISRegistryService;
|
||||
import eu.dnetlib.enabling.is.registry.schema.OpaqueResourceValidator;
|
||||
import eu.dnetlib.enabling.is.registry.schema.ValidationException;
|
||||
import eu.dnetlib.enabling.is.registry.validation.ProfileValidationStrategy;
|
||||
import eu.dnetlib.enabling.is.registry.validation.RegistrationPhase;
|
||||
import eu.dnetlib.enabling.is.store.rmi.ISStoreException;
|
||||
import eu.dnetlib.enabling.is.store.rmi.ISStoreService;
|
||||
import eu.dnetlib.enabling.tools.CompatResourceIdentifierResolverImpl;
|
||||
import eu.dnetlib.enabling.tools.OpaqueResource;
|
||||
import eu.dnetlib.enabling.tools.ResourceIdentifierComposer;
|
||||
import eu.dnetlib.enabling.tools.ResourceIdentifierResolver;
|
||||
import eu.dnetlib.enabling.tools.XQueryUtils;
|
||||
|
||||
public class IdPreservingPendingResourceManagerImpl implements PendingResourceManager, ResourceKindResolver {
|
||||
|
||||
/**
|
||||
* is registry
|
||||
*/
|
||||
private ISRegistryService isRegistry;
|
||||
|
||||
/**
|
||||
* is store
|
||||
*/
|
||||
private ISStoreService isStore;
|
||||
|
||||
/**
|
||||
* This bean resolver
|
||||
*/
|
||||
private ResourceKindResolver resourceKindResolver;
|
||||
|
||||
/**
|
||||
* used to validate resources.
|
||||
*/
|
||||
private OpaqueResourceValidator resourceValidator;
|
||||
|
||||
/**
|
||||
* used to get the root collection.
|
||||
*/
|
||||
private XQueryUtils xqueryUtils;
|
||||
|
||||
/**
|
||||
* manages resource identifier mappings with the abstract xmldb namespace (files/collections).
|
||||
*/
|
||||
@Resource
|
||||
private ResourceIdentifierResolver resIdResolver = new CompatResourceIdentifierResolverImpl();
|
||||
|
||||
/**
|
||||
* used to create a new resource id.
|
||||
*/
|
||||
@Resource
|
||||
private ResourceIdentifierComposer resIdComposer = new CompatResourceIdentifierResolverImpl();
|
||||
|
||||
/**
|
||||
* used to validate resources w.r.t. a set of defined properties.
|
||||
*/
|
||||
@Resource
|
||||
private ProfileValidationStrategy profileValidationStrategy;
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @see eu.dnetlib.enabling.is.registry.PendingResourceManager#setPending(eu.dnetlib.enabling.tools.OpaqueResource)
|
||||
*/
|
||||
@Override
|
||||
public void setPending(final OpaqueResource resource, final boolean local) {
|
||||
try {
|
||||
resource.setResourceKind(getPendingKindForType(resource.getResourceType()));
|
||||
|
||||
if (!local) {
|
||||
isRegistry.deleteProfile(resource.getResourceId());
|
||||
|
||||
registerProfile(resource);
|
||||
}
|
||||
|
||||
} catch (XPathExpressionException e) {
|
||||
throw new IllegalStateException(e);
|
||||
} catch (ISRegistryException e) {
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @see eu.dnetlib.enabling.is.registry.PendingResourceManager#setPending(eu.dnetlib.enabling.tools.OpaqueResource)
|
||||
*/
|
||||
@Override
|
||||
public void setPending(final OpaqueResource resource) {
|
||||
setPending(resource, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @see eu.dnetlib.enabling.is.registry.PendingResourceManager#setValid(eu.dnetlib.enabling.tools.OpaqueResource)
|
||||
*/
|
||||
@Override
|
||||
public void setValid(final OpaqueResource resource) {
|
||||
try {
|
||||
if (resource.getResourceKind() != null && resource.getResourceKind().equals(getNormalKindForType(resource.getResourceType()))) { throw new IllegalArgumentException(
|
||||
"trying to validate an already valid resource"); }
|
||||
|
||||
profileValidationStrategy.accept(resource, RegistrationPhase.Validate);
|
||||
|
||||
resource.setResourceKind(getNormalKindForType(resource.getResourceType()));
|
||||
|
||||
isRegistry.deleteProfile(resource.getResourceId());
|
||||
|
||||
registerProfile(resource);
|
||||
|
||||
} catch (XPathExpressionException e) {
|
||||
throw new IllegalStateException(e);
|
||||
} catch (ISRegistryException e) {
|
||||
throw new IllegalStateException(e);
|
||||
} catch (ValidationException e) {
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public String registerProfile(final OpaqueResource resource) throws ISRegistryException {
|
||||
try {
|
||||
final String oldId = resource.getResourceId();
|
||||
final String fileName = resIdResolver.getFileName(oldId);
|
||||
final String newColl = xqueryUtils.getCollectionPath(resource);
|
||||
|
||||
final String newId = resIdComposer.createResourceId(fileName, newColl);
|
||||
|
||||
resource.setResourceId(newId);
|
||||
|
||||
resource.setModificationDate(new Date());
|
||||
|
||||
// log.info("validating to xml schema: " + resource.asString());
|
||||
resourceValidator.validate(resource);
|
||||
|
||||
// TODO: factor out ResourceType class
|
||||
isStore.insertXML(fileName, xqueryUtils.getRootCollection() + newColl, resource.asString());
|
||||
|
||||
return resource.getResourceId();
|
||||
} catch (ISStoreException e) {
|
||||
throw new ISRegistryException(e);
|
||||
} catch (ValidationException e) {
|
||||
throw new ISRegistryException("profile is not conforming to the schema: " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getNormalKindForType(final String resourceType) throws XPathExpressionException {
|
||||
return resourceKindResolver.getNormalKindForType(resourceType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPendingKindForType(final String resourceType) throws XPathExpressionException {
|
||||
return resourceKindResolver.getPendingKindForType(resourceType);
|
||||
}
|
||||
|
||||
// /////////////////////////////
|
||||
|
||||
public ResourceKindResolver getResourceKindResolver() {
|
||||
return resourceKindResolver;
|
||||
}
|
||||
|
||||
@Required
|
||||
public void setResourceKindResolver(final ResourceKindResolver resourceKindResolver) {
|
||||
this.resourceKindResolver = resourceKindResolver;
|
||||
}
|
||||
|
||||
@Required
|
||||
public void setXqueryUtils(final XQueryUtils xqueryUtils) {
|
||||
this.xqueryUtils = xqueryUtils;
|
||||
}
|
||||
|
||||
public OpaqueResourceValidator getResourceValidator() {
|
||||
return resourceValidator;
|
||||
}
|
||||
|
||||
@Required
|
||||
public void setResourceValidator(final OpaqueResourceValidator resourceValidator) {
|
||||
this.resourceValidator = resourceValidator;
|
||||
}
|
||||
|
||||
public ISRegistryService getIsRegistry() {
|
||||
return isRegistry;
|
||||
}
|
||||
|
||||
@Required
|
||||
public void setIsRegistry(final ISRegistryService isRegistry) {
|
||||
this.isRegistry = isRegistry;
|
||||
}
|
||||
|
||||
public ISStoreService getIsStore() {
|
||||
return isStore;
|
||||
}
|
||||
|
||||
@Required
|
||||
public void setIsStore(final ISStoreService isStore) {
|
||||
this.isStore = isStore;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
package eu.dnetlib.enabling.is.registry;
|
||||
|
||||
import javax.xml.xpath.XPathExpressionException;
|
||||
|
||||
/**
|
||||
* Uses current driver convention and tries to guess the correct resource kinds (both normal and pending) depending on
|
||||
* the resource type name.
|
||||
*
|
||||
* @author marko
|
||||
*
|
||||
*/
|
||||
public class NameBasedResourceKindResolver implements ResourceKindResolver {
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* @see eu.dnetlib.enabling.is.registry.ResourceKindResolver#getNormalKindForType(java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public String getNormalKindForType(final String resourceType) throws XPathExpressionException {
|
||||
if (isService(resourceType))
|
||||
return "ServiceResources";
|
||||
return generateKind(resourceType);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* @see eu.dnetlib.enabling.is.registry.ResourceKindResolver#getPendingKindForType(java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public String getPendingKindForType(final String resourceType) throws XPathExpressionException {
|
||||
if (isService(resourceType))
|
||||
return "PendingServiceResources";
|
||||
return "PendingDSResources";
|
||||
}
|
||||
|
||||
private boolean isService(final String resourceType) {
|
||||
return resourceType.matches(".*ServiceResourceType$");
|
||||
}
|
||||
|
||||
private String generateKind(final String resourceType) {
|
||||
return resourceType.replaceAll("ResourceType$", "Resources");
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
package eu.dnetlib.enabling.is.registry;
|
||||
|
||||
public class NoSuchPendingCategoryException extends IllegalStateException {
|
||||
|
||||
public NoSuchPendingCategoryException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static final long serialVersionUID = 6934748076388947172L;
|
||||
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
package eu.dnetlib.enabling.is.registry;
|
||||
|
||||
import eu.dnetlib.enabling.tools.OpaqueResource;
|
||||
|
||||
/**
|
||||
* The IS registry has to handle the 'pending' state of the resources in several ways.
|
||||
*
|
||||
* <p>Implementors of this interface will change the profiles according to the pending profile management policy.</p>
|
||||
*
|
||||
* <p>See implementors.</p>
|
||||
*
|
||||
* @author marko
|
||||
*
|
||||
*/
|
||||
public interface PendingResourceManager {
|
||||
|
||||
/**
|
||||
* change a profile to a pending state.
|
||||
*
|
||||
* @param resource opaque resource
|
||||
*/
|
||||
void setPending(OpaqueResource resource);
|
||||
|
||||
/**
|
||||
* change a profile to a valid state.
|
||||
*
|
||||
* same as setPending(resource, false);
|
||||
*
|
||||
* @param resource opaque resource
|
||||
*/
|
||||
void setValid(OpaqueResource resource);
|
||||
|
||||
/**
|
||||
* change a profile to a valid state.
|
||||
*
|
||||
* @param resource resource
|
||||
* @param local true if the resource is not persistent
|
||||
*/
|
||||
void setPending(OpaqueResource resource, boolean local);
|
||||
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
package eu.dnetlib.enabling.is.registry;
|
||||
|
||||
/**
|
||||
* Internally used by the Registry Service to perform modifications on the service blackboard, a funcionality provided
|
||||
* by the registry API.
|
||||
*
|
||||
* @author marko
|
||||
*
|
||||
*/
|
||||
public interface RegistryBlackboardManager {
|
||||
/**
|
||||
* add a new blackboard message.
|
||||
*
|
||||
* @param profId
|
||||
* service profile id
|
||||
* @param messageId
|
||||
* message identifier, chosen by the client
|
||||
* @param message
|
||||
* message body
|
||||
*/
|
||||
void addMessage(String profId, String messageId, String message);
|
||||
|
||||
/**
|
||||
* Reply to a given message replacing the current message with the parameter. The message ID is inferred from the
|
||||
* new message body.
|
||||
*
|
||||
* @param profId
|
||||
* service profile id
|
||||
* @param message
|
||||
* message body
|
||||
*/
|
||||
void replyMessage(String profId, String message);
|
||||
|
||||
/**
|
||||
* delete a message for a given message id.
|
||||
*
|
||||
* @param profId
|
||||
* service profile id
|
||||
* @param messageId
|
||||
* message id
|
||||
*/
|
||||
void deleteMessage(String profId, String messageId);
|
||||
}
|
|
@ -0,0 +1,257 @@
|
|||
package eu.dnetlib.enabling.is.registry;
|
||||
|
||||
import javax.xml.transform.dom.DOMResult;
|
||||
import javax.xml.xpath.XPathConstants;
|
||||
import javax.xml.xpath.XPathExpressionException;
|
||||
import javax.xml.xpath.XPathFactory;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.beans.factory.annotation.Required;
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.Element;
|
||||
import org.w3c.dom.Node;
|
||||
|
||||
import eu.dnetlib.enabling.is.lookup.rmi.ISLookUpService;
|
||||
import eu.dnetlib.enabling.is.registry.rmi.ISRegistryService;
|
||||
import eu.dnetlib.enabling.tools.OpaqueResource;
|
||||
import eu.dnetlib.enabling.tools.StringOpaqueResource;
|
||||
import eu.dnetlib.enabling.tools.blackboard.BlackboardMessage;
|
||||
import eu.dnetlib.miscutils.datetime.DateUtils;
|
||||
import eu.dnetlib.miscutils.jaxb.JaxbFactory;
|
||||
|
||||
/**
|
||||
* Simple registry blackboard manager implementation.
|
||||
*
|
||||
* @author marko
|
||||
*
|
||||
*/
|
||||
public class RegistryBlackboardManagerImpl implements RegistryBlackboardManager { // NOPMD
|
||||
|
||||
/**
|
||||
* logger.
|
||||
*/
|
||||
private static final Log log = LogFactory.getLog(RegistryBlackboardManagerImpl.class); // NOPMD by marko on 11/24/08 5:02 PM
|
||||
|
||||
/**
|
||||
* timestamp padding.
|
||||
*/
|
||||
private static final String PADDING = "000";
|
||||
|
||||
/**
|
||||
* milliseconds in a second.
|
||||
*/
|
||||
private static final int MILLIS = 1000;
|
||||
|
||||
/**
|
||||
* IS Lookup
|
||||
*/
|
||||
private ISLookUpService isLookup;
|
||||
|
||||
/**
|
||||
* the registry which is bound with this registry blackboard manager implementation.
|
||||
*/
|
||||
private ISRegistryService registryService;
|
||||
|
||||
/**
|
||||
* blackboard message factory.
|
||||
*/
|
||||
private JaxbFactory<BlackboardMessage> messageFactory;
|
||||
|
||||
/**
|
||||
* provides the current date. Testers can override.
|
||||
*/
|
||||
private MessageDater messageDater = new MessageDater();
|
||||
|
||||
/**
|
||||
* Testers can override.
|
||||
*
|
||||
* @author marko
|
||||
*
|
||||
*/
|
||||
public static class MessageDater {
|
||||
|
||||
public String getCurrentDate() {
|
||||
return DateUtils.now_ISO8601();
|
||||
}
|
||||
|
||||
public String getNumericStamp() {
|
||||
return Long.toString(System.currentTimeMillis() / MILLIS) + "." + System.currentTimeMillis() % MILLIS + PADDING;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* LAST_REQUEST or LAST_RESPONSE blackboard time stamp holders.
|
||||
*
|
||||
* @author marko
|
||||
*
|
||||
*/
|
||||
public enum LastStamp {
|
||||
/**
|
||||
* LAST_REQUEST, used when the blackboard message flows from the client to the server.
|
||||
*/
|
||||
REQUEST,
|
||||
|
||||
/**
|
||||
* LAST_RESPONSE, used when the blackboard message flows from the server to the client, signaling the completion/progress of the
|
||||
* action..
|
||||
*/
|
||||
RESPONSE
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @see eu.dnetlib.enabling.is.registry.RegistryBlackboardManager#addMessage(java.lang.String, java.lang.String, java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public void addMessage(final String profId, final String messageId, final String message) { // NOPMD
|
||||
try {
|
||||
final BlackboardMessage bbm = messageFactory.parse(message);
|
||||
bbm.setDate(messageDater.getCurrentDate()); // preserve compatibility.
|
||||
|
||||
if (bbm.getId() == null || !bbm.getId().equals(messageId)) { throw new IllegalArgumentException("invalid blackboard message id"); }
|
||||
|
||||
synchronized (this) {
|
||||
final OpaqueResource serviceProfile = new StringOpaqueResource(isLookup.getResourceProfile(profId));
|
||||
|
||||
final Document doc = serviceProfile.asDom();
|
||||
final Node bboard = (Node) XPathFactory.newInstance().newXPath().evaluate("//BLACKBOARD", doc, XPathConstants.NODE);
|
||||
|
||||
// delete current element if exists
|
||||
final Node messageElement = (Node) XPathFactory.newInstance().newXPath().evaluate("//BLACKBOARD/MESSAGE[@id='" + messageId + "']", doc,
|
||||
XPathConstants.NODE);
|
||||
|
||||
if (messageElement != null) {
|
||||
bboard.removeChild(messageElement);
|
||||
}
|
||||
|
||||
// append the serialized node to the blackboard node
|
||||
messageFactory.serialize(bbm, new DOMResult(bboard));
|
||||
|
||||
updateLastStamps(doc, LastStamp.REQUEST, messageId);
|
||||
|
||||
registryService.updateProfile(profId, serviceProfile.asString(), serviceProfile.getResourceType());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method which updates the LAST_* stamps in the blackboard header.
|
||||
*
|
||||
* @param doc
|
||||
* profile DOM document
|
||||
* @param stamp
|
||||
* which stamp to modify
|
||||
* @param messageId
|
||||
* message id to point the stamp to
|
||||
* @throws XPathExpressionException
|
||||
* could happen
|
||||
*/
|
||||
protected void updateLastStamps(final Document doc, final LastStamp stamp, final String messageId) throws XPathExpressionException {
|
||||
final Element lastRequest = (Element) XPathFactory.newInstance().newXPath().evaluate("//BLACKBOARD/LAST_" + stamp, doc, XPathConstants.NODE);
|
||||
lastRequest.setTextContent(messageId);
|
||||
lastRequest.setAttribute("date", messageDater.getNumericStamp());
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @see eu.dnetlib.enabling.is.registry.RegistryBlackboardManager#deleteMessage(java.lang.String, java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public void deleteMessage(final String profId, final String messageId) {
|
||||
try {
|
||||
synchronized (this) {
|
||||
final OpaqueResource serviceProfile = new StringOpaqueResource(isLookup.getResourceProfile(profId));
|
||||
final Document doc = serviceProfile.asDom();
|
||||
|
||||
final Node message = (Node) XPathFactory.newInstance().newXPath().evaluate("//BLACKBOARD/MESSAGE[@id='" + messageId + "']", doc,
|
||||
XPathConstants.NODE);
|
||||
|
||||
message.getParentNode().removeChild(message);
|
||||
|
||||
registryService.updateProfile(profId, serviceProfile.asString(), serviceProfile.getResourceType());
|
||||
}
|
||||
log.debug("Deleted bb message " + messageId + " from profile " + profId);
|
||||
} catch (Exception e) {
|
||||
log.error("Error deleting bb message " + messageId + " from profile " + profId, e);
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @see eu.dnetlib.enabling.is.registry.RegistryBlackboardManager#replyMessage(java.lang.String, java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public void replyMessage(final String profId, final String message) {
|
||||
try {
|
||||
final BlackboardMessage bbm = messageFactory.parse(message);
|
||||
bbm.setDate(messageDater.getCurrentDate()); // preserve compatibility.
|
||||
|
||||
final String messageId = bbm.getId();
|
||||
|
||||
synchronized (this) {
|
||||
final OpaqueResource serviceProfile = new StringOpaqueResource(isLookup.getResourceProfile(profId));
|
||||
final Document doc = serviceProfile.asDom();
|
||||
|
||||
final Node messageElement = (Node) XPathFactory.newInstance().newXPath().evaluate("//BLACKBOARD/MESSAGE[@id='" + messageId + "']", doc,
|
||||
XPathConstants.NODE);
|
||||
|
||||
if (messageElement == null) { throw new IllegalArgumentException("no such blackboard message " + messageId + ". Unably to reply"); }
|
||||
|
||||
final Node bboard = messageElement.getParentNode();
|
||||
bboard.removeChild(messageElement);
|
||||
|
||||
// append the serialized node to the blackboard node
|
||||
messageFactory.serialize(bbm, new DOMResult(bboard));
|
||||
|
||||
updateLastStamps(doc, LastStamp.RESPONSE, messageId);
|
||||
|
||||
registryService.updateProfile(profId, serviceProfile.asString(), serviceProfile.getResourceType());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public ISRegistryService getRegistryService() {
|
||||
return registryService;
|
||||
}
|
||||
|
||||
@Required
|
||||
public void setRegistryService(final ISRegistryService registryService) {
|
||||
this.registryService = registryService;
|
||||
}
|
||||
|
||||
public JaxbFactory<BlackboardMessage> getMessageFactory() {
|
||||
return messageFactory;
|
||||
}
|
||||
|
||||
@Required
|
||||
public void setMessageFactory(final JaxbFactory<BlackboardMessage> messageFactory) {
|
||||
this.messageFactory = messageFactory;
|
||||
}
|
||||
|
||||
public MessageDater getMessageDater() {
|
||||
return messageDater;
|
||||
}
|
||||
|
||||
public void setMessageDater(final MessageDater messageDater) {
|
||||
this.messageDater = messageDater;
|
||||
}
|
||||
|
||||
public ISLookUpService getIsLookup() {
|
||||
return isLookup;
|
||||
}
|
||||
|
||||
@Required
|
||||
public void setIsLookup(final ISLookUpService isLookup) {
|
||||
this.isLookup = isLookup;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
package eu.dnetlib.enabling.is.registry;
|
||||
|
||||
import javax.xml.xpath.XPathExpressionException;
|
||||
|
||||
public interface ResourceKindResolver {
|
||||
String getNormalKindForType(final String resourceType) throws XPathExpressionException;
|
||||
String getPendingKindForType(final String resourceType) throws XPathExpressionException;
|
||||
}
|
|
@ -0,0 +1,62 @@
|
|||
package eu.dnetlib.enabling.is.registry;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import javax.xml.xpath.XPathExpressionException;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.beans.factory.annotation.Required;
|
||||
|
||||
/**
|
||||
* Returns the first resource resolver
|
||||
*
|
||||
* @author marko
|
||||
*
|
||||
*/
|
||||
public class ResourceKindResolverChain implements ResourceKindResolver {
|
||||
|
||||
private static final Log log = LogFactory.getLog(ResourceKindResolverChain.class); // NOPMD by marko on 11/24/08 5:02 PM
|
||||
|
||||
/**
|
||||
* resolvers.
|
||||
*/
|
||||
private List<ResourceKindResolver> resolvers;
|
||||
|
||||
@Override
|
||||
public String getNormalKindForType(final String resourceType) throws XPathExpressionException {
|
||||
for (final ResourceKindResolver resolver : resolvers) {
|
||||
final String res = resolver.getNormalKindForType(resourceType);
|
||||
if (res != null)
|
||||
return res;
|
||||
}
|
||||
return null;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPendingKindForType(final String resourceType) throws XPathExpressionException {
|
||||
for (final ResourceKindResolver resolver : resolvers) {
|
||||
try {
|
||||
final String res = resolver.getPendingKindForType(resourceType);
|
||||
if (res != null)
|
||||
return res;
|
||||
} catch (NoSuchPendingCategoryException e) {
|
||||
log.debug("resolver didn't find pending category", e);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
log.debug("cannot find pending category because no resolver found a pending category");
|
||||
throw new NoSuchPendingCategoryException("no pending category for " + resourceType);
|
||||
}
|
||||
|
||||
public List<ResourceKindResolver> getResolvers() {
|
||||
return resolvers;
|
||||
}
|
||||
|
||||
@Required
|
||||
public void setResolvers(final List<ResourceKindResolver> resolvers) {
|
||||
this.resolvers = resolvers;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
package eu.dnetlib.enabling.is.registry.schema;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.StringReader;
|
||||
|
||||
import javax.xml.transform.stream.StreamSource;
|
||||
import javax.xml.validation.Schema;
|
||||
import javax.xml.validation.Validator;
|
||||
|
||||
import org.xml.sax.SAXException;
|
||||
|
||||
import eu.dnetlib.enabling.tools.OpaqueResource;
|
||||
|
||||
/**
|
||||
* validates an opaque resource according to its declared resource type.
|
||||
*
|
||||
* @author marko
|
||||
*
|
||||
*/
|
||||
public class OpaqueResourceValidatorImpl implements OpaqueResourceValidator {
|
||||
|
||||
/**
|
||||
* schema dao.
|
||||
*/
|
||||
private ResourceSchemaDAO schemaDao;
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @see eu.dnetlib.enabling.is.registry.schema.OpaqueResourceValidator#validate(eu.dnetlib.enabling.tools.OpaqueResource)
|
||||
*/
|
||||
@Override
|
||||
public void validate(final OpaqueResource resource) throws ValidationException {
|
||||
final Schema schema = getSchemaDao().getResourceSchema(resource.getResourceType());
|
||||
if (schema == null)
|
||||
throw new ValidationException("no registered schema for " + resource.getResourceType());
|
||||
final Validator validator = schema.newValidator();
|
||||
|
||||
try {
|
||||
// hack to workaround for #1500
|
||||
validator.validate(new StreamSource(new StringReader(resource.asString())));
|
||||
} catch (SAXException e) {
|
||||
throw new ValidationException(e);
|
||||
} catch (IOException e) {
|
||||
throw new ValidationException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public ResourceSchemaDAO getSchemaDao() {
|
||||
return schemaDao;
|
||||
}
|
||||
|
||||
public void setSchemaDao(final ResourceSchemaDAO schemaDao) {
|
||||
this.schemaDao = schemaDao;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
package eu.dnetlib.enabling.is.registry.schema;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import eu.dnetlib.enabling.tools.OpaqueResource;
|
||||
|
||||
/**
|
||||
* Unlike the OpaqueResourceValidatorImpl, this implementation only logs an error but accepts every resource as valid.
|
||||
*
|
||||
* Use only during testing/development!
|
||||
*
|
||||
* @author marko
|
||||
*
|
||||
*/
|
||||
public class PermissiveOpaqueResourceValidatorImpl extends OpaqueResourceValidatorImpl {
|
||||
/**
|
||||
* logger.
|
||||
*/
|
||||
private static final Log log = LogFactory.getLog(PermissiveOpaqueResourceValidatorImpl.class); // NOPMD by marko on 11/24/08 5:02 PM
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @see eu.dnetlib.enabling.is.registry.schema.OpaqueResourceValidatorImpl#validate(eu.dnetlib.enabling.tools.OpaqueResource)
|
||||
*/
|
||||
@Override
|
||||
public void validate(final OpaqueResource resource) throws ValidationException {
|
||||
try {
|
||||
super.validate(resource);
|
||||
} catch (ValidationException e) {
|
||||
log.fatal("validation error, continuing (permissive mode)", e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
package eu.dnetlib.enabling.is.registry.schema;
|
||||
|
||||
import javax.xml.validation.Schema;
|
||||
|
||||
/**
|
||||
* data access object for managing resource schemas.
|
||||
*
|
||||
* @author marko
|
||||
*
|
||||
*/
|
||||
public interface ResourceSchemaDAO {
|
||||
|
||||
/**
|
||||
* obtain a resource schema instance for a given resource type.
|
||||
*
|
||||
* @param resourceType resource type
|
||||
* @return schema instance
|
||||
*/
|
||||
Schema getResourceSchema(String resourceType);
|
||||
|
||||
}
|
|
@ -0,0 +1,65 @@
|
|||
package eu.dnetlib.enabling.is.registry.schema;
|
||||
|
||||
import java.io.StringReader;
|
||||
|
||||
import javax.xml.XMLConstants;
|
||||
import javax.xml.transform.stream.StreamSource;
|
||||
import javax.xml.validation.Schema;
|
||||
import javax.xml.validation.SchemaFactory;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.beans.factory.annotation.Required;
|
||||
import org.xml.sax.SAXException;
|
||||
|
||||
import eu.dnetlib.enabling.is.lookup.rmi.ISLookUpException;
|
||||
import eu.dnetlib.enabling.is.lookup.rmi.ISLookUpService;
|
||||
|
||||
/**
|
||||
* manages the resource schemas through the registry service.
|
||||
*
|
||||
* @author marko
|
||||
*
|
||||
*/
|
||||
public class ResourceSchemaDAOImpl implements ResourceSchemaDAO {
|
||||
|
||||
private ISLookUpService isLookup;
|
||||
|
||||
/**
|
||||
* logger.
|
||||
*/
|
||||
private static final Log log = LogFactory.getLog(ResourceSchemaDAOImpl.class); // NOPMD by marko on 11/24/08 5:02 PM
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @see eu.dnetlib.enabling.is.registry.schema.ResourceSchemaDAO#getResourceSchema(java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public Schema getResourceSchema(final String resourceType) {
|
||||
try {
|
||||
final String schemaSource = isLookup.getResourceTypeSchema(resourceType);
|
||||
if (schemaSource == null || schemaSource.isEmpty()) {
|
||||
log.warn("cannot find resource type " + resourceType);
|
||||
return null;
|
||||
}
|
||||
return SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI).newSchema(new StreamSource(new StringReader(schemaSource)));
|
||||
} catch (ISLookUpException e) {
|
||||
log.warn("cannot find resource type" + resourceType, e);
|
||||
return null;
|
||||
} catch (SAXException e) {
|
||||
log.fatal("cannot parse resource type schema", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public ISLookUpService getIsLookup() {
|
||||
return isLookup;
|
||||
}
|
||||
|
||||
@Required
|
||||
public void setIsLookup(final ISLookUpService isLookup) {
|
||||
this.isLookup = isLookup;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
package eu.dnetlib.enabling.is.registry.validation;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Required;
|
||||
|
||||
import eu.dnetlib.enabling.tools.OpaqueResource;
|
||||
|
||||
public abstract class AbstractProfileValidator implements ProfileValidator {
|
||||
|
||||
private RegistrationPhase phase;
|
||||
|
||||
@Override
|
||||
public boolean handle(final OpaqueResource resource, final RegistrationPhase phase) {
|
||||
return this.phase == phase;
|
||||
}
|
||||
|
||||
@Required
|
||||
public void setPhase(String phase) {
|
||||
this.phase = RegistrationPhase.valueOf(phase);
|
||||
}
|
||||
|
||||
public String getPhase() {
|
||||
return phase.name();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
package eu.dnetlib.enabling.is.registry.validation;
|
||||
|
||||
import eu.dnetlib.enabling.tools.OpaqueResource;
|
||||
|
||||
/**
|
||||
* Dummy bean used to populate the ProfileValidator list.
|
||||
* @see eu.dnetlib.enabling.is.registry.validation.ProfileValidationStrategy
|
||||
*
|
||||
* @author claudio
|
||||
*
|
||||
*/
|
||||
public class AlwaysAcceptProfileValidator implements ProfileValidator {
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @see eu.dnetlib.enabling.is.registry.validation.ProfileValidator#accept(OpaqueResource)
|
||||
*/
|
||||
@Override
|
||||
public boolean accept(OpaqueResource resource) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @see eu.dnetlib.enabling.is.registry.validation.ProfileValidator#handle(OpaqueResource, RegistrationPhase)
|
||||
*/
|
||||
@Override
|
||||
public boolean handle(OpaqueResource resource, RegistrationPhase phase) {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
package eu.dnetlib.enabling.is.registry.validation;
|
||||
|
||||
import javax.xml.xpath.XPath;
|
||||
import javax.xml.xpath.XPathExpressionException;
|
||||
import javax.xml.xpath.XPathFactory;
|
||||
|
||||
import eu.dnetlib.enabling.tools.OpaqueResource;
|
||||
|
||||
public class EnsurePropertyExistsProfileValidator extends TypeAwareProfileValidator {
|
||||
|
||||
private String name; // property name
|
||||
|
||||
@Override
|
||||
public boolean accept(OpaqueResource resource) {
|
||||
try {
|
||||
final XPath xpath = XPathFactory.newInstance().newXPath();
|
||||
|
||||
final String xquery = "//EXTRA_FIELDS/FIELD[./key = '" + getName() + "']/value/text()";
|
||||
final String value = xpath.evaluate(xquery, resource.asDom().getDocumentElement()) + "";
|
||||
|
||||
if (value.isEmpty())
|
||||
return false;
|
||||
|
||||
return true;
|
||||
|
||||
} catch (XPathExpressionException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
package eu.dnetlib.enabling.is.registry.validation;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
import eu.dnetlib.enabling.is.registry.schema.ValidationException;
|
||||
import eu.dnetlib.enabling.tools.OpaqueResource;
|
||||
|
||||
/**
|
||||
* ProfileValidationStrategy iterates all the profile validators,
|
||||
* once a suitable validator is found, it's called to accept or
|
||||
* reject the given resource.
|
||||
*
|
||||
* @author claudio
|
||||
*
|
||||
*/
|
||||
public class ProfileValidationStrategy {
|
||||
|
||||
@Resource
|
||||
private List<ProfileValidator> profileValidators;
|
||||
|
||||
public boolean accept(OpaqueResource resource, RegistrationPhase phase) throws ValidationException {
|
||||
for(ProfileValidator validator : profileValidators) {
|
||||
if (validator.handle(resource, phase)) {
|
||||
if (validator.accept(resource))
|
||||
return true;
|
||||
else throw new ValidationException("Cannot validate the given resource: " + resource.asString());
|
||||
}
|
||||
}
|
||||
// if no validator handles the resource
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
package eu.dnetlib.enabling.is.registry.validation;
|
||||
|
||||
import eu.dnetlib.enabling.tools.OpaqueResource;
|
||||
|
||||
public interface ProfileValidator {
|
||||
/**
|
||||
* True if this validator will handle this profile, false otherwise.
|
||||
* 'accept' will be invoked only if 'handle' returns true
|
||||
*
|
||||
* @param resource
|
||||
* @param phase
|
||||
* @return
|
||||
*/
|
||||
public boolean handle(OpaqueResource resource, RegistrationPhase phase);
|
||||
|
||||
/**
|
||||
* true if accept, false reject.
|
||||
*
|
||||
* @param resource
|
||||
* @return
|
||||
*/
|
||||
public boolean accept(OpaqueResource resource);
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
package eu.dnetlib.enabling.is.registry.validation;
|
||||
|
||||
/**
|
||||
* Resources registration phases.
|
||||
*
|
||||
* @author claudio
|
||||
*
|
||||
*/
|
||||
public enum RegistrationPhase {
|
||||
Register,
|
||||
Validate // as in 'validateProfile', not this 'validation'.
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
package eu.dnetlib.enabling.is.registry.validation;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Required;
|
||||
|
||||
import eu.dnetlib.enabling.tools.OpaqueResource;
|
||||
|
||||
public abstract class TypeAwareProfileValidator extends AbstractProfileValidator {
|
||||
|
||||
private String resourceType;
|
||||
|
||||
@Override
|
||||
public boolean handle(OpaqueResource resource, RegistrationPhase phase) {
|
||||
return super.handle(resource, phase) && getResourceType().equals(resource.getResourceType());
|
||||
}
|
||||
|
||||
@Required
|
||||
public void setResourceType(String resourceType) {
|
||||
this.resourceType = resourceType;
|
||||
}
|
||||
|
||||
public String getResourceType() {
|
||||
return resourceType;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
package eu.dnetlib.enabling.is.sn;
|
||||
|
||||
/**
|
||||
* NotificationDetector interface defines an injection point for the NotificationSender instance.
|
||||
*
|
||||
* <p>
|
||||
* It will be fairly common for implementors of NotificatiorDetector to back the sender reference into an instance
|
||||
* variable. This abstract class offers this for free.
|
||||
* </p>
|
||||
*
|
||||
* @author marko
|
||||
*
|
||||
*/
|
||||
public abstract class AbstractNotificationDetector implements NotificationDetector {
|
||||
|
||||
/**
|
||||
* notification sender which will receive events triggered by this detector.
|
||||
*/
|
||||
private NotificationSender sender;
|
||||
|
||||
public NotificationSender getSender() {
|
||||
return sender;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSender(final NotificationSender sender) {
|
||||
this.sender = sender;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
package eu.dnetlib.enabling.is.sn;
|
||||
|
||||
|
||||
/**
|
||||
* NotificationSender interface defines an injection point for the NotificationInvoker instance.
|
||||
*
|
||||
* <p>
|
||||
* It will be fairly common for implementors of NotificationSender to back the invoker reference into an instance
|
||||
* variable. This abstract class offers this for free. </p>
|
||||
*
|
||||
* @author marko
|
||||
*
|
||||
*/
|
||||
public abstract class AbstractNotificationSender implements NotificationSender {
|
||||
|
||||
/**
|
||||
* notification invoker used to send messages to destinations.
|
||||
*/
|
||||
private NotificationInvoker invoker;
|
||||
|
||||
public NotificationInvoker getInvoker() {
|
||||
return invoker;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setInvoker(final NotificationInvoker invoker) {
|
||||
this.invoker = invoker;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
package eu.dnetlib.enabling.is.sn;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import org.apache.oro.text.perl.Perl5Util;
|
||||
|
||||
/**
|
||||
* Provides common functionality for subscription registries.
|
||||
*
|
||||
* @author marko
|
||||
*
|
||||
*/
|
||||
public abstract class AbstractSubscriptionRegistry {
|
||||
|
||||
/**
|
||||
* prefix position in regular expression.
|
||||
*/
|
||||
private static final int PREFIX_POSITION = 1;
|
||||
|
||||
/**
|
||||
* rest of string position in regular expression.
|
||||
*/
|
||||
private static final int REST_POSITION = 3;
|
||||
|
||||
/**
|
||||
* Return true if the subscription prefix is acceptable.
|
||||
*
|
||||
* Topic expressions are made of slash-delimited components. The "prefix" here is the first slash (/) delimited
|
||||
* string of the topic expression.
|
||||
*
|
||||
* TODO: stupid implementation.
|
||||
*
|
||||
* @param subscription
|
||||
* subscription request
|
||||
* @return true if accepted
|
||||
*/
|
||||
protected TopicExpressionMatchResult matchPrefix(final SubscriptionRequest subscription) {
|
||||
final Perl5Util matcher = new Perl5Util(); // NOPMD
|
||||
|
||||
for (String prefix : getAcceptedPrefixes())
|
||||
if (matcher.match("/^(" + prefix + ")($|/)(.*)$/", subscription.getTopicExpression())) {
|
||||
return new TopicExpressionMatchResult(matcher.getMatch().group(PREFIX_POSITION), matcher.getMatch().group(REST_POSITION));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* A collection of accepted prefixes.
|
||||
*
|
||||
* @return prefix list
|
||||
*/
|
||||
protected abstract Collection<String> getAcceptedPrefixes();
|
||||
}
|
|
@ -0,0 +1,119 @@
|
|||
package eu.dnetlib.enabling.is.sn;
|
||||
|
||||
import java.util.concurrent.BlockingQueue;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
|
||||
import javax.xml.ws.wsaddressing.W3CEndpointReference;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
/**
|
||||
* Asynchronous but in-order delivery of notifications.
|
||||
*
|
||||
* @author marko
|
||||
*
|
||||
*/
|
||||
public class AsynchronousNotificationSenderImpl extends AbstractNotificationSender implements Runnable { // NOPMD
|
||||
/**
|
||||
* logger.
|
||||
*/
|
||||
private static final Log log = LogFactory.getLog(AsynchronousNotificationSenderImpl.class); // NOPMD by marko on 11/24/08 5:02 PM
|
||||
|
||||
/**
|
||||
* Encapsulates an notification job.
|
||||
*
|
||||
* @author marko
|
||||
*
|
||||
*/
|
||||
class NotificationJob {
|
||||
/**
|
||||
* notification destination.
|
||||
*/
|
||||
private final transient W3CEndpointReference destination;
|
||||
|
||||
/**
|
||||
* notification message.
|
||||
*/
|
||||
private final transient NotificationMessage message;
|
||||
|
||||
/**
|
||||
* construct a new notification job.
|
||||
*
|
||||
* @param destination destination
|
||||
* @param message message
|
||||
*/
|
||||
public NotificationJob(final W3CEndpointReference destination, final NotificationMessage message) {
|
||||
super();
|
||||
this.destination = destination;
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
public W3CEndpointReference getDestination() {
|
||||
return destination;
|
||||
}
|
||||
|
||||
public NotificationMessage getMessage() {
|
||||
return message;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* job queue.
|
||||
*/
|
||||
private BlockingQueue<NotificationJob> jobQueue = new LinkedBlockingQueue<NotificationJob>();
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @see eu.dnetlib.enabling.is.sn.NotificationSender#send(javax.xml.ws.wsaddressing.W3CEndpointReference,
|
||||
* eu.dnetlib.enabling.is.sn.NotificationMessage)
|
||||
*/
|
||||
@Override
|
||||
public void send(final W3CEndpointReference destination, final NotificationMessage message) {
|
||||
log.debug("queuing asynchronous notification");
|
||||
try {
|
||||
jobQueue.put(new NotificationJob(destination, message));
|
||||
} catch (InterruptedException e) {
|
||||
log.warn("possibly lost notification", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* start this notification sender (called by spring lifecycle).
|
||||
*/
|
||||
void start() {
|
||||
new Thread(this).start(); // NOPMD
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* @see java.lang.Runnable#run()
|
||||
*/
|
||||
@Override
|
||||
public void run() {
|
||||
while (true) {
|
||||
try {
|
||||
final NotificationJob job = jobQueue.take();
|
||||
|
||||
try {
|
||||
getInvoker().send(job.getDestination(), job.getMessage(), 0);
|
||||
} catch (javax.xml.ws.soap.SOAPFaultException t) {
|
||||
log.fatal("error sending notification to " + job.getDestination().toString(), t);
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
log.warn("possibly lost notification", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public BlockingQueue<NotificationJob> getJobQueue() {
|
||||
return jobQueue;
|
||||
}
|
||||
|
||||
public void setJobQueue(final BlockingQueue<NotificationJob> jobQueue) {
|
||||
this.jobQueue = jobQueue;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
package eu.dnetlib.enabling.is.sn;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
public class DnetPathVerifier {
|
||||
|
||||
/**
|
||||
* logger.
|
||||
*/
|
||||
private static final Log log = LogFactory.getLog(DnetPathVerifier.class); // NOPMD by marko on 11/24/08 5:02 PM
|
||||
|
||||
public DnetPathVerifier(final String dnetPath) {
|
||||
File f = new File(dnetPath);
|
||||
if (f.exists() == false) {
|
||||
log.info("path '" + dnetPath + "' not found, creating...");
|
||||
f.mkdirs();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,65 @@
|
|||
package eu.dnetlib.enabling.is.sn;
|
||||
|
||||
import javax.xml.transform.dom.DOMResult;
|
||||
import javax.xml.ws.wsaddressing.W3CEndpointReference;
|
||||
import javax.xml.xpath.XPathExpressionException;
|
||||
import javax.xml.xpath.XPathFactory;
|
||||
|
||||
/**
|
||||
* Extracts useful low level informations from an EPR, so that these can be encoded in the OAI
|
||||
* resumption token.
|
||||
*
|
||||
* @author michele
|
||||
*
|
||||
*/
|
||||
public final class EPRUtil {
|
||||
|
||||
/**
|
||||
* prevents instantiation.
|
||||
*/
|
||||
private EPRUtil() {
|
||||
// prevents instantiation
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts the service address out of the EPR.
|
||||
*
|
||||
* @param epr epr
|
||||
* @return address
|
||||
*/
|
||||
public static String getAddress(final W3CEndpointReference epr) {
|
||||
return getValue(epr, "Address");
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts the resource identifier out of the EPR.
|
||||
* @param epr epr
|
||||
* @return resource identifier
|
||||
*/
|
||||
public static String getResourceIdentifier(final W3CEndpointReference epr) {
|
||||
return getValue(epr, "ResourceIdentifier");
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts an element with a given local name out of the resource identifier.
|
||||
*
|
||||
* @param epr epr
|
||||
* @param name element name
|
||||
* @return element value
|
||||
*/
|
||||
private static String getValue(final W3CEndpointReference epr, final String name) {
|
||||
final DOMResult dom = new DOMResult();
|
||||
epr.writeTo(dom);
|
||||
|
||||
try {
|
||||
return XPathFactory.newInstance().newXPath().evaluate("//*[local-name() = '" + name + "']", dom.getNode());
|
||||
} catch (final XPathExpressionException e) {
|
||||
throw new IllegalStateException("cannot construct xpath expression", e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,180 @@
|
|||
package eu.dnetlib.enabling.is.sn;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Collection;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipOutputStream;
|
||||
|
||||
import javax.xml.ws.wsaddressing.W3CEndpointReference;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.beans.factory.annotation.Required;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
|
||||
import eu.dnetlib.enabling.is.sn.resourcestate.ResourceStateSubscription;
|
||||
import eu.dnetlib.enabling.is.sn.resourcestate.ResourceStateSubscriptionRegistry;
|
||||
import eu.dnetlib.enabling.is.sn.rmi.ISSNException;
|
||||
import eu.dnetlib.enabling.is.sn.rmi.SubscriptionRequestRejectedException;
|
||||
import eu.dnetlib.enabling.tools.UniqueIdentifierGenerator;
|
||||
import eu.dnetlib.enabling.tools.UniqueIdentifierGeneratorImpl;
|
||||
import eu.dnetlib.miscutils.datetime.DateUtils;
|
||||
|
||||
/**
|
||||
* Core business logic of ISSN service, decouple from compatibility RMI interface.
|
||||
*
|
||||
* @author marko
|
||||
*
|
||||
*/
|
||||
public class ISSNServiceCore {
|
||||
|
||||
/**
|
||||
* logger.
|
||||
*/
|
||||
private static final Log log = LogFactory.getLog(ISSNServiceCore.class); // NOPMD by marko on 11/24/08 5:02 PM
|
||||
|
||||
/**
|
||||
* subscription registries to lookup.
|
||||
*/
|
||||
private SubscriptionRegistry registry;
|
||||
|
||||
/**
|
||||
* generates subscription identifiers.
|
||||
*/
|
||||
private UniqueIdentifierGenerator uuidGenerator = new UniqueIdentifierGeneratorImpl("sn");
|
||||
|
||||
/**
|
||||
* Directory in which backups are saved.
|
||||
*/
|
||||
private String backupDir;
|
||||
|
||||
/**
|
||||
* subscribe a consumer to topics matching the topic expression.
|
||||
*
|
||||
* @param consumerReference
|
||||
* EPR to the service to be notified
|
||||
* @param topicExpression
|
||||
* topic expression
|
||||
* @param ttl
|
||||
* time to live in seconds
|
||||
* @return subscription identifier
|
||||
*/
|
||||
public String subscribe(final W3CEndpointReference consumerReference, final String topicExpression, final int ttl) throws SubscriptionRequestRejectedException {
|
||||
log.debug("subscribing");
|
||||
final SubscriptionRequest srq = new SubscriptionRequest(uuidGenerator.generateIdentifier(), consumerReference, topicExpression, ttl); // NOPMD
|
||||
|
||||
final String subId = getRegistry().registerSubscription(srq);
|
||||
if (subId != null) {
|
||||
return subId;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unsubscribe a subscription, by id.
|
||||
*
|
||||
* @param subscrId subscription id
|
||||
* @return true if unsubscribed
|
||||
*/
|
||||
public boolean unsubscribe(final String subscrId) {
|
||||
return getRegistry().unsubscribe(subscrId);
|
||||
}
|
||||
|
||||
public String backup() throws ISSNException {
|
||||
log.info("Starting backup...");
|
||||
try {
|
||||
|
||||
verifyBackupDir();
|
||||
|
||||
String seq = (new SimpleDateFormat("yyyyMMdd-HHmm")).format(new Date());
|
||||
|
||||
ZipOutputStream zip = new ZipOutputStream(new FileOutputStream(backupDir + "/data-" + seq + ".zip"));
|
||||
|
||||
FileWriter logFile = new FileWriter(backupDir + "/report-" + seq + ".log");
|
||||
logFile.write("Backup started at: " + DateUtils.now_ISO8601() + "\n\n");
|
||||
|
||||
backup(zip, logFile);
|
||||
|
||||
logFile.write("\nBackup finished at: " + DateUtils.now_ISO8601() + "\n");
|
||||
|
||||
logFile.flush();
|
||||
logFile.close();
|
||||
|
||||
zip.flush();
|
||||
zip.close();
|
||||
|
||||
log.info("Backup finished");
|
||||
return backupDir;
|
||||
} catch (final Exception e) {
|
||||
log.error("Backup failed", e);
|
||||
throw new ISSNException("cannot backup", e);
|
||||
}
|
||||
}
|
||||
|
||||
private void backup(ZipOutputStream zip, FileWriter logFile) throws IOException {
|
||||
|
||||
for (ResourceStateSubscription sub : getRegistry().listSubscriptions()) {
|
||||
|
||||
logFile.write("SUBSCRIPTION: " + sub.getSubscriptionId() + "\n");
|
||||
log.info("Backup of subscription: " + sub.getSubscriptionId());
|
||||
|
||||
final Map<String, String> attrs = new HashMap<String, String>(); // NOPMD
|
||||
attrs.put("prefix", sub.getPrefix());
|
||||
attrs.put("type", sub.getType());
|
||||
attrs.put("resourceId", sub.getResourceId());
|
||||
attrs.put("xpath", sub.getXpath());
|
||||
attrs.put("id", sub.getSubscriptionId());
|
||||
attrs.put("subscriber", sub.getSubscriber().toString());
|
||||
|
||||
zip.putNextEntry(new ZipEntry(sub.getSubscriptionId()));
|
||||
zip.write(encodeJSon(attrs).getBytes());
|
||||
zip.closeEntry();
|
||||
}
|
||||
}
|
||||
|
||||
private String encodeJSon(final Map<String, String> map) {
|
||||
return new Gson().toJson(
|
||||
map,
|
||||
new TypeToken<Map<String, String>>() {}.getType()
|
||||
);
|
||||
}
|
||||
|
||||
private void verifyBackupDir() {
|
||||
File d = new File(backupDir);
|
||||
if (!d.exists()) d.mkdirs();
|
||||
}
|
||||
|
||||
public UniqueIdentifierGenerator getUuidGenerator() {
|
||||
return uuidGenerator;
|
||||
}
|
||||
|
||||
public void setUuidGenerator(final UniqueIdentifierGenerator uuidGenerator) {
|
||||
this.uuidGenerator = uuidGenerator;
|
||||
}
|
||||
|
||||
public String getBackupDir() {
|
||||
return backupDir;
|
||||
}
|
||||
|
||||
@Required
|
||||
public void setBackupDir(String backupDir) {
|
||||
this.backupDir = backupDir;
|
||||
}
|
||||
|
||||
public SubscriptionRegistry getRegistry() {
|
||||
return registry;
|
||||
}
|
||||
|
||||
public void setRegistry(final SubscriptionRegistry registry) {
|
||||
this.registry = registry;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,203 @@
|
|||
package eu.dnetlib.enabling.is.sn;
|
||||
|
||||
import java.util.Calendar;
|
||||
import java.util.List;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.xml.ws.Endpoint;
|
||||
import javax.xml.ws.wsaddressing.W3CEndpointReference;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import eu.dnetlib.enabling.is.sn.rmi.ISSNException;
|
||||
import eu.dnetlib.enabling.is.sn.rmi.ISSNService;
|
||||
import eu.dnetlib.enabling.is.sn.rmi.SubscriptionRequestRejectedException;
|
||||
import eu.dnetlib.enabling.tools.AbstractBaseService;
|
||||
import eu.dnetlib.soap.EndpointReferenceBuilder;
|
||||
|
||||
/**
|
||||
* implementation of ISSNService.
|
||||
*
|
||||
* @author marko
|
||||
*
|
||||
*/
|
||||
public class ISSNServiceImpl extends AbstractBaseService implements ISSNService {
|
||||
|
||||
/**
|
||||
* logger.
|
||||
*/
|
||||
private static final Log log = LogFactory.getLog(ISSNServiceImpl.class); // NOPMD by marko on 11/24/08 5:02 PM
|
||||
|
||||
/**
|
||||
* obvious constant.
|
||||
*/
|
||||
private static final int MILLIS_IN_SECOND = 1000;
|
||||
|
||||
/**
|
||||
* service endpoint.
|
||||
*/
|
||||
private Endpoint endpoint;
|
||||
|
||||
/**
|
||||
* core business logic.
|
||||
*/
|
||||
private ISSNServiceCore core;
|
||||
|
||||
/**
|
||||
* injected EPR builder.
|
||||
*/
|
||||
@Resource(name = "jaxwsEndpointReferenceBuilder")
|
||||
private EndpointReferenceBuilder<Endpoint> eprBuilder;
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @see eu.dnetlib.enabling.is.sn.rmi.ISSNService#actionCreatePerformed(java.lang.String, java.lang.String, java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public boolean actionCreatePerformed(final String resourceType, final String profileId, final String profile) throws ISSNException {
|
||||
log.fatal("actionCreatePerformed(String, String, String) not implemented");
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @see eu.dnetlib.enabling.is.sn.rmi.ISSNService#actionDeletePerformed(java.lang.String, java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public boolean actionDeletePerformed(final String resourceType, final String profileId) throws ISSNException {
|
||||
log.fatal("actionDeletePerformed(String, String) not implemented");
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @see eu.dnetlib.enabling.is.sn.rmi.ISSNService#actionUpdatePerformed(java.lang.String, java.lang.String, java.lang.String,
|
||||
* java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public boolean actionUpdatePerformed(final String resourceType, final String profileId, final String profileBefore, final String profileAfter)
|
||||
throws ISSNException {
|
||||
log.fatal("actionUpdatePerformed(String, String, String, String) not implemented");
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @see eu.dnetlib.enabling.is.sn.rmi.ISSNService#getCurrentMessage(java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public String getCurrentMessage(final String topic) throws ISSNException {
|
||||
log.fatal("getCurrentMessage(String) not implemented");
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @see eu.dnetlib.enabling.is.sn.rmi.ISSNService#listSubscriptions()
|
||||
*/
|
||||
@Override
|
||||
public List<String> listSubscriptions() {
|
||||
log.fatal("listSubscriptions() not implemented");
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @see eu.dnetlib.enabling.is.sn.rmi.ISSNService#pauseSubscription(java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public boolean pauseSubscription(final String subscrId) throws ISSNException {
|
||||
log.fatal("pauseSubscription(String) not implemented");
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @see eu.dnetlib.enabling.is.sn.rmi.ISSNService#renew(java.lang.String, int)
|
||||
*/
|
||||
@Override
|
||||
public boolean renew(final String subscrId, final int terminationTime) throws ISSNException {
|
||||
log.fatal("renew(String, int) not implemented");
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @see eu.dnetlib.enabling.is.sn.rmi.ISSNService#resumeSubscription(java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public boolean resumeSubscription(final String subscrId) throws ISSNException {
|
||||
log.fatal("resumeSubscription(String) not implemented");
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @see eu.dnetlib.enabling.is.sn.rmi.ISSNService#subscribe(javax.xml.ws.wsaddressing.W3CEndpointReference, java.lang.String, int)
|
||||
*/
|
||||
@Override
|
||||
public String subscribe(final W3CEndpointReference consumerReference, final String topicExpression, final int termTime) throws ISSNException, SubscriptionRequestRejectedException {
|
||||
|
||||
log.debug("subscribe request from: " + consumerReference.toString() + " topic: " + topicExpression);
|
||||
|
||||
int ttl;
|
||||
if (termTime == 0) {
|
||||
ttl = 0;
|
||||
} else {
|
||||
ttl = (int) (termTime - (Calendar.getInstance().getTimeInMillis() / MILLIS_IN_SECOND));
|
||||
}
|
||||
|
||||
final String res = core.subscribe(consumerReference, topicExpression, ttl);
|
||||
if (res == null) throw new ISSNException("couldn't find a subscription registry for the given topic: " + topicExpression);
|
||||
|
||||
log.debug("subscribe success, subscriptionId: " + res);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @see eu.dnetlib.enabling.is.sn.rmi.ISSNService#unsubscribe(java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public boolean unsubscribe(final String subscrId) throws ISSNException {
|
||||
log.debug("unsubscribe request for: " + subscrId);
|
||||
return core.unsubscribe(subscrId);
|
||||
}
|
||||
|
||||
public Endpoint getEndpoint() {
|
||||
return endpoint;
|
||||
}
|
||||
|
||||
public void setEndpoint(final Endpoint endpoint) {
|
||||
this.endpoint = endpoint;
|
||||
}
|
||||
|
||||
public ISSNServiceCore getCore() {
|
||||
return core;
|
||||
}
|
||||
|
||||
public void setCore(final ISSNServiceCore core) {
|
||||
this.core = core;
|
||||
}
|
||||
|
||||
public EndpointReferenceBuilder<Endpoint> getEprBuilder() {
|
||||
return eprBuilder;
|
||||
}
|
||||
|
||||
public void setEprBuilder(final EndpointReferenceBuilder<Endpoint> eprBuilder) {
|
||||
this.eprBuilder = eprBuilder;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,263 @@
|
|||
package eu.dnetlib.enabling.is.sn;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Date;
|
||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||
|
||||
import javax.xml.ws.wsaddressing.W3CEndpointReference;
|
||||
|
||||
/**
|
||||
* In memory implementation of a notification invocation logger.
|
||||
*
|
||||
* @author marko
|
||||
*
|
||||
*/
|
||||
public class MemoryNotificationInvocationLogger implements NotificationInvocationLogger {
|
||||
|
||||
/**
|
||||
* default log size.
|
||||
*/
|
||||
private static final int DEFAULT_SIZE = 100;
|
||||
|
||||
/**
|
||||
* Entry.
|
||||
*
|
||||
* @author marko
|
||||
*
|
||||
*/
|
||||
public class MemoryEntry implements Entry {
|
||||
|
||||
/**
|
||||
* logged message.
|
||||
*/
|
||||
private NotificationMessage message;
|
||||
|
||||
/**
|
||||
* message status.
|
||||
*/
|
||||
private Status status = Status.Queued;
|
||||
|
||||
/**
|
||||
* saved exception in case of Failed state.
|
||||
*/
|
||||
private Throwable exception;
|
||||
|
||||
/**
|
||||
* destination.
|
||||
*/
|
||||
private W3CEndpointReference destinationEpr;
|
||||
|
||||
/**
|
||||
* start date time.
|
||||
*/
|
||||
private Date start;
|
||||
|
||||
/**
|
||||
* finish date time.
|
||||
*/
|
||||
private Date finish;
|
||||
|
||||
/**
|
||||
* construct a new message.
|
||||
*
|
||||
* @param endpointReference
|
||||
* destination
|
||||
*
|
||||
* @param message
|
||||
* message
|
||||
*/
|
||||
public MemoryEntry(final W3CEndpointReference endpointReference, final NotificationMessage message) {
|
||||
this.destinationEpr = endpointReference;
|
||||
this.message = message;
|
||||
this.start = new Date();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @see eu.dnetlib.enabling.is.sn.NotificationInvocationLogger.Entry#ongoing()
|
||||
*/
|
||||
@Override
|
||||
public void ongoing() {
|
||||
status = Status.Ongoing;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @see eu.dnetlib.enabling.is.sn.NotificationInvocationLogger.Entry#failure(java.lang.Throwable)
|
||||
*/
|
||||
@Override
|
||||
public void failure(final Throwable exc) {
|
||||
status = Status.Failed;
|
||||
this.exception = exc;
|
||||
commit();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @see eu.dnetlib.enabling.is.sn.NotificationInvocationLogger.Entry#success()
|
||||
*/
|
||||
@Override
|
||||
public void success() {
|
||||
status = Status.Succeeded;
|
||||
commit();
|
||||
}
|
||||
|
||||
/**
|
||||
* finalize log entry.
|
||||
*/
|
||||
protected void commit() {
|
||||
this.finish = new Date();
|
||||
}
|
||||
|
||||
@Override
|
||||
public NotificationMessage getMessage() {
|
||||
return message;
|
||||
}
|
||||
|
||||
public void setMessage(final NotificationMessage message) {
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Throwable getException() {
|
||||
return exception;
|
||||
}
|
||||
|
||||
public void setException(final Throwable exception) {
|
||||
this.exception = exception;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Status getStatus() {
|
||||
return status;
|
||||
}
|
||||
|
||||
public void setStatus(final Status status) {
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
public W3CEndpointReference getDestinationEpr() {
|
||||
return destinationEpr;
|
||||
}
|
||||
|
||||
public void setDestinationEpr(final W3CEndpointReference destinationEpr) {
|
||||
this.destinationEpr = destinationEpr;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDestination() {
|
||||
return EPRUtil.getAddress(destinationEpr);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @see eu.dnetlib.enabling.is.sn.NotificationInvocationLogger.Entry#getErrorMessage()
|
||||
*/
|
||||
@Override
|
||||
public String getErrorMessage() {
|
||||
if (getException() == null)
|
||||
return "";
|
||||
return getException().getMessage();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Date getStart() {
|
||||
return start;
|
||||
}
|
||||
|
||||
public void setStart(final Date start) {
|
||||
this.start = start;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Date getFinish() {
|
||||
return finish;
|
||||
}
|
||||
|
||||
public void setFinish(final Date finish) {
|
||||
this.finish = finish;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* @see eu.dnetlib.enabling.is.sn.NotificationInvocationLogger.Entry#getDuration()
|
||||
*/
|
||||
@Override
|
||||
public String getDuration() {
|
||||
if (finish == null || start == null)
|
||||
return "-";
|
||||
return (finish.getTime() - start.getTime()) + " ms";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* the actual log storage.
|
||||
*/
|
||||
private ConcurrentLinkedQueue<Entry> queue = new ConcurrentLinkedQueue<Entry>();
|
||||
|
||||
/**
|
||||
* max log size.
|
||||
*/
|
||||
private int size = DEFAULT_SIZE;
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @see eu.dnetlib.enabling.is.sn.NotificationInvocationLogger#startLogging(eu.dnetlib.enabling.is.sn.NotificationMessage)
|
||||
*/
|
||||
@Override
|
||||
public Entry startLogging(final W3CEndpointReference dest, final NotificationMessage message) {
|
||||
final Entry entry = createLoggingEntry(dest, message);
|
||||
queue.add(entry);
|
||||
ensureQueueLength();
|
||||
return entry;
|
||||
}
|
||||
|
||||
/**
|
||||
* ensure that the queue doesn't grow beyond size.
|
||||
*/
|
||||
private void ensureQueueLength() {
|
||||
if (queue.size() > size)
|
||||
queue.poll();
|
||||
}
|
||||
|
||||
/**
|
||||
* create a new memory log object.
|
||||
*
|
||||
* @param dest
|
||||
* destination
|
||||
*
|
||||
* @param message
|
||||
* message to be logged
|
||||
* @return new entry instance
|
||||
*/
|
||||
protected Entry createLoggingEntry(final W3CEndpointReference dest, final NotificationMessage message) {
|
||||
return new MemoryEntry(dest, message);
|
||||
}
|
||||
|
||||
public ConcurrentLinkedQueue<Entry> getQueue() {
|
||||
return queue;
|
||||
}
|
||||
|
||||
public void setQueue(final ConcurrentLinkedQueue<Entry> queue) {
|
||||
this.queue = queue;
|
||||
}
|
||||
|
||||
public int getSize() {
|
||||
return size;
|
||||
}
|
||||
|
||||
public void setSize(final int size) {
|
||||
this.size = size;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<Entry> getEntries() {
|
||||
return getQueue();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
package eu.dnetlib.enabling.is.sn;
|
||||
|
||||
|
||||
/**
|
||||
* Implementors of this interface are able to detect events which will trigger notifications.
|
||||
* @author marko
|
||||
*
|
||||
*/
|
||||
public interface NotificationDetector {
|
||||
|
||||
/**
|
||||
* injection point for NotificationSender.
|
||||
*
|
||||
* @param sender sender
|
||||
*/
|
||||
void setSender(NotificationSender sender);
|
||||
}
|
|
@ -0,0 +1,217 @@
|
|||
package eu.dnetlib.enabling.is.sn;
|
||||
|
||||
import java.io.StringWriter;
|
||||
import java.util.Collection;
|
||||
|
||||
import javax.xml.transform.Transformer;
|
||||
import javax.xml.transform.TransformerException;
|
||||
import javax.xml.transform.TransformerFactory;
|
||||
import javax.xml.transform.dom.DOMSource;
|
||||
import javax.xml.transform.stream.StreamResult;
|
||||
import javax.xml.xpath.XPath;
|
||||
import javax.xml.xpath.XPathConstants;
|
||||
import javax.xml.xpath.XPathExpressionException;
|
||||
import javax.xml.xpath.XPathFactory;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.w3c.dom.Node;
|
||||
|
||||
import eu.dnetlib.enabling.is.sn.resourcestate.ResourceStateNotificationDetector;
|
||||
import eu.dnetlib.enabling.is.sn.resourcestate.ResourceStateSubscription;
|
||||
import eu.dnetlib.enabling.is.sn.resourcestate.ResourceStateSubscriptionRegistry;
|
||||
import eu.dnetlib.enabling.tools.OpaqueResource;
|
||||
|
||||
/**
|
||||
* This notification detector uses a local xmldb trigger as a source of events.
|
||||
*
|
||||
* @author marko
|
||||
*
|
||||
*/
|
||||
public class NotificationDetectorImpl extends AbstractNotificationDetector implements ResourceStateNotificationDetector<OpaqueResource> {
|
||||
|
||||
/**
|
||||
* logger.
|
||||
*/
|
||||
private static final Log log = LogFactory.getLog(NotificationDetectorImpl.class); // NOPMD by marko on 11/24/08 5:02 PM
|
||||
|
||||
/**
|
||||
* subscription registries to lookup.
|
||||
*/
|
||||
private SubscriptionRegistry registry;
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @see eu.dnetlib.enabling.is.sn.resourcestate.ResourceStateNotificationDetector#resourceCreated(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public void resourceCreated(final OpaqueResource newResource) {
|
||||
log.debug("resource created: " + getRegistry());
|
||||
|
||||
final Collection<ResourceStateSubscription> subs =
|
||||
getRegistry().listMatchingSubscriptions(ResourceStateSubscription.PREFIX_CREATE, newResource.getResourceType(), newResource.getResourceId());
|
||||
for (ResourceStateSubscription sub : subs) {
|
||||
if (matchPath(newResource, sub.getXpath())) {
|
||||
send(sub, newResource, ResourceStateSubscription.PREFIX_CREATE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* helper method. sends a notification for a given prefix.
|
||||
*
|
||||
* @param sub
|
||||
* subscription
|
||||
* @param resource
|
||||
* resource
|
||||
* @param prefix
|
||||
* prefix
|
||||
*/
|
||||
private void send(final ResourceStateSubscription sub, final OpaqueResource resource, final String prefix) {
|
||||
log.debug("RESOURCE " + resource);
|
||||
log.debug("id: " + resource.getResourceId());
|
||||
log.debug("dom: " + resource.asDom());
|
||||
|
||||
final StringBuffer topicBuffer = new StringBuffer();
|
||||
|
||||
if (sub.getPrefix() == null && "*".equals(sub.getPrefix()))
|
||||
topicBuffer.append(prefix);
|
||||
else
|
||||
topicBuffer.append(sub.getPrefix());
|
||||
|
||||
topicBuffer.append('.');
|
||||
topicBuffer.append(sub.getType());
|
||||
topicBuffer.append('.');
|
||||
topicBuffer.append(sub.getResourceId());
|
||||
if (sub.getXpath() != null && !sub.getXpath().isEmpty()) {
|
||||
topicBuffer.append(sub.getXpath().replace('/', '.'));
|
||||
}
|
||||
|
||||
getSender().send(sub.getSubscriberAsEpr(), new NotificationMessage(sub.getSubscriptionId(), topicBuffer.toString(), resource.getResourceId(), // NOPMD
|
||||
resource.asString()));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @see eu.dnetlib.enabling.is.sn.resourcestate.ResourceStateNotificationDetector#resourceDeleted(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public void resourceDeleted(final OpaqueResource oldResource) {
|
||||
log.debug("resource deleted: " + getRegistry());
|
||||
|
||||
final Collection<ResourceStateSubscription> subs =
|
||||
registry.listMatchingSubscriptions(ResourceStateSubscription.PREFIX_DELETE, oldResource.getResourceType(), oldResource.getResourceId());
|
||||
for (ResourceStateSubscription sub : subs) {
|
||||
if (matchPath(oldResource, sub.getXpath())) {
|
||||
send(sub, oldResource, ResourceStateSubscription.PREFIX_DELETE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @see eu.dnetlib.enabling.is.sn.resourcestate.ResourceStateNotificationDetector#resourceUpdated(java.lang.Object,
|
||||
* java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public void resourceUpdated(final OpaqueResource oldResource, final OpaqueResource newResource) {
|
||||
log.debug("resource updated: " + getRegistry());
|
||||
|
||||
final Collection<ResourceStateSubscription> subs =
|
||||
registry.listMatchingSubscriptions(ResourceStateSubscription.PREFIX_UPDATE, oldResource.getResourceType(), oldResource.getResourceId());
|
||||
for (ResourceStateSubscription sub : subs) {
|
||||
if (comparePath(oldResource, newResource, sub.getXpath())) {
|
||||
log.debug("updated, sending: " + newResource.asString());
|
||||
send(sub, newResource, ResourceStateSubscription.PREFIX_UPDATE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* check if an xpath matches a given resource.
|
||||
*
|
||||
* @param resource
|
||||
* resource
|
||||
* @param xpath
|
||||
* xpath
|
||||
* @return true if the resource has some value for the given path
|
||||
*/
|
||||
private boolean matchPath(final OpaqueResource resource, final String xpath) {
|
||||
// by convention empty xpath matches any document
|
||||
if (xpath == null || xpath.isEmpty())
|
||||
return true;
|
||||
|
||||
final XPath xpa = XPathFactory.newInstance().newXPath();
|
||||
try {
|
||||
return !xpa.evaluate(xpath, resource.asDom()).isEmpty();
|
||||
} catch (XPathExpressionException e) {
|
||||
log.warn("wrong xpath expression, notification possibly missed", e);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* compare the content of two profiles for the same xpath. Return true if some change has been made so that the
|
||||
* notification can be delivered.
|
||||
*
|
||||
* @param oldResource
|
||||
* old version
|
||||
* @param newResource
|
||||
* new version
|
||||
* @param xpath
|
||||
* XPath
|
||||
* @return true if the two documents differ under a given path
|
||||
*/
|
||||
private boolean comparePath(final OpaqueResource oldResource, final OpaqueResource newResource, final String xpath) {
|
||||
// by convention empty xpath matches any document
|
||||
if (oldResource == null || newResource == null || xpath == null || xpath.isEmpty())
|
||||
return true;
|
||||
|
||||
final XPath xpa = XPathFactory.newInstance().newXPath();
|
||||
try {
|
||||
final Transformer transformer = TransformerFactory.newInstance().newTransformer();
|
||||
|
||||
final Node left = (Node) xpa.evaluate(xpath, oldResource.asDom(), XPathConstants.NODE);
|
||||
final Node right = (Node) xpa.evaluate(xpath, newResource.asDom(), XPathConstants.NODE);
|
||||
|
||||
if (left==null || right==null) {
|
||||
if (left != null) {
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
if (right != null) {
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final StringWriter leftWriter = new StringWriter();
|
||||
final StringWriter rightWriter = new StringWriter();
|
||||
|
||||
transformer.transform(new DOMSource(left), new StreamResult(leftWriter));
|
||||
transformer.transform(new DOMSource(right), new StreamResult(rightWriter));
|
||||
|
||||
return !leftWriter.toString().equals(rightWriter.toString());
|
||||
} catch (XPathExpressionException e) {
|
||||
log.warn("wrong xpath expression, notification possibly missed", e);
|
||||
} catch (TransformerException e) {
|
||||
log.warn("serialization problem", e);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public SubscriptionRegistry getRegistry() {
|
||||
return registry;
|
||||
}
|
||||
|
||||
public void setRegistry(final SubscriptionRegistry registry) {
|
||||
this.registry = registry;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,142 @@
|
|||
package eu.dnetlib.enabling.is.sn;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Date;
|
||||
|
||||
import javax.xml.ws.wsaddressing.W3CEndpointReference;
|
||||
|
||||
/**
|
||||
* A notification logger maintains a log of sent notifications, and their status (succes or failure with exception etc).
|
||||
*
|
||||
* @author marko
|
||||
*
|
||||
*/
|
||||
public interface NotificationInvocationLogger {
|
||||
|
||||
/**
|
||||
* A log entry. Used to create log entries in two phases. First a log entry is created with "startLogging" and after
|
||||
* the notification is sent the log entry is committed with success() of failure().
|
||||
*
|
||||
* @author marko
|
||||
*
|
||||
*/
|
||||
interface Entry {
|
||||
/**
|
||||
* log entry status.
|
||||
*
|
||||
* @author marko
|
||||
*
|
||||
*/
|
||||
enum Status {
|
||||
/**
|
||||
* notification is queued but not started to be sent.
|
||||
*/
|
||||
Queued,
|
||||
/**
|
||||
* notification is ongoing.
|
||||
*/
|
||||
Ongoing,
|
||||
/**
|
||||
* notification succeeded.
|
||||
*/
|
||||
Succeeded,
|
||||
/**
|
||||
* notification failed.
|
||||
*/
|
||||
Failed
|
||||
};
|
||||
|
||||
/**
|
||||
* sets the status to ongoing.
|
||||
*/
|
||||
void ongoing();
|
||||
|
||||
/**
|
||||
* commits the log entry tagging it as succeeded.
|
||||
*/
|
||||
void success();
|
||||
|
||||
/**
|
||||
* commits the log entry tagging it as failed.
|
||||
*
|
||||
* @param exception
|
||||
* throwable, cause of failure
|
||||
*/
|
||||
void failure(Throwable exception);
|
||||
|
||||
/**
|
||||
* get start date time.
|
||||
*
|
||||
* @return date
|
||||
*/
|
||||
Date getStart();
|
||||
|
||||
/**
|
||||
* get finish date time.
|
||||
*
|
||||
* @return date
|
||||
*/
|
||||
Date getFinish();
|
||||
|
||||
/**
|
||||
* get log status.
|
||||
*
|
||||
* @return log status
|
||||
*/
|
||||
Status getStatus();
|
||||
|
||||
/**
|
||||
* get log message.
|
||||
*
|
||||
* @return log message
|
||||
*/
|
||||
NotificationMessage getMessage();
|
||||
|
||||
/**
|
||||
* get destination.
|
||||
*
|
||||
* @return destination url
|
||||
*/
|
||||
String getDestination();
|
||||
|
||||
/**
|
||||
* get exception.
|
||||
*
|
||||
* @return exception
|
||||
*/
|
||||
Throwable getException();
|
||||
|
||||
/**
|
||||
* Get exception error message or empty string if succeded.
|
||||
*
|
||||
* @return error message
|
||||
*/
|
||||
String getErrorMessage();
|
||||
|
||||
/**
|
||||
* Human readable duration.
|
||||
*
|
||||
* @return human readable duration
|
||||
*/
|
||||
String getDuration();
|
||||
}
|
||||
|
||||
/**
|
||||
* Start logging a notification invocation.
|
||||
*
|
||||
* @param destination
|
||||
* destination
|
||||
* @param message
|
||||
* message to be logged.
|
||||
* @return an entry object which has to be committed.
|
||||
*
|
||||
*/
|
||||
Entry startLogging(W3CEndpointReference destination, NotificationMessage message);
|
||||
|
||||
/**
|
||||
* get all entries.
|
||||
*
|
||||
* @return all entries
|
||||
*/
|
||||
Collection<Entry> getEntries();
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
package eu.dnetlib.enabling.is.sn;
|
||||
|
||||
import javax.xml.ws.wsaddressing.W3CEndpointReference;
|
||||
|
||||
/**
|
||||
* Implementors of this interface decouple the notification producing and dispatching policies
|
||||
* with the actually on-wire sending of the notification message.
|
||||
*
|
||||
* <p>
|
||||
* Notification invokers expose a fairly low level interface to notification dispatchers, so that
|
||||
* dispatching policies can configure various aspects of the underlying transport.
|
||||
* </p>
|
||||
*
|
||||
* @author marko
|
||||
*
|
||||
*/
|
||||
public interface NotificationInvoker {
|
||||
/**
|
||||
* for now only timeout is exposed.
|
||||
*
|
||||
* @param destination destination EPR
|
||||
* @param message message
|
||||
* @param timeout timeout in seconds
|
||||
*/
|
||||
void send(W3CEndpointReference destination, NotificationMessage message, int timeout);
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
package eu.dnetlib.enabling.is.sn;
|
||||
|
||||
import javax.xml.ws.WebServiceFeature;
|
||||
import javax.xml.ws.wsaddressing.W3CEndpointReference;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.beans.factory.annotation.Required;
|
||||
|
||||
import eu.dnetlib.common.rmi.BaseService;
|
||||
|
||||
/**
|
||||
* This is a basic notification invoker which calls dnet1.0 compatible notify() methods.
|
||||
*
|
||||
* @author marko
|
||||
*
|
||||
*/
|
||||
public class NotificationInvokerImpl implements NotificationInvoker {
|
||||
/**
|
||||
* logger.
|
||||
*/
|
||||
private static final Log log = LogFactory.getLog(NotificationInvokerImpl.class); // NOPMD by marko on 11/24/08 5:02 PM
|
||||
|
||||
/**
|
||||
* invocation logger.
|
||||
*/
|
||||
private NotificationInvocationLogger invocationLogger;
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @see eu.dnetlib.enabling.is.sn.NotificationInvoker#send(javax.xml.ws.wsaddressing.W3CEndpointReference,
|
||||
* eu.dnetlib.enabling.is.sn.NotificationMessage, int)
|
||||
*/
|
||||
@Override
|
||||
public void send(final W3CEndpointReference destination, final NotificationMessage message, final int timeout) {
|
||||
final BaseService service = destination.getPort(BaseService.class, new WebServiceFeature[] {});
|
||||
log.info("phisically sending notification: " + message.getTopic());
|
||||
|
||||
final NotificationInvocationLogger.Entry logEntry = invocationLogger.startLogging(destination, message);
|
||||
logEntry.ongoing();
|
||||
|
||||
try {
|
||||
service.notify(message.getSubscriptionId(), message.getTopic(), message.getResourceId(), message.getBody());
|
||||
logEntry.success();
|
||||
} catch (final Throwable e) { // NOPMD
|
||||
log.debug("notification error", e);
|
||||
logEntry.failure(e);
|
||||
}
|
||||
}
|
||||
|
||||
public NotificationInvocationLogger getInvocationLogger() {
|
||||
return invocationLogger;
|
||||
}
|
||||
|
||||
@Required
|
||||
public void setInvocationLogger(final NotificationInvocationLogger invocationLogger) {
|
||||
this.invocationLogger = invocationLogger;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,85 @@
|
|||
package eu.dnetlib.enabling.is.sn;
|
||||
|
||||
/**
|
||||
* This class encapsulates the notification message sent to ISSN subscribers.
|
||||
*
|
||||
* @author marko
|
||||
*
|
||||
*/
|
||||
public class NotificationMessage {
|
||||
|
||||
/**
|
||||
* subscription identifier.
|
||||
*/
|
||||
private String subscriptionId;
|
||||
|
||||
/**
|
||||
* subscription topic that triggered the notification.
|
||||
*/
|
||||
private String topic;
|
||||
|
||||
/**
|
||||
* resource identifier that triggered the notification.
|
||||
*/
|
||||
private String resourceId;
|
||||
|
||||
/**
|
||||
* message body.
|
||||
*/
|
||||
private String body;
|
||||
|
||||
/**
|
||||
* default constructor.
|
||||
*/
|
||||
public NotificationMessage() {
|
||||
// no operation
|
||||
}
|
||||
|
||||
/**
|
||||
* constructor with full parameters.
|
||||
*
|
||||
* @param subscriptionId subscription identifier
|
||||
* @param topic produced topic
|
||||
* @param resourceId resource identifier of the resource which triggered the notification, or null
|
||||
* @param body body of the document which triggered the notification, or null
|
||||
*/
|
||||
public NotificationMessage(final String subscriptionId, final String topic, final String resourceId, final String body) {
|
||||
super();
|
||||
this.subscriptionId = subscriptionId;
|
||||
this.topic = topic;
|
||||
this.resourceId = resourceId;
|
||||
this.body = body;
|
||||
}
|
||||
|
||||
public String getSubscriptionId() {
|
||||
return subscriptionId;
|
||||
}
|
||||
|
||||
public void setSubscriptionId(final String subscriptionId) {
|
||||
this.subscriptionId = subscriptionId;
|
||||
}
|
||||
|
||||
public String getTopic() {
|
||||
return topic;
|
||||
}
|
||||
|
||||
public void setTopic(final String topic) {
|
||||
this.topic = topic;
|
||||
}
|
||||
|
||||
public String getResourceId() {
|
||||
return resourceId;
|
||||
}
|
||||
|
||||
public void setResourceId(final String resourceId) {
|
||||
this.resourceId = resourceId;
|
||||
}
|
||||
|
||||
public String getBody() {
|
||||
return body;
|
||||
}
|
||||
|
||||
public void setBody(final String body) {
|
||||
this.body = body;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
package eu.dnetlib.enabling.is.sn;
|
||||
|
||||
import javax.xml.ws.wsaddressing.W3CEndpointReference;
|
||||
|
||||
/**
|
||||
* Instances implementing this interfaces will send notifications to consumers.
|
||||
*
|
||||
* <p>
|
||||
* Notifications will be already detected and the message body will be already computed.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* There will be different NotificationSenders, depending on the performance and reliability characteristics required by
|
||||
* the message type.
|
||||
* <p>
|
||||
*
|
||||
* <p>Each notification sender will use a NotificationInvoker to actually forward the notification</p>
|
||||
*
|
||||
* @author marko
|
||||
* @see eu.dnetlib.enabling.is.sn.NotificationInvoker
|
||||
*/
|
||||
public interface NotificationSender {
|
||||
/**
|
||||
* sends a given message according to specific policies.
|
||||
*
|
||||
* @param destination destination EPR
|
||||
* @param message message
|
||||
*/
|
||||
void send(W3CEndpointReference destination, NotificationMessage message);
|
||||
|
||||
/**
|
||||
* Sets the notification invoker which will actually perform the notification delivery.
|
||||
*
|
||||
* @param invoker notification invoker
|
||||
*/
|
||||
void setInvoker(NotificationInvoker invoker);
|
||||
}
|
|
@ -0,0 +1,80 @@
|
|||
package eu.dnetlib.enabling.is.sn;
|
||||
|
||||
import javax.xml.xpath.XPathExpressionException;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.w3c.dom.Document;
|
||||
|
||||
import eu.dnetlib.enabling.is.sn.resourcestate.ResourceStateNotificationDetector;
|
||||
import eu.dnetlib.enabling.tools.DOMOpaqueResource;
|
||||
import eu.dnetlib.enabling.tools.OpaqueResource;
|
||||
import eu.dnetlib.xml.database.LoggingTrigger;
|
||||
|
||||
/**
|
||||
* This trigger generates notification events for the subscription notification layer.
|
||||
*
|
||||
* @author marko
|
||||
*
|
||||
*/
|
||||
public class NotificationTriggerImpl extends LoggingTrigger {
|
||||
/**
|
||||
* logger.
|
||||
*/
|
||||
private static final Log log = LogFactory.getLog(NotificationTriggerImpl.class); // NOPMD by marko on 11/24/08 5:02 PM
|
||||
|
||||
/**
|
||||
* notification detector to notify on events.
|
||||
*/
|
||||
private ResourceStateNotificationDetector<OpaqueResource> detector;
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* @see eu.dnetlib.xml.database.LoggingTrigger#created(java.lang.String, java.lang.String, org.w3c.dom.Document)
|
||||
*/
|
||||
@Override
|
||||
public void created(final String file, final String collection, final Document newDoc) {
|
||||
super.created(file, collection, newDoc);
|
||||
try {
|
||||
getDetector().resourceCreated(new DOMOpaqueResource(newDoc));
|
||||
} catch (XPathExpressionException e) {
|
||||
log.fatal("cannot detect notification because of xpath error; notification possibly missed", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* @see eu.dnetlib.xml.database.LoggingTrigger#deleted(java.lang.String, java.lang.String, org.w3c.dom.Document)
|
||||
*/
|
||||
@Override
|
||||
public void deleted(final String file, final String collection, final Document oldDoc) {
|
||||
super.deleted(file, collection, oldDoc);
|
||||
try {
|
||||
getDetector().resourceDeleted(new DOMOpaqueResource(oldDoc));
|
||||
} catch (XPathExpressionException e) {
|
||||
log.fatal("cannot detect notification because of xpath error; notification possibly missed", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* @see eu.dnetlib.xml.database.LoggingTrigger#updated(java.lang.String, java.lang.String, org.w3c.dom.Document, org.w3c.dom.Document)
|
||||
*/
|
||||
@Override
|
||||
public void updated(final String file, final String collection, final Document oldDoc, final Document newDoc) {
|
||||
super.updated(file, collection, oldDoc, newDoc);
|
||||
try {
|
||||
getDetector().resourceUpdated(new DOMOpaqueResource(oldDoc), new DOMOpaqueResource(newDoc));
|
||||
} catch (XPathExpressionException e) {
|
||||
log.fatal("cannot detect notification because of xpath error; notification possibly missed", e);
|
||||
}
|
||||
}
|
||||
|
||||
public ResourceStateNotificationDetector<OpaqueResource> getDetector() {
|
||||
return detector;
|
||||
}
|
||||
|
||||
public void setDetector(final ResourceStateNotificationDetector<OpaqueResource> detector) {
|
||||
this.detector = detector;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
package eu.dnetlib.enabling.is.sn;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* Stores subscriptions.
|
||||
*
|
||||
* @author marko
|
||||
*
|
||||
* @param <T>
|
||||
* subscription type
|
||||
*/
|
||||
public interface SubscriptionDAO<T> {
|
||||
/**
|
||||
* add a new subscription to the subscription store.
|
||||
*
|
||||
* TODO: throw some exception on already existing subscription
|
||||
*
|
||||
* @param subscription
|
||||
* subscription
|
||||
*/
|
||||
void addSubscription(T subscription);
|
||||
|
||||
/**
|
||||
* get a particular subscription.
|
||||
*
|
||||
* @param subscriptionId identifier
|
||||
* @return null if none
|
||||
*/
|
||||
T getSubscription(String subscriptionId);
|
||||
|
||||
|
||||
/**
|
||||
* lists all subscriptions.
|
||||
*
|
||||
* @return all subscriptions
|
||||
*/
|
||||
Collection<T> listSubscriptions();
|
||||
|
||||
/**
|
||||
* lists all subscriptions for a given prefix.
|
||||
*
|
||||
* @param prefix topic expression prefix
|
||||
* @return all matching subscriptions
|
||||
*/
|
||||
Collection<T> listSubscriptions(String prefix);
|
||||
|
||||
/**
|
||||
* removes a particular subscription.
|
||||
*
|
||||
* @param subscriptionId identifier
|
||||
* @return true if successful
|
||||
*/
|
||||
boolean removeSubscription(String subscriptionId);
|
||||
|
||||
}
|
|
@ -0,0 +1,84 @@
|
|||
package eu.dnetlib.enabling.is.sn;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import eu.dnetlib.enabling.is.sn.resourcestate.ResourceStateSubscription;
|
||||
import eu.dnetlib.enabling.is.sn.rmi.SubscriptionRequestRejectedException;
|
||||
import org.springframework.cache.annotation.CacheEvict;
|
||||
import org.springframework.cache.annotation.Cacheable;
|
||||
|
||||
/**
|
||||
* A subscription registry stores subscriptions.
|
||||
*
|
||||
* <p>
|
||||
* Different subscription registries know how to to store different kind of subscriptions. Each registry is specialized
|
||||
* in one type of subscriptions and knows how to quickly find all potentially interesting subscriptions so that a
|
||||
* particular NotificationDetector can do his job the quickest way possible.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* This interface is generic only for subscription purposes because the Subscriber component simply tries to register a
|
||||
* new subscription to all available subscription registries.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* Normally a subscription registry manages only a set of topic expression prefixes, but this interface doesn't force
|
||||
* the Subscriber to know this information; instead the subscription registry itself will decide whether to accept the
|
||||
* subscription or not.
|
||||
* </p>
|
||||
* <p>
|
||||
* Since many subscription registries may accept the same subscription, the identifier is preallocated by the
|
||||
* Subscriber, since the subscription is only one, and even if we give the possibility for several detectors to detect
|
||||
* it from different sources only one event will be generated.
|
||||
* </p>
|
||||
*
|
||||
* @author marko
|
||||
*
|
||||
*/
|
||||
public interface SubscriptionRegistry {
|
||||
|
||||
/**
|
||||
* register a subscription.
|
||||
*
|
||||
* @param subscription
|
||||
* subscription request
|
||||
* @return if we can accept this subcription we return the (possibly changed) identifier, otherwise null
|
||||
*/
|
||||
String registerSubscription(SubscriptionRequest subscription) throws SubscriptionRequestRejectedException;
|
||||
|
||||
/**
|
||||
* Unsubscribe a subscription if it exists.
|
||||
*
|
||||
* @param subId subscription identifier
|
||||
* @return true if this subscription existed and was successfully removed
|
||||
*/
|
||||
boolean unsubscribe(final String subId);
|
||||
|
||||
/**
|
||||
* return all subscriptions matching a given prefix and a given type. Wildcard subscriptions will match any resource type.
|
||||
*
|
||||
* @param prefix
|
||||
* prefix
|
||||
* @param type
|
||||
* concrete type
|
||||
* @param resId
|
||||
* resource identifier
|
||||
* @return all matching subscriptions
|
||||
*/
|
||||
Collection<ResourceStateSubscription> listMatchingSubscriptions(final String prefix, final String type, final String resId);
|
||||
|
||||
/**
|
||||
* return all subscriptions.
|
||||
*
|
||||
* @return all subscriptions
|
||||
*/
|
||||
Collection<ResourceStateSubscription> listSubscriptions();
|
||||
|
||||
/**
|
||||
* removes a particular subscription.
|
||||
*
|
||||
* @param subscriptionId identifier
|
||||
* @return true if successful
|
||||
*/
|
||||
boolean removeSubscription(String subscriptionId);
|
||||
}
|
|
@ -0,0 +1,88 @@
|
|||
package eu.dnetlib.enabling.is.sn;
|
||||
|
||||
import javax.xml.ws.wsaddressing.W3CEndpointReference;
|
||||
|
||||
/**
|
||||
* A SubscriptionRequest encapsulates various information about a subscription request.
|
||||
*
|
||||
* @author marko
|
||||
*
|
||||
*/
|
||||
public class SubscriptionRequest {
|
||||
|
||||
/**
|
||||
* subscriber.
|
||||
*/
|
||||
private W3CEndpointReference subscriber;
|
||||
|
||||
/**
|
||||
* topic expression.
|
||||
*/
|
||||
private String topicExpression;
|
||||
|
||||
/**
|
||||
* Preallocated subscription Id. If registries accept the subscription, they will store this in the subscription
|
||||
* identifier.
|
||||
*/
|
||||
private String subscriptionId;
|
||||
|
||||
/**
|
||||
* time to live.
|
||||
*/
|
||||
private int ttl;
|
||||
|
||||
/**
|
||||
* default constructor.
|
||||
*/
|
||||
public SubscriptionRequest() {
|
||||
// no operation
|
||||
}
|
||||
|
||||
/**
|
||||
* construct with fields.
|
||||
*
|
||||
* @param subscriptionId subscription id
|
||||
* @param subscriber subscriber
|
||||
* @param topicExpression topic expression
|
||||
* @param ttl time to live
|
||||
*/
|
||||
public SubscriptionRequest(final String subscriptionId, final W3CEndpointReference subscriber, final String topicExpression, final int ttl) {
|
||||
super();
|
||||
this.subscriptionId = subscriptionId;
|
||||
this.subscriber = subscriber;
|
||||
this.topicExpression = topicExpression;
|
||||
this.ttl = ttl;
|
||||
}
|
||||
|
||||
public W3CEndpointReference getSubscriber() {
|
||||
return subscriber;
|
||||
}
|
||||
|
||||
public void setSubscriber(final W3CEndpointReference subscriber) {
|
||||
this.subscriber = subscriber;
|
||||
}
|
||||
|
||||
public String getTopicExpression() {
|
||||
return topicExpression;
|
||||
}
|
||||
|
||||
public void setTopicExpression(final String topicExpression) {
|
||||
this.topicExpression = topicExpression;
|
||||
}
|
||||
|
||||
public String getSubscriptionId() {
|
||||
return subscriptionId;
|
||||
}
|
||||
|
||||
public void setSubscriptionId(final String subscriptionId) {
|
||||
this.subscriptionId = subscriptionId;
|
||||
}
|
||||
|
||||
public int getTtl() {
|
||||
return ttl;
|
||||
}
|
||||
|
||||
public void setTtl(final int ttl) {
|
||||
this.ttl = ttl;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
package eu.dnetlib.enabling.is.sn;
|
||||
|
||||
import javax.xml.ws.wsaddressing.W3CEndpointReference;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
/**
|
||||
* This implementation of NotificationSender simply sends notification synchronously.
|
||||
*
|
||||
* NOTE: this is only for testing. Real-wold cases should use AsynchrnonousNotificationSender, because we have to
|
||||
* get out the thread serving eXist queries.
|
||||
*
|
||||
* @author marko
|
||||
*
|
||||
*/
|
||||
public class SynchronousNotificationSenderImpl extends AbstractNotificationSender {
|
||||
|
||||
/**
|
||||
* logger.
|
||||
*/
|
||||
private static final Log log = LogFactory.getLog(SynchronousNotificationSenderImpl.class); // NOPMD by marko on 11/24/08 5:02 PM
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @see eu.dnetlib.enabling.is.sn.NotificationSender#send(javax.xml.ws.wsaddressing.W3CEndpointReference,
|
||||
* eu.dnetlib.enabling.is.sn.NotificationMessage)
|
||||
*/
|
||||
@Override
|
||||
public void send(final W3CEndpointReference destination, final NotificationMessage message) {
|
||||
log.info("synchronously sending message " + message.getSubscriptionId() + ", " + message.getTopic() + ", " + message.getResourceId() + ", "
|
||||
+ message.getBody());
|
||||
try {
|
||||
getInvoker().send(destination, message, 0);
|
||||
} catch (javax.xml.ws.soap.SOAPFaultException t) {
|
||||
log.fatal("error sending notification to " + destination.toString(), t);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
package eu.dnetlib.enabling.is.sn;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import eu.dnetlib.enabling.is.sn.rmi.ISSNException;
|
||||
|
||||
/**
|
||||
* As a complementary approach w.r.t unit tests, this class is an extension of
|
||||
* the default ISSN Service which creates a number of initial subscriptions so that we can play
|
||||
* with some notifications.
|
||||
*
|
||||
* This class plays well with TestISStoreServiceImpl, which creates some profiles at startup time
|
||||
* and schedules some automated mutations.
|
||||
*
|
||||
* @author marko
|
||||
*
|
||||
*/
|
||||
public class TestISSNServiceImpl extends ISSNServiceImpl {
|
||||
/**
|
||||
* logger.
|
||||
*/
|
||||
private static final Log log = LogFactory.getLog(TestISSNServiceImpl.class); // NOPMD by marko on 11/24/08 5:02 PM
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* @see eu.dnetlib.enabling.tools.AbstractBaseService#start()
|
||||
*/
|
||||
@Override
|
||||
public void start() {
|
||||
super.start();
|
||||
|
||||
try {
|
||||
subscribe(getEprBuilder().getEndpointReference(getEndpoint()), "CREATE/TestResourceType/*", 0);
|
||||
} catch (ISSNException e) {
|
||||
log.fatal("cannot subscribe test subscriptions", e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
package eu.dnetlib.enabling.is.sn;
|
||||
|
||||
/**
|
||||
* Groups a topic expression prefix match result.
|
||||
*
|
||||
* <p>
|
||||
* Utility class.
|
||||
* </p>
|
||||
*
|
||||
* @author marko
|
||||
*
|
||||
*/
|
||||
public class TopicExpressionMatchResult {
|
||||
/**
|
||||
* Topic expression prefix.
|
||||
*/
|
||||
private final transient String prefix;
|
||||
|
||||
/**
|
||||
* RestOf the topic expression.
|
||||
*/
|
||||
private final transient String rest;
|
||||
|
||||
/**
|
||||
* construct a new topic expression prefix match result.
|
||||
* @param prefix
|
||||
* prefix
|
||||
* @param rest
|
||||
* rest
|
||||
*/
|
||||
public TopicExpressionMatchResult(final String prefix, final String rest) {
|
||||
super();
|
||||
this.prefix = prefix;
|
||||
this.rest = rest;
|
||||
}
|
||||
|
||||
public String getPrefix() {
|
||||
return prefix;
|
||||
}
|
||||
|
||||
public String getRest() {
|
||||
return rest;
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,83 @@
|
|||
package eu.dnetlib.enabling.is.sn.resourcestate;
|
||||
|
||||
import eu.dnetlib.enabling.is.sn.NotificationSender;
|
||||
|
||||
/**
|
||||
* sits on top of a ResourceStateNotificationDetector and filters out resources for which we don't want to generate
|
||||
* notifications.
|
||||
*
|
||||
* @author marko
|
||||
*
|
||||
* @param <T>
|
||||
* type of the resource object
|
||||
*/
|
||||
public abstract class AbstractResourceStateNotificationDetectorFilter<T> implements ResourceStateNotificationDetector<T> {
|
||||
|
||||
/**
|
||||
* delegate.
|
||||
*/
|
||||
private ResourceStateNotificationDetector<T> delegate;
|
||||
|
||||
/**
|
||||
* implement this in order to decide which resources are interesting for notifications, and which are not (for
|
||||
* example pending resources are by ignored in dnet 1.0).
|
||||
*
|
||||
* @param resource
|
||||
* resource
|
||||
* @return true if the resource is potentially accepted for notification
|
||||
*/
|
||||
abstract boolean accept(T resource);
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @see eu.dnetlib.enabling.is.sn.resourcestate.ResourceStateNotificationDetector#resourceCreated(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public void resourceCreated(final T newResource) {
|
||||
if (accept(newResource))
|
||||
delegate.resourceCreated(newResource);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @see eu.dnetlib.enabling.is.sn.resourcestate.ResourceStateNotificationDetector#resourceDeleted(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public void resourceDeleted(final T oldResource) {
|
||||
if (accept(oldResource))
|
||||
delegate.resourceDeleted(oldResource);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @see eu.dnetlib.enabling.is.sn.resourcestate.ResourceStateNotificationDetector#resourceUpdated(java.lang.Object,
|
||||
* java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public void resourceUpdated(final T oldResource, final T newResource) {
|
||||
if (accept(oldResource) || accept(newResource))
|
||||
delegate.resourceUpdated(oldResource, newResource);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @see eu.dnetlib.enabling.is.sn.NotificationDetector#setSender(eu.dnetlib.enabling.is.sn.NotificationSender)
|
||||
*/
|
||||
@Override
|
||||
public void setSender(final NotificationSender sender) {
|
||||
delegate.setSender(sender);
|
||||
}
|
||||
|
||||
public ResourceStateNotificationDetector<T> getDelegate() {
|
||||
return delegate;
|
||||
}
|
||||
|
||||
public void setDelegate(final ResourceStateNotificationDetector<T> delegate) {
|
||||
this.delegate = delegate;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
package eu.dnetlib.enabling.is.sn.resourcestate;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Required;
|
||||
|
||||
import eu.dnetlib.enabling.tools.OpaqueResource;
|
||||
import eu.dnetlib.miscutils.coupling.ExternalCondition;
|
||||
|
||||
/**
|
||||
* Ignores pending profiles from notification detection.
|
||||
*
|
||||
* @author marko
|
||||
*
|
||||
*/
|
||||
public class ConditionalResourceStateNotificationDetectorFilter extends AbstractResourceStateNotificationDetectorFilter<OpaqueResource> {
|
||||
|
||||
/**
|
||||
* external condition that drives this filter. We accept notification while the external condition is false.
|
||||
*/
|
||||
private ExternalCondition inhibitionCondition; // NOPMD
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* @see eu.dnetlib.enabling.is.sn.resourcestate.AbstractResourceStateNotificationDetectorFilter#accept(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
boolean accept(final OpaqueResource resource) {
|
||||
return !inhibitionCondition.isTrue();
|
||||
}
|
||||
|
||||
public ExternalCondition getInhibitionCondition() {
|
||||
return inhibitionCondition;
|
||||
}
|
||||
|
||||
@Required
|
||||
public void setInhibitionCondition(final ExternalCondition inhibitionCondition) { // NOPMD
|
||||
this.inhibitionCondition = inhibitionCondition;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,132 @@
|
|||
package eu.dnetlib.enabling.is.sn.resourcestate;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
*
|
||||
* dummy implementation of the resource state subscription DAO layer, using an in-memory map.
|
||||
*
|
||||
* @author marko
|
||||
*
|
||||
*/
|
||||
public class MemoryResourceStateSubscriptionDAOImpl implements ResourceStateSubscriptionDAO {
|
||||
|
||||
/**
|
||||
* by id.
|
||||
*/
|
||||
private Map<String, ResourceStateSubscription> byId = new HashMap<String, ResourceStateSubscription>();
|
||||
|
||||
/**
|
||||
* groups subscriptions with the same prefix and type.
|
||||
*/
|
||||
private Map<String, Collection<ResourceStateSubscription>> byPrefixAndType = new HashMap<String, Collection<ResourceStateSubscription>>();
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @see eu.dnetlib.enabling.is.sn.resourcestate.ResourceStateSubscriptionDAO#listSubscriptions(java.lang.String,
|
||||
* java.lang.String, java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public Collection<ResourceStateSubscription> listSubscriptions(final String prefix, final String resourceType, final String resourceId) {
|
||||
return orDefault(getByPrefixAndType().get(prefix + "/" + resourceType + "/" + resourceId));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @see eu.dnetlib.enabling.is.sn.SubscriptionDAO#addSubscription(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public void addSubscription(final ResourceStateSubscription subscription) {
|
||||
getById().put(subscription.getSubscriptionId(), subscription);
|
||||
|
||||
final String key = subscription.getPrefix() + "/" + subscription.getType() + "/" + subscription.getResourceId();
|
||||
final Collection<ResourceStateSubscription> prefTypeList = getByPrefixAndType().get(key);
|
||||
if (prefTypeList == null)
|
||||
getByPrefixAndType().put(key, new ArrayList<ResourceStateSubscription>());
|
||||
getByPrefixAndType().get(key).add(subscription);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @see eu.dnetlib.enabling.is.sn.SubscriptionDAO#getSubscription(java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public ResourceStateSubscription getSubscription(final String subscriptionId) {
|
||||
return getById().get(subscriptionId);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @see eu.dnetlib.enabling.is.sn.SubscriptionDAO#listSubscriptions()
|
||||
*/
|
||||
@Override
|
||||
public Collection<ResourceStateSubscription> listSubscriptions() {
|
||||
return orDefault(getById().values());
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @see eu.dnetlib.enabling.is.sn.SubscriptionDAO#listSubscriptions(java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public Collection<ResourceStateSubscription> listSubscriptions(final String prefix) {
|
||||
return listSubscriptions(prefix, "*", "*");
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @see eu.dnetlib.enabling.is.sn.SubscriptionDAO#removeSubscription(java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public boolean removeSubscription(final String subscriptionId) {
|
||||
final ResourceStateSubscription subscription = getSubscription(subscriptionId);
|
||||
if (subscription == null)
|
||||
return false;
|
||||
final String key = subscription.getPrefix() + "/" + subscription.getType() + "/" + subscription.getResourceId();
|
||||
|
||||
final Collection<ResourceStateSubscription> prefTypeList = getByPrefixAndType().get(key);
|
||||
prefTypeList.remove(subscription);
|
||||
|
||||
getById().remove(subscriptionId);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* inner helper method. returns an empty collection instead of a null.
|
||||
*
|
||||
* @param collection
|
||||
* some collection
|
||||
* @return input collection or empty collection
|
||||
*/
|
||||
private Collection<ResourceStateSubscription> orDefault(final Collection<ResourceStateSubscription> collection) {
|
||||
if (collection == null)
|
||||
return new ArrayList<ResourceStateSubscription>();
|
||||
return collection;
|
||||
}
|
||||
|
||||
public Map<String, ResourceStateSubscription> getById() {
|
||||
return byId;
|
||||
}
|
||||
|
||||
public void setById(final Map<String, ResourceStateSubscription> byId) {
|
||||
this.byId = byId;
|
||||
}
|
||||
|
||||
public Map<String, Collection<ResourceStateSubscription>> getByPrefixAndType() {
|
||||
return byPrefixAndType;
|
||||
}
|
||||
|
||||
public void setByPrefixAndType(final Map<String, Collection<ResourceStateSubscription>> byPrefixAndType) {
|
||||
this.byPrefixAndType = byPrefixAndType;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
package eu.dnetlib.enabling.is.sn.resourcestate;
|
||||
|
||||
import eu.dnetlib.enabling.tools.OpaqueResource;
|
||||
|
||||
/**
|
||||
* Ignores pending profiles from notification detection.
|
||||
*
|
||||
* @author marko
|
||||
*
|
||||
*/
|
||||
public class PendingResourceStateNotificationDetectorFilter extends AbstractResourceStateNotificationDetectorFilter<OpaqueResource> {
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* @see eu.dnetlib.enabling.is.sn.resourcestate.AbstractResourceStateNotificationDetectorFilter#accept(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
boolean accept(final OpaqueResource resource) {
|
||||
if (resource.getResourceKind().startsWith("Pending"))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
package eu.dnetlib.enabling.is.sn.resourcestate;
|
||||
|
||||
import eu.dnetlib.enabling.is.sn.NotificationDetector;
|
||||
|
||||
/**
|
||||
* Implementors detect topic assertions by sensing changes in resource state.
|
||||
*
|
||||
* @author marko
|
||||
* @param <T>
|
||||
* type of resource
|
||||
*/
|
||||
public interface ResourceStateNotificationDetector<T> extends NotificationDetector {
|
||||
/**
|
||||
* called when a new resource is created.
|
||||
*
|
||||
* @param newResource
|
||||
* new resource
|
||||
*/
|
||||
void resourceCreated(T newResource);
|
||||
|
||||
/**
|
||||
* called when a resource is modified.
|
||||
*
|
||||
* @param oldResource
|
||||
* old resource
|
||||
* @param newResource
|
||||
* new resource
|
||||
*/
|
||||
void resourceUpdated(T oldResource, T newResource);
|
||||
|
||||
/**
|
||||
* called when a resource is deleted.
|
||||
*
|
||||
* @param oldResource
|
||||
* old resource
|
||||
*/
|
||||
void resourceDeleted(T oldResource);
|
||||
|
||||
}
|
|
@ -0,0 +1,225 @@
|
|||
package eu.dnetlib.enabling.is.sn.resourcestate;
|
||||
|
||||
import java.io.StringReader;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.Table;
|
||||
import javax.xml.transform.stream.StreamSource;
|
||||
import javax.xml.ws.EndpointReference;
|
||||
import javax.xml.ws.wsaddressing.W3CEndpointReference;
|
||||
|
||||
import eu.dnetlib.enabling.is.sn.SubscriptionRequest;
|
||||
import org.apache.commons.lang3.builder.EqualsBuilder;
|
||||
import org.apache.commons.lang3.builder.HashCodeBuilder;
|
||||
|
||||
/**
|
||||
* This class describes a ResourceState subscription, i.e. a subscription that is registered on a topic that depends on
|
||||
* some xpath on some resource, and which is triggered when the value of this xpath changes.
|
||||
*
|
||||
* Topics of this type could not be there.
|
||||
*
|
||||
* @author marko
|
||||
*
|
||||
*/
|
||||
@Entity(name = "subscriptions")
|
||||
@Table(name = "subscriptions")
|
||||
public class ResourceStateSubscription {
|
||||
|
||||
/**
|
||||
* hash seed.
|
||||
*/
|
||||
private static final int HASH_SEED_2 = 59;
|
||||
|
||||
/**
|
||||
* hash seed.
|
||||
*/
|
||||
private static final int HASH_SEED = 47;
|
||||
|
||||
/**
|
||||
* create topic prefix.
|
||||
*/
|
||||
public static final String PREFIX_CREATE = "CREATE";
|
||||
|
||||
/**
|
||||
* delete topic prefix.
|
||||
*/
|
||||
public static final String PREFIX_DELETE = "DELETE";
|
||||
|
||||
/**
|
||||
* update topic prefix.
|
||||
*/
|
||||
public static final String PREFIX_UPDATE = "UPDATE";
|
||||
|
||||
/**
|
||||
* pending create topic prefix.
|
||||
*/
|
||||
public static final String PREFIX_PENDING_CREATE = "PENDING_CREATE";
|
||||
|
||||
/**
|
||||
* pending delete topic prefix.
|
||||
*/
|
||||
public static final String PREFIX_PENDING_DELETE = "PENDING_DELETE";
|
||||
|
||||
/**
|
||||
* pending update topic prefix.
|
||||
*/
|
||||
public static final String PREFIX_PENDING_UPDATE = "PENDING_UPDATE";
|
||||
|
||||
|
||||
/**
|
||||
* subscription identifier.
|
||||
*/
|
||||
@Id
|
||||
@Column(name = "subscriptionid")
|
||||
private String subscriptionId;
|
||||
|
||||
/**
|
||||
* prefix: crude.
|
||||
*/
|
||||
@Column(name = "prefix")
|
||||
private String prefix;
|
||||
|
||||
/**
|
||||
* resource type.
|
||||
*/
|
||||
@Column(name = "type")
|
||||
private String type;
|
||||
|
||||
/**
|
||||
* resource id.
|
||||
*/
|
||||
@Column(name = "resourceid")
|
||||
private String resourceId;
|
||||
|
||||
/**
|
||||
* xpath.
|
||||
*/
|
||||
@Column(name = "xpath")
|
||||
private String xpath;
|
||||
|
||||
/**
|
||||
* consumer (subscriber) reference.
|
||||
*/
|
||||
@Column(name = "subscriber", length = 4096)
|
||||
private String subscriber;
|
||||
|
||||
/**
|
||||
* default constructor. for unit testing.
|
||||
*/
|
||||
public ResourceStateSubscription() {
|
||||
this.type = "*";
|
||||
this.resourceId = "*";
|
||||
}
|
||||
|
||||
/**
|
||||
* create a new instance.
|
||||
*
|
||||
* @param request
|
||||
* original request.
|
||||
* @param prefix
|
||||
* prefix
|
||||
* @param type
|
||||
* resource type
|
||||
* @param resourceId
|
||||
* resource identifier
|
||||
* @param xpath
|
||||
* xpath
|
||||
*/
|
||||
public ResourceStateSubscription(final SubscriptionRequest request, final String prefix, final String type, final String resourceId,
|
||||
final String xpath) {
|
||||
super();
|
||||
setSubscriptionId(request.getSubscriptionId());
|
||||
setSubscriber(request.getSubscriber());
|
||||
setPrefix(prefix);
|
||||
setType(type);
|
||||
setResourceId(resourceId);
|
||||
setXpath(xpath);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @see java.lang.Object#hashCode()
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return new HashCodeBuilder(HASH_SEED, HASH_SEED_2).append(subscriptionId).append(subscriber.toString()).append(prefix).append(type).append(xpath)
|
||||
.toHashCode();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @see java.lang.Object#equals(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(final Object obj) {
|
||||
if (!(obj instanceof ResourceStateSubscription))
|
||||
return false;
|
||||
|
||||
if (this == obj)
|
||||
return true;
|
||||
|
||||
final ResourceStateSubscription rhs = (ResourceStateSubscription) obj;
|
||||
return new EqualsBuilder().append(subscriptionId, rhs.getSubscriptionId()).append(prefix, rhs.getPrefix()).append(
|
||||
resourceId, rhs.getResourceId()).append(xpath, rhs.getXpath()).isEquals();
|
||||
}
|
||||
|
||||
public String getSubscriptionId() {
|
||||
return subscriptionId;
|
||||
}
|
||||
|
||||
public void setSubscriptionId(final String subscriptionId) {
|
||||
this.subscriptionId = subscriptionId;
|
||||
}
|
||||
|
||||
public String getPrefix() {
|
||||
return prefix;
|
||||
}
|
||||
|
||||
public void setPrefix(final String prefix) {
|
||||
this.prefix = prefix;
|
||||
}
|
||||
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public void setType(final String type) {
|
||||
this.type = type == null || type.isEmpty() ? "*" : type;
|
||||
}
|
||||
|
||||
public String getXpath() {
|
||||
return xpath;
|
||||
}
|
||||
|
||||
public void setXpath(final String xpath) {
|
||||
this.xpath = xpath;
|
||||
}
|
||||
|
||||
public String getSubscriber() {
|
||||
return subscriber;
|
||||
}
|
||||
|
||||
public W3CEndpointReference getSubscriberAsEpr() {
|
||||
return (W3CEndpointReference) EndpointReference.readFrom(new StreamSource(new StringReader(getSubscriber())));
|
||||
}
|
||||
|
||||
public void setSubscriber(final W3CEndpointReference epr) {
|
||||
this.subscriber = (epr != null) ? epr.toString() : null;;
|
||||
}
|
||||
|
||||
public void setSubscriber(final String subscriber) {
|
||||
this.subscriber = subscriber;
|
||||
}
|
||||
|
||||
public void setResourceId(final String resourceId) {
|
||||
this.resourceId = resourceId == null || resourceId.isEmpty() ? "*" : resourceId;
|
||||
}
|
||||
|
||||
public String getResourceId() {
|
||||
return resourceId;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
package eu.dnetlib.enabling.is.sn.resourcestate;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import eu.dnetlib.enabling.is.sn.SubscriptionDAO;
|
||||
|
||||
/**
|
||||
* Stores ResourceState subscriptions.
|
||||
*
|
||||
* @author marko
|
||||
*
|
||||
*/
|
||||
public interface ResourceStateSubscriptionDAO extends SubscriptionDAO<ResourceStateSubscription> {
|
||||
|
||||
/**
|
||||
* get all subscriptions matching a given prefix and a given resource type.
|
||||
*
|
||||
* @param prefix null means any prefix
|
||||
* @param resourceType resource type.
|
||||
* @param resourceId resource identifier
|
||||
* @return matching subscriptions
|
||||
*/
|
||||
Collection<ResourceStateSubscription> listSubscriptions(String prefix, String resourceType, String resourceId);
|
||||
}
|
|
@ -0,0 +1,233 @@
|
|||
package eu.dnetlib.enabling.is.sn.resourcestate;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.xml.transform.dom.DOMResult;
|
||||
import javax.xml.ws.wsaddressing.W3CEndpointReference;
|
||||
import javax.xml.xpath.XPathExpressionException;
|
||||
import javax.xml.xpath.XPathFactory;
|
||||
|
||||
import com.google.common.collect.Sets;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.apache.oro.text.perl.Perl5Util;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Required;
|
||||
|
||||
import eu.dnetlib.enabling.is.sn.AbstractSubscriptionRegistry;
|
||||
import eu.dnetlib.enabling.is.sn.SubscriptionRegistry;
|
||||
import eu.dnetlib.enabling.is.sn.SubscriptionRequest;
|
||||
import eu.dnetlib.enabling.is.sn.TopicExpressionMatchResult;
|
||||
import eu.dnetlib.enabling.is.sn.rmi.SubscriptionRequestRejectedException;
|
||||
import org.springframework.cache.annotation.CacheEvict;
|
||||
import org.springframework.cache.annotation.Cacheable;
|
||||
|
||||
/**
|
||||
* Manage subscription for UPDATE/CREATE/DELETE resource-related topic prefixes.
|
||||
*
|
||||
* @author marko
|
||||
*
|
||||
*/
|
||||
public class ResourceStateSubscriptionRegistry extends AbstractSubscriptionRegistry implements SubscriptionRegistry {
|
||||
|
||||
private static final Log log = LogFactory.getLog(ResourceStateSubscriptionRegistry.class);
|
||||
|
||||
/**
|
||||
* subscription DAO.
|
||||
*/
|
||||
private ResourceStateSubscriptionDAO subscriptionDao;
|
||||
|
||||
/**
|
||||
* subscription request filter.
|
||||
*/
|
||||
@Autowired
|
||||
private SubscriptionRequestFilter subscriptionRequestFilter;
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @see eu.dnetlib.enabling.is.sn.SubscriptionRegistry#registerSubscription(eu.dnetlib.enabling.is.sn.SubscriptionRequest)
|
||||
*/
|
||||
@Override
|
||||
@CacheEvict(value = "subscriptions", allEntries = true)
|
||||
public String registerSubscription(final SubscriptionRequest subscription) throws SubscriptionRequestRejectedException {
|
||||
final TopicExpressionMatchResult prefixMatch = matchPrefix(subscription);
|
||||
if (prefixMatch == null)
|
||||
return null;
|
||||
|
||||
final TopicExpressionMatchResult typeMatch = matchType(prefixMatch.getRest());
|
||||
if (typeMatch == null)
|
||||
return null; // TODO: decide whether to fail or not
|
||||
|
||||
final TopicExpressionMatchResult idMatch = matchId(typeMatch.getRest());
|
||||
|
||||
if (idMatch == null)
|
||||
return null; // TODO: decide whether to fail or not
|
||||
|
||||
final ResourceStateSubscription rss = new ResourceStateSubscription(subscription, prefixMatch.getPrefix(), typeMatch.getPrefix(), idMatch.getPrefix(),
|
||||
idMatch.getRest());
|
||||
|
||||
if (!getSubscriptionRequestFilter().accept(rss))
|
||||
throw new SubscriptionRequestRejectedException(String.format("rejected subscription request, resourceId: '%s', xpath: '%s', from: %s",
|
||||
rss.getResourceId(), rss.getXpath(), rss.getSubscriber()));
|
||||
|
||||
return registerSubscription(rss);
|
||||
}
|
||||
|
||||
/**
|
||||
* this registers the real subscription.
|
||||
*
|
||||
* TODO: am I sure that the overload is a good thing here?
|
||||
*
|
||||
* @param subscription
|
||||
* subscription
|
||||
* @return subscription id (potentially changed)
|
||||
*/
|
||||
private String registerSubscription(final ResourceStateSubscription subscription) {
|
||||
if(log.isDebugEnabled()) {
|
||||
log.debug("evict subscriptions cache");
|
||||
}
|
||||
|
||||
// TODO: change the dao, and implement a method which finds a given subscription directly.
|
||||
final Collection<ResourceStateSubscription> similar = subscriptionDao.listSubscriptions(subscription.getPrefix(), subscription.getType(),
|
||||
subscription.getResourceId());
|
||||
for (final ResourceStateSubscription r : similar) {
|
||||
if (r != null && getAddress(subscription.getSubscriberAsEpr()).equals(getAddress(r.getSubscriberAsEpr()))
|
||||
&& (subscription.getXpath() == r.getXpath() || subscription.getXpath().equals(r.getXpath()))
|
||||
&& (subscription.getResourceId() == r.getResourceId() || subscription.getResourceId().equals(r.getResourceId())))
|
||||
return r.getSubscriptionId();
|
||||
}
|
||||
|
||||
subscriptionDao.addSubscription(subscription);
|
||||
|
||||
return subscription.getSubscriptionId();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @see eu.dnetlib.enabling.is.sn.SubscriptionRegistry#unsubscribe(java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
@CacheEvict(value = "subscriptions", allEntries = true)
|
||||
public boolean unsubscribe(final String subId) {
|
||||
log.info("evict subscriptions cache");
|
||||
return subscriptionDao.removeSubscription(subId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains the address component of the EPR.
|
||||
*
|
||||
* TODO: refactor in a utility class.
|
||||
*
|
||||
* @param epr
|
||||
* endpoint reference
|
||||
* @return address contained in the endpoint reference
|
||||
*/
|
||||
private Object getAddress(final W3CEndpointReference epr) {
|
||||
final DOMResult dom = new DOMResult();
|
||||
epr.writeTo(dom);
|
||||
|
||||
try {
|
||||
return XPathFactory.newInstance().newXPath().evaluate("//*[local-name() = 'Address']", dom.getNode());
|
||||
} catch (final XPathExpressionException e) {
|
||||
throw new IllegalStateException("cannot construct xpath expression", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* extract resource type name.
|
||||
*
|
||||
* @param rest
|
||||
* topic expression without prefix
|
||||
* @return tuple containing type name and rest of the prefix
|
||||
*/
|
||||
public TopicExpressionMatchResult matchType(final String rest) {
|
||||
final Perl5Util matcher = new Perl5Util(); // NOPMD
|
||||
if (!matcher.match("/^(\\*|[a-zA-Z_0-9]*)($|/)(.*)$/", rest))
|
||||
return null;
|
||||
|
||||
return new TopicExpressionMatchResult(matcher.getMatch().group(1), matcher.getMatch().group(2 + 1));
|
||||
}
|
||||
|
||||
/**
|
||||
* extract resource id.
|
||||
*
|
||||
* @param rest
|
||||
* topic expression without prefix
|
||||
* @return tuple containing type name and rest of the prefix
|
||||
*/
|
||||
public TopicExpressionMatchResult matchId(final String rest) {
|
||||
final Perl5Util matcher = new Perl5Util(); // NOPMD
|
||||
if (!matcher.match("/^([^/]*)(.*)/", rest))
|
||||
return null;
|
||||
|
||||
return new TopicExpressionMatchResult(matcher.getMatch().group(1), matcher.getMatch().group(2));
|
||||
}
|
||||
|
||||
/**
|
||||
* return all subscriptions matching a given prefix and a given type. Wildcard subscriptions will match any resource type.
|
||||
*
|
||||
* @param prefix
|
||||
* prefix
|
||||
* @param type
|
||||
* concrete type
|
||||
* @param resId
|
||||
* resource identifier
|
||||
* @return all matching subscriptions
|
||||
*/
|
||||
@Override
|
||||
@Cacheable(value="subscriptions", key="{ #prefix, #type, #resId }")
|
||||
public Collection<ResourceStateSubscription> listMatchingSubscriptions(final String prefix, final String type, final String resId) {
|
||||
|
||||
if(log.isDebugEnabled()) {
|
||||
log.debug(String.format("uncached list subscriptions [prefix: '%s', type: '%s', resourceId: '%s']", prefix, type, resId));
|
||||
}
|
||||
final Set<ResourceStateSubscription> merged = new HashSet<ResourceStateSubscription>();
|
||||
merged.addAll(subscriptionDao.listSubscriptions(prefix, type, resId));
|
||||
merged.addAll(subscriptionDao.listSubscriptions(prefix, type, "*"));
|
||||
merged.addAll(subscriptionDao.listSubscriptions(prefix, "*", "*"));
|
||||
return merged;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Cacheable(value="subscriptions")
|
||||
public Collection<ResourceStateSubscription> listSubscriptions() {
|
||||
log.info("uncached list subscriptions");
|
||||
|
||||
return Sets.newHashSet(subscriptionDao.listSubscriptions());
|
||||
}
|
||||
|
||||
@Override
|
||||
@CacheEvict(value = "subscriptions", allEntries = true)
|
||||
public boolean removeSubscription(final String subscriptionId) {
|
||||
return subscriptionDao.removeSubscription(subscriptionId);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Collection<String> getAcceptedPrefixes() {
|
||||
return Arrays.asList(new String[] { ResourceStateSubscription.PREFIX_CREATE, ResourceStateSubscription.PREFIX_DELETE,
|
||||
ResourceStateSubscription.PREFIX_UPDATE });
|
||||
}
|
||||
|
||||
public ResourceStateSubscriptionDAO getSubscriptionDao() {
|
||||
return subscriptionDao;
|
||||
}
|
||||
|
||||
@Required
|
||||
public void setSubscriptionDao(final ResourceStateSubscriptionDAO subscriptionDao) {
|
||||
this.subscriptionDao = subscriptionDao;
|
||||
}
|
||||
|
||||
public SubscriptionRequestFilter getSubscriptionRequestFilter() {
|
||||
return subscriptionRequestFilter;
|
||||
}
|
||||
|
||||
public void setSubscriptionRequestFilter(final SubscriptionRequestFilter subscriptionRequestFilter) {
|
||||
this.subscriptionRequestFilter = subscriptionRequestFilter;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
package eu.dnetlib.enabling.is.sn.resourcestate;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
|
||||
public class SubscriptionRequestFilter {
|
||||
|
||||
/**
|
||||
* logger.
|
||||
*/
|
||||
private static final Log log = LogFactory.getLog(SubscriptionRequestFilter.class); // NOPMD by marko on 11/24/08 5:02 PM
|
||||
|
||||
/**
|
||||
* resource wildcard
|
||||
*/
|
||||
private static final String ANY_RESOURCE = "*";
|
||||
|
||||
@Value("${services.issn.subscription.filter.active}")
|
||||
private boolean active = false;
|
||||
|
||||
public boolean accept(final ResourceStateSubscription rss) {
|
||||
|
||||
if (!isActive()) return true;
|
||||
|
||||
if (StringUtils.isBlank(rss.getXpath()) & StringUtils.equals(rss.getResourceId(), ANY_RESOURCE)) {
|
||||
log.debug(String.format("rejected subscription request, resourceId: '%s', xpath: '%s', from: %s", rss.getResourceId(), rss.getXpath(),
|
||||
rss.getSubscriber()));
|
||||
return false; // we reject wide subscriptions
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean isActive() {
|
||||
return active;
|
||||
}
|
||||
|
||||
public void setActive(boolean active) {
|
||||
this.active = active;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,151 @@
|
|||
package eu.dnetlib.enabling.is.sn.resourcestate.hib;
|
||||
|
||||
import static java.sql.Types.VARCHAR;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.io.StringReader;
|
||||
import java.io.StringWriter;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
|
||||
import javax.xml.transform.stream.StreamResult;
|
||||
import javax.xml.transform.stream.StreamSource;
|
||||
import javax.xml.ws.EndpointReference;
|
||||
import javax.xml.ws.wsaddressing.W3CEndpointReference;
|
||||
|
||||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.engine.spi.SessionImplementor;
|
||||
import org.hibernate.usertype.UserType;
|
||||
|
||||
/**
|
||||
* Serializes Endpoint reference types to database columns (strings).
|
||||
*
|
||||
* @author marko
|
||||
*
|
||||
*/
|
||||
public class EndpointReferenceType implements UserType { // NOPMD
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @see org.hibernate.usertype.UserType#assemble(java.io.Serializable, java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public Object assemble(final Serializable arg0, final Object owner) {
|
||||
if (arg0 == null) return null;
|
||||
return EndpointReference.readFrom(new StreamSource(new StringReader((String) arg0)));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @see org.hibernate.usertype.UserType#deepCopy(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public Object deepCopy(final Object arg0) {
|
||||
if (arg0 == null) return null;
|
||||
|
||||
return arg0;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @see org.hibernate.usertype.UserType#disassemble(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public Serializable disassemble(final Object arg0) {
|
||||
final StringWriter buffer = new StringWriter();
|
||||
((W3CEndpointReference) arg0).writeTo(new StreamResult(buffer));
|
||||
return buffer.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @see org.hibernate.usertype.UserType#equals(java.lang.Object, java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(final Object arg0, final Object arg1) {
|
||||
if (arg0 == arg1) // NOPMD
|
||||
return true;
|
||||
if ((arg0 == null) || (arg1 == null)) return false;
|
||||
return arg0.equals(arg1);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @see org.hibernate.usertype.UserType#hashCode(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public int hashCode(final Object arg0) {
|
||||
return disassemble(arg0).hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isMutable() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @see org.hibernate.usertype.UserType#nullSafeGet(java.sql.ResultSet, java.lang.String[], org.hibernate.engine.spi.SessionImplementor,
|
||||
* java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public Object nullSafeGet(final ResultSet rset, final String[] names, final SessionImplementor si, final Object owner) throws SQLException {
|
||||
return assemble(rset.getString(names[0]), owner);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @see org.hibernate.usertype.UserType#nullSafeSet(java.sql.PreparedStatement, java.lang.Object, int,
|
||||
* org.hibernate.engine.spi.SessionImplementor)
|
||||
*/
|
||||
@Override
|
||||
public void nullSafeSet(final PreparedStatement statement, final Object epr, final int index, final SessionImplementor arg3) throws HibernateException,
|
||||
SQLException {
|
||||
if (epr != null) {
|
||||
statement.setString(index, (String) disassemble(epr));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @see org.hibernate.usertype.UserType#replace(java.lang.Object, java.lang.Object, java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public Object replace(final Object arg0, final Object arg1, final Object arg2) {
|
||||
// is not mutable
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @see org.hibernate.usertype.UserType#returnedClass()
|
||||
*/
|
||||
@Override
|
||||
@SuppressWarnings("rawtypes")
|
||||
public Class returnedClass() {
|
||||
return W3CEndpointReference.class;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @see org.hibernate.usertype.UserType#sqlTypes()
|
||||
*/
|
||||
@Override
|
||||
public int[] sqlTypes() {
|
||||
return new int[] { VARCHAR };
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,137 @@
|
|||
package eu.dnetlib.enabling.is.sn.resourcestate.hib;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import eu.dnetlib.enabling.is.sn.resourcestate.ResourceStateSubscription;
|
||||
import eu.dnetlib.enabling.is.sn.resourcestate.ResourceStateSubscriptionDAO;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.hibernate.Criteria;
|
||||
import org.hibernate.SessionFactory;
|
||||
import org.hibernate.criterion.Example;
|
||||
import org.springframework.beans.factory.annotation.Required;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
/**
|
||||
* Hibernate storage for resource state subscriptions.
|
||||
*
|
||||
* @author marko
|
||||
*
|
||||
*/
|
||||
public class HibernateResourceStateSubscriptionDAOImpl implements ResourceStateSubscriptionDAO {
|
||||
|
||||
private static final Log log = LogFactory.getLog(HibernateResourceStateSubscriptionDAOImpl.class);
|
||||
|
||||
private SessionFactory sessionFactory;
|
||||
|
||||
private Collection<ResourceStateSubscription> transformToSubscription(final List<Object> inputList) {
|
||||
return inputList.stream()
|
||||
.map(o -> (ResourceStateSubscription) o)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @see eu.dnetlib.enabling.is.sn.resourcestate.ResourceStateSubscriptionDAO#listSubscriptions(java.lang.String, java.lang.String,
|
||||
* java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
@Transactional(readOnly = true)
|
||||
public Collection<ResourceStateSubscription> listSubscriptions(final String prefix, final String resourceType, final String resourceId) {
|
||||
|
||||
final ResourceStateSubscription exampleEntity = new ResourceStateSubscription();
|
||||
exampleEntity.setPrefix(prefix);
|
||||
exampleEntity.setType(resourceType);
|
||||
exampleEntity.setResourceId(resourceId);
|
||||
|
||||
return transformToSubscription(queryByCriteria(exampleEntity));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @see eu.dnetlib.enabling.is.sn.SubscriptionDAO#addSubscription(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
@Transactional
|
||||
public void addSubscription(final ResourceStateSubscription subscription) {
|
||||
|
||||
log.debug("evict cached subscriptions");
|
||||
|
||||
getSessionFactory().getCurrentSession().save(subscription);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @see eu.dnetlib.enabling.is.sn.SubscriptionDAO#getSubscription(java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
@Transactional(readOnly = true)
|
||||
public ResourceStateSubscription getSubscription(final String subscriptionId) {
|
||||
return (ResourceStateSubscription) getSessionFactory().getCurrentSession().get(ResourceStateSubscription.class, subscriptionId);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @see eu.dnetlib.enabling.is.sn.SubscriptionDAO#listSubscriptions()
|
||||
*/
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
@Transactional(readOnly = true)
|
||||
public Collection<ResourceStateSubscription> listSubscriptions() {
|
||||
return getSessionFactory().getCurrentSession().createQuery("from subscriptions").list();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @see eu.dnetlib.enabling.is.sn.SubscriptionDAO#listSubscriptions(java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
@Transactional(readOnly = true)
|
||||
public Collection<ResourceStateSubscription> listSubscriptions(final String prefix) {
|
||||
final ResourceStateSubscription exampleEntity = new ResourceStateSubscription();
|
||||
exampleEntity.setPrefix(prefix);
|
||||
|
||||
return transformToSubscription(queryByCriteria(exampleEntity));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @see eu.dnetlib.enabling.is.sn.SubscriptionDAO#removeSubscription(java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
@Transactional
|
||||
public boolean removeSubscription(final String subscriptionId) {
|
||||
if (StringUtils.isBlank(subscriptionId)) return false;
|
||||
|
||||
final ResourceStateSubscription entity = getSubscription(subscriptionId);
|
||||
|
||||
if (entity == null) return false;
|
||||
|
||||
getSessionFactory().getCurrentSession().delete(entity);
|
||||
return true;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private List<Object> queryByCriteria(final ResourceStateSubscription exampleEntity) {
|
||||
Criteria criteria = getSessionFactory().getCurrentSession().createCriteria(ResourceStateSubscription.class).add(Example.create(exampleEntity));
|
||||
return criteria.list();
|
||||
}
|
||||
|
||||
public SessionFactory getSessionFactory() {
|
||||
return sessionFactory;
|
||||
}
|
||||
|
||||
@Required
|
||||
public void setSessionFactory(SessionFactory sessionFactory) {
|
||||
this.sessionFactory = sessionFactory;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,323 @@
|
|||
package eu.dnetlib.enabling.is.store;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import javax.annotation.Resource;
|
||||
import javax.jws.WebService;
|
||||
import javax.xml.ws.Endpoint;
|
||||
|
||||
import com.google.common.collect.Iterators;
|
||||
import eu.dnetlib.enabling.is.store.rmi.ISStoreException;
|
||||
import eu.dnetlib.enabling.is.store.rmi.ISStoreService;
|
||||
import eu.dnetlib.enabling.tools.AbstractBaseService;
|
||||
import eu.dnetlib.soap.EndpointReferenceBuilder;
|
||||
import eu.dnetlib.xml.database.XMLDatabase;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.quartz.Job;
|
||||
import org.quartz.JobExecutionException;
|
||||
import org.xmldb.api.base.XMLDBException;
|
||||
|
||||
/**
|
||||
* ISStore service implementation.
|
||||
*
|
||||
* @author marko
|
||||
*
|
||||
*/
|
||||
@WebService(targetNamespace = "http://services.dnetlib.eu/")
|
||||
public class ISStoreServiceImpl extends AbstractBaseService implements ISStoreService { // NOPMD by marko on 11/24/08
|
||||
|
||||
/**
|
||||
* logger.
|
||||
*/
|
||||
private static final Log log = LogFactory.getLog(ISStoreServiceImpl.class); // NOPMD by marko on 11/24/08 4:46 PM
|
||||
|
||||
/**
|
||||
* xml database used by the ISStore.
|
||||
*/
|
||||
private XMLDatabase xmlDatabase;
|
||||
|
||||
/**
|
||||
* Service endpoint.
|
||||
*/
|
||||
private Endpoint endpoint;
|
||||
|
||||
/**
|
||||
* injected EPR builder.
|
||||
*/
|
||||
@Resource(name = "jaxwsEndpointReferenceBuilder")
|
||||
private EndpointReferenceBuilder<Endpoint> eprBuilder;
|
||||
|
||||
/**
|
||||
* initializer job
|
||||
*/
|
||||
private Job contentInitializerJob;
|
||||
|
||||
@Override
|
||||
public void start() {
|
||||
super.start();
|
||||
|
||||
new Thread(new Runnable() {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
Thread.sleep(500);
|
||||
contentInitializerJob.execute(null);
|
||||
} catch (JobExecutionException e) {
|
||||
log.fatal("failed to initialize xmldb", e);
|
||||
} catch (InterruptedException e) {
|
||||
log.fatal("failed to initialize xmldb", e);
|
||||
}
|
||||
}
|
||||
}).start();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* web service context (not really useful right now).
|
||||
*/
|
||||
// @Resource
|
||||
// private WebServiceContext context;
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @see eu.dnetlib.enabling.is.store.rmi.ISStoreService#createFileColl(java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public boolean createFileColl(final String fileColl) throws ISStoreException {
|
||||
try {
|
||||
xmlDatabase.createCollection(fileColl);
|
||||
} catch (XMLDBException e) {
|
||||
throw new ISStoreException(e);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @see eu.dnetlib.enabling.is.store.rmi.ISStoreService#deleteFileColl(java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public boolean deleteFileColl(final String fileColl) throws ISStoreException {
|
||||
try {
|
||||
xmlDatabase.removeCollection(fileColl);
|
||||
} catch (XMLDBException e) {
|
||||
throw new ISStoreException(e);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @see eu.dnetlib.enabling.is.store.rmi.ISStoreService#deleteXML(java.lang.String, java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public boolean deleteXML(final String fileName, final String fileColl) throws ISStoreException {
|
||||
try {
|
||||
return xmlDatabase.remove(fileName, fileColl);
|
||||
} catch (XMLDBException e) {
|
||||
throw new ISStoreException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @see eu.dnetlib.enabling.is.store.rmi.ISStoreService#executeXUpdate(java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public boolean executeXUpdate(final String query) throws ISStoreException {
|
||||
getXMLbyQuery(query);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @see eu.dnetlib.enabling.is.store.rmi.ISStoreService#getFileColls()
|
||||
*/
|
||||
@Override
|
||||
public List<String> getFileColls() throws ISStoreException {
|
||||
try {
|
||||
return xmlDatabase.listChildCollections(xmlDatabase.getRootCollection());
|
||||
} catch (XMLDBException e) {
|
||||
throw new ISStoreException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @see eu.dnetlib.enabling.is.store.rmi.ISStoreService#getFileNames(java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public List<String> getFileNames(final String fileColl) throws ISStoreException {
|
||||
try {
|
||||
return xmlDatabase.list(fileColl);
|
||||
} catch (XMLDBException e) {
|
||||
throw new ISStoreException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @see eu.dnetlib.enabling.is.store.rmi.ISStoreService#getXML(java.lang.String, java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public String getXML(final String fileName, final String fileColl) throws ISStoreException {
|
||||
try {
|
||||
return xmlDatabase.read(fileName, fileColl);
|
||||
} catch (XMLDBException e) {
|
||||
throw new ISStoreException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @see eu.dnetlib.enabling.is.store.rmi.ISStoreService#getXMLbyQuery(java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public String getXMLbyQuery(final String query) throws ISStoreException {
|
||||
log.debug(query);
|
||||
|
||||
try {
|
||||
final Iterator<String> res = xmlDatabase.xquery(query);
|
||||
if (res == null) return null;
|
||||
if (!res.hasNext()) return null;
|
||||
return res.next();
|
||||
} catch (XMLDBException e) {
|
||||
throw new ISStoreException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @see eu.dnetlib.enabling.is.store.rmi.ISStoreService#insertXML(java.lang.String, java.lang.String, java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public boolean insertXML(final String fileName, final String fileColl, final String file) throws ISStoreException {
|
||||
try {
|
||||
xmlDatabase.create(fileName, fileColl, file);
|
||||
} catch (XMLDBException e) {
|
||||
throw new ISStoreException(e);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @see eu.dnetlib.enabling.is.store.rmi.ISStoreService#quickSearchXML(java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public List<String> quickSearchXML(final String query) throws ISStoreException {
|
||||
log.debug(query);
|
||||
try {
|
||||
final Iterator<String> res = xmlDatabase.xquery(query);
|
||||
if (res == null) return new ArrayList<>();
|
||||
|
||||
final ArrayList<String> ans = new ArrayList<String>();
|
||||
Iterators.addAll(ans, res);
|
||||
return ans;
|
||||
} catch (XMLDBException e) {
|
||||
log.fatal("searching", e);
|
||||
throw new ISStoreException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @see eu.dnetlib.enabling.is.store.rmi.ISStoreService#reindex()
|
||||
*/
|
||||
@Override
|
||||
public boolean reindex() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @see eu.dnetlib.enabling.is.store.rmi.ISStoreService#sync()
|
||||
*/
|
||||
@Override
|
||||
public boolean sync() {
|
||||
log.info("TEST: " + endpoint);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @see eu.dnetlib.enabling.is.store.rmi.ISStoreService#updateXML(java.lang.String, java.lang.String, java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public boolean updateXML(final String fileName, final String fileColl, final String file) throws ISStoreException {
|
||||
try {
|
||||
xmlDatabase.update(fileName, fileColl, file);
|
||||
} catch (XMLDBException e) {
|
||||
throw new ISStoreException(e);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @see eu.dnetlib.enabling.is.store.rmi.ISStoreService#backup()
|
||||
*/
|
||||
@Override
|
||||
public String backup() throws ISStoreException {
|
||||
try {
|
||||
return xmlDatabase.backup();
|
||||
} catch (Exception e) {
|
||||
throw new ISStoreException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public XMLDatabase getXmlDatabase() {
|
||||
return xmlDatabase;
|
||||
}
|
||||
|
||||
public void setXmlDatabase(final XMLDatabase xmlDatabase) {
|
||||
this.xmlDatabase = xmlDatabase;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRunning() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public Endpoint getEndpoint() {
|
||||
return endpoint;
|
||||
}
|
||||
|
||||
public void setEndpoint(final Endpoint endpoint) {
|
||||
this.endpoint = endpoint;
|
||||
}
|
||||
|
||||
protected EndpointReferenceBuilder<Endpoint> getEprBuilder() {
|
||||
return eprBuilder;
|
||||
}
|
||||
|
||||
protected void setEprBuilder(final EndpointReferenceBuilder<Endpoint> eprBuilder) {
|
||||
this.eprBuilder = eprBuilder;
|
||||
}
|
||||
|
||||
public Job getContentInitializerJob() {
|
||||
return contentInitializerJob;
|
||||
}
|
||||
|
||||
public void setContentInitializerJob(final Job contentInitializerJob) {
|
||||
this.contentInitializerJob = contentInitializerJob;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,180 @@
|
|||
package eu.dnetlib.enabling.is.store;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
import javax.xml.xpath.XPathExpressionException;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.quartz.Job;
|
||||
import org.quartz.JobExecutionContext;
|
||||
import org.quartz.JobExecutionException;
|
||||
import org.springframework.beans.factory.annotation.Required;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.xml.sax.SAXException;
|
||||
|
||||
import eu.dnetlib.enabling.is.registry.rmi.ISRegistryException;
|
||||
import eu.dnetlib.enabling.tools.ResourceLoaderHelper;
|
||||
import eu.dnetlib.miscutils.coupling.StaticCondition;
|
||||
|
||||
/**
|
||||
* This job is scheduled at startup of a test environment to load some data into the store.
|
||||
*
|
||||
* <p>
|
||||
* You should configure this bean with paths to the profile and schema files you want to add. This can be done setting
|
||||
* the 'resources' and 'schemas' properties using the syntax documented <a
|
||||
* href="http://static.springframework.org/spring/docs/
|
||||
* 2.5.x/reference/resources.html#resources-app-ctx-wildcards-in-resource-paths">here</a>
|
||||
* </p>
|
||||
*
|
||||
* @author marko
|
||||
*
|
||||
*/
|
||||
public class TestContentInitializerJob extends AbstractContentInitializer implements Job {
|
||||
/**
|
||||
* milliseconds in a second.
|
||||
*/
|
||||
private static final double MILLIS = 1000.0;
|
||||
|
||||
/**
|
||||
* logger.
|
||||
*/
|
||||
static final Log log = LogFactory.getLog(TestContentInitializerJob.class); // NOPMD by marko on 11/24/08 5:02 PM
|
||||
|
||||
/**
|
||||
* hackish way of communicating to the integration tester that we have finished.
|
||||
*/
|
||||
private static boolean initialized = false;
|
||||
|
||||
/**
|
||||
* resourceLoader compatible pattern matching all files to load.
|
||||
*/
|
||||
private String resources;
|
||||
|
||||
/**
|
||||
* resourceLoader compatible pattern matching all xsd files to load.
|
||||
*/
|
||||
private String schemas;
|
||||
|
||||
/**
|
||||
* resource loader helper. we cannot implement the ResourceLoaderAware interface.
|
||||
*/
|
||||
private ResourceLoaderHelper resourceLoader;
|
||||
|
||||
/**
|
||||
* set to true in order to disable notification detection. Useful for bulk profile insertion.
|
||||
*/
|
||||
private StaticCondition snDisable;
|
||||
|
||||
public TestContentInitializerJob() {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @see org.quartz.Job#execute(org.quartz.JobExecutionContext)
|
||||
*/
|
||||
@Override
|
||||
public void execute(final JobExecutionContext arg0) throws JobExecutionException {
|
||||
initialize();
|
||||
setInitialized(true);
|
||||
}
|
||||
|
||||
public void initialize() throws JobExecutionException {
|
||||
log.info("Initializing store with some profiles and collections for test and development ...");
|
||||
|
||||
if (!getBulkImporter().isEnabled()) {
|
||||
log.info("skipping store initialization because the database already exists");
|
||||
return;
|
||||
}
|
||||
|
||||
log.info("loading resources: " + getResources());
|
||||
|
||||
try {
|
||||
String type = "schema/profile"; // NOPMD
|
||||
String name = "none"; // NOPMD
|
||||
try {
|
||||
final long start = System.currentTimeMillis();
|
||||
|
||||
type = "schema"; // NOPMD
|
||||
for (Resource res : resourceLoader.getResourcePatternResolver().getResources(schemas)) {
|
||||
name = res.getURL().toString(); // NOPMD
|
||||
registerSchema(res.getURL());
|
||||
}
|
||||
|
||||
try {
|
||||
snDisable.setCondition(true);
|
||||
type = "profile";
|
||||
for (Resource res : resourceLoader.getResourcePatternResolver().getResources(resources)) {
|
||||
name = res.getURL().toString(); // NOPMD
|
||||
registerProfile(res.getURL());
|
||||
}
|
||||
} finally {
|
||||
snDisable.setCondition(false);
|
||||
}
|
||||
|
||||
log.info("bulk registration finished in: " + ((System.currentTimeMillis() - start) / MILLIS) + "s");
|
||||
} catch (ISRegistryException e) {
|
||||
log.fatal("cannot register " + type + ": " + name, e);
|
||||
throw new JobExecutionException("registry exception", e);
|
||||
} catch (IOException e) {
|
||||
throw new JobExecutionException("io exception", e);
|
||||
} catch (XPathExpressionException e) {
|
||||
throw new JobExecutionException("xpath exception", e);
|
||||
} catch (SAXException e) {
|
||||
throw new JobExecutionException("sax exception", e);
|
||||
} catch (ParserConfigurationException e) {
|
||||
throw new JobExecutionException("parser exception", e);
|
||||
}
|
||||
} finally {
|
||||
log.info("INITIALIZED");
|
||||
setInitialized(true);
|
||||
}
|
||||
}
|
||||
|
||||
public static void setInitialized(final boolean initialized) {
|
||||
TestContentInitializerJob.initialized = initialized;
|
||||
}
|
||||
|
||||
public static boolean isInitialized() {
|
||||
return initialized;
|
||||
}
|
||||
|
||||
public void setResources(final String resources) {
|
||||
this.resources = resources;
|
||||
}
|
||||
|
||||
public String getResources() {
|
||||
return resources;
|
||||
}
|
||||
|
||||
@Required
|
||||
public ResourceLoaderHelper getResourceLoader() {
|
||||
return resourceLoader;
|
||||
}
|
||||
|
||||
@Required
|
||||
public void setResourceLoader(final ResourceLoaderHelper resourceLoader) {
|
||||
this.resourceLoader = resourceLoader;
|
||||
}
|
||||
|
||||
@Required
|
||||
public void setSchemas(final String schemas) {
|
||||
this.schemas = schemas;
|
||||
}
|
||||
|
||||
public String getSchemas() {
|
||||
return schemas;
|
||||
}
|
||||
|
||||
public void setSnDisable(final StaticCondition snDisable) {
|
||||
this.snDisable = snDisable;
|
||||
}
|
||||
|
||||
public StaticCondition getSnDisable() {
|
||||
return snDisable;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
xquery version "1.0";
|
||||
|
||||
module namespace dnet="http://namespace.dnetlib.eu/xquery/dnet";
|
||||
declare namespace xmldb="http://exist-db.org/xquery/xmldb";
|
||||
|
||||
declare function dnet:deleteDocument($x as element()) {
|
||||
|
||||
xmldb:remove(replace($x/base-uri(),'/[^/]*$', ''), replace($x/base-uri(),'^.*/([^/]*)$', '$1'))
|
||||
|
||||
};
|
|
@ -0,0 +1,46 @@
|
|||
package eu.dnetlib.enabling.tools;
|
||||
|
||||
import com.sun.xml.messaging.saaj.util.Base64;
|
||||
|
||||
/**
|
||||
* resolve resource file and collection names from the resource identifier according to the DNet 1.0 policy, by encoding
|
||||
* the collection path in the identifier itself (as base64).
|
||||
*
|
||||
* @author marko
|
||||
*
|
||||
*/
|
||||
public class CompatResourceIdentifierResolverImpl implements ResourceIdentifierResolver, ResourceIdentifierComposer {
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @see eu.dnetlib.enabling.tools.ResourceIdentifierResolver#getCollectionName(java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public String getCollectionName(final String resId) {
|
||||
final String[] components = resId.split("_");
|
||||
if (components.length == 1)
|
||||
return "DefaultCollection";
|
||||
return Base64.base64Decode(components[1]);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @see eu.dnetlib.enabling.tools.ResourceIdentifierResolver#getFileName(java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public String getFileName(final String resId) {
|
||||
return resId.split("_")[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @see eu.dnetlib.enabling.tools.ResourceIdentifierComposer#createResourceId(java.lang.String, java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public String createResourceId(final String fileName, final String coll) {
|
||||
return fileName + "_" + new String(Base64.encode(coll.getBytes()));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
package eu.dnetlib.enabling.tools;
|
||||
|
||||
import org.aopalliance.intercept.MethodInvocation;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.springframework.aop.interceptor.CustomizableTraceInterceptor;
|
||||
|
||||
/**
|
||||
* This class intercepts calls to the OAICore to measure its execution time. It uses Spring AOP.
|
||||
*
|
||||
* @author alessia
|
||||
*/
|
||||
public class LogInterceptor extends CustomizableTraceInterceptor {
|
||||
|
||||
@Override
|
||||
protected void writeToLog(final Log logger, final String message, final Throwable ex) {
|
||||
if (ex != null) {
|
||||
logger.error(message, ex);
|
||||
} else {
|
||||
logger.debug(message);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isInterceptorEnabled(final MethodInvocation invocation, final Log logger) {
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
package eu.dnetlib.enabling.tools;
|
||||
|
||||
/**
|
||||
* Abstracts the creation of a resource identifier from xmldb file name and xmldb collection name.
|
||||
*
|
||||
* @author marko
|
||||
*
|
||||
*/
|
||||
public interface ResourceIdentifierComposer {
|
||||
/**
|
||||
* Create a resId from a xmldb filename and collection name.
|
||||
*
|
||||
* @param fileName
|
||||
* @param coll
|
||||
* @return
|
||||
*/
|
||||
String createResourceId(final String fileName, final String coll);
|
||||
}
|
|
@ -0,0 +1,161 @@
|
|||
package eu.dnetlib.enabling.tools;
|
||||
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.File;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
|
||||
import eu.dnetlib.enabling.is.sn.rmi.ISSNService;
|
||||
import eu.dnetlib.enabling.is.store.rmi.ISStoreException;
|
||||
import eu.dnetlib.enabling.is.store.rmi.ISStoreService;
|
||||
|
||||
/**
|
||||
*
|
||||
* TODO: document. TODO: Too low level, why the interfacing the Store and not the Registry ?
|
||||
*
|
||||
* @author michele
|
||||
*
|
||||
*/
|
||||
public class ResourceType {
|
||||
|
||||
/**
|
||||
* xmldb collection where resource types are stored.
|
||||
*/
|
||||
public static final String RESOURCE_TYPES = "DRIVERResourceTypes";
|
||||
|
||||
/**
|
||||
* resource type. (Including kind?)
|
||||
*/
|
||||
private String resourceType; // NOPMD
|
||||
|
||||
/**
|
||||
* resource schema. (Body?)
|
||||
*/
|
||||
private String resourceSchema; // NOPMD
|
||||
/**
|
||||
* file where a copy of the schema is stored locally TODO: why ?
|
||||
*/
|
||||
private File fileSchema;
|
||||
|
||||
/**
|
||||
* instanciate an already registered resource type, fetching it from the store.
|
||||
*
|
||||
* @param resourceType
|
||||
* resourceType name
|
||||
* @param store
|
||||
* store service where the type is stored
|
||||
* @param basedir
|
||||
* base dir where a local copy is held (why?)
|
||||
* @throws ISStoreException
|
||||
* happens
|
||||
*/
|
||||
public ResourceType(final String resourceType, final ISStoreService store, final String basedir) throws ISStoreException {
|
||||
this(resourceType, store.getXML(resourceType, RESOURCE_TYPES), basedir);
|
||||
}
|
||||
|
||||
/**
|
||||
* construct a resource type.
|
||||
*
|
||||
* @param resourceType
|
||||
* resourceType name
|
||||
* @param resourceSchema
|
||||
* resourceSchema xsd body
|
||||
* @param basedir
|
||||
* base directory of some local copy (?)
|
||||
* @throws ISStoreException
|
||||
* happens
|
||||
*/
|
||||
public ResourceType(final String resourceType, final String resourceSchema, final String basedir) throws ISStoreException {
|
||||
this.resourceType = resourceType;
|
||||
this.resourceSchema = resourceSchema;
|
||||
if (basedir != null)
|
||||
this.fileSchema = saveSchemaAsFile(basedir);
|
||||
}
|
||||
|
||||
/**
|
||||
* stores the schema on the xmldb.
|
||||
*
|
||||
* @param store
|
||||
* store service
|
||||
* @throws ISStoreException
|
||||
* happens
|
||||
*/
|
||||
public void store(final ISStoreService store) throws ISStoreException {
|
||||
store.insertXML(resourceType, RESOURCE_TYPES, resourceSchema);
|
||||
}
|
||||
|
||||
/**
|
||||
* updates the in memory resource instance from the store.
|
||||
*
|
||||
* @param store store service
|
||||
* @throws ISStoreException happens
|
||||
*/
|
||||
public void update(final ISStoreService store) throws ISStoreException {
|
||||
store.updateXML(resourceType, RESOURCE_TYPES, resourceSchema);
|
||||
}
|
||||
|
||||
/**
|
||||
* save the schema to a file.
|
||||
*
|
||||
* @param basedir
|
||||
* base directory
|
||||
* @return the newly created file
|
||||
* @throws ISStoreException
|
||||
* happens, even if the file cannot be created.
|
||||
*/
|
||||
private File saveSchemaAsFile(final String basedir) throws ISStoreException {
|
||||
fileSchema = new File(basedir + "/" + resourceType);
|
||||
if (!fileSchema.exists()) {
|
||||
try {
|
||||
final BufferedWriter out = new BufferedWriter(new FileWriter(fileSchema));
|
||||
out.write(resourceSchema);
|
||||
out.close();
|
||||
} catch (IOException e) {
|
||||
throw new ISStoreException("Error saving file", e);
|
||||
}
|
||||
}
|
||||
return fileSchema;
|
||||
}
|
||||
|
||||
/**
|
||||
* it says "delete and notify" but it only deletes the schema from the filesystem and from the store.
|
||||
*
|
||||
* TODO: document and possibly refactor.
|
||||
*
|
||||
* @param store
|
||||
* store service
|
||||
* @param issn
|
||||
* ISSN service
|
||||
* @throws ISStoreException
|
||||
* happens
|
||||
*/
|
||||
public void deleteAndNotify(final ISStoreService store, final ISSNService issn) throws ISStoreException {
|
||||
fileSchema.delete();
|
||||
store.deleteXML(resourceType, RESOURCE_TYPES);
|
||||
}
|
||||
|
||||
public String getResourceType() {
|
||||
return resourceType;
|
||||
}
|
||||
|
||||
public void setResourceType(final String resourceType) {
|
||||
this.resourceType = resourceType;
|
||||
}
|
||||
|
||||
public String getResourceSchema() {
|
||||
return resourceSchema;
|
||||
}
|
||||
|
||||
public void setResourceSchema(final String resourceSchema) {
|
||||
this.resourceSchema = resourceSchema;
|
||||
}
|
||||
|
||||
public File getFileSchema() {
|
||||
return fileSchema;
|
||||
}
|
||||
|
||||
public void setFileSchema(final File fileSchema) {
|
||||
this.fileSchema = fileSchema;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
package eu.dnetlib.enabling.tools;
|
||||
|
||||
|
||||
/**
|
||||
* Standard DNet-1.0 compat xquery utils.
|
||||
*
|
||||
* @author marko
|
||||
*
|
||||
*/
|
||||
public class XQueryUtilsImpl implements XQueryUtils {
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* @see eu.dnetlib.enabling.tools.XQueryUtils#getCollectionAbsPath(eu.dnetlib.enabling.tools.OpaqueResource)
|
||||
*/
|
||||
@Override
|
||||
public String getCollectionAbsPath(final OpaqueResource resource) {
|
||||
return getRootCollection() + getCollectionPath(resource);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* @see eu.dnetlib.enabling.tools.XQueryUtils#getCollectionPath(eu.dnetlib.enabling.tools.OpaqueResource)
|
||||
*/
|
||||
@Override
|
||||
public String getCollectionPath(final OpaqueResource resource) {
|
||||
final StringBuilder buffer = new StringBuilder();
|
||||
buffer.append(resource.getResourceKind());
|
||||
buffer.append('/');
|
||||
buffer.append(resource.getResourceType());
|
||||
return buffer.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* @see eu.dnetlib.enabling.tools.XQueryUtils#getRootCollection()
|
||||
*/
|
||||
@Override
|
||||
public String getRootCollection() {
|
||||
return "/db/DRIVER/";
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* @see eu.dnetlib.enabling.tools.XQueryUtils#getFileName(eu.dnetlib.enabling.tools.OpaqueResource)
|
||||
*/
|
||||
@Override
|
||||
public String getFileName(final OpaqueResource resource) {
|
||||
return resource.getResourceId().split("_")[0];
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
package eu.dnetlib.xml.database;
|
||||
|
||||
/**
|
||||
* most trigger will hold the trigger name in an instance variable.
|
||||
*
|
||||
* The Trigger contract requires a getter (getName()). This class implements the setter too.
|
||||
*
|
||||
* @author marko
|
||||
*
|
||||
*/
|
||||
public abstract class AbstractTrigger implements Trigger {
|
||||
|
||||
/**
|
||||
* trigger name.
|
||||
*/
|
||||
private String name;
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(final String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
package eu.dnetlib.xml.database;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.w3c.dom.Document;
|
||||
|
||||
/**
|
||||
* This trigger simply logs all xmldb CRUDE events.
|
||||
*
|
||||
* @author marko
|
||||
*
|
||||
*/
|
||||
public class LoggingTrigger extends AbstractTrigger {
|
||||
/**
|
||||
* logger.
|
||||
*/
|
||||
private static final Log log = LogFactory.getLog(LoggingTrigger.class); // NOPMD by marko on 11/24/08 5:02 PM
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* @see eu.dnetlib.xml.database.Trigger#created(java.lang.String, java.lang.String, org.w3c.dom.Document)
|
||||
*/
|
||||
@Override
|
||||
public void created(final String file, final String collection, final Document newDoc) {
|
||||
log.info("xml resource created: " + collection + "/" + file);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* @see eu.dnetlib.xml.database.Trigger#deleted(java.lang.String, java.lang.String, org.w3c.dom.Document)
|
||||
*/
|
||||
@Override
|
||||
public void deleted(final String file, final String collection, final Document oldDoc) {
|
||||
log.info("xml resource deleted: " + collection + "/" + file);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* @see eu.dnetlib.xml.database.Trigger#updated(java.lang.String, java.lang.String, org.w3c.dom.Document, org.w3c.dom.Document)
|
||||
*/
|
||||
@Override
|
||||
public void updated(final String file, final String collection, final Document oldDoc, final Document newDoc) {
|
||||
log.info("xml resource updated: " + collection + "/" + file);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
package eu.dnetlib.xml.database;
|
||||
|
||||
import org.w3c.dom.Document;
|
||||
|
||||
/**
|
||||
* xml db trigger.
|
||||
*
|
||||
* @author marko
|
||||
*
|
||||
*/
|
||||
public interface Trigger {
|
||||
/**
|
||||
* each trigger has a user defined unique name.
|
||||
*
|
||||
* @return trigger name
|
||||
*/
|
||||
String getName();
|
||||
|
||||
/**
|
||||
* triggered when a new document is created.
|
||||
*
|
||||
* @param file
|
||||
* file name
|
||||
* @param collection
|
||||
* collection name
|
||||
* @param newDoc
|
||||
* newly created document
|
||||
*/
|
||||
void created(String file, String collection, Document newDoc);
|
||||
|
||||
/**
|
||||
* triggered when a document is updated.
|
||||
*
|
||||
* @param file
|
||||
* file name
|
||||
* @param collection
|
||||
* collection name
|
||||
* @param oldDoc
|
||||
* old version
|
||||
* @param newDoc
|
||||
* new version
|
||||
*/
|
||||
void updated(String file, String collection, Document oldDoc, Document newDoc);
|
||||
|
||||
/**
|
||||
* triggered when a document is deleted.
|
||||
*
|
||||
* @param file
|
||||
* file name
|
||||
* @param collection
|
||||
* collection name
|
||||
* @param oldDoc
|
||||
* deleted document
|
||||
*/
|
||||
void deleted(String file, String collection, Document oldDoc);
|
||||
}
|
|
@ -0,0 +1,175 @@
|
|||
package eu.dnetlib.xml.database;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import org.exist.util.DatabaseConfigurationException;
|
||||
import org.xmldb.api.base.XMLDBException;
|
||||
|
||||
/**
|
||||
* xmldb API is ugly.
|
||||
*
|
||||
* This is a thin wrapper to the xmldb API with focus on the primary operations used by dnet
|
||||
*
|
||||
* @author marko
|
||||
*
|
||||
*/
|
||||
public interface XMLDatabase { // NOPMD
|
||||
/**
|
||||
* creates a new resource or updates the resource if it already exists.
|
||||
*
|
||||
* @param name
|
||||
* file name
|
||||
* @param collection
|
||||
* collection name
|
||||
* @param content
|
||||
* serialized xml string
|
||||
* @throws XMLDBException
|
||||
* happens
|
||||
*/
|
||||
void create(String name, String collection, String content) throws XMLDBException;
|
||||
|
||||
/**
|
||||
* updates and already existing resource.
|
||||
*
|
||||
* @param name
|
||||
* file name
|
||||
* @param collection
|
||||
* collection name
|
||||
* @param content
|
||||
* serialized xml string
|
||||
* @throws XMLDBException
|
||||
* fails if the resource doesn't exist
|
||||
*/
|
||||
void update(String name, String collection, String content) throws XMLDBException;
|
||||
|
||||
/**
|
||||
* removes a resource.
|
||||
*
|
||||
* @param name
|
||||
* file name
|
||||
* @param collection
|
||||
* collection name
|
||||
* @return false if the resource doesn't exist
|
||||
* @throws XMLDBException
|
||||
* could happen
|
||||
*/
|
||||
boolean remove(String name, String collection) throws XMLDBException;
|
||||
|
||||
/**
|
||||
* read a resource string xml.
|
||||
*
|
||||
* @param name
|
||||
* file name
|
||||
* @param collection
|
||||
* collection name
|
||||
* @return null if the resource doesn't exist, otherwise it returns the xml string serialization
|
||||
* @throws XMLDBException
|
||||
* happens
|
||||
*/
|
||||
String read(String name, String collection) throws XMLDBException;
|
||||
|
||||
/**
|
||||
* Execute an xquery.
|
||||
*
|
||||
* @param xquery
|
||||
* xquery source
|
||||
* @return a xmldb resultset object
|
||||
* @throws XMLDBException
|
||||
* happens
|
||||
*/
|
||||
Iterator<String> xquery(String xquery) throws XMLDBException;
|
||||
|
||||
/**
|
||||
* creates a new collection, non recursively.
|
||||
*
|
||||
* @param collection
|
||||
* collection name
|
||||
* @throws XMLDBException
|
||||
* happens
|
||||
*/
|
||||
void createCollection(String collection) throws XMLDBException;
|
||||
|
||||
|
||||
/**
|
||||
* remove a collection.
|
||||
*
|
||||
* @param collection
|
||||
* collection name
|
||||
* @throws XMLDBException
|
||||
* happens also when the collection doesn't eXist
|
||||
*/
|
||||
void removeCollection(String collection) throws XMLDBException;
|
||||
|
||||
void xupdate(String query) throws XMLDBException;
|
||||
|
||||
/**
|
||||
* check whether a collection exists.
|
||||
*
|
||||
* @param collection
|
||||
* collection name
|
||||
* @return true if the collection exists
|
||||
* @throws XMLDBException
|
||||
* happens
|
||||
*/
|
||||
boolean collectionExists(String collection) throws XMLDBException;
|
||||
|
||||
/**
|
||||
* lists child collections.
|
||||
*
|
||||
* @param collection
|
||||
* parent collections
|
||||
* @return list of collection names
|
||||
* @throws XMLDBException
|
||||
* happens
|
||||
*/
|
||||
List<String> listChildCollections(String collection) throws XMLDBException;
|
||||
|
||||
/**
|
||||
* list the content of a collection.
|
||||
*
|
||||
* @param collection
|
||||
* parent collection
|
||||
* @return list of resource names
|
||||
* @throws XMLDBException
|
||||
* happens
|
||||
*/
|
||||
List<String> list(String collection) throws XMLDBException;
|
||||
|
||||
/**
|
||||
* returns the name of the root collection.
|
||||
*
|
||||
* @return collection name
|
||||
*/
|
||||
String getRootCollection();
|
||||
|
||||
/**
|
||||
* register a new trigger on a collection.
|
||||
*
|
||||
* @param trigger
|
||||
* trigger instance
|
||||
* @param collection
|
||||
* collection pattern
|
||||
* @throws XMLDBException
|
||||
* happens
|
||||
*/
|
||||
void registerTrigger(Trigger trigger, String collection) throws XMLDBException;
|
||||
|
||||
|
||||
/**
|
||||
* make a backup of entire database.
|
||||
*
|
||||
* @throws XMLDBException could happen
|
||||
* @throws DatabaseConfigurationException could happen
|
||||
* @return the path in which the Backup has been saved
|
||||
*/
|
||||
String backup() throws XMLDBException, DatabaseConfigurationException;
|
||||
|
||||
/**
|
||||
* Return the dir that contains all backups.
|
||||
*
|
||||
* @return the path in which the Backup has been saved
|
||||
*/
|
||||
String getBackupDir();
|
||||
|
||||
}
|
|
@ -0,0 +1,197 @@
|
|||
package eu.dnetlib.xml.database.exist;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import eu.dnetlib.miscutils.functional.xml.IndentXmlString;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.exist.collections.Collection;
|
||||
import org.exist.collections.triggers.SAXTrigger;
|
||||
import org.exist.collections.triggers.TriggerException;
|
||||
import org.exist.dom.persistent.DocumentImpl;
|
||||
import org.exist.storage.DBBroker;
|
||||
import org.exist.storage.txn.Txn;
|
||||
import org.exist.xmldb.XmldbURI;
|
||||
|
||||
import eu.dnetlib.xml.database.Trigger;
|
||||
|
||||
/**
|
||||
* this trigger delegates diffs for CRUDE events to an non-exist dependent eu.dnetlib.xml.database.Trigger instance.
|
||||
*
|
||||
* Since eXist triggers are instantiated by eXist, we need to locate the Trigger instances which are registered to the database instance.
|
||||
*
|
||||
* @author marko
|
||||
*
|
||||
*/
|
||||
public class DelegatingDiffTrigger extends SAXTrigger {
|
||||
|
||||
/**
|
||||
* logger.
|
||||
*/
|
||||
private static final Log log = LogFactory.getLog(DelegatingDiffTrigger.class); // NOPMD by marko on 11/24/08 5:02 PM
|
||||
|
||||
/**
|
||||
* trigger identifier, from configuration.
|
||||
*/
|
||||
private String triggerName;
|
||||
|
||||
private Map<String, ExistsTriggerEvent> existsTriggerEventMap = new HashMap<>();
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @see org.exist.collections.triggers.FilteringTrigger#configure(org.exist.storage.DBBroker, org.exist.collections.Collection,
|
||||
* java.util.Map)
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public void configure(final DBBroker dbBroker, final Collection parent, final Map<String, List<?>> parameters) throws TriggerException {
|
||||
super.configure(dbBroker, parent, parameters);
|
||||
|
||||
if (parameters == null) { return; }
|
||||
|
||||
final Map<String, List<?>> params = parameters;
|
||||
if (parameters.containsKey("triggerName")) {
|
||||
final List<?> myTriggerName = parameters.get("triggerName");
|
||||
if ((myTriggerName != null) && (myTriggerName.size() == 1)) {
|
||||
setTriggerName(myTriggerName.get(0).toString());
|
||||
}
|
||||
}
|
||||
if (getTriggerName() == null) {
|
||||
log.fatal("trigger id not configured");
|
||||
throw new TriggerException("trigger name not configured");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* find the trigger instance associated with this delegation.
|
||||
*
|
||||
* @return trigger instance
|
||||
*/
|
||||
protected Trigger getTrigger() {
|
||||
final Trigger trigger = ExistTriggerRegistry.defaultInstance().getTrigger(getTriggerName());
|
||||
if (trigger == null) {
|
||||
log.fatal("no trigger " + triggerName + " but there is a registered callback for it");
|
||||
return null;
|
||||
}
|
||||
|
||||
return trigger;
|
||||
}
|
||||
|
||||
public String getTriggerName() {
|
||||
return triggerName;
|
||||
}
|
||||
|
||||
public void setTriggerName(final String triggerId) {
|
||||
triggerName = triggerId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beforeCreateDocument(final DBBroker dbBroker, final Txn txn, final XmldbURI xmldbURI) throws TriggerException {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterCreateDocument(final DBBroker dbBroker, final Txn txn, final DocumentImpl document) throws TriggerException {
|
||||
|
||||
try {
|
||||
final Trigger trigger = getTrigger();
|
||||
final String collection = document.getCollection().getURI().toString();
|
||||
final String fileName = document.getFileURI().toString();
|
||||
if (trigger != null) {
|
||||
trigger.created(fileName, collection, document);
|
||||
}
|
||||
} catch (final Exception e) {
|
||||
throw new TriggerException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beforeUpdateDocument(final DBBroker dbBroker, final Txn txn, final DocumentImpl document) throws TriggerException {
|
||||
|
||||
try {
|
||||
final String collection = document.getCollection().getURI().toString();
|
||||
final String fileName = document.getFileURI().toString();
|
||||
final ExistsTriggerEvent event = new ExistsTriggerEvent();
|
||||
event.setOldDocument(IndentXmlString.apply(document));
|
||||
event.setEventType(EventType.UPDATE);
|
||||
event.setCollection(collection);
|
||||
event.setName(fileName);
|
||||
existsTriggerEventMap.put(String.valueOf(txn.getId()), event);
|
||||
} catch (final Exception e) {
|
||||
throw new TriggerException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterUpdateDocument(final DBBroker dbBroker, final Txn txn, final DocumentImpl document) throws TriggerException {
|
||||
|
||||
try {
|
||||
if (!existsTriggerEventMap.containsKey(
|
||||
String.valueOf(txn.getId()))) { throw new TriggerException("Error on trigger missing previous operation beforeUpdateTrigger"); }
|
||||
final ExistsTriggerEvent existsTriggerEvent = existsTriggerEventMap.remove(String.valueOf(txn.getId()));
|
||||
|
||||
existsTriggerEvent.setDocument(IndentXmlString.apply(document));
|
||||
final Trigger trigger = getTrigger();
|
||||
if (trigger != null) {
|
||||
trigger.updated(existsTriggerEvent.getName(), existsTriggerEvent.getCollection(), existsTriggerEvent.getOldDocument(),
|
||||
existsTriggerEvent.getDocument());
|
||||
}
|
||||
} catch (final Exception e) {
|
||||
throw new TriggerException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beforeUpdateDocumentMetadata(final DBBroker dbBroker, final Txn txn, final DocumentImpl document) throws TriggerException {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterUpdateDocumentMetadata(final DBBroker dbBroker, final Txn txn, final DocumentImpl document) throws TriggerException {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beforeCopyDocument(final DBBroker dbBroker, final Txn txn, final DocumentImpl document, final XmldbURI xmldbURI) throws TriggerException {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterCopyDocument(final DBBroker dbBroker, final Txn txn, final DocumentImpl document, final XmldbURI xmldbURI) throws TriggerException {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beforeMoveDocument(final DBBroker dbBroker, final Txn txn, final DocumentImpl document, final XmldbURI xmldbURI) throws TriggerException {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterMoveDocument(final DBBroker dbBroker, final Txn txn, final DocumentImpl document, final XmldbURI xmldbURI) throws TriggerException {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beforeDeleteDocument(final DBBroker dbBroker, final Txn txn, final DocumentImpl document) throws TriggerException {
|
||||
|
||||
try {
|
||||
final Trigger trigger = getTrigger();
|
||||
final String collection = document.getCollection().getURI().toString();
|
||||
final String fileName = document.getFileURI().toString();
|
||||
if (trigger != null) {
|
||||
trigger.deleted(fileName, collection, IndentXmlString.apply(document));
|
||||
}
|
||||
} catch (final Exception e) {
|
||||
throw new TriggerException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterDeleteDocument(final DBBroker dbBroker, final Txn txn, final XmldbURI xmldbURI) throws TriggerException {
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
package eu.dnetlib.xml.database.exist;
|
||||
|
||||
/**
|
||||
* Created by claudio on 20/12/2016.
|
||||
*/
|
||||
public enum EventType {
|
||||
UPDATE,
|
||||
CREATE,
|
||||
DELETE
|
||||
}
|
|
@ -0,0 +1,82 @@
|
|||
package eu.dnetlib.xml.database.exist;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.StringReader;
|
||||
import java.io.StringWriter;
|
||||
|
||||
import javax.xml.parsers.DocumentBuilder;
|
||||
import javax.xml.parsers.DocumentBuilderFactory;
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
|
||||
import org.apache.xml.serialize.OutputFormat;
|
||||
import org.apache.xml.serialize.XMLSerializer;
|
||||
import org.w3c.dom.Document;
|
||||
import org.xml.sax.InputSource;
|
||||
import org.xml.sax.SAXException;
|
||||
|
||||
/**
|
||||
* Exist has an internal DOM implementation.
|
||||
*
|
||||
* @author marko
|
||||
*
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
public class ExistDOMConverter {
|
||||
|
||||
/**
|
||||
* convert a DOM document to InputSource on which you can run an XPath.
|
||||
*
|
||||
* The internal eXist DOM implementation has some problems.
|
||||
*
|
||||
* @param input
|
||||
* DOM document
|
||||
* @return sax input source
|
||||
* @throws IOException
|
||||
* happens ?
|
||||
*/
|
||||
public InputSource asInputSource(final Document input) throws IOException {
|
||||
return new InputSource(new StringReader(asString(input)));
|
||||
}
|
||||
|
||||
/**
|
||||
* serialize a dom document to a string.
|
||||
*
|
||||
* TODO: avoid using deprecated XMLSerializer
|
||||
*
|
||||
* cannot use Transformer because eXist DOM impl is incomplete.
|
||||
*
|
||||
* @param input
|
||||
* DOM document
|
||||
* @return sax input source
|
||||
* @throws IOException
|
||||
* happens ?
|
||||
*/
|
||||
|
||||
public String asString(final Document input) throws IOException {
|
||||
final StringWriter writer = new StringWriter();
|
||||
|
||||
new XMLSerializer(writer, new OutputFormat()).serialize(input.getDocumentElement());
|
||||
|
||||
return writer.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* convert a DOM document to a w3c DOM Document on which you can run an XPath.
|
||||
*
|
||||
* The internal eXist DOM implementation has some problems.
|
||||
*
|
||||
* @param input
|
||||
* input eXist DOM document
|
||||
* @return good DOM document
|
||||
* @throws IOException
|
||||
* happens
|
||||
* @throws ParserConfigurationException
|
||||
* happens
|
||||
* @throws SAXException
|
||||
* happens
|
||||
*/
|
||||
public Document asDocument(final Document input) throws IOException, ParserConfigurationException, SAXException {
|
||||
final DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
|
||||
return builder.parse(asInputSource(input));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,635 @@
|
|||
package eu.dnetlib.xml.database.exist; // NOPMD
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.*;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipOutputStream;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.exist.collections.CollectionConfiguration;
|
||||
import org.exist.util.DatabaseConfigurationException;
|
||||
import org.exist.xmldb.DatabaseImpl;
|
||||
import org.exist.xmldb.DatabaseInstanceManager;
|
||||
import org.exist.xmldb.EXistResource;
|
||||
import org.exist.xmldb.XmldbURI;
|
||||
import org.springframework.beans.factory.annotation.Required;
|
||||
import org.springframework.context.Lifecycle;
|
||||
import org.xmldb.api.DatabaseManager;
|
||||
import org.xmldb.api.base.*;
|
||||
import org.xmldb.api.base.Collection;
|
||||
import org.xmldb.api.modules.CollectionManagementService;
|
||||
import org.xmldb.api.modules.XPathQueryService;
|
||||
|
||||
import eu.dnetlib.miscutils.datetime.DateUtils;
|
||||
import eu.dnetlib.xml.database.Trigger;
|
||||
|
||||
import eu.dnetlib.xml.database.XMLDatabase;
|
||||
|
||||
/**
|
||||
* eXist database wrapper.
|
||||
*
|
||||
* @author marko
|
||||
*
|
||||
*/
|
||||
public class ExistDatabase implements XMLDatabase, Lifecycle { // NOPMD by marko
|
||||
|
||||
/**
|
||||
* logger.
|
||||
*/
|
||||
private static final Log log = LogFactory.getLog(ExistDatabase.class); // NOPMD
|
||||
|
||||
/**
|
||||
* eXist collection configuration special file.
|
||||
*/
|
||||
public static final String COLLECTION_XCONF = "collection.xconf";
|
||||
|
||||
/**
|
||||
* exist xml resource type code.
|
||||
*/
|
||||
private static final String XMLRESOURCE = "XMLResource";
|
||||
|
||||
/**
|
||||
* collection name to trigger instance map.
|
||||
*
|
||||
* all triggers declared here will be registered at startup.
|
||||
*
|
||||
*/
|
||||
private Map<String, Trigger> triggerConf = new HashMap<>();
|
||||
|
||||
private final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
|
||||
|
||||
private final Lock readLock = rwl.readLock();
|
||||
|
||||
private final Lock writeLock = rwl.writeLock();
|
||||
|
||||
/**
|
||||
* eXist database.
|
||||
*/
|
||||
private Database database;
|
||||
|
||||
/**
|
||||
* eXist collection.
|
||||
*/
|
||||
private Collection root;
|
||||
/**
|
||||
* eXist database manager.
|
||||
*/
|
||||
private DatabaseInstanceManager manager;
|
||||
/**
|
||||
* eXist xpath service.
|
||||
*/
|
||||
private XPathQueryService queryService;
|
||||
/**
|
||||
* eXist collection manager.
|
||||
*/
|
||||
private CollectionManagementService colman;
|
||||
/**
|
||||
* eXist configuration file.
|
||||
*/
|
||||
private String configFile;
|
||||
|
||||
/**
|
||||
* Directory in which backups are saved.
|
||||
*/
|
||||
private String backupDir;
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @see org.springframework.context.Lifecycle#start()
|
||||
*/
|
||||
@Override
|
||||
public void start() {
|
||||
log.info("starting database");
|
||||
try {
|
||||
if (getDatabase() == null) {
|
||||
setDatabase(new DatabaseImpl());
|
||||
getDatabase().setProperty("configuration", getConfigFile());
|
||||
getDatabase().setProperty("create-database", "true");
|
||||
}
|
||||
|
||||
DatabaseManager.registerDatabase(getDatabase());
|
||||
|
||||
setRoot(DatabaseManager.getCollection("xmldb:exist://" + getRootCollection(), "admin", ""));
|
||||
setManager((DatabaseInstanceManager) getRoot().getService("DatabaseInstanceManager", "1.0"));
|
||||
setQueryService((XPathQueryService) getRoot().getService("XPathQueryService", "1.0"));
|
||||
setColman((CollectionManagementService) getRoot().getService("CollectionManagementService", "1.0"));
|
||||
|
||||
for (final Entry<String, Trigger> entry : getTriggerConf().entrySet())
|
||||
registerTrigger(entry.getValue(), entry.getKey());
|
||||
|
||||
} catch (final XMLDBException e) {
|
||||
throw new IllegalStateException("cannot open eXist database", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* helper method.
|
||||
*
|
||||
* @param collection
|
||||
* collection name
|
||||
* @return an eXist collection
|
||||
* @throws XMLDBException
|
||||
* happens
|
||||
*/
|
||||
protected Collection getCollection(final String collection) throws XMLDBException {
|
||||
readLock.lock();
|
||||
try {
|
||||
if (!collection.startsWith("/db"))
|
||||
throw new XMLDBException(0, "collection path should begin with /db");
|
||||
return database.getCollection("exist://" + collection, "admin", "");
|
||||
}finally {
|
||||
readLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @see eu.dnetlib.xml.database.XMLDatabase#create(java.lang.String, java.lang.String, java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public void create(final String name, final String collection, final String content) throws XMLDBException {
|
||||
writeLock.lock();
|
||||
try {
|
||||
if ("".equals(name))
|
||||
throw new XMLDBException(0, "cannot create a xml file with an empty file name");
|
||||
|
||||
Collection col = getCollection(collection);
|
||||
|
||||
if (col == null) {
|
||||
// create parent collections
|
||||
createCollection(collection, true);
|
||||
col = getCollection(collection);
|
||||
}
|
||||
|
||||
final Resource res = col.createResource(name, XMLRESOURCE);
|
||||
res.setContent(content);
|
||||
col.storeResource(res);
|
||||
|
||||
((EXistResource) res).freeResources();
|
||||
col.close();
|
||||
}finally {
|
||||
writeLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @see eu.dnetlib.xml.database.XMLDatabase#remove(java.lang.String, java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public boolean remove(final String name, final String collection) throws XMLDBException {
|
||||
writeLock.lock();
|
||||
try {
|
||||
final Collection col = getCollection(collection);
|
||||
|
||||
final Resource res = col.getResource(name);
|
||||
if (res == null)
|
||||
return false;
|
||||
|
||||
col.removeResource(res);
|
||||
col.close();
|
||||
return true;
|
||||
} finally {
|
||||
writeLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @see eu.dnetlib.xml.database.XMLDatabase#update(java.lang.String, java.lang.String, java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public void update(final String name, final String collection, final String content) throws XMLDBException {
|
||||
writeLock.lock();
|
||||
try{
|
||||
final Collection col = getCollection(collection);
|
||||
|
||||
final Resource res = col.getResource(name);
|
||||
if (res == null) {
|
||||
throw new XMLDBException(0, "resource doesn't exist");
|
||||
}
|
||||
res.setContent(content);
|
||||
col.storeResource(res);
|
||||
((EXistResource) res).freeResources();
|
||||
col.close();
|
||||
} finally {
|
||||
writeLock.unlock();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @see eu.dnetlib.xml.database.XMLDatabase#read(java.lang.String, java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public String read(final String name, final String collection) throws XMLDBException {
|
||||
readLock.lock();
|
||||
try {
|
||||
Resource res = null;
|
||||
final Collection coll = getCollection(collection);
|
||||
try {
|
||||
if (coll == null)
|
||||
return null;
|
||||
res = coll.getResource(name);
|
||||
if (res != null)
|
||||
return (String) res.getContent();
|
||||
return null;
|
||||
} finally {
|
||||
if (res != null)
|
||||
((EXistResource) res).freeResources();
|
||||
coll.close();
|
||||
}
|
||||
}finally {
|
||||
readLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @see eu.dnetlib.xml.database.XMLDatabase#xquery(java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public Iterator<String> xquery(final String query) throws XMLDBException {
|
||||
readLock.lock();
|
||||
try {
|
||||
final ResourceSet result = getQueryService().query(query);
|
||||
if (result == null)
|
||||
return null;
|
||||
final ResourceIterator iterator = result.getIterator();
|
||||
return new Iterator<String>() {
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
try {
|
||||
return iterator.hasMoreResources();
|
||||
} catch (XMLDBException e) {
|
||||
throw new RuntimeException("Error while getting next element", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String next() {
|
||||
Resource res = null;
|
||||
try {
|
||||
res = iterator.nextResource();
|
||||
return (String) res.getContent();
|
||||
} catch (XMLDBException e) {
|
||||
throw new RuntimeException("Error while getting next element", e);
|
||||
} finally {
|
||||
if (res != null)
|
||||
try {
|
||||
((EXistResource) res).freeResources();
|
||||
} catch (XMLDBException e) {
|
||||
log.error("error on free resource");
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
} finally {
|
||||
readLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void xupdate(final String query) throws XMLDBException {
|
||||
writeLock.lock();
|
||||
try{
|
||||
getQueryService().query(query);
|
||||
} finally {
|
||||
writeLock.unlock();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @see org.springframework.context.Lifecycle#stop()
|
||||
*/
|
||||
@Override
|
||||
public void stop() {
|
||||
// no operation
|
||||
try {
|
||||
getManager().shutdown();
|
||||
DatabaseManager.deregisterDatabase(database);
|
||||
} catch (final XMLDBException e) {
|
||||
log.fatal("cannot close database", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @see eu.dnetlib.xml.database.XMLDatabase#collectionExists(java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public boolean collectionExists(final String collection) throws XMLDBException {
|
||||
Collection col = null;
|
||||
try{
|
||||
col = getCollection(collection);
|
||||
return col != null;
|
||||
} finally {
|
||||
if (col!=null)
|
||||
col.close();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @see eu.dnetlib.xml.database.XMLDatabase#createCollection(java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public void createCollection(final String collection) throws XMLDBException {
|
||||
writeLock.lock();
|
||||
try {
|
||||
createCollection(collection, false);
|
||||
}finally {
|
||||
writeLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
private void createCollection(final String collection, final boolean recursive) throws XMLDBException {
|
||||
if (recursive) {
|
||||
final XmldbURI uri = XmldbURI.create(collection).removeLastSegment();
|
||||
if (!collectionExists(uri.toString()))
|
||||
createCollection(uri.toString(), true);
|
||||
}
|
||||
getColman().createCollection(collection);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @see eu.dnetlib.xml.database.XMLDatabase#removeCollection(java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public void removeCollection(final String collection) throws XMLDBException {
|
||||
writeLock.lock();
|
||||
try {
|
||||
getColman().removeCollection(collection);
|
||||
}finally {
|
||||
writeLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public String getConfigFile() {
|
||||
return configFile;
|
||||
}
|
||||
|
||||
public void setConfigFile(final String configFile) {
|
||||
this.configFile = configFile;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String getBackupDir() {
|
||||
return backupDir;
|
||||
}
|
||||
|
||||
@Required
|
||||
public void setBackupDir(final String backupDir) {
|
||||
this.backupDir = backupDir;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @see org.springframework.context.Lifecycle#isRunning() useless contract with spring.
|
||||
*
|
||||
*/
|
||||
@Override
|
||||
public boolean isRunning() {
|
||||
return false;
|
||||
}
|
||||
|
||||
protected Database getDatabase() {
|
||||
return database;
|
||||
}
|
||||
|
||||
protected void setDatabase(final Database database) {
|
||||
this.database = database;
|
||||
}
|
||||
|
||||
protected Collection getRoot() {
|
||||
return root;
|
||||
}
|
||||
|
||||
protected void setRoot(final Collection root) {
|
||||
this.root = root;
|
||||
}
|
||||
|
||||
protected DatabaseInstanceManager getManager() {
|
||||
return manager;
|
||||
}
|
||||
|
||||
protected void setManager(final DatabaseInstanceManager manager) {
|
||||
this.manager = manager;
|
||||
}
|
||||
|
||||
protected XPathQueryService getQueryService() {
|
||||
return queryService;
|
||||
}
|
||||
|
||||
protected void setQueryService(final XPathQueryService queryService) {
|
||||
this.queryService = queryService;
|
||||
}
|
||||
|
||||
protected CollectionManagementService getColman() {
|
||||
return colman;
|
||||
}
|
||||
|
||||
protected void setColman(final CollectionManagementService colman) {
|
||||
this.colman = colman;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRootCollection() {
|
||||
return "/db";
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @see eu.dnetlib.xml.database.XMLDatabase#listChildCollections(java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public List<String> listChildCollections(final String collection) throws XMLDBException {
|
||||
readLock.lock();
|
||||
try {
|
||||
final Collection col = getCollection(collection);
|
||||
if (col == null)
|
||||
return new ArrayList<>();
|
||||
return Arrays.asList(col.listChildCollections());
|
||||
} finally {
|
||||
readLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @see eu.dnetlib.xml.database.XMLDatabase#list(java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public List<String> list(final String collection) throws XMLDBException {
|
||||
readLock.lock();
|
||||
try {
|
||||
final Collection col = getCollection(collection);
|
||||
if(col == null)
|
||||
return new ArrayList();
|
||||
return Arrays.asList(col.listResources());
|
||||
} finally {
|
||||
readLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* sets an underlying eXist trigger class for a given collection.
|
||||
*
|
||||
* @param triggerClass
|
||||
* exist trigger class
|
||||
* @param collection
|
||||
* collection name
|
||||
* @param events
|
||||
* list of event names
|
||||
* @param parameters
|
||||
* parameter map
|
||||
* @throws XMLDBException
|
||||
* happens
|
||||
*/
|
||||
void setExistTrigger(final Class<?> triggerClass, final String collection, final List<String> events, final Map<String, String> parameters)
|
||||
throws XMLDBException {
|
||||
|
||||
// Arrays.asList(new String[] { "store", "update", "delete" }
|
||||
|
||||
final StringBuilder conf = new StringBuilder();
|
||||
conf.append("<exist:collection xmlns:exist=\"http://exist-db.org/collection-config/1.0\"><exist:triggers>");
|
||||
|
||||
final String className = triggerClass.getCanonicalName(); // PMD
|
||||
|
||||
conf.append("<exist:trigger event=\"store,update,remove\" class=\"" + className + "\">");
|
||||
if (parameters != null)
|
||||
for (final Entry<String, String> entry : parameters.entrySet())
|
||||
conf.append("<exist:parameter name=\"" + entry.getKey() + "\" value=\"" + entry.getValue() + "\"/>");
|
||||
conf.append("</exist:trigger>");
|
||||
|
||||
conf.append("</exist:triggers></exist:collection>");
|
||||
|
||||
log.info(conf.toString());
|
||||
createCollection("/db/system/config" + collection, true);
|
||||
create(CollectionConfiguration.DEFAULT_COLLECTION_CONFIG_FILE_URI.toString(), "/db/system/config" + collection, conf.toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @see eu.dnetlib.xml.database.XMLDatabase#registerTrigger(eu.dnetlib.xml.database.Trigger, java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public void registerTrigger(final Trigger trigger, final String collection) throws XMLDBException {
|
||||
final Map<String, String> params = new HashMap<String, String>();
|
||||
params.put("triggerName", trigger.getName());
|
||||
|
||||
ExistTriggerRegistry.defaultInstance().registerTrigger(trigger.getName(), trigger);
|
||||
|
||||
setExistTrigger(DelegatingDiffTrigger.class, collection, Arrays.asList("store", "update", "delete" ), params);
|
||||
}
|
||||
|
||||
public Map<String, Trigger> getTriggerConf() {
|
||||
return triggerConf;
|
||||
}
|
||||
|
||||
public void setTriggerConf(final Map<String, Trigger> triggerConf) {
|
||||
this.triggerConf = triggerConf;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @see eu.dnetlib.xml.database.XMLDatabase#backup()
|
||||
*/
|
||||
@Override
|
||||
public String backup() throws XMLDBException, DatabaseConfigurationException {
|
||||
log.info("Starting backup...");
|
||||
readLock.lock();
|
||||
try {
|
||||
verifyBackupDir();
|
||||
|
||||
String seq = (new SimpleDateFormat("yyyyMMdd-HHmm")).format(new Date());
|
||||
|
||||
ZipOutputStream zip = new ZipOutputStream(new FileOutputStream(backupDir + "/data-" + seq + ".zip"));
|
||||
|
||||
FileWriter logFile = new FileWriter(backupDir + "/report-" + seq + ".log");
|
||||
logFile.write("Backup started at: " + DateUtils.now_ISO8601() + "\n\n");
|
||||
|
||||
backup(getRoot().getName(), zip, logFile);
|
||||
|
||||
logFile.write("\nBackup finished at: " + DateUtils.now_ISO8601() + "\n");
|
||||
|
||||
logFile.flush();
|
||||
logFile.close();
|
||||
|
||||
zip.flush();
|
||||
zip.close();
|
||||
|
||||
log.info("Backup finished");
|
||||
return backupDir;
|
||||
} catch (final Exception e) {
|
||||
log.error("Backup failed", e);
|
||||
throw new XMLDBException(0, "cannot backup", e);
|
||||
}
|
||||
finally {
|
||||
readLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void verifyBackupDir() {
|
||||
File d = new File(backupDir);
|
||||
if (!d.exists()) d.mkdirs();
|
||||
}
|
||||
|
||||
private void backup(String coll, ZipOutputStream zip, FileWriter logFile) throws XMLDBException, IOException {
|
||||
readLock.lock();
|
||||
logFile.write("COLLECTION: " + coll + "\n");
|
||||
log.info("Backup of collection " + coll);
|
||||
try {
|
||||
for (String file : list(coll)) {
|
||||
zip.putNextEntry(new ZipEntry(coll + "/" + file + ".xml"));
|
||||
Resource resource = getCollection(coll).getResource(file);
|
||||
zip.write(resource.getContent().toString().getBytes());
|
||||
zip.closeEntry();
|
||||
}
|
||||
|
||||
for (String c : listChildCollections(coll)) {
|
||||
backup(coll + "/" + c, zip, logFile);
|
||||
}
|
||||
}finally {
|
||||
readLock.unlock();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,72 @@
|
|||
package eu.dnetlib.xml.database.exist;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import eu.dnetlib.xml.database.Trigger;
|
||||
|
||||
/**
|
||||
* eXist triggers are instantiated directly by the exist database via reflection.
|
||||
*
|
||||
* we need a way to manage trigger objects from outside, in order to manage them manage them from the IoC container.
|
||||
*
|
||||
* @author marko
|
||||
*
|
||||
*/
|
||||
public final class ExistTriggerRegistry {
|
||||
|
||||
/**
|
||||
* singleton object.
|
||||
*/
|
||||
private static ExistTriggerRegistry singleton = new ExistTriggerRegistry();
|
||||
|
||||
/**
|
||||
* get the singleton instance.
|
||||
*
|
||||
* @return singleton object
|
||||
*/
|
||||
public static ExistTriggerRegistry defaultInstance() {
|
||||
return singleton;
|
||||
}
|
||||
|
||||
/**
|
||||
* forbids instantiation.
|
||||
*/
|
||||
private ExistTriggerRegistry() {
|
||||
}
|
||||
|
||||
/**
|
||||
* maps trigger names to trigger instances.
|
||||
*/
|
||||
private Map<String, Trigger> triggerRegistry = new HashMap<String, Trigger>();
|
||||
|
||||
/**
|
||||
* get a trigger for a given id.
|
||||
*
|
||||
* @param triggerId trigger identifier
|
||||
* @return trigger instance
|
||||
*/
|
||||
public Trigger getTrigger(final String triggerId) {
|
||||
return getTriggerRegistry().get(triggerId);
|
||||
}
|
||||
|
||||
/**
|
||||
* associate a new trigger.
|
||||
*
|
||||
* @param name trigger name
|
||||
* @param trigger trigger instance
|
||||
*/
|
||||
public void registerTrigger(final String name, final Trigger trigger) {
|
||||
triggerRegistry.put(name, trigger);
|
||||
}
|
||||
|
||||
Map<String, Trigger> getTriggerRegistry() {
|
||||
return triggerRegistry;
|
||||
}
|
||||
|
||||
void setTriggerRegistry(final Map<String, Trigger> triggerRegistry) {
|
||||
this.triggerRegistry = triggerRegistry;
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,60 @@
|
|||
package eu.dnetlib.xml.database.exist;
|
||||
|
||||
import org.w3c.dom.Document;
|
||||
|
||||
/**
|
||||
* Created by sandro on 3/14/16.
|
||||
*/
|
||||
public class ExistsTriggerEvent {
|
||||
|
||||
private String collection;
|
||||
|
||||
private String name;
|
||||
|
||||
private EventType eventType;
|
||||
|
||||
private Document document;
|
||||
|
||||
private Document oldDocument;
|
||||
|
||||
|
||||
public String getCollection() {
|
||||
return collection;
|
||||
}
|
||||
|
||||
public void setCollection(final String collection) {
|
||||
this.collection = collection;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(final String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public EventType getEventType() {
|
||||
return eventType;
|
||||
}
|
||||
|
||||
public void setEventType(final EventType eventType) {
|
||||
this.eventType = eventType;
|
||||
}
|
||||
|
||||
public Document getDocument() {
|
||||
return document;
|
||||
}
|
||||
|
||||
public void setDocument(final Document document) {
|
||||
this.document = document;
|
||||
}
|
||||
|
||||
public Document getOldDocument() {
|
||||
return oldDocument;
|
||||
}
|
||||
|
||||
public void setOldDocument(final Document oldDocument) {
|
||||
this.oldDocument = oldDocument;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,207 @@
|
|||
package eu.dnetlib.xml.database.exist;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.FileReader;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.StringReader;
|
||||
import java.io.StringWriter;
|
||||
|
||||
import eu.dnetlib.enabling.is.store.BulkResourceImporter;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Required;
|
||||
|
||||
/**
|
||||
* Persistent exist.
|
||||
*
|
||||
* TODO: this is copy&paste from TemporaryExistDatase. Refactor common stuff.
|
||||
*
|
||||
* @author marko
|
||||
*
|
||||
*/
|
||||
public class PersistentExistDatabase extends ExistDatabase {
|
||||
|
||||
/**
|
||||
* logger.
|
||||
*/
|
||||
private static final Log log = LogFactory.getLog(PersistentExistDatabase.class); // NOPMD by marko on 11/24/08 5:02 PM
|
||||
|
||||
/**
|
||||
* db directory.
|
||||
*/
|
||||
private transient File dbDirectory;
|
||||
|
||||
/**
|
||||
* this config file will be copied to a newly created temporary directory.
|
||||
*/
|
||||
private String configTemplate = "default-exist-conf.xml";
|
||||
|
||||
/**
|
||||
* db root path.
|
||||
*/
|
||||
private String dbRootPath;
|
||||
|
||||
/**
|
||||
* bulk importer.
|
||||
*/
|
||||
@Autowired
|
||||
private BulkResourceImporter bulkImporter;
|
||||
|
||||
/**
|
||||
* exist config file.
|
||||
*/
|
||||
private File existConfigFile;
|
||||
|
||||
/**
|
||||
* true if the database permits execution of java code from xquery.
|
||||
*/
|
||||
private boolean XQueryJavaEnabled;
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @see eu.dnetlib.xml.database.exist.ExistDatabase#start()
|
||||
*/
|
||||
@Override
|
||||
public void start() {
|
||||
log.warn("STARTING PERSISTENT EXIST DATABASE");
|
||||
dbDirectory = new File(dbRootPath);
|
||||
|
||||
if (dbDirectory.exists()) {
|
||||
getBulkImporter().setEnabled(false);
|
||||
existConfigFile = new File(dbDirectory, "conf.xml");
|
||||
enableJava(existConfigFile, isXQueryJavaEnabled());
|
||||
setConfigFile(existConfigFile.getAbsolutePath());
|
||||
} else {
|
||||
createPersistentDatabase();
|
||||
}
|
||||
|
||||
super.start();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop() {
|
||||
log.info("shutting down xmldb");
|
||||
super.stop();
|
||||
log.info("xmldb closed");
|
||||
}
|
||||
|
||||
protected void enableJava(final File conf, final boolean enabled) {
|
||||
final StringWriter buffer = new StringWriter();
|
||||
if (conf.exists()) {
|
||||
try {
|
||||
IOUtils.copy(new FileReader(conf), buffer);
|
||||
final String newConf = patchConfigFileEnableJava(buffer.toString(), enabled);
|
||||
if (!newConf.equals(buffer.toString())) {
|
||||
FileWriter writer = new FileWriter(conf);
|
||||
try {
|
||||
IOUtils.copy(new StringReader(newConf), writer);
|
||||
} finally {
|
||||
writer.close();
|
||||
}
|
||||
}
|
||||
} catch (final FileNotFoundException e) {
|
||||
log.warn("cannot patch eXist conf file", e);
|
||||
} catch (final IOException e) {
|
||||
log.warn("cannot patch eXist conf file", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param conf
|
||||
* content of the configuration file
|
||||
* @param enabled
|
||||
* enabled or disabled
|
||||
* @return new conf file
|
||||
*/
|
||||
protected String patchConfigFileEnableJava(final String conf, final boolean enabled) {
|
||||
return conf.replaceAll("enable-java-binding=\"[^\"]*\"", "enable-java-binding=\"" + (enabled ? "yes" : "no") + "\"");
|
||||
}
|
||||
|
||||
/**
|
||||
* create a temporary directory and copy the default configuration file.
|
||||
*/
|
||||
protected void createPersistentDatabase() {
|
||||
log.debug("creating persistent database");
|
||||
try {
|
||||
new File(dbDirectory, "data").mkdirs();
|
||||
|
||||
final InputStream defaultConf = getClass().getResourceAsStream(getConfigTemplate());
|
||||
if (defaultConf == null)
|
||||
throw new IOException("cannot find " + getConfigTemplate());
|
||||
|
||||
existConfigFile = new File(dbDirectory, "conf.xml");
|
||||
final FileOutputStream confOutput = new FileOutputStream(existConfigFile);
|
||||
|
||||
try {
|
||||
IOUtils.copy(defaultConf, confOutput);
|
||||
} finally {
|
||||
confOutput.close();
|
||||
}
|
||||
enableJava(existConfigFile, isXQueryJavaEnabled());
|
||||
|
||||
setConfigFile(existConfigFile.getAbsolutePath());
|
||||
} catch (final IOException e) {
|
||||
log.fatal("creating database dir", e);
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
log.debug("created temp database");
|
||||
}
|
||||
|
||||
public File getDbDirectory() {
|
||||
return dbDirectory;
|
||||
}
|
||||
|
||||
public void setDbDirectory(final File dbDirectory) {
|
||||
this.dbDirectory = dbDirectory;
|
||||
}
|
||||
|
||||
public String getConfigTemplate() {
|
||||
return configTemplate;
|
||||
}
|
||||
|
||||
public void setConfigTemplate(final String configTemplate) {
|
||||
this.configTemplate = configTemplate;
|
||||
}
|
||||
|
||||
public BulkResourceImporter getBulkImporter() {
|
||||
return bulkImporter;
|
||||
}
|
||||
|
||||
public void setBulkImporter(final BulkResourceImporter bulkImporter) {
|
||||
this.bulkImporter = bulkImporter;
|
||||
}
|
||||
|
||||
public File getExistConfigFile() {
|
||||
return existConfigFile;
|
||||
}
|
||||
|
||||
public void setExistConfigFile(final File existConfigFile) {
|
||||
this.existConfigFile = existConfigFile;
|
||||
}
|
||||
|
||||
@Required
|
||||
public String getDbRootPath() {
|
||||
return dbRootPath;
|
||||
}
|
||||
|
||||
public void setDbRootPath(final String dbRootPath) {
|
||||
this.dbRootPath = dbRootPath;
|
||||
}
|
||||
|
||||
public boolean isXQueryJavaEnabled() {
|
||||
return XQueryJavaEnabled;
|
||||
}
|
||||
|
||||
public void setXQueryJavaEnabled(final boolean xQueryJavaEnabled) {
|
||||
XQueryJavaEnabled = xQueryJavaEnabled;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,106 @@
|
|||
package eu.dnetlib.xml.database.exist;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
/**
|
||||
* This class creates a temporary exist database instances.
|
||||
*
|
||||
* @author marko
|
||||
*
|
||||
*/
|
||||
public class TemporaryExistDatabase extends ExistDatabase {
|
||||
/**
|
||||
* logger.
|
||||
*/
|
||||
private static final Log log = LogFactory.getLog(TemporaryExistDatabase.class); // NOPMD by marko on 11/24/08 5:02 PM
|
||||
|
||||
/**
|
||||
* temporary directory. this way we won't delete other things on shutdown if somebody changes the configuration file
|
||||
* location with setConfigFile().
|
||||
*/
|
||||
private transient File tempDirectory;
|
||||
|
||||
/**
|
||||
* this config file will be copied to a newly created temporary directory.
|
||||
*/
|
||||
private String configTemplate = "default-exist-conf.xml";
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @see eu.dnetlib.xml.database.exist.ExistDatabase#start()
|
||||
*/
|
||||
@Override
|
||||
public void start() {
|
||||
log.warn("STARTING TEMPORARY EXIST DATABASE");
|
||||
createTemporaryDatabase();
|
||||
super.start();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @see eu.dnetlib.xml.database.exist.ExistDatabase#stop()
|
||||
*/
|
||||
@Override
|
||||
public void stop() {
|
||||
super.stop();
|
||||
try {
|
||||
FileUtils.deleteDirectory(tempDirectory);
|
||||
} catch (IOException e) {
|
||||
log.fatal("cannot delete temporary exist directory", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* create a temporary directory and copy the default configuration file.
|
||||
*/
|
||||
protected void createTemporaryDatabase() {
|
||||
log.debug("creating temp database");
|
||||
try {
|
||||
File tmpName;
|
||||
tmpName = File.createTempFile("exist", "");
|
||||
|
||||
tmpName.delete();
|
||||
|
||||
tempDirectory = new File(tmpName.getAbsolutePath());
|
||||
new File(tempDirectory, "data").mkdirs();
|
||||
|
||||
final InputStream defaultConf = getClass().getResourceAsStream(getConfigTemplate());
|
||||
if (defaultConf == null)
|
||||
throw new IOException("cannot find " + getConfigTemplate());
|
||||
|
||||
final File existConfigFile = new File(tempDirectory, "conf.xml");
|
||||
final FileOutputStream confOutput = new FileOutputStream(existConfigFile);
|
||||
|
||||
try {
|
||||
IOUtils.copy(defaultConf, confOutput);
|
||||
} finally {
|
||||
confOutput.close();
|
||||
}
|
||||
|
||||
setConfigFile(existConfigFile.getAbsolutePath());
|
||||
} catch (IOException e) {
|
||||
log.fatal("creating database dir", e);
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
log.debug("created temp database");
|
||||
}
|
||||
|
||||
protected String getConfigTemplate() {
|
||||
return configTemplate;
|
||||
}
|
||||
|
||||
protected void setConfigTemplate(final String configTemplate) {
|
||||
this.configTemplate = configTemplate;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,264 @@
|
|||
package org.hibernate.dialect;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Types;
|
||||
|
||||
import org.hibernate.dialect.function.*;
|
||||
import org.hibernate.exception.*;
|
||||
import org.hibernate.exception.spi.SQLExceptionConverter;
|
||||
import org.hibernate.exception.spi.TemplatedViolatedConstraintNameExtracter;
|
||||
import org.hibernate.exception.spi.ViolatedConstraintNameExtracter;
|
||||
import org.hibernate.internal.util.JdbcExceptionHelper;
|
||||
import org.hibernate.type.StandardBasicTypes;
|
||||
|
||||
public class SQLiteDialect extends Dialect {
|
||||
|
||||
public SQLiteDialect() {
|
||||
registerColumnType(Types.BIT, "boolean");
|
||||
registerColumnType(Types.TINYINT, "tinyint");
|
||||
registerColumnType(Types.SMALLINT, "smallint");
|
||||
registerColumnType(Types.INTEGER, "integer");
|
||||
registerColumnType(Types.BIGINT, "bigint");
|
||||
registerColumnType(Types.FLOAT, "float");
|
||||
registerColumnType(Types.REAL, "real");
|
||||
registerColumnType(Types.DOUBLE, "double");
|
||||
registerColumnType(Types.NUMERIC, "numeric($p, $s)");
|
||||
registerColumnType(Types.DECIMAL, "decimal");
|
||||
registerColumnType(Types.CHAR, "char");
|
||||
registerColumnType(Types.VARCHAR, "varchar($l)");
|
||||
registerColumnType(Types.LONGVARCHAR, "longvarchar");
|
||||
registerColumnType(Types.DATE, "date");
|
||||
registerColumnType(Types.TIME, "time");
|
||||
registerColumnType(Types.TIMESTAMP, "datetime");
|
||||
registerColumnType(Types.BINARY, "blob");
|
||||
registerColumnType(Types.VARBINARY, "blob");
|
||||
registerColumnType(Types.LONGVARBINARY, "blob");
|
||||
registerColumnType(Types.BLOB, "blob");
|
||||
registerColumnType(Types.CLOB, "clob");
|
||||
registerColumnType(Types.BOOLEAN, "boolean");
|
||||
|
||||
registerFunction("concat", new VarArgsSQLFunction(StandardBasicTypes.STRING, "", "||", ""));
|
||||
registerFunction("mod", new SQLFunctionTemplate(StandardBasicTypes.INTEGER, "?1 % ?2"));
|
||||
registerFunction("quote", new StandardSQLFunction("quote", StandardBasicTypes.STRING));
|
||||
registerFunction("random", new NoArgSQLFunction("random", StandardBasicTypes.INTEGER));
|
||||
registerFunction("round", new StandardSQLFunction("round"));
|
||||
registerFunction("substr", new StandardSQLFunction("substr", StandardBasicTypes.STRING));
|
||||
registerFunction("trim", new AbstractAnsiTrimEmulationFunction() {
|
||||
|
||||
@Override
|
||||
protected SQLFunction resolveBothSpaceTrimFunction() {
|
||||
return new SQLFunctionTemplate(StandardBasicTypes.STRING, "trim(?1)");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected SQLFunction resolveBothSpaceTrimFromFunction() {
|
||||
return new SQLFunctionTemplate(StandardBasicTypes.STRING, "trim(?2)");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected SQLFunction resolveLeadingSpaceTrimFunction() {
|
||||
return new SQLFunctionTemplate(StandardBasicTypes.STRING, "ltrim(?1)");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected SQLFunction resolveTrailingSpaceTrimFunction() {
|
||||
return new SQLFunctionTemplate(StandardBasicTypes.STRING, "rtrim(?1)");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected SQLFunction resolveBothTrimFunction() {
|
||||
return new SQLFunctionTemplate(StandardBasicTypes.STRING, "trim(?1, ?2)");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected SQLFunction resolveLeadingTrimFunction() {
|
||||
return new SQLFunctionTemplate(StandardBasicTypes.STRING, "ltrim(?1, ?2)");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected SQLFunction resolveTrailingTrimFunction() {
|
||||
return new SQLFunctionTemplate(StandardBasicTypes.STRING, "rtrim(?1, ?2)");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsIdentityColumns() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* public boolean supportsInsertSelectIdentity() { return true; // As specified in NHibernate dialect }
|
||||
*/
|
||||
|
||||
@Override
|
||||
public boolean hasDataTypeInIdentityColumn() {
|
||||
return false; // As specified in NHibernate dialect
|
||||
}
|
||||
|
||||
/*
|
||||
* public String appendIdentitySelectToInsert(String insertString) { return new StringBuffer(insertString.length()+30). // As specified
|
||||
* in NHibernate dialect append(insertString). append("; ").append(getIdentitySelectString()). toString(); }
|
||||
*/
|
||||
|
||||
@Override
|
||||
public String getIdentityColumnString() {
|
||||
// return "integer primary key autoincrement";
|
||||
return "integer";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getIdentitySelectString() {
|
||||
return "select last_insert_rowid()";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsLimit() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean bindLimitParametersInReverseOrder() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getLimitString(final String query, final boolean hasOffset) {
|
||||
return query + (hasOffset ? " limit ? offset ?" : " limit ?");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsTemporaryTables() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCreateTemporaryTableString() {
|
||||
return "create temporary table if not exists";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean performTemporaryTableDDLInIsolation() {
|
||||
return Boolean.FALSE;
|
||||
}
|
||||
|
||||
/*
|
||||
* @Override public boolean dropTemporaryTableAfterUse() { return true; // temporary tables are only dropped when the connection is
|
||||
* closed. If the connection is pooled... }
|
||||
*/
|
||||
|
||||
@Override
|
||||
public boolean supportsCurrentTimestampSelection() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCurrentTimestampSelectStringCallable() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCurrentTimestampSelectString() {
|
||||
return "select current_timestamp";
|
||||
}
|
||||
|
||||
private static final int SQLITE_BUSY = 5;
|
||||
private static final int SQLITE_LOCKED = 6;
|
||||
private static final int SQLITE_IOERR = 10;
|
||||
private static final int SQLITE_CORRUPT = 11;
|
||||
private static final int SQLITE_NOTFOUND = 12;
|
||||
private static final int SQLITE_FULL = 13;
|
||||
private static final int SQLITE_CANTOPEN = 14;
|
||||
private static final int SQLITE_PROTOCOL = 15;
|
||||
private static final int SQLITE_TOOBIG = 18;
|
||||
private static final int SQLITE_CONSTRAINT = 19;
|
||||
private static final int SQLITE_MISMATCH = 20;
|
||||
private static final int SQLITE_NOTADB = 26;
|
||||
|
||||
@Override
|
||||
public SQLExceptionConverter buildSQLExceptionConverter() {
|
||||
return (SQLExceptionConverter) (sqlException, message, sql) -> {
|
||||
final int errorCode = JdbcExceptionHelper.extractErrorCode(sqlException);
|
||||
if (errorCode == SQLITE_CONSTRAINT) {
|
||||
final String constraintName = EXTRACTER.extractConstraintName(sqlException);
|
||||
return new ConstraintViolationException(message, sqlException, sql, constraintName);
|
||||
} else if ((errorCode == SQLITE_TOOBIG) || (errorCode == SQLITE_MISMATCH)) return new DataException(message, sqlException, sql);
|
||||
else if ((errorCode == SQLITE_BUSY) || (errorCode == SQLITE_LOCKED)) return new LockAcquisitionException(message, sqlException, sql);
|
||||
else if (((errorCode >= SQLITE_IOERR) && (errorCode <= SQLITE_PROTOCOL)) || (errorCode == SQLITE_NOTADB))
|
||||
return new JDBCConnectionException(message, sqlException, sql);
|
||||
return new GenericJDBCException(message, sqlException, sql);
|
||||
};
|
||||
}
|
||||
|
||||
public static final ViolatedConstraintNameExtracter EXTRACTER = new TemplatedViolatedConstraintNameExtracter() {
|
||||
|
||||
@Override
|
||||
public String extractConstraintName(final SQLException sqle) {
|
||||
return extractUsingTemplate("constraint ", " failed", sqle.getMessage());
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public boolean supportsUnionAll() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasAlterTable() {
|
||||
return false; // As specified in NHibernate dialect
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean dropConstraints() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAddColumnString() {
|
||||
return "add column";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getForUpdateString() {
|
||||
return "";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsOuterJoinForUpdate() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDropForeignKeyString() {
|
||||
throw new UnsupportedOperationException("No drop foreign key syntax supported by SQLiteDialect");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAddForeignKeyConstraintString(final String constraintName,
|
||||
final String[] foreignKey,
|
||||
final String referencedTable,
|
||||
final String[] primaryKey,
|
||||
final boolean referencesPrimaryKey) {
|
||||
throw new UnsupportedOperationException("No add foreign key syntax supported by SQLiteDialect");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAddPrimaryKeyConstraintString(final String constraintName) {
|
||||
throw new UnsupportedOperationException("No add primary key syntax supported by SQLiteDialect");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsIfExistsBeforeTableName() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsTupleDistinctCounts() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSelectGUIDString() {
|
||||
return "select hex(randomblob(16))";
|
||||
}
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jaxws="http://cxf.apache.org/jaxws"
|
||||
xmlns:sec="http://cxf.apache.org/configuration/security" xmlns:wsa="http://cxf.apache.org/ws/addressing"
|
||||
xmlns:p="http://www.springframework.org/schema/p" xmlns:http="http://cxf.apache.org/transports/http/configuration"
|
||||
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
|
||||
http://cxf.apache.org/ws/addressing http://cxf.apache.org/schemas/ws-addr-conf.xsd
|
||||
http://cxf.apache.org/configuration/security http://cxf.apache.org/schemas/configuration/security.xsd
|
||||
http://cxf.apache.org/transports/http/configuration http://cxf.apache.org/schemas/configuration/http-conf.xsd
|
||||
http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd">
|
||||
|
||||
<!--
|
||||
common job scheduler. Use SchedulerAccessorBean to add triggers.
|
||||
-->
|
||||
<bean id="jobScheduler"
|
||||
class="org.springframework.scheduling.quartz.SchedulerFactoryBean"
|
||||
destroy-method="destroy">
|
||||
<property name="jobFactory">
|
||||
<bean id="jobSchedulerFactory"
|
||||
class="org.springframework.scheduling.quartz.SpringBeanJobFactory" />
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<!-- service locators: TODO: parameterize via properties -->
|
||||
<bean id="storeLocator" class="eu.dnetlib.enabling.tools.StaticServiceLocator"
|
||||
p:service-ref="isStoreService" />
|
||||
<bean id="registryLocator" class="eu.dnetlib.enabling.tools.StaticServiceLocator"
|
||||
p:service-ref="isRegistryService" />
|
||||
<bean id="snLocator" class="eu.dnetlib.enabling.tools.StaticServiceLocator"
|
||||
p:service-ref="isSNService" />
|
||||
<bean id="lookupLocator" class="eu.dnetlib.enabling.tools.StaticServiceLocator"
|
||||
p:service-ref="isLookUpService" />
|
||||
<!--
|
||||
<bean id="msroLocator" class="eu.dnetlib.enabling.tools.StaticServiceLocator"
|
||||
p:service-ref="msroService" />
|
||||
|
||||
<bean id="anyIndexLocatorDynamic" class="eu.dnetlib.enabling.tools.DynamicServiceLocator"
|
||||
p:clazz="eu.dnetlib.data.index.IIndexService" p:lookUpLocator-ref="lookupLocator"
|
||||
p:serviceResolver-ref="serviceResolver" />
|
||||
-->
|
||||
<!-- common service resolution chain -->
|
||||
<bean id="serviceResolver" class="eu.dnetlib.enabling.tools.ServiceResolverChain">
|
||||
<property name="resolvers">
|
||||
<list>
|
||||
<bean id="localServiceResolver" class="eu.dnetlib.enabling.tools.LocalServiceResolverImpl"
|
||||
p:baseAddress="${transport.soap.baseAddress}" />
|
||||
<bean id="jaxwsServiceResolver" class="eu.dnetlib.enabling.tools.JaxwsServiceResolverImpl" />
|
||||
</list>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<bean id="uuidGenerator" class="eu.dnetlib.enabling.tools.UniqueIdentifierGeneratorImpl" />
|
||||
</beans>
|
|
@ -0,0 +1,29 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jaxws="http://cxf.apache.org/jaxws"
|
||||
xmlns:sec="http://cxf.apache.org/configuration/security" xmlns:wsa="http://cxf.apache.org/ws/addressing"
|
||||
xmlns:p="http://www.springframework.org/schema/p" xmlns:http="http://cxf.apache.org/transports/http/configuration"
|
||||
xmlns:t="http://dnetlib.eu/springbeans/t" xmlns:template="http://dnetlib.eu/springbeans/template"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
|
||||
http://cxf.apache.org/ws/addressing http://cxf.apache.org/schemas/ws-addr-conf.xsd
|
||||
http://cxf.apache.org/configuration/security http://cxf.apache.org/schemas/configuration/security.xsd
|
||||
http://cxf.apache.org/transports/http/configuration http://cxf.apache.org/schemas/configuration/http-conf.xsd
|
||||
http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd
|
||||
http://dnetlib.eu/springbeans/template http://dnetlib.eu/springbeans/template.xsd">
|
||||
|
||||
<!-- beans -->
|
||||
<bean id="isLookUpService" class="eu.dnetlib.enabling.is.lookup.ISLookUpServiceImpl"
|
||||
init-method="start" destroy-method="stop" p:isStore-ref="isStoreService"
|
||||
p:xqueryUtils-ref="xqueryUtils"/>
|
||||
|
||||
<!-- endpoints -->
|
||||
<jaxws:endpoint id="isLookUpServiceEndpoint"
|
||||
implementor="#isLookUpService" implementorClass="eu.dnetlib.enabling.is.lookup.rmi.ISLookUpService"
|
||||
address="/isLookUp" />
|
||||
|
||||
<template:instance name="serviceRegistrationManager"
|
||||
t:serviceRegistrationManagerClass="eu.dnetlib.enabling.tools.registration.ValidatingServiceRegistrationManagerImpl"
|
||||
t:name="isLookUpServiceRegistrationManager" t:service="isLookUpService" t:endpoint="isLookUpServiceEndpoint"
|
||||
t:jobScheduler="jobScheduler"/>
|
||||
|
||||
</beans>
|
|
@ -0,0 +1,245 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--Sample XML file generated by XMLSpy v2007 sp1 (http://www.altova.com)-->
|
||||
<RESOURCE_PROFILE>
|
||||
<HEADER>
|
||||
<RESOURCE_IDENTIFIER value=""/>
|
||||
<RESOURCE_TYPE value="SystemManagementDSResourceType"/>
|
||||
<RESOURCE_KIND value="SystemManagementDSResources"/>
|
||||
<RESOURCE_URI value="00000000000000000000000000000000000000000"/>
|
||||
<DATE_OF_CREATION value="10/04/2007"/>
|
||||
</HEADER>
|
||||
<BODY>
|
||||
<CONFIGURATION>
|
||||
<NAME>DRIVER Information Space Application</NAME>
|
||||
<MANAGER_SERVICE_ID value="000000000000000000000000000000000000"/>
|
||||
<QoSTHRESHOLDS>
|
||||
</QoSTHRESHOLDS>
|
||||
<MAPPINGS>
|
||||
<MAPPING>
|
||||
<PENDING_TYPOLOGY>PendingRepositoryResources</PENDING_TYPOLOGY>
|
||||
<RESOURCE_KIND>RepositoryServiceResources</RESOURCE_KIND>
|
||||
<RESOURCE_TYPES>
|
||||
<RESOURCE_TYPE>RepositoryServiceResourceType</RESOURCE_TYPE>
|
||||
</RESOURCE_TYPES>
|
||||
</MAPPING>
|
||||
<MAPPING>
|
||||
<PENDING_TYPOLOGY>PendingServiceResources</PENDING_TYPOLOGY>
|
||||
<RESOURCE_KIND>ServiceResources</RESOURCE_KIND>
|
||||
<RESOURCE_TYPES>
|
||||
<RESOURCE_TYPE>IS_StoreServiceResourceType</RESOURCE_TYPE>
|
||||
<RESOURCE_TYPE>IS_SNServiceResourceType</RESOURCE_TYPE>
|
||||
<RESOURCE_TYPE>IS_LookUpServiceResourceType</RESOURCE_TYPE>
|
||||
<RESOURCE_TYPE>IS_UIServiceResourceType</RESOURCE_TYPE>
|
||||
<RESOURCE_TYPE>IS_RegistryServiceResourceType</RESOURCE_TYPE>
|
||||
<RESOURCE_TYPE>MS_RMServiceResourceType</RESOURCE_TYPE>
|
||||
<RESOURCE_TYPE>MS_ROServiceResourceType</RESOURCE_TYPE>
|
||||
<RESOURCE_TYPE>HostingNodeManagerServiceResourceType</RESOURCE_TYPE>
|
||||
<RESOURCE_TYPE>HostingContextManagerServiceResourceType</RESOURCE_TYPE>
|
||||
<RESOURCE_TYPE>MDStoreServiceResourceType</RESOURCE_TYPE>
|
||||
<RESOURCE_TYPE>DepotServiceResourceType</RESOURCE_TYPE>
|
||||
<RESOURCE_TYPE>DataAccessServiceResourceType</RESOURCE_TYPE>
|
||||
<RESOURCE_TYPE>AggregatorServiceResourceType</RESOURCE_TYPE>
|
||||
<RESOURCE_TYPE>HarvestingServiceResourceType</RESOURCE_TYPE>
|
||||
<RESOURCE_TYPE>HarvestingManagerServiceResourceType</RESOURCE_TYPE>
|
||||
<RESOURCE_TYPE>TransformationServiceResourceType</RESOURCE_TYPE>
|
||||
<RESOURCE_TYPE>TransformationManagerServiceResourceType</RESOURCE_TYPE>
|
||||
<RESOURCE_TYPE>TransformationRuleEditorServiceResourceType</RESOURCE_TYPE>
|
||||
<RESOURCE_TYPE>FeatureExtractionServiceResourceType</RESOURCE_TYPE>
|
||||
<RESOURCE_TYPE>IndexServiceResourceType</RESOURCE_TYPE>
|
||||
<RESOURCE_TYPE>BrowseServiceResourceType</RESOURCE_TYPE>
|
||||
<RESOURCE_TYPE>DownloadServiceResourceType</RESOURCE_TYPE>
|
||||
<RESOURCE_TYPE>CS_EngineServiceResourceType</RESOURCE_TYPE>
|
||||
<RESOURCE_TYPE>CS_UIServiceResourceType</RESOURCE_TYPE>
|
||||
<RESOURCE_TYPE>ResultSetServiceResourceType</RESOURCE_TYPE>
|
||||
<RESOURCE_TYPE>OAIServiceResourceType</RESOURCE_TYPE>
|
||||
<RESOURCE_TYPE>A2ServiceResourceType</RESOURCE_TYPE>
|
||||
<RESOURCE_TYPE>ObjectPackagingServiceResourceType</RESOURCE_TYPE>
|
||||
<RESOURCE_TYPE>DLMServiceResourceType</RESOURCE_TYPE>
|
||||
<RESOURCE_TYPE>TextEngineServiceResourceType</RESOURCE_TYPE>
|
||||
<RESOURCE_TYPE>PublisherServiceResourceType</RESOURCE_TYPE>
|
||||
<RESOURCE_TYPE>DriverTesterServiceResourceType</RESOURCE_TYPE>
|
||||
<RESOURCE_TYPE>SearchServiceResourceType</RESOURCE_TYPE>
|
||||
<RESOURCE_TYPE>CollectionServiceResourceType</RESOURCE_TYPE>
|
||||
<RESOURCE_TYPE>CommunityServiceResourceType</RESOURCE_TYPE>
|
||||
<RESOURCE_TYPE>ForumServiceResourceType</RESOURCE_TYPE>
|
||||
<RESOURCE_TYPE>RatingServiceResourceType</RESOURCE_TYPE>
|
||||
<RESOURCE_TYPE>RecommendationServiceResourceType</RESOURCE_TYPE>
|
||||
<RESOURCE_TYPE>UserProfileServiceResourceType</RESOURCE_TYPE>
|
||||
<RESOURCE_TYPE>ValidatorServiceResourceType</RESOURCE_TYPE>
|
||||
<RESOURCE_TYPE>ValidatorUserInterfaceServiceResourceType</RESOURCE_TYPE>
|
||||
<RESOURCE_TYPE>WebInterfaceServiceResourceType</RESOURCE_TYPE>
|
||||
<RESOURCE_TYPE>CitationServiceResourceType</RESOURCE_TYPE>
|
||||
<RESOURCE_TYPE>SimilarityServiceResourceType</RESOURCE_TYPE>
|
||||
<RESOURCE_TYPE>DLMSConnectionServiceResourceType</RESOURCE_TYPE>
|
||||
|
||||
<RESOURCE_TYPE>TagSessionManagerServiceResourceType</RESOURCE_TYPE>
|
||||
<RESOURCE_TYPE>TagStoreServiceResourceType</RESOURCE_TYPE>
|
||||
<RESOURCE_TYPE>PIDBridgeServiceResourceType</RESOURCE_TYPE>
|
||||
<RESOURCE_TYPE>PIDAssignerServiceResourceType</RESOURCE_TYPE>
|
||||
<RESOURCE_TYPE>CleanerServiceResourceType</RESOURCE_TYPE>
|
||||
</RESOURCE_TYPES>
|
||||
</MAPPING>
|
||||
<MAPPING>
|
||||
<PENDING_TYPOLOGY>PendingDSResources</PENDING_TYPOLOGY>
|
||||
<RESOURCE_KIND>DRIVERHostingNodeDSResources</RESOURCE_KIND>
|
||||
<RESOURCE_TYPES>
|
||||
<RESOURCE_TYPE>DRIVERHostingNodeDSResourceType</RESOURCE_TYPE>
|
||||
</RESOURCE_TYPES>
|
||||
</MAPPING>
|
||||
<MAPPING>
|
||||
<PENDING_TYPOLOGY>PendingDSResources</PENDING_TYPOLOGY>
|
||||
<RESOURCE_KIND>UserDSResources</RESOURCE_KIND>
|
||||
<RESOURCE_TYPES>
|
||||
<RESOURCE_TYPE>UserDSResourceType</RESOURCE_TYPE>
|
||||
</RESOURCE_TYPES>
|
||||
</MAPPING>
|
||||
<MAPPING>
|
||||
<PENDING_TYPOLOGY/>
|
||||
<RESOURCE_KIND>CommunityDSResources</RESOURCE_KIND>
|
||||
<RESOURCE_TYPES>
|
||||
<RESOURCE_TYPE>CommunityDSResourceType</RESOURCE_TYPE>
|
||||
</RESOURCE_TYPES>
|
||||
</MAPPING>
|
||||
<MAPPING>
|
||||
<PENDING_TYPOLOGY/>
|
||||
<RESOURCE_KIND>DriverTestDSResources</RESOURCE_KIND>
|
||||
<RESOURCE_TYPES>
|
||||
<RESOURCE_TYPE>DriverTestDSResourceType</RESOURCE_TYPE>
|
||||
</RESOURCE_TYPES>
|
||||
</MAPPING>
|
||||
<MAPPING>
|
||||
<PENDING_TYPOLOGY>PendingDSResources</PENDING_TYPOLOGY>
|
||||
<RESOURCE_KIND>DriverPendingTestDSResources</RESOURCE_KIND>
|
||||
<RESOURCE_TYPES>
|
||||
<RESOURCE_TYPE>DriverPendingTestDSResourceType</RESOURCE_TYPE>
|
||||
</RESOURCE_TYPES>
|
||||
</MAPPING>
|
||||
<MAPPING>
|
||||
<PENDING_TYPOLOGY/>
|
||||
<RESOURCE_KIND>CollectionDSResources</RESOURCE_KIND>
|
||||
<RESOURCE_TYPES>
|
||||
<RESOURCE_TYPE>CollectionDSResourceType</RESOURCE_TYPE>
|
||||
</RESOURCE_TYPES>
|
||||
</MAPPING>
|
||||
<MAPPING>
|
||||
<PENDING_TYPOLOGY/>
|
||||
<RESOURCE_KIND>HarvestingInstanceDSResources</RESOURCE_KIND>
|
||||
<RESOURCE_TYPES>
|
||||
<RESOURCE_TYPE>HarvestingInstanceDSResourceType</RESOURCE_TYPE>
|
||||
</RESOURCE_TYPES>
|
||||
</MAPPING>
|
||||
<MAPPING>
|
||||
<PENDING_TYPOLOGY/>
|
||||
<RESOURCE_KIND>HarvestingDSResources</RESOURCE_KIND>
|
||||
<RESOURCE_TYPES>
|
||||
<RESOURCE_TYPE>HarvestingDSResourceType</RESOURCE_TYPE>
|
||||
</RESOURCE_TYPES>
|
||||
</MAPPING>
|
||||
<MAPPING>
|
||||
<PENDING_TYPOLOGY/>
|
||||
<RESOURCE_KIND>IndexDSResources</RESOURCE_KIND>
|
||||
<RESOURCE_TYPES>
|
||||
<RESOURCE_TYPE>IndexDSResourceType</RESOURCE_TYPE>
|
||||
</RESOURCE_TYPES>
|
||||
</MAPPING>
|
||||
<MAPPING>
|
||||
<PENDING_TYPOLOGY/>
|
||||
<RESOURCE_KIND>MDStoreDSResources</RESOURCE_KIND>
|
||||
<RESOURCE_TYPES>
|
||||
<RESOURCE_TYPE>MDStoreDSResourceType</RESOURCE_TYPE>
|
||||
</RESOURCE_TYPES>
|
||||
</MAPPING>
|
||||
<MAPPING>
|
||||
<PENDING_TYPOLOGY/>
|
||||
<RESOURCE_KIND>StoreDSResources</RESOURCE_KIND>
|
||||
<RESOURCE_TYPES>
|
||||
<RESOURCE_TYPE>StoreDSResourceType</RESOURCE_TYPE>
|
||||
</RESOURCE_TYPES>
|
||||
</MAPPING>
|
||||
<MAPPING>
|
||||
<PENDING_TYPOLOGY/>
|
||||
<RESOURCE_KIND>ResultSetDSResources</RESOURCE_KIND>
|
||||
<RESOURCE_TYPES>
|
||||
<RESOURCE_TYPE>ResultSetDSResourceType</RESOURCE_TYPE>
|
||||
</RESOURCE_TYPES>
|
||||
</MAPPING>
|
||||
<MAPPING>
|
||||
<PENDING_TYPOLOGY/>
|
||||
<RESOURCE_KIND>RecommendationDSResources</RESOURCE_KIND>
|
||||
<RESOURCE_TYPES>
|
||||
<RESOURCE_TYPE>RecommendationResourceType</RESOURCE_TYPE>
|
||||
</RESOURCE_TYPES>
|
||||
</MAPPING>
|
||||
<MAPPING>
|
||||
<PENDING_TYPOLOGY/>
|
||||
<RESOURCE_KIND>TransformationDSResources</RESOURCE_KIND>
|
||||
<RESOURCE_TYPES>
|
||||
<RESOURCE_TYPE>TransformationDSResourceType</RESOURCE_TYPE>
|
||||
</RESOURCE_TYPES>
|
||||
</MAPPING>
|
||||
<MAPPING>
|
||||
<PENDING_TYPOLOGY/>
|
||||
<RESOURCE_KIND>VocabularyDSResources</RESOURCE_KIND>
|
||||
<RESOURCE_TYPES>
|
||||
<RESOURCE_TYPE>VocabularyDSResourceType</RESOURCE_TYPE>
|
||||
</RESOURCE_TYPES>
|
||||
</MAPPING>
|
||||
<MAPPING>
|
||||
<PENDING_TYPOLOGY/>
|
||||
<RESOURCE_KIND>SystemManagementDSResources</RESOURCE_KIND>
|
||||
<RESOURCE_TYPES>
|
||||
<RESOURCE_TYPE>SystemManagementDSResourceType</RESOURCE_TYPE>
|
||||
</RESOURCE_TYPES>
|
||||
</MAPPING>
|
||||
</MAPPINGS>
|
||||
<FIELD_SETTINGS>
|
||||
<FIELD_SETTING name="DMF">
|
||||
<NAME>dr:CobjContentSynthesis</NAME>
|
||||
<NAME>dr:CobjTypology</NAME>
|
||||
<NAME>dr:CobjIdentifier</NAME>
|
||||
<NAME>dr:CobjModel</NAME>
|
||||
<NAME>dr:CobjMDFormats</NAME>
|
||||
<NAME>dr:CobjDescriptionSynthesis</NAME>
|
||||
<NAME>dr:repositoryName</NAME>
|
||||
<NAME>dr:repositoryLink</NAME>
|
||||
<NAME>dr:repositoryCountry</NAME>
|
||||
<NAME>dr:repositoryInstitution</NAME>
|
||||
<NAME>dc:creator</NAME>
|
||||
<NAME>dc:title</NAME>
|
||||
<NAME>dc:subject</NAME>
|
||||
<NAME>dr:CobjCategory</NAME>
|
||||
<NAME>dc:language</NAME>
|
||||
<NAME>dc:dateAccepted</NAME>
|
||||
<NAME>dc:identifier</NAME>
|
||||
<NAME>dc:publisher </NAME>
|
||||
<NAME>dc:source </NAME>
|
||||
<NAME>dc:contributor </NAME>
|
||||
<NAME>dc:relation</NAME>
|
||||
<NAME>dc:description</NAME>
|
||||
</FIELD_SETTING>
|
||||
<FIELD_SETTING name="Index Configuration Fields">
|
||||
<NAME>dr:repositoryCountry</NAME>
|
||||
</FIELD_SETTING>
|
||||
<FIELD_SETTING name="Index Result Fields">
|
||||
<NAME>*</NAME>
|
||||
</FIELD_SETTING>
|
||||
<FIELD_SETTING name="DMF Provenance Fields">
|
||||
<NAME>dr:repositoryName</NAME>
|
||||
<NAME>dr:repositoryLink</NAME>
|
||||
<NAME>dr:repositoryCountry</NAME>
|
||||
<NAME>dr:repositoryInstitution</NAME>
|
||||
</FIELD_SETTING>
|
||||
<FIELD_SETTING name="Repository Provenance Fields">
|
||||
<NAME>ENGLISH_NAME</NAME>
|
||||
<NAME>REPOSITORY_WEBPAGE</NAME>
|
||||
<NAME>COUNTRY</NAME>
|
||||
<NAME>REPOSITORY_INSTITUTION</NAME>
|
||||
</FIELD_SETTING>
|
||||
</FIELD_SETTINGS>
|
||||
</CONFIGURATION>
|
||||
<STATUS>
|
||||
<LAST_UPDATE value="10/04/2007"/>
|
||||
</STATUS>
|
||||
<SECURITY_PARAMETERS></SECURITY_PARAMETERS>
|
||||
</BODY>
|
||||
</RESOURCE_PROFILE>
|
|
@ -0,0 +1,2 @@
|
|||
# values: idPreservingPendingManager, compatPendingManager
|
||||
services.registry.pending.resource.manager=idPreservingPendingManager
|
|
@ -0,0 +1,75 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jaxws="http://cxf.apache.org/jaxws"
|
||||
xmlns:sec="http://cxf.apache.org/configuration/security" xmlns:wsa="http://cxf.apache.org/ws/addressing"
|
||||
xmlns:p="http://www.springframework.org/schema/p" xmlns:http="http://cxf.apache.org/transports/http/configuration"
|
||||
xmlns:t="http://dnetlib.eu/springbeans/t" xmlns:template="http://dnetlib.eu/springbeans/template"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
|
||||
http://cxf.apache.org/ws/addressing http://cxf.apache.org/schemas/ws-addr-conf.xsd
|
||||
http://cxf.apache.org/configuration/security http://cxf.apache.org/schemas/configuration/security.xsd
|
||||
http://cxf.apache.org/transports/http/configuration http://cxf.apache.org/schemas/configuration/http-conf.xsd
|
||||
http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd
|
||||
http://dnetlib.eu/springbeans/template http://dnetlib.eu/springbeans/template.xsd">
|
||||
<!-- beans -->
|
||||
<bean id="isRegistryService" class="eu.dnetlib.enabling.is.registry.ISRegistryServiceImpl"
|
||||
init-method="start" destroy-method="stop" p:isLookup-ref="isLookUpService" p:isStore-ref="isStoreService"
|
||||
p:pendingManager-ref="pendingManager" p:resourceValidator-ref="resourceValidator" p:xqueryUtils-ref="xqueryUtils" />
|
||||
|
||||
<bean id="registryBlackboardManager"
|
||||
class="eu.dnetlib.enabling.is.registry.RegistryBlackboardManagerImpl"
|
||||
p:messageFactory-ref="blackboardMessageFactory" p:isLookup-ref="isLookUpService"
|
||||
p:registryService-ref="isRegistryService" />
|
||||
|
||||
<alias alias="pendingManager" name="${services.registry.pending.resource.manager}" />
|
||||
|
||||
<bean id="compatPendingManager"
|
||||
class="eu.dnetlib.enabling.is.registry.CompatPendingResourceManagerImpl"
|
||||
p:isRegistry-ref="isRegistryService" p:resourceKindResolver-ref="resourceKindResolverChain" />
|
||||
|
||||
<bean id="idPreservingPendingManager"
|
||||
class="eu.dnetlib.enabling.is.registry.IdPreservingPendingResourceManagerImpl"
|
||||
p:resourceValidator-ref="resourceValidator" p:xqueryUtils-ref="xqueryUtils"
|
||||
p:isRegistry-ref="isRegistryService" p:isStore-ref="isStoreService"
|
||||
p:resourceKindResolver-ref="resourceKindResolverChain" />
|
||||
|
||||
<bean id="resourceKindResolverChain"
|
||||
class="eu.dnetlib.enabling.is.registry.ResourceKindResolverChain">
|
||||
<property name="resolvers">
|
||||
<list>
|
||||
<ref bean="resourceKindResolver" />
|
||||
<ref bean="nameBasedResourceKindResolver" />
|
||||
</list>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<bean id="nameBasedResourceKindResolver"
|
||||
class="eu.dnetlib.enabling.is.registry.NameBasedResourceKindResolver" />
|
||||
|
||||
<bean id="resourceKindResolver"
|
||||
class="eu.dnetlib.enabling.is.registry.ApplicationProfileResourceKindResolver" />
|
||||
|
||||
<bean id="resourceIdentifierResolver"
|
||||
class="eu.dnetlib.enabling.tools.CompatResourceIdentifierResolverImpl" />
|
||||
|
||||
<bean id="resourceValidator"
|
||||
class="eu.dnetlib.enabling.is.registry.schema.OpaqueResourceValidatorImpl"
|
||||
p:schemaDao-ref="resourceSchemaDao" />
|
||||
|
||||
<bean id="resourceSchemaDao"
|
||||
class="eu.dnetlib.enabling.is.registry.schema.ResourceSchemaDAOImpl"
|
||||
p:isLookup-ref="isLookUpService" />
|
||||
|
||||
<bean id="profileValidationStrategy" class="eu.dnetlib.enabling.is.registry.validation.ProfileValidationStrategy" />
|
||||
|
||||
<bean id="alwaysAcceptProfileValidator" class="eu.dnetlib.enabling.is.registry.validation.AlwaysAcceptProfileValidator" />
|
||||
|
||||
<!-- endpoints -->
|
||||
<jaxws:endpoint id="isRegistryServiceEndpoint"
|
||||
implementor="#isRegistryService" implementorClass="eu.dnetlib.enabling.is.registry.rmi.ISRegistryService"
|
||||
address="/isRegistry" />
|
||||
|
||||
<template:instance name="serviceRegistrationManager"
|
||||
t:serviceRegistrationManagerClass="eu.dnetlib.enabling.tools.registration.ValidatingServiceRegistrationManagerImpl"
|
||||
t:name="isRegistryServiceRegistrationManager" t:service="isRegistryService"
|
||||
t:endpoint="isRegistryServiceEndpoint" t:jobScheduler="jobScheduler" />
|
||||
</beans>
|
|
@ -0,0 +1,19 @@
|
|||
services.issn.path=${dnet.data.path}/issn
|
||||
services.issn.hib.issndb.url=jdbc:sqlite:${services.issn.path}/dnet_issn.db
|
||||
services.issn.hib.issndb.username=dnet
|
||||
services.issn.hib.issndb.password=dnetPwd
|
||||
services.issn.hibernate.hbm.auto=update
|
||||
services.issn.hib.issndb.dialect=org.hibernate.dialect.SQLiteDialect
|
||||
services.issn.hib.driverName = org.sqlite.JDBC
|
||||
|
||||
services.issn.subscription.filter.active = false
|
||||
services.is.sn.subscriptions.cache.ttl = 86400
|
||||
services.is.sn.subscriptions.cache.size = 1000
|
||||
|
||||
#TO USE POSTGRES YOU NEED TO UNCOMMENT THIS
|
||||
#services.issn.hib.issndb.url=jdbc:postgresql://localhost:5432/dnet_issn
|
||||
#services.issn.hib.issndb.username=dnet
|
||||
#services.issn.hib.issndb.password=dnetPwd
|
||||
#services.issn.hibernate.hbm.auto=update
|
||||
#services.issn.hib.issndb.dialect=org.hibernate.dialect.PostgreSQLDialect
|
||||
#services.issn.hib.driverName = org.postgresql.Driver
|
|
@ -0,0 +1,86 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jaxws="http://cxf.apache.org/jaxws"
|
||||
xmlns:sec="http://cxf.apache.org/configuration/security" xmlns:wsa="http://cxf.apache.org/ws/addressing"
|
||||
xmlns:p="http://www.springframework.org/schema/p" xmlns:http="http://cxf.apache.org/transports/http/configuration"
|
||||
xmlns:util="http://www.springframework.org/schema/util" xmlns:t="http://dnetlib.eu/springbeans/t"
|
||||
xmlns:template="http://dnetlib.eu/springbeans/template" xmlns:cache="http://www.springframework.org/schema/cache"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
|
||||
http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache.xsd
|
||||
http://cxf.apache.org/ws/addressing http://cxf.apache.org/schemas/ws-addr-conf.xsd
|
||||
http://cxf.apache.org/configuration/security http://cxf.apache.org/schemas/configuration/security.xsd
|
||||
http://cxf.apache.org/transports/http/configuration http://cxf.apache.org/schemas/configuration/http-conf.xsd
|
||||
http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd
|
||||
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-2.0.xsd
|
||||
http://dnetlib.eu/springbeans/template http://dnetlib.eu/springbeans/template.xsd">
|
||||
|
||||
<!-- beans -->
|
||||
<bean name="isSNService" class="eu.dnetlib.enabling.is.sn.ISSNServiceImpl"
|
||||
p:endpoint-ref="isSNServiceEndpoint" p:core-ref="isSNServiceCore"
|
||||
init-method="start" destroy-method="stop" />
|
||||
|
||||
<bean name="isSNServiceCore" class="eu.dnetlib.enabling.is.sn.ISSNServiceCore"
|
||||
p:registry-ref="issResourceStateNotificationRegistry"
|
||||
p:backupDir="${services.is.sn.data.path}/backups"/>
|
||||
|
||||
<bean name="issnNotificationDetector" class="eu.dnetlib.enabling.is.sn.NotificationDetectorImpl"
|
||||
p:sender-ref="issnNotificationSender" p:registry-ref="issResourceStateNotificationRegistry" />
|
||||
|
||||
<bean id="issnNotificationDetectorPendingSupport"
|
||||
class="eu.dnetlib.enabling.is.sn.resourcestate.PendingResourceStateNotificationDetectorFilter"
|
||||
p:delegate-ref="issnNotificationDetector" />
|
||||
|
||||
<bean id="subscriptionRequestFilter" class="eu.dnetlib.enabling.is.sn.resourcestate.SubscriptionRequestFilter" />
|
||||
|
||||
<!--
|
||||
set this condition to true to globally inhibit notification processing
|
||||
-->
|
||||
<bean id="issnInhibitionCondition" class="eu.dnetlib.miscutils.coupling.StaticCondition" />
|
||||
|
||||
<bean id="issnNotificationDetectorConditional"
|
||||
class="eu.dnetlib.enabling.is.sn.resourcestate.ConditionalResourceStateNotificationDetectorFilter"
|
||||
p:inhibitionCondition-ref="issnInhibitionCondition" p:delegate-ref="issnNotificationDetectorPendingSupport" />
|
||||
|
||||
<bean id="issResourceStateNotificationRegistry"
|
||||
class="eu.dnetlib.enabling.is.sn.resourcestate.ResourceStateSubscriptionRegistry"
|
||||
p:subscriptionDao-ref="hibernateResourceStateSubscriptionDAO" />
|
||||
|
||||
<bean name="issnNotificationSender"
|
||||
class="eu.dnetlib.enabling.is.sn.AsynchronousNotificationSenderImpl"
|
||||
p:invoker-ref="issnNotificationInvoker" init-method="start" />
|
||||
|
||||
<bean name="issnNotificationInvocationLogger"
|
||||
class="eu.dnetlib.enabling.is.sn.MemoryNotificationInvocationLogger" />
|
||||
|
||||
<bean name="issnNotificationInvoker" class="eu.dnetlib.enabling.is.sn.NotificationInvokerImpl"
|
||||
p:invocationLogger-ref="issnNotificationInvocationLogger" />
|
||||
|
||||
<bean name="issnIntegrationTrigger" class="eu.dnetlib.enabling.is.sn.NotificationTriggerImpl"
|
||||
p:name="issnIntegrationTrigger" p:detector-ref="issnNotificationDetectorConditional" />
|
||||
|
||||
|
||||
<bean id="issnCacheManager" class="org.springframework.cache.ehcache.EhCacheCacheManager"
|
||||
p:cacheManager-ref="issnCacheManagerFactory" />
|
||||
|
||||
<bean id="issnCacheManagerFactory"
|
||||
class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean"
|
||||
p:cacheManagerName="issnCacheManager" />
|
||||
|
||||
<bean id="issnCache"
|
||||
class="org.springframework.cache.ehcache.EhCacheFactoryBean"
|
||||
p:eternal="false" p:timeToLive="${services.is.sn.subscriptions.cache.ttl}"
|
||||
p:timeToIdle="${services.is.sn.subscriptions.cache.ttl}"
|
||||
p:overflowToDisk="false"
|
||||
p:maxElementsInMemory="${services.is.sn.subscriptions.cache.size}"
|
||||
p:cacheManager-ref="issnCacheManagerFactory"
|
||||
p:cacheName="issnCache" p:name="subscriptions" />
|
||||
|
||||
<!-- endpoints -->
|
||||
<jaxws:endpoint id="isSNServiceEndpoint" implementor="#isSNService"
|
||||
implementorClass="eu.dnetlib.enabling.is.sn.rmi.ISSNService" address="/isSN" />
|
||||
|
||||
<template:instance name="serviceRegistrationManager"
|
||||
t:serviceRegistrationManagerClass="eu.dnetlib.enabling.tools.registration.ValidatingServiceRegistrationManagerImpl"
|
||||
t:name="isSNServiceRegistrationManager" t:service="isSNService"
|
||||
t:endpoint="isSNServiceEndpoint" t:jobScheduler="jobScheduler" />
|
||||
</beans>
|
|
@ -0,0 +1,54 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
|
||||
xmlns:context="http://www.springframework.org/schema/context" xmlns:p="http://www.springframework.org/schema/p"
|
||||
xmlns:tx="http://www.springframework.org/schema/tx" xmlns:util="http://www.springframework.org/schema/util"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
|
||||
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
|
||||
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
|
||||
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
|
||||
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">
|
||||
|
||||
<bean id="verifyPath" class="eu.dnetlib.enabling.is.sn.DnetPathVerifier">
|
||||
<constructor-arg value="${services.issn.path}"/>
|
||||
</bean>
|
||||
|
||||
<!-- DATASOURCE -->
|
||||
<bean id="issnDataSource"
|
||||
class="org.springframework.jdbc.datasource.DriverManagerDataSource"
|
||||
p:driverClassName="${services.issn.hib.driverName}" p:url="${services.issn.hib.issndb.url}"
|
||||
p:username="${services.issn.hib.issndb.username}" p:password="${services.issn.hib.issndb.password}"
|
||||
depends-on="verifyPath"
|
||||
/>
|
||||
|
||||
<!-- Hibernate SessionFactory -->
|
||||
<bean id="issnSessionFactory"
|
||||
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean"
|
||||
p:dataSource-ref="issnDataSource"
|
||||
depends-on="verifyPath"
|
||||
>
|
||||
<property name="annotatedClasses">
|
||||
<list>
|
||||
<value>eu.dnetlib.enabling.is.sn.resourcestate.ResourceStateSubscription</value>
|
||||
</list>
|
||||
</property>
|
||||
<property name="hibernateProperties">
|
||||
<props>
|
||||
<prop key="hibernate.dialect">${services.issn.hib.issndb.dialect}</prop>
|
||||
<prop key="hibernate.show_sql">false</prop>
|
||||
<prop key="hibernate.hbm2ddl.auto">${services.issn.hibernate.hbm.auto}</prop>
|
||||
</props>
|
||||
</property>
|
||||
</bean>
|
||||
<!-- Transaction manager for a single Hibernate SessionFactory (alternative
|
||||
to JTA) -->
|
||||
<tx:annotation-driven transaction-manager="issnTransactionManager" />
|
||||
|
||||
<bean id="issnTransactionManager"
|
||||
class="org.springframework.orm.hibernate4.HibernateTransactionManager"
|
||||
p:sessionFactory-ref="issnSessionFactory" />
|
||||
|
||||
<bean id="hibernateResourceStateSubscriptionDAO"
|
||||
class="eu.dnetlib.enabling.is.sn.resourcestate.hib.HibernateResourceStateSubscriptionDAOImpl"
|
||||
p:sessionFactory-ref="issnSessionFactory" />
|
||||
</beans>
|
|
@ -0,0 +1,2 @@
|
|||
services.is.store.enable.java=true
|
||||
services.is.store.initializer.timetosleep = 4000
|
|
@ -0,0 +1,116 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jaxws="http://cxf.apache.org/jaxws"
|
||||
xmlns:sec="http://cxf.apache.org/configuration/security" xmlns:wsa="http://cxf.apache.org/ws/addressing"
|
||||
xmlns:p="http://www.springframework.org/schema/p" xmlns:http="http://cxf.apache.org/transports/http/configuration"
|
||||
xmlns:t="http://dnetlib.eu/springbeans/t" xmlns:template="http://dnetlib.eu/springbeans/template"
|
||||
xmlns:util="http://www.springframework.org/schema/util"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
|
||||
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd
|
||||
http://cxf.apache.org/ws/addressing http://cxf.apache.org/schemas/ws-addr-conf.xsd
|
||||
http://cxf.apache.org/configuration/security http://cxf.apache.org/schemas/configuration/security.xsd
|
||||
http://cxf.apache.org/transports/http/configuration http://cxf.apache.org/schemas/configuration/http-conf.xsd
|
||||
http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd
|
||||
http://dnetlib.eu/springbeans/template http://dnetlib.eu/springbeans/template.xsd">
|
||||
<!-- beans -->
|
||||
|
||||
<bean name="abstractExistDatabase" init-method="start"
|
||||
destroy-method="stop" p:triggerConf-ref="issnTriggers" abstract="true"
|
||||
p:backupDir="${services.is.store.data.path}/backups" />
|
||||
|
||||
<bean name="temporaryExistDatabase" class="eu.dnetlib.xml.database.exist.TemporaryExistDatabase"
|
||||
parent="abstractExistDatabase" lazy-init="true" />
|
||||
|
||||
<bean name="persistentExistDatabase" class="eu.dnetlib.xml.database.exist.PersistentExistDatabase"
|
||||
parent="abstractExistDatabase"
|
||||
p:dbRootPath="${services.is.store.data.path}/db" p:XQueryJavaEnabled="${services.is.store.enable.java}"
|
||||
lazy-init="true" />
|
||||
|
||||
<alias name="${services.is.store.database.bean}" alias="existDatabase"/>
|
||||
|
||||
<!-- Adding interceptors to log about the execution of methods on exist -->
|
||||
<bean name="persistentExistLogInterceptor"
|
||||
class="eu.dnetlib.enabling.tools.LogInterceptor">
|
||||
<property name="enterMessage"
|
||||
value="ENTER | $[targetClassShortName].$[methodName]($[arguments])"/>
|
||||
<property name="exitMessage"
|
||||
value="EXIT | $[targetClassShortName].$[methodName]($[arguments]) | $[invocationTime]ms"/>
|
||||
</bean>
|
||||
|
||||
<bean
|
||||
class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
|
||||
<property name="beanNames" value="persistentExistDatabase"/>
|
||||
<property name="proxyTargetClass" value="true"/>
|
||||
<property name="interceptorNames">
|
||||
<list>
|
||||
<value>persistentExistLogInterceptor</value>
|
||||
</list>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<!-- end AOP interceptors -->
|
||||
|
||||
<util:map id="issnTriggers">
|
||||
<entry key="/db" value-ref="issnIntegrationTrigger" />
|
||||
</util:map>
|
||||
|
||||
<bean name="isStoreService" class="eu.dnetlib.enabling.is.store.ISStoreServiceImpl"
|
||||
scope="singleton" init-method="start" destroy-method="stop"
|
||||
p:xmlDatabase-ref="existDatabase" p:endpoint-ref="isStoreServiceEndpoint"
|
||||
p:contentInitializerJob-ref="embeddedContentLoaderJob" />
|
||||
|
||||
<bean id="bulkResourceImporter" class="eu.dnetlib.enabling.is.store.BulkResourceImporter"
|
||||
p:serviceLocator-ref="uniqueServiceLocator" p:xqueryUtils-ref="xqueryUtils"
|
||||
p:resourceValidator-ref="resourceValidator" p:validating="${services.is.store.bulk.validation}" />
|
||||
|
||||
<bean id="embeddedContentLoaderJob" class="eu.dnetlib.enabling.is.store.TestContentInitializerJob"
|
||||
scope="singleton" p:serviceLocator-ref="uniqueServiceLocator"
|
||||
p:resources="classpath*:/eu/dnetlib/test/profiles/**/*.xml" p:schemas="${services.schemas}"
|
||||
p:resourceLoader-ref="resourceLoaderHelper" p:bulkImporter-ref="bulkResourceImporter"
|
||||
p:snDisable-ref="issnInhibitionCondition" p:timeToSleep="${services.is.store.initializer.timetosleep}" />
|
||||
|
||||
<!-- <bean id="testContentLoaderTrigger" class="org.springframework.scheduling.quartz.SimpleTriggerFactoryBean" -->
|
||||
<!-- p:repeatCount="0" p:startDelay="3000"> -->
|
||||
<!-- <property name="jobDetail"> -->
|
||||
<!-- <bean id="testContentLoaderTriggerDetails" class="org.springframework.scheduling.quartz.JobDetailBean" -->
|
||||
<!-- p:jobClass="eu.dnetlib.enabling.is.store.TestContentInitializerJob" -->
|
||||
<!-- depends-on="snLocator"> -->
|
||||
<!-- <property name="jobDataAsMap"> -->
|
||||
<!-- <map> -->
|
||||
<!-- <entry key="registryLocator" value-ref="registryLocator" /> -->
|
||||
<!-- <entry key="resources" value="classpath*:/eu/dnetlib/test/profiles/**/*.xml"
|
||||
/> -->
|
||||
<!-- <entry key="schemas" value="${services.schemas}" /> -->
|
||||
<!-- <entry key="resourceLoader" value-ref="resourceLoaderHelper" /> -->
|
||||
<!-- <entry key="bulkImporter" value-ref="bulkResourceImporter" /> -->
|
||||
<!-- <entry key="snDisable" value-ref="issnInhibitionCondition" /> -->
|
||||
<!-- </map> -->
|
||||
<!-- </property> -->
|
||||
<!-- </bean> -->
|
||||
<!-- </property> -->
|
||||
<!-- </bean> -->
|
||||
|
||||
<bean id="resourceLoaderHelper" class="eu.dnetlib.enabling.tools.ResourceLoaderHelper" />
|
||||
|
||||
<!-- <bean id="storeJobSchedulerAccessor" -->
|
||||
<!-- class="org.springframework.scheduling.quartz.SchedulerAccessorBean" -->
|
||||
<!-- p:scheduler-ref="jobScheduler"> -->
|
||||
<!-- <property name="triggers"> -->
|
||||
<!-- <list> -->
|
||||
<!-- <ref bean="testContentLoaderTrigger" /> -->
|
||||
<!-- </list> -->
|
||||
<!-- </property> -->
|
||||
<!-- </bean> -->
|
||||
|
||||
<!-- endpoints -->
|
||||
<jaxws:endpoint id="isStoreServiceEndpoint" implementor="#isStoreService"
|
||||
implementorClass="eu.dnetlib.enabling.is.store.rmi.ISStoreService"
|
||||
address="/isStore" />
|
||||
|
||||
<template:instance name="serviceRegistrationManager"
|
||||
t:serviceRegistrationManagerClass="eu.dnetlib.enabling.tools.registration.ValidatingServiceRegistrationManagerImpl"
|
||||
t:name="isStoreServiceRegistrationManager" t:service="isStoreService"
|
||||
t:endpoint="isStoreServiceEndpoint" t:jobScheduler="jobScheduler" />
|
||||
|
||||
|
||||
</beans>
|
|
@ -0,0 +1,10 @@
|
|||
xquery version "1.0";
|
||||
|
||||
module namespace dnet="http://namespace.dnetlib.eu/xquery/dnet";
|
||||
declare namespace xmldb="http://exist-db.org/xquery/xmldb";
|
||||
|
||||
declare function dnet:deleteDocument($x as element()) {
|
||||
|
||||
xmldb:remove(replace($x/base-uri(),'/[^/]*$', ''), replace($x/base-uri(),'^.*/([^/]*)$', '$1'))
|
||||
|
||||
};
|
|
@ -0,0 +1,14 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jaxws="http://cxf.apache.org/jaxws"
|
||||
xmlns:sec="http://cxf.apache.org/configuration/security" xmlns:wsa="http://cxf.apache.org/ws/addressing"
|
||||
xmlns:p="http://www.springframework.org/schema/p" xmlns:http="http://cxf.apache.org/transports/http/configuration"
|
||||
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
|
||||
http://cxf.apache.org/ws/addressing http://cxf.apache.org/schemas/ws-addr-conf.xsd
|
||||
http://cxf.apache.org/configuration/security http://cxf.apache.org/schemas/configuration/security.xsd
|
||||
http://cxf.apache.org/transports/http/configuration http://cxf.apache.org/schemas/configuration/http-conf.xsd
|
||||
http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd">
|
||||
|
||||
<bean id="xqueryUtils" class="eu.dnetlib.enabling.tools.XQueryUtilsImpl" />
|
||||
</beans>
|
|
@ -0,0 +1,85 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<exist xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:noNamespaceSchemaLocation="schema/conf.xsd">
|
||||
|
||||
<db-connection cacheSize="48M" collectionCache="24M"
|
||||
database="native" files="data" pageSize="4096">
|
||||
|
||||
<recovery enabled="yes" group-commit="no" journal-dir="data"
|
||||
size="100M" sync-on-commit="no" />
|
||||
<watchdog output-size-limit="10000" query-timeout="-1" />
|
||||
|
||||
</db-connection>
|
||||
|
||||
<serializer add-exist-id="none" compress-output="no"
|
||||
enable-xinclude="no" enable-xsl="no" indent="no"
|
||||
match-tagging-attributes="no" match-tagging-elements="no" />
|
||||
|
||||
<xquery enable-java-binding="no" enable-query-rewriting="yes"
|
||||
backwardCompatible="no">
|
||||
<builtin-modules>
|
||||
<!-- Default Modules -->
|
||||
<module class="org.exist.xquery.functions.util.UtilModule"
|
||||
uri="http://exist-db.org/xquery/util" />
|
||||
<module class="org.exist.xquery.functions.transform.TransformModule"
|
||||
uri="http://exist-db.org/xquery/transform" />
|
||||
<module class="org.exist.xquery.functions.xmldb.XMLDBModule"
|
||||
uri="http://exist-db.org/xquery/xmldb" />
|
||||
<!-- <module class="org.exist.xquery.functions.request.RequestModule"-->
|
||||
<!-- uri="http://exist-db.org/xquery/request" />-->
|
||||
<!-- <module class="org.exist.xquery.functions.response.ResponseModule"-->
|
||||
<!-- uri="http://exist-db.org/xquery/response" />-->
|
||||
<!-- <module class="org.exist.xquery.functions.session.SessionModule"-->
|
||||
<!-- uri="http://exist-db.org/xquery/session" />-->
|
||||
<!-- <module class="org.exist.xquery.functions.text.TextModule"-->
|
||||
<!-- uri="http://exist-db.org/xquery/text" />-->
|
||||
<!-- <module class="org.exist.xquery.modules.example.ExampleModule"-->
|
||||
<!-- uri="http://exist-db.org/xquery/examples" />-->
|
||||
<!-- <module class="org.exist.xquery.functions.validation.ValidationModule"-->
|
||||
<!-- uri="http://exist-db.org/xquery/validation" />-->
|
||||
<!-- <module class="org.exist.xquery.functions.system.SystemModule"-->
|
||||
<!-- uri="http://exist-db.org/xquery/system" />-->
|
||||
|
||||
<!-- New Modularized Indexes -->
|
||||
<!-- <module class="org.exist.xquery.modules.ngram.NGramModule"-->
|
||||
<!-- uri="http://exist-db.org/xquery/ngram" />-->
|
||||
|
||||
<!--
|
||||
<module class="org.exist.xquery.modules.spatial.SpatialModule"
|
||||
uri="http://exist-db.org/xquery/spatial" />
|
||||
-->
|
||||
<!-- Optional Modules -->
|
||||
<!--
|
||||
<module
|
||||
class="org.exist.xquery.modules.compression.CompressionModule"
|
||||
uri="http://exist-db.org/xquery/compression" /> <module
|
||||
class="org.exist.xquery.modules.datetime.DateTimeModule"
|
||||
uri="http://exist-db.org/xquery/datetime" /> <module
|
||||
class="org.exist.xquery.modules.example.ExampleModule"
|
||||
uri="http://exist-db.org/xquery/examples" /> <module
|
||||
class="org.exist.xquery.modules.httpclient.HTTPClientModule"
|
||||
uri="http://exist-db.org/xquery/httpclient" /> <module
|
||||
class="org.exist.xquery.modules.image.ImageModule"
|
||||
uri="http://exist-db.org/xquery/image" /> <module
|
||||
class="org.exist.xquery.modules.mail.MailModule"
|
||||
uri="http://exist-db.org/xquery/mail" /> <module
|
||||
class="org.exist.xquery.modules.math.MathModule"
|
||||
uri="http://exist-db.org/xquery/math" /> <module
|
||||
class="org.exist.xquery.modules.scheduler.SchedulerModule"
|
||||
uri="http://exist-db.org/xquery/scheduler" /> <module
|
||||
class="org.exist.xquery.modules.simpleql.SimpleQLModule"
|
||||
uri="http://exist-db.org/xquery/simple-ql" /> <module
|
||||
class="org.exist.xquery.modules.sql.SQLModule"
|
||||
uri="http://exist-db.org/xquery/sql" /> <module
|
||||
class="org.exist.xquery.modules.xslfo.XSLFOModule"
|
||||
uri="http://exist-db.org/xquery/xslfo" /> <module
|
||||
class="org.exist.xquery.modules.xmldiff.XmlDiffModule"
|
||||
uri="http://exist-db.org/xquery/xmldiff" />
|
||||
-->
|
||||
</builtin-modules>
|
||||
</xquery>
|
||||
|
||||
<xupdate allowed-fragmentation="5" enable-consistency-checks="no" />
|
||||
|
||||
|
||||
</exist>
|
|
@ -0,0 +1,145 @@
|
|||
package eu.dnetlib.enabling.is.lookup;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.mockito.Matchers.anyString;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.StringReader;
|
||||
import java.io.StringWriter;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.dom4j.Document;
|
||||
import org.dom4j.DocumentException;
|
||||
import org.dom4j.io.SAXReader;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
|
||||
import eu.dnetlib.enabling.is.lookup.rmi.ISLookUpDocumentNotFoundException;
|
||||
import eu.dnetlib.enabling.is.lookup.rmi.ISLookUpException;
|
||||
import eu.dnetlib.enabling.is.store.rmi.ISStoreException;
|
||||
import eu.dnetlib.enabling.is.store.rmi.ISStoreService;
|
||||
import eu.dnetlib.enabling.tools.XQueryUtilsImpl;
|
||||
|
||||
/**
|
||||
* ISLookUpService test.
|
||||
*
|
||||
* @author marko
|
||||
*
|
||||
*/
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class ISLookUpServiceImplTest {
|
||||
|
||||
/**
|
||||
* test profile id.
|
||||
*/
|
||||
private static final String PROF_ID = "first_c2Vjb25k";
|
||||
|
||||
/**
|
||||
* List of ids.
|
||||
*/
|
||||
private static final List<String> ID_LIST = Arrays.asList(new String[] { "fff", "ggg", "hhh" });
|
||||
|
||||
/**
|
||||
* class under test.
|
||||
*/
|
||||
private transient ISLookUpServiceImpl lookup;
|
||||
|
||||
/**
|
||||
* is store service mock.
|
||||
*/
|
||||
@Mock
|
||||
private transient ISStoreService storeService;
|
||||
|
||||
/**
|
||||
* common test case init.
|
||||
*/
|
||||
@Before
|
||||
public void setUp() {
|
||||
lookup = new ISLookUpServiceImpl();
|
||||
lookup.setXqueryUtils(new XQueryUtilsImpl());
|
||||
lookup.setIsStore(storeService);
|
||||
}
|
||||
|
||||
/**
|
||||
* test get file name from id.
|
||||
*/
|
||||
@Test
|
||||
public void testGetFileNameForId() {
|
||||
assertEquals("check", "first", lookup.getFileNameForId(PROF_ID));
|
||||
}
|
||||
|
||||
/**
|
||||
* test get file coll from id.
|
||||
*/
|
||||
@Test
|
||||
public void testGetFileCollForId() {
|
||||
assertEquals("check", "second", lookup.getFileCollForId(PROF_ID));
|
||||
}
|
||||
|
||||
/**
|
||||
* test get resource profile.
|
||||
*
|
||||
* @throws ISLookUpException
|
||||
* shouldn't happen
|
||||
* @throws ISStoreException
|
||||
* shouldn't happen
|
||||
*/
|
||||
@Test
|
||||
public void testGetResourceProfile() throws ISLookUpException, ISStoreException {
|
||||
when(storeService.getXML("first", "/db/DRIVER/second")).thenReturn("<someResult/>");
|
||||
|
||||
assertNotNull("get profile", lookup.getResourceProfile(PROF_ID));
|
||||
}
|
||||
|
||||
/**
|
||||
* test get resource profile when no such document exists.
|
||||
*
|
||||
* @throws ISLookUpException
|
||||
* expected
|
||||
*/
|
||||
@Test(expected = ISLookUpDocumentNotFoundException.class)
|
||||
public void testGetResourceProfileNonExisting() throws ISLookUpException {
|
||||
lookup.getResourceProfile(PROF_ID);
|
||||
}
|
||||
|
||||
/**
|
||||
* test getCollection.
|
||||
*
|
||||
* @throws IOException
|
||||
* could happen
|
||||
* @throws ISStoreException
|
||||
* could happen
|
||||
* @throws ISLookUpException
|
||||
* could happen
|
||||
* @throws DocumentException
|
||||
* could happen
|
||||
*/
|
||||
@Test
|
||||
public void testGetCollection() throws IOException, ISStoreException, ISLookUpException, DocumentException {
|
||||
final StringWriter writer = new StringWriter();
|
||||
IOUtils.copy(getClass().getResourceAsStream("collProfile.xml"), writer);
|
||||
final String simpleProf = writer.getBuffer().toString();
|
||||
|
||||
when(storeService.getXML(anyString(), anyString())).thenReturn(simpleProf);
|
||||
when(
|
||||
storeService.quickSearchXML("for $x in collection('/db/DRIVER/CollectionDSResources') where $x//FATHER/@id = '" + PROF_ID
|
||||
+ "' return $x//RESOURCE_IDENTIFIER/@value/string()")).thenReturn(ID_LIST);
|
||||
|
||||
final String profile = lookup.retrieveCollection(PROF_ID);
|
||||
final SAXReader reader = new SAXReader();
|
||||
final Document doc = reader.read(new StringReader(profile));
|
||||
|
||||
assertEquals("children", ID_LIST.size(), doc.selectNodes("//CHILDREN/CHILD").size());
|
||||
for (final String id : ID_LIST) {
|
||||
assertNotNull("child", doc.selectSingleNode("//CHILDREN/CHILD[@id='" + id + "']"));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
package eu.dnetlib.enabling.is.registry;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import javax.xml.xpath.XPathExpressionException;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
public class ApplicationProfileResourceKindResolverTest {
|
||||
|
||||
private ApplicationProfileResourceKindResolver resolver;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
resolver = new ApplicationProfileResourceKindResolver();
|
||||
}
|
||||
|
||||
@Test(expected = NoSuchPendingCategoryException.class)
|
||||
public void testPending() throws XPathExpressionException {
|
||||
resolver.getPendingKindForType("TestType");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPendingExisting() throws XPathExpressionException {
|
||||
assertEquals("PendingServiceResources", resolver.getPendingKindForType("IndexServiceResourceType"));
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,149 @@
|
|||
package eu.dnetlib.enabling.is.registry;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Matchers.anyObject;
|
||||
import static org.mockito.Matchers.anyString;
|
||||
import static org.mockito.Matchers.eq;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import javax.xml.xpath.XPathExpressionException;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
|
||||
import eu.dnetlib.enabling.is.registry.rmi.ISRegistryException;
|
||||
import eu.dnetlib.enabling.is.registry.rmi.ISRegistryService;
|
||||
import eu.dnetlib.enabling.is.registry.schema.ValidationException;
|
||||
import eu.dnetlib.enabling.is.registry.validation.ProfileValidationStrategy;
|
||||
import eu.dnetlib.enabling.is.registry.validation.RegistrationPhase;
|
||||
import eu.dnetlib.enabling.tools.OpaqueResource;
|
||||
|
||||
/**
|
||||
* test compatibility pending resource manager implementation.
|
||||
*
|
||||
* @author marko
|
||||
*
|
||||
*/
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class CompatPendingResourceManagerImplTest {
|
||||
|
||||
/**
|
||||
* instance under test.
|
||||
*/
|
||||
private transient CompatPendingResourceManagerImpl pendingManager;
|
||||
|
||||
/**
|
||||
* registry service mock.
|
||||
*/
|
||||
@Mock
|
||||
private transient ISRegistryService registryService;
|
||||
|
||||
/**
|
||||
* resource mock.
|
||||
*/
|
||||
@Mock
|
||||
private transient OpaqueResource resource;
|
||||
/**
|
||||
* used to validate resources w.r.t. a set of defined properties.
|
||||
*/
|
||||
@Mock
|
||||
private ProfileValidationStrategy profileValidationStrategy;
|
||||
|
||||
/**
|
||||
* prepare instance for testing.
|
||||
*/
|
||||
@Before
|
||||
public void setUp() {
|
||||
pendingManager = new CompatPendingResourceManagerImpl();
|
||||
pendingManager.setIsRegistry(registryService);
|
||||
pendingManager.setResourceKindResolver(new ApplicationProfileResourceKindResolver());
|
||||
pendingManager.setProfileValidationStrategy(profileValidationStrategy);
|
||||
}
|
||||
|
||||
/**
|
||||
* test that the application profile can be queried correctly.
|
||||
*
|
||||
* @throws XPathExpressionException
|
||||
* shouldn't happen
|
||||
*/
|
||||
@Test
|
||||
public void testGetPendingKindForType() throws XPathExpressionException {
|
||||
assertEquals("check pending", "PendingRepositoryResources", pendingManager.getPendingKindForType("RepositoryServiceResourceType"));
|
||||
assertEquals("check pending", "PendingDSResources", pendingManager.getPendingKindForType("UserDSResourceType"));
|
||||
}
|
||||
|
||||
/**
|
||||
* check that unexistent types throw an exception.
|
||||
*
|
||||
* @throws XPathExpressionException
|
||||
* shouldn't happen
|
||||
*/
|
||||
@Test(expected = IllegalStateException.class)
|
||||
public void testGetPendingKindForNoSuchType() throws XPathExpressionException {
|
||||
pendingManager.getPendingKindForType("NoSuchType");
|
||||
}
|
||||
|
||||
/**
|
||||
* test that the application profile can be queried correctly.
|
||||
*
|
||||
* @throws XPathExpressionException
|
||||
* shouldn't happen
|
||||
*/
|
||||
@Test
|
||||
public void testGetNormalKindForType() throws XPathExpressionException {
|
||||
assertEquals("check kind", "RepositoryServiceResources", pendingManager.getNormalKindForType("RepositoryServiceResourceType"));
|
||||
assertEquals("check kind", "UserDSResources", pendingManager.getNormalKindForType("UserDSResourceType"));
|
||||
assertNull("check unexisting type", pendingManager.getNormalKindForType("NoSuchType"));
|
||||
}
|
||||
|
||||
/**
|
||||
* test that the resource is correctly moved from the pending collection to the new collection.
|
||||
*
|
||||
* @throws ISRegistryException
|
||||
* shoudn't happen
|
||||
* @throws ValidationException
|
||||
*/
|
||||
@Test
|
||||
public void testSetValid() throws ISRegistryException, ValidationException {
|
||||
final String profId = "123";
|
||||
when(resource.asString()).thenReturn("");
|
||||
when(resource.getResourceId()).thenReturn(profId);
|
||||
//when(profileValidationStrategy.accept(any(OpaqueResource.class), eq(RegistrationPhase.Register))).thenReturn(true);
|
||||
|
||||
pendingManager.setValid(resource);
|
||||
|
||||
verify(registryService).deleteProfile(profId);
|
||||
verify(registryService).registerProfile(anyString());
|
||||
|
||||
assertNotNull("dummy", registryService);
|
||||
}
|
||||
|
||||
/**
|
||||
* test that the resource is correctly moved from the current collection to the correct pending collection.
|
||||
*
|
||||
* @throws ISRegistryException
|
||||
* shoudn't happen
|
||||
*/
|
||||
@Test
|
||||
public void testSetPending() throws ISRegistryException {
|
||||
final String profId = "321";
|
||||
when(resource.asString()).thenReturn("");
|
||||
when(resource.getResourceId()).thenReturn(profId);
|
||||
when(resource.getResourceType()).thenReturn("RepositoryServiceResourceType");
|
||||
|
||||
pendingManager.setPending(resource);
|
||||
|
||||
verify(registryService).deleteProfile(profId);
|
||||
verify(registryService).registerProfile(anyString());
|
||||
|
||||
assertNotNull("dummy", registryService);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,489 @@
|
|||
package eu.dnetlib.enabling.is.registry; // NOPMD
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.Matchers.anyObject;
|
||||
import static org.mockito.Matchers.anyString;
|
||||
import static org.mockito.Matchers.eq;
|
||||
import static org.mockito.Mockito.doThrow;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.StringWriter;
|
||||
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
import javax.xml.xpath.XPathExpressionException;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
import org.xml.sax.SAXException;
|
||||
|
||||
import eu.dnetlib.enabling.is.lookup.rmi.ISLookUpException;
|
||||
import eu.dnetlib.enabling.is.lookup.rmi.ISLookUpService;
|
||||
import eu.dnetlib.enabling.is.registry.rmi.ISRegistryException;
|
||||
import eu.dnetlib.enabling.is.registry.schema.OpaqueResourceValidator;
|
||||
import eu.dnetlib.enabling.is.registry.schema.ValidationException;
|
||||
import eu.dnetlib.enabling.is.registry.validation.ProfileValidationStrategy;
|
||||
import eu.dnetlib.enabling.is.registry.validation.RegistrationPhase;
|
||||
import eu.dnetlib.enabling.is.store.rmi.ISStoreException;
|
||||
import eu.dnetlib.enabling.is.store.rmi.ISStoreService;
|
||||
import eu.dnetlib.enabling.tools.CompatResourceIdentifierResolverImpl;
|
||||
import eu.dnetlib.enabling.tools.OpaqueResource;
|
||||
import eu.dnetlib.enabling.tools.ResourceType;
|
||||
import eu.dnetlib.enabling.tools.StringOpaqueResource;
|
||||
import eu.dnetlib.enabling.tools.XQueryUtils;
|
||||
import eu.dnetlib.enabling.tools.XQueryUtilsImpl;
|
||||
|
||||
/**
|
||||
* test registry service.
|
||||
*
|
||||
* @author marko
|
||||
*
|
||||
*/
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class ISRegistryServiceImplTest { // NOPMD
|
||||
|
||||
/**
|
||||
* a test resource type.
|
||||
*/
|
||||
private static final String REPOSITORY_TYPE = "RepositoryServiceResourceType";
|
||||
|
||||
/**
|
||||
* TODO: use a shared constant for this.
|
||||
*/
|
||||
private static final String DB_DRIVER = "/db/DRIVER/";
|
||||
|
||||
/**
|
||||
* class under test.
|
||||
*/
|
||||
private transient ISRegistryServiceImpl registry;
|
||||
|
||||
/**
|
||||
* store service mock.
|
||||
*/
|
||||
@Mock
|
||||
private transient ISStoreService storeService;
|
||||
|
||||
/**
|
||||
* lookup service mock.
|
||||
*/
|
||||
@Mock
|
||||
private transient ISLookUpService lookUpService;
|
||||
|
||||
/**
|
||||
* xml source of a test profile, loaded from test-profile.xml.
|
||||
*/
|
||||
private transient String profileSource;
|
||||
|
||||
/**
|
||||
* resource identifier resolver, converts IDs to filename/collection pairs.
|
||||
*/
|
||||
private transient CompatResourceIdentifierResolverImpl resIdResolver;
|
||||
|
||||
/**
|
||||
* schema validator.
|
||||
*/
|
||||
@Mock
|
||||
private transient OpaqueResourceValidator validator;
|
||||
|
||||
/**
|
||||
* xquery utils, used for xmldb root path.
|
||||
*/
|
||||
private final transient XQueryUtils xqueryUtils = new XQueryUtilsImpl();
|
||||
|
||||
/**
|
||||
* used to validate resources w.r.t. a set of defined properties.
|
||||
*/
|
||||
@Mock
|
||||
private ProfileValidationStrategy profileValidationStrategy;
|
||||
|
||||
/**
|
||||
* common initialization.
|
||||
*
|
||||
* @throws IOException
|
||||
* shouldn't happen
|
||||
*/
|
||||
@Before
|
||||
public void setUp() throws IOException {
|
||||
registry = new ISRegistryServiceImpl();
|
||||
registry.setXqueryUtils(new XQueryUtilsImpl());
|
||||
resIdResolver = new CompatResourceIdentifierResolverImpl();
|
||||
registry.setResIdResolver(resIdResolver);
|
||||
|
||||
final CompatPendingResourceManagerImpl pendingManager = new CompatPendingResourceManagerImpl();
|
||||
pendingManager.setResourceKindResolver(new ApplicationProfileResourceKindResolver());
|
||||
pendingManager.setProfileValidationStrategy(profileValidationStrategy);
|
||||
|
||||
registry.setPendingManager(pendingManager);
|
||||
pendingManager.setIsRegistry(registry);
|
||||
registry.setIsStore(storeService);
|
||||
registry.setIsLookup(lookUpService);
|
||||
|
||||
registry.setResourceValidator(validator);
|
||||
|
||||
final StringWriter writer = new StringWriter();
|
||||
IOUtils.copy(getClass().getResourceAsStream("test-profile.xml"), writer);
|
||||
profileSource = writer.getBuffer().toString();
|
||||
|
||||
registry.setProfileValidationStrategy(profileValidationStrategy);
|
||||
}
|
||||
|
||||
/**
|
||||
* test the deletion of a profile.
|
||||
*
|
||||
* @throws ISRegistryException
|
||||
* shouldn't happen
|
||||
* @throws XPathExpressionException
|
||||
* shouldn't happen
|
||||
* @throws SAXException
|
||||
* shouldn't happen
|
||||
* @throws IOException
|
||||
* shouldn't happen
|
||||
* @throws ParserConfigurationException
|
||||
* shouldn't happen
|
||||
* @throws ISStoreException
|
||||
* shouldn't happen
|
||||
*/
|
||||
@Test
|
||||
public void testDeleteProfile() throws ISRegistryException, XPathExpressionException, SAXException, IOException, ParserConfigurationException,
|
||||
ISStoreException {
|
||||
final OpaqueResource resource = new StringOpaqueResource(profileSource);
|
||||
final String resId = resource.getResourceId();
|
||||
|
||||
boolean catched = false; // NOPMD
|
||||
try {
|
||||
registry.deleteProfile(resId);
|
||||
} catch (ISRegistryDocumentNotFoundException e) {
|
||||
catched = true;
|
||||
}
|
||||
|
||||
assertTrue("exception raised", catched);
|
||||
verify(storeService).deleteXML(registry.getResIdResolver().getFileName(resId), DB_DRIVER + registry.getResIdResolver().getCollectionName(resId));
|
||||
|
||||
assertNotNull("dummy", storeService);
|
||||
}
|
||||
|
||||
/**
|
||||
* test the deletion of an inexitent profile. It should throwa specific exception
|
||||
*
|
||||
* @throws ISRegistryException
|
||||
* shouldn't happen
|
||||
* @throws XPathExpressionException
|
||||
* shouldn't happen
|
||||
* @throws SAXException
|
||||
* shouldn't happen
|
||||
* @throws IOException
|
||||
* shouldn't happen
|
||||
* @throws ParserConfigurationException
|
||||
* shouldn't happen
|
||||
* @throws ISStoreException
|
||||
* shouldn't happen
|
||||
*/
|
||||
@Test(expected = ISRegistryDocumentNotFoundException.class)
|
||||
public void testDeleteInexistentProfile() throws ISRegistryException, XPathExpressionException, SAXException, IOException,
|
||||
ParserConfigurationException, ISStoreException {
|
||||
final OpaqueResource resource = new StringOpaqueResource(profileSource);
|
||||
final String resId = resource.getResourceId();
|
||||
final String wrongId = "xx" + resId;
|
||||
|
||||
when(storeService.deleteXML(registry.getResIdResolver().getFileName(wrongId), DB_DRIVER + registry.getResIdResolver().getCollectionName(wrongId)))
|
||||
.thenReturn(false);
|
||||
|
||||
registry.deleteProfile(wrongId);
|
||||
}
|
||||
|
||||
/**
|
||||
* test register profile.
|
||||
*
|
||||
* @throws ISRegistryException
|
||||
* shouldn't happen
|
||||
* @throws ISStoreException
|
||||
* shouldn't happen
|
||||
* @throws IOException
|
||||
* shouldn't happen
|
||||
* @throws ParserConfigurationException
|
||||
* shouldn't happen
|
||||
* @throws SAXException
|
||||
* shouldn't happen
|
||||
* @throws XPathExpressionException
|
||||
* shouldn't happen
|
||||
* @throws ValidationException
|
||||
*/
|
||||
@Test
|
||||
public void testRegisterProfile() throws ISRegistryException, ISStoreException, IOException, XPathExpressionException, SAXException,
|
||||
ParserConfigurationException, ValidationException {
|
||||
|
||||
when(profileValidationStrategy.accept((OpaqueResource) anyObject(), eq(RegistrationPhase.Register))).thenReturn(true);
|
||||
final String newId = registry.registerProfile(profileSource);
|
||||
|
||||
verify(storeService).insertXML(eq(resIdResolver.getFileName(newId)), eq(DB_DRIVER + resIdResolver.getCollectionName(newId)), anyString());
|
||||
|
||||
final OpaqueResource resource = new StringOpaqueResource(profileSource);
|
||||
assertFalse("new identifier is generated", newId.equals(resource.getResourceId()));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* test update profile.
|
||||
*
|
||||
* @throws XPathExpressionException
|
||||
* should'nt happen
|
||||
* @throws SAXException
|
||||
* should'nt happen
|
||||
* @throws IOException
|
||||
* should'nt happen
|
||||
* @throws ParserConfigurationException
|
||||
* should'nt happen
|
||||
* @throws ISRegistryException
|
||||
* should'nt happen
|
||||
* @throws ISStoreException
|
||||
* should'nt happen
|
||||
*/
|
||||
@Test
|
||||
public void testUpdateProfile() throws XPathExpressionException, SAXException, IOException, ParserConfigurationException, ISRegistryException,
|
||||
ISStoreException {
|
||||
final OpaqueResource resource = new StringOpaqueResource(profileSource);
|
||||
|
||||
final String fileName = resIdResolver.getFileName(resource.getResourceId());
|
||||
final String fileColl = resIdResolver.getCollectionName(resource.getResourceId());
|
||||
when(storeService.updateXML(eq(fileName), eq(DB_DRIVER + fileColl), anyString())).thenReturn(true);
|
||||
|
||||
when(storeService.getXML(fileName, DB_DRIVER + fileColl)).thenReturn(resource.asString());
|
||||
|
||||
final boolean res = registry.updateProfile(resource.getResourceId(), resource.asString(), resource.getResourceType());
|
||||
assertTrue("success", res);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check that the xml schema is correctly validated even on updateProfile.
|
||||
*
|
||||
* @throws XPathExpressionException
|
||||
* cannot happen
|
||||
* @throws SAXException
|
||||
* cannot happen
|
||||
* @throws IOException
|
||||
* cannot happen
|
||||
* @throws ParserConfigurationException
|
||||
* cannot happen
|
||||
* @throws ISRegistryException
|
||||
* mock
|
||||
* @throws ValidationException
|
||||
* mock
|
||||
*/
|
||||
@Test(expected = ISRegistryException.class)
|
||||
public void testUpdateProfileSchemaValidate() throws XPathExpressionException, SAXException, IOException, ParserConfigurationException,
|
||||
ISRegistryException, ValidationException {
|
||||
final OpaqueResource resource = new StringOpaqueResource(profileSource);
|
||||
|
||||
//doThrow(new ValidationException("invalid xml")).when(validator).validate((OpaqueResource) anyObject());
|
||||
|
||||
registry.updateProfile(resource.getResourceId(), "<invalid/>", resource.getResourceType());
|
||||
}
|
||||
|
||||
/**
|
||||
* test profile validation.
|
||||
*
|
||||
* @throws XPathExpressionException
|
||||
* shouldn't happen
|
||||
* @throws SAXException
|
||||
* shouldn't happen
|
||||
* @throws IOException
|
||||
* shouldn't happen
|
||||
* @throws ParserConfigurationException
|
||||
* shouldn't happen
|
||||
* @throws ISRegistryException
|
||||
* shouldn't happen
|
||||
* @throws ISStoreException
|
||||
* shouldn't happen
|
||||
* @throws ISLookUpException
|
||||
* shouldn't happen
|
||||
* @throws ValidationException
|
||||
*/
|
||||
@Test
|
||||
public void testValidateProfile() throws XPathExpressionException, SAXException, IOException, ParserConfigurationException, ISRegistryException,
|
||||
ISStoreException, ISLookUpException, ValidationException {
|
||||
final OpaqueResource resource = new StringOpaqueResource(profileSource);
|
||||
|
||||
final String oldId = registry.insertProfileForValidation(resource.getResourceType(), resource.asString());
|
||||
resource.setResourceKind("PendingRepositoryResources"); // simulate the validation
|
||||
|
||||
resource.setResourceId(oldId);
|
||||
when(lookUpService.getResourceProfile(oldId)).thenReturn(resource.asString());
|
||||
when(storeService.deleteXML(resIdResolver.getFileName(oldId), DB_DRIVER + resIdResolver.getCollectionName(oldId))).thenReturn(true);
|
||||
when(profileValidationStrategy.accept((OpaqueResource) anyObject(), eq(RegistrationPhase.Register))).thenReturn(true);
|
||||
|
||||
final String newId = registry.validateProfile(oldId);
|
||||
|
||||
verify(storeService).deleteXML(resIdResolver.getFileName(oldId), DB_DRIVER + resIdResolver.getCollectionName(oldId));
|
||||
verify(storeService).insertXML(eq(resIdResolver.getFileName(newId)), eq(DB_DRIVER + resIdResolver.getCollectionName(newId)), anyString());
|
||||
|
||||
assertFalse("the id should be be unstable", resIdResolver.getFileName(oldId).equals(resIdResolver.getFileName(newId)));
|
||||
}
|
||||
|
||||
/**
|
||||
* test invalidate profile.
|
||||
*
|
||||
* @throws XPathExpressionException
|
||||
* shouldn't happen
|
||||
* @throws SAXException
|
||||
* shouldn't happen
|
||||
* @throws IOException
|
||||
* shouldn't happen
|
||||
* @throws ParserConfigurationException
|
||||
* shouldn't happen
|
||||
* @throws ISRegistryException
|
||||
* shouldn't happen
|
||||
* @throws ISStoreException
|
||||
* shouldn't happen
|
||||
* @throws ISLookUpException
|
||||
* shouldn't happen
|
||||
*/
|
||||
@Test
|
||||
public void testInvalidateProfile() throws XPathExpressionException, SAXException, IOException, ParserConfigurationException, ISRegistryException,
|
||||
ISStoreException, ISLookUpException {
|
||||
|
||||
final OpaqueResource resource = new StringOpaqueResource(profileSource);
|
||||
resource.setResourceKind("PendingResources");
|
||||
|
||||
final String oldId = registry.registerProfile(resource.asString());
|
||||
|
||||
resource.setResourceId(oldId);
|
||||
when(lookUpService.getResourceProfile(oldId)).thenReturn(resource.asString());
|
||||
when(storeService.deleteXML(resIdResolver.getFileName(oldId), DB_DRIVER + resIdResolver.getCollectionName(oldId))).thenReturn(true);
|
||||
|
||||
final String newId = registry.invalidateProfile(oldId);
|
||||
|
||||
verify(storeService).deleteXML(resIdResolver.getFileName(oldId), DB_DRIVER + resIdResolver.getCollectionName(oldId));
|
||||
verify(storeService).insertXML(eq(resIdResolver.getFileName(newId)), eq(DB_DRIVER + resIdResolver.getCollectionName(newId)), anyString());
|
||||
|
||||
assertFalse("the id should be be unstable", resIdResolver.getFileName(oldId).equals(resIdResolver.getFileName(newId)));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* test that the resource kind is correctly changed when inserting for validation.
|
||||
*
|
||||
* @throws IOException
|
||||
* shouldn't happen
|
||||
* @throws ISRegistryException
|
||||
* shouldn't happen
|
||||
* @throws ISStoreException
|
||||
* shouldn't happen
|
||||
* @throws XPathExpressionException
|
||||
* shouldn't happen
|
||||
* @throws SAXException
|
||||
* shouldn't happen
|
||||
* @throws ParserConfigurationException
|
||||
* shouldn't happen
|
||||
*/
|
||||
@Test
|
||||
public void testInsertProfileForValidation() throws IOException, ISRegistryException, ISStoreException, XPathExpressionException, SAXException,
|
||||
ParserConfigurationException {
|
||||
|
||||
final OpaqueResource resource = new StringOpaqueResource(profileSource);
|
||||
final String newId = registry.insertProfileForValidation(resource.getResourceType(), resource.asString());
|
||||
|
||||
verify(storeService).insertXML(eq(resIdResolver.getFileName(newId)), eq(DB_DRIVER + "PendingRepositoryResources/RepositoryServiceResourceType"),
|
||||
anyString());
|
||||
|
||||
verify(storeService, never()).deleteXML(anyString(), anyString());
|
||||
|
||||
assertEquals("check pending id", "PendingRepositoryResources/RepositoryServiceResourceType", resIdResolver.getCollectionName(newId));
|
||||
}
|
||||
|
||||
/**
|
||||
* The ISRegistry's insertProfileForValidation contract specifies that an exception should be raised if the argument doesn't match the
|
||||
* type.
|
||||
*
|
||||
* @throws IOException
|
||||
* shouldn't happen
|
||||
* @throws ISRegistryException
|
||||
* expected
|
||||
*/
|
||||
@Test(expected = ISRegistryException.class)
|
||||
public void testInsertProfileForValidationInvalid() throws IOException, ISRegistryException {
|
||||
registry.insertProfileForValidation("WrongRepositoryServiceResourceType", profileSource);
|
||||
}
|
||||
|
||||
/**
|
||||
* test resource type addition.
|
||||
*
|
||||
* @throws ISRegistryException
|
||||
* shouldn't happen
|
||||
* @throws IOException
|
||||
* shouldn't happen
|
||||
* @throws ISStoreException
|
||||
* cannot happen, mock
|
||||
*/
|
||||
@Test
|
||||
public void testAddResourceType() throws ISRegistryException, IOException, ISStoreException {
|
||||
final StringWriter resourceSchema = new StringWriter();
|
||||
|
||||
IOUtils.copy(getClass().getResourceAsStream("RepositoryServiceResourceType.xsd"), resourceSchema);
|
||||
assertNotNull("check schema", resourceSchema.toString());
|
||||
|
||||
registry.addResourceType(REPOSITORY_TYPE, resourceSchema.toString());
|
||||
|
||||
verify(storeService).insertXML(REPOSITORY_TYPE, xqueryUtils.getRootCollection() + ResourceType.RESOURCE_TYPES, resourceSchema.toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* test resource type deletion.
|
||||
*
|
||||
* @throws ISRegistryException
|
||||
* shouldn't happen
|
||||
* @throws ISStoreException
|
||||
* cannot happen, mock
|
||||
*/
|
||||
@Test
|
||||
public void testDeleteResourceType() throws ISRegistryException, ISStoreException {
|
||||
assertNotNull("dummy", registry);
|
||||
|
||||
registry.deleteResourceType(REPOSITORY_TYPE, false);
|
||||
|
||||
verify(storeService).deleteXML(REPOSITORY_TYPE, xqueryUtils.getRootCollection() + ResourceType.RESOURCE_TYPES);
|
||||
}
|
||||
|
||||
/**
|
||||
* register secure profile.
|
||||
*
|
||||
* @throws ISRegistryException
|
||||
* shouldn't happen
|
||||
* @throws ISLookUpException
|
||||
* mocked
|
||||
* @throws IOException
|
||||
* shouldn't happen
|
||||
* @throws ISStoreException
|
||||
* mock
|
||||
* @throws ValidationException
|
||||
*/
|
||||
@Test
|
||||
public void testRegisterSecureProfile() throws ISRegistryException, ISLookUpException, IOException, ISStoreException, ValidationException { // NOPMD
|
||||
final String resourceProfId = "12-70b2a9e0-7d53-4ffb-be43-f3c571ae21a6_VXNlckRTUmVzb3VyY2VzL1VzZXJEU1Jlc291cmNlVHlwZQ==";
|
||||
final String secureProfId = "sec123_U2VjdXJpdHlQcm9maWxlRFNSZXNvdXJjZXMvU2VjdXJpdHlQcm9maWxlRFNSZXNvdXJjZVR5cGU=";
|
||||
|
||||
final StringWriter profile = new StringWriter();
|
||||
IOUtils.copy(getClass().getResourceAsStream("userProfile.xml"), profile);
|
||||
when(lookUpService.getResourceProfile(resourceProfId)).thenReturn(profile.toString());
|
||||
when(profileValidationStrategy.accept((OpaqueResource) anyObject(), eq(RegistrationPhase.Register))).thenReturn(true);
|
||||
|
||||
final StringWriter secure = new StringWriter();
|
||||
IOUtils.copy(getClass().getResourceAsStream("securityProfile.xml"), secure);
|
||||
when(lookUpService.getResourceProfile(secureProfId)).thenReturn(secure.toString());
|
||||
when(storeService.deleteXML(resIdResolver.getFileName(resourceProfId), DB_DRIVER + resIdResolver.getCollectionName(resourceProfId))).thenReturn(
|
||||
true);
|
||||
when(storeService.updateXML(eq("sec123"), eq(DB_DRIVER + "SecurityProfileDSResources/SecurityProfileDSResourceType"), anyString())).thenReturn(
|
||||
true);
|
||||
when(storeService.getXML("sec123", DB_DRIVER + "SecurityProfileDSResources/SecurityProfileDSResourceType")).thenReturn("<RESOURCE_PROFILE/>");
|
||||
|
||||
registry.registerSecureProfile(resourceProfId, secureProfId);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
package eu.dnetlib.enabling.is.registry;
|
||||
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import javax.xml.xpath.XPathExpressionException;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* Test the name based resource kind resolver.
|
||||
*
|
||||
* @author marko
|
||||
*
|
||||
*/
|
||||
public class NameBasedResourceKindResolverTest {
|
||||
|
||||
/**
|
||||
* instance under test.
|
||||
*/
|
||||
private NameBasedResourceKindResolver resolver;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
resolver = new NameBasedResourceKindResolver();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testService() throws XPathExpressionException {
|
||||
assertEquals("ServiceResources", resolver.getNormalKindForType("MyNewServiceResourceType"));
|
||||
assertEquals("PendingServiceResources", resolver.getPendingKindForType("MyNewServiceResourceType"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGeneric() throws XPathExpressionException {
|
||||
assertEquals("MyNewResources", resolver.getNormalKindForType("MyNewResourceType"));
|
||||
assertEquals("PendingDSResources", resolver.getPendingKindForType("MyNewResourceType"));
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,293 @@
|
|||
package eu.dnetlib.enabling.is.registry; // NOPMD
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.fail;
|
||||
import static org.mockito.Matchers.anyString;
|
||||
import static org.mockito.Matchers.argThat;
|
||||
import static org.mockito.Matchers.eq;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.StringWriter;
|
||||
|
||||
import javax.xml.bind.JAXBException;
|
||||
import javax.xml.transform.dom.DOMSource;
|
||||
import javax.xml.xpath.XPathConstants;
|
||||
import javax.xml.xpath.XPathFactory;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.ArgumentMatcher;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
import org.w3c.dom.Element;
|
||||
import org.w3c.dom.Node;
|
||||
|
||||
import eu.dnetlib.enabling.is.lookup.rmi.ISLookUpException;
|
||||
import eu.dnetlib.enabling.is.lookup.rmi.ISLookUpService;
|
||||
import eu.dnetlib.enabling.is.registry.rmi.ISRegistryException;
|
||||
import eu.dnetlib.enabling.is.registry.rmi.ISRegistryService;
|
||||
import eu.dnetlib.enabling.tools.OpaqueResource;
|
||||
import eu.dnetlib.enabling.tools.StringOpaqueResource;
|
||||
import eu.dnetlib.enabling.tools.blackboard.ActionStatus;
|
||||
import eu.dnetlib.enabling.tools.blackboard.BlackboardMessage;
|
||||
import eu.dnetlib.enabling.tools.blackboard.BlackboardMessageImpl;
|
||||
import eu.dnetlib.enabling.tools.blackboard.BlackboardParameter;
|
||||
import eu.dnetlib.enabling.tools.blackboard.BlackboardParameterImpl;
|
||||
import eu.dnetlib.miscutils.jaxb.JaxbFactory;
|
||||
|
||||
/**
|
||||
* RegistryBlackboardManagerImpl test.
|
||||
*
|
||||
* @author marko
|
||||
*
|
||||
*/
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class RegistryBlackboardManagerImplTest {
|
||||
|
||||
/**
|
||||
* logger.
|
||||
*/
|
||||
private static final Log log = LogFactory.getLog(RegistryBlackboardManagerImplTest.class); // NOPMD by marko on 11/24/08 5:02 PM
|
||||
|
||||
/**
|
||||
* test message id.
|
||||
*/
|
||||
private static final String MSG_ID = "xxx";
|
||||
|
||||
/**
|
||||
* fake message date.
|
||||
*/
|
||||
private static final String MSG_DATE = "2009-03-19T17:55:45+01:00";
|
||||
|
||||
/**
|
||||
* service profile ID.
|
||||
*/
|
||||
private static final String PROF_ID = "123";
|
||||
|
||||
/**
|
||||
* lookup service mock.
|
||||
*/
|
||||
@Mock
|
||||
private transient ISLookUpService lookupService;
|
||||
|
||||
/**
|
||||
* registry service mock.
|
||||
*/
|
||||
@Mock
|
||||
private transient ISRegistryService registryService;
|
||||
|
||||
/**
|
||||
* instance under test.
|
||||
*/
|
||||
private transient RegistryBlackboardManagerImpl manager;
|
||||
|
||||
/**
|
||||
* common setup.
|
||||
*
|
||||
* @throws JAXBException
|
||||
* could happen
|
||||
* @throws IOException
|
||||
* shouldn't happen
|
||||
* @throws ISLookUpException
|
||||
* mock
|
||||
*/
|
||||
@Before
|
||||
public void setUp() throws JAXBException, IOException, ISLookUpException {
|
||||
manager = new RegistryBlackboardManagerImpl();
|
||||
manager.setIsLookup(lookupService);
|
||||
manager.setRegistryService(registryService);
|
||||
|
||||
manager.setMessageFactory(new JaxbFactory<BlackboardMessage>(BlackboardMessageImpl.class));
|
||||
|
||||
manager.setMessageDater(new RegistryBlackboardManagerImpl.MessageDater() {
|
||||
|
||||
@Override
|
||||
public String getCurrentDate() {
|
||||
return MSG_DATE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getNumericStamp() {
|
||||
return "1237483712.666000";
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* add message.
|
||||
*
|
||||
* @throws JAXBException
|
||||
* could happen
|
||||
* @throws ISRegistryException
|
||||
* could happen
|
||||
* @throws IOException
|
||||
* could happen
|
||||
* @throws ISLookUpException
|
||||
* mock
|
||||
*/
|
||||
@Test
|
||||
public void testAddMessage() throws JAXBException, ISRegistryException, IOException, ISLookUpException {
|
||||
final StringWriter serviceProfile = new StringWriter();
|
||||
IOUtils.copy(getClass().getResourceAsStream("serviceProfile.xml"), serviceProfile);
|
||||
when(lookupService.getResourceProfile(PROF_ID)).thenReturn(serviceProfile.toString());
|
||||
|
||||
final BlackboardMessage message = manager.getMessageFactory().newInstance();
|
||||
message.setId(MSG_ID);
|
||||
message.setDate(MSG_DATE);
|
||||
message.setAction("CREATE");
|
||||
message.setActionStatus(ActionStatus.ASSIGNED);
|
||||
|
||||
final BlackboardParameter param1 = new BlackboardParameterImpl();
|
||||
param1.setName("format");
|
||||
param1.setValue("DMF");
|
||||
message.getParameters().add(param1);
|
||||
|
||||
final BlackboardParameter param2 = new BlackboardParameterImpl();
|
||||
param1.setName("id");
|
||||
param1.setValue("");
|
||||
message.getParameters().add(param2);
|
||||
|
||||
manager.addMessage(PROF_ID, MSG_ID, manager.getMessageFactory().serialize(message));
|
||||
|
||||
verify(registryService).updateProfile(eq(PROF_ID), argThat(new ArgumentMatcher<String>() {
|
||||
|
||||
@Override
|
||||
public boolean matches(final String argument) {
|
||||
log.info("arg: " + argument);
|
||||
|
||||
try {
|
||||
final OpaqueResource updatedResource = new StringOpaqueResource((String) argument);
|
||||
final Node messageNode = (Node) XPathFactory.newInstance().newXPath().evaluate("//BLACKBOARD/MESSAGE[last()]",
|
||||
updatedResource.asDom(), XPathConstants.NODE);
|
||||
|
||||
final BlackboardMessage updatedMessage = manager.getMessageFactory().parse(new DOMSource(messageNode));
|
||||
|
||||
assertEquals("messages should match", message, updatedMessage);
|
||||
|
||||
final Element lastUpdated = (Element) XPathFactory.newInstance().newXPath().evaluate("//BLACKBOARD/LAST_REQUEST",
|
||||
updatedResource.asDom(), XPathConstants.NODE);
|
||||
assertEquals("stamp date", manager.getMessageDater().getNumericStamp(), lastUpdated.getAttribute("date"));
|
||||
assertEquals("stamp message", MSG_ID, lastUpdated.getTextContent());
|
||||
} catch (Exception e) {
|
||||
fail("got exception" + e);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}), anyString());
|
||||
}
|
||||
|
||||
/**
|
||||
* delete message.
|
||||
*
|
||||
* @throws ISLookUpException
|
||||
* mock
|
||||
* @throws IOException
|
||||
* could happen
|
||||
* @throws ISRegistryException
|
||||
* mock
|
||||
*/
|
||||
@Test
|
||||
public void testDeleteMessage() throws ISLookUpException, IOException, ISRegistryException {
|
||||
final StringWriter serviceProfile = new StringWriter();
|
||||
|
||||
IOUtils.copy(getClass().getResourceAsStream("serviceProfileWithMessage.xml"), serviceProfile);
|
||||
when(lookupService.getResourceProfile(PROF_ID)).thenReturn(serviceProfile.toString());
|
||||
|
||||
manager.deleteMessage(PROF_ID, MSG_ID);
|
||||
|
||||
verify(registryService).updateProfile(eq(PROF_ID), argThat(new ArgumentMatcher<String>() {
|
||||
|
||||
@Override
|
||||
public boolean matches(final String argument) {
|
||||
log.debug("arg: " + argument);
|
||||
|
||||
try {
|
||||
final OpaqueResource updatedResource = new StringOpaqueResource((String) argument);
|
||||
|
||||
final Node messageNode = (Node) XPathFactory.newInstance().newXPath().evaluate("//BLACKBOARD/MESSAGE[last()]",
|
||||
updatedResource.asDom(), XPathConstants.NODE);
|
||||
|
||||
assertNull("message should be deleted", messageNode);
|
||||
} catch (Exception e) {
|
||||
fail("got exception" + e);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}), anyString());
|
||||
|
||||
// assertNotNull("dummy", manager);
|
||||
}
|
||||
|
||||
/**
|
||||
* replay message.
|
||||
*
|
||||
* @throws ISLookUpException
|
||||
* mock
|
||||
* @throws IOException
|
||||
* shouldn't happen
|
||||
* @throws ISRegistryException
|
||||
* mock
|
||||
* @throws JAXBException
|
||||
* could happen
|
||||
*/
|
||||
@Test
|
||||
public void testReplyMessage() throws ISLookUpException, IOException, ISRegistryException, JAXBException {
|
||||
final StringWriter serviceProfile = new StringWriter();
|
||||
|
||||
IOUtils.copy(getClass().getResourceAsStream("serviceProfileWithMessage.xml"), serviceProfile);
|
||||
when(lookupService.getResourceProfile(PROF_ID)).thenReturn(serviceProfile.toString());
|
||||
|
||||
final BlackboardMessage message = manager.getMessageFactory().newInstance();
|
||||
message.setId(MSG_ID);
|
||||
message.setDate(MSG_DATE);
|
||||
message.setAction("CREATE");
|
||||
message.setActionStatus(ActionStatus.ONGOING);
|
||||
|
||||
final BlackboardParameter param1 = new BlackboardParameterImpl();
|
||||
param1.setName("format");
|
||||
param1.setValue("DMF");
|
||||
message.getParameters().add(param1);
|
||||
|
||||
final BlackboardParameter param2 = new BlackboardParameterImpl();
|
||||
param1.setName("id");
|
||||
param1.setValue("");
|
||||
message.getParameters().add(param2);
|
||||
|
||||
manager.replyMessage(PROF_ID, manager.getMessageFactory().serialize(message));
|
||||
|
||||
verify(registryService).updateProfile(eq(PROF_ID), argThat(new ArgumentMatcher<String>() {
|
||||
|
||||
@Override
|
||||
public boolean matches(final String argument) {
|
||||
log.info("arg: " + argument);
|
||||
|
||||
try {
|
||||
final OpaqueResource updatedResource = new StringOpaqueResource((String) argument);
|
||||
|
||||
final Node messageNode = (Node) XPathFactory.newInstance().newXPath().evaluate("//BLACKBOARD/MESSAGE[last()]",
|
||||
updatedResource.asDom(), XPathConstants.NODE);
|
||||
|
||||
final BlackboardMessage updatedMessage = manager.getMessageFactory().parse(new DOMSource(messageNode));
|
||||
|
||||
assertEquals("messages should match", message, updatedMessage);
|
||||
|
||||
final Element lastUpdated = (Element) XPathFactory.newInstance().newXPath().evaluate("//BLACKBOARD/LAST_RESPONSE",
|
||||
updatedResource.asDom(), XPathConstants.NODE);
|
||||
assertEquals("stamp date", manager.getMessageDater().getNumericStamp(), lastUpdated.getAttribute("date"));
|
||||
assertEquals("stamp message", MSG_ID, lastUpdated.getTextContent());
|
||||
} catch (Exception e) {
|
||||
fail("got exception" + e);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}), anyString());
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
package eu.dnetlib.enabling.is.registry;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import javax.xml.xpath.XPathExpressionException;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
/**
|
||||
* Test if the kind resolver chain correctly fails back.
|
||||
*
|
||||
* @author marko
|
||||
*
|
||||
*/
|
||||
public class ResourceKindResolverChainTest {
|
||||
|
||||
private ResourceKindResolverChain chain;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
chain = new ResourceKindResolverChain();
|
||||
chain.setResolvers(Lists.newArrayList(new ApplicationProfileResourceKindResolver(), new NameBasedResourceKindResolver()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testChain() throws XPathExpressionException {
|
||||
assertEquals("ServiceResources", chain.getNormalKindForType("MyServiceResourceType"));
|
||||
assertEquals("PendingServiceResources", chain.getPendingKindForType("MyServiceResourceType"));
|
||||
|
||||
assertEquals("RepositoryServiceResources", chain.getNormalKindForType("RepositoryServiceResourceType"));
|
||||
assertEquals("PendingRepositoryResources", chain.getPendingKindForType("RepositoryServiceResourceType"));
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue