added dnet-information-serice, which embeds old cnr-xmldb, cnr-enabling-services

This commit is contained in:
Claudio Atzori 2019-06-04 18:03:36 +02:00
parent c121531bdc
commit 103acc089e
334 changed files with 16114 additions and 23 deletions

View File

@ -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>

View File

@ -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>

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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");
}
}

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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;
}
}

View File

@ -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;
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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);
}
}
}

View File

@ -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);
}

View File

@ -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;
}
}

View File

@ -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();
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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);
}

View File

@ -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'.
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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();
}

View File

@ -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;
}
}

View File

@ -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();
}
}
}

View File

@ -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);
}
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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();
}
}

View File

@ -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);
}

View File

@ -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;
}
}

View File

@ -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();
}

View File

@ -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);
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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);
}

View File

@ -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;
}
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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;
}
}

View File

@ -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);
}
}
}

View File

@ -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);
}
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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);
}

View File

@ -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;
}
}

View File

@ -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);
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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 };
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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'))
};

View File

@ -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()));
}
}

View File

@ -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;
}
}

View File

@ -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);
}

View File

@ -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;
}
}

View File

@ -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];
}
}

View File

@ -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;
}
}

View File

@ -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);
}
}

View 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);
}

View File

@ -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();
}

View File

@ -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 {
}
}

View File

@ -0,0 +1,10 @@
package eu.dnetlib.xml.database.exist;
/**
* Created by claudio on 20/12/2016.
*/
public enum EventType {
UPDATE,
CREATE,
DELETE
}

View File

@ -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));
}
}

View File

@ -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();
}
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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))";
}
}

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -0,0 +1,2 @@
# values: idPreservingPendingManager, compatPendingManager
services.registry.pending.resource.manager=idPreservingPendingManager

View File

@ -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>

View File

@ -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

View File

@ -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>

View File

@ -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>

View File

@ -0,0 +1,2 @@
services.is.store.enable.java=true
services.is.store.initializer.timetosleep = 4000

View File

@ -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>

View File

@ -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'))
};

View File

@ -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>

View File

@ -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>

View File

@ -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 + "']"));
}
}
}

View File

@ -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"));
}
}

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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"));
}
}

View File

@ -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());
}
}

View File

@ -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