added dnet-information-serice, which embeds old cnr-xmldb, cnr-enabling-services
This commit is contained in:
parent
c121531bdc
commit
103acc089e
|
@ -65,12 +65,6 @@
|
||||||
<artifactId>gson</artifactId>
|
<artifactId>gson</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
|
||||||
<groupId>junit</groupId>
|
|
||||||
<artifactId>junit</artifactId>
|
|
||||||
<scope>test</scope>
|
|
||||||
</dependency>
|
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>log4j</groupId>
|
<groupId>log4j</groupId>
|
||||||
<artifactId>log4j</artifactId>
|
<artifactId>log4j</artifactId>
|
||||||
|
|
|
@ -0,0 +1,152 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<parent>
|
||||||
|
<groupId>eu.dnetlib</groupId>
|
||||||
|
<artifactId>dnet-core</artifactId>
|
||||||
|
<version>1.0.0-SNAPSHOT</version>
|
||||||
|
</parent>
|
||||||
|
<artifactId>dnet-information-service</artifactId>
|
||||||
|
<groupId>eu.dnetlib</groupId>
|
||||||
|
<packaging>jar</packaging>
|
||||||
|
<version>1.0.0-SNAPSHOT</version>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>eu.dnetlib</groupId>
|
||||||
|
<artifactId>dnet-core-components</artifactId>
|
||||||
|
<version>${project.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>eu.dnetlib</groupId>
|
||||||
|
<artifactId>dnet-core-services</artifactId>
|
||||||
|
<version>${project.version}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- Spring -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework</groupId>
|
||||||
|
<artifactId>spring-orm</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<!-- Exist XmlDB -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.exist-db</groupId>
|
||||||
|
<artifactId>exist-core</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.exist-db</groupId>
|
||||||
|
<artifactId>exist-start</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.postgresql</groupId>
|
||||||
|
<artifactId>postgresql</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.xerial</groupId>
|
||||||
|
<artifactId>sqlite-jdbc</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.hibernate</groupId>
|
||||||
|
<artifactId>hibernate-core</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>commons-collections</groupId>
|
||||||
|
<artifactId>commons-collections</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>commons-dbcp</groupId>
|
||||||
|
<artifactId>commons-dbcp</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.sun.xml.messaging.saaj</groupId>
|
||||||
|
<artifactId>saaj-impl</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>jaxen</groupId>
|
||||||
|
<artifactId>jaxen</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>xerces</groupId>
|
||||||
|
<artifactId>xercesImpl</artifactId>
|
||||||
|
<!-- scope needed for both compile and test -->
|
||||||
|
<!-- <scope>compile</scope> -->
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.aspectj</groupId>
|
||||||
|
<artifactId>aspectjrt</artifactId>
|
||||||
|
<!-- scope needed for both compile and test -->
|
||||||
|
<scope>runtime</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>commons-codec</groupId>
|
||||||
|
<artifactId>commons-codec</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>commons-beanutils</groupId>
|
||||||
|
<artifactId>commons-beanutils</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.cxf</groupId>
|
||||||
|
<artifactId>cxf-rt-frontend-jaxws</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
|
||||||
|
<!-- Test deps -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>hsqldb</groupId>
|
||||||
|
<artifactId>hsqldb</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.aspectj</groupId>
|
||||||
|
<artifactId>aspectjweaver</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.hibernate</groupId>
|
||||||
|
<artifactId>hibernate-annotations</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework</groupId>
|
||||||
|
<artifactId>spring-webmvc</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework</groupId>
|
||||||
|
<artifactId>spring-test</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.cxf</groupId>
|
||||||
|
<artifactId>cxf-rt-ws-policy</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.cxf</groupId>
|
||||||
|
<artifactId>cxf-rt-frontend-jaxrs</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.cxf</groupId>
|
||||||
|
<artifactId>cxf-rt-transports-local</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.cxf</groupId>
|
||||||
|
<artifactId>cxf-rt-ws-rm</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
</project>
|
|
@ -0,0 +1,394 @@
|
||||||
|
package eu.dnetlib.enabling.is.lookup;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.StringReader;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
import javax.jws.WebService;
|
||||||
|
import javax.xml.parsers.ParserConfigurationException;
|
||||||
|
import javax.xml.xpath.XPathExpressionException;
|
||||||
|
|
||||||
|
import com.sun.xml.messaging.saaj.util.Base64;
|
||||||
|
import eu.dnetlib.enabling.is.lookup.rmi.ISLookUpDocumentNotFoundException;
|
||||||
|
import eu.dnetlib.enabling.is.lookup.rmi.ISLookUpException;
|
||||||
|
import eu.dnetlib.enabling.is.lookup.rmi.ISLookUpService;
|
||||||
|
import eu.dnetlib.enabling.is.store.rmi.ISStoreException;
|
||||||
|
import eu.dnetlib.enabling.is.store.rmi.ISStoreService;
|
||||||
|
import eu.dnetlib.enabling.tools.*;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.apache.commons.logging.Log;
|
||||||
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
import org.dom4j.Document;
|
||||||
|
import org.dom4j.Element;
|
||||||
|
import org.dom4j.io.SAXReader;
|
||||||
|
import org.springframework.beans.factory.annotation.Required;
|
||||||
|
import org.xml.sax.SAXException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ISLookUpService implementation.
|
||||||
|
*
|
||||||
|
* @author marko
|
||||||
|
* @author michele
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@WebService(targetNamespace = "http://services.dnetlib.eu/")
|
||||||
|
public class ISLookUpServiceImpl extends AbstractBaseService implements ISLookUpService { // NOPMD
|
||||||
|
|
||||||
|
/**
|
||||||
|
* error message when the given collection cannot be fetched.
|
||||||
|
*/
|
||||||
|
private static final String COLLECTION_ERROR = "cannot get collection";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* base xmldb directory.
|
||||||
|
*/
|
||||||
|
private static final String DB_BASE_DIR = "/db/DRIVER";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* error message when the profile is not present in the db.
|
||||||
|
*/
|
||||||
|
private static final String PROFILE_NOT_FOUND = "Profile not found";
|
||||||
|
|
||||||
|
private ISStoreService isStore;
|
||||||
|
|
||||||
|
// NOPMD by marko on 11/24/08
|
||||||
|
// 5:02 PM
|
||||||
|
/**
|
||||||
|
* logger.
|
||||||
|
*/
|
||||||
|
public static final Log log = LogFactory.getLog(ISLookUpServiceImpl.class); // NOPMD by marko on 11/24/08 5:02 PM
|
||||||
|
|
||||||
|
/**
|
||||||
|
* resource identifier resolver. Resolves identifiers to xmldb file and collection names.
|
||||||
|
*/
|
||||||
|
private ResourceIdentifierResolver resIdManager = new CompatResourceIdentifierResolverImpl();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* xquery utils. Used to obtain the xmldb collection mapping for resources.
|
||||||
|
*/
|
||||||
|
private XQueryUtils xqueryUtils;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*
|
||||||
|
* @see eu.dnetlib.enabling.is.lookup.rmi.ISLookUpService#flushCachedResultSets()
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public Boolean flushCachedResultSets() {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*
|
||||||
|
* @see eu.dnetlib.enabling.is.lookup.rmi.ISLookUpService#retrieveCollection(java.lang.String)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String retrieveCollection(final String profId) throws ISLookUpException {
|
||||||
|
try {
|
||||||
|
String profile = this.getResourceProfile(profId);
|
||||||
|
final List<String> list = quickSearchProfile("for $x in collection('/db/DRIVER/CollectionDSResources') where $x//FATHER/@id = '" + profId
|
||||||
|
+ "' return $x//RESOURCE_IDENTIFIER/@value/string()");
|
||||||
|
|
||||||
|
if (!list.isEmpty()) {
|
||||||
|
final SAXReader reader = new SAXReader();
|
||||||
|
final Document doc = reader.read(new StringReader(profile));
|
||||||
|
final Element childrenNode = (Element) doc.selectSingleNode("//CHILDREN"); // NOPMD
|
||||||
|
for (final String idC : list) {
|
||||||
|
childrenNode.addElement("CHILD").addAttribute("id", idC);
|
||||||
|
}
|
||||||
|
profile = doc.asXML();
|
||||||
|
}
|
||||||
|
|
||||||
|
return profile;
|
||||||
|
} catch (final Exception e) {
|
||||||
|
throw new ISLookUpException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*
|
||||||
|
* @see eu.dnetlib.enabling.is.lookup.rmi.ISLookUpService#getCollection(java.lang.String, java.lang.String)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String getCollection(final String profId, final String format) throws ISLookUpException {
|
||||||
|
OpaqueResource prof;
|
||||||
|
try {
|
||||||
|
prof = new StringOpaqueResource(profId);
|
||||||
|
|
||||||
|
final StringBuilder query = new StringBuilder();
|
||||||
|
if (format != null && format.equals("ui")) {
|
||||||
|
query.append("doc('");
|
||||||
|
query.append(xqueryUtils.getCollectionAbsPath(prof));
|
||||||
|
query.append('/');
|
||||||
|
query.append(prof.getResourceId().split("_")[0]);
|
||||||
|
query.append("')");
|
||||||
|
} else {
|
||||||
|
query.append("let $x := doc('");
|
||||||
|
query.append(xqueryUtils.getCollectionAbsPath(prof));
|
||||||
|
query.append('/');
|
||||||
|
query.append(prof.getResourceId().split("_")[0]);
|
||||||
|
query.append("') return <COLLECTION name='{$x//NAME}' id='{$x//RESOURCE_IDENTIFIER/@value/string()}'>");
|
||||||
|
query.append("<STATUS private='{$x//PRIVATE}' visible='{$x//VISIBLE}' container='{$x//CONTAINER}'");
|
||||||
|
query.append("count_docs='{$x//COUNT_DOCS/@number/string()}' last_update='{$x//COUNT_DOCS/@last_update/string()}' />");
|
||||||
|
query.append("{$x//IMAGE_URL}{$x//DESCRIPTION}{$x//OWNER}{$x//FATHER}{$x//SUBJECT}{$x//CHILDREN}{$x//MEMBERSHIP_CONDITION}{$x//RETRIEVAL_CONDITION}</COLLECTION>");
|
||||||
|
}
|
||||||
|
|
||||||
|
return isStore.getXMLbyQuery(query.toString());
|
||||||
|
} catch (final ISStoreException e) {
|
||||||
|
throw new ISLookUpException(e);
|
||||||
|
} catch (final XPathExpressionException e) {
|
||||||
|
throw new ISLookUpException(COLLECTION_ERROR, e);
|
||||||
|
} catch (final SAXException e) {
|
||||||
|
throw new ISLookUpException(COLLECTION_ERROR, e);
|
||||||
|
} catch (final IOException e) {
|
||||||
|
throw new ISLookUpException(COLLECTION_ERROR, e);
|
||||||
|
} catch (final ParserConfigurationException e) {
|
||||||
|
throw new ISLookUpException(COLLECTION_ERROR, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*
|
||||||
|
* @see eu.dnetlib.enabling.is.lookup.rmi.ISLookUpService#getResourceProfile(java.lang.String)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String getResourceProfile(final String profId) throws ISLookUpException {
|
||||||
|
if (profId == null || profId.isEmpty()) { throw new ISLookUpException("Invalid null profile ID: " + profId); }
|
||||||
|
|
||||||
|
try {
|
||||||
|
final String res = isStore.getXML(getFileNameForId(profId),
|
||||||
|
xqueryUtils.getRootCollection() + getFileCollForId(profId));
|
||||||
|
if (res == null) { throw new ISLookUpDocumentNotFoundException("document " + profId + " not found"); }
|
||||||
|
return res;
|
||||||
|
} catch (final ISStoreException e) {
|
||||||
|
throw new ISLookUpException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* obtain the xmldb file name from the profile identifier.
|
||||||
|
*
|
||||||
|
* @param profId
|
||||||
|
* profile id
|
||||||
|
* @return xml db file name
|
||||||
|
*/
|
||||||
|
String getFileNameForId(final String profId) {
|
||||||
|
return resIdManager.getFileName(profId);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* obtain the xmldb collection name from the profile identifier.
|
||||||
|
*
|
||||||
|
* @param profId
|
||||||
|
* profile id
|
||||||
|
* @return plaintext xmldb collection name
|
||||||
|
*/
|
||||||
|
String getFileCollForId(final String profId) {
|
||||||
|
return resIdManager.getCollectionName(profId);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*
|
||||||
|
* @see eu.dnetlib.enabling.is.lookup.rmi.ISLookUpService#getResourceProfileByQuery(java.lang.String)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String getResourceProfileByQuery(final String xquery) throws ISLookUpException {
|
||||||
|
String resource;
|
||||||
|
//TODO remove following hack as soon as https://issue.openaire.research-infrastructures.eu/issues/2774 is closed.
|
||||||
|
if (StringUtils.isNotBlank(xquery) && xquery.trim().startsWith("//*[local-name() = 'complexType'")) {
|
||||||
|
final Pattern p = Pattern.compile(".*value = '([a-zA-z]+)']");
|
||||||
|
final Matcher m = p.matcher(xquery);
|
||||||
|
if (m.matches()) {
|
||||||
|
final String serviceName = m.group(1);
|
||||||
|
log.debug(String.format("found service '%s', hacking response for xquery: %s", serviceName, xquery));
|
||||||
|
return getResourceTypeSchema(serviceName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
resource = isStore.getXMLbyQuery(xquery);
|
||||||
|
if (resource == null || resource.isEmpty()) { throw new ISLookUpDocumentNotFoundException(PROFILE_NOT_FOUND); }
|
||||||
|
return resource;
|
||||||
|
} catch (final ISStoreException e) {
|
||||||
|
throw new ISLookUpException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*
|
||||||
|
* @see eu.dnetlib.enabling.is.lookup.rmi.ISLookUpService#getResourceQoSParams(java.lang.String)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String getResourceQoSParams(final String profId) throws ISLookUpException {
|
||||||
|
final String query = "for $x in collection('/db/DRIVER/ServiceResources') where $x//RESOURCE_IDENTIFIER/@value = '" + profId + "' return $x//QOS";
|
||||||
|
return getResourceProfileByQuery(query);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*
|
||||||
|
* @see eu.dnetlib.enabling.is.lookup.rmi.ISLookUpService#getResourceTypeSchema(java.lang.String)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String getResourceTypeSchema(final String resourceType) throws ISLookUpException, ISLookUpDocumentNotFoundException {
|
||||||
|
if (resourceType == null || resourceType.isEmpty()) { throw new ISLookUpException("Invalid resourceType"); }
|
||||||
|
|
||||||
|
try {
|
||||||
|
final String resource = isStore.getXML(resourceType, xqueryUtils.getRootCollection() + ResourceType.RESOURCE_TYPES);
|
||||||
|
if (resource == null || resource.isEmpty()) { throw new ISLookUpDocumentNotFoundException(PROFILE_NOT_FOUND); }
|
||||||
|
return resource;
|
||||||
|
} catch (final ISStoreException e) {
|
||||||
|
throw new ISLookUpException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*
|
||||||
|
* @see eu.dnetlib.enabling.is.lookup.rmi.ISLookUpService#listCollections(java.lang.String, java.lang.String, java.lang.String)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public List<String> listCollections(final String format, final String idfatherParam, final String owner) throws ISLookUpException {
|
||||||
|
String idfather = idfatherParam; // PMD
|
||||||
|
if (idfather == null || idfather.length() == 0) {
|
||||||
|
idfather = "InfoSpace";
|
||||||
|
}
|
||||||
|
final String fileColl = xqueryUtils.getRootCollection() + "CollectionDSResources/CollectionDSResourceType";
|
||||||
|
|
||||||
|
final StringBuilder query = new StringBuilder();
|
||||||
|
query.append("for $x in collection('" + fileColl + "') where $x//FATHER[@id='" + idfather + "'] "); // NOPMD
|
||||||
|
if (owner != null && owner.length() > 0) {
|
||||||
|
query.append("and $x//OWNER[@id='" + owner + "'] ");
|
||||||
|
}
|
||||||
|
if (format != null && format.equals("short")) {
|
||||||
|
query.append("return $x//RESOURCE_IDENTIFIER/@value/string()");
|
||||||
|
} else {
|
||||||
|
query.append("return $x");
|
||||||
|
}
|
||||||
|
|
||||||
|
return quickSearchProfile(query.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*
|
||||||
|
* @see eu.dnetlib.enabling.is.lookup.rmi.ISLookUpService#listDHNIDs()
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public List<String> listDHNIDs() throws ISLookUpException {
|
||||||
|
final String fileColl = DB_BASE_DIR + "/InfrastructureResources/DRIVERHostingNodeDSResourceType";
|
||||||
|
|
||||||
|
final ArrayList<String> ret = new ArrayList<String>();
|
||||||
|
try {
|
||||||
|
for (final String i : isStore.getFileNames(fileColl)) {
|
||||||
|
ret.add(i + ":" + fileColl);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
} catch (final ISStoreException e) {
|
||||||
|
throw new ISLookUpException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*
|
||||||
|
* @see eu.dnetlib.enabling.is.lookup.rmi.ISLookUpService#listResourceTypes()
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public List<String> listResourceTypes() throws ISLookUpException {
|
||||||
|
try {
|
||||||
|
return isStore.getFileNames(DB_BASE_DIR + "/" + ResourceType.RESOURCE_TYPES);
|
||||||
|
} catch (final ISStoreException e) {
|
||||||
|
throw new ISLookUpException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*
|
||||||
|
* @see eu.dnetlib.enabling.is.lookup.rmi.ISLookUpService#listServiceIDs(java.lang.String)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public List<String> listServiceIDs(final String serviceType) throws ISLookUpException {
|
||||||
|
final String fileColl = "ServiceResources/" + serviceType;
|
||||||
|
final String encodedColl = "_" + new String(Base64.encode(fileColl.getBytes())); // NOPMD
|
||||||
|
|
||||||
|
final List<String> ret = new ArrayList<String>();
|
||||||
|
try {
|
||||||
|
for (final String i : isStore.getFileNames(DB_BASE_DIR + "/" + fileColl)) {
|
||||||
|
ret.add(i + encodedColl);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
} catch (final ISStoreException e) {
|
||||||
|
throw new ISLookUpException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*
|
||||||
|
* @see eu.dnetlib.enabling.is.lookup.rmi.ISLookUpService#listServiceTypes()
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public List<String> listServiceTypes() throws ISLookUpException {
|
||||||
|
final List<String> ret = new ArrayList<String>();
|
||||||
|
try {
|
||||||
|
for (final String i : isStore.getFileColls()) {
|
||||||
|
if (i.startsWith("ServiceResources/")) {
|
||||||
|
ret.add(i.substring("ServiceResources/".length()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
} catch (final ISStoreException e) {
|
||||||
|
throw new ISLookUpException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*
|
||||||
|
* @see eu.dnetlib.enabling.is.lookup.rmi.ISLookUpService#quickSearchProfile(java.lang.String)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public List<String> quickSearchProfile(final String xquery) throws ISLookUpException {
|
||||||
|
try {
|
||||||
|
return isStore.quickSearchXML(xquery);
|
||||||
|
} catch (final ISStoreException e) {
|
||||||
|
throw new ISLookUpException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public ResourceIdentifierResolver getResIdManager() {
|
||||||
|
return resIdManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setResIdManager(final ResourceIdentifierResolver resIdManager) {
|
||||||
|
this.resIdManager = resIdManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Required
|
||||||
|
public void setXqueryUtils(final XQueryUtils xqueryUtils) {
|
||||||
|
this.xqueryUtils = xqueryUtils;
|
||||||
|
}
|
||||||
|
|
||||||
|
public XQueryUtils getXqueryUtils() {
|
||||||
|
return xqueryUtils;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ISStoreService getIsStore() {
|
||||||
|
return isStore;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Required
|
||||||
|
public void setIsStore(final ISStoreService isStore) {
|
||||||
|
this.isStore = isStore;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,77 @@
|
||||||
|
package eu.dnetlib.enabling.is.registry;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import javax.xml.parsers.DocumentBuilderFactory;
|
||||||
|
import javax.xml.parsers.ParserConfigurationException;
|
||||||
|
import javax.xml.xpath.XPath;
|
||||||
|
import javax.xml.xpath.XPathExpressionException;
|
||||||
|
import javax.xml.xpath.XPathFactory;
|
||||||
|
|
||||||
|
import org.w3c.dom.Document;
|
||||||
|
import org.xml.sax.SAXException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resolves resource kinds (pending and normal from the application profile xml file).
|
||||||
|
*
|
||||||
|
* @author marko
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class ApplicationProfileResourceKindResolver implements ResourceKindResolver {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* information space application profile. Contains, among others, mappings for the.. TODO: move to a DAO.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
private Document appProfile;
|
||||||
|
|
||||||
|
public ApplicationProfileResourceKindResolver() {
|
||||||
|
try {
|
||||||
|
appProfile = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(
|
||||||
|
getClass().getResourceAsStream("DRIVERInformationSpaceApplicationProfile.xml"));
|
||||||
|
} catch (SAXException e) {
|
||||||
|
throw new IllegalStateException("cannot parse information space application profile", e);
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new IllegalStateException("cannot parse information space application profile", e);
|
||||||
|
} catch (ParserConfigurationException e) {
|
||||||
|
throw new IllegalStateException("cannot parse information space application profile", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get the default resource kind associated with a given resource type.
|
||||||
|
*
|
||||||
|
* @param resourceType
|
||||||
|
* resource type
|
||||||
|
* @return resourceType
|
||||||
|
* @throws XPathExpressionException
|
||||||
|
* happens?
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String getNormalKindForType(final String resourceType) throws XPathExpressionException {
|
||||||
|
final XPath xpath = XPathFactory.newInstance().newXPath();
|
||||||
|
final String res = xpath.evaluate("//RESOURCE_TYPE[text() = '" + resourceType + "']/../../RESOURCE_KIND", appProfile);
|
||||||
|
if (res.isEmpty())
|
||||||
|
return null;
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* find the associated pending typology for a given resource type.
|
||||||
|
*
|
||||||
|
* @param resourceType
|
||||||
|
* resource type
|
||||||
|
* @return pending resource kind
|
||||||
|
* @throws XPathExpressionException
|
||||||
|
* shouldn't happen
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String getPendingKindForType(final String resourceType) throws XPathExpressionException {
|
||||||
|
final XPath xpath = XPathFactory.newInstance().newXPath();
|
||||||
|
final String res = xpath.evaluate("//RESOURCE_TYPE[text() = '" + resourceType + "']/../../PENDING_TYPOLOGY", appProfile);
|
||||||
|
if (res.isEmpty())
|
||||||
|
throw new NoSuchPendingCategoryException("no pending category for " + resourceType);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,141 @@
|
||||||
|
package eu.dnetlib.enabling.is.registry;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import javax.xml.xpath.XPathExpressionException;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Required;
|
||||||
|
|
||||||
|
import eu.dnetlib.enabling.is.registry.rmi.ISRegistryException;
|
||||||
|
import eu.dnetlib.enabling.is.registry.rmi.ISRegistryService;
|
||||||
|
import eu.dnetlib.enabling.is.registry.schema.ValidationException;
|
||||||
|
import eu.dnetlib.enabling.is.registry.validation.ProfileValidationStrategy;
|
||||||
|
import eu.dnetlib.enabling.is.registry.validation.RegistrationPhase;
|
||||||
|
import eu.dnetlib.enabling.tools.OpaqueResource;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* implement the compatibility pending profile policy.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* pending profiles receive their own special resource kind and are 'moved' to a different collection
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author marko
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class CompatPendingResourceManagerImpl implements PendingResourceManager, ResourceKindResolver {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* IS Registry
|
||||||
|
*/
|
||||||
|
private ISRegistryService isRegistry;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This bean resolver
|
||||||
|
*/
|
||||||
|
private ResourceKindResolver resourceKindResolver;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* used to validate resources w.r.t. a set of defined properties.
|
||||||
|
*/
|
||||||
|
@Resource
|
||||||
|
private ProfileValidationStrategy profileValidationStrategy;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*
|
||||||
|
* @see eu.dnetlib.enabling.is.registry.PendingResourceManager#setPending(eu.dnetlib.enabling.tools.OpaqueResource)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void setPending(final OpaqueResource resource, final boolean local) {
|
||||||
|
try {
|
||||||
|
resource.setResourceKind(getPendingKindForType(resource.getResourceType()));
|
||||||
|
|
||||||
|
if (!local) {
|
||||||
|
isRegistry.deleteProfile(resource.getResourceId());
|
||||||
|
final String newId = isRegistry.registerProfile(resource.asString());
|
||||||
|
resource.setResourceId(newId);
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (XPathExpressionException e) {
|
||||||
|
throw new IllegalStateException(e);
|
||||||
|
} catch (ISRegistryException e) {
|
||||||
|
throw new IllegalStateException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*
|
||||||
|
* @see eu.dnetlib.enabling.is.registry.PendingResourceManager#setPending(eu.dnetlib.enabling.tools.OpaqueResource)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void setPending(final OpaqueResource resource) {
|
||||||
|
setPending(resource, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*
|
||||||
|
* @see eu.dnetlib.enabling.is.registry.PendingResourceManager#setValid(eu.dnetlib.enabling.tools.OpaqueResource)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void setValid(final OpaqueResource resource) {
|
||||||
|
try {
|
||||||
|
if (resource.getResourceKind() != null && resource.getResourceKind().equals(getNormalKindForType(resource.getResourceType()))) { throw new IllegalArgumentException(
|
||||||
|
"trying to validate an already valid resource"); }
|
||||||
|
|
||||||
|
profileValidationStrategy.accept(resource, RegistrationPhase.Validate);
|
||||||
|
|
||||||
|
resource.setResourceKind(getNormalKindForType(resource.getResourceType()));
|
||||||
|
|
||||||
|
isRegistry.deleteProfile(resource.getResourceId());
|
||||||
|
|
||||||
|
final String newId = isRegistry.registerProfile(resource.asString());
|
||||||
|
resource.setResourceId(newId);
|
||||||
|
|
||||||
|
} catch (XPathExpressionException e) {
|
||||||
|
throw new IllegalStateException(e);
|
||||||
|
} catch (ISRegistryException e) {
|
||||||
|
throw new IllegalStateException(e);
|
||||||
|
} catch (ValidationException e) {
|
||||||
|
throw new IllegalStateException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getNormalKindForType(final String resourceType) throws XPathExpressionException {
|
||||||
|
return resourceKindResolver.getNormalKindForType(resourceType);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getPendingKindForType(final String resourceType) throws XPathExpressionException {
|
||||||
|
return resourceKindResolver.getPendingKindForType(resourceType);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ResourceKindResolver getResourceKindResolver() {
|
||||||
|
return resourceKindResolver;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Required
|
||||||
|
public void setResourceKindResolver(final ResourceKindResolver resourceKindResolver) {
|
||||||
|
this.resourceKindResolver = resourceKindResolver;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ProfileValidationStrategy getProfileValidationStrategy() {
|
||||||
|
return profileValidationStrategy;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setProfileValidationStrategy(final ProfileValidationStrategy profileValidationStrategy) {
|
||||||
|
this.profileValidationStrategy = profileValidationStrategy;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ISRegistryService getIsRegistry() {
|
||||||
|
return isRegistry;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Required
|
||||||
|
public void setIsRegistry(final ISRegistryService isRegistry) {
|
||||||
|
this.isRegistry = isRegistry;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,595 @@
|
||||||
|
package eu.dnetlib.enabling.is.registry; // NOPMD
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import javax.jws.WebService;
|
||||||
|
import javax.xml.parsers.ParserConfigurationException;
|
||||||
|
import javax.xml.xpath.XPath;
|
||||||
|
import javax.xml.xpath.XPathConstants;
|
||||||
|
import javax.xml.xpath.XPathExpressionException;
|
||||||
|
import javax.xml.xpath.XPathFactory;
|
||||||
|
|
||||||
|
import org.apache.commons.logging.Log;
|
||||||
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
import org.springframework.beans.factory.annotation.Required;
|
||||||
|
import org.w3c.dom.Element;
|
||||||
|
import org.xml.sax.SAXException;
|
||||||
|
|
||||||
|
import com.sun.xml.messaging.saaj.util.Base64;
|
||||||
|
|
||||||
|
import eu.dnetlib.common.rmi.APIDeprecatedException;
|
||||||
|
import eu.dnetlib.common.rmi.UnimplementedException;
|
||||||
|
import eu.dnetlib.enabling.is.lookup.rmi.ISLookUpDocumentNotFoundException;
|
||||||
|
import eu.dnetlib.enabling.is.lookup.rmi.ISLookUpException;
|
||||||
|
import eu.dnetlib.enabling.is.lookup.rmi.ISLookUpService;
|
||||||
|
import eu.dnetlib.enabling.is.registry.rmi.ISRegistryException;
|
||||||
|
import eu.dnetlib.enabling.is.registry.rmi.ISRegistryService;
|
||||||
|
import eu.dnetlib.enabling.is.registry.schema.OpaqueResourceValidator;
|
||||||
|
import eu.dnetlib.enabling.is.registry.schema.ValidationException;
|
||||||
|
import eu.dnetlib.enabling.is.registry.validation.ProfileValidationStrategy;
|
||||||
|
import eu.dnetlib.enabling.is.registry.validation.RegistrationPhase;
|
||||||
|
import eu.dnetlib.enabling.is.store.rmi.ISStoreException;
|
||||||
|
import eu.dnetlib.enabling.is.store.rmi.ISStoreService;
|
||||||
|
import eu.dnetlib.enabling.tools.AbstractBaseService;
|
||||||
|
import eu.dnetlib.enabling.tools.CompatResourceIdentifierResolverImpl;
|
||||||
|
import eu.dnetlib.enabling.tools.OpaqueResource;
|
||||||
|
import eu.dnetlib.enabling.tools.ResourceIdentifierResolver;
|
||||||
|
import eu.dnetlib.enabling.tools.ResourceType;
|
||||||
|
import eu.dnetlib.enabling.tools.StringOpaqueResource;
|
||||||
|
import eu.dnetlib.enabling.tools.UniqueIdentifierGenerator;
|
||||||
|
import eu.dnetlib.enabling.tools.UniqueIdentifierGeneratorImpl;
|
||||||
|
import eu.dnetlib.enabling.tools.XQueryUtils;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registry service implementation.
|
||||||
|
*
|
||||||
|
* @author marko
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@WebService(targetNamespace = "http://services.dnetlib.eu/")
|
||||||
|
public class ISRegistryServiceImpl extends AbstractBaseService implements ISRegistryService { // NOPMD by marko on
|
||||||
|
|
||||||
|
/**
|
||||||
|
* logger.
|
||||||
|
*/
|
||||||
|
private static final Log log = LogFactory.getLog(ISRegistryServiceImpl.class); // NOPMD by marko on 11/24/08 5:02 PM
|
||||||
|
|
||||||
|
/**
|
||||||
|
* error message: secure profile registration.
|
||||||
|
*/
|
||||||
|
private static final String ERROR_SEC_PROFILE = "cannot register secure profile";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* error message: trying to retrieve the current stored version of the resource profile.
|
||||||
|
*/
|
||||||
|
private static final String CANT_FETCH = "cannot fetch original profile";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* error message: cannot create a resource.
|
||||||
|
*/
|
||||||
|
private static final String CANT_CREATE = "cannot create resource";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* IS Store
|
||||||
|
*/
|
||||||
|
private ISStoreService isStore;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* IS Lookup
|
||||||
|
*/
|
||||||
|
private ISLookUpService isLookup;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* uuid generator.
|
||||||
|
*/
|
||||||
|
@Resource
|
||||||
|
private UniqueIdentifierGenerator uuidGenerator = new UniqueIdentifierGeneratorImpl();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* manages the pending state of resource. Different implementations can be plugged in.
|
||||||
|
*/
|
||||||
|
private PendingResourceManager pendingManager = new CompatPendingResourceManagerImpl();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* manages resource identifier mappings with the abstract xmldb namespace (files/collections).
|
||||||
|
*/
|
||||||
|
@Resource
|
||||||
|
private ResourceIdentifierResolver resIdResolver = new CompatResourceIdentifierResolverImpl();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* used to validate resources.
|
||||||
|
*/
|
||||||
|
private OpaqueResourceValidator resourceValidator;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* used to validate resources w.r.t. a set of defined properties.
|
||||||
|
*/
|
||||||
|
@Resource
|
||||||
|
private ProfileValidationStrategy profileValidationStrategy;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* query utils. Used to obtain xmldb collection names and other things useful for interacting with the IS_Store.
|
||||||
|
*/
|
||||||
|
private XQueryUtils xqueryUtils;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* the blackboard management stuff is factored out here.
|
||||||
|
*/
|
||||||
|
@Resource
|
||||||
|
private RegistryBlackboardManager blackboardManager;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void start() {
|
||||||
|
super.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*
|
||||||
|
* @see eu.dnetlib.enabling.is.registry.rmi.ISRegistryService#addBlackBoardMessage(java.lang.String, java.lang.String, java.lang.String)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void addBlackBoardMessage(final String profId, final String messageId, final String message) throws ISRegistryException {
|
||||||
|
blackboardManager.addMessage(profId, messageId, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*
|
||||||
|
* @see eu.dnetlib.enabling.is.registry.rmi.ISRegistryService#addOrUpdateResourceType(java.lang.String, java.lang.String)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean addOrUpdateResourceType(final String resourceType, final String resourceSchema) throws ISRegistryException {
|
||||||
|
return addResourceType(resourceType, resourceSchema);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*
|
||||||
|
* @see eu.dnetlib.enabling.is.registry.rmi.ISRegistryService#addProfileNode(java.lang.String, java.lang.String, java.lang.String)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean addProfileNode(final String profId, final String xpath, final String node) throws ISRegistryException {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
throw new UnimplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*
|
||||||
|
* @see eu.dnetlib.enabling.is.registry.rmi.ISRegistryService#addResourceType(java.lang.String, java.lang.String)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean addResourceType(final String resourceType, final String resourceSchema) throws ISRegistryException {
|
||||||
|
try {
|
||||||
|
return isStore.insertXML(resourceType, xqueryUtils.getRootCollection() + ResourceType.RESOURCE_TYPES,
|
||||||
|
resourceSchema);
|
||||||
|
} catch (ISStoreException e) {
|
||||||
|
throw new ISRegistryException("cannot add resource type", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*
|
||||||
|
* @see eu.dnetlib.enabling.is.registry.rmi.ISRegistryService#deleteBlackBoardMessage(java.lang.String, java.lang.String)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void deleteBlackBoardMessage(final String profId, final String messageId) throws ISRegistryException {
|
||||||
|
blackboardManager.deleteMessage(profId, messageId);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*
|
||||||
|
* @see eu.dnetlib.enabling.is.registry.rmi.ISRegistryService#deleteProfile(java.lang.String)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean deleteProfile(final String resId) throws ISRegistryException {
|
||||||
|
try {
|
||||||
|
final boolean res = isStore.deleteXML(resIdResolver.getFileName(resId),
|
||||||
|
"/db/DRIVER/" + resIdResolver.getCollectionName(resId));
|
||||||
|
if (!res) { throw new ISRegistryDocumentNotFoundException("document " + resId + " not found"); }
|
||||||
|
|
||||||
|
return true;
|
||||||
|
} catch (ISStoreException e) {
|
||||||
|
throw new ISRegistryException("cannot delete profile " + resId, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*
|
||||||
|
* @see eu.dnetlib.enabling.is.registry.rmi.ISRegistryService#deleteProfiles(java.util.List)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean deleteProfiles(final List<String> arrayprofId) throws ISRegistryException {
|
||||||
|
throw new APIDeprecatedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*
|
||||||
|
* @see eu.dnetlib.enabling.is.registry.rmi.ISRegistryService#deleteResourceType(java.lang.String, java.lang.Boolean)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean deleteResourceType(final String resourceType, final Boolean hierarchical) throws ISRegistryException {
|
||||||
|
try {
|
||||||
|
return isStore.deleteXML(resourceType, xqueryUtils.getRootCollection() + ResourceType.RESOURCE_TYPES);
|
||||||
|
} catch (ISStoreException e) {
|
||||||
|
throw new ISRegistryException("error deleting resource type " + resourceType, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*
|
||||||
|
* @see eu.dnetlib.enabling.is.registry.rmi.ISRegistryService#executeXUpdate(java.lang.String)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean executeXUpdate(final String xquery) throws ISRegistryException {
|
||||||
|
try {
|
||||||
|
return isStore.executeXUpdate(xquery);
|
||||||
|
} catch (ISStoreException e) {
|
||||||
|
throw new ISRegistryException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*
|
||||||
|
* @see eu.dnetlib.enabling.is.registry.rmi.ISRegistryService#insertProfileForValidation(java.lang.String, java.lang.String)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String insertProfileForValidation(final String resourceType, final String resourceProfile) throws ISRegistryException {
|
||||||
|
try {
|
||||||
|
final OpaqueResource resource = new StringOpaqueResource(resourceProfile);
|
||||||
|
if (!resourceType.equals(resource.getResourceType())) { throw new ISRegistryException("expected resource type doesn't match to resource"); }
|
||||||
|
|
||||||
|
pendingManager.setPending(resource, true);
|
||||||
|
|
||||||
|
return registerProfile(resource.asString());
|
||||||
|
} catch (XPathExpressionException e) {
|
||||||
|
throw new ISRegistryException(e);
|
||||||
|
} catch (SAXException e) {
|
||||||
|
throw new ISRegistryException(e);
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new ISRegistryException(e);
|
||||||
|
} catch (ParserConfigurationException e) {
|
||||||
|
throw new ISRegistryException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*
|
||||||
|
* @see eu.dnetlib.enabling.is.registry.rmi.ISRegistryService#refreshProfile(java.lang.String, java.lang.String)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean refreshProfile(final String profId, final String resourceType) throws ISRegistryException {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
throw new UnimplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*
|
||||||
|
* @see eu.dnetlib.enabling.is.registry.rmi.ISRegistryService#registerProfile(java.lang.String)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String registerProfile(final String resourceProfile) throws ISRegistryException {
|
||||||
|
log.debug("registering profile");
|
||||||
|
|
||||||
|
try {
|
||||||
|
final OpaqueResource resource = new StringOpaqueResource(resourceProfile);
|
||||||
|
|
||||||
|
// TODO: factor this out (possibly not within the OpaqueResource class)
|
||||||
|
final String coll = xqueryUtils.getCollectionPath(resource);
|
||||||
|
final String fileName = uuidGenerator.generateIdentifier();
|
||||||
|
final String newId = fileName + "_" + new String(Base64.encode(coll.getBytes()));
|
||||||
|
resource.setResourceId(newId);
|
||||||
|
|
||||||
|
resource.setModificationDate(new Date());
|
||||||
|
|
||||||
|
// log.info("validating to xml schema: " + resource.asString());
|
||||||
|
resourceValidator.validate(resource);
|
||||||
|
|
||||||
|
profileValidationStrategy.accept(resource, RegistrationPhase.Register);
|
||||||
|
|
||||||
|
// TODO: factor out ResourceType class
|
||||||
|
isStore.insertXML(fileName, xqueryUtils.getRootCollection() + coll, resource.asString());
|
||||||
|
|
||||||
|
return resource.getResourceId();
|
||||||
|
} catch (XPathExpressionException e) {
|
||||||
|
throw new ISRegistryException(e);
|
||||||
|
} catch (SAXException e) {
|
||||||
|
throw new ISRegistryException(e);
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new ISRegistryException(e);
|
||||||
|
} catch (ParserConfigurationException e) {
|
||||||
|
throw new ISRegistryException(e);
|
||||||
|
} catch (ISStoreException e) {
|
||||||
|
throw new ISRegistryException(e);
|
||||||
|
} catch (ValidationException e) {
|
||||||
|
throw new ISRegistryException("profile is not conforming to the schema: " + e.getMessage(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*
|
||||||
|
* @see eu.dnetlib.enabling.is.registry.rmi.ISRegistryService#registerSecureProfile(java.lang.String, java.lang.String)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String registerSecureProfile(final String resourceProfId, final String secureProfId) throws ISRegistryException {
|
||||||
|
try {
|
||||||
|
synchronized (this) {
|
||||||
|
final String secureProfSrc;
|
||||||
|
try {
|
||||||
|
secureProfSrc = isLookup.getResourceProfile(secureProfId); // NOPMD
|
||||||
|
} catch (ISLookUpDocumentNotFoundException e) {
|
||||||
|
throw new ISRegistryException("cannot register secure profile, the given secure profile doesn't exist", e);
|
||||||
|
}
|
||||||
|
final OpaqueResource secureProf = new StringOpaqueResource(secureProfSrc);
|
||||||
|
|
||||||
|
final String profId = validateProfile(resourceProfId);
|
||||||
|
|
||||||
|
final XPath xpath = XPathFactory.newInstance().newXPath();
|
||||||
|
final Element idEl = (Element) xpath.evaluate("/RESOURCE_PROFILE/BODY/CONFIGURATION/resourceId", secureProf.asDom(), XPathConstants.NODE);
|
||||||
|
idEl.setTextContent(profId);
|
||||||
|
|
||||||
|
if (!updateProfile(secureProfId, secureProf.asString(), secureProf.getResourceType())) { throw new ISRegistryException(
|
||||||
|
"cannot update security profile (updateProfile returned false)"); }
|
||||||
|
|
||||||
|
return profId;
|
||||||
|
}
|
||||||
|
} catch (XPathExpressionException e) {
|
||||||
|
throw new ISRegistryException(ERROR_SEC_PROFILE, e);
|
||||||
|
} catch (SAXException e) {
|
||||||
|
throw new ISRegistryException(ERROR_SEC_PROFILE, e);
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new ISRegistryException(ERROR_SEC_PROFILE, e);
|
||||||
|
} catch (ParserConfigurationException e) {
|
||||||
|
throw new ISRegistryException(ERROR_SEC_PROFILE, e);
|
||||||
|
} catch (ISLookUpException e) {
|
||||||
|
throw new ISRegistryException("cannot register secure profile, problem fetching the given secure profile", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*
|
||||||
|
* @see eu.dnetlib.enabling.is.registry.rmi.ISRegistryService#removeProfileNode(java.lang.String, java.lang.String)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean removeProfileNode(final String profId, final String nodeId) throws ISRegistryException {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
throw new UnimplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*
|
||||||
|
* @see eu.dnetlib.enabling.is.registry.rmi.ISRegistryService#replyBlackBoardMessage(java.lang.String, java.lang.String)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void replyBlackBoardMessage(final String profId, final String message) throws ISRegistryException {
|
||||||
|
blackboardManager.replyMessage(profId, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*
|
||||||
|
* @see eu.dnetlib.enabling.is.registry.rmi.ISRegistryService#updateProfile(java.lang.String, java.lang.String, java.lang.String)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean updateProfile(final String resId, final String resourceProfile, final String resourceType) throws ISRegistryException {
|
||||||
|
try {
|
||||||
|
final String fileName = resIdResolver.getFileName(resId);
|
||||||
|
final String fileColl = "/db/DRIVER/" + resIdResolver.getCollectionName(resId);
|
||||||
|
|
||||||
|
final String oldProfileSrc = isStore.getXML(fileName, fileColl);
|
||||||
|
|
||||||
|
if (oldProfileSrc == null) { throw new ISRegistryException("cannot update a non existing profile " + resId); }
|
||||||
|
|
||||||
|
final OpaqueResource oldResource = new StringOpaqueResource(oldProfileSrc);
|
||||||
|
|
||||||
|
final StringOpaqueResource newResource = new StringOpaqueResource(resourceProfile);
|
||||||
|
newResource.setResourceId(oldResource.getResourceId());
|
||||||
|
newResource.setResourceKind(oldResource.getResourceKind());
|
||||||
|
newResource.setResourceType(oldResource.getResourceType());
|
||||||
|
newResource.setModificationDate(new Date());
|
||||||
|
|
||||||
|
getResourceValidator().validate(newResource);
|
||||||
|
|
||||||
|
return isStore.updateXML(fileName, fileColl, newResource.asString());
|
||||||
|
} catch (ISStoreException e) {
|
||||||
|
throw new ISRegistryException(e);
|
||||||
|
} catch (XPathExpressionException e) {
|
||||||
|
throw new ISRegistryException(e);
|
||||||
|
} catch (ValidationException e) {
|
||||||
|
throw new ISRegistryException("profile not conforming to xml schema", e);
|
||||||
|
} catch (SAXException e) {
|
||||||
|
throw new ISRegistryException(e);
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new ISRegistryException(e);
|
||||||
|
} catch (ParserConfigurationException e) {
|
||||||
|
throw new ISRegistryException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*
|
||||||
|
* @see eu.dnetlib.enabling.is.registry.rmi.ISRegistryService#updateProfileDHN(java.lang.String)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String updateProfileDHN(final String resourceProfile) throws ISRegistryException {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
throw new UnimplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*
|
||||||
|
* @see eu.dnetlib.enabling.is.registry.rmi.ISRegistryService#updateProfileNode(java.lang.String, java.lang.String, java.lang.String)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean updateProfileNode(final String profId, final String xpath, final String node) throws ISRegistryException {
|
||||||
|
return executeXUpdate("for $x in collection('/db/DRIVER')//RESOURCE_PROFILE[.//RESOURCE_IDENTIFIER/@value eq '" + profId + "']" + xpath
|
||||||
|
+ " return update replace $x with " + node);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*
|
||||||
|
* @see eu.dnetlib.enabling.is.registry.rmi.ISRegistryService#updateRegionDescription(java.lang.String, java.lang.String)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean updateRegionDescription(final String profId, final String resourceProfile) throws ISRegistryException {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
throw new UnimplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*
|
||||||
|
* @see eu.dnetlib.enabling.is.registry.rmi.ISRegistryService#validateProfile(java.lang.String)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String validateProfile(final String profId) throws ISRegistryException {
|
||||||
|
try {
|
||||||
|
final String resourceProfile = isLookup.getResourceProfile(profId);
|
||||||
|
final OpaqueResource resource = new StringOpaqueResource(resourceProfile);
|
||||||
|
pendingManager.setValid(resource);
|
||||||
|
|
||||||
|
return resource.getResourceId();
|
||||||
|
} catch (ISLookUpException e) {
|
||||||
|
throw new ISRegistryException(CANT_FETCH, e);
|
||||||
|
} catch (XPathExpressionException e) {
|
||||||
|
throw new ISRegistryException(CANT_CREATE, e);
|
||||||
|
} catch (SAXException e) {
|
||||||
|
throw new ISRegistryException(CANT_CREATE, e);
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new ISRegistryException(CANT_CREATE, e);
|
||||||
|
} catch (ParserConfigurationException e) {
|
||||||
|
throw new ISRegistryException(CANT_CREATE, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*
|
||||||
|
* @see eu.dnetlib.enabling.is.registry.rmi.ISRegistryService#invalidateProfile(java.lang.String)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String invalidateProfile(final String profId) throws ISRegistryException {
|
||||||
|
try {
|
||||||
|
final String resourceProfile = isLookup.getResourceProfile(profId);
|
||||||
|
final OpaqueResource resource = new StringOpaqueResource(resourceProfile);
|
||||||
|
pendingManager.setPending(resource);
|
||||||
|
|
||||||
|
return resource.getResourceId();
|
||||||
|
} catch (ISLookUpException e) {
|
||||||
|
throw new ISRegistryException(CANT_FETCH, e);
|
||||||
|
} catch (XPathExpressionException e) {
|
||||||
|
throw new ISRegistryException(CANT_CREATE, e);
|
||||||
|
} catch (SAXException e) {
|
||||||
|
throw new ISRegistryException(CANT_CREATE, e);
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new ISRegistryException(CANT_CREATE, e);
|
||||||
|
} catch (ParserConfigurationException e) {
|
||||||
|
throw new ISRegistryException(CANT_CREATE, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*
|
||||||
|
* @see eu.dnetlib.enabling.is.registry.rmi.ISRegistryService#validateProfiles(java.util.List)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public List<String> validateProfiles(final List<String> profIds) throws ISRegistryException {
|
||||||
|
throw new APIDeprecatedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public UniqueIdentifierGenerator getUuidGenerator() {
|
||||||
|
return uuidGenerator;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUuidGenerator(final UniqueIdentifierGenerator uuidGenerator) {
|
||||||
|
this.uuidGenerator = uuidGenerator;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PendingResourceManager getPendingManager() {
|
||||||
|
return pendingManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPendingManager(final PendingResourceManager pendingManager) {
|
||||||
|
this.pendingManager = pendingManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ResourceIdentifierResolver getResIdResolver() {
|
||||||
|
return resIdResolver;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setResIdResolver(final ResourceIdentifierResolver resIdResolver) {
|
||||||
|
this.resIdResolver = resIdResolver;
|
||||||
|
}
|
||||||
|
|
||||||
|
public OpaqueResourceValidator getResourceValidator() {
|
||||||
|
return resourceValidator;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Required
|
||||||
|
public void setResourceValidator(final OpaqueResourceValidator resourceValidator) {
|
||||||
|
this.resourceValidator = resourceValidator;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Required
|
||||||
|
public void setXqueryUtils(final XQueryUtils xqueryUtils) {
|
||||||
|
this.xqueryUtils = xqueryUtils;
|
||||||
|
}
|
||||||
|
|
||||||
|
public XQueryUtils getXqueryUtils() {
|
||||||
|
return xqueryUtils;
|
||||||
|
}
|
||||||
|
|
||||||
|
public RegistryBlackboardManager getBlackboardManager() {
|
||||||
|
return blackboardManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setBlackboardManager(final RegistryBlackboardManager blackboardManager) {
|
||||||
|
this.blackboardManager = blackboardManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ProfileValidationStrategy getProfileValidationStrategy() {
|
||||||
|
return profileValidationStrategy;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setProfileValidationStrategy(final ProfileValidationStrategy profileValidationStrategy) {
|
||||||
|
this.profileValidationStrategy = profileValidationStrategy;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ISStoreService getIsStore() {
|
||||||
|
return isStore;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Required
|
||||||
|
public void setIsStore(final ISStoreService isStore) {
|
||||||
|
this.isStore = isStore;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ISLookUpService getIsLookup() {
|
||||||
|
return isLookup;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Required
|
||||||
|
public void setIsLookup(final ISLookUpService isLookup) {
|
||||||
|
this.isLookup = isLookup;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,209 @@
|
||||||
|
package eu.dnetlib.enabling.is.registry;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import javax.xml.xpath.XPathExpressionException;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Required;
|
||||||
|
|
||||||
|
import eu.dnetlib.enabling.is.registry.rmi.ISRegistryException;
|
||||||
|
import eu.dnetlib.enabling.is.registry.rmi.ISRegistryService;
|
||||||
|
import eu.dnetlib.enabling.is.registry.schema.OpaqueResourceValidator;
|
||||||
|
import eu.dnetlib.enabling.is.registry.schema.ValidationException;
|
||||||
|
import eu.dnetlib.enabling.is.registry.validation.ProfileValidationStrategy;
|
||||||
|
import eu.dnetlib.enabling.is.registry.validation.RegistrationPhase;
|
||||||
|
import eu.dnetlib.enabling.is.store.rmi.ISStoreException;
|
||||||
|
import eu.dnetlib.enabling.is.store.rmi.ISStoreService;
|
||||||
|
import eu.dnetlib.enabling.tools.CompatResourceIdentifierResolverImpl;
|
||||||
|
import eu.dnetlib.enabling.tools.OpaqueResource;
|
||||||
|
import eu.dnetlib.enabling.tools.ResourceIdentifierComposer;
|
||||||
|
import eu.dnetlib.enabling.tools.ResourceIdentifierResolver;
|
||||||
|
import eu.dnetlib.enabling.tools.XQueryUtils;
|
||||||
|
|
||||||
|
public class IdPreservingPendingResourceManagerImpl implements PendingResourceManager, ResourceKindResolver {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* is registry
|
||||||
|
*/
|
||||||
|
private ISRegistryService isRegistry;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* is store
|
||||||
|
*/
|
||||||
|
private ISStoreService isStore;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This bean resolver
|
||||||
|
*/
|
||||||
|
private ResourceKindResolver resourceKindResolver;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* used to validate resources.
|
||||||
|
*/
|
||||||
|
private OpaqueResourceValidator resourceValidator;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* used to get the root collection.
|
||||||
|
*/
|
||||||
|
private XQueryUtils xqueryUtils;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* manages resource identifier mappings with the abstract xmldb namespace (files/collections).
|
||||||
|
*/
|
||||||
|
@Resource
|
||||||
|
private ResourceIdentifierResolver resIdResolver = new CompatResourceIdentifierResolverImpl();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* used to create a new resource id.
|
||||||
|
*/
|
||||||
|
@Resource
|
||||||
|
private ResourceIdentifierComposer resIdComposer = new CompatResourceIdentifierResolverImpl();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* used to validate resources w.r.t. a set of defined properties.
|
||||||
|
*/
|
||||||
|
@Resource
|
||||||
|
private ProfileValidationStrategy profileValidationStrategy;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*
|
||||||
|
* @see eu.dnetlib.enabling.is.registry.PendingResourceManager#setPending(eu.dnetlib.enabling.tools.OpaqueResource)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void setPending(final OpaqueResource resource, final boolean local) {
|
||||||
|
try {
|
||||||
|
resource.setResourceKind(getPendingKindForType(resource.getResourceType()));
|
||||||
|
|
||||||
|
if (!local) {
|
||||||
|
isRegistry.deleteProfile(resource.getResourceId());
|
||||||
|
|
||||||
|
registerProfile(resource);
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (XPathExpressionException e) {
|
||||||
|
throw new IllegalStateException(e);
|
||||||
|
} catch (ISRegistryException e) {
|
||||||
|
throw new IllegalStateException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*
|
||||||
|
* @see eu.dnetlib.enabling.is.registry.PendingResourceManager#setPending(eu.dnetlib.enabling.tools.OpaqueResource)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void setPending(final OpaqueResource resource) {
|
||||||
|
setPending(resource, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*
|
||||||
|
* @see eu.dnetlib.enabling.is.registry.PendingResourceManager#setValid(eu.dnetlib.enabling.tools.OpaqueResource)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void setValid(final OpaqueResource resource) {
|
||||||
|
try {
|
||||||
|
if (resource.getResourceKind() != null && resource.getResourceKind().equals(getNormalKindForType(resource.getResourceType()))) { throw new IllegalArgumentException(
|
||||||
|
"trying to validate an already valid resource"); }
|
||||||
|
|
||||||
|
profileValidationStrategy.accept(resource, RegistrationPhase.Validate);
|
||||||
|
|
||||||
|
resource.setResourceKind(getNormalKindForType(resource.getResourceType()));
|
||||||
|
|
||||||
|
isRegistry.deleteProfile(resource.getResourceId());
|
||||||
|
|
||||||
|
registerProfile(resource);
|
||||||
|
|
||||||
|
} catch (XPathExpressionException e) {
|
||||||
|
throw new IllegalStateException(e);
|
||||||
|
} catch (ISRegistryException e) {
|
||||||
|
throw new IllegalStateException(e);
|
||||||
|
} catch (ValidationException e) {
|
||||||
|
throw new IllegalStateException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public String registerProfile(final OpaqueResource resource) throws ISRegistryException {
|
||||||
|
try {
|
||||||
|
final String oldId = resource.getResourceId();
|
||||||
|
final String fileName = resIdResolver.getFileName(oldId);
|
||||||
|
final String newColl = xqueryUtils.getCollectionPath(resource);
|
||||||
|
|
||||||
|
final String newId = resIdComposer.createResourceId(fileName, newColl);
|
||||||
|
|
||||||
|
resource.setResourceId(newId);
|
||||||
|
|
||||||
|
resource.setModificationDate(new Date());
|
||||||
|
|
||||||
|
// log.info("validating to xml schema: " + resource.asString());
|
||||||
|
resourceValidator.validate(resource);
|
||||||
|
|
||||||
|
// TODO: factor out ResourceType class
|
||||||
|
isStore.insertXML(fileName, xqueryUtils.getRootCollection() + newColl, resource.asString());
|
||||||
|
|
||||||
|
return resource.getResourceId();
|
||||||
|
} catch (ISStoreException e) {
|
||||||
|
throw new ISRegistryException(e);
|
||||||
|
} catch (ValidationException e) {
|
||||||
|
throw new ISRegistryException("profile is not conforming to the schema: " + e.getMessage(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getNormalKindForType(final String resourceType) throws XPathExpressionException {
|
||||||
|
return resourceKindResolver.getNormalKindForType(resourceType);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getPendingKindForType(final String resourceType) throws XPathExpressionException {
|
||||||
|
return resourceKindResolver.getPendingKindForType(resourceType);
|
||||||
|
}
|
||||||
|
|
||||||
|
// /////////////////////////////
|
||||||
|
|
||||||
|
public ResourceKindResolver getResourceKindResolver() {
|
||||||
|
return resourceKindResolver;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Required
|
||||||
|
public void setResourceKindResolver(final ResourceKindResolver resourceKindResolver) {
|
||||||
|
this.resourceKindResolver = resourceKindResolver;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Required
|
||||||
|
public void setXqueryUtils(final XQueryUtils xqueryUtils) {
|
||||||
|
this.xqueryUtils = xqueryUtils;
|
||||||
|
}
|
||||||
|
|
||||||
|
public OpaqueResourceValidator getResourceValidator() {
|
||||||
|
return resourceValidator;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Required
|
||||||
|
public void setResourceValidator(final OpaqueResourceValidator resourceValidator) {
|
||||||
|
this.resourceValidator = resourceValidator;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ISRegistryService getIsRegistry() {
|
||||||
|
return isRegistry;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Required
|
||||||
|
public void setIsRegistry(final ISRegistryService isRegistry) {
|
||||||
|
this.isRegistry = isRegistry;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ISStoreService getIsStore() {
|
||||||
|
return isStore;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Required
|
||||||
|
public void setIsStore(final ISStoreService isStore) {
|
||||||
|
this.isStore = isStore;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,44 @@
|
||||||
|
package eu.dnetlib.enabling.is.registry;
|
||||||
|
|
||||||
|
import javax.xml.xpath.XPathExpressionException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Uses current driver convention and tries to guess the correct resource kinds (both normal and pending) depending on
|
||||||
|
* the resource type name.
|
||||||
|
*
|
||||||
|
* @author marko
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class NameBasedResourceKindResolver implements ResourceKindResolver {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
* @see eu.dnetlib.enabling.is.registry.ResourceKindResolver#getNormalKindForType(java.lang.String)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String getNormalKindForType(final String resourceType) throws XPathExpressionException {
|
||||||
|
if (isService(resourceType))
|
||||||
|
return "ServiceResources";
|
||||||
|
return generateKind(resourceType);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
* @see eu.dnetlib.enabling.is.registry.ResourceKindResolver#getPendingKindForType(java.lang.String)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String getPendingKindForType(final String resourceType) throws XPathExpressionException {
|
||||||
|
if (isService(resourceType))
|
||||||
|
return "PendingServiceResources";
|
||||||
|
return "PendingDSResources";
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isService(final String resourceType) {
|
||||||
|
return resourceType.matches(".*ServiceResourceType$");
|
||||||
|
}
|
||||||
|
|
||||||
|
private String generateKind(final String resourceType) {
|
||||||
|
return resourceType.replaceAll("ResourceType$", "Resources");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,14 @@
|
||||||
|
package eu.dnetlib.enabling.is.registry;
|
||||||
|
|
||||||
|
public class NoSuchPendingCategoryException extends IllegalStateException {
|
||||||
|
|
||||||
|
public NoSuchPendingCategoryException(String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
private static final long serialVersionUID = 6934748076388947172L;
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,41 @@
|
||||||
|
package eu.dnetlib.enabling.is.registry;
|
||||||
|
|
||||||
|
import eu.dnetlib.enabling.tools.OpaqueResource;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The IS registry has to handle the 'pending' state of the resources in several ways.
|
||||||
|
*
|
||||||
|
* <p>Implementors of this interface will change the profiles according to the pending profile management policy.</p>
|
||||||
|
*
|
||||||
|
* <p>See implementors.</p>
|
||||||
|
*
|
||||||
|
* @author marko
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public interface PendingResourceManager {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* change a profile to a pending state.
|
||||||
|
*
|
||||||
|
* @param resource opaque resource
|
||||||
|
*/
|
||||||
|
void setPending(OpaqueResource resource);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* change a profile to a valid state.
|
||||||
|
*
|
||||||
|
* same as setPending(resource, false);
|
||||||
|
*
|
||||||
|
* @param resource opaque resource
|
||||||
|
*/
|
||||||
|
void setValid(OpaqueResource resource);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* change a profile to a valid state.
|
||||||
|
*
|
||||||
|
* @param resource resource
|
||||||
|
* @param local true if the resource is not persistent
|
||||||
|
*/
|
||||||
|
void setPending(OpaqueResource resource, boolean local);
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,43 @@
|
||||||
|
package eu.dnetlib.enabling.is.registry;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internally used by the Registry Service to perform modifications on the service blackboard, a funcionality provided
|
||||||
|
* by the registry API.
|
||||||
|
*
|
||||||
|
* @author marko
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public interface RegistryBlackboardManager {
|
||||||
|
/**
|
||||||
|
* add a new blackboard message.
|
||||||
|
*
|
||||||
|
* @param profId
|
||||||
|
* service profile id
|
||||||
|
* @param messageId
|
||||||
|
* message identifier, chosen by the client
|
||||||
|
* @param message
|
||||||
|
* message body
|
||||||
|
*/
|
||||||
|
void addMessage(String profId, String messageId, String message);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reply to a given message replacing the current message with the parameter. The message ID is inferred from the
|
||||||
|
* new message body.
|
||||||
|
*
|
||||||
|
* @param profId
|
||||||
|
* service profile id
|
||||||
|
* @param message
|
||||||
|
* message body
|
||||||
|
*/
|
||||||
|
void replyMessage(String profId, String message);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* delete a message for a given message id.
|
||||||
|
*
|
||||||
|
* @param profId
|
||||||
|
* service profile id
|
||||||
|
* @param messageId
|
||||||
|
* message id
|
||||||
|
*/
|
||||||
|
void deleteMessage(String profId, String messageId);
|
||||||
|
}
|
|
@ -0,0 +1,257 @@
|
||||||
|
package eu.dnetlib.enabling.is.registry;
|
||||||
|
|
||||||
|
import javax.xml.transform.dom.DOMResult;
|
||||||
|
import javax.xml.xpath.XPathConstants;
|
||||||
|
import javax.xml.xpath.XPathExpressionException;
|
||||||
|
import javax.xml.xpath.XPathFactory;
|
||||||
|
|
||||||
|
import org.apache.commons.logging.Log;
|
||||||
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
import org.springframework.beans.factory.annotation.Required;
|
||||||
|
import org.w3c.dom.Document;
|
||||||
|
import org.w3c.dom.Element;
|
||||||
|
import org.w3c.dom.Node;
|
||||||
|
|
||||||
|
import eu.dnetlib.enabling.is.lookup.rmi.ISLookUpService;
|
||||||
|
import eu.dnetlib.enabling.is.registry.rmi.ISRegistryService;
|
||||||
|
import eu.dnetlib.enabling.tools.OpaqueResource;
|
||||||
|
import eu.dnetlib.enabling.tools.StringOpaqueResource;
|
||||||
|
import eu.dnetlib.enabling.tools.blackboard.BlackboardMessage;
|
||||||
|
import eu.dnetlib.miscutils.datetime.DateUtils;
|
||||||
|
import eu.dnetlib.miscutils.jaxb.JaxbFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Simple registry blackboard manager implementation.
|
||||||
|
*
|
||||||
|
* @author marko
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class RegistryBlackboardManagerImpl implements RegistryBlackboardManager { // NOPMD
|
||||||
|
|
||||||
|
/**
|
||||||
|
* logger.
|
||||||
|
*/
|
||||||
|
private static final Log log = LogFactory.getLog(RegistryBlackboardManagerImpl.class); // NOPMD by marko on 11/24/08 5:02 PM
|
||||||
|
|
||||||
|
/**
|
||||||
|
* timestamp padding.
|
||||||
|
*/
|
||||||
|
private static final String PADDING = "000";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* milliseconds in a second.
|
||||||
|
*/
|
||||||
|
private static final int MILLIS = 1000;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* IS Lookup
|
||||||
|
*/
|
||||||
|
private ISLookUpService isLookup;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* the registry which is bound with this registry blackboard manager implementation.
|
||||||
|
*/
|
||||||
|
private ISRegistryService registryService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* blackboard message factory.
|
||||||
|
*/
|
||||||
|
private JaxbFactory<BlackboardMessage> messageFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* provides the current date. Testers can override.
|
||||||
|
*/
|
||||||
|
private MessageDater messageDater = new MessageDater();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Testers can override.
|
||||||
|
*
|
||||||
|
* @author marko
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public static class MessageDater {
|
||||||
|
|
||||||
|
public String getCurrentDate() {
|
||||||
|
return DateUtils.now_ISO8601();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getNumericStamp() {
|
||||||
|
return Long.toString(System.currentTimeMillis() / MILLIS) + "." + System.currentTimeMillis() % MILLIS + PADDING;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* LAST_REQUEST or LAST_RESPONSE blackboard time stamp holders.
|
||||||
|
*
|
||||||
|
* @author marko
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public enum LastStamp {
|
||||||
|
/**
|
||||||
|
* LAST_REQUEST, used when the blackboard message flows from the client to the server.
|
||||||
|
*/
|
||||||
|
REQUEST,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* LAST_RESPONSE, used when the blackboard message flows from the server to the client, signaling the completion/progress of the
|
||||||
|
* action..
|
||||||
|
*/
|
||||||
|
RESPONSE
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*
|
||||||
|
* @see eu.dnetlib.enabling.is.registry.RegistryBlackboardManager#addMessage(java.lang.String, java.lang.String, java.lang.String)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void addMessage(final String profId, final String messageId, final String message) { // NOPMD
|
||||||
|
try {
|
||||||
|
final BlackboardMessage bbm = messageFactory.parse(message);
|
||||||
|
bbm.setDate(messageDater.getCurrentDate()); // preserve compatibility.
|
||||||
|
|
||||||
|
if (bbm.getId() == null || !bbm.getId().equals(messageId)) { throw new IllegalArgumentException("invalid blackboard message id"); }
|
||||||
|
|
||||||
|
synchronized (this) {
|
||||||
|
final OpaqueResource serviceProfile = new StringOpaqueResource(isLookup.getResourceProfile(profId));
|
||||||
|
|
||||||
|
final Document doc = serviceProfile.asDom();
|
||||||
|
final Node bboard = (Node) XPathFactory.newInstance().newXPath().evaluate("//BLACKBOARD", doc, XPathConstants.NODE);
|
||||||
|
|
||||||
|
// delete current element if exists
|
||||||
|
final Node messageElement = (Node) XPathFactory.newInstance().newXPath().evaluate("//BLACKBOARD/MESSAGE[@id='" + messageId + "']", doc,
|
||||||
|
XPathConstants.NODE);
|
||||||
|
|
||||||
|
if (messageElement != null) {
|
||||||
|
bboard.removeChild(messageElement);
|
||||||
|
}
|
||||||
|
|
||||||
|
// append the serialized node to the blackboard node
|
||||||
|
messageFactory.serialize(bbm, new DOMResult(bboard));
|
||||||
|
|
||||||
|
updateLastStamps(doc, LastStamp.REQUEST, messageId);
|
||||||
|
|
||||||
|
registryService.updateProfile(profId, serviceProfile.asString(), serviceProfile.getResourceType());
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new IllegalStateException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper method which updates the LAST_* stamps in the blackboard header.
|
||||||
|
*
|
||||||
|
* @param doc
|
||||||
|
* profile DOM document
|
||||||
|
* @param stamp
|
||||||
|
* which stamp to modify
|
||||||
|
* @param messageId
|
||||||
|
* message id to point the stamp to
|
||||||
|
* @throws XPathExpressionException
|
||||||
|
* could happen
|
||||||
|
*/
|
||||||
|
protected void updateLastStamps(final Document doc, final LastStamp stamp, final String messageId) throws XPathExpressionException {
|
||||||
|
final Element lastRequest = (Element) XPathFactory.newInstance().newXPath().evaluate("//BLACKBOARD/LAST_" + stamp, doc, XPathConstants.NODE);
|
||||||
|
lastRequest.setTextContent(messageId);
|
||||||
|
lastRequest.setAttribute("date", messageDater.getNumericStamp());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*
|
||||||
|
* @see eu.dnetlib.enabling.is.registry.RegistryBlackboardManager#deleteMessage(java.lang.String, java.lang.String)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void deleteMessage(final String profId, final String messageId) {
|
||||||
|
try {
|
||||||
|
synchronized (this) {
|
||||||
|
final OpaqueResource serviceProfile = new StringOpaqueResource(isLookup.getResourceProfile(profId));
|
||||||
|
final Document doc = serviceProfile.asDom();
|
||||||
|
|
||||||
|
final Node message = (Node) XPathFactory.newInstance().newXPath().evaluate("//BLACKBOARD/MESSAGE[@id='" + messageId + "']", doc,
|
||||||
|
XPathConstants.NODE);
|
||||||
|
|
||||||
|
message.getParentNode().removeChild(message);
|
||||||
|
|
||||||
|
registryService.updateProfile(profId, serviceProfile.asString(), serviceProfile.getResourceType());
|
||||||
|
}
|
||||||
|
log.debug("Deleted bb message " + messageId + " from profile " + profId);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("Error deleting bb message " + messageId + " from profile " + profId, e);
|
||||||
|
throw new IllegalStateException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*
|
||||||
|
* @see eu.dnetlib.enabling.is.registry.RegistryBlackboardManager#replyMessage(java.lang.String, java.lang.String)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void replyMessage(final String profId, final String message) {
|
||||||
|
try {
|
||||||
|
final BlackboardMessage bbm = messageFactory.parse(message);
|
||||||
|
bbm.setDate(messageDater.getCurrentDate()); // preserve compatibility.
|
||||||
|
|
||||||
|
final String messageId = bbm.getId();
|
||||||
|
|
||||||
|
synchronized (this) {
|
||||||
|
final OpaqueResource serviceProfile = new StringOpaqueResource(isLookup.getResourceProfile(profId));
|
||||||
|
final Document doc = serviceProfile.asDom();
|
||||||
|
|
||||||
|
final Node messageElement = (Node) XPathFactory.newInstance().newXPath().evaluate("//BLACKBOARD/MESSAGE[@id='" + messageId + "']", doc,
|
||||||
|
XPathConstants.NODE);
|
||||||
|
|
||||||
|
if (messageElement == null) { throw new IllegalArgumentException("no such blackboard message " + messageId + ". Unably to reply"); }
|
||||||
|
|
||||||
|
final Node bboard = messageElement.getParentNode();
|
||||||
|
bboard.removeChild(messageElement);
|
||||||
|
|
||||||
|
// append the serialized node to the blackboard node
|
||||||
|
messageFactory.serialize(bbm, new DOMResult(bboard));
|
||||||
|
|
||||||
|
updateLastStamps(doc, LastStamp.RESPONSE, messageId);
|
||||||
|
|
||||||
|
registryService.updateProfile(profId, serviceProfile.asString(), serviceProfile.getResourceType());
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new IllegalStateException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public ISRegistryService getRegistryService() {
|
||||||
|
return registryService;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Required
|
||||||
|
public void setRegistryService(final ISRegistryService registryService) {
|
||||||
|
this.registryService = registryService;
|
||||||
|
}
|
||||||
|
|
||||||
|
public JaxbFactory<BlackboardMessage> getMessageFactory() {
|
||||||
|
return messageFactory;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Required
|
||||||
|
public void setMessageFactory(final JaxbFactory<BlackboardMessage> messageFactory) {
|
||||||
|
this.messageFactory = messageFactory;
|
||||||
|
}
|
||||||
|
|
||||||
|
public MessageDater getMessageDater() {
|
||||||
|
return messageDater;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMessageDater(final MessageDater messageDater) {
|
||||||
|
this.messageDater = messageDater;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ISLookUpService getIsLookup() {
|
||||||
|
return isLookup;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Required
|
||||||
|
public void setIsLookup(final ISLookUpService isLookup) {
|
||||||
|
this.isLookup = isLookup;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,8 @@
|
||||||
|
package eu.dnetlib.enabling.is.registry;
|
||||||
|
|
||||||
|
import javax.xml.xpath.XPathExpressionException;
|
||||||
|
|
||||||
|
public interface ResourceKindResolver {
|
||||||
|
String getNormalKindForType(final String resourceType) throws XPathExpressionException;
|
||||||
|
String getPendingKindForType(final String resourceType) throws XPathExpressionException;
|
||||||
|
}
|
|
@ -0,0 +1,62 @@
|
||||||
|
package eu.dnetlib.enabling.is.registry;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import javax.xml.xpath.XPathExpressionException;
|
||||||
|
|
||||||
|
import org.apache.commons.logging.Log;
|
||||||
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
import org.springframework.beans.factory.annotation.Required;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the first resource resolver
|
||||||
|
*
|
||||||
|
* @author marko
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class ResourceKindResolverChain implements ResourceKindResolver {
|
||||||
|
|
||||||
|
private static final Log log = LogFactory.getLog(ResourceKindResolverChain.class); // NOPMD by marko on 11/24/08 5:02 PM
|
||||||
|
|
||||||
|
/**
|
||||||
|
* resolvers.
|
||||||
|
*/
|
||||||
|
private List<ResourceKindResolver> resolvers;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getNormalKindForType(final String resourceType) throws XPathExpressionException {
|
||||||
|
for (final ResourceKindResolver resolver : resolvers) {
|
||||||
|
final String res = resolver.getNormalKindForType(resourceType);
|
||||||
|
if (res != null)
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getPendingKindForType(final String resourceType) throws XPathExpressionException {
|
||||||
|
for (final ResourceKindResolver resolver : resolvers) {
|
||||||
|
try {
|
||||||
|
final String res = resolver.getPendingKindForType(resourceType);
|
||||||
|
if (res != null)
|
||||||
|
return res;
|
||||||
|
} catch (NoSuchPendingCategoryException e) {
|
||||||
|
log.debug("resolver didn't find pending category", e);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
log.debug("cannot find pending category because no resolver found a pending category");
|
||||||
|
throw new NoSuchPendingCategoryException("no pending category for " + resourceType);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<ResourceKindResolver> getResolvers() {
|
||||||
|
return resolvers;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Required
|
||||||
|
public void setResolvers(final List<ResourceKindResolver> resolvers) {
|
||||||
|
this.resolvers = resolvers;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,57 @@
|
||||||
|
package eu.dnetlib.enabling.is.registry.schema;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.StringReader;
|
||||||
|
|
||||||
|
import javax.xml.transform.stream.StreamSource;
|
||||||
|
import javax.xml.validation.Schema;
|
||||||
|
import javax.xml.validation.Validator;
|
||||||
|
|
||||||
|
import org.xml.sax.SAXException;
|
||||||
|
|
||||||
|
import eu.dnetlib.enabling.tools.OpaqueResource;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* validates an opaque resource according to its declared resource type.
|
||||||
|
*
|
||||||
|
* @author marko
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class OpaqueResourceValidatorImpl implements OpaqueResourceValidator {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* schema dao.
|
||||||
|
*/
|
||||||
|
private ResourceSchemaDAO schemaDao;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*
|
||||||
|
* @see eu.dnetlib.enabling.is.registry.schema.OpaqueResourceValidator#validate(eu.dnetlib.enabling.tools.OpaqueResource)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void validate(final OpaqueResource resource) throws ValidationException {
|
||||||
|
final Schema schema = getSchemaDao().getResourceSchema(resource.getResourceType());
|
||||||
|
if (schema == null)
|
||||||
|
throw new ValidationException("no registered schema for " + resource.getResourceType());
|
||||||
|
final Validator validator = schema.newValidator();
|
||||||
|
|
||||||
|
try {
|
||||||
|
// hack to workaround for #1500
|
||||||
|
validator.validate(new StreamSource(new StringReader(resource.asString())));
|
||||||
|
} catch (SAXException e) {
|
||||||
|
throw new ValidationException(e);
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new ValidationException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public ResourceSchemaDAO getSchemaDao() {
|
||||||
|
return schemaDao;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSchemaDao(final ResourceSchemaDAO schemaDao) {
|
||||||
|
this.schemaDao = schemaDao;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,36 @@
|
||||||
|
package eu.dnetlib.enabling.is.registry.schema;
|
||||||
|
|
||||||
|
import org.apache.commons.logging.Log;
|
||||||
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
|
||||||
|
import eu.dnetlib.enabling.tools.OpaqueResource;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unlike the OpaqueResourceValidatorImpl, this implementation only logs an error but accepts every resource as valid.
|
||||||
|
*
|
||||||
|
* Use only during testing/development!
|
||||||
|
*
|
||||||
|
* @author marko
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class PermissiveOpaqueResourceValidatorImpl extends OpaqueResourceValidatorImpl {
|
||||||
|
/**
|
||||||
|
* logger.
|
||||||
|
*/
|
||||||
|
private static final Log log = LogFactory.getLog(PermissiveOpaqueResourceValidatorImpl.class); // NOPMD by marko on 11/24/08 5:02 PM
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*
|
||||||
|
* @see eu.dnetlib.enabling.is.registry.schema.OpaqueResourceValidatorImpl#validate(eu.dnetlib.enabling.tools.OpaqueResource)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void validate(final OpaqueResource resource) throws ValidationException {
|
||||||
|
try {
|
||||||
|
super.validate(resource);
|
||||||
|
} catch (ValidationException e) {
|
||||||
|
log.fatal("validation error, continuing (permissive mode)", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
package eu.dnetlib.enabling.is.registry.schema;
|
||||||
|
|
||||||
|
import javax.xml.validation.Schema;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* data access object for managing resource schemas.
|
||||||
|
*
|
||||||
|
* @author marko
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public interface ResourceSchemaDAO {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* obtain a resource schema instance for a given resource type.
|
||||||
|
*
|
||||||
|
* @param resourceType resource type
|
||||||
|
* @return schema instance
|
||||||
|
*/
|
||||||
|
Schema getResourceSchema(String resourceType);
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,65 @@
|
||||||
|
package eu.dnetlib.enabling.is.registry.schema;
|
||||||
|
|
||||||
|
import java.io.StringReader;
|
||||||
|
|
||||||
|
import javax.xml.XMLConstants;
|
||||||
|
import javax.xml.transform.stream.StreamSource;
|
||||||
|
import javax.xml.validation.Schema;
|
||||||
|
import javax.xml.validation.SchemaFactory;
|
||||||
|
|
||||||
|
import org.apache.commons.logging.Log;
|
||||||
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
import org.springframework.beans.factory.annotation.Required;
|
||||||
|
import org.xml.sax.SAXException;
|
||||||
|
|
||||||
|
import eu.dnetlib.enabling.is.lookup.rmi.ISLookUpException;
|
||||||
|
import eu.dnetlib.enabling.is.lookup.rmi.ISLookUpService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* manages the resource schemas through the registry service.
|
||||||
|
*
|
||||||
|
* @author marko
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class ResourceSchemaDAOImpl implements ResourceSchemaDAO {
|
||||||
|
|
||||||
|
private ISLookUpService isLookup;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* logger.
|
||||||
|
*/
|
||||||
|
private static final Log log = LogFactory.getLog(ResourceSchemaDAOImpl.class); // NOPMD by marko on 11/24/08 5:02 PM
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*
|
||||||
|
* @see eu.dnetlib.enabling.is.registry.schema.ResourceSchemaDAO#getResourceSchema(java.lang.String)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public Schema getResourceSchema(final String resourceType) {
|
||||||
|
try {
|
||||||
|
final String schemaSource = isLookup.getResourceTypeSchema(resourceType);
|
||||||
|
if (schemaSource == null || schemaSource.isEmpty()) {
|
||||||
|
log.warn("cannot find resource type " + resourceType);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI).newSchema(new StreamSource(new StringReader(schemaSource)));
|
||||||
|
} catch (ISLookUpException e) {
|
||||||
|
log.warn("cannot find resource type" + resourceType, e);
|
||||||
|
return null;
|
||||||
|
} catch (SAXException e) {
|
||||||
|
log.fatal("cannot parse resource type schema", e);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public ISLookUpService getIsLookup() {
|
||||||
|
return isLookup;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Required
|
||||||
|
public void setIsLookup(final ISLookUpService isLookup) {
|
||||||
|
this.isLookup = isLookup;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,24 @@
|
||||||
|
package eu.dnetlib.enabling.is.registry.validation;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Required;
|
||||||
|
|
||||||
|
import eu.dnetlib.enabling.tools.OpaqueResource;
|
||||||
|
|
||||||
|
public abstract class AbstractProfileValidator implements ProfileValidator {
|
||||||
|
|
||||||
|
private RegistrationPhase phase;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean handle(final OpaqueResource resource, final RegistrationPhase phase) {
|
||||||
|
return this.phase == phase;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Required
|
||||||
|
public void setPhase(String phase) {
|
||||||
|
this.phase = RegistrationPhase.valueOf(phase);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPhase() {
|
||||||
|
return phase.name();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,34 @@
|
||||||
|
package eu.dnetlib.enabling.is.registry.validation;
|
||||||
|
|
||||||
|
import eu.dnetlib.enabling.tools.OpaqueResource;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dummy bean used to populate the ProfileValidator list.
|
||||||
|
* @see eu.dnetlib.enabling.is.registry.validation.ProfileValidationStrategy
|
||||||
|
*
|
||||||
|
* @author claudio
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class AlwaysAcceptProfileValidator implements ProfileValidator {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*
|
||||||
|
* @see eu.dnetlib.enabling.is.registry.validation.ProfileValidator#accept(OpaqueResource)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean accept(OpaqueResource resource) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*
|
||||||
|
* @see eu.dnetlib.enabling.is.registry.validation.ProfileValidator#handle(OpaqueResource, RegistrationPhase)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean handle(OpaqueResource resource, RegistrationPhase phase) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,38 @@
|
||||||
|
package eu.dnetlib.enabling.is.registry.validation;
|
||||||
|
|
||||||
|
import javax.xml.xpath.XPath;
|
||||||
|
import javax.xml.xpath.XPathExpressionException;
|
||||||
|
import javax.xml.xpath.XPathFactory;
|
||||||
|
|
||||||
|
import eu.dnetlib.enabling.tools.OpaqueResource;
|
||||||
|
|
||||||
|
public class EnsurePropertyExistsProfileValidator extends TypeAwareProfileValidator {
|
||||||
|
|
||||||
|
private String name; // property name
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean accept(OpaqueResource resource) {
|
||||||
|
try {
|
||||||
|
final XPath xpath = XPathFactory.newInstance().newXPath();
|
||||||
|
|
||||||
|
final String xquery = "//EXTRA_FIELDS/FIELD[./key = '" + getName() + "']/value/text()";
|
||||||
|
final String value = xpath.evaluate(xquery, resource.asDom().getDocumentElement()) + "";
|
||||||
|
|
||||||
|
if (value.isEmpty())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
|
||||||
|
} catch (XPathExpressionException e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,34 @@
|
||||||
|
package eu.dnetlib.enabling.is.registry.validation;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
|
||||||
|
import eu.dnetlib.enabling.is.registry.schema.ValidationException;
|
||||||
|
import eu.dnetlib.enabling.tools.OpaqueResource;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ProfileValidationStrategy iterates all the profile validators,
|
||||||
|
* once a suitable validator is found, it's called to accept or
|
||||||
|
* reject the given resource.
|
||||||
|
*
|
||||||
|
* @author claudio
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class ProfileValidationStrategy {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private List<ProfileValidator> profileValidators;
|
||||||
|
|
||||||
|
public boolean accept(OpaqueResource resource, RegistrationPhase phase) throws ValidationException {
|
||||||
|
for(ProfileValidator validator : profileValidators) {
|
||||||
|
if (validator.handle(resource, phase)) {
|
||||||
|
if (validator.accept(resource))
|
||||||
|
return true;
|
||||||
|
else throw new ValidationException("Cannot validate the given resource: " + resource.asString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// if no validator handles the resource
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,23 @@
|
||||||
|
package eu.dnetlib.enabling.is.registry.validation;
|
||||||
|
|
||||||
|
import eu.dnetlib.enabling.tools.OpaqueResource;
|
||||||
|
|
||||||
|
public interface ProfileValidator {
|
||||||
|
/**
|
||||||
|
* True if this validator will handle this profile, false otherwise.
|
||||||
|
* 'accept' will be invoked only if 'handle' returns true
|
||||||
|
*
|
||||||
|
* @param resource
|
||||||
|
* @param phase
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public boolean handle(OpaqueResource resource, RegistrationPhase phase);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* true if accept, false reject.
|
||||||
|
*
|
||||||
|
* @param resource
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public boolean accept(OpaqueResource resource);
|
||||||
|
}
|
|
@ -0,0 +1,12 @@
|
||||||
|
package eu.dnetlib.enabling.is.registry.validation;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resources registration phases.
|
||||||
|
*
|
||||||
|
* @author claudio
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public enum RegistrationPhase {
|
||||||
|
Register,
|
||||||
|
Validate // as in 'validateProfile', not this 'validation'.
|
||||||
|
}
|
|
@ -0,0 +1,25 @@
|
||||||
|
package eu.dnetlib.enabling.is.registry.validation;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Required;
|
||||||
|
|
||||||
|
import eu.dnetlib.enabling.tools.OpaqueResource;
|
||||||
|
|
||||||
|
public abstract class TypeAwareProfileValidator extends AbstractProfileValidator {
|
||||||
|
|
||||||
|
private String resourceType;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean handle(OpaqueResource resource, RegistrationPhase phase) {
|
||||||
|
return super.handle(resource, phase) && getResourceType().equals(resource.getResourceType());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Required
|
||||||
|
public void setResourceType(String resourceType) {
|
||||||
|
this.resourceType = resourceType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getResourceType() {
|
||||||
|
return resourceType;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,30 @@
|
||||||
|
package eu.dnetlib.enabling.is.sn;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* NotificationDetector interface defines an injection point for the NotificationSender instance.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* It will be fairly common for implementors of NotificatiorDetector to back the sender reference into an instance
|
||||||
|
* variable. This abstract class offers this for free.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author marko
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public abstract class AbstractNotificationDetector implements NotificationDetector {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* notification sender which will receive events triggered by this detector.
|
||||||
|
*/
|
||||||
|
private NotificationSender sender;
|
||||||
|
|
||||||
|
public NotificationSender getSender() {
|
||||||
|
return sender;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setSender(final NotificationSender sender) {
|
||||||
|
this.sender = sender;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,30 @@
|
||||||
|
package eu.dnetlib.enabling.is.sn;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* NotificationSender interface defines an injection point for the NotificationInvoker instance.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* It will be fairly common for implementors of NotificationSender to back the invoker reference into an instance
|
||||||
|
* variable. This abstract class offers this for free. </p>
|
||||||
|
*
|
||||||
|
* @author marko
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public abstract class AbstractNotificationSender implements NotificationSender {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* notification invoker used to send messages to destinations.
|
||||||
|
*/
|
||||||
|
private NotificationInvoker invoker;
|
||||||
|
|
||||||
|
public NotificationInvoker getInvoker() {
|
||||||
|
return invoker;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setInvoker(final NotificationInvoker invoker) {
|
||||||
|
this.invoker = invoker;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,53 @@
|
||||||
|
package eu.dnetlib.enabling.is.sn;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
|
import org.apache.oro.text.perl.Perl5Util;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides common functionality for subscription registries.
|
||||||
|
*
|
||||||
|
* @author marko
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public abstract class AbstractSubscriptionRegistry {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* prefix position in regular expression.
|
||||||
|
*/
|
||||||
|
private static final int PREFIX_POSITION = 1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* rest of string position in regular expression.
|
||||||
|
*/
|
||||||
|
private static final int REST_POSITION = 3;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return true if the subscription prefix is acceptable.
|
||||||
|
*
|
||||||
|
* Topic expressions are made of slash-delimited components. The "prefix" here is the first slash (/) delimited
|
||||||
|
* string of the topic expression.
|
||||||
|
*
|
||||||
|
* TODO: stupid implementation.
|
||||||
|
*
|
||||||
|
* @param subscription
|
||||||
|
* subscription request
|
||||||
|
* @return true if accepted
|
||||||
|
*/
|
||||||
|
protected TopicExpressionMatchResult matchPrefix(final SubscriptionRequest subscription) {
|
||||||
|
final Perl5Util matcher = new Perl5Util(); // NOPMD
|
||||||
|
|
||||||
|
for (String prefix : getAcceptedPrefixes())
|
||||||
|
if (matcher.match("/^(" + prefix + ")($|/)(.*)$/", subscription.getTopicExpression())) {
|
||||||
|
return new TopicExpressionMatchResult(matcher.getMatch().group(PREFIX_POSITION), matcher.getMatch().group(REST_POSITION));
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A collection of accepted prefixes.
|
||||||
|
*
|
||||||
|
* @return prefix list
|
||||||
|
*/
|
||||||
|
protected abstract Collection<String> getAcceptedPrefixes();
|
||||||
|
}
|
|
@ -0,0 +1,119 @@
|
||||||
|
package eu.dnetlib.enabling.is.sn;
|
||||||
|
|
||||||
|
import java.util.concurrent.BlockingQueue;
|
||||||
|
import java.util.concurrent.LinkedBlockingQueue;
|
||||||
|
|
||||||
|
import javax.xml.ws.wsaddressing.W3CEndpointReference;
|
||||||
|
|
||||||
|
import org.apache.commons.logging.Log;
|
||||||
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Asynchronous but in-order delivery of notifications.
|
||||||
|
*
|
||||||
|
* @author marko
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class AsynchronousNotificationSenderImpl extends AbstractNotificationSender implements Runnable { // NOPMD
|
||||||
|
/**
|
||||||
|
* logger.
|
||||||
|
*/
|
||||||
|
private static final Log log = LogFactory.getLog(AsynchronousNotificationSenderImpl.class); // NOPMD by marko on 11/24/08 5:02 PM
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Encapsulates an notification job.
|
||||||
|
*
|
||||||
|
* @author marko
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
class NotificationJob {
|
||||||
|
/**
|
||||||
|
* notification destination.
|
||||||
|
*/
|
||||||
|
private final transient W3CEndpointReference destination;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* notification message.
|
||||||
|
*/
|
||||||
|
private final transient NotificationMessage message;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* construct a new notification job.
|
||||||
|
*
|
||||||
|
* @param destination destination
|
||||||
|
* @param message message
|
||||||
|
*/
|
||||||
|
public NotificationJob(final W3CEndpointReference destination, final NotificationMessage message) {
|
||||||
|
super();
|
||||||
|
this.destination = destination;
|
||||||
|
this.message = message;
|
||||||
|
}
|
||||||
|
|
||||||
|
public W3CEndpointReference getDestination() {
|
||||||
|
return destination;
|
||||||
|
}
|
||||||
|
|
||||||
|
public NotificationMessage getMessage() {
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* job queue.
|
||||||
|
*/
|
||||||
|
private BlockingQueue<NotificationJob> jobQueue = new LinkedBlockingQueue<NotificationJob>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*
|
||||||
|
* @see eu.dnetlib.enabling.is.sn.NotificationSender#send(javax.xml.ws.wsaddressing.W3CEndpointReference,
|
||||||
|
* eu.dnetlib.enabling.is.sn.NotificationMessage)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void send(final W3CEndpointReference destination, final NotificationMessage message) {
|
||||||
|
log.debug("queuing asynchronous notification");
|
||||||
|
try {
|
||||||
|
jobQueue.put(new NotificationJob(destination, message));
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
log.warn("possibly lost notification", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* start this notification sender (called by spring lifecycle).
|
||||||
|
*/
|
||||||
|
void start() {
|
||||||
|
new Thread(this).start(); // NOPMD
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
* @see java.lang.Runnable#run()
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
while (true) {
|
||||||
|
try {
|
||||||
|
final NotificationJob job = jobQueue.take();
|
||||||
|
|
||||||
|
try {
|
||||||
|
getInvoker().send(job.getDestination(), job.getMessage(), 0);
|
||||||
|
} catch (javax.xml.ws.soap.SOAPFaultException t) {
|
||||||
|
log.fatal("error sending notification to " + job.getDestination().toString(), t);
|
||||||
|
}
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
log.warn("possibly lost notification", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public BlockingQueue<NotificationJob> getJobQueue() {
|
||||||
|
return jobQueue;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setJobQueue(final BlockingQueue<NotificationJob> jobQueue) {
|
||||||
|
this.jobQueue = jobQueue;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,23 @@
|
||||||
|
package eu.dnetlib.enabling.is.sn;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
|
||||||
|
import org.apache.commons.logging.Log;
|
||||||
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
|
||||||
|
public class DnetPathVerifier {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* logger.
|
||||||
|
*/
|
||||||
|
private static final Log log = LogFactory.getLog(DnetPathVerifier.class); // NOPMD by marko on 11/24/08 5:02 PM
|
||||||
|
|
||||||
|
public DnetPathVerifier(final String dnetPath) {
|
||||||
|
File f = new File(dnetPath);
|
||||||
|
if (f.exists() == false) {
|
||||||
|
log.info("path '" + dnetPath + "' not found, creating...");
|
||||||
|
f.mkdirs();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,65 @@
|
||||||
|
package eu.dnetlib.enabling.is.sn;
|
||||||
|
|
||||||
|
import javax.xml.transform.dom.DOMResult;
|
||||||
|
import javax.xml.ws.wsaddressing.W3CEndpointReference;
|
||||||
|
import javax.xml.xpath.XPathExpressionException;
|
||||||
|
import javax.xml.xpath.XPathFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extracts useful low level informations from an EPR, so that these can be encoded in the OAI
|
||||||
|
* resumption token.
|
||||||
|
*
|
||||||
|
* @author michele
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public final class EPRUtil {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* prevents instantiation.
|
||||||
|
*/
|
||||||
|
private EPRUtil() {
|
||||||
|
// prevents instantiation
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extracts the service address out of the EPR.
|
||||||
|
*
|
||||||
|
* @param epr epr
|
||||||
|
* @return address
|
||||||
|
*/
|
||||||
|
public static String getAddress(final W3CEndpointReference epr) {
|
||||||
|
return getValue(epr, "Address");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extracts the resource identifier out of the EPR.
|
||||||
|
* @param epr epr
|
||||||
|
* @return resource identifier
|
||||||
|
*/
|
||||||
|
public static String getResourceIdentifier(final W3CEndpointReference epr) {
|
||||||
|
return getValue(epr, "ResourceIdentifier");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extracts an element with a given local name out of the resource identifier.
|
||||||
|
*
|
||||||
|
* @param epr epr
|
||||||
|
* @param name element name
|
||||||
|
* @return element value
|
||||||
|
*/
|
||||||
|
private static String getValue(final W3CEndpointReference epr, final String name) {
|
||||||
|
final DOMResult dom = new DOMResult();
|
||||||
|
epr.writeTo(dom);
|
||||||
|
|
||||||
|
try {
|
||||||
|
return XPathFactory.newInstance().newXPath().evaluate("//*[local-name() = '" + name + "']", dom.getNode());
|
||||||
|
} catch (final XPathExpressionException e) {
|
||||||
|
throw new IllegalStateException("cannot construct xpath expression", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,180 @@
|
||||||
|
package eu.dnetlib.enabling.is.sn;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.FileWriter;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.zip.ZipEntry;
|
||||||
|
import java.util.zip.ZipOutputStream;
|
||||||
|
|
||||||
|
import javax.xml.ws.wsaddressing.W3CEndpointReference;
|
||||||
|
|
||||||
|
import org.apache.commons.logging.Log;
|
||||||
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
import org.springframework.beans.factory.annotation.Required;
|
||||||
|
|
||||||
|
import com.google.gson.Gson;
|
||||||
|
import com.google.gson.reflect.TypeToken;
|
||||||
|
|
||||||
|
import eu.dnetlib.enabling.is.sn.resourcestate.ResourceStateSubscription;
|
||||||
|
import eu.dnetlib.enabling.is.sn.resourcestate.ResourceStateSubscriptionRegistry;
|
||||||
|
import eu.dnetlib.enabling.is.sn.rmi.ISSNException;
|
||||||
|
import eu.dnetlib.enabling.is.sn.rmi.SubscriptionRequestRejectedException;
|
||||||
|
import eu.dnetlib.enabling.tools.UniqueIdentifierGenerator;
|
||||||
|
import eu.dnetlib.enabling.tools.UniqueIdentifierGeneratorImpl;
|
||||||
|
import eu.dnetlib.miscutils.datetime.DateUtils;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Core business logic of ISSN service, decouple from compatibility RMI interface.
|
||||||
|
*
|
||||||
|
* @author marko
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class ISSNServiceCore {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* logger.
|
||||||
|
*/
|
||||||
|
private static final Log log = LogFactory.getLog(ISSNServiceCore.class); // NOPMD by marko on 11/24/08 5:02 PM
|
||||||
|
|
||||||
|
/**
|
||||||
|
* subscription registries to lookup.
|
||||||
|
*/
|
||||||
|
private SubscriptionRegistry registry;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* generates subscription identifiers.
|
||||||
|
*/
|
||||||
|
private UniqueIdentifierGenerator uuidGenerator = new UniqueIdentifierGeneratorImpl("sn");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Directory in which backups are saved.
|
||||||
|
*/
|
||||||
|
private String backupDir;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* subscribe a consumer to topics matching the topic expression.
|
||||||
|
*
|
||||||
|
* @param consumerReference
|
||||||
|
* EPR to the service to be notified
|
||||||
|
* @param topicExpression
|
||||||
|
* topic expression
|
||||||
|
* @param ttl
|
||||||
|
* time to live in seconds
|
||||||
|
* @return subscription identifier
|
||||||
|
*/
|
||||||
|
public String subscribe(final W3CEndpointReference consumerReference, final String topicExpression, final int ttl) throws SubscriptionRequestRejectedException {
|
||||||
|
log.debug("subscribing");
|
||||||
|
final SubscriptionRequest srq = new SubscriptionRequest(uuidGenerator.generateIdentifier(), consumerReference, topicExpression, ttl); // NOPMD
|
||||||
|
|
||||||
|
final String subId = getRegistry().registerSubscription(srq);
|
||||||
|
if (subId != null) {
|
||||||
|
return subId;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unsubscribe a subscription, by id.
|
||||||
|
*
|
||||||
|
* @param subscrId subscription id
|
||||||
|
* @return true if unsubscribed
|
||||||
|
*/
|
||||||
|
public boolean unsubscribe(final String subscrId) {
|
||||||
|
return getRegistry().unsubscribe(subscrId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String backup() throws ISSNException {
|
||||||
|
log.info("Starting backup...");
|
||||||
|
try {
|
||||||
|
|
||||||
|
verifyBackupDir();
|
||||||
|
|
||||||
|
String seq = (new SimpleDateFormat("yyyyMMdd-HHmm")).format(new Date());
|
||||||
|
|
||||||
|
ZipOutputStream zip = new ZipOutputStream(new FileOutputStream(backupDir + "/data-" + seq + ".zip"));
|
||||||
|
|
||||||
|
FileWriter logFile = new FileWriter(backupDir + "/report-" + seq + ".log");
|
||||||
|
logFile.write("Backup started at: " + DateUtils.now_ISO8601() + "\n\n");
|
||||||
|
|
||||||
|
backup(zip, logFile);
|
||||||
|
|
||||||
|
logFile.write("\nBackup finished at: " + DateUtils.now_ISO8601() + "\n");
|
||||||
|
|
||||||
|
logFile.flush();
|
||||||
|
logFile.close();
|
||||||
|
|
||||||
|
zip.flush();
|
||||||
|
zip.close();
|
||||||
|
|
||||||
|
log.info("Backup finished");
|
||||||
|
return backupDir;
|
||||||
|
} catch (final Exception e) {
|
||||||
|
log.error("Backup failed", e);
|
||||||
|
throw new ISSNException("cannot backup", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void backup(ZipOutputStream zip, FileWriter logFile) throws IOException {
|
||||||
|
|
||||||
|
for (ResourceStateSubscription sub : getRegistry().listSubscriptions()) {
|
||||||
|
|
||||||
|
logFile.write("SUBSCRIPTION: " + sub.getSubscriptionId() + "\n");
|
||||||
|
log.info("Backup of subscription: " + sub.getSubscriptionId());
|
||||||
|
|
||||||
|
final Map<String, String> attrs = new HashMap<String, String>(); // NOPMD
|
||||||
|
attrs.put("prefix", sub.getPrefix());
|
||||||
|
attrs.put("type", sub.getType());
|
||||||
|
attrs.put("resourceId", sub.getResourceId());
|
||||||
|
attrs.put("xpath", sub.getXpath());
|
||||||
|
attrs.put("id", sub.getSubscriptionId());
|
||||||
|
attrs.put("subscriber", sub.getSubscriber().toString());
|
||||||
|
|
||||||
|
zip.putNextEntry(new ZipEntry(sub.getSubscriptionId()));
|
||||||
|
zip.write(encodeJSon(attrs).getBytes());
|
||||||
|
zip.closeEntry();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String encodeJSon(final Map<String, String> map) {
|
||||||
|
return new Gson().toJson(
|
||||||
|
map,
|
||||||
|
new TypeToken<Map<String, String>>() {}.getType()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void verifyBackupDir() {
|
||||||
|
File d = new File(backupDir);
|
||||||
|
if (!d.exists()) d.mkdirs();
|
||||||
|
}
|
||||||
|
|
||||||
|
public UniqueIdentifierGenerator getUuidGenerator() {
|
||||||
|
return uuidGenerator;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUuidGenerator(final UniqueIdentifierGenerator uuidGenerator) {
|
||||||
|
this.uuidGenerator = uuidGenerator;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getBackupDir() {
|
||||||
|
return backupDir;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Required
|
||||||
|
public void setBackupDir(String backupDir) {
|
||||||
|
this.backupDir = backupDir;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SubscriptionRegistry getRegistry() {
|
||||||
|
return registry;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRegistry(final SubscriptionRegistry registry) {
|
||||||
|
this.registry = registry;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,203 @@
|
||||||
|
package eu.dnetlib.enabling.is.sn;
|
||||||
|
|
||||||
|
import java.util.Calendar;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import javax.xml.ws.Endpoint;
|
||||||
|
import javax.xml.ws.wsaddressing.W3CEndpointReference;
|
||||||
|
|
||||||
|
import org.apache.commons.logging.Log;
|
||||||
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
|
||||||
|
import eu.dnetlib.enabling.is.sn.rmi.ISSNException;
|
||||||
|
import eu.dnetlib.enabling.is.sn.rmi.ISSNService;
|
||||||
|
import eu.dnetlib.enabling.is.sn.rmi.SubscriptionRequestRejectedException;
|
||||||
|
import eu.dnetlib.enabling.tools.AbstractBaseService;
|
||||||
|
import eu.dnetlib.soap.EndpointReferenceBuilder;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* implementation of ISSNService.
|
||||||
|
*
|
||||||
|
* @author marko
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class ISSNServiceImpl extends AbstractBaseService implements ISSNService {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* logger.
|
||||||
|
*/
|
||||||
|
private static final Log log = LogFactory.getLog(ISSNServiceImpl.class); // NOPMD by marko on 11/24/08 5:02 PM
|
||||||
|
|
||||||
|
/**
|
||||||
|
* obvious constant.
|
||||||
|
*/
|
||||||
|
private static final int MILLIS_IN_SECOND = 1000;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* service endpoint.
|
||||||
|
*/
|
||||||
|
private Endpoint endpoint;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* core business logic.
|
||||||
|
*/
|
||||||
|
private ISSNServiceCore core;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* injected EPR builder.
|
||||||
|
*/
|
||||||
|
@Resource(name = "jaxwsEndpointReferenceBuilder")
|
||||||
|
private EndpointReferenceBuilder<Endpoint> eprBuilder;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*
|
||||||
|
* @see eu.dnetlib.enabling.is.sn.rmi.ISSNService#actionCreatePerformed(java.lang.String, java.lang.String, java.lang.String)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean actionCreatePerformed(final String resourceType, final String profileId, final String profile) throws ISSNException {
|
||||||
|
log.fatal("actionCreatePerformed(String, String, String) not implemented");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*
|
||||||
|
* @see eu.dnetlib.enabling.is.sn.rmi.ISSNService#actionDeletePerformed(java.lang.String, java.lang.String)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean actionDeletePerformed(final String resourceType, final String profileId) throws ISSNException {
|
||||||
|
log.fatal("actionDeletePerformed(String, String) not implemented");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*
|
||||||
|
* @see eu.dnetlib.enabling.is.sn.rmi.ISSNService#actionUpdatePerformed(java.lang.String, java.lang.String, java.lang.String,
|
||||||
|
* java.lang.String)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean actionUpdatePerformed(final String resourceType, final String profileId, final String profileBefore, final String profileAfter)
|
||||||
|
throws ISSNException {
|
||||||
|
log.fatal("actionUpdatePerformed(String, String, String, String) not implemented");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*
|
||||||
|
* @see eu.dnetlib.enabling.is.sn.rmi.ISSNService#getCurrentMessage(java.lang.String)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String getCurrentMessage(final String topic) throws ISSNException {
|
||||||
|
log.fatal("getCurrentMessage(String) not implemented");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*
|
||||||
|
* @see eu.dnetlib.enabling.is.sn.rmi.ISSNService#listSubscriptions()
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public List<String> listSubscriptions() {
|
||||||
|
log.fatal("listSubscriptions() not implemented");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*
|
||||||
|
* @see eu.dnetlib.enabling.is.sn.rmi.ISSNService#pauseSubscription(java.lang.String)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean pauseSubscription(final String subscrId) throws ISSNException {
|
||||||
|
log.fatal("pauseSubscription(String) not implemented");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*
|
||||||
|
* @see eu.dnetlib.enabling.is.sn.rmi.ISSNService#renew(java.lang.String, int)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean renew(final String subscrId, final int terminationTime) throws ISSNException {
|
||||||
|
log.fatal("renew(String, int) not implemented");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*
|
||||||
|
* @see eu.dnetlib.enabling.is.sn.rmi.ISSNService#resumeSubscription(java.lang.String)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean resumeSubscription(final String subscrId) throws ISSNException {
|
||||||
|
log.fatal("resumeSubscription(String) not implemented");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*
|
||||||
|
* @see eu.dnetlib.enabling.is.sn.rmi.ISSNService#subscribe(javax.xml.ws.wsaddressing.W3CEndpointReference, java.lang.String, int)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String subscribe(final W3CEndpointReference consumerReference, final String topicExpression, final int termTime) throws ISSNException, SubscriptionRequestRejectedException {
|
||||||
|
|
||||||
|
log.debug("subscribe request from: " + consumerReference.toString() + " topic: " + topicExpression);
|
||||||
|
|
||||||
|
int ttl;
|
||||||
|
if (termTime == 0) {
|
||||||
|
ttl = 0;
|
||||||
|
} else {
|
||||||
|
ttl = (int) (termTime - (Calendar.getInstance().getTimeInMillis() / MILLIS_IN_SECOND));
|
||||||
|
}
|
||||||
|
|
||||||
|
final String res = core.subscribe(consumerReference, topicExpression, ttl);
|
||||||
|
if (res == null) throw new ISSNException("couldn't find a subscription registry for the given topic: " + topicExpression);
|
||||||
|
|
||||||
|
log.debug("subscribe success, subscriptionId: " + res);
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*
|
||||||
|
* @see eu.dnetlib.enabling.is.sn.rmi.ISSNService#unsubscribe(java.lang.String)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean unsubscribe(final String subscrId) throws ISSNException {
|
||||||
|
log.debug("unsubscribe request for: " + subscrId);
|
||||||
|
return core.unsubscribe(subscrId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Endpoint getEndpoint() {
|
||||||
|
return endpoint;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEndpoint(final Endpoint endpoint) {
|
||||||
|
this.endpoint = endpoint;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ISSNServiceCore getCore() {
|
||||||
|
return core;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCore(final ISSNServiceCore core) {
|
||||||
|
this.core = core;
|
||||||
|
}
|
||||||
|
|
||||||
|
public EndpointReferenceBuilder<Endpoint> getEprBuilder() {
|
||||||
|
return eprBuilder;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEprBuilder(final EndpointReferenceBuilder<Endpoint> eprBuilder) {
|
||||||
|
this.eprBuilder = eprBuilder;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,263 @@
|
||||||
|
package eu.dnetlib.enabling.is.sn;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||||
|
|
||||||
|
import javax.xml.ws.wsaddressing.W3CEndpointReference;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* In memory implementation of a notification invocation logger.
|
||||||
|
*
|
||||||
|
* @author marko
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class MemoryNotificationInvocationLogger implements NotificationInvocationLogger {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* default log size.
|
||||||
|
*/
|
||||||
|
private static final int DEFAULT_SIZE = 100;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Entry.
|
||||||
|
*
|
||||||
|
* @author marko
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class MemoryEntry implements Entry {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* logged message.
|
||||||
|
*/
|
||||||
|
private NotificationMessage message;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* message status.
|
||||||
|
*/
|
||||||
|
private Status status = Status.Queued;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* saved exception in case of Failed state.
|
||||||
|
*/
|
||||||
|
private Throwable exception;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* destination.
|
||||||
|
*/
|
||||||
|
private W3CEndpointReference destinationEpr;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* start date time.
|
||||||
|
*/
|
||||||
|
private Date start;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* finish date time.
|
||||||
|
*/
|
||||||
|
private Date finish;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* construct a new message.
|
||||||
|
*
|
||||||
|
* @param endpointReference
|
||||||
|
* destination
|
||||||
|
*
|
||||||
|
* @param message
|
||||||
|
* message
|
||||||
|
*/
|
||||||
|
public MemoryEntry(final W3CEndpointReference endpointReference, final NotificationMessage message) {
|
||||||
|
this.destinationEpr = endpointReference;
|
||||||
|
this.message = message;
|
||||||
|
this.start = new Date();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*
|
||||||
|
* @see eu.dnetlib.enabling.is.sn.NotificationInvocationLogger.Entry#ongoing()
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void ongoing() {
|
||||||
|
status = Status.Ongoing;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*
|
||||||
|
* @see eu.dnetlib.enabling.is.sn.NotificationInvocationLogger.Entry#failure(java.lang.Throwable)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void failure(final Throwable exc) {
|
||||||
|
status = Status.Failed;
|
||||||
|
this.exception = exc;
|
||||||
|
commit();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*
|
||||||
|
* @see eu.dnetlib.enabling.is.sn.NotificationInvocationLogger.Entry#success()
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void success() {
|
||||||
|
status = Status.Succeeded;
|
||||||
|
commit();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* finalize log entry.
|
||||||
|
*/
|
||||||
|
protected void commit() {
|
||||||
|
this.finish = new Date();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public NotificationMessage getMessage() {
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMessage(final NotificationMessage message) {
|
||||||
|
this.message = message;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Throwable getException() {
|
||||||
|
return exception;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setException(final Throwable exception) {
|
||||||
|
this.exception = exception;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Status getStatus() {
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setStatus(final Status status) {
|
||||||
|
this.status = status;
|
||||||
|
}
|
||||||
|
|
||||||
|
public W3CEndpointReference getDestinationEpr() {
|
||||||
|
return destinationEpr;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDestinationEpr(final W3CEndpointReference destinationEpr) {
|
||||||
|
this.destinationEpr = destinationEpr;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getDestination() {
|
||||||
|
return EPRUtil.getAddress(destinationEpr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*
|
||||||
|
* @see eu.dnetlib.enabling.is.sn.NotificationInvocationLogger.Entry#getErrorMessage()
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String getErrorMessage() {
|
||||||
|
if (getException() == null)
|
||||||
|
return "";
|
||||||
|
return getException().getMessage();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Date getStart() {
|
||||||
|
return start;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setStart(final Date start) {
|
||||||
|
this.start = start;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Date getFinish() {
|
||||||
|
return finish;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFinish(final Date finish) {
|
||||||
|
this.finish = finish;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
* @see eu.dnetlib.enabling.is.sn.NotificationInvocationLogger.Entry#getDuration()
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String getDuration() {
|
||||||
|
if (finish == null || start == null)
|
||||||
|
return "-";
|
||||||
|
return (finish.getTime() - start.getTime()) + " ms";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* the actual log storage.
|
||||||
|
*/
|
||||||
|
private ConcurrentLinkedQueue<Entry> queue = new ConcurrentLinkedQueue<Entry>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* max log size.
|
||||||
|
*/
|
||||||
|
private int size = DEFAULT_SIZE;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*
|
||||||
|
* @see eu.dnetlib.enabling.is.sn.NotificationInvocationLogger#startLogging(eu.dnetlib.enabling.is.sn.NotificationMessage)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public Entry startLogging(final W3CEndpointReference dest, final NotificationMessage message) {
|
||||||
|
final Entry entry = createLoggingEntry(dest, message);
|
||||||
|
queue.add(entry);
|
||||||
|
ensureQueueLength();
|
||||||
|
return entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ensure that the queue doesn't grow beyond size.
|
||||||
|
*/
|
||||||
|
private void ensureQueueLength() {
|
||||||
|
if (queue.size() > size)
|
||||||
|
queue.poll();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* create a new memory log object.
|
||||||
|
*
|
||||||
|
* @param dest
|
||||||
|
* destination
|
||||||
|
*
|
||||||
|
* @param message
|
||||||
|
* message to be logged
|
||||||
|
* @return new entry instance
|
||||||
|
*/
|
||||||
|
protected Entry createLoggingEntry(final W3CEndpointReference dest, final NotificationMessage message) {
|
||||||
|
return new MemoryEntry(dest, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ConcurrentLinkedQueue<Entry> getQueue() {
|
||||||
|
return queue;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setQueue(final ConcurrentLinkedQueue<Entry> queue) {
|
||||||
|
this.queue = queue;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getSize() {
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSize(final int size) {
|
||||||
|
this.size = size;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Collection<Entry> getEntries() {
|
||||||
|
return getQueue();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,17 @@
|
||||||
|
package eu.dnetlib.enabling.is.sn;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implementors of this interface are able to detect events which will trigger notifications.
|
||||||
|
* @author marko
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public interface NotificationDetector {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* injection point for NotificationSender.
|
||||||
|
*
|
||||||
|
* @param sender sender
|
||||||
|
*/
|
||||||
|
void setSender(NotificationSender sender);
|
||||||
|
}
|
|
@ -0,0 +1,217 @@
|
||||||
|
package eu.dnetlib.enabling.is.sn;
|
||||||
|
|
||||||
|
import java.io.StringWriter;
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
|
import javax.xml.transform.Transformer;
|
||||||
|
import javax.xml.transform.TransformerException;
|
||||||
|
import javax.xml.transform.TransformerFactory;
|
||||||
|
import javax.xml.transform.dom.DOMSource;
|
||||||
|
import javax.xml.transform.stream.StreamResult;
|
||||||
|
import javax.xml.xpath.XPath;
|
||||||
|
import javax.xml.xpath.XPathConstants;
|
||||||
|
import javax.xml.xpath.XPathExpressionException;
|
||||||
|
import javax.xml.xpath.XPathFactory;
|
||||||
|
|
||||||
|
import org.apache.commons.logging.Log;
|
||||||
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
import org.w3c.dom.Node;
|
||||||
|
|
||||||
|
import eu.dnetlib.enabling.is.sn.resourcestate.ResourceStateNotificationDetector;
|
||||||
|
import eu.dnetlib.enabling.is.sn.resourcestate.ResourceStateSubscription;
|
||||||
|
import eu.dnetlib.enabling.is.sn.resourcestate.ResourceStateSubscriptionRegistry;
|
||||||
|
import eu.dnetlib.enabling.tools.OpaqueResource;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This notification detector uses a local xmldb trigger as a source of events.
|
||||||
|
*
|
||||||
|
* @author marko
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class NotificationDetectorImpl extends AbstractNotificationDetector implements ResourceStateNotificationDetector<OpaqueResource> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* logger.
|
||||||
|
*/
|
||||||
|
private static final Log log = LogFactory.getLog(NotificationDetectorImpl.class); // NOPMD by marko on 11/24/08 5:02 PM
|
||||||
|
|
||||||
|
/**
|
||||||
|
* subscription registries to lookup.
|
||||||
|
*/
|
||||||
|
private SubscriptionRegistry registry;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*
|
||||||
|
* @see eu.dnetlib.enabling.is.sn.resourcestate.ResourceStateNotificationDetector#resourceCreated(java.lang.Object)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void resourceCreated(final OpaqueResource newResource) {
|
||||||
|
log.debug("resource created: " + getRegistry());
|
||||||
|
|
||||||
|
final Collection<ResourceStateSubscription> subs =
|
||||||
|
getRegistry().listMatchingSubscriptions(ResourceStateSubscription.PREFIX_CREATE, newResource.getResourceType(), newResource.getResourceId());
|
||||||
|
for (ResourceStateSubscription sub : subs) {
|
||||||
|
if (matchPath(newResource, sub.getXpath())) {
|
||||||
|
send(sub, newResource, ResourceStateSubscription.PREFIX_CREATE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* helper method. sends a notification for a given prefix.
|
||||||
|
*
|
||||||
|
* @param sub
|
||||||
|
* subscription
|
||||||
|
* @param resource
|
||||||
|
* resource
|
||||||
|
* @param prefix
|
||||||
|
* prefix
|
||||||
|
*/
|
||||||
|
private void send(final ResourceStateSubscription sub, final OpaqueResource resource, final String prefix) {
|
||||||
|
log.debug("RESOURCE " + resource);
|
||||||
|
log.debug("id: " + resource.getResourceId());
|
||||||
|
log.debug("dom: " + resource.asDom());
|
||||||
|
|
||||||
|
final StringBuffer topicBuffer = new StringBuffer();
|
||||||
|
|
||||||
|
if (sub.getPrefix() == null && "*".equals(sub.getPrefix()))
|
||||||
|
topicBuffer.append(prefix);
|
||||||
|
else
|
||||||
|
topicBuffer.append(sub.getPrefix());
|
||||||
|
|
||||||
|
topicBuffer.append('.');
|
||||||
|
topicBuffer.append(sub.getType());
|
||||||
|
topicBuffer.append('.');
|
||||||
|
topicBuffer.append(sub.getResourceId());
|
||||||
|
if (sub.getXpath() != null && !sub.getXpath().isEmpty()) {
|
||||||
|
topicBuffer.append(sub.getXpath().replace('/', '.'));
|
||||||
|
}
|
||||||
|
|
||||||
|
getSender().send(sub.getSubscriberAsEpr(), new NotificationMessage(sub.getSubscriptionId(), topicBuffer.toString(), resource.getResourceId(), // NOPMD
|
||||||
|
resource.asString()));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*
|
||||||
|
* @see eu.dnetlib.enabling.is.sn.resourcestate.ResourceStateNotificationDetector#resourceDeleted(java.lang.Object)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void resourceDeleted(final OpaqueResource oldResource) {
|
||||||
|
log.debug("resource deleted: " + getRegistry());
|
||||||
|
|
||||||
|
final Collection<ResourceStateSubscription> subs =
|
||||||
|
registry.listMatchingSubscriptions(ResourceStateSubscription.PREFIX_DELETE, oldResource.getResourceType(), oldResource.getResourceId());
|
||||||
|
for (ResourceStateSubscription sub : subs) {
|
||||||
|
if (matchPath(oldResource, sub.getXpath())) {
|
||||||
|
send(sub, oldResource, ResourceStateSubscription.PREFIX_DELETE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*
|
||||||
|
* @see eu.dnetlib.enabling.is.sn.resourcestate.ResourceStateNotificationDetector#resourceUpdated(java.lang.Object,
|
||||||
|
* java.lang.Object)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void resourceUpdated(final OpaqueResource oldResource, final OpaqueResource newResource) {
|
||||||
|
log.debug("resource updated: " + getRegistry());
|
||||||
|
|
||||||
|
final Collection<ResourceStateSubscription> subs =
|
||||||
|
registry.listMatchingSubscriptions(ResourceStateSubscription.PREFIX_UPDATE, oldResource.getResourceType(), oldResource.getResourceId());
|
||||||
|
for (ResourceStateSubscription sub : subs) {
|
||||||
|
if (comparePath(oldResource, newResource, sub.getXpath())) {
|
||||||
|
log.debug("updated, sending: " + newResource.asString());
|
||||||
|
send(sub, newResource, ResourceStateSubscription.PREFIX_UPDATE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* check if an xpath matches a given resource.
|
||||||
|
*
|
||||||
|
* @param resource
|
||||||
|
* resource
|
||||||
|
* @param xpath
|
||||||
|
* xpath
|
||||||
|
* @return true if the resource has some value for the given path
|
||||||
|
*/
|
||||||
|
private boolean matchPath(final OpaqueResource resource, final String xpath) {
|
||||||
|
// by convention empty xpath matches any document
|
||||||
|
if (xpath == null || xpath.isEmpty())
|
||||||
|
return true;
|
||||||
|
|
||||||
|
final XPath xpa = XPathFactory.newInstance().newXPath();
|
||||||
|
try {
|
||||||
|
return !xpa.evaluate(xpath, resource.asDom()).isEmpty();
|
||||||
|
} catch (XPathExpressionException e) {
|
||||||
|
log.warn("wrong xpath expression, notification possibly missed", e);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* compare the content of two profiles for the same xpath. Return true if some change has been made so that the
|
||||||
|
* notification can be delivered.
|
||||||
|
*
|
||||||
|
* @param oldResource
|
||||||
|
* old version
|
||||||
|
* @param newResource
|
||||||
|
* new version
|
||||||
|
* @param xpath
|
||||||
|
* XPath
|
||||||
|
* @return true if the two documents differ under a given path
|
||||||
|
*/
|
||||||
|
private boolean comparePath(final OpaqueResource oldResource, final OpaqueResource newResource, final String xpath) {
|
||||||
|
// by convention empty xpath matches any document
|
||||||
|
if (oldResource == null || newResource == null || xpath == null || xpath.isEmpty())
|
||||||
|
return true;
|
||||||
|
|
||||||
|
final XPath xpa = XPathFactory.newInstance().newXPath();
|
||||||
|
try {
|
||||||
|
final Transformer transformer = TransformerFactory.newInstance().newTransformer();
|
||||||
|
|
||||||
|
final Node left = (Node) xpa.evaluate(xpath, oldResource.asDom(), XPathConstants.NODE);
|
||||||
|
final Node right = (Node) xpa.evaluate(xpath, newResource.asDom(), XPathConstants.NODE);
|
||||||
|
|
||||||
|
if (left==null || right==null) {
|
||||||
|
if (left != null) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (right != null) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
final StringWriter leftWriter = new StringWriter();
|
||||||
|
final StringWriter rightWriter = new StringWriter();
|
||||||
|
|
||||||
|
transformer.transform(new DOMSource(left), new StreamResult(leftWriter));
|
||||||
|
transformer.transform(new DOMSource(right), new StreamResult(rightWriter));
|
||||||
|
|
||||||
|
return !leftWriter.toString().equals(rightWriter.toString());
|
||||||
|
} catch (XPathExpressionException e) {
|
||||||
|
log.warn("wrong xpath expression, notification possibly missed", e);
|
||||||
|
} catch (TransformerException e) {
|
||||||
|
log.warn("serialization problem", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SubscriptionRegistry getRegistry() {
|
||||||
|
return registry;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRegistry(final SubscriptionRegistry registry) {
|
||||||
|
this.registry = registry;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,142 @@
|
||||||
|
package eu.dnetlib.enabling.is.sn;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
import javax.xml.ws.wsaddressing.W3CEndpointReference;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A notification logger maintains a log of sent notifications, and their status (succes or failure with exception etc).
|
||||||
|
*
|
||||||
|
* @author marko
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public interface NotificationInvocationLogger {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A log entry. Used to create log entries in two phases. First a log entry is created with "startLogging" and after
|
||||||
|
* the notification is sent the log entry is committed with success() of failure().
|
||||||
|
*
|
||||||
|
* @author marko
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
interface Entry {
|
||||||
|
/**
|
||||||
|
* log entry status.
|
||||||
|
*
|
||||||
|
* @author marko
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
enum Status {
|
||||||
|
/**
|
||||||
|
* notification is queued but not started to be sent.
|
||||||
|
*/
|
||||||
|
Queued,
|
||||||
|
/**
|
||||||
|
* notification is ongoing.
|
||||||
|
*/
|
||||||
|
Ongoing,
|
||||||
|
/**
|
||||||
|
* notification succeeded.
|
||||||
|
*/
|
||||||
|
Succeeded,
|
||||||
|
/**
|
||||||
|
* notification failed.
|
||||||
|
*/
|
||||||
|
Failed
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* sets the status to ongoing.
|
||||||
|
*/
|
||||||
|
void ongoing();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* commits the log entry tagging it as succeeded.
|
||||||
|
*/
|
||||||
|
void success();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* commits the log entry tagging it as failed.
|
||||||
|
*
|
||||||
|
* @param exception
|
||||||
|
* throwable, cause of failure
|
||||||
|
*/
|
||||||
|
void failure(Throwable exception);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get start date time.
|
||||||
|
*
|
||||||
|
* @return date
|
||||||
|
*/
|
||||||
|
Date getStart();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get finish date time.
|
||||||
|
*
|
||||||
|
* @return date
|
||||||
|
*/
|
||||||
|
Date getFinish();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get log status.
|
||||||
|
*
|
||||||
|
* @return log status
|
||||||
|
*/
|
||||||
|
Status getStatus();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get log message.
|
||||||
|
*
|
||||||
|
* @return log message
|
||||||
|
*/
|
||||||
|
NotificationMessage getMessage();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get destination.
|
||||||
|
*
|
||||||
|
* @return destination url
|
||||||
|
*/
|
||||||
|
String getDestination();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get exception.
|
||||||
|
*
|
||||||
|
* @return exception
|
||||||
|
*/
|
||||||
|
Throwable getException();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get exception error message or empty string if succeded.
|
||||||
|
*
|
||||||
|
* @return error message
|
||||||
|
*/
|
||||||
|
String getErrorMessage();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Human readable duration.
|
||||||
|
*
|
||||||
|
* @return human readable duration
|
||||||
|
*/
|
||||||
|
String getDuration();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Start logging a notification invocation.
|
||||||
|
*
|
||||||
|
* @param destination
|
||||||
|
* destination
|
||||||
|
* @param message
|
||||||
|
* message to be logged.
|
||||||
|
* @return an entry object which has to be committed.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
Entry startLogging(W3CEndpointReference destination, NotificationMessage message);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get all entries.
|
||||||
|
*
|
||||||
|
* @return all entries
|
||||||
|
*/
|
||||||
|
Collection<Entry> getEntries();
|
||||||
|
}
|
|
@ -0,0 +1,26 @@
|
||||||
|
package eu.dnetlib.enabling.is.sn;
|
||||||
|
|
||||||
|
import javax.xml.ws.wsaddressing.W3CEndpointReference;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implementors of this interface decouple the notification producing and dispatching policies
|
||||||
|
* with the actually on-wire sending of the notification message.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* Notification invokers expose a fairly low level interface to notification dispatchers, so that
|
||||||
|
* dispatching policies can configure various aspects of the underlying transport.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author marko
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public interface NotificationInvoker {
|
||||||
|
/**
|
||||||
|
* for now only timeout is exposed.
|
||||||
|
*
|
||||||
|
* @param destination destination EPR
|
||||||
|
* @param message message
|
||||||
|
* @param timeout timeout in seconds
|
||||||
|
*/
|
||||||
|
void send(W3CEndpointReference destination, NotificationMessage message, int timeout);
|
||||||
|
}
|
|
@ -0,0 +1,61 @@
|
||||||
|
package eu.dnetlib.enabling.is.sn;
|
||||||
|
|
||||||
|
import javax.xml.ws.WebServiceFeature;
|
||||||
|
import javax.xml.ws.wsaddressing.W3CEndpointReference;
|
||||||
|
|
||||||
|
import org.apache.commons.logging.Log;
|
||||||
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
import org.springframework.beans.factory.annotation.Required;
|
||||||
|
|
||||||
|
import eu.dnetlib.common.rmi.BaseService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is a basic notification invoker which calls dnet1.0 compatible notify() methods.
|
||||||
|
*
|
||||||
|
* @author marko
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class NotificationInvokerImpl implements NotificationInvoker {
|
||||||
|
/**
|
||||||
|
* logger.
|
||||||
|
*/
|
||||||
|
private static final Log log = LogFactory.getLog(NotificationInvokerImpl.class); // NOPMD by marko on 11/24/08 5:02 PM
|
||||||
|
|
||||||
|
/**
|
||||||
|
* invocation logger.
|
||||||
|
*/
|
||||||
|
private NotificationInvocationLogger invocationLogger;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*
|
||||||
|
* @see eu.dnetlib.enabling.is.sn.NotificationInvoker#send(javax.xml.ws.wsaddressing.W3CEndpointReference,
|
||||||
|
* eu.dnetlib.enabling.is.sn.NotificationMessage, int)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void send(final W3CEndpointReference destination, final NotificationMessage message, final int timeout) {
|
||||||
|
final BaseService service = destination.getPort(BaseService.class, new WebServiceFeature[] {});
|
||||||
|
log.info("phisically sending notification: " + message.getTopic());
|
||||||
|
|
||||||
|
final NotificationInvocationLogger.Entry logEntry = invocationLogger.startLogging(destination, message);
|
||||||
|
logEntry.ongoing();
|
||||||
|
|
||||||
|
try {
|
||||||
|
service.notify(message.getSubscriptionId(), message.getTopic(), message.getResourceId(), message.getBody());
|
||||||
|
logEntry.success();
|
||||||
|
} catch (final Throwable e) { // NOPMD
|
||||||
|
log.debug("notification error", e);
|
||||||
|
logEntry.failure(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public NotificationInvocationLogger getInvocationLogger() {
|
||||||
|
return invocationLogger;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Required
|
||||||
|
public void setInvocationLogger(final NotificationInvocationLogger invocationLogger) {
|
||||||
|
this.invocationLogger = invocationLogger;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,85 @@
|
||||||
|
package eu.dnetlib.enabling.is.sn;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class encapsulates the notification message sent to ISSN subscribers.
|
||||||
|
*
|
||||||
|
* @author marko
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class NotificationMessage {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* subscription identifier.
|
||||||
|
*/
|
||||||
|
private String subscriptionId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* subscription topic that triggered the notification.
|
||||||
|
*/
|
||||||
|
private String topic;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* resource identifier that triggered the notification.
|
||||||
|
*/
|
||||||
|
private String resourceId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* message body.
|
||||||
|
*/
|
||||||
|
private String body;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* default constructor.
|
||||||
|
*/
|
||||||
|
public NotificationMessage() {
|
||||||
|
// no operation
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* constructor with full parameters.
|
||||||
|
*
|
||||||
|
* @param subscriptionId subscription identifier
|
||||||
|
* @param topic produced topic
|
||||||
|
* @param resourceId resource identifier of the resource which triggered the notification, or null
|
||||||
|
* @param body body of the document which triggered the notification, or null
|
||||||
|
*/
|
||||||
|
public NotificationMessage(final String subscriptionId, final String topic, final String resourceId, final String body) {
|
||||||
|
super();
|
||||||
|
this.subscriptionId = subscriptionId;
|
||||||
|
this.topic = topic;
|
||||||
|
this.resourceId = resourceId;
|
||||||
|
this.body = body;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSubscriptionId() {
|
||||||
|
return subscriptionId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSubscriptionId(final String subscriptionId) {
|
||||||
|
this.subscriptionId = subscriptionId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getTopic() {
|
||||||
|
return topic;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTopic(final String topic) {
|
||||||
|
this.topic = topic;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getResourceId() {
|
||||||
|
return resourceId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setResourceId(final String resourceId) {
|
||||||
|
this.resourceId = resourceId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getBody() {
|
||||||
|
return body;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setBody(final String body) {
|
||||||
|
this.body = body;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,37 @@
|
||||||
|
package eu.dnetlib.enabling.is.sn;
|
||||||
|
|
||||||
|
import javax.xml.ws.wsaddressing.W3CEndpointReference;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instances implementing this interfaces will send notifications to consumers.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* Notifications will be already detected and the message body will be already computed.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* There will be different NotificationSenders, depending on the performance and reliability characteristics required by
|
||||||
|
* the message type.
|
||||||
|
* <p>
|
||||||
|
*
|
||||||
|
* <p>Each notification sender will use a NotificationInvoker to actually forward the notification</p>
|
||||||
|
*
|
||||||
|
* @author marko
|
||||||
|
* @see eu.dnetlib.enabling.is.sn.NotificationInvoker
|
||||||
|
*/
|
||||||
|
public interface NotificationSender {
|
||||||
|
/**
|
||||||
|
* sends a given message according to specific policies.
|
||||||
|
*
|
||||||
|
* @param destination destination EPR
|
||||||
|
* @param message message
|
||||||
|
*/
|
||||||
|
void send(W3CEndpointReference destination, NotificationMessage message);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the notification invoker which will actually perform the notification delivery.
|
||||||
|
*
|
||||||
|
* @param invoker notification invoker
|
||||||
|
*/
|
||||||
|
void setInvoker(NotificationInvoker invoker);
|
||||||
|
}
|
|
@ -0,0 +1,80 @@
|
||||||
|
package eu.dnetlib.enabling.is.sn;
|
||||||
|
|
||||||
|
import javax.xml.xpath.XPathExpressionException;
|
||||||
|
|
||||||
|
import org.apache.commons.logging.Log;
|
||||||
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
import org.w3c.dom.Document;
|
||||||
|
|
||||||
|
import eu.dnetlib.enabling.is.sn.resourcestate.ResourceStateNotificationDetector;
|
||||||
|
import eu.dnetlib.enabling.tools.DOMOpaqueResource;
|
||||||
|
import eu.dnetlib.enabling.tools.OpaqueResource;
|
||||||
|
import eu.dnetlib.xml.database.LoggingTrigger;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This trigger generates notification events for the subscription notification layer.
|
||||||
|
*
|
||||||
|
* @author marko
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class NotificationTriggerImpl extends LoggingTrigger {
|
||||||
|
/**
|
||||||
|
* logger.
|
||||||
|
*/
|
||||||
|
private static final Log log = LogFactory.getLog(NotificationTriggerImpl.class); // NOPMD by marko on 11/24/08 5:02 PM
|
||||||
|
|
||||||
|
/**
|
||||||
|
* notification detector to notify on events.
|
||||||
|
*/
|
||||||
|
private ResourceStateNotificationDetector<OpaqueResource> detector;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
* @see eu.dnetlib.xml.database.LoggingTrigger#created(java.lang.String, java.lang.String, org.w3c.dom.Document)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void created(final String file, final String collection, final Document newDoc) {
|
||||||
|
super.created(file, collection, newDoc);
|
||||||
|
try {
|
||||||
|
getDetector().resourceCreated(new DOMOpaqueResource(newDoc));
|
||||||
|
} catch (XPathExpressionException e) {
|
||||||
|
log.fatal("cannot detect notification because of xpath error; notification possibly missed", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
* @see eu.dnetlib.xml.database.LoggingTrigger#deleted(java.lang.String, java.lang.String, org.w3c.dom.Document)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void deleted(final String file, final String collection, final Document oldDoc) {
|
||||||
|
super.deleted(file, collection, oldDoc);
|
||||||
|
try {
|
||||||
|
getDetector().resourceDeleted(new DOMOpaqueResource(oldDoc));
|
||||||
|
} catch (XPathExpressionException e) {
|
||||||
|
log.fatal("cannot detect notification because of xpath error; notification possibly missed", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
* @see eu.dnetlib.xml.database.LoggingTrigger#updated(java.lang.String, java.lang.String, org.w3c.dom.Document, org.w3c.dom.Document)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void updated(final String file, final String collection, final Document oldDoc, final Document newDoc) {
|
||||||
|
super.updated(file, collection, oldDoc, newDoc);
|
||||||
|
try {
|
||||||
|
getDetector().resourceUpdated(new DOMOpaqueResource(oldDoc), new DOMOpaqueResource(newDoc));
|
||||||
|
} catch (XPathExpressionException e) {
|
||||||
|
log.fatal("cannot detect notification because of xpath error; notification possibly missed", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public ResourceStateNotificationDetector<OpaqueResource> getDetector() {
|
||||||
|
return detector;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDetector(final ResourceStateNotificationDetector<OpaqueResource> detector) {
|
||||||
|
this.detector = detector;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,56 @@
|
||||||
|
package eu.dnetlib.enabling.is.sn;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stores subscriptions.
|
||||||
|
*
|
||||||
|
* @author marko
|
||||||
|
*
|
||||||
|
* @param <T>
|
||||||
|
* subscription type
|
||||||
|
*/
|
||||||
|
public interface SubscriptionDAO<T> {
|
||||||
|
/**
|
||||||
|
* add a new subscription to the subscription store.
|
||||||
|
*
|
||||||
|
* TODO: throw some exception on already existing subscription
|
||||||
|
*
|
||||||
|
* @param subscription
|
||||||
|
* subscription
|
||||||
|
*/
|
||||||
|
void addSubscription(T subscription);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get a particular subscription.
|
||||||
|
*
|
||||||
|
* @param subscriptionId identifier
|
||||||
|
* @return null if none
|
||||||
|
*/
|
||||||
|
T getSubscription(String subscriptionId);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* lists all subscriptions.
|
||||||
|
*
|
||||||
|
* @return all subscriptions
|
||||||
|
*/
|
||||||
|
Collection<T> listSubscriptions();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* lists all subscriptions for a given prefix.
|
||||||
|
*
|
||||||
|
* @param prefix topic expression prefix
|
||||||
|
* @return all matching subscriptions
|
||||||
|
*/
|
||||||
|
Collection<T> listSubscriptions(String prefix);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* removes a particular subscription.
|
||||||
|
*
|
||||||
|
* @param subscriptionId identifier
|
||||||
|
* @return true if successful
|
||||||
|
*/
|
||||||
|
boolean removeSubscription(String subscriptionId);
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,84 @@
|
||||||
|
package eu.dnetlib.enabling.is.sn;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
|
import eu.dnetlib.enabling.is.sn.resourcestate.ResourceStateSubscription;
|
||||||
|
import eu.dnetlib.enabling.is.sn.rmi.SubscriptionRequestRejectedException;
|
||||||
|
import org.springframework.cache.annotation.CacheEvict;
|
||||||
|
import org.springframework.cache.annotation.Cacheable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A subscription registry stores subscriptions.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* Different subscription registries know how to to store different kind of subscriptions. Each registry is specialized
|
||||||
|
* in one type of subscriptions and knows how to quickly find all potentially interesting subscriptions so that a
|
||||||
|
* particular NotificationDetector can do his job the quickest way possible.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* This interface is generic only for subscription purposes because the Subscriber component simply tries to register a
|
||||||
|
* new subscription to all available subscription registries.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* Normally a subscription registry manages only a set of topic expression prefixes, but this interface doesn't force
|
||||||
|
* the Subscriber to know this information; instead the subscription registry itself will decide whether to accept the
|
||||||
|
* subscription or not.
|
||||||
|
* </p>
|
||||||
|
* <p>
|
||||||
|
* Since many subscription registries may accept the same subscription, the identifier is preallocated by the
|
||||||
|
* Subscriber, since the subscription is only one, and even if we give the possibility for several detectors to detect
|
||||||
|
* it from different sources only one event will be generated.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author marko
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public interface SubscriptionRegistry {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* register a subscription.
|
||||||
|
*
|
||||||
|
* @param subscription
|
||||||
|
* subscription request
|
||||||
|
* @return if we can accept this subcription we return the (possibly changed) identifier, otherwise null
|
||||||
|
*/
|
||||||
|
String registerSubscription(SubscriptionRequest subscription) throws SubscriptionRequestRejectedException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unsubscribe a subscription if it exists.
|
||||||
|
*
|
||||||
|
* @param subId subscription identifier
|
||||||
|
* @return true if this subscription existed and was successfully removed
|
||||||
|
*/
|
||||||
|
boolean unsubscribe(final String subId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* return all subscriptions matching a given prefix and a given type. Wildcard subscriptions will match any resource type.
|
||||||
|
*
|
||||||
|
* @param prefix
|
||||||
|
* prefix
|
||||||
|
* @param type
|
||||||
|
* concrete type
|
||||||
|
* @param resId
|
||||||
|
* resource identifier
|
||||||
|
* @return all matching subscriptions
|
||||||
|
*/
|
||||||
|
Collection<ResourceStateSubscription> listMatchingSubscriptions(final String prefix, final String type, final String resId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* return all subscriptions.
|
||||||
|
*
|
||||||
|
* @return all subscriptions
|
||||||
|
*/
|
||||||
|
Collection<ResourceStateSubscription> listSubscriptions();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* removes a particular subscription.
|
||||||
|
*
|
||||||
|
* @param subscriptionId identifier
|
||||||
|
* @return true if successful
|
||||||
|
*/
|
||||||
|
boolean removeSubscription(String subscriptionId);
|
||||||
|
}
|
|
@ -0,0 +1,88 @@
|
||||||
|
package eu.dnetlib.enabling.is.sn;
|
||||||
|
|
||||||
|
import javax.xml.ws.wsaddressing.W3CEndpointReference;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A SubscriptionRequest encapsulates various information about a subscription request.
|
||||||
|
*
|
||||||
|
* @author marko
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class SubscriptionRequest {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* subscriber.
|
||||||
|
*/
|
||||||
|
private W3CEndpointReference subscriber;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* topic expression.
|
||||||
|
*/
|
||||||
|
private String topicExpression;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Preallocated subscription Id. If registries accept the subscription, they will store this in the subscription
|
||||||
|
* identifier.
|
||||||
|
*/
|
||||||
|
private String subscriptionId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* time to live.
|
||||||
|
*/
|
||||||
|
private int ttl;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* default constructor.
|
||||||
|
*/
|
||||||
|
public SubscriptionRequest() {
|
||||||
|
// no operation
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* construct with fields.
|
||||||
|
*
|
||||||
|
* @param subscriptionId subscription id
|
||||||
|
* @param subscriber subscriber
|
||||||
|
* @param topicExpression topic expression
|
||||||
|
* @param ttl time to live
|
||||||
|
*/
|
||||||
|
public SubscriptionRequest(final String subscriptionId, final W3CEndpointReference subscriber, final String topicExpression, final int ttl) {
|
||||||
|
super();
|
||||||
|
this.subscriptionId = subscriptionId;
|
||||||
|
this.subscriber = subscriber;
|
||||||
|
this.topicExpression = topicExpression;
|
||||||
|
this.ttl = ttl;
|
||||||
|
}
|
||||||
|
|
||||||
|
public W3CEndpointReference getSubscriber() {
|
||||||
|
return subscriber;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSubscriber(final W3CEndpointReference subscriber) {
|
||||||
|
this.subscriber = subscriber;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getTopicExpression() {
|
||||||
|
return topicExpression;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTopicExpression(final String topicExpression) {
|
||||||
|
this.topicExpression = topicExpression;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSubscriptionId() {
|
||||||
|
return subscriptionId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSubscriptionId(final String subscriptionId) {
|
||||||
|
this.subscriptionId = subscriptionId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getTtl() {
|
||||||
|
return ttl;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTtl(final int ttl) {
|
||||||
|
this.ttl = ttl;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,40 @@
|
||||||
|
package eu.dnetlib.enabling.is.sn;
|
||||||
|
|
||||||
|
import javax.xml.ws.wsaddressing.W3CEndpointReference;
|
||||||
|
|
||||||
|
import org.apache.commons.logging.Log;
|
||||||
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This implementation of NotificationSender simply sends notification synchronously.
|
||||||
|
*
|
||||||
|
* NOTE: this is only for testing. Real-wold cases should use AsynchrnonousNotificationSender, because we have to
|
||||||
|
* get out the thread serving eXist queries.
|
||||||
|
*
|
||||||
|
* @author marko
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class SynchronousNotificationSenderImpl extends AbstractNotificationSender {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* logger.
|
||||||
|
*/
|
||||||
|
private static final Log log = LogFactory.getLog(SynchronousNotificationSenderImpl.class); // NOPMD by marko on 11/24/08 5:02 PM
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*
|
||||||
|
* @see eu.dnetlib.enabling.is.sn.NotificationSender#send(javax.xml.ws.wsaddressing.W3CEndpointReference,
|
||||||
|
* eu.dnetlib.enabling.is.sn.NotificationMessage)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void send(final W3CEndpointReference destination, final NotificationMessage message) {
|
||||||
|
log.info("synchronously sending message " + message.getSubscriptionId() + ", " + message.getTopic() + ", " + message.getResourceId() + ", "
|
||||||
|
+ message.getBody());
|
||||||
|
try {
|
||||||
|
getInvoker().send(destination, message, 0);
|
||||||
|
} catch (javax.xml.ws.soap.SOAPFaultException t) {
|
||||||
|
log.fatal("error sending notification to " + destination.toString(), t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,40 @@
|
||||||
|
package eu.dnetlib.enabling.is.sn;
|
||||||
|
|
||||||
|
import org.apache.commons.logging.Log;
|
||||||
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
|
||||||
|
import eu.dnetlib.enabling.is.sn.rmi.ISSNException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* As a complementary approach w.r.t unit tests, this class is an extension of
|
||||||
|
* the default ISSN Service which creates a number of initial subscriptions so that we can play
|
||||||
|
* with some notifications.
|
||||||
|
*
|
||||||
|
* This class plays well with TestISStoreServiceImpl, which creates some profiles at startup time
|
||||||
|
* and schedules some automated mutations.
|
||||||
|
*
|
||||||
|
* @author marko
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class TestISSNServiceImpl extends ISSNServiceImpl {
|
||||||
|
/**
|
||||||
|
* logger.
|
||||||
|
*/
|
||||||
|
private static final Log log = LogFactory.getLog(TestISSNServiceImpl.class); // NOPMD by marko on 11/24/08 5:02 PM
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
* @see eu.dnetlib.enabling.tools.AbstractBaseService#start()
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void start() {
|
||||||
|
super.start();
|
||||||
|
|
||||||
|
try {
|
||||||
|
subscribe(getEprBuilder().getEndpointReference(getEndpoint()), "CREATE/TestResourceType/*", 0);
|
||||||
|
} catch (ISSNException e) {
|
||||||
|
log.fatal("cannot subscribe test subscriptions", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,46 @@
|
||||||
|
package eu.dnetlib.enabling.is.sn;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Groups a topic expression prefix match result.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* Utility class.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author marko
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class TopicExpressionMatchResult {
|
||||||
|
/**
|
||||||
|
* Topic expression prefix.
|
||||||
|
*/
|
||||||
|
private final transient String prefix;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* RestOf the topic expression.
|
||||||
|
*/
|
||||||
|
private final transient String rest;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* construct a new topic expression prefix match result.
|
||||||
|
* @param prefix
|
||||||
|
* prefix
|
||||||
|
* @param rest
|
||||||
|
* rest
|
||||||
|
*/
|
||||||
|
public TopicExpressionMatchResult(final String prefix, final String rest) {
|
||||||
|
super();
|
||||||
|
this.prefix = prefix;
|
||||||
|
this.rest = rest;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPrefix() {
|
||||||
|
return prefix;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getRest() {
|
||||||
|
return rest;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,83 @@
|
||||||
|
package eu.dnetlib.enabling.is.sn.resourcestate;
|
||||||
|
|
||||||
|
import eu.dnetlib.enabling.is.sn.NotificationSender;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* sits on top of a ResourceStateNotificationDetector and filters out resources for which we don't want to generate
|
||||||
|
* notifications.
|
||||||
|
*
|
||||||
|
* @author marko
|
||||||
|
*
|
||||||
|
* @param <T>
|
||||||
|
* type of the resource object
|
||||||
|
*/
|
||||||
|
public abstract class AbstractResourceStateNotificationDetectorFilter<T> implements ResourceStateNotificationDetector<T> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* delegate.
|
||||||
|
*/
|
||||||
|
private ResourceStateNotificationDetector<T> delegate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* implement this in order to decide which resources are interesting for notifications, and which are not (for
|
||||||
|
* example pending resources are by ignored in dnet 1.0).
|
||||||
|
*
|
||||||
|
* @param resource
|
||||||
|
* resource
|
||||||
|
* @return true if the resource is potentially accepted for notification
|
||||||
|
*/
|
||||||
|
abstract boolean accept(T resource);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*
|
||||||
|
* @see eu.dnetlib.enabling.is.sn.resourcestate.ResourceStateNotificationDetector#resourceCreated(java.lang.Object)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void resourceCreated(final T newResource) {
|
||||||
|
if (accept(newResource))
|
||||||
|
delegate.resourceCreated(newResource);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*
|
||||||
|
* @see eu.dnetlib.enabling.is.sn.resourcestate.ResourceStateNotificationDetector#resourceDeleted(java.lang.Object)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void resourceDeleted(final T oldResource) {
|
||||||
|
if (accept(oldResource))
|
||||||
|
delegate.resourceDeleted(oldResource);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*
|
||||||
|
* @see eu.dnetlib.enabling.is.sn.resourcestate.ResourceStateNotificationDetector#resourceUpdated(java.lang.Object,
|
||||||
|
* java.lang.Object)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void resourceUpdated(final T oldResource, final T newResource) {
|
||||||
|
if (accept(oldResource) || accept(newResource))
|
||||||
|
delegate.resourceUpdated(oldResource, newResource);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*
|
||||||
|
* @see eu.dnetlib.enabling.is.sn.NotificationDetector#setSender(eu.dnetlib.enabling.is.sn.NotificationSender)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void setSender(final NotificationSender sender) {
|
||||||
|
delegate.setSender(sender);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ResourceStateNotificationDetector<T> getDelegate() {
|
||||||
|
return delegate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDelegate(final ResourceStateNotificationDetector<T> delegate) {
|
||||||
|
this.delegate = delegate;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,39 @@
|
||||||
|
package eu.dnetlib.enabling.is.sn.resourcestate;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Required;
|
||||||
|
|
||||||
|
import eu.dnetlib.enabling.tools.OpaqueResource;
|
||||||
|
import eu.dnetlib.miscutils.coupling.ExternalCondition;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ignores pending profiles from notification detection.
|
||||||
|
*
|
||||||
|
* @author marko
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class ConditionalResourceStateNotificationDetectorFilter extends AbstractResourceStateNotificationDetectorFilter<OpaqueResource> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* external condition that drives this filter. We accept notification while the external condition is false.
|
||||||
|
*/
|
||||||
|
private ExternalCondition inhibitionCondition; // NOPMD
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
* @see eu.dnetlib.enabling.is.sn.resourcestate.AbstractResourceStateNotificationDetectorFilter#accept(java.lang.Object)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
boolean accept(final OpaqueResource resource) {
|
||||||
|
return !inhibitionCondition.isTrue();
|
||||||
|
}
|
||||||
|
|
||||||
|
public ExternalCondition getInhibitionCondition() {
|
||||||
|
return inhibitionCondition;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Required
|
||||||
|
public void setInhibitionCondition(final ExternalCondition inhibitionCondition) { // NOPMD
|
||||||
|
this.inhibitionCondition = inhibitionCondition;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,132 @@
|
||||||
|
package eu.dnetlib.enabling.is.sn.resourcestate;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* dummy implementation of the resource state subscription DAO layer, using an in-memory map.
|
||||||
|
*
|
||||||
|
* @author marko
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class MemoryResourceStateSubscriptionDAOImpl implements ResourceStateSubscriptionDAO {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* by id.
|
||||||
|
*/
|
||||||
|
private Map<String, ResourceStateSubscription> byId = new HashMap<String, ResourceStateSubscription>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* groups subscriptions with the same prefix and type.
|
||||||
|
*/
|
||||||
|
private Map<String, Collection<ResourceStateSubscription>> byPrefixAndType = new HashMap<String, Collection<ResourceStateSubscription>>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*
|
||||||
|
* @see eu.dnetlib.enabling.is.sn.resourcestate.ResourceStateSubscriptionDAO#listSubscriptions(java.lang.String,
|
||||||
|
* java.lang.String, java.lang.String)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public Collection<ResourceStateSubscription> listSubscriptions(final String prefix, final String resourceType, final String resourceId) {
|
||||||
|
return orDefault(getByPrefixAndType().get(prefix + "/" + resourceType + "/" + resourceId));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*
|
||||||
|
* @see eu.dnetlib.enabling.is.sn.SubscriptionDAO#addSubscription(java.lang.Object)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void addSubscription(final ResourceStateSubscription subscription) {
|
||||||
|
getById().put(subscription.getSubscriptionId(), subscription);
|
||||||
|
|
||||||
|
final String key = subscription.getPrefix() + "/" + subscription.getType() + "/" + subscription.getResourceId();
|
||||||
|
final Collection<ResourceStateSubscription> prefTypeList = getByPrefixAndType().get(key);
|
||||||
|
if (prefTypeList == null)
|
||||||
|
getByPrefixAndType().put(key, new ArrayList<ResourceStateSubscription>());
|
||||||
|
getByPrefixAndType().get(key).add(subscription);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*
|
||||||
|
* @see eu.dnetlib.enabling.is.sn.SubscriptionDAO#getSubscription(java.lang.String)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public ResourceStateSubscription getSubscription(final String subscriptionId) {
|
||||||
|
return getById().get(subscriptionId);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*
|
||||||
|
* @see eu.dnetlib.enabling.is.sn.SubscriptionDAO#listSubscriptions()
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public Collection<ResourceStateSubscription> listSubscriptions() {
|
||||||
|
return orDefault(getById().values());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*
|
||||||
|
* @see eu.dnetlib.enabling.is.sn.SubscriptionDAO#listSubscriptions(java.lang.String)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public Collection<ResourceStateSubscription> listSubscriptions(final String prefix) {
|
||||||
|
return listSubscriptions(prefix, "*", "*");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*
|
||||||
|
* @see eu.dnetlib.enabling.is.sn.SubscriptionDAO#removeSubscription(java.lang.String)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean removeSubscription(final String subscriptionId) {
|
||||||
|
final ResourceStateSubscription subscription = getSubscription(subscriptionId);
|
||||||
|
if (subscription == null)
|
||||||
|
return false;
|
||||||
|
final String key = subscription.getPrefix() + "/" + subscription.getType() + "/" + subscription.getResourceId();
|
||||||
|
|
||||||
|
final Collection<ResourceStateSubscription> prefTypeList = getByPrefixAndType().get(key);
|
||||||
|
prefTypeList.remove(subscription);
|
||||||
|
|
||||||
|
getById().remove(subscriptionId);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* inner helper method. returns an empty collection instead of a null.
|
||||||
|
*
|
||||||
|
* @param collection
|
||||||
|
* some collection
|
||||||
|
* @return input collection or empty collection
|
||||||
|
*/
|
||||||
|
private Collection<ResourceStateSubscription> orDefault(final Collection<ResourceStateSubscription> collection) {
|
||||||
|
if (collection == null)
|
||||||
|
return new ArrayList<ResourceStateSubscription>();
|
||||||
|
return collection;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<String, ResourceStateSubscription> getById() {
|
||||||
|
return byId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setById(final Map<String, ResourceStateSubscription> byId) {
|
||||||
|
this.byId = byId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<String, Collection<ResourceStateSubscription>> getByPrefixAndType() {
|
||||||
|
return byPrefixAndType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setByPrefixAndType(final Map<String, Collection<ResourceStateSubscription>> byPrefixAndType) {
|
||||||
|
this.byPrefixAndType = byPrefixAndType;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,24 @@
|
||||||
|
package eu.dnetlib.enabling.is.sn.resourcestate;
|
||||||
|
|
||||||
|
import eu.dnetlib.enabling.tools.OpaqueResource;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ignores pending profiles from notification detection.
|
||||||
|
*
|
||||||
|
* @author marko
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class PendingResourceStateNotificationDetectorFilter extends AbstractResourceStateNotificationDetectorFilter<OpaqueResource> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
* @see eu.dnetlib.enabling.is.sn.resourcestate.AbstractResourceStateNotificationDetectorFilter#accept(java.lang.Object)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
boolean accept(final OpaqueResource resource) {
|
||||||
|
if (resource.getResourceKind().startsWith("Pending"))
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,39 @@
|
||||||
|
package eu.dnetlib.enabling.is.sn.resourcestate;
|
||||||
|
|
||||||
|
import eu.dnetlib.enabling.is.sn.NotificationDetector;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implementors detect topic assertions by sensing changes in resource state.
|
||||||
|
*
|
||||||
|
* @author marko
|
||||||
|
* @param <T>
|
||||||
|
* type of resource
|
||||||
|
*/
|
||||||
|
public interface ResourceStateNotificationDetector<T> extends NotificationDetector {
|
||||||
|
/**
|
||||||
|
* called when a new resource is created.
|
||||||
|
*
|
||||||
|
* @param newResource
|
||||||
|
* new resource
|
||||||
|
*/
|
||||||
|
void resourceCreated(T newResource);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* called when a resource is modified.
|
||||||
|
*
|
||||||
|
* @param oldResource
|
||||||
|
* old resource
|
||||||
|
* @param newResource
|
||||||
|
* new resource
|
||||||
|
*/
|
||||||
|
void resourceUpdated(T oldResource, T newResource);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* called when a resource is deleted.
|
||||||
|
*
|
||||||
|
* @param oldResource
|
||||||
|
* old resource
|
||||||
|
*/
|
||||||
|
void resourceDeleted(T oldResource);
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,225 @@
|
||||||
|
package eu.dnetlib.enabling.is.sn.resourcestate;
|
||||||
|
|
||||||
|
import java.io.StringReader;
|
||||||
|
import javax.persistence.Column;
|
||||||
|
import javax.persistence.Entity;
|
||||||
|
import javax.persistence.Id;
|
||||||
|
import javax.persistence.Table;
|
||||||
|
import javax.xml.transform.stream.StreamSource;
|
||||||
|
import javax.xml.ws.EndpointReference;
|
||||||
|
import javax.xml.ws.wsaddressing.W3CEndpointReference;
|
||||||
|
|
||||||
|
import eu.dnetlib.enabling.is.sn.SubscriptionRequest;
|
||||||
|
import org.apache.commons.lang3.builder.EqualsBuilder;
|
||||||
|
import org.apache.commons.lang3.builder.HashCodeBuilder;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class describes a ResourceState subscription, i.e. a subscription that is registered on a topic that depends on
|
||||||
|
* some xpath on some resource, and which is triggered when the value of this xpath changes.
|
||||||
|
*
|
||||||
|
* Topics of this type could not be there.
|
||||||
|
*
|
||||||
|
* @author marko
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@Entity(name = "subscriptions")
|
||||||
|
@Table(name = "subscriptions")
|
||||||
|
public class ResourceStateSubscription {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* hash seed.
|
||||||
|
*/
|
||||||
|
private static final int HASH_SEED_2 = 59;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* hash seed.
|
||||||
|
*/
|
||||||
|
private static final int HASH_SEED = 47;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* create topic prefix.
|
||||||
|
*/
|
||||||
|
public static final String PREFIX_CREATE = "CREATE";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* delete topic prefix.
|
||||||
|
*/
|
||||||
|
public static final String PREFIX_DELETE = "DELETE";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* update topic prefix.
|
||||||
|
*/
|
||||||
|
public static final String PREFIX_UPDATE = "UPDATE";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* pending create topic prefix.
|
||||||
|
*/
|
||||||
|
public static final String PREFIX_PENDING_CREATE = "PENDING_CREATE";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* pending delete topic prefix.
|
||||||
|
*/
|
||||||
|
public static final String PREFIX_PENDING_DELETE = "PENDING_DELETE";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* pending update topic prefix.
|
||||||
|
*/
|
||||||
|
public static final String PREFIX_PENDING_UPDATE = "PENDING_UPDATE";
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* subscription identifier.
|
||||||
|
*/
|
||||||
|
@Id
|
||||||
|
@Column(name = "subscriptionid")
|
||||||
|
private String subscriptionId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* prefix: crude.
|
||||||
|
*/
|
||||||
|
@Column(name = "prefix")
|
||||||
|
private String prefix;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* resource type.
|
||||||
|
*/
|
||||||
|
@Column(name = "type")
|
||||||
|
private String type;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* resource id.
|
||||||
|
*/
|
||||||
|
@Column(name = "resourceid")
|
||||||
|
private String resourceId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* xpath.
|
||||||
|
*/
|
||||||
|
@Column(name = "xpath")
|
||||||
|
private String xpath;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* consumer (subscriber) reference.
|
||||||
|
*/
|
||||||
|
@Column(name = "subscriber", length = 4096)
|
||||||
|
private String subscriber;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* default constructor. for unit testing.
|
||||||
|
*/
|
||||||
|
public ResourceStateSubscription() {
|
||||||
|
this.type = "*";
|
||||||
|
this.resourceId = "*";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* create a new instance.
|
||||||
|
*
|
||||||
|
* @param request
|
||||||
|
* original request.
|
||||||
|
* @param prefix
|
||||||
|
* prefix
|
||||||
|
* @param type
|
||||||
|
* resource type
|
||||||
|
* @param resourceId
|
||||||
|
* resource identifier
|
||||||
|
* @param xpath
|
||||||
|
* xpath
|
||||||
|
*/
|
||||||
|
public ResourceStateSubscription(final SubscriptionRequest request, final String prefix, final String type, final String resourceId,
|
||||||
|
final String xpath) {
|
||||||
|
super();
|
||||||
|
setSubscriptionId(request.getSubscriptionId());
|
||||||
|
setSubscriber(request.getSubscriber());
|
||||||
|
setPrefix(prefix);
|
||||||
|
setType(type);
|
||||||
|
setResourceId(resourceId);
|
||||||
|
setXpath(xpath);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*
|
||||||
|
* @see java.lang.Object#hashCode()
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return new HashCodeBuilder(HASH_SEED, HASH_SEED_2).append(subscriptionId).append(subscriber.toString()).append(prefix).append(type).append(xpath)
|
||||||
|
.toHashCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*
|
||||||
|
* @see java.lang.Object#equals(java.lang.Object)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean equals(final Object obj) {
|
||||||
|
if (!(obj instanceof ResourceStateSubscription))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (this == obj)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
final ResourceStateSubscription rhs = (ResourceStateSubscription) obj;
|
||||||
|
return new EqualsBuilder().append(subscriptionId, rhs.getSubscriptionId()).append(prefix, rhs.getPrefix()).append(
|
||||||
|
resourceId, rhs.getResourceId()).append(xpath, rhs.getXpath()).isEquals();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSubscriptionId() {
|
||||||
|
return subscriptionId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSubscriptionId(final String subscriptionId) {
|
||||||
|
this.subscriptionId = subscriptionId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPrefix() {
|
||||||
|
return prefix;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPrefix(final String prefix) {
|
||||||
|
this.prefix = prefix;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getType() {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setType(final String type) {
|
||||||
|
this.type = type == null || type.isEmpty() ? "*" : type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getXpath() {
|
||||||
|
return xpath;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setXpath(final String xpath) {
|
||||||
|
this.xpath = xpath;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSubscriber() {
|
||||||
|
return subscriber;
|
||||||
|
}
|
||||||
|
|
||||||
|
public W3CEndpointReference getSubscriberAsEpr() {
|
||||||
|
return (W3CEndpointReference) EndpointReference.readFrom(new StreamSource(new StringReader(getSubscriber())));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSubscriber(final W3CEndpointReference epr) {
|
||||||
|
this.subscriber = (epr != null) ? epr.toString() : null;;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSubscriber(final String subscriber) {
|
||||||
|
this.subscriber = subscriber;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setResourceId(final String resourceId) {
|
||||||
|
this.resourceId = resourceId == null || resourceId.isEmpty() ? "*" : resourceId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getResourceId() {
|
||||||
|
return resourceId;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,24 @@
|
||||||
|
package eu.dnetlib.enabling.is.sn.resourcestate;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
|
import eu.dnetlib.enabling.is.sn.SubscriptionDAO;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stores ResourceState subscriptions.
|
||||||
|
*
|
||||||
|
* @author marko
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public interface ResourceStateSubscriptionDAO extends SubscriptionDAO<ResourceStateSubscription> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get all subscriptions matching a given prefix and a given resource type.
|
||||||
|
*
|
||||||
|
* @param prefix null means any prefix
|
||||||
|
* @param resourceType resource type.
|
||||||
|
* @param resourceId resource identifier
|
||||||
|
* @return matching subscriptions
|
||||||
|
*/
|
||||||
|
Collection<ResourceStateSubscription> listSubscriptions(String prefix, String resourceType, String resourceId);
|
||||||
|
}
|
|
@ -0,0 +1,233 @@
|
||||||
|
package eu.dnetlib.enabling.is.sn.resourcestate;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import javax.xml.transform.dom.DOMResult;
|
||||||
|
import javax.xml.ws.wsaddressing.W3CEndpointReference;
|
||||||
|
import javax.xml.xpath.XPathExpressionException;
|
||||||
|
import javax.xml.xpath.XPathFactory;
|
||||||
|
|
||||||
|
import com.google.common.collect.Sets;
|
||||||
|
import org.apache.commons.logging.Log;
|
||||||
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
import org.apache.oro.text.perl.Perl5Util;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.beans.factory.annotation.Required;
|
||||||
|
|
||||||
|
import eu.dnetlib.enabling.is.sn.AbstractSubscriptionRegistry;
|
||||||
|
import eu.dnetlib.enabling.is.sn.SubscriptionRegistry;
|
||||||
|
import eu.dnetlib.enabling.is.sn.SubscriptionRequest;
|
||||||
|
import eu.dnetlib.enabling.is.sn.TopicExpressionMatchResult;
|
||||||
|
import eu.dnetlib.enabling.is.sn.rmi.SubscriptionRequestRejectedException;
|
||||||
|
import org.springframework.cache.annotation.CacheEvict;
|
||||||
|
import org.springframework.cache.annotation.Cacheable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Manage subscription for UPDATE/CREATE/DELETE resource-related topic prefixes.
|
||||||
|
*
|
||||||
|
* @author marko
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class ResourceStateSubscriptionRegistry extends AbstractSubscriptionRegistry implements SubscriptionRegistry {
|
||||||
|
|
||||||
|
private static final Log log = LogFactory.getLog(ResourceStateSubscriptionRegistry.class);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* subscription DAO.
|
||||||
|
*/
|
||||||
|
private ResourceStateSubscriptionDAO subscriptionDao;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* subscription request filter.
|
||||||
|
*/
|
||||||
|
@Autowired
|
||||||
|
private SubscriptionRequestFilter subscriptionRequestFilter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*
|
||||||
|
* @see eu.dnetlib.enabling.is.sn.SubscriptionRegistry#registerSubscription(eu.dnetlib.enabling.is.sn.SubscriptionRequest)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
@CacheEvict(value = "subscriptions", allEntries = true)
|
||||||
|
public String registerSubscription(final SubscriptionRequest subscription) throws SubscriptionRequestRejectedException {
|
||||||
|
final TopicExpressionMatchResult prefixMatch = matchPrefix(subscription);
|
||||||
|
if (prefixMatch == null)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
final TopicExpressionMatchResult typeMatch = matchType(prefixMatch.getRest());
|
||||||
|
if (typeMatch == null)
|
||||||
|
return null; // TODO: decide whether to fail or not
|
||||||
|
|
||||||
|
final TopicExpressionMatchResult idMatch = matchId(typeMatch.getRest());
|
||||||
|
|
||||||
|
if (idMatch == null)
|
||||||
|
return null; // TODO: decide whether to fail or not
|
||||||
|
|
||||||
|
final ResourceStateSubscription rss = new ResourceStateSubscription(subscription, prefixMatch.getPrefix(), typeMatch.getPrefix(), idMatch.getPrefix(),
|
||||||
|
idMatch.getRest());
|
||||||
|
|
||||||
|
if (!getSubscriptionRequestFilter().accept(rss))
|
||||||
|
throw new SubscriptionRequestRejectedException(String.format("rejected subscription request, resourceId: '%s', xpath: '%s', from: %s",
|
||||||
|
rss.getResourceId(), rss.getXpath(), rss.getSubscriber()));
|
||||||
|
|
||||||
|
return registerSubscription(rss);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* this registers the real subscription.
|
||||||
|
*
|
||||||
|
* TODO: am I sure that the overload is a good thing here?
|
||||||
|
*
|
||||||
|
* @param subscription
|
||||||
|
* subscription
|
||||||
|
* @return subscription id (potentially changed)
|
||||||
|
*/
|
||||||
|
private String registerSubscription(final ResourceStateSubscription subscription) {
|
||||||
|
if(log.isDebugEnabled()) {
|
||||||
|
log.debug("evict subscriptions cache");
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: change the dao, and implement a method which finds a given subscription directly.
|
||||||
|
final Collection<ResourceStateSubscription> similar = subscriptionDao.listSubscriptions(subscription.getPrefix(), subscription.getType(),
|
||||||
|
subscription.getResourceId());
|
||||||
|
for (final ResourceStateSubscription r : similar) {
|
||||||
|
if (r != null && getAddress(subscription.getSubscriberAsEpr()).equals(getAddress(r.getSubscriberAsEpr()))
|
||||||
|
&& (subscription.getXpath() == r.getXpath() || subscription.getXpath().equals(r.getXpath()))
|
||||||
|
&& (subscription.getResourceId() == r.getResourceId() || subscription.getResourceId().equals(r.getResourceId())))
|
||||||
|
return r.getSubscriptionId();
|
||||||
|
}
|
||||||
|
|
||||||
|
subscriptionDao.addSubscription(subscription);
|
||||||
|
|
||||||
|
return subscription.getSubscriptionId();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*
|
||||||
|
* @see eu.dnetlib.enabling.is.sn.SubscriptionRegistry#unsubscribe(java.lang.String)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
@CacheEvict(value = "subscriptions", allEntries = true)
|
||||||
|
public boolean unsubscribe(final String subId) {
|
||||||
|
log.info("evict subscriptions cache");
|
||||||
|
return subscriptionDao.removeSubscription(subId);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obtains the address component of the EPR.
|
||||||
|
*
|
||||||
|
* TODO: refactor in a utility class.
|
||||||
|
*
|
||||||
|
* @param epr
|
||||||
|
* endpoint reference
|
||||||
|
* @return address contained in the endpoint reference
|
||||||
|
*/
|
||||||
|
private Object getAddress(final W3CEndpointReference epr) {
|
||||||
|
final DOMResult dom = new DOMResult();
|
||||||
|
epr.writeTo(dom);
|
||||||
|
|
||||||
|
try {
|
||||||
|
return XPathFactory.newInstance().newXPath().evaluate("//*[local-name() = 'Address']", dom.getNode());
|
||||||
|
} catch (final XPathExpressionException e) {
|
||||||
|
throw new IllegalStateException("cannot construct xpath expression", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* extract resource type name.
|
||||||
|
*
|
||||||
|
* @param rest
|
||||||
|
* topic expression without prefix
|
||||||
|
* @return tuple containing type name and rest of the prefix
|
||||||
|
*/
|
||||||
|
public TopicExpressionMatchResult matchType(final String rest) {
|
||||||
|
final Perl5Util matcher = new Perl5Util(); // NOPMD
|
||||||
|
if (!matcher.match("/^(\\*|[a-zA-Z_0-9]*)($|/)(.*)$/", rest))
|
||||||
|
return null;
|
||||||
|
|
||||||
|
return new TopicExpressionMatchResult(matcher.getMatch().group(1), matcher.getMatch().group(2 + 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* extract resource id.
|
||||||
|
*
|
||||||
|
* @param rest
|
||||||
|
* topic expression without prefix
|
||||||
|
* @return tuple containing type name and rest of the prefix
|
||||||
|
*/
|
||||||
|
public TopicExpressionMatchResult matchId(final String rest) {
|
||||||
|
final Perl5Util matcher = new Perl5Util(); // NOPMD
|
||||||
|
if (!matcher.match("/^([^/]*)(.*)/", rest))
|
||||||
|
return null;
|
||||||
|
|
||||||
|
return new TopicExpressionMatchResult(matcher.getMatch().group(1), matcher.getMatch().group(2));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* return all subscriptions matching a given prefix and a given type. Wildcard subscriptions will match any resource type.
|
||||||
|
*
|
||||||
|
* @param prefix
|
||||||
|
* prefix
|
||||||
|
* @param type
|
||||||
|
* concrete type
|
||||||
|
* @param resId
|
||||||
|
* resource identifier
|
||||||
|
* @return all matching subscriptions
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
@Cacheable(value="subscriptions", key="{ #prefix, #type, #resId }")
|
||||||
|
public Collection<ResourceStateSubscription> listMatchingSubscriptions(final String prefix, final String type, final String resId) {
|
||||||
|
|
||||||
|
if(log.isDebugEnabled()) {
|
||||||
|
log.debug(String.format("uncached list subscriptions [prefix: '%s', type: '%s', resourceId: '%s']", prefix, type, resId));
|
||||||
|
}
|
||||||
|
final Set<ResourceStateSubscription> merged = new HashSet<ResourceStateSubscription>();
|
||||||
|
merged.addAll(subscriptionDao.listSubscriptions(prefix, type, resId));
|
||||||
|
merged.addAll(subscriptionDao.listSubscriptions(prefix, type, "*"));
|
||||||
|
merged.addAll(subscriptionDao.listSubscriptions(prefix, "*", "*"));
|
||||||
|
return merged;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Cacheable(value="subscriptions")
|
||||||
|
public Collection<ResourceStateSubscription> listSubscriptions() {
|
||||||
|
log.info("uncached list subscriptions");
|
||||||
|
|
||||||
|
return Sets.newHashSet(subscriptionDao.listSubscriptions());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@CacheEvict(value = "subscriptions", allEntries = true)
|
||||||
|
public boolean removeSubscription(final String subscriptionId) {
|
||||||
|
return subscriptionDao.removeSubscription(subscriptionId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Collection<String> getAcceptedPrefixes() {
|
||||||
|
return Arrays.asList(new String[] { ResourceStateSubscription.PREFIX_CREATE, ResourceStateSubscription.PREFIX_DELETE,
|
||||||
|
ResourceStateSubscription.PREFIX_UPDATE });
|
||||||
|
}
|
||||||
|
|
||||||
|
public ResourceStateSubscriptionDAO getSubscriptionDao() {
|
||||||
|
return subscriptionDao;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Required
|
||||||
|
public void setSubscriptionDao(final ResourceStateSubscriptionDAO subscriptionDao) {
|
||||||
|
this.subscriptionDao = subscriptionDao;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SubscriptionRequestFilter getSubscriptionRequestFilter() {
|
||||||
|
return subscriptionRequestFilter;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSubscriptionRequestFilter(final SubscriptionRequestFilter subscriptionRequestFilter) {
|
||||||
|
this.subscriptionRequestFilter = subscriptionRequestFilter;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,43 @@
|
||||||
|
package eu.dnetlib.enabling.is.sn.resourcestate;
|
||||||
|
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.apache.commons.logging.Log;
|
||||||
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
|
||||||
|
public class SubscriptionRequestFilter {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* logger.
|
||||||
|
*/
|
||||||
|
private static final Log log = LogFactory.getLog(SubscriptionRequestFilter.class); // NOPMD by marko on 11/24/08 5:02 PM
|
||||||
|
|
||||||
|
/**
|
||||||
|
* resource wildcard
|
||||||
|
*/
|
||||||
|
private static final String ANY_RESOURCE = "*";
|
||||||
|
|
||||||
|
@Value("${services.issn.subscription.filter.active}")
|
||||||
|
private boolean active = false;
|
||||||
|
|
||||||
|
public boolean accept(final ResourceStateSubscription rss) {
|
||||||
|
|
||||||
|
if (!isActive()) return true;
|
||||||
|
|
||||||
|
if (StringUtils.isBlank(rss.getXpath()) & StringUtils.equals(rss.getResourceId(), ANY_RESOURCE)) {
|
||||||
|
log.debug(String.format("rejected subscription request, resourceId: '%s', xpath: '%s', from: %s", rss.getResourceId(), rss.getXpath(),
|
||||||
|
rss.getSubscriber()));
|
||||||
|
return false; // we reject wide subscriptions
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isActive() {
|
||||||
|
return active;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setActive(boolean active) {
|
||||||
|
this.active = active;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,151 @@
|
||||||
|
package eu.dnetlib.enabling.is.sn.resourcestate.hib;
|
||||||
|
|
||||||
|
import static java.sql.Types.VARCHAR;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.io.StringReader;
|
||||||
|
import java.io.StringWriter;
|
||||||
|
import java.sql.PreparedStatement;
|
||||||
|
import java.sql.ResultSet;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
|
||||||
|
import javax.xml.transform.stream.StreamResult;
|
||||||
|
import javax.xml.transform.stream.StreamSource;
|
||||||
|
import javax.xml.ws.EndpointReference;
|
||||||
|
import javax.xml.ws.wsaddressing.W3CEndpointReference;
|
||||||
|
|
||||||
|
import org.hibernate.HibernateException;
|
||||||
|
import org.hibernate.engine.spi.SessionImplementor;
|
||||||
|
import org.hibernate.usertype.UserType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Serializes Endpoint reference types to database columns (strings).
|
||||||
|
*
|
||||||
|
* @author marko
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class EndpointReferenceType implements UserType { // NOPMD
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*
|
||||||
|
* @see org.hibernate.usertype.UserType#assemble(java.io.Serializable, java.lang.Object)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public Object assemble(final Serializable arg0, final Object owner) {
|
||||||
|
if (arg0 == null) return null;
|
||||||
|
return EndpointReference.readFrom(new StreamSource(new StringReader((String) arg0)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*
|
||||||
|
* @see org.hibernate.usertype.UserType#deepCopy(java.lang.Object)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public Object deepCopy(final Object arg0) {
|
||||||
|
if (arg0 == null) return null;
|
||||||
|
|
||||||
|
return arg0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*
|
||||||
|
* @see org.hibernate.usertype.UserType#disassemble(java.lang.Object)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public Serializable disassemble(final Object arg0) {
|
||||||
|
final StringWriter buffer = new StringWriter();
|
||||||
|
((W3CEndpointReference) arg0).writeTo(new StreamResult(buffer));
|
||||||
|
return buffer.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*
|
||||||
|
* @see org.hibernate.usertype.UserType#equals(java.lang.Object, java.lang.Object)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean equals(final Object arg0, final Object arg1) {
|
||||||
|
if (arg0 == arg1) // NOPMD
|
||||||
|
return true;
|
||||||
|
if ((arg0 == null) || (arg1 == null)) return false;
|
||||||
|
return arg0.equals(arg1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*
|
||||||
|
* @see org.hibernate.usertype.UserType#hashCode(java.lang.Object)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public int hashCode(final Object arg0) {
|
||||||
|
return disassemble(arg0).hashCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isMutable() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* {@inheritDoc}
|
||||||
|
*
|
||||||
|
* @see org.hibernate.usertype.UserType#nullSafeGet(java.sql.ResultSet, java.lang.String[], org.hibernate.engine.spi.SessionImplementor,
|
||||||
|
* java.lang.Object)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public Object nullSafeGet(final ResultSet rset, final String[] names, final SessionImplementor si, final Object owner) throws SQLException {
|
||||||
|
return assemble(rset.getString(names[0]), owner);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*
|
||||||
|
* @see org.hibernate.usertype.UserType#nullSafeSet(java.sql.PreparedStatement, java.lang.Object, int,
|
||||||
|
* org.hibernate.engine.spi.SessionImplementor)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void nullSafeSet(final PreparedStatement statement, final Object epr, final int index, final SessionImplementor arg3) throws HibernateException,
|
||||||
|
SQLException {
|
||||||
|
if (epr != null) {
|
||||||
|
statement.setString(index, (String) disassemble(epr));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*
|
||||||
|
* @see org.hibernate.usertype.UserType#replace(java.lang.Object, java.lang.Object, java.lang.Object)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public Object replace(final Object arg0, final Object arg1, final Object arg2) {
|
||||||
|
// is not mutable
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*
|
||||||
|
* @see org.hibernate.usertype.UserType#returnedClass()
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
@SuppressWarnings("rawtypes")
|
||||||
|
public Class returnedClass() {
|
||||||
|
return W3CEndpointReference.class;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*
|
||||||
|
* @see org.hibernate.usertype.UserType#sqlTypes()
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public int[] sqlTypes() {
|
||||||
|
return new int[] { VARCHAR };
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,137 @@
|
||||||
|
package eu.dnetlib.enabling.is.sn.resourcestate.hib;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import eu.dnetlib.enabling.is.sn.resourcestate.ResourceStateSubscription;
|
||||||
|
import eu.dnetlib.enabling.is.sn.resourcestate.ResourceStateSubscriptionDAO;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.apache.commons.logging.Log;
|
||||||
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
import org.hibernate.Criteria;
|
||||||
|
import org.hibernate.SessionFactory;
|
||||||
|
import org.hibernate.criterion.Example;
|
||||||
|
import org.springframework.beans.factory.annotation.Required;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hibernate storage for resource state subscriptions.
|
||||||
|
*
|
||||||
|
* @author marko
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class HibernateResourceStateSubscriptionDAOImpl implements ResourceStateSubscriptionDAO {
|
||||||
|
|
||||||
|
private static final Log log = LogFactory.getLog(HibernateResourceStateSubscriptionDAOImpl.class);
|
||||||
|
|
||||||
|
private SessionFactory sessionFactory;
|
||||||
|
|
||||||
|
private Collection<ResourceStateSubscription> transformToSubscription(final List<Object> inputList) {
|
||||||
|
return inputList.stream()
|
||||||
|
.map(o -> (ResourceStateSubscription) o)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*
|
||||||
|
* @see eu.dnetlib.enabling.is.sn.resourcestate.ResourceStateSubscriptionDAO#listSubscriptions(java.lang.String, java.lang.String,
|
||||||
|
* java.lang.String)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
@Transactional(readOnly = true)
|
||||||
|
public Collection<ResourceStateSubscription> listSubscriptions(final String prefix, final String resourceType, final String resourceId) {
|
||||||
|
|
||||||
|
final ResourceStateSubscription exampleEntity = new ResourceStateSubscription();
|
||||||
|
exampleEntity.setPrefix(prefix);
|
||||||
|
exampleEntity.setType(resourceType);
|
||||||
|
exampleEntity.setResourceId(resourceId);
|
||||||
|
|
||||||
|
return transformToSubscription(queryByCriteria(exampleEntity));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*
|
||||||
|
* @see eu.dnetlib.enabling.is.sn.SubscriptionDAO#addSubscription(java.lang.Object)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
@Transactional
|
||||||
|
public void addSubscription(final ResourceStateSubscription subscription) {
|
||||||
|
|
||||||
|
log.debug("evict cached subscriptions");
|
||||||
|
|
||||||
|
getSessionFactory().getCurrentSession().save(subscription);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*
|
||||||
|
* @see eu.dnetlib.enabling.is.sn.SubscriptionDAO#getSubscription(java.lang.String)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
@Transactional(readOnly = true)
|
||||||
|
public ResourceStateSubscription getSubscription(final String subscriptionId) {
|
||||||
|
return (ResourceStateSubscription) getSessionFactory().getCurrentSession().get(ResourceStateSubscription.class, subscriptionId);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*
|
||||||
|
* @see eu.dnetlib.enabling.is.sn.SubscriptionDAO#listSubscriptions()
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
@Transactional(readOnly = true)
|
||||||
|
public Collection<ResourceStateSubscription> listSubscriptions() {
|
||||||
|
return getSessionFactory().getCurrentSession().createQuery("from subscriptions").list();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*
|
||||||
|
* @see eu.dnetlib.enabling.is.sn.SubscriptionDAO#listSubscriptions(java.lang.String)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
@Transactional(readOnly = true)
|
||||||
|
public Collection<ResourceStateSubscription> listSubscriptions(final String prefix) {
|
||||||
|
final ResourceStateSubscription exampleEntity = new ResourceStateSubscription();
|
||||||
|
exampleEntity.setPrefix(prefix);
|
||||||
|
|
||||||
|
return transformToSubscription(queryByCriteria(exampleEntity));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*
|
||||||
|
* @see eu.dnetlib.enabling.is.sn.SubscriptionDAO#removeSubscription(java.lang.String)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
@Transactional
|
||||||
|
public boolean removeSubscription(final String subscriptionId) {
|
||||||
|
if (StringUtils.isBlank(subscriptionId)) return false;
|
||||||
|
|
||||||
|
final ResourceStateSubscription entity = getSubscription(subscriptionId);
|
||||||
|
|
||||||
|
if (entity == null) return false;
|
||||||
|
|
||||||
|
getSessionFactory().getCurrentSession().delete(entity);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
private List<Object> queryByCriteria(final ResourceStateSubscription exampleEntity) {
|
||||||
|
Criteria criteria = getSessionFactory().getCurrentSession().createCriteria(ResourceStateSubscription.class).add(Example.create(exampleEntity));
|
||||||
|
return criteria.list();
|
||||||
|
}
|
||||||
|
|
||||||
|
public SessionFactory getSessionFactory() {
|
||||||
|
return sessionFactory;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Required
|
||||||
|
public void setSessionFactory(SessionFactory sessionFactory) {
|
||||||
|
this.sessionFactory = sessionFactory;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,323 @@
|
||||||
|
package eu.dnetlib.enabling.is.store;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import javax.jws.WebService;
|
||||||
|
import javax.xml.ws.Endpoint;
|
||||||
|
|
||||||
|
import com.google.common.collect.Iterators;
|
||||||
|
import eu.dnetlib.enabling.is.store.rmi.ISStoreException;
|
||||||
|
import eu.dnetlib.enabling.is.store.rmi.ISStoreService;
|
||||||
|
import eu.dnetlib.enabling.tools.AbstractBaseService;
|
||||||
|
import eu.dnetlib.soap.EndpointReferenceBuilder;
|
||||||
|
import eu.dnetlib.xml.database.XMLDatabase;
|
||||||
|
import org.apache.commons.logging.Log;
|
||||||
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
import org.quartz.Job;
|
||||||
|
import org.quartz.JobExecutionException;
|
||||||
|
import org.xmldb.api.base.XMLDBException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ISStore service implementation.
|
||||||
|
*
|
||||||
|
* @author marko
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@WebService(targetNamespace = "http://services.dnetlib.eu/")
|
||||||
|
public class ISStoreServiceImpl extends AbstractBaseService implements ISStoreService { // NOPMD by marko on 11/24/08
|
||||||
|
|
||||||
|
/**
|
||||||
|
* logger.
|
||||||
|
*/
|
||||||
|
private static final Log log = LogFactory.getLog(ISStoreServiceImpl.class); // NOPMD by marko on 11/24/08 4:46 PM
|
||||||
|
|
||||||
|
/**
|
||||||
|
* xml database used by the ISStore.
|
||||||
|
*/
|
||||||
|
private XMLDatabase xmlDatabase;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Service endpoint.
|
||||||
|
*/
|
||||||
|
private Endpoint endpoint;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* injected EPR builder.
|
||||||
|
*/
|
||||||
|
@Resource(name = "jaxwsEndpointReferenceBuilder")
|
||||||
|
private EndpointReferenceBuilder<Endpoint> eprBuilder;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* initializer job
|
||||||
|
*/
|
||||||
|
private Job contentInitializerJob;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void start() {
|
||||||
|
super.start();
|
||||||
|
|
||||||
|
new Thread(new Runnable() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
try {
|
||||||
|
Thread.sleep(500);
|
||||||
|
contentInitializerJob.execute(null);
|
||||||
|
} catch (JobExecutionException e) {
|
||||||
|
log.fatal("failed to initialize xmldb", e);
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
log.fatal("failed to initialize xmldb", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}).start();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* web service context (not really useful right now).
|
||||||
|
*/
|
||||||
|
// @Resource
|
||||||
|
// private WebServiceContext context;
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*
|
||||||
|
* @see eu.dnetlib.enabling.is.store.rmi.ISStoreService#createFileColl(java.lang.String)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean createFileColl(final String fileColl) throws ISStoreException {
|
||||||
|
try {
|
||||||
|
xmlDatabase.createCollection(fileColl);
|
||||||
|
} catch (XMLDBException e) {
|
||||||
|
throw new ISStoreException(e);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*
|
||||||
|
* @see eu.dnetlib.enabling.is.store.rmi.ISStoreService#deleteFileColl(java.lang.String)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean deleteFileColl(final String fileColl) throws ISStoreException {
|
||||||
|
try {
|
||||||
|
xmlDatabase.removeCollection(fileColl);
|
||||||
|
} catch (XMLDBException e) {
|
||||||
|
throw new ISStoreException(e);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*
|
||||||
|
* @see eu.dnetlib.enabling.is.store.rmi.ISStoreService#deleteXML(java.lang.String, java.lang.String)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean deleteXML(final String fileName, final String fileColl) throws ISStoreException {
|
||||||
|
try {
|
||||||
|
return xmlDatabase.remove(fileName, fileColl);
|
||||||
|
} catch (XMLDBException e) {
|
||||||
|
throw new ISStoreException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*
|
||||||
|
* @see eu.dnetlib.enabling.is.store.rmi.ISStoreService#executeXUpdate(java.lang.String)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean executeXUpdate(final String query) throws ISStoreException {
|
||||||
|
getXMLbyQuery(query);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*
|
||||||
|
* @see eu.dnetlib.enabling.is.store.rmi.ISStoreService#getFileColls()
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public List<String> getFileColls() throws ISStoreException {
|
||||||
|
try {
|
||||||
|
return xmlDatabase.listChildCollections(xmlDatabase.getRootCollection());
|
||||||
|
} catch (XMLDBException e) {
|
||||||
|
throw new ISStoreException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*
|
||||||
|
* @see eu.dnetlib.enabling.is.store.rmi.ISStoreService#getFileNames(java.lang.String)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public List<String> getFileNames(final String fileColl) throws ISStoreException {
|
||||||
|
try {
|
||||||
|
return xmlDatabase.list(fileColl);
|
||||||
|
} catch (XMLDBException e) {
|
||||||
|
throw new ISStoreException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*
|
||||||
|
* @see eu.dnetlib.enabling.is.store.rmi.ISStoreService#getXML(java.lang.String, java.lang.String)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String getXML(final String fileName, final String fileColl) throws ISStoreException {
|
||||||
|
try {
|
||||||
|
return xmlDatabase.read(fileName, fileColl);
|
||||||
|
} catch (XMLDBException e) {
|
||||||
|
throw new ISStoreException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*
|
||||||
|
* @see eu.dnetlib.enabling.is.store.rmi.ISStoreService#getXMLbyQuery(java.lang.String)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String getXMLbyQuery(final String query) throws ISStoreException {
|
||||||
|
log.debug(query);
|
||||||
|
|
||||||
|
try {
|
||||||
|
final Iterator<String> res = xmlDatabase.xquery(query);
|
||||||
|
if (res == null) return null;
|
||||||
|
if (!res.hasNext()) return null;
|
||||||
|
return res.next();
|
||||||
|
} catch (XMLDBException e) {
|
||||||
|
throw new ISStoreException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*
|
||||||
|
* @see eu.dnetlib.enabling.is.store.rmi.ISStoreService#insertXML(java.lang.String, java.lang.String, java.lang.String)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean insertXML(final String fileName, final String fileColl, final String file) throws ISStoreException {
|
||||||
|
try {
|
||||||
|
xmlDatabase.create(fileName, fileColl, file);
|
||||||
|
} catch (XMLDBException e) {
|
||||||
|
throw new ISStoreException(e);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*
|
||||||
|
* @see eu.dnetlib.enabling.is.store.rmi.ISStoreService#quickSearchXML(java.lang.String)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public List<String> quickSearchXML(final String query) throws ISStoreException {
|
||||||
|
log.debug(query);
|
||||||
|
try {
|
||||||
|
final Iterator<String> res = xmlDatabase.xquery(query);
|
||||||
|
if (res == null) return new ArrayList<>();
|
||||||
|
|
||||||
|
final ArrayList<String> ans = new ArrayList<String>();
|
||||||
|
Iterators.addAll(ans, res);
|
||||||
|
return ans;
|
||||||
|
} catch (XMLDBException e) {
|
||||||
|
log.fatal("searching", e);
|
||||||
|
throw new ISStoreException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*
|
||||||
|
* @see eu.dnetlib.enabling.is.store.rmi.ISStoreService#reindex()
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean reindex() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*
|
||||||
|
* @see eu.dnetlib.enabling.is.store.rmi.ISStoreService#sync()
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean sync() {
|
||||||
|
log.info("TEST: " + endpoint);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*
|
||||||
|
* @see eu.dnetlib.enabling.is.store.rmi.ISStoreService#updateXML(java.lang.String, java.lang.String, java.lang.String)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean updateXML(final String fileName, final String fileColl, final String file) throws ISStoreException {
|
||||||
|
try {
|
||||||
|
xmlDatabase.update(fileName, fileColl, file);
|
||||||
|
} catch (XMLDBException e) {
|
||||||
|
throw new ISStoreException(e);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*
|
||||||
|
* @see eu.dnetlib.enabling.is.store.rmi.ISStoreService#backup()
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String backup() throws ISStoreException {
|
||||||
|
try {
|
||||||
|
return xmlDatabase.backup();
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new ISStoreException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public XMLDatabase getXmlDatabase() {
|
||||||
|
return xmlDatabase;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setXmlDatabase(final XMLDatabase xmlDatabase) {
|
||||||
|
this.xmlDatabase = xmlDatabase;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isRunning() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Endpoint getEndpoint() {
|
||||||
|
return endpoint;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEndpoint(final Endpoint endpoint) {
|
||||||
|
this.endpoint = endpoint;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected EndpointReferenceBuilder<Endpoint> getEprBuilder() {
|
||||||
|
return eprBuilder;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void setEprBuilder(final EndpointReferenceBuilder<Endpoint> eprBuilder) {
|
||||||
|
this.eprBuilder = eprBuilder;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Job getContentInitializerJob() {
|
||||||
|
return contentInitializerJob;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setContentInitializerJob(final Job contentInitializerJob) {
|
||||||
|
this.contentInitializerJob = contentInitializerJob;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,180 @@
|
||||||
|
package eu.dnetlib.enabling.is.store;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import javax.xml.parsers.ParserConfigurationException;
|
||||||
|
import javax.xml.xpath.XPathExpressionException;
|
||||||
|
|
||||||
|
import org.apache.commons.logging.Log;
|
||||||
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
import org.quartz.Job;
|
||||||
|
import org.quartz.JobExecutionContext;
|
||||||
|
import org.quartz.JobExecutionException;
|
||||||
|
import org.springframework.beans.factory.annotation.Required;
|
||||||
|
import org.springframework.core.io.Resource;
|
||||||
|
import org.xml.sax.SAXException;
|
||||||
|
|
||||||
|
import eu.dnetlib.enabling.is.registry.rmi.ISRegistryException;
|
||||||
|
import eu.dnetlib.enabling.tools.ResourceLoaderHelper;
|
||||||
|
import eu.dnetlib.miscutils.coupling.StaticCondition;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This job is scheduled at startup of a test environment to load some data into the store.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* You should configure this bean with paths to the profile and schema files you want to add. This can be done setting
|
||||||
|
* the 'resources' and 'schemas' properties using the syntax documented <a
|
||||||
|
* href="http://static.springframework.org/spring/docs/
|
||||||
|
* 2.5.x/reference/resources.html#resources-app-ctx-wildcards-in-resource-paths">here</a>
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author marko
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class TestContentInitializerJob extends AbstractContentInitializer implements Job {
|
||||||
|
/**
|
||||||
|
* milliseconds in a second.
|
||||||
|
*/
|
||||||
|
private static final double MILLIS = 1000.0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* logger.
|
||||||
|
*/
|
||||||
|
static final Log log = LogFactory.getLog(TestContentInitializerJob.class); // NOPMD by marko on 11/24/08 5:02 PM
|
||||||
|
|
||||||
|
/**
|
||||||
|
* hackish way of communicating to the integration tester that we have finished.
|
||||||
|
*/
|
||||||
|
private static boolean initialized = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* resourceLoader compatible pattern matching all files to load.
|
||||||
|
*/
|
||||||
|
private String resources;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* resourceLoader compatible pattern matching all xsd files to load.
|
||||||
|
*/
|
||||||
|
private String schemas;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* resource loader helper. we cannot implement the ResourceLoaderAware interface.
|
||||||
|
*/
|
||||||
|
private ResourceLoaderHelper resourceLoader;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* set to true in order to disable notification detection. Useful for bulk profile insertion.
|
||||||
|
*/
|
||||||
|
private StaticCondition snDisable;
|
||||||
|
|
||||||
|
public TestContentInitializerJob() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*
|
||||||
|
* @see org.quartz.Job#execute(org.quartz.JobExecutionContext)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void execute(final JobExecutionContext arg0) throws JobExecutionException {
|
||||||
|
initialize();
|
||||||
|
setInitialized(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void initialize() throws JobExecutionException {
|
||||||
|
log.info("Initializing store with some profiles and collections for test and development ...");
|
||||||
|
|
||||||
|
if (!getBulkImporter().isEnabled()) {
|
||||||
|
log.info("skipping store initialization because the database already exists");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
log.info("loading resources: " + getResources());
|
||||||
|
|
||||||
|
try {
|
||||||
|
String type = "schema/profile"; // NOPMD
|
||||||
|
String name = "none"; // NOPMD
|
||||||
|
try {
|
||||||
|
final long start = System.currentTimeMillis();
|
||||||
|
|
||||||
|
type = "schema"; // NOPMD
|
||||||
|
for (Resource res : resourceLoader.getResourcePatternResolver().getResources(schemas)) {
|
||||||
|
name = res.getURL().toString(); // NOPMD
|
||||||
|
registerSchema(res.getURL());
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
snDisable.setCondition(true);
|
||||||
|
type = "profile";
|
||||||
|
for (Resource res : resourceLoader.getResourcePatternResolver().getResources(resources)) {
|
||||||
|
name = res.getURL().toString(); // NOPMD
|
||||||
|
registerProfile(res.getURL());
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
snDisable.setCondition(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
log.info("bulk registration finished in: " + ((System.currentTimeMillis() - start) / MILLIS) + "s");
|
||||||
|
} catch (ISRegistryException e) {
|
||||||
|
log.fatal("cannot register " + type + ": " + name, e);
|
||||||
|
throw new JobExecutionException("registry exception", e);
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new JobExecutionException("io exception", e);
|
||||||
|
} catch (XPathExpressionException e) {
|
||||||
|
throw new JobExecutionException("xpath exception", e);
|
||||||
|
} catch (SAXException e) {
|
||||||
|
throw new JobExecutionException("sax exception", e);
|
||||||
|
} catch (ParserConfigurationException e) {
|
||||||
|
throw new JobExecutionException("parser exception", e);
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
log.info("INITIALIZED");
|
||||||
|
setInitialized(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void setInitialized(final boolean initialized) {
|
||||||
|
TestContentInitializerJob.initialized = initialized;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isInitialized() {
|
||||||
|
return initialized;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setResources(final String resources) {
|
||||||
|
this.resources = resources;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getResources() {
|
||||||
|
return resources;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Required
|
||||||
|
public ResourceLoaderHelper getResourceLoader() {
|
||||||
|
return resourceLoader;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Required
|
||||||
|
public void setResourceLoader(final ResourceLoaderHelper resourceLoader) {
|
||||||
|
this.resourceLoader = resourceLoader;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Required
|
||||||
|
public void setSchemas(final String schemas) {
|
||||||
|
this.schemas = schemas;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSchemas() {
|
||||||
|
return schemas;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSnDisable(final StaticCondition snDisable) {
|
||||||
|
this.snDisable = snDisable;
|
||||||
|
}
|
||||||
|
|
||||||
|
public StaticCondition getSnDisable() {
|
||||||
|
return snDisable;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,10 @@
|
||||||
|
xquery version "1.0";
|
||||||
|
|
||||||
|
module namespace dnet="http://namespace.dnetlib.eu/xquery/dnet";
|
||||||
|
declare namespace xmldb="http://exist-db.org/xquery/xmldb";
|
||||||
|
|
||||||
|
declare function dnet:deleteDocument($x as element()) {
|
||||||
|
|
||||||
|
xmldb:remove(replace($x/base-uri(),'/[^/]*$', ''), replace($x/base-uri(),'^.*/([^/]*)$', '$1'))
|
||||||
|
|
||||||
|
};
|
|
@ -0,0 +1,46 @@
|
||||||
|
package eu.dnetlib.enabling.tools;
|
||||||
|
|
||||||
|
import com.sun.xml.messaging.saaj.util.Base64;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* resolve resource file and collection names from the resource identifier according to the DNet 1.0 policy, by encoding
|
||||||
|
* the collection path in the identifier itself (as base64).
|
||||||
|
*
|
||||||
|
* @author marko
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class CompatResourceIdentifierResolverImpl implements ResourceIdentifierResolver, ResourceIdentifierComposer {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*
|
||||||
|
* @see eu.dnetlib.enabling.tools.ResourceIdentifierResolver#getCollectionName(java.lang.String)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String getCollectionName(final String resId) {
|
||||||
|
final String[] components = resId.split("_");
|
||||||
|
if (components.length == 1)
|
||||||
|
return "DefaultCollection";
|
||||||
|
return Base64.base64Decode(components[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*
|
||||||
|
* @see eu.dnetlib.enabling.tools.ResourceIdentifierResolver#getFileName(java.lang.String)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String getFileName(final String resId) {
|
||||||
|
return resId.split("_")[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*
|
||||||
|
* @see eu.dnetlib.enabling.tools.ResourceIdentifierComposer#createResourceId(java.lang.String, java.lang.String)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String createResourceId(final String fileName, final String coll) {
|
||||||
|
return fileName + "_" + new String(Base64.encode(coll.getBytes()));
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,27 @@
|
||||||
|
package eu.dnetlib.enabling.tools;
|
||||||
|
|
||||||
|
import org.aopalliance.intercept.MethodInvocation;
|
||||||
|
import org.apache.commons.logging.Log;
|
||||||
|
import org.springframework.aop.interceptor.CustomizableTraceInterceptor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class intercepts calls to the OAICore to measure its execution time. It uses Spring AOP.
|
||||||
|
*
|
||||||
|
* @author alessia
|
||||||
|
*/
|
||||||
|
public class LogInterceptor extends CustomizableTraceInterceptor {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void writeToLog(final Log logger, final String message, final Throwable ex) {
|
||||||
|
if (ex != null) {
|
||||||
|
logger.error(message, ex);
|
||||||
|
} else {
|
||||||
|
logger.debug(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean isInterceptorEnabled(final MethodInvocation invocation, final Log logger) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,18 @@
|
||||||
|
package eu.dnetlib.enabling.tools;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Abstracts the creation of a resource identifier from xmldb file name and xmldb collection name.
|
||||||
|
*
|
||||||
|
* @author marko
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public interface ResourceIdentifierComposer {
|
||||||
|
/**
|
||||||
|
* Create a resId from a xmldb filename and collection name.
|
||||||
|
*
|
||||||
|
* @param fileName
|
||||||
|
* @param coll
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
String createResourceId(final String fileName, final String coll);
|
||||||
|
}
|
|
@ -0,0 +1,161 @@
|
||||||
|
package eu.dnetlib.enabling.tools;
|
||||||
|
|
||||||
|
import java.io.BufferedWriter;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileWriter;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import eu.dnetlib.enabling.is.sn.rmi.ISSNService;
|
||||||
|
import eu.dnetlib.enabling.is.store.rmi.ISStoreException;
|
||||||
|
import eu.dnetlib.enabling.is.store.rmi.ISStoreService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* TODO: document. TODO: Too low level, why the interfacing the Store and not the Registry ?
|
||||||
|
*
|
||||||
|
* @author michele
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class ResourceType {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* xmldb collection where resource types are stored.
|
||||||
|
*/
|
||||||
|
public static final String RESOURCE_TYPES = "DRIVERResourceTypes";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* resource type. (Including kind?)
|
||||||
|
*/
|
||||||
|
private String resourceType; // NOPMD
|
||||||
|
|
||||||
|
/**
|
||||||
|
* resource schema. (Body?)
|
||||||
|
*/
|
||||||
|
private String resourceSchema; // NOPMD
|
||||||
|
/**
|
||||||
|
* file where a copy of the schema is stored locally TODO: why ?
|
||||||
|
*/
|
||||||
|
private File fileSchema;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* instanciate an already registered resource type, fetching it from the store.
|
||||||
|
*
|
||||||
|
* @param resourceType
|
||||||
|
* resourceType name
|
||||||
|
* @param store
|
||||||
|
* store service where the type is stored
|
||||||
|
* @param basedir
|
||||||
|
* base dir where a local copy is held (why?)
|
||||||
|
* @throws ISStoreException
|
||||||
|
* happens
|
||||||
|
*/
|
||||||
|
public ResourceType(final String resourceType, final ISStoreService store, final String basedir) throws ISStoreException {
|
||||||
|
this(resourceType, store.getXML(resourceType, RESOURCE_TYPES), basedir);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* construct a resource type.
|
||||||
|
*
|
||||||
|
* @param resourceType
|
||||||
|
* resourceType name
|
||||||
|
* @param resourceSchema
|
||||||
|
* resourceSchema xsd body
|
||||||
|
* @param basedir
|
||||||
|
* base directory of some local copy (?)
|
||||||
|
* @throws ISStoreException
|
||||||
|
* happens
|
||||||
|
*/
|
||||||
|
public ResourceType(final String resourceType, final String resourceSchema, final String basedir) throws ISStoreException {
|
||||||
|
this.resourceType = resourceType;
|
||||||
|
this.resourceSchema = resourceSchema;
|
||||||
|
if (basedir != null)
|
||||||
|
this.fileSchema = saveSchemaAsFile(basedir);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* stores the schema on the xmldb.
|
||||||
|
*
|
||||||
|
* @param store
|
||||||
|
* store service
|
||||||
|
* @throws ISStoreException
|
||||||
|
* happens
|
||||||
|
*/
|
||||||
|
public void store(final ISStoreService store) throws ISStoreException {
|
||||||
|
store.insertXML(resourceType, RESOURCE_TYPES, resourceSchema);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* updates the in memory resource instance from the store.
|
||||||
|
*
|
||||||
|
* @param store store service
|
||||||
|
* @throws ISStoreException happens
|
||||||
|
*/
|
||||||
|
public void update(final ISStoreService store) throws ISStoreException {
|
||||||
|
store.updateXML(resourceType, RESOURCE_TYPES, resourceSchema);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* save the schema to a file.
|
||||||
|
*
|
||||||
|
* @param basedir
|
||||||
|
* base directory
|
||||||
|
* @return the newly created file
|
||||||
|
* @throws ISStoreException
|
||||||
|
* happens, even if the file cannot be created.
|
||||||
|
*/
|
||||||
|
private File saveSchemaAsFile(final String basedir) throws ISStoreException {
|
||||||
|
fileSchema = new File(basedir + "/" + resourceType);
|
||||||
|
if (!fileSchema.exists()) {
|
||||||
|
try {
|
||||||
|
final BufferedWriter out = new BufferedWriter(new FileWriter(fileSchema));
|
||||||
|
out.write(resourceSchema);
|
||||||
|
out.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new ISStoreException("Error saving file", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return fileSchema;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* it says "delete and notify" but it only deletes the schema from the filesystem and from the store.
|
||||||
|
*
|
||||||
|
* TODO: document and possibly refactor.
|
||||||
|
*
|
||||||
|
* @param store
|
||||||
|
* store service
|
||||||
|
* @param issn
|
||||||
|
* ISSN service
|
||||||
|
* @throws ISStoreException
|
||||||
|
* happens
|
||||||
|
*/
|
||||||
|
public void deleteAndNotify(final ISStoreService store, final ISSNService issn) throws ISStoreException {
|
||||||
|
fileSchema.delete();
|
||||||
|
store.deleteXML(resourceType, RESOURCE_TYPES);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getResourceType() {
|
||||||
|
return resourceType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setResourceType(final String resourceType) {
|
||||||
|
this.resourceType = resourceType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getResourceSchema() {
|
||||||
|
return resourceSchema;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setResourceSchema(final String resourceSchema) {
|
||||||
|
this.resourceSchema = resourceSchema;
|
||||||
|
}
|
||||||
|
|
||||||
|
public File getFileSchema() {
|
||||||
|
return fileSchema;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFileSchema(final File fileSchema) {
|
||||||
|
this.fileSchema = fileSchema;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,52 @@
|
||||||
|
package eu.dnetlib.enabling.tools;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Standard DNet-1.0 compat xquery utils.
|
||||||
|
*
|
||||||
|
* @author marko
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class XQueryUtilsImpl implements XQueryUtils {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
* @see eu.dnetlib.enabling.tools.XQueryUtils#getCollectionAbsPath(eu.dnetlib.enabling.tools.OpaqueResource)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String getCollectionAbsPath(final OpaqueResource resource) {
|
||||||
|
return getRootCollection() + getCollectionPath(resource);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
* @see eu.dnetlib.enabling.tools.XQueryUtils#getCollectionPath(eu.dnetlib.enabling.tools.OpaqueResource)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String getCollectionPath(final OpaqueResource resource) {
|
||||||
|
final StringBuilder buffer = new StringBuilder();
|
||||||
|
buffer.append(resource.getResourceKind());
|
||||||
|
buffer.append('/');
|
||||||
|
buffer.append(resource.getResourceType());
|
||||||
|
return buffer.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
* @see eu.dnetlib.enabling.tools.XQueryUtils#getRootCollection()
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String getRootCollection() {
|
||||||
|
return "/db/DRIVER/";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
* @see eu.dnetlib.enabling.tools.XQueryUtils#getFileName(eu.dnetlib.enabling.tools.OpaqueResource)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String getFileName(final OpaqueResource resource) {
|
||||||
|
return resource.getResourceId().split("_")[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,27 @@
|
||||||
|
package eu.dnetlib.xml.database;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* most trigger will hold the trigger name in an instance variable.
|
||||||
|
*
|
||||||
|
* The Trigger contract requires a getter (getName()). This class implements the setter too.
|
||||||
|
*
|
||||||
|
* @author marko
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public abstract class AbstractTrigger implements Trigger {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* trigger name.
|
||||||
|
*/
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(final String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,46 @@
|
||||||
|
package eu.dnetlib.xml.database;
|
||||||
|
|
||||||
|
import org.apache.commons.logging.Log;
|
||||||
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
import org.w3c.dom.Document;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This trigger simply logs all xmldb CRUDE events.
|
||||||
|
*
|
||||||
|
* @author marko
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class LoggingTrigger extends AbstractTrigger {
|
||||||
|
/**
|
||||||
|
* logger.
|
||||||
|
*/
|
||||||
|
private static final Log log = LogFactory.getLog(LoggingTrigger.class); // NOPMD by marko on 11/24/08 5:02 PM
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
* @see eu.dnetlib.xml.database.Trigger#created(java.lang.String, java.lang.String, org.w3c.dom.Document)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void created(final String file, final String collection, final Document newDoc) {
|
||||||
|
log.info("xml resource created: " + collection + "/" + file);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
* @see eu.dnetlib.xml.database.Trigger#deleted(java.lang.String, java.lang.String, org.w3c.dom.Document)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void deleted(final String file, final String collection, final Document oldDoc) {
|
||||||
|
log.info("xml resource deleted: " + collection + "/" + file);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
* @see eu.dnetlib.xml.database.Trigger#updated(java.lang.String, java.lang.String, org.w3c.dom.Document, org.w3c.dom.Document)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void updated(final String file, final String collection, final Document oldDoc, final Document newDoc) {
|
||||||
|
log.info("xml resource updated: " + collection + "/" + file);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,56 @@
|
||||||
|
package eu.dnetlib.xml.database;
|
||||||
|
|
||||||
|
import org.w3c.dom.Document;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* xml db trigger.
|
||||||
|
*
|
||||||
|
* @author marko
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public interface Trigger {
|
||||||
|
/**
|
||||||
|
* each trigger has a user defined unique name.
|
||||||
|
*
|
||||||
|
* @return trigger name
|
||||||
|
*/
|
||||||
|
String getName();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* triggered when a new document is created.
|
||||||
|
*
|
||||||
|
* @param file
|
||||||
|
* file name
|
||||||
|
* @param collection
|
||||||
|
* collection name
|
||||||
|
* @param newDoc
|
||||||
|
* newly created document
|
||||||
|
*/
|
||||||
|
void created(String file, String collection, Document newDoc);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* triggered when a document is updated.
|
||||||
|
*
|
||||||
|
* @param file
|
||||||
|
* file name
|
||||||
|
* @param collection
|
||||||
|
* collection name
|
||||||
|
* @param oldDoc
|
||||||
|
* old version
|
||||||
|
* @param newDoc
|
||||||
|
* new version
|
||||||
|
*/
|
||||||
|
void updated(String file, String collection, Document oldDoc, Document newDoc);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* triggered when a document is deleted.
|
||||||
|
*
|
||||||
|
* @param file
|
||||||
|
* file name
|
||||||
|
* @param collection
|
||||||
|
* collection name
|
||||||
|
* @param oldDoc
|
||||||
|
* deleted document
|
||||||
|
*/
|
||||||
|
void deleted(String file, String collection, Document oldDoc);
|
||||||
|
}
|
|
@ -0,0 +1,175 @@
|
||||||
|
package eu.dnetlib.xml.database;
|
||||||
|
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.exist.util.DatabaseConfigurationException;
|
||||||
|
import org.xmldb.api.base.XMLDBException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* xmldb API is ugly.
|
||||||
|
*
|
||||||
|
* This is a thin wrapper to the xmldb API with focus on the primary operations used by dnet
|
||||||
|
*
|
||||||
|
* @author marko
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public interface XMLDatabase { // NOPMD
|
||||||
|
/**
|
||||||
|
* creates a new resource or updates the resource if it already exists.
|
||||||
|
*
|
||||||
|
* @param name
|
||||||
|
* file name
|
||||||
|
* @param collection
|
||||||
|
* collection name
|
||||||
|
* @param content
|
||||||
|
* serialized xml string
|
||||||
|
* @throws XMLDBException
|
||||||
|
* happens
|
||||||
|
*/
|
||||||
|
void create(String name, String collection, String content) throws XMLDBException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* updates and already existing resource.
|
||||||
|
*
|
||||||
|
* @param name
|
||||||
|
* file name
|
||||||
|
* @param collection
|
||||||
|
* collection name
|
||||||
|
* @param content
|
||||||
|
* serialized xml string
|
||||||
|
* @throws XMLDBException
|
||||||
|
* fails if the resource doesn't exist
|
||||||
|
*/
|
||||||
|
void update(String name, String collection, String content) throws XMLDBException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* removes a resource.
|
||||||
|
*
|
||||||
|
* @param name
|
||||||
|
* file name
|
||||||
|
* @param collection
|
||||||
|
* collection name
|
||||||
|
* @return false if the resource doesn't exist
|
||||||
|
* @throws XMLDBException
|
||||||
|
* could happen
|
||||||
|
*/
|
||||||
|
boolean remove(String name, String collection) throws XMLDBException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* read a resource string xml.
|
||||||
|
*
|
||||||
|
* @param name
|
||||||
|
* file name
|
||||||
|
* @param collection
|
||||||
|
* collection name
|
||||||
|
* @return null if the resource doesn't exist, otherwise it returns the xml string serialization
|
||||||
|
* @throws XMLDBException
|
||||||
|
* happens
|
||||||
|
*/
|
||||||
|
String read(String name, String collection) throws XMLDBException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute an xquery.
|
||||||
|
*
|
||||||
|
* @param xquery
|
||||||
|
* xquery source
|
||||||
|
* @return a xmldb resultset object
|
||||||
|
* @throws XMLDBException
|
||||||
|
* happens
|
||||||
|
*/
|
||||||
|
Iterator<String> xquery(String xquery) throws XMLDBException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* creates a new collection, non recursively.
|
||||||
|
*
|
||||||
|
* @param collection
|
||||||
|
* collection name
|
||||||
|
* @throws XMLDBException
|
||||||
|
* happens
|
||||||
|
*/
|
||||||
|
void createCollection(String collection) throws XMLDBException;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* remove a collection.
|
||||||
|
*
|
||||||
|
* @param collection
|
||||||
|
* collection name
|
||||||
|
* @throws XMLDBException
|
||||||
|
* happens also when the collection doesn't eXist
|
||||||
|
*/
|
||||||
|
void removeCollection(String collection) throws XMLDBException;
|
||||||
|
|
||||||
|
void xupdate(String query) throws XMLDBException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* check whether a collection exists.
|
||||||
|
*
|
||||||
|
* @param collection
|
||||||
|
* collection name
|
||||||
|
* @return true if the collection exists
|
||||||
|
* @throws XMLDBException
|
||||||
|
* happens
|
||||||
|
*/
|
||||||
|
boolean collectionExists(String collection) throws XMLDBException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* lists child collections.
|
||||||
|
*
|
||||||
|
* @param collection
|
||||||
|
* parent collections
|
||||||
|
* @return list of collection names
|
||||||
|
* @throws XMLDBException
|
||||||
|
* happens
|
||||||
|
*/
|
||||||
|
List<String> listChildCollections(String collection) throws XMLDBException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* list the content of a collection.
|
||||||
|
*
|
||||||
|
* @param collection
|
||||||
|
* parent collection
|
||||||
|
* @return list of resource names
|
||||||
|
* @throws XMLDBException
|
||||||
|
* happens
|
||||||
|
*/
|
||||||
|
List<String> list(String collection) throws XMLDBException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* returns the name of the root collection.
|
||||||
|
*
|
||||||
|
* @return collection name
|
||||||
|
*/
|
||||||
|
String getRootCollection();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* register a new trigger on a collection.
|
||||||
|
*
|
||||||
|
* @param trigger
|
||||||
|
* trigger instance
|
||||||
|
* @param collection
|
||||||
|
* collection pattern
|
||||||
|
* @throws XMLDBException
|
||||||
|
* happens
|
||||||
|
*/
|
||||||
|
void registerTrigger(Trigger trigger, String collection) throws XMLDBException;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* make a backup of entire database.
|
||||||
|
*
|
||||||
|
* @throws XMLDBException could happen
|
||||||
|
* @throws DatabaseConfigurationException could happen
|
||||||
|
* @return the path in which the Backup has been saved
|
||||||
|
*/
|
||||||
|
String backup() throws XMLDBException, DatabaseConfigurationException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the dir that contains all backups.
|
||||||
|
*
|
||||||
|
* @return the path in which the Backup has been saved
|
||||||
|
*/
|
||||||
|
String getBackupDir();
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,197 @@
|
||||||
|
package eu.dnetlib.xml.database.exist;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import eu.dnetlib.miscutils.functional.xml.IndentXmlString;
|
||||||
|
import org.apache.commons.logging.Log;
|
||||||
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
import org.exist.collections.Collection;
|
||||||
|
import org.exist.collections.triggers.SAXTrigger;
|
||||||
|
import org.exist.collections.triggers.TriggerException;
|
||||||
|
import org.exist.dom.persistent.DocumentImpl;
|
||||||
|
import org.exist.storage.DBBroker;
|
||||||
|
import org.exist.storage.txn.Txn;
|
||||||
|
import org.exist.xmldb.XmldbURI;
|
||||||
|
|
||||||
|
import eu.dnetlib.xml.database.Trigger;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* this trigger delegates diffs for CRUDE events to an non-exist dependent eu.dnetlib.xml.database.Trigger instance.
|
||||||
|
*
|
||||||
|
* Since eXist triggers are instantiated by eXist, we need to locate the Trigger instances which are registered to the database instance.
|
||||||
|
*
|
||||||
|
* @author marko
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class DelegatingDiffTrigger extends SAXTrigger {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* logger.
|
||||||
|
*/
|
||||||
|
private static final Log log = LogFactory.getLog(DelegatingDiffTrigger.class); // NOPMD by marko on 11/24/08 5:02 PM
|
||||||
|
|
||||||
|
/**
|
||||||
|
* trigger identifier, from configuration.
|
||||||
|
*/
|
||||||
|
private String triggerName;
|
||||||
|
|
||||||
|
private Map<String, ExistsTriggerEvent> existsTriggerEventMap = new HashMap<>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*
|
||||||
|
* @see org.exist.collections.triggers.FilteringTrigger#configure(org.exist.storage.DBBroker, org.exist.collections.Collection,
|
||||||
|
* java.util.Map)
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
@Override
|
||||||
|
public void configure(final DBBroker dbBroker, final Collection parent, final Map<String, List<?>> parameters) throws TriggerException {
|
||||||
|
super.configure(dbBroker, parent, parameters);
|
||||||
|
|
||||||
|
if (parameters == null) { return; }
|
||||||
|
|
||||||
|
final Map<String, List<?>> params = parameters;
|
||||||
|
if (parameters.containsKey("triggerName")) {
|
||||||
|
final List<?> myTriggerName = parameters.get("triggerName");
|
||||||
|
if ((myTriggerName != null) && (myTriggerName.size() == 1)) {
|
||||||
|
setTriggerName(myTriggerName.get(0).toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (getTriggerName() == null) {
|
||||||
|
log.fatal("trigger id not configured");
|
||||||
|
throw new TriggerException("trigger name not configured");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* find the trigger instance associated with this delegation.
|
||||||
|
*
|
||||||
|
* @return trigger instance
|
||||||
|
*/
|
||||||
|
protected Trigger getTrigger() {
|
||||||
|
final Trigger trigger = ExistTriggerRegistry.defaultInstance().getTrigger(getTriggerName());
|
||||||
|
if (trigger == null) {
|
||||||
|
log.fatal("no trigger " + triggerName + " but there is a registered callback for it");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return trigger;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getTriggerName() {
|
||||||
|
return triggerName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTriggerName(final String triggerId) {
|
||||||
|
triggerName = triggerId;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void beforeCreateDocument(final DBBroker dbBroker, final Txn txn, final XmldbURI xmldbURI) throws TriggerException {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void afterCreateDocument(final DBBroker dbBroker, final Txn txn, final DocumentImpl document) throws TriggerException {
|
||||||
|
|
||||||
|
try {
|
||||||
|
final Trigger trigger = getTrigger();
|
||||||
|
final String collection = document.getCollection().getURI().toString();
|
||||||
|
final String fileName = document.getFileURI().toString();
|
||||||
|
if (trigger != null) {
|
||||||
|
trigger.created(fileName, collection, document);
|
||||||
|
}
|
||||||
|
} catch (final Exception e) {
|
||||||
|
throw new TriggerException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void beforeUpdateDocument(final DBBroker dbBroker, final Txn txn, final DocumentImpl document) throws TriggerException {
|
||||||
|
|
||||||
|
try {
|
||||||
|
final String collection = document.getCollection().getURI().toString();
|
||||||
|
final String fileName = document.getFileURI().toString();
|
||||||
|
final ExistsTriggerEvent event = new ExistsTriggerEvent();
|
||||||
|
event.setOldDocument(IndentXmlString.apply(document));
|
||||||
|
event.setEventType(EventType.UPDATE);
|
||||||
|
event.setCollection(collection);
|
||||||
|
event.setName(fileName);
|
||||||
|
existsTriggerEventMap.put(String.valueOf(txn.getId()), event);
|
||||||
|
} catch (final Exception e) {
|
||||||
|
throw new TriggerException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void afterUpdateDocument(final DBBroker dbBroker, final Txn txn, final DocumentImpl document) throws TriggerException {
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (!existsTriggerEventMap.containsKey(
|
||||||
|
String.valueOf(txn.getId()))) { throw new TriggerException("Error on trigger missing previous operation beforeUpdateTrigger"); }
|
||||||
|
final ExistsTriggerEvent existsTriggerEvent = existsTriggerEventMap.remove(String.valueOf(txn.getId()));
|
||||||
|
|
||||||
|
existsTriggerEvent.setDocument(IndentXmlString.apply(document));
|
||||||
|
final Trigger trigger = getTrigger();
|
||||||
|
if (trigger != null) {
|
||||||
|
trigger.updated(existsTriggerEvent.getName(), existsTriggerEvent.getCollection(), existsTriggerEvent.getOldDocument(),
|
||||||
|
existsTriggerEvent.getDocument());
|
||||||
|
}
|
||||||
|
} catch (final Exception e) {
|
||||||
|
throw new TriggerException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void beforeUpdateDocumentMetadata(final DBBroker dbBroker, final Txn txn, final DocumentImpl document) throws TriggerException {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void afterUpdateDocumentMetadata(final DBBroker dbBroker, final Txn txn, final DocumentImpl document) throws TriggerException {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void beforeCopyDocument(final DBBroker dbBroker, final Txn txn, final DocumentImpl document, final XmldbURI xmldbURI) throws TriggerException {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void afterCopyDocument(final DBBroker dbBroker, final Txn txn, final DocumentImpl document, final XmldbURI xmldbURI) throws TriggerException {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void beforeMoveDocument(final DBBroker dbBroker, final Txn txn, final DocumentImpl document, final XmldbURI xmldbURI) throws TriggerException {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void afterMoveDocument(final DBBroker dbBroker, final Txn txn, final DocumentImpl document, final XmldbURI xmldbURI) throws TriggerException {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void beforeDeleteDocument(final DBBroker dbBroker, final Txn txn, final DocumentImpl document) throws TriggerException {
|
||||||
|
|
||||||
|
try {
|
||||||
|
final Trigger trigger = getTrigger();
|
||||||
|
final String collection = document.getCollection().getURI().toString();
|
||||||
|
final String fileName = document.getFileURI().toString();
|
||||||
|
if (trigger != null) {
|
||||||
|
trigger.deleted(fileName, collection, IndentXmlString.apply(document));
|
||||||
|
}
|
||||||
|
} catch (final Exception e) {
|
||||||
|
throw new TriggerException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void afterDeleteDocument(final DBBroker dbBroker, final Txn txn, final XmldbURI xmldbURI) throws TriggerException {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,10 @@
|
||||||
|
package eu.dnetlib.xml.database.exist;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by claudio on 20/12/2016.
|
||||||
|
*/
|
||||||
|
public enum EventType {
|
||||||
|
UPDATE,
|
||||||
|
CREATE,
|
||||||
|
DELETE
|
||||||
|
}
|
|
@ -0,0 +1,82 @@
|
||||||
|
package eu.dnetlib.xml.database.exist;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.StringReader;
|
||||||
|
import java.io.StringWriter;
|
||||||
|
|
||||||
|
import javax.xml.parsers.DocumentBuilder;
|
||||||
|
import javax.xml.parsers.DocumentBuilderFactory;
|
||||||
|
import javax.xml.parsers.ParserConfigurationException;
|
||||||
|
|
||||||
|
import org.apache.xml.serialize.OutputFormat;
|
||||||
|
import org.apache.xml.serialize.XMLSerializer;
|
||||||
|
import org.w3c.dom.Document;
|
||||||
|
import org.xml.sax.InputSource;
|
||||||
|
import org.xml.sax.SAXException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exist has an internal DOM implementation.
|
||||||
|
*
|
||||||
|
* @author marko
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("deprecation")
|
||||||
|
public class ExistDOMConverter {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* convert a DOM document to InputSource on which you can run an XPath.
|
||||||
|
*
|
||||||
|
* The internal eXist DOM implementation has some problems.
|
||||||
|
*
|
||||||
|
* @param input
|
||||||
|
* DOM document
|
||||||
|
* @return sax input source
|
||||||
|
* @throws IOException
|
||||||
|
* happens ?
|
||||||
|
*/
|
||||||
|
public InputSource asInputSource(final Document input) throws IOException {
|
||||||
|
return new InputSource(new StringReader(asString(input)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* serialize a dom document to a string.
|
||||||
|
*
|
||||||
|
* TODO: avoid using deprecated XMLSerializer
|
||||||
|
*
|
||||||
|
* cannot use Transformer because eXist DOM impl is incomplete.
|
||||||
|
*
|
||||||
|
* @param input
|
||||||
|
* DOM document
|
||||||
|
* @return sax input source
|
||||||
|
* @throws IOException
|
||||||
|
* happens ?
|
||||||
|
*/
|
||||||
|
|
||||||
|
public String asString(final Document input) throws IOException {
|
||||||
|
final StringWriter writer = new StringWriter();
|
||||||
|
|
||||||
|
new XMLSerializer(writer, new OutputFormat()).serialize(input.getDocumentElement());
|
||||||
|
|
||||||
|
return writer.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* convert a DOM document to a w3c DOM Document on which you can run an XPath.
|
||||||
|
*
|
||||||
|
* The internal eXist DOM implementation has some problems.
|
||||||
|
*
|
||||||
|
* @param input
|
||||||
|
* input eXist DOM document
|
||||||
|
* @return good DOM document
|
||||||
|
* @throws IOException
|
||||||
|
* happens
|
||||||
|
* @throws ParserConfigurationException
|
||||||
|
* happens
|
||||||
|
* @throws SAXException
|
||||||
|
* happens
|
||||||
|
*/
|
||||||
|
public Document asDocument(final Document input) throws IOException, ParserConfigurationException, SAXException {
|
||||||
|
final DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
|
||||||
|
return builder.parse(asInputSource(input));
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,635 @@
|
||||||
|
package eu.dnetlib.xml.database.exist; // NOPMD
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.FileWriter;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.Map.Entry;
|
||||||
|
import java.util.concurrent.locks.Lock;
|
||||||
|
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||||
|
import java.util.zip.ZipEntry;
|
||||||
|
import java.util.zip.ZipOutputStream;
|
||||||
|
|
||||||
|
import org.apache.commons.logging.Log;
|
||||||
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
import org.exist.collections.CollectionConfiguration;
|
||||||
|
import org.exist.util.DatabaseConfigurationException;
|
||||||
|
import org.exist.xmldb.DatabaseImpl;
|
||||||
|
import org.exist.xmldb.DatabaseInstanceManager;
|
||||||
|
import org.exist.xmldb.EXistResource;
|
||||||
|
import org.exist.xmldb.XmldbURI;
|
||||||
|
import org.springframework.beans.factory.annotation.Required;
|
||||||
|
import org.springframework.context.Lifecycle;
|
||||||
|
import org.xmldb.api.DatabaseManager;
|
||||||
|
import org.xmldb.api.base.*;
|
||||||
|
import org.xmldb.api.base.Collection;
|
||||||
|
import org.xmldb.api.modules.CollectionManagementService;
|
||||||
|
import org.xmldb.api.modules.XPathQueryService;
|
||||||
|
|
||||||
|
import eu.dnetlib.miscutils.datetime.DateUtils;
|
||||||
|
import eu.dnetlib.xml.database.Trigger;
|
||||||
|
|
||||||
|
import eu.dnetlib.xml.database.XMLDatabase;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* eXist database wrapper.
|
||||||
|
*
|
||||||
|
* @author marko
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class ExistDatabase implements XMLDatabase, Lifecycle { // NOPMD by marko
|
||||||
|
|
||||||
|
/**
|
||||||
|
* logger.
|
||||||
|
*/
|
||||||
|
private static final Log log = LogFactory.getLog(ExistDatabase.class); // NOPMD
|
||||||
|
|
||||||
|
/**
|
||||||
|
* eXist collection configuration special file.
|
||||||
|
*/
|
||||||
|
public static final String COLLECTION_XCONF = "collection.xconf";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* exist xml resource type code.
|
||||||
|
*/
|
||||||
|
private static final String XMLRESOURCE = "XMLResource";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* collection name to trigger instance map.
|
||||||
|
*
|
||||||
|
* all triggers declared here will be registered at startup.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
private Map<String, Trigger> triggerConf = new HashMap<>();
|
||||||
|
|
||||||
|
private final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
|
||||||
|
|
||||||
|
private final Lock readLock = rwl.readLock();
|
||||||
|
|
||||||
|
private final Lock writeLock = rwl.writeLock();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* eXist database.
|
||||||
|
*/
|
||||||
|
private Database database;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* eXist collection.
|
||||||
|
*/
|
||||||
|
private Collection root;
|
||||||
|
/**
|
||||||
|
* eXist database manager.
|
||||||
|
*/
|
||||||
|
private DatabaseInstanceManager manager;
|
||||||
|
/**
|
||||||
|
* eXist xpath service.
|
||||||
|
*/
|
||||||
|
private XPathQueryService queryService;
|
||||||
|
/**
|
||||||
|
* eXist collection manager.
|
||||||
|
*/
|
||||||
|
private CollectionManagementService colman;
|
||||||
|
/**
|
||||||
|
* eXist configuration file.
|
||||||
|
*/
|
||||||
|
private String configFile;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Directory in which backups are saved.
|
||||||
|
*/
|
||||||
|
private String backupDir;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*
|
||||||
|
* @see org.springframework.context.Lifecycle#start()
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void start() {
|
||||||
|
log.info("starting database");
|
||||||
|
try {
|
||||||
|
if (getDatabase() == null) {
|
||||||
|
setDatabase(new DatabaseImpl());
|
||||||
|
getDatabase().setProperty("configuration", getConfigFile());
|
||||||
|
getDatabase().setProperty("create-database", "true");
|
||||||
|
}
|
||||||
|
|
||||||
|
DatabaseManager.registerDatabase(getDatabase());
|
||||||
|
|
||||||
|
setRoot(DatabaseManager.getCollection("xmldb:exist://" + getRootCollection(), "admin", ""));
|
||||||
|
setManager((DatabaseInstanceManager) getRoot().getService("DatabaseInstanceManager", "1.0"));
|
||||||
|
setQueryService((XPathQueryService) getRoot().getService("XPathQueryService", "1.0"));
|
||||||
|
setColman((CollectionManagementService) getRoot().getService("CollectionManagementService", "1.0"));
|
||||||
|
|
||||||
|
for (final Entry<String, Trigger> entry : getTriggerConf().entrySet())
|
||||||
|
registerTrigger(entry.getValue(), entry.getKey());
|
||||||
|
|
||||||
|
} catch (final XMLDBException e) {
|
||||||
|
throw new IllegalStateException("cannot open eXist database", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* helper method.
|
||||||
|
*
|
||||||
|
* @param collection
|
||||||
|
* collection name
|
||||||
|
* @return an eXist collection
|
||||||
|
* @throws XMLDBException
|
||||||
|
* happens
|
||||||
|
*/
|
||||||
|
protected Collection getCollection(final String collection) throws XMLDBException {
|
||||||
|
readLock.lock();
|
||||||
|
try {
|
||||||
|
if (!collection.startsWith("/db"))
|
||||||
|
throw new XMLDBException(0, "collection path should begin with /db");
|
||||||
|
return database.getCollection("exist://" + collection, "admin", "");
|
||||||
|
}finally {
|
||||||
|
readLock.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*
|
||||||
|
* @see eu.dnetlib.xml.database.XMLDatabase#create(java.lang.String, java.lang.String, java.lang.String)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void create(final String name, final String collection, final String content) throws XMLDBException {
|
||||||
|
writeLock.lock();
|
||||||
|
try {
|
||||||
|
if ("".equals(name))
|
||||||
|
throw new XMLDBException(0, "cannot create a xml file with an empty file name");
|
||||||
|
|
||||||
|
Collection col = getCollection(collection);
|
||||||
|
|
||||||
|
if (col == null) {
|
||||||
|
// create parent collections
|
||||||
|
createCollection(collection, true);
|
||||||
|
col = getCollection(collection);
|
||||||
|
}
|
||||||
|
|
||||||
|
final Resource res = col.createResource(name, XMLRESOURCE);
|
||||||
|
res.setContent(content);
|
||||||
|
col.storeResource(res);
|
||||||
|
|
||||||
|
((EXistResource) res).freeResources();
|
||||||
|
col.close();
|
||||||
|
}finally {
|
||||||
|
writeLock.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*
|
||||||
|
* @see eu.dnetlib.xml.database.XMLDatabase#remove(java.lang.String, java.lang.String)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean remove(final String name, final String collection) throws XMLDBException {
|
||||||
|
writeLock.lock();
|
||||||
|
try {
|
||||||
|
final Collection col = getCollection(collection);
|
||||||
|
|
||||||
|
final Resource res = col.getResource(name);
|
||||||
|
if (res == null)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
col.removeResource(res);
|
||||||
|
col.close();
|
||||||
|
return true;
|
||||||
|
} finally {
|
||||||
|
writeLock.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*
|
||||||
|
* @see eu.dnetlib.xml.database.XMLDatabase#update(java.lang.String, java.lang.String, java.lang.String)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void update(final String name, final String collection, final String content) throws XMLDBException {
|
||||||
|
writeLock.lock();
|
||||||
|
try{
|
||||||
|
final Collection col = getCollection(collection);
|
||||||
|
|
||||||
|
final Resource res = col.getResource(name);
|
||||||
|
if (res == null) {
|
||||||
|
throw new XMLDBException(0, "resource doesn't exist");
|
||||||
|
}
|
||||||
|
res.setContent(content);
|
||||||
|
col.storeResource(res);
|
||||||
|
((EXistResource) res).freeResources();
|
||||||
|
col.close();
|
||||||
|
} finally {
|
||||||
|
writeLock.unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*
|
||||||
|
* @see eu.dnetlib.xml.database.XMLDatabase#read(java.lang.String, java.lang.String)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String read(final String name, final String collection) throws XMLDBException {
|
||||||
|
readLock.lock();
|
||||||
|
try {
|
||||||
|
Resource res = null;
|
||||||
|
final Collection coll = getCollection(collection);
|
||||||
|
try {
|
||||||
|
if (coll == null)
|
||||||
|
return null;
|
||||||
|
res = coll.getResource(name);
|
||||||
|
if (res != null)
|
||||||
|
return (String) res.getContent();
|
||||||
|
return null;
|
||||||
|
} finally {
|
||||||
|
if (res != null)
|
||||||
|
((EXistResource) res).freeResources();
|
||||||
|
coll.close();
|
||||||
|
}
|
||||||
|
}finally {
|
||||||
|
readLock.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*
|
||||||
|
* @see eu.dnetlib.xml.database.XMLDatabase#xquery(java.lang.String)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public Iterator<String> xquery(final String query) throws XMLDBException {
|
||||||
|
readLock.lock();
|
||||||
|
try {
|
||||||
|
final ResourceSet result = getQueryService().query(query);
|
||||||
|
if (result == null)
|
||||||
|
return null;
|
||||||
|
final ResourceIterator iterator = result.getIterator();
|
||||||
|
return new Iterator<String>() {
|
||||||
|
@Override
|
||||||
|
public boolean hasNext() {
|
||||||
|
try {
|
||||||
|
return iterator.hasMoreResources();
|
||||||
|
} catch (XMLDBException e) {
|
||||||
|
throw new RuntimeException("Error while getting next element", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String next() {
|
||||||
|
Resource res = null;
|
||||||
|
try {
|
||||||
|
res = iterator.nextResource();
|
||||||
|
return (String) res.getContent();
|
||||||
|
} catch (XMLDBException e) {
|
||||||
|
throw new RuntimeException("Error while getting next element", e);
|
||||||
|
} finally {
|
||||||
|
if (res != null)
|
||||||
|
try {
|
||||||
|
((EXistResource) res).freeResources();
|
||||||
|
} catch (XMLDBException e) {
|
||||||
|
log.error("error on free resource");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} finally {
|
||||||
|
readLock.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void xupdate(final String query) throws XMLDBException {
|
||||||
|
writeLock.lock();
|
||||||
|
try{
|
||||||
|
getQueryService().query(query);
|
||||||
|
} finally {
|
||||||
|
writeLock.unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*
|
||||||
|
* @see org.springframework.context.Lifecycle#stop()
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void stop() {
|
||||||
|
// no operation
|
||||||
|
try {
|
||||||
|
getManager().shutdown();
|
||||||
|
DatabaseManager.deregisterDatabase(database);
|
||||||
|
} catch (final XMLDBException e) {
|
||||||
|
log.fatal("cannot close database", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*
|
||||||
|
* @see eu.dnetlib.xml.database.XMLDatabase#collectionExists(java.lang.String)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean collectionExists(final String collection) throws XMLDBException {
|
||||||
|
Collection col = null;
|
||||||
|
try{
|
||||||
|
col = getCollection(collection);
|
||||||
|
return col != null;
|
||||||
|
} finally {
|
||||||
|
if (col!=null)
|
||||||
|
col.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*
|
||||||
|
* @see eu.dnetlib.xml.database.XMLDatabase#createCollection(java.lang.String)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void createCollection(final String collection) throws XMLDBException {
|
||||||
|
writeLock.lock();
|
||||||
|
try {
|
||||||
|
createCollection(collection, false);
|
||||||
|
}finally {
|
||||||
|
writeLock.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private void createCollection(final String collection, final boolean recursive) throws XMLDBException {
|
||||||
|
if (recursive) {
|
||||||
|
final XmldbURI uri = XmldbURI.create(collection).removeLastSegment();
|
||||||
|
if (!collectionExists(uri.toString()))
|
||||||
|
createCollection(uri.toString(), true);
|
||||||
|
}
|
||||||
|
getColman().createCollection(collection);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*
|
||||||
|
* @see eu.dnetlib.xml.database.XMLDatabase#removeCollection(java.lang.String)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void removeCollection(final String collection) throws XMLDBException {
|
||||||
|
writeLock.lock();
|
||||||
|
try {
|
||||||
|
getColman().removeCollection(collection);
|
||||||
|
}finally {
|
||||||
|
writeLock.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getConfigFile() {
|
||||||
|
return configFile;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setConfigFile(final String configFile) {
|
||||||
|
this.configFile = configFile;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getBackupDir() {
|
||||||
|
return backupDir;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Required
|
||||||
|
public void setBackupDir(final String backupDir) {
|
||||||
|
this.backupDir = backupDir;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*
|
||||||
|
* @see org.springframework.context.Lifecycle#isRunning() useless contract with spring.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean isRunning() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Database getDatabase() {
|
||||||
|
return database;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void setDatabase(final Database database) {
|
||||||
|
this.database = database;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Collection getRoot() {
|
||||||
|
return root;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void setRoot(final Collection root) {
|
||||||
|
this.root = root;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected DatabaseInstanceManager getManager() {
|
||||||
|
return manager;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void setManager(final DatabaseInstanceManager manager) {
|
||||||
|
this.manager = manager;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected XPathQueryService getQueryService() {
|
||||||
|
return queryService;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void setQueryService(final XPathQueryService queryService) {
|
||||||
|
this.queryService = queryService;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected CollectionManagementService getColman() {
|
||||||
|
return colman;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void setColman(final CollectionManagementService colman) {
|
||||||
|
this.colman = colman;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getRootCollection() {
|
||||||
|
return "/db";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*
|
||||||
|
* @see eu.dnetlib.xml.database.XMLDatabase#listChildCollections(java.lang.String)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public List<String> listChildCollections(final String collection) throws XMLDBException {
|
||||||
|
readLock.lock();
|
||||||
|
try {
|
||||||
|
final Collection col = getCollection(collection);
|
||||||
|
if (col == null)
|
||||||
|
return new ArrayList<>();
|
||||||
|
return Arrays.asList(col.listChildCollections());
|
||||||
|
} finally {
|
||||||
|
readLock.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*
|
||||||
|
* @see eu.dnetlib.xml.database.XMLDatabase#list(java.lang.String)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public List<String> list(final String collection) throws XMLDBException {
|
||||||
|
readLock.lock();
|
||||||
|
try {
|
||||||
|
final Collection col = getCollection(collection);
|
||||||
|
if(col == null)
|
||||||
|
return new ArrayList();
|
||||||
|
return Arrays.asList(col.listResources());
|
||||||
|
} finally {
|
||||||
|
readLock.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* sets an underlying eXist trigger class for a given collection.
|
||||||
|
*
|
||||||
|
* @param triggerClass
|
||||||
|
* exist trigger class
|
||||||
|
* @param collection
|
||||||
|
* collection name
|
||||||
|
* @param events
|
||||||
|
* list of event names
|
||||||
|
* @param parameters
|
||||||
|
* parameter map
|
||||||
|
* @throws XMLDBException
|
||||||
|
* happens
|
||||||
|
*/
|
||||||
|
void setExistTrigger(final Class<?> triggerClass, final String collection, final List<String> events, final Map<String, String> parameters)
|
||||||
|
throws XMLDBException {
|
||||||
|
|
||||||
|
// Arrays.asList(new String[] { "store", "update", "delete" }
|
||||||
|
|
||||||
|
final StringBuilder conf = new StringBuilder();
|
||||||
|
conf.append("<exist:collection xmlns:exist=\"http://exist-db.org/collection-config/1.0\"><exist:triggers>");
|
||||||
|
|
||||||
|
final String className = triggerClass.getCanonicalName(); // PMD
|
||||||
|
|
||||||
|
conf.append("<exist:trigger event=\"store,update,remove\" class=\"" + className + "\">");
|
||||||
|
if (parameters != null)
|
||||||
|
for (final Entry<String, String> entry : parameters.entrySet())
|
||||||
|
conf.append("<exist:parameter name=\"" + entry.getKey() + "\" value=\"" + entry.getValue() + "\"/>");
|
||||||
|
conf.append("</exist:trigger>");
|
||||||
|
|
||||||
|
conf.append("</exist:triggers></exist:collection>");
|
||||||
|
|
||||||
|
log.info(conf.toString());
|
||||||
|
createCollection("/db/system/config" + collection, true);
|
||||||
|
create(CollectionConfiguration.DEFAULT_COLLECTION_CONFIG_FILE_URI.toString(), "/db/system/config" + collection, conf.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*
|
||||||
|
* @see eu.dnetlib.xml.database.XMLDatabase#registerTrigger(eu.dnetlib.xml.database.Trigger, java.lang.String)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void registerTrigger(final Trigger trigger, final String collection) throws XMLDBException {
|
||||||
|
final Map<String, String> params = new HashMap<String, String>();
|
||||||
|
params.put("triggerName", trigger.getName());
|
||||||
|
|
||||||
|
ExistTriggerRegistry.defaultInstance().registerTrigger(trigger.getName(), trigger);
|
||||||
|
|
||||||
|
setExistTrigger(DelegatingDiffTrigger.class, collection, Arrays.asList("store", "update", "delete" ), params);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<String, Trigger> getTriggerConf() {
|
||||||
|
return triggerConf;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTriggerConf(final Map<String, Trigger> triggerConf) {
|
||||||
|
this.triggerConf = triggerConf;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*
|
||||||
|
* @see eu.dnetlib.xml.database.XMLDatabase#backup()
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String backup() throws XMLDBException, DatabaseConfigurationException {
|
||||||
|
log.info("Starting backup...");
|
||||||
|
readLock.lock();
|
||||||
|
try {
|
||||||
|
verifyBackupDir();
|
||||||
|
|
||||||
|
String seq = (new SimpleDateFormat("yyyyMMdd-HHmm")).format(new Date());
|
||||||
|
|
||||||
|
ZipOutputStream zip = new ZipOutputStream(new FileOutputStream(backupDir + "/data-" + seq + ".zip"));
|
||||||
|
|
||||||
|
FileWriter logFile = new FileWriter(backupDir + "/report-" + seq + ".log");
|
||||||
|
logFile.write("Backup started at: " + DateUtils.now_ISO8601() + "\n\n");
|
||||||
|
|
||||||
|
backup(getRoot().getName(), zip, logFile);
|
||||||
|
|
||||||
|
logFile.write("\nBackup finished at: " + DateUtils.now_ISO8601() + "\n");
|
||||||
|
|
||||||
|
logFile.flush();
|
||||||
|
logFile.close();
|
||||||
|
|
||||||
|
zip.flush();
|
||||||
|
zip.close();
|
||||||
|
|
||||||
|
log.info("Backup finished");
|
||||||
|
return backupDir;
|
||||||
|
} catch (final Exception e) {
|
||||||
|
log.error("Backup failed", e);
|
||||||
|
throw new XMLDBException(0, "cannot backup", e);
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
readLock.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void verifyBackupDir() {
|
||||||
|
File d = new File(backupDir);
|
||||||
|
if (!d.exists()) d.mkdirs();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void backup(String coll, ZipOutputStream zip, FileWriter logFile) throws XMLDBException, IOException {
|
||||||
|
readLock.lock();
|
||||||
|
logFile.write("COLLECTION: " + coll + "\n");
|
||||||
|
log.info("Backup of collection " + coll);
|
||||||
|
try {
|
||||||
|
for (String file : list(coll)) {
|
||||||
|
zip.putNextEntry(new ZipEntry(coll + "/" + file + ".xml"));
|
||||||
|
Resource resource = getCollection(coll).getResource(file);
|
||||||
|
zip.write(resource.getContent().toString().getBytes());
|
||||||
|
zip.closeEntry();
|
||||||
|
}
|
||||||
|
|
||||||
|
for (String c : listChildCollections(coll)) {
|
||||||
|
backup(coll + "/" + c, zip, logFile);
|
||||||
|
}
|
||||||
|
}finally {
|
||||||
|
readLock.unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,72 @@
|
||||||
|
package eu.dnetlib.xml.database.exist;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import eu.dnetlib.xml.database.Trigger;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* eXist triggers are instantiated directly by the exist database via reflection.
|
||||||
|
*
|
||||||
|
* we need a way to manage trigger objects from outside, in order to manage them manage them from the IoC container.
|
||||||
|
*
|
||||||
|
* @author marko
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public final class ExistTriggerRegistry {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* singleton object.
|
||||||
|
*/
|
||||||
|
private static ExistTriggerRegistry singleton = new ExistTriggerRegistry();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get the singleton instance.
|
||||||
|
*
|
||||||
|
* @return singleton object
|
||||||
|
*/
|
||||||
|
public static ExistTriggerRegistry defaultInstance() {
|
||||||
|
return singleton;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* forbids instantiation.
|
||||||
|
*/
|
||||||
|
private ExistTriggerRegistry() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* maps trigger names to trigger instances.
|
||||||
|
*/
|
||||||
|
private Map<String, Trigger> triggerRegistry = new HashMap<String, Trigger>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get a trigger for a given id.
|
||||||
|
*
|
||||||
|
* @param triggerId trigger identifier
|
||||||
|
* @return trigger instance
|
||||||
|
*/
|
||||||
|
public Trigger getTrigger(final String triggerId) {
|
||||||
|
return getTriggerRegistry().get(triggerId);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* associate a new trigger.
|
||||||
|
*
|
||||||
|
* @param name trigger name
|
||||||
|
* @param trigger trigger instance
|
||||||
|
*/
|
||||||
|
public void registerTrigger(final String name, final Trigger trigger) {
|
||||||
|
triggerRegistry.put(name, trigger);
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, Trigger> getTriggerRegistry() {
|
||||||
|
return triggerRegistry;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setTriggerRegistry(final Map<String, Trigger> triggerRegistry) {
|
||||||
|
this.triggerRegistry = triggerRegistry;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,60 @@
|
||||||
|
package eu.dnetlib.xml.database.exist;
|
||||||
|
|
||||||
|
import org.w3c.dom.Document;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by sandro on 3/14/16.
|
||||||
|
*/
|
||||||
|
public class ExistsTriggerEvent {
|
||||||
|
|
||||||
|
private String collection;
|
||||||
|
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
private EventType eventType;
|
||||||
|
|
||||||
|
private Document document;
|
||||||
|
|
||||||
|
private Document oldDocument;
|
||||||
|
|
||||||
|
|
||||||
|
public String getCollection() {
|
||||||
|
return collection;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCollection(final String collection) {
|
||||||
|
this.collection = collection;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(final String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public EventType getEventType() {
|
||||||
|
return eventType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEventType(final EventType eventType) {
|
||||||
|
this.eventType = eventType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Document getDocument() {
|
||||||
|
return document;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDocument(final Document document) {
|
||||||
|
this.document = document;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Document getOldDocument() {
|
||||||
|
return oldDocument;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setOldDocument(final Document oldDocument) {
|
||||||
|
this.oldDocument = oldDocument;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,207 @@
|
||||||
|
package eu.dnetlib.xml.database.exist;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.FileReader;
|
||||||
|
import java.io.FileWriter;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.StringReader;
|
||||||
|
import java.io.StringWriter;
|
||||||
|
|
||||||
|
import eu.dnetlib.enabling.is.store.BulkResourceImporter;
|
||||||
|
import org.apache.commons.io.IOUtils;
|
||||||
|
import org.apache.commons.logging.Log;
|
||||||
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.beans.factory.annotation.Required;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Persistent exist.
|
||||||
|
*
|
||||||
|
* TODO: this is copy&paste from TemporaryExistDatase. Refactor common stuff.
|
||||||
|
*
|
||||||
|
* @author marko
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class PersistentExistDatabase extends ExistDatabase {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* logger.
|
||||||
|
*/
|
||||||
|
private static final Log log = LogFactory.getLog(PersistentExistDatabase.class); // NOPMD by marko on 11/24/08 5:02 PM
|
||||||
|
|
||||||
|
/**
|
||||||
|
* db directory.
|
||||||
|
*/
|
||||||
|
private transient File dbDirectory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* this config file will be copied to a newly created temporary directory.
|
||||||
|
*/
|
||||||
|
private String configTemplate = "default-exist-conf.xml";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* db root path.
|
||||||
|
*/
|
||||||
|
private String dbRootPath;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* bulk importer.
|
||||||
|
*/
|
||||||
|
@Autowired
|
||||||
|
private BulkResourceImporter bulkImporter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* exist config file.
|
||||||
|
*/
|
||||||
|
private File existConfigFile;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* true if the database permits execution of java code from xquery.
|
||||||
|
*/
|
||||||
|
private boolean XQueryJavaEnabled;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*
|
||||||
|
* @see eu.dnetlib.xml.database.exist.ExistDatabase#start()
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void start() {
|
||||||
|
log.warn("STARTING PERSISTENT EXIST DATABASE");
|
||||||
|
dbDirectory = new File(dbRootPath);
|
||||||
|
|
||||||
|
if (dbDirectory.exists()) {
|
||||||
|
getBulkImporter().setEnabled(false);
|
||||||
|
existConfigFile = new File(dbDirectory, "conf.xml");
|
||||||
|
enableJava(existConfigFile, isXQueryJavaEnabled());
|
||||||
|
setConfigFile(existConfigFile.getAbsolutePath());
|
||||||
|
} else {
|
||||||
|
createPersistentDatabase();
|
||||||
|
}
|
||||||
|
|
||||||
|
super.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void stop() {
|
||||||
|
log.info("shutting down xmldb");
|
||||||
|
super.stop();
|
||||||
|
log.info("xmldb closed");
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void enableJava(final File conf, final boolean enabled) {
|
||||||
|
final StringWriter buffer = new StringWriter();
|
||||||
|
if (conf.exists()) {
|
||||||
|
try {
|
||||||
|
IOUtils.copy(new FileReader(conf), buffer);
|
||||||
|
final String newConf = patchConfigFileEnableJava(buffer.toString(), enabled);
|
||||||
|
if (!newConf.equals(buffer.toString())) {
|
||||||
|
FileWriter writer = new FileWriter(conf);
|
||||||
|
try {
|
||||||
|
IOUtils.copy(new StringReader(newConf), writer);
|
||||||
|
} finally {
|
||||||
|
writer.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (final FileNotFoundException e) {
|
||||||
|
log.warn("cannot patch eXist conf file", e);
|
||||||
|
} catch (final IOException e) {
|
||||||
|
log.warn("cannot patch eXist conf file", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param conf
|
||||||
|
* content of the configuration file
|
||||||
|
* @param enabled
|
||||||
|
* enabled or disabled
|
||||||
|
* @return new conf file
|
||||||
|
*/
|
||||||
|
protected String patchConfigFileEnableJava(final String conf, final boolean enabled) {
|
||||||
|
return conf.replaceAll("enable-java-binding=\"[^\"]*\"", "enable-java-binding=\"" + (enabled ? "yes" : "no") + "\"");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* create a temporary directory and copy the default configuration file.
|
||||||
|
*/
|
||||||
|
protected void createPersistentDatabase() {
|
||||||
|
log.debug("creating persistent database");
|
||||||
|
try {
|
||||||
|
new File(dbDirectory, "data").mkdirs();
|
||||||
|
|
||||||
|
final InputStream defaultConf = getClass().getResourceAsStream(getConfigTemplate());
|
||||||
|
if (defaultConf == null)
|
||||||
|
throw new IOException("cannot find " + getConfigTemplate());
|
||||||
|
|
||||||
|
existConfigFile = new File(dbDirectory, "conf.xml");
|
||||||
|
final FileOutputStream confOutput = new FileOutputStream(existConfigFile);
|
||||||
|
|
||||||
|
try {
|
||||||
|
IOUtils.copy(defaultConf, confOutput);
|
||||||
|
} finally {
|
||||||
|
confOutput.close();
|
||||||
|
}
|
||||||
|
enableJava(existConfigFile, isXQueryJavaEnabled());
|
||||||
|
|
||||||
|
setConfigFile(existConfigFile.getAbsolutePath());
|
||||||
|
} catch (final IOException e) {
|
||||||
|
log.fatal("creating database dir", e);
|
||||||
|
throw new IllegalStateException(e);
|
||||||
|
}
|
||||||
|
log.debug("created temp database");
|
||||||
|
}
|
||||||
|
|
||||||
|
public File getDbDirectory() {
|
||||||
|
return dbDirectory;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDbDirectory(final File dbDirectory) {
|
||||||
|
this.dbDirectory = dbDirectory;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getConfigTemplate() {
|
||||||
|
return configTemplate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setConfigTemplate(final String configTemplate) {
|
||||||
|
this.configTemplate = configTemplate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BulkResourceImporter getBulkImporter() {
|
||||||
|
return bulkImporter;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setBulkImporter(final BulkResourceImporter bulkImporter) {
|
||||||
|
this.bulkImporter = bulkImporter;
|
||||||
|
}
|
||||||
|
|
||||||
|
public File getExistConfigFile() {
|
||||||
|
return existConfigFile;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setExistConfigFile(final File existConfigFile) {
|
||||||
|
this.existConfigFile = existConfigFile;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Required
|
||||||
|
public String getDbRootPath() {
|
||||||
|
return dbRootPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDbRootPath(final String dbRootPath) {
|
||||||
|
this.dbRootPath = dbRootPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isXQueryJavaEnabled() {
|
||||||
|
return XQueryJavaEnabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setXQueryJavaEnabled(final boolean xQueryJavaEnabled) {
|
||||||
|
XQueryJavaEnabled = xQueryJavaEnabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,106 @@
|
||||||
|
package eu.dnetlib.xml.database.exist;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
|
||||||
|
import org.apache.commons.io.FileUtils;
|
||||||
|
import org.apache.commons.io.IOUtils;
|
||||||
|
import org.apache.commons.logging.Log;
|
||||||
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class creates a temporary exist database instances.
|
||||||
|
*
|
||||||
|
* @author marko
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class TemporaryExistDatabase extends ExistDatabase {
|
||||||
|
/**
|
||||||
|
* logger.
|
||||||
|
*/
|
||||||
|
private static final Log log = LogFactory.getLog(TemporaryExistDatabase.class); // NOPMD by marko on 11/24/08 5:02 PM
|
||||||
|
|
||||||
|
/**
|
||||||
|
* temporary directory. this way we won't delete other things on shutdown if somebody changes the configuration file
|
||||||
|
* location with setConfigFile().
|
||||||
|
*/
|
||||||
|
private transient File tempDirectory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* this config file will be copied to a newly created temporary directory.
|
||||||
|
*/
|
||||||
|
private String configTemplate = "default-exist-conf.xml";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*
|
||||||
|
* @see eu.dnetlib.xml.database.exist.ExistDatabase#start()
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void start() {
|
||||||
|
log.warn("STARTING TEMPORARY EXIST DATABASE");
|
||||||
|
createTemporaryDatabase();
|
||||||
|
super.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*
|
||||||
|
* @see eu.dnetlib.xml.database.exist.ExistDatabase#stop()
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void stop() {
|
||||||
|
super.stop();
|
||||||
|
try {
|
||||||
|
FileUtils.deleteDirectory(tempDirectory);
|
||||||
|
} catch (IOException e) {
|
||||||
|
log.fatal("cannot delete temporary exist directory", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* create a temporary directory and copy the default configuration file.
|
||||||
|
*/
|
||||||
|
protected void createTemporaryDatabase() {
|
||||||
|
log.debug("creating temp database");
|
||||||
|
try {
|
||||||
|
File tmpName;
|
||||||
|
tmpName = File.createTempFile("exist", "");
|
||||||
|
|
||||||
|
tmpName.delete();
|
||||||
|
|
||||||
|
tempDirectory = new File(tmpName.getAbsolutePath());
|
||||||
|
new File(tempDirectory, "data").mkdirs();
|
||||||
|
|
||||||
|
final InputStream defaultConf = getClass().getResourceAsStream(getConfigTemplate());
|
||||||
|
if (defaultConf == null)
|
||||||
|
throw new IOException("cannot find " + getConfigTemplate());
|
||||||
|
|
||||||
|
final File existConfigFile = new File(tempDirectory, "conf.xml");
|
||||||
|
final FileOutputStream confOutput = new FileOutputStream(existConfigFile);
|
||||||
|
|
||||||
|
try {
|
||||||
|
IOUtils.copy(defaultConf, confOutput);
|
||||||
|
} finally {
|
||||||
|
confOutput.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
setConfigFile(existConfigFile.getAbsolutePath());
|
||||||
|
} catch (IOException e) {
|
||||||
|
log.fatal("creating database dir", e);
|
||||||
|
throw new IllegalStateException(e);
|
||||||
|
}
|
||||||
|
log.debug("created temp database");
|
||||||
|
}
|
||||||
|
|
||||||
|
protected String getConfigTemplate() {
|
||||||
|
return configTemplate;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void setConfigTemplate(final String configTemplate) {
|
||||||
|
this.configTemplate = configTemplate;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,264 @@
|
||||||
|
package org.hibernate.dialect;
|
||||||
|
|
||||||
|
import java.sql.SQLException;
|
||||||
|
import java.sql.Types;
|
||||||
|
|
||||||
|
import org.hibernate.dialect.function.*;
|
||||||
|
import org.hibernate.exception.*;
|
||||||
|
import org.hibernate.exception.spi.SQLExceptionConverter;
|
||||||
|
import org.hibernate.exception.spi.TemplatedViolatedConstraintNameExtracter;
|
||||||
|
import org.hibernate.exception.spi.ViolatedConstraintNameExtracter;
|
||||||
|
import org.hibernate.internal.util.JdbcExceptionHelper;
|
||||||
|
import org.hibernate.type.StandardBasicTypes;
|
||||||
|
|
||||||
|
public class SQLiteDialect extends Dialect {
|
||||||
|
|
||||||
|
public SQLiteDialect() {
|
||||||
|
registerColumnType(Types.BIT, "boolean");
|
||||||
|
registerColumnType(Types.TINYINT, "tinyint");
|
||||||
|
registerColumnType(Types.SMALLINT, "smallint");
|
||||||
|
registerColumnType(Types.INTEGER, "integer");
|
||||||
|
registerColumnType(Types.BIGINT, "bigint");
|
||||||
|
registerColumnType(Types.FLOAT, "float");
|
||||||
|
registerColumnType(Types.REAL, "real");
|
||||||
|
registerColumnType(Types.DOUBLE, "double");
|
||||||
|
registerColumnType(Types.NUMERIC, "numeric($p, $s)");
|
||||||
|
registerColumnType(Types.DECIMAL, "decimal");
|
||||||
|
registerColumnType(Types.CHAR, "char");
|
||||||
|
registerColumnType(Types.VARCHAR, "varchar($l)");
|
||||||
|
registerColumnType(Types.LONGVARCHAR, "longvarchar");
|
||||||
|
registerColumnType(Types.DATE, "date");
|
||||||
|
registerColumnType(Types.TIME, "time");
|
||||||
|
registerColumnType(Types.TIMESTAMP, "datetime");
|
||||||
|
registerColumnType(Types.BINARY, "blob");
|
||||||
|
registerColumnType(Types.VARBINARY, "blob");
|
||||||
|
registerColumnType(Types.LONGVARBINARY, "blob");
|
||||||
|
registerColumnType(Types.BLOB, "blob");
|
||||||
|
registerColumnType(Types.CLOB, "clob");
|
||||||
|
registerColumnType(Types.BOOLEAN, "boolean");
|
||||||
|
|
||||||
|
registerFunction("concat", new VarArgsSQLFunction(StandardBasicTypes.STRING, "", "||", ""));
|
||||||
|
registerFunction("mod", new SQLFunctionTemplate(StandardBasicTypes.INTEGER, "?1 % ?2"));
|
||||||
|
registerFunction("quote", new StandardSQLFunction("quote", StandardBasicTypes.STRING));
|
||||||
|
registerFunction("random", new NoArgSQLFunction("random", StandardBasicTypes.INTEGER));
|
||||||
|
registerFunction("round", new StandardSQLFunction("round"));
|
||||||
|
registerFunction("substr", new StandardSQLFunction("substr", StandardBasicTypes.STRING));
|
||||||
|
registerFunction("trim", new AbstractAnsiTrimEmulationFunction() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected SQLFunction resolveBothSpaceTrimFunction() {
|
||||||
|
return new SQLFunctionTemplate(StandardBasicTypes.STRING, "trim(?1)");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected SQLFunction resolveBothSpaceTrimFromFunction() {
|
||||||
|
return new SQLFunctionTemplate(StandardBasicTypes.STRING, "trim(?2)");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected SQLFunction resolveLeadingSpaceTrimFunction() {
|
||||||
|
return new SQLFunctionTemplate(StandardBasicTypes.STRING, "ltrim(?1)");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected SQLFunction resolveTrailingSpaceTrimFunction() {
|
||||||
|
return new SQLFunctionTemplate(StandardBasicTypes.STRING, "rtrim(?1)");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected SQLFunction resolveBothTrimFunction() {
|
||||||
|
return new SQLFunctionTemplate(StandardBasicTypes.STRING, "trim(?1, ?2)");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected SQLFunction resolveLeadingTrimFunction() {
|
||||||
|
return new SQLFunctionTemplate(StandardBasicTypes.STRING, "ltrim(?1, ?2)");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected SQLFunction resolveTrailingTrimFunction() {
|
||||||
|
return new SQLFunctionTemplate(StandardBasicTypes.STRING, "rtrim(?1, ?2)");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean supportsIdentityColumns() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* public boolean supportsInsertSelectIdentity() { return true; // As specified in NHibernate dialect }
|
||||||
|
*/
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasDataTypeInIdentityColumn() {
|
||||||
|
return false; // As specified in NHibernate dialect
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* public String appendIdentitySelectToInsert(String insertString) { return new StringBuffer(insertString.length()+30). // As specified
|
||||||
|
* in NHibernate dialect append(insertString). append("; ").append(getIdentitySelectString()). toString(); }
|
||||||
|
*/
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getIdentityColumnString() {
|
||||||
|
// return "integer primary key autoincrement";
|
||||||
|
return "integer";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getIdentitySelectString() {
|
||||||
|
return "select last_insert_rowid()";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean supportsLimit() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean bindLimitParametersInReverseOrder() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String getLimitString(final String query, final boolean hasOffset) {
|
||||||
|
return query + (hasOffset ? " limit ? offset ?" : " limit ?");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean supportsTemporaryTables() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getCreateTemporaryTableString() {
|
||||||
|
return "create temporary table if not exists";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Boolean performTemporaryTableDDLInIsolation() {
|
||||||
|
return Boolean.FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @Override public boolean dropTemporaryTableAfterUse() { return true; // temporary tables are only dropped when the connection is
|
||||||
|
* closed. If the connection is pooled... }
|
||||||
|
*/
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean supportsCurrentTimestampSelection() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isCurrentTimestampSelectStringCallable() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getCurrentTimestampSelectString() {
|
||||||
|
return "select current_timestamp";
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final int SQLITE_BUSY = 5;
|
||||||
|
private static final int SQLITE_LOCKED = 6;
|
||||||
|
private static final int SQLITE_IOERR = 10;
|
||||||
|
private static final int SQLITE_CORRUPT = 11;
|
||||||
|
private static final int SQLITE_NOTFOUND = 12;
|
||||||
|
private static final int SQLITE_FULL = 13;
|
||||||
|
private static final int SQLITE_CANTOPEN = 14;
|
||||||
|
private static final int SQLITE_PROTOCOL = 15;
|
||||||
|
private static final int SQLITE_TOOBIG = 18;
|
||||||
|
private static final int SQLITE_CONSTRAINT = 19;
|
||||||
|
private static final int SQLITE_MISMATCH = 20;
|
||||||
|
private static final int SQLITE_NOTADB = 26;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SQLExceptionConverter buildSQLExceptionConverter() {
|
||||||
|
return (SQLExceptionConverter) (sqlException, message, sql) -> {
|
||||||
|
final int errorCode = JdbcExceptionHelper.extractErrorCode(sqlException);
|
||||||
|
if (errorCode == SQLITE_CONSTRAINT) {
|
||||||
|
final String constraintName = EXTRACTER.extractConstraintName(sqlException);
|
||||||
|
return new ConstraintViolationException(message, sqlException, sql, constraintName);
|
||||||
|
} else if ((errorCode == SQLITE_TOOBIG) || (errorCode == SQLITE_MISMATCH)) return new DataException(message, sqlException, sql);
|
||||||
|
else if ((errorCode == SQLITE_BUSY) || (errorCode == SQLITE_LOCKED)) return new LockAcquisitionException(message, sqlException, sql);
|
||||||
|
else if (((errorCode >= SQLITE_IOERR) && (errorCode <= SQLITE_PROTOCOL)) || (errorCode == SQLITE_NOTADB))
|
||||||
|
return new JDBCConnectionException(message, sqlException, sql);
|
||||||
|
return new GenericJDBCException(message, sqlException, sql);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final ViolatedConstraintNameExtracter EXTRACTER = new TemplatedViolatedConstraintNameExtracter() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String extractConstraintName(final SQLException sqle) {
|
||||||
|
return extractUsingTemplate("constraint ", " failed", sqle.getMessage());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean supportsUnionAll() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasAlterTable() {
|
||||||
|
return false; // As specified in NHibernate dialect
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean dropConstraints() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getAddColumnString() {
|
||||||
|
return "add column";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getForUpdateString() {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean supportsOuterJoinForUpdate() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getDropForeignKeyString() {
|
||||||
|
throw new UnsupportedOperationException("No drop foreign key syntax supported by SQLiteDialect");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getAddForeignKeyConstraintString(final String constraintName,
|
||||||
|
final String[] foreignKey,
|
||||||
|
final String referencedTable,
|
||||||
|
final String[] primaryKey,
|
||||||
|
final boolean referencesPrimaryKey) {
|
||||||
|
throw new UnsupportedOperationException("No add foreign key syntax supported by SQLiteDialect");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getAddPrimaryKeyConstraintString(final String constraintName) {
|
||||||
|
throw new UnsupportedOperationException("No add primary key syntax supported by SQLiteDialect");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean supportsIfExistsBeforeTableName() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean supportsTupleDistinctCounts() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getSelectGUIDString() {
|
||||||
|
return "select hex(randomblob(16))";
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,54 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jaxws="http://cxf.apache.org/jaxws"
|
||||||
|
xmlns:sec="http://cxf.apache.org/configuration/security" xmlns:wsa="http://cxf.apache.org/ws/addressing"
|
||||||
|
xmlns:p="http://www.springframework.org/schema/p" xmlns:http="http://cxf.apache.org/transports/http/configuration"
|
||||||
|
|
||||||
|
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
|
||||||
|
http://cxf.apache.org/ws/addressing http://cxf.apache.org/schemas/ws-addr-conf.xsd
|
||||||
|
http://cxf.apache.org/configuration/security http://cxf.apache.org/schemas/configuration/security.xsd
|
||||||
|
http://cxf.apache.org/transports/http/configuration http://cxf.apache.org/schemas/configuration/http-conf.xsd
|
||||||
|
http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd">
|
||||||
|
|
||||||
|
<!--
|
||||||
|
common job scheduler. Use SchedulerAccessorBean to add triggers.
|
||||||
|
-->
|
||||||
|
<bean id="jobScheduler"
|
||||||
|
class="org.springframework.scheduling.quartz.SchedulerFactoryBean"
|
||||||
|
destroy-method="destroy">
|
||||||
|
<property name="jobFactory">
|
||||||
|
<bean id="jobSchedulerFactory"
|
||||||
|
class="org.springframework.scheduling.quartz.SpringBeanJobFactory" />
|
||||||
|
</property>
|
||||||
|
</bean>
|
||||||
|
|
||||||
|
<!-- service locators: TODO: parameterize via properties -->
|
||||||
|
<bean id="storeLocator" class="eu.dnetlib.enabling.tools.StaticServiceLocator"
|
||||||
|
p:service-ref="isStoreService" />
|
||||||
|
<bean id="registryLocator" class="eu.dnetlib.enabling.tools.StaticServiceLocator"
|
||||||
|
p:service-ref="isRegistryService" />
|
||||||
|
<bean id="snLocator" class="eu.dnetlib.enabling.tools.StaticServiceLocator"
|
||||||
|
p:service-ref="isSNService" />
|
||||||
|
<bean id="lookupLocator" class="eu.dnetlib.enabling.tools.StaticServiceLocator"
|
||||||
|
p:service-ref="isLookUpService" />
|
||||||
|
<!--
|
||||||
|
<bean id="msroLocator" class="eu.dnetlib.enabling.tools.StaticServiceLocator"
|
||||||
|
p:service-ref="msroService" />
|
||||||
|
|
||||||
|
<bean id="anyIndexLocatorDynamic" class="eu.dnetlib.enabling.tools.DynamicServiceLocator"
|
||||||
|
p:clazz="eu.dnetlib.data.index.IIndexService" p:lookUpLocator-ref="lookupLocator"
|
||||||
|
p:serviceResolver-ref="serviceResolver" />
|
||||||
|
-->
|
||||||
|
<!-- common service resolution chain -->
|
||||||
|
<bean id="serviceResolver" class="eu.dnetlib.enabling.tools.ServiceResolverChain">
|
||||||
|
<property name="resolvers">
|
||||||
|
<list>
|
||||||
|
<bean id="localServiceResolver" class="eu.dnetlib.enabling.tools.LocalServiceResolverImpl"
|
||||||
|
p:baseAddress="${transport.soap.baseAddress}" />
|
||||||
|
<bean id="jaxwsServiceResolver" class="eu.dnetlib.enabling.tools.JaxwsServiceResolverImpl" />
|
||||||
|
</list>
|
||||||
|
</property>
|
||||||
|
</bean>
|
||||||
|
|
||||||
|
<bean id="uuidGenerator" class="eu.dnetlib.enabling.tools.UniqueIdentifierGeneratorImpl" />
|
||||||
|
</beans>
|
|
@ -0,0 +1,29 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jaxws="http://cxf.apache.org/jaxws"
|
||||||
|
xmlns:sec="http://cxf.apache.org/configuration/security" xmlns:wsa="http://cxf.apache.org/ws/addressing"
|
||||||
|
xmlns:p="http://www.springframework.org/schema/p" xmlns:http="http://cxf.apache.org/transports/http/configuration"
|
||||||
|
xmlns:t="http://dnetlib.eu/springbeans/t" xmlns:template="http://dnetlib.eu/springbeans/template"
|
||||||
|
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
|
||||||
|
http://cxf.apache.org/ws/addressing http://cxf.apache.org/schemas/ws-addr-conf.xsd
|
||||||
|
http://cxf.apache.org/configuration/security http://cxf.apache.org/schemas/configuration/security.xsd
|
||||||
|
http://cxf.apache.org/transports/http/configuration http://cxf.apache.org/schemas/configuration/http-conf.xsd
|
||||||
|
http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd
|
||||||
|
http://dnetlib.eu/springbeans/template http://dnetlib.eu/springbeans/template.xsd">
|
||||||
|
|
||||||
|
<!-- beans -->
|
||||||
|
<bean id="isLookUpService" class="eu.dnetlib.enabling.is.lookup.ISLookUpServiceImpl"
|
||||||
|
init-method="start" destroy-method="stop" p:isStore-ref="isStoreService"
|
||||||
|
p:xqueryUtils-ref="xqueryUtils"/>
|
||||||
|
|
||||||
|
<!-- endpoints -->
|
||||||
|
<jaxws:endpoint id="isLookUpServiceEndpoint"
|
||||||
|
implementor="#isLookUpService" implementorClass="eu.dnetlib.enabling.is.lookup.rmi.ISLookUpService"
|
||||||
|
address="/isLookUp" />
|
||||||
|
|
||||||
|
<template:instance name="serviceRegistrationManager"
|
||||||
|
t:serviceRegistrationManagerClass="eu.dnetlib.enabling.tools.registration.ValidatingServiceRegistrationManagerImpl"
|
||||||
|
t:name="isLookUpServiceRegistrationManager" t:service="isLookUpService" t:endpoint="isLookUpServiceEndpoint"
|
||||||
|
t:jobScheduler="jobScheduler"/>
|
||||||
|
|
||||||
|
</beans>
|
|
@ -0,0 +1,245 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!--Sample XML file generated by XMLSpy v2007 sp1 (http://www.altova.com)-->
|
||||||
|
<RESOURCE_PROFILE>
|
||||||
|
<HEADER>
|
||||||
|
<RESOURCE_IDENTIFIER value=""/>
|
||||||
|
<RESOURCE_TYPE value="SystemManagementDSResourceType"/>
|
||||||
|
<RESOURCE_KIND value="SystemManagementDSResources"/>
|
||||||
|
<RESOURCE_URI value="00000000000000000000000000000000000000000"/>
|
||||||
|
<DATE_OF_CREATION value="10/04/2007"/>
|
||||||
|
</HEADER>
|
||||||
|
<BODY>
|
||||||
|
<CONFIGURATION>
|
||||||
|
<NAME>DRIVER Information Space Application</NAME>
|
||||||
|
<MANAGER_SERVICE_ID value="000000000000000000000000000000000000"/>
|
||||||
|
<QoSTHRESHOLDS>
|
||||||
|
</QoSTHRESHOLDS>
|
||||||
|
<MAPPINGS>
|
||||||
|
<MAPPING>
|
||||||
|
<PENDING_TYPOLOGY>PendingRepositoryResources</PENDING_TYPOLOGY>
|
||||||
|
<RESOURCE_KIND>RepositoryServiceResources</RESOURCE_KIND>
|
||||||
|
<RESOURCE_TYPES>
|
||||||
|
<RESOURCE_TYPE>RepositoryServiceResourceType</RESOURCE_TYPE>
|
||||||
|
</RESOURCE_TYPES>
|
||||||
|
</MAPPING>
|
||||||
|
<MAPPING>
|
||||||
|
<PENDING_TYPOLOGY>PendingServiceResources</PENDING_TYPOLOGY>
|
||||||
|
<RESOURCE_KIND>ServiceResources</RESOURCE_KIND>
|
||||||
|
<RESOURCE_TYPES>
|
||||||
|
<RESOURCE_TYPE>IS_StoreServiceResourceType</RESOURCE_TYPE>
|
||||||
|
<RESOURCE_TYPE>IS_SNServiceResourceType</RESOURCE_TYPE>
|
||||||
|
<RESOURCE_TYPE>IS_LookUpServiceResourceType</RESOURCE_TYPE>
|
||||||
|
<RESOURCE_TYPE>IS_UIServiceResourceType</RESOURCE_TYPE>
|
||||||
|
<RESOURCE_TYPE>IS_RegistryServiceResourceType</RESOURCE_TYPE>
|
||||||
|
<RESOURCE_TYPE>MS_RMServiceResourceType</RESOURCE_TYPE>
|
||||||
|
<RESOURCE_TYPE>MS_ROServiceResourceType</RESOURCE_TYPE>
|
||||||
|
<RESOURCE_TYPE>HostingNodeManagerServiceResourceType</RESOURCE_TYPE>
|
||||||
|
<RESOURCE_TYPE>HostingContextManagerServiceResourceType</RESOURCE_TYPE>
|
||||||
|
<RESOURCE_TYPE>MDStoreServiceResourceType</RESOURCE_TYPE>
|
||||||
|
<RESOURCE_TYPE>DepotServiceResourceType</RESOURCE_TYPE>
|
||||||
|
<RESOURCE_TYPE>DataAccessServiceResourceType</RESOURCE_TYPE>
|
||||||
|
<RESOURCE_TYPE>AggregatorServiceResourceType</RESOURCE_TYPE>
|
||||||
|
<RESOURCE_TYPE>HarvestingServiceResourceType</RESOURCE_TYPE>
|
||||||
|
<RESOURCE_TYPE>HarvestingManagerServiceResourceType</RESOURCE_TYPE>
|
||||||
|
<RESOURCE_TYPE>TransformationServiceResourceType</RESOURCE_TYPE>
|
||||||
|
<RESOURCE_TYPE>TransformationManagerServiceResourceType</RESOURCE_TYPE>
|
||||||
|
<RESOURCE_TYPE>TransformationRuleEditorServiceResourceType</RESOURCE_TYPE>
|
||||||
|
<RESOURCE_TYPE>FeatureExtractionServiceResourceType</RESOURCE_TYPE>
|
||||||
|
<RESOURCE_TYPE>IndexServiceResourceType</RESOURCE_TYPE>
|
||||||
|
<RESOURCE_TYPE>BrowseServiceResourceType</RESOURCE_TYPE>
|
||||||
|
<RESOURCE_TYPE>DownloadServiceResourceType</RESOURCE_TYPE>
|
||||||
|
<RESOURCE_TYPE>CS_EngineServiceResourceType</RESOURCE_TYPE>
|
||||||
|
<RESOURCE_TYPE>CS_UIServiceResourceType</RESOURCE_TYPE>
|
||||||
|
<RESOURCE_TYPE>ResultSetServiceResourceType</RESOURCE_TYPE>
|
||||||
|
<RESOURCE_TYPE>OAIServiceResourceType</RESOURCE_TYPE>
|
||||||
|
<RESOURCE_TYPE>A2ServiceResourceType</RESOURCE_TYPE>
|
||||||
|
<RESOURCE_TYPE>ObjectPackagingServiceResourceType</RESOURCE_TYPE>
|
||||||
|
<RESOURCE_TYPE>DLMServiceResourceType</RESOURCE_TYPE>
|
||||||
|
<RESOURCE_TYPE>TextEngineServiceResourceType</RESOURCE_TYPE>
|
||||||
|
<RESOURCE_TYPE>PublisherServiceResourceType</RESOURCE_TYPE>
|
||||||
|
<RESOURCE_TYPE>DriverTesterServiceResourceType</RESOURCE_TYPE>
|
||||||
|
<RESOURCE_TYPE>SearchServiceResourceType</RESOURCE_TYPE>
|
||||||
|
<RESOURCE_TYPE>CollectionServiceResourceType</RESOURCE_TYPE>
|
||||||
|
<RESOURCE_TYPE>CommunityServiceResourceType</RESOURCE_TYPE>
|
||||||
|
<RESOURCE_TYPE>ForumServiceResourceType</RESOURCE_TYPE>
|
||||||
|
<RESOURCE_TYPE>RatingServiceResourceType</RESOURCE_TYPE>
|
||||||
|
<RESOURCE_TYPE>RecommendationServiceResourceType</RESOURCE_TYPE>
|
||||||
|
<RESOURCE_TYPE>UserProfileServiceResourceType</RESOURCE_TYPE>
|
||||||
|
<RESOURCE_TYPE>ValidatorServiceResourceType</RESOURCE_TYPE>
|
||||||
|
<RESOURCE_TYPE>ValidatorUserInterfaceServiceResourceType</RESOURCE_TYPE>
|
||||||
|
<RESOURCE_TYPE>WebInterfaceServiceResourceType</RESOURCE_TYPE>
|
||||||
|
<RESOURCE_TYPE>CitationServiceResourceType</RESOURCE_TYPE>
|
||||||
|
<RESOURCE_TYPE>SimilarityServiceResourceType</RESOURCE_TYPE>
|
||||||
|
<RESOURCE_TYPE>DLMSConnectionServiceResourceType</RESOURCE_TYPE>
|
||||||
|
|
||||||
|
<RESOURCE_TYPE>TagSessionManagerServiceResourceType</RESOURCE_TYPE>
|
||||||
|
<RESOURCE_TYPE>TagStoreServiceResourceType</RESOURCE_TYPE>
|
||||||
|
<RESOURCE_TYPE>PIDBridgeServiceResourceType</RESOURCE_TYPE>
|
||||||
|
<RESOURCE_TYPE>PIDAssignerServiceResourceType</RESOURCE_TYPE>
|
||||||
|
<RESOURCE_TYPE>CleanerServiceResourceType</RESOURCE_TYPE>
|
||||||
|
</RESOURCE_TYPES>
|
||||||
|
</MAPPING>
|
||||||
|
<MAPPING>
|
||||||
|
<PENDING_TYPOLOGY>PendingDSResources</PENDING_TYPOLOGY>
|
||||||
|
<RESOURCE_KIND>DRIVERHostingNodeDSResources</RESOURCE_KIND>
|
||||||
|
<RESOURCE_TYPES>
|
||||||
|
<RESOURCE_TYPE>DRIVERHostingNodeDSResourceType</RESOURCE_TYPE>
|
||||||
|
</RESOURCE_TYPES>
|
||||||
|
</MAPPING>
|
||||||
|
<MAPPING>
|
||||||
|
<PENDING_TYPOLOGY>PendingDSResources</PENDING_TYPOLOGY>
|
||||||
|
<RESOURCE_KIND>UserDSResources</RESOURCE_KIND>
|
||||||
|
<RESOURCE_TYPES>
|
||||||
|
<RESOURCE_TYPE>UserDSResourceType</RESOURCE_TYPE>
|
||||||
|
</RESOURCE_TYPES>
|
||||||
|
</MAPPING>
|
||||||
|
<MAPPING>
|
||||||
|
<PENDING_TYPOLOGY/>
|
||||||
|
<RESOURCE_KIND>CommunityDSResources</RESOURCE_KIND>
|
||||||
|
<RESOURCE_TYPES>
|
||||||
|
<RESOURCE_TYPE>CommunityDSResourceType</RESOURCE_TYPE>
|
||||||
|
</RESOURCE_TYPES>
|
||||||
|
</MAPPING>
|
||||||
|
<MAPPING>
|
||||||
|
<PENDING_TYPOLOGY/>
|
||||||
|
<RESOURCE_KIND>DriverTestDSResources</RESOURCE_KIND>
|
||||||
|
<RESOURCE_TYPES>
|
||||||
|
<RESOURCE_TYPE>DriverTestDSResourceType</RESOURCE_TYPE>
|
||||||
|
</RESOURCE_TYPES>
|
||||||
|
</MAPPING>
|
||||||
|
<MAPPING>
|
||||||
|
<PENDING_TYPOLOGY>PendingDSResources</PENDING_TYPOLOGY>
|
||||||
|
<RESOURCE_KIND>DriverPendingTestDSResources</RESOURCE_KIND>
|
||||||
|
<RESOURCE_TYPES>
|
||||||
|
<RESOURCE_TYPE>DriverPendingTestDSResourceType</RESOURCE_TYPE>
|
||||||
|
</RESOURCE_TYPES>
|
||||||
|
</MAPPING>
|
||||||
|
<MAPPING>
|
||||||
|
<PENDING_TYPOLOGY/>
|
||||||
|
<RESOURCE_KIND>CollectionDSResources</RESOURCE_KIND>
|
||||||
|
<RESOURCE_TYPES>
|
||||||
|
<RESOURCE_TYPE>CollectionDSResourceType</RESOURCE_TYPE>
|
||||||
|
</RESOURCE_TYPES>
|
||||||
|
</MAPPING>
|
||||||
|
<MAPPING>
|
||||||
|
<PENDING_TYPOLOGY/>
|
||||||
|
<RESOURCE_KIND>HarvestingInstanceDSResources</RESOURCE_KIND>
|
||||||
|
<RESOURCE_TYPES>
|
||||||
|
<RESOURCE_TYPE>HarvestingInstanceDSResourceType</RESOURCE_TYPE>
|
||||||
|
</RESOURCE_TYPES>
|
||||||
|
</MAPPING>
|
||||||
|
<MAPPING>
|
||||||
|
<PENDING_TYPOLOGY/>
|
||||||
|
<RESOURCE_KIND>HarvestingDSResources</RESOURCE_KIND>
|
||||||
|
<RESOURCE_TYPES>
|
||||||
|
<RESOURCE_TYPE>HarvestingDSResourceType</RESOURCE_TYPE>
|
||||||
|
</RESOURCE_TYPES>
|
||||||
|
</MAPPING>
|
||||||
|
<MAPPING>
|
||||||
|
<PENDING_TYPOLOGY/>
|
||||||
|
<RESOURCE_KIND>IndexDSResources</RESOURCE_KIND>
|
||||||
|
<RESOURCE_TYPES>
|
||||||
|
<RESOURCE_TYPE>IndexDSResourceType</RESOURCE_TYPE>
|
||||||
|
</RESOURCE_TYPES>
|
||||||
|
</MAPPING>
|
||||||
|
<MAPPING>
|
||||||
|
<PENDING_TYPOLOGY/>
|
||||||
|
<RESOURCE_KIND>MDStoreDSResources</RESOURCE_KIND>
|
||||||
|
<RESOURCE_TYPES>
|
||||||
|
<RESOURCE_TYPE>MDStoreDSResourceType</RESOURCE_TYPE>
|
||||||
|
</RESOURCE_TYPES>
|
||||||
|
</MAPPING>
|
||||||
|
<MAPPING>
|
||||||
|
<PENDING_TYPOLOGY/>
|
||||||
|
<RESOURCE_KIND>StoreDSResources</RESOURCE_KIND>
|
||||||
|
<RESOURCE_TYPES>
|
||||||
|
<RESOURCE_TYPE>StoreDSResourceType</RESOURCE_TYPE>
|
||||||
|
</RESOURCE_TYPES>
|
||||||
|
</MAPPING>
|
||||||
|
<MAPPING>
|
||||||
|
<PENDING_TYPOLOGY/>
|
||||||
|
<RESOURCE_KIND>ResultSetDSResources</RESOURCE_KIND>
|
||||||
|
<RESOURCE_TYPES>
|
||||||
|
<RESOURCE_TYPE>ResultSetDSResourceType</RESOURCE_TYPE>
|
||||||
|
</RESOURCE_TYPES>
|
||||||
|
</MAPPING>
|
||||||
|
<MAPPING>
|
||||||
|
<PENDING_TYPOLOGY/>
|
||||||
|
<RESOURCE_KIND>RecommendationDSResources</RESOURCE_KIND>
|
||||||
|
<RESOURCE_TYPES>
|
||||||
|
<RESOURCE_TYPE>RecommendationResourceType</RESOURCE_TYPE>
|
||||||
|
</RESOURCE_TYPES>
|
||||||
|
</MAPPING>
|
||||||
|
<MAPPING>
|
||||||
|
<PENDING_TYPOLOGY/>
|
||||||
|
<RESOURCE_KIND>TransformationDSResources</RESOURCE_KIND>
|
||||||
|
<RESOURCE_TYPES>
|
||||||
|
<RESOURCE_TYPE>TransformationDSResourceType</RESOURCE_TYPE>
|
||||||
|
</RESOURCE_TYPES>
|
||||||
|
</MAPPING>
|
||||||
|
<MAPPING>
|
||||||
|
<PENDING_TYPOLOGY/>
|
||||||
|
<RESOURCE_KIND>VocabularyDSResources</RESOURCE_KIND>
|
||||||
|
<RESOURCE_TYPES>
|
||||||
|
<RESOURCE_TYPE>VocabularyDSResourceType</RESOURCE_TYPE>
|
||||||
|
</RESOURCE_TYPES>
|
||||||
|
</MAPPING>
|
||||||
|
<MAPPING>
|
||||||
|
<PENDING_TYPOLOGY/>
|
||||||
|
<RESOURCE_KIND>SystemManagementDSResources</RESOURCE_KIND>
|
||||||
|
<RESOURCE_TYPES>
|
||||||
|
<RESOURCE_TYPE>SystemManagementDSResourceType</RESOURCE_TYPE>
|
||||||
|
</RESOURCE_TYPES>
|
||||||
|
</MAPPING>
|
||||||
|
</MAPPINGS>
|
||||||
|
<FIELD_SETTINGS>
|
||||||
|
<FIELD_SETTING name="DMF">
|
||||||
|
<NAME>dr:CobjContentSynthesis</NAME>
|
||||||
|
<NAME>dr:CobjTypology</NAME>
|
||||||
|
<NAME>dr:CobjIdentifier</NAME>
|
||||||
|
<NAME>dr:CobjModel</NAME>
|
||||||
|
<NAME>dr:CobjMDFormats</NAME>
|
||||||
|
<NAME>dr:CobjDescriptionSynthesis</NAME>
|
||||||
|
<NAME>dr:repositoryName</NAME>
|
||||||
|
<NAME>dr:repositoryLink</NAME>
|
||||||
|
<NAME>dr:repositoryCountry</NAME>
|
||||||
|
<NAME>dr:repositoryInstitution</NAME>
|
||||||
|
<NAME>dc:creator</NAME>
|
||||||
|
<NAME>dc:title</NAME>
|
||||||
|
<NAME>dc:subject</NAME>
|
||||||
|
<NAME>dr:CobjCategory</NAME>
|
||||||
|
<NAME>dc:language</NAME>
|
||||||
|
<NAME>dc:dateAccepted</NAME>
|
||||||
|
<NAME>dc:identifier</NAME>
|
||||||
|
<NAME>dc:publisher </NAME>
|
||||||
|
<NAME>dc:source </NAME>
|
||||||
|
<NAME>dc:contributor </NAME>
|
||||||
|
<NAME>dc:relation</NAME>
|
||||||
|
<NAME>dc:description</NAME>
|
||||||
|
</FIELD_SETTING>
|
||||||
|
<FIELD_SETTING name="Index Configuration Fields">
|
||||||
|
<NAME>dr:repositoryCountry</NAME>
|
||||||
|
</FIELD_SETTING>
|
||||||
|
<FIELD_SETTING name="Index Result Fields">
|
||||||
|
<NAME>*</NAME>
|
||||||
|
</FIELD_SETTING>
|
||||||
|
<FIELD_SETTING name="DMF Provenance Fields">
|
||||||
|
<NAME>dr:repositoryName</NAME>
|
||||||
|
<NAME>dr:repositoryLink</NAME>
|
||||||
|
<NAME>dr:repositoryCountry</NAME>
|
||||||
|
<NAME>dr:repositoryInstitution</NAME>
|
||||||
|
</FIELD_SETTING>
|
||||||
|
<FIELD_SETTING name="Repository Provenance Fields">
|
||||||
|
<NAME>ENGLISH_NAME</NAME>
|
||||||
|
<NAME>REPOSITORY_WEBPAGE</NAME>
|
||||||
|
<NAME>COUNTRY</NAME>
|
||||||
|
<NAME>REPOSITORY_INSTITUTION</NAME>
|
||||||
|
</FIELD_SETTING>
|
||||||
|
</FIELD_SETTINGS>
|
||||||
|
</CONFIGURATION>
|
||||||
|
<STATUS>
|
||||||
|
<LAST_UPDATE value="10/04/2007"/>
|
||||||
|
</STATUS>
|
||||||
|
<SECURITY_PARAMETERS></SECURITY_PARAMETERS>
|
||||||
|
</BODY>
|
||||||
|
</RESOURCE_PROFILE>
|
|
@ -0,0 +1,2 @@
|
||||||
|
# values: idPreservingPendingManager, compatPendingManager
|
||||||
|
services.registry.pending.resource.manager=idPreservingPendingManager
|
|
@ -0,0 +1,75 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jaxws="http://cxf.apache.org/jaxws"
|
||||||
|
xmlns:sec="http://cxf.apache.org/configuration/security" xmlns:wsa="http://cxf.apache.org/ws/addressing"
|
||||||
|
xmlns:p="http://www.springframework.org/schema/p" xmlns:http="http://cxf.apache.org/transports/http/configuration"
|
||||||
|
xmlns:t="http://dnetlib.eu/springbeans/t" xmlns:template="http://dnetlib.eu/springbeans/template"
|
||||||
|
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
|
||||||
|
http://cxf.apache.org/ws/addressing http://cxf.apache.org/schemas/ws-addr-conf.xsd
|
||||||
|
http://cxf.apache.org/configuration/security http://cxf.apache.org/schemas/configuration/security.xsd
|
||||||
|
http://cxf.apache.org/transports/http/configuration http://cxf.apache.org/schemas/configuration/http-conf.xsd
|
||||||
|
http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd
|
||||||
|
http://dnetlib.eu/springbeans/template http://dnetlib.eu/springbeans/template.xsd">
|
||||||
|
<!-- beans -->
|
||||||
|
<bean id="isRegistryService" class="eu.dnetlib.enabling.is.registry.ISRegistryServiceImpl"
|
||||||
|
init-method="start" destroy-method="stop" p:isLookup-ref="isLookUpService" p:isStore-ref="isStoreService"
|
||||||
|
p:pendingManager-ref="pendingManager" p:resourceValidator-ref="resourceValidator" p:xqueryUtils-ref="xqueryUtils" />
|
||||||
|
|
||||||
|
<bean id="registryBlackboardManager"
|
||||||
|
class="eu.dnetlib.enabling.is.registry.RegistryBlackboardManagerImpl"
|
||||||
|
p:messageFactory-ref="blackboardMessageFactory" p:isLookup-ref="isLookUpService"
|
||||||
|
p:registryService-ref="isRegistryService" />
|
||||||
|
|
||||||
|
<alias alias="pendingManager" name="${services.registry.pending.resource.manager}" />
|
||||||
|
|
||||||
|
<bean id="compatPendingManager"
|
||||||
|
class="eu.dnetlib.enabling.is.registry.CompatPendingResourceManagerImpl"
|
||||||
|
p:isRegistry-ref="isRegistryService" p:resourceKindResolver-ref="resourceKindResolverChain" />
|
||||||
|
|
||||||
|
<bean id="idPreservingPendingManager"
|
||||||
|
class="eu.dnetlib.enabling.is.registry.IdPreservingPendingResourceManagerImpl"
|
||||||
|
p:resourceValidator-ref="resourceValidator" p:xqueryUtils-ref="xqueryUtils"
|
||||||
|
p:isRegistry-ref="isRegistryService" p:isStore-ref="isStoreService"
|
||||||
|
p:resourceKindResolver-ref="resourceKindResolverChain" />
|
||||||
|
|
||||||
|
<bean id="resourceKindResolverChain"
|
||||||
|
class="eu.dnetlib.enabling.is.registry.ResourceKindResolverChain">
|
||||||
|
<property name="resolvers">
|
||||||
|
<list>
|
||||||
|
<ref bean="resourceKindResolver" />
|
||||||
|
<ref bean="nameBasedResourceKindResolver" />
|
||||||
|
</list>
|
||||||
|
</property>
|
||||||
|
</bean>
|
||||||
|
|
||||||
|
<bean id="nameBasedResourceKindResolver"
|
||||||
|
class="eu.dnetlib.enabling.is.registry.NameBasedResourceKindResolver" />
|
||||||
|
|
||||||
|
<bean id="resourceKindResolver"
|
||||||
|
class="eu.dnetlib.enabling.is.registry.ApplicationProfileResourceKindResolver" />
|
||||||
|
|
||||||
|
<bean id="resourceIdentifierResolver"
|
||||||
|
class="eu.dnetlib.enabling.tools.CompatResourceIdentifierResolverImpl" />
|
||||||
|
|
||||||
|
<bean id="resourceValidator"
|
||||||
|
class="eu.dnetlib.enabling.is.registry.schema.OpaqueResourceValidatorImpl"
|
||||||
|
p:schemaDao-ref="resourceSchemaDao" />
|
||||||
|
|
||||||
|
<bean id="resourceSchemaDao"
|
||||||
|
class="eu.dnetlib.enabling.is.registry.schema.ResourceSchemaDAOImpl"
|
||||||
|
p:isLookup-ref="isLookUpService" />
|
||||||
|
|
||||||
|
<bean id="profileValidationStrategy" class="eu.dnetlib.enabling.is.registry.validation.ProfileValidationStrategy" />
|
||||||
|
|
||||||
|
<bean id="alwaysAcceptProfileValidator" class="eu.dnetlib.enabling.is.registry.validation.AlwaysAcceptProfileValidator" />
|
||||||
|
|
||||||
|
<!-- endpoints -->
|
||||||
|
<jaxws:endpoint id="isRegistryServiceEndpoint"
|
||||||
|
implementor="#isRegistryService" implementorClass="eu.dnetlib.enabling.is.registry.rmi.ISRegistryService"
|
||||||
|
address="/isRegistry" />
|
||||||
|
|
||||||
|
<template:instance name="serviceRegistrationManager"
|
||||||
|
t:serviceRegistrationManagerClass="eu.dnetlib.enabling.tools.registration.ValidatingServiceRegistrationManagerImpl"
|
||||||
|
t:name="isRegistryServiceRegistrationManager" t:service="isRegistryService"
|
||||||
|
t:endpoint="isRegistryServiceEndpoint" t:jobScheduler="jobScheduler" />
|
||||||
|
</beans>
|
|
@ -0,0 +1,19 @@
|
||||||
|
services.issn.path=${dnet.data.path}/issn
|
||||||
|
services.issn.hib.issndb.url=jdbc:sqlite:${services.issn.path}/dnet_issn.db
|
||||||
|
services.issn.hib.issndb.username=dnet
|
||||||
|
services.issn.hib.issndb.password=dnetPwd
|
||||||
|
services.issn.hibernate.hbm.auto=update
|
||||||
|
services.issn.hib.issndb.dialect=org.hibernate.dialect.SQLiteDialect
|
||||||
|
services.issn.hib.driverName = org.sqlite.JDBC
|
||||||
|
|
||||||
|
services.issn.subscription.filter.active = false
|
||||||
|
services.is.sn.subscriptions.cache.ttl = 86400
|
||||||
|
services.is.sn.subscriptions.cache.size = 1000
|
||||||
|
|
||||||
|
#TO USE POSTGRES YOU NEED TO UNCOMMENT THIS
|
||||||
|
#services.issn.hib.issndb.url=jdbc:postgresql://localhost:5432/dnet_issn
|
||||||
|
#services.issn.hib.issndb.username=dnet
|
||||||
|
#services.issn.hib.issndb.password=dnetPwd
|
||||||
|
#services.issn.hibernate.hbm.auto=update
|
||||||
|
#services.issn.hib.issndb.dialect=org.hibernate.dialect.PostgreSQLDialect
|
||||||
|
#services.issn.hib.driverName = org.postgresql.Driver
|
|
@ -0,0 +1,86 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jaxws="http://cxf.apache.org/jaxws"
|
||||||
|
xmlns:sec="http://cxf.apache.org/configuration/security" xmlns:wsa="http://cxf.apache.org/ws/addressing"
|
||||||
|
xmlns:p="http://www.springframework.org/schema/p" xmlns:http="http://cxf.apache.org/transports/http/configuration"
|
||||||
|
xmlns:util="http://www.springframework.org/schema/util" xmlns:t="http://dnetlib.eu/springbeans/t"
|
||||||
|
xmlns:template="http://dnetlib.eu/springbeans/template" xmlns:cache="http://www.springframework.org/schema/cache"
|
||||||
|
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
|
||||||
|
http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache.xsd
|
||||||
|
http://cxf.apache.org/ws/addressing http://cxf.apache.org/schemas/ws-addr-conf.xsd
|
||||||
|
http://cxf.apache.org/configuration/security http://cxf.apache.org/schemas/configuration/security.xsd
|
||||||
|
http://cxf.apache.org/transports/http/configuration http://cxf.apache.org/schemas/configuration/http-conf.xsd
|
||||||
|
http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd
|
||||||
|
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-2.0.xsd
|
||||||
|
http://dnetlib.eu/springbeans/template http://dnetlib.eu/springbeans/template.xsd">
|
||||||
|
|
||||||
|
<!-- beans -->
|
||||||
|
<bean name="isSNService" class="eu.dnetlib.enabling.is.sn.ISSNServiceImpl"
|
||||||
|
p:endpoint-ref="isSNServiceEndpoint" p:core-ref="isSNServiceCore"
|
||||||
|
init-method="start" destroy-method="stop" />
|
||||||
|
|
||||||
|
<bean name="isSNServiceCore" class="eu.dnetlib.enabling.is.sn.ISSNServiceCore"
|
||||||
|
p:registry-ref="issResourceStateNotificationRegistry"
|
||||||
|
p:backupDir="${services.is.sn.data.path}/backups"/>
|
||||||
|
|
||||||
|
<bean name="issnNotificationDetector" class="eu.dnetlib.enabling.is.sn.NotificationDetectorImpl"
|
||||||
|
p:sender-ref="issnNotificationSender" p:registry-ref="issResourceStateNotificationRegistry" />
|
||||||
|
|
||||||
|
<bean id="issnNotificationDetectorPendingSupport"
|
||||||
|
class="eu.dnetlib.enabling.is.sn.resourcestate.PendingResourceStateNotificationDetectorFilter"
|
||||||
|
p:delegate-ref="issnNotificationDetector" />
|
||||||
|
|
||||||
|
<bean id="subscriptionRequestFilter" class="eu.dnetlib.enabling.is.sn.resourcestate.SubscriptionRequestFilter" />
|
||||||
|
|
||||||
|
<!--
|
||||||
|
set this condition to true to globally inhibit notification processing
|
||||||
|
-->
|
||||||
|
<bean id="issnInhibitionCondition" class="eu.dnetlib.miscutils.coupling.StaticCondition" />
|
||||||
|
|
||||||
|
<bean id="issnNotificationDetectorConditional"
|
||||||
|
class="eu.dnetlib.enabling.is.sn.resourcestate.ConditionalResourceStateNotificationDetectorFilter"
|
||||||
|
p:inhibitionCondition-ref="issnInhibitionCondition" p:delegate-ref="issnNotificationDetectorPendingSupport" />
|
||||||
|
|
||||||
|
<bean id="issResourceStateNotificationRegistry"
|
||||||
|
class="eu.dnetlib.enabling.is.sn.resourcestate.ResourceStateSubscriptionRegistry"
|
||||||
|
p:subscriptionDao-ref="hibernateResourceStateSubscriptionDAO" />
|
||||||
|
|
||||||
|
<bean name="issnNotificationSender"
|
||||||
|
class="eu.dnetlib.enabling.is.sn.AsynchronousNotificationSenderImpl"
|
||||||
|
p:invoker-ref="issnNotificationInvoker" init-method="start" />
|
||||||
|
|
||||||
|
<bean name="issnNotificationInvocationLogger"
|
||||||
|
class="eu.dnetlib.enabling.is.sn.MemoryNotificationInvocationLogger" />
|
||||||
|
|
||||||
|
<bean name="issnNotificationInvoker" class="eu.dnetlib.enabling.is.sn.NotificationInvokerImpl"
|
||||||
|
p:invocationLogger-ref="issnNotificationInvocationLogger" />
|
||||||
|
|
||||||
|
<bean name="issnIntegrationTrigger" class="eu.dnetlib.enabling.is.sn.NotificationTriggerImpl"
|
||||||
|
p:name="issnIntegrationTrigger" p:detector-ref="issnNotificationDetectorConditional" />
|
||||||
|
|
||||||
|
|
||||||
|
<bean id="issnCacheManager" class="org.springframework.cache.ehcache.EhCacheCacheManager"
|
||||||
|
p:cacheManager-ref="issnCacheManagerFactory" />
|
||||||
|
|
||||||
|
<bean id="issnCacheManagerFactory"
|
||||||
|
class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean"
|
||||||
|
p:cacheManagerName="issnCacheManager" />
|
||||||
|
|
||||||
|
<bean id="issnCache"
|
||||||
|
class="org.springframework.cache.ehcache.EhCacheFactoryBean"
|
||||||
|
p:eternal="false" p:timeToLive="${services.is.sn.subscriptions.cache.ttl}"
|
||||||
|
p:timeToIdle="${services.is.sn.subscriptions.cache.ttl}"
|
||||||
|
p:overflowToDisk="false"
|
||||||
|
p:maxElementsInMemory="${services.is.sn.subscriptions.cache.size}"
|
||||||
|
p:cacheManager-ref="issnCacheManagerFactory"
|
||||||
|
p:cacheName="issnCache" p:name="subscriptions" />
|
||||||
|
|
||||||
|
<!-- endpoints -->
|
||||||
|
<jaxws:endpoint id="isSNServiceEndpoint" implementor="#isSNService"
|
||||||
|
implementorClass="eu.dnetlib.enabling.is.sn.rmi.ISSNService" address="/isSN" />
|
||||||
|
|
||||||
|
<template:instance name="serviceRegistrationManager"
|
||||||
|
t:serviceRegistrationManagerClass="eu.dnetlib.enabling.tools.registration.ValidatingServiceRegistrationManagerImpl"
|
||||||
|
t:name="isSNServiceRegistrationManager" t:service="isSNService"
|
||||||
|
t:endpoint="isSNServiceEndpoint" t:jobScheduler="jobScheduler" />
|
||||||
|
</beans>
|
|
@ -0,0 +1,54 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
|
||||||
|
xmlns:context="http://www.springframework.org/schema/context" xmlns:p="http://www.springframework.org/schema/p"
|
||||||
|
xmlns:tx="http://www.springframework.org/schema/tx" xmlns:util="http://www.springframework.org/schema/util"
|
||||||
|
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
|
||||||
|
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
|
||||||
|
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
|
||||||
|
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
|
||||||
|
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">
|
||||||
|
|
||||||
|
<bean id="verifyPath" class="eu.dnetlib.enabling.is.sn.DnetPathVerifier">
|
||||||
|
<constructor-arg value="${services.issn.path}"/>
|
||||||
|
</bean>
|
||||||
|
|
||||||
|
<!-- DATASOURCE -->
|
||||||
|
<bean id="issnDataSource"
|
||||||
|
class="org.springframework.jdbc.datasource.DriverManagerDataSource"
|
||||||
|
p:driverClassName="${services.issn.hib.driverName}" p:url="${services.issn.hib.issndb.url}"
|
||||||
|
p:username="${services.issn.hib.issndb.username}" p:password="${services.issn.hib.issndb.password}"
|
||||||
|
depends-on="verifyPath"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<!-- Hibernate SessionFactory -->
|
||||||
|
<bean id="issnSessionFactory"
|
||||||
|
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean"
|
||||||
|
p:dataSource-ref="issnDataSource"
|
||||||
|
depends-on="verifyPath"
|
||||||
|
>
|
||||||
|
<property name="annotatedClasses">
|
||||||
|
<list>
|
||||||
|
<value>eu.dnetlib.enabling.is.sn.resourcestate.ResourceStateSubscription</value>
|
||||||
|
</list>
|
||||||
|
</property>
|
||||||
|
<property name="hibernateProperties">
|
||||||
|
<props>
|
||||||
|
<prop key="hibernate.dialect">${services.issn.hib.issndb.dialect}</prop>
|
||||||
|
<prop key="hibernate.show_sql">false</prop>
|
||||||
|
<prop key="hibernate.hbm2ddl.auto">${services.issn.hibernate.hbm.auto}</prop>
|
||||||
|
</props>
|
||||||
|
</property>
|
||||||
|
</bean>
|
||||||
|
<!-- Transaction manager for a single Hibernate SessionFactory (alternative
|
||||||
|
to JTA) -->
|
||||||
|
<tx:annotation-driven transaction-manager="issnTransactionManager" />
|
||||||
|
|
||||||
|
<bean id="issnTransactionManager"
|
||||||
|
class="org.springframework.orm.hibernate4.HibernateTransactionManager"
|
||||||
|
p:sessionFactory-ref="issnSessionFactory" />
|
||||||
|
|
||||||
|
<bean id="hibernateResourceStateSubscriptionDAO"
|
||||||
|
class="eu.dnetlib.enabling.is.sn.resourcestate.hib.HibernateResourceStateSubscriptionDAOImpl"
|
||||||
|
p:sessionFactory-ref="issnSessionFactory" />
|
||||||
|
</beans>
|
|
@ -0,0 +1,2 @@
|
||||||
|
services.is.store.enable.java=true
|
||||||
|
services.is.store.initializer.timetosleep = 4000
|
|
@ -0,0 +1,116 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jaxws="http://cxf.apache.org/jaxws"
|
||||||
|
xmlns:sec="http://cxf.apache.org/configuration/security" xmlns:wsa="http://cxf.apache.org/ws/addressing"
|
||||||
|
xmlns:p="http://www.springframework.org/schema/p" xmlns:http="http://cxf.apache.org/transports/http/configuration"
|
||||||
|
xmlns:t="http://dnetlib.eu/springbeans/t" xmlns:template="http://dnetlib.eu/springbeans/template"
|
||||||
|
xmlns:util="http://www.springframework.org/schema/util"
|
||||||
|
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
|
||||||
|
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd
|
||||||
|
http://cxf.apache.org/ws/addressing http://cxf.apache.org/schemas/ws-addr-conf.xsd
|
||||||
|
http://cxf.apache.org/configuration/security http://cxf.apache.org/schemas/configuration/security.xsd
|
||||||
|
http://cxf.apache.org/transports/http/configuration http://cxf.apache.org/schemas/configuration/http-conf.xsd
|
||||||
|
http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd
|
||||||
|
http://dnetlib.eu/springbeans/template http://dnetlib.eu/springbeans/template.xsd">
|
||||||
|
<!-- beans -->
|
||||||
|
|
||||||
|
<bean name="abstractExistDatabase" init-method="start"
|
||||||
|
destroy-method="stop" p:triggerConf-ref="issnTriggers" abstract="true"
|
||||||
|
p:backupDir="${services.is.store.data.path}/backups" />
|
||||||
|
|
||||||
|
<bean name="temporaryExistDatabase" class="eu.dnetlib.xml.database.exist.TemporaryExistDatabase"
|
||||||
|
parent="abstractExistDatabase" lazy-init="true" />
|
||||||
|
|
||||||
|
<bean name="persistentExistDatabase" class="eu.dnetlib.xml.database.exist.PersistentExistDatabase"
|
||||||
|
parent="abstractExistDatabase"
|
||||||
|
p:dbRootPath="${services.is.store.data.path}/db" p:XQueryJavaEnabled="${services.is.store.enable.java}"
|
||||||
|
lazy-init="true" />
|
||||||
|
|
||||||
|
<alias name="${services.is.store.database.bean}" alias="existDatabase"/>
|
||||||
|
|
||||||
|
<!-- Adding interceptors to log about the execution of methods on exist -->
|
||||||
|
<bean name="persistentExistLogInterceptor"
|
||||||
|
class="eu.dnetlib.enabling.tools.LogInterceptor">
|
||||||
|
<property name="enterMessage"
|
||||||
|
value="ENTER | $[targetClassShortName].$[methodName]($[arguments])"/>
|
||||||
|
<property name="exitMessage"
|
||||||
|
value="EXIT | $[targetClassShortName].$[methodName]($[arguments]) | $[invocationTime]ms"/>
|
||||||
|
</bean>
|
||||||
|
|
||||||
|
<bean
|
||||||
|
class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
|
||||||
|
<property name="beanNames" value="persistentExistDatabase"/>
|
||||||
|
<property name="proxyTargetClass" value="true"/>
|
||||||
|
<property name="interceptorNames">
|
||||||
|
<list>
|
||||||
|
<value>persistentExistLogInterceptor</value>
|
||||||
|
</list>
|
||||||
|
</property>
|
||||||
|
</bean>
|
||||||
|
|
||||||
|
<!-- end AOP interceptors -->
|
||||||
|
|
||||||
|
<util:map id="issnTriggers">
|
||||||
|
<entry key="/db" value-ref="issnIntegrationTrigger" />
|
||||||
|
</util:map>
|
||||||
|
|
||||||
|
<bean name="isStoreService" class="eu.dnetlib.enabling.is.store.ISStoreServiceImpl"
|
||||||
|
scope="singleton" init-method="start" destroy-method="stop"
|
||||||
|
p:xmlDatabase-ref="existDatabase" p:endpoint-ref="isStoreServiceEndpoint"
|
||||||
|
p:contentInitializerJob-ref="embeddedContentLoaderJob" />
|
||||||
|
|
||||||
|
<bean id="bulkResourceImporter" class="eu.dnetlib.enabling.is.store.BulkResourceImporter"
|
||||||
|
p:serviceLocator-ref="uniqueServiceLocator" p:xqueryUtils-ref="xqueryUtils"
|
||||||
|
p:resourceValidator-ref="resourceValidator" p:validating="${services.is.store.bulk.validation}" />
|
||||||
|
|
||||||
|
<bean id="embeddedContentLoaderJob" class="eu.dnetlib.enabling.is.store.TestContentInitializerJob"
|
||||||
|
scope="singleton" p:serviceLocator-ref="uniqueServiceLocator"
|
||||||
|
p:resources="classpath*:/eu/dnetlib/test/profiles/**/*.xml" p:schemas="${services.schemas}"
|
||||||
|
p:resourceLoader-ref="resourceLoaderHelper" p:bulkImporter-ref="bulkResourceImporter"
|
||||||
|
p:snDisable-ref="issnInhibitionCondition" p:timeToSleep="${services.is.store.initializer.timetosleep}" />
|
||||||
|
|
||||||
|
<!-- <bean id="testContentLoaderTrigger" class="org.springframework.scheduling.quartz.SimpleTriggerFactoryBean" -->
|
||||||
|
<!-- p:repeatCount="0" p:startDelay="3000"> -->
|
||||||
|
<!-- <property name="jobDetail"> -->
|
||||||
|
<!-- <bean id="testContentLoaderTriggerDetails" class="org.springframework.scheduling.quartz.JobDetailBean" -->
|
||||||
|
<!-- p:jobClass="eu.dnetlib.enabling.is.store.TestContentInitializerJob" -->
|
||||||
|
<!-- depends-on="snLocator"> -->
|
||||||
|
<!-- <property name="jobDataAsMap"> -->
|
||||||
|
<!-- <map> -->
|
||||||
|
<!-- <entry key="registryLocator" value-ref="registryLocator" /> -->
|
||||||
|
<!-- <entry key="resources" value="classpath*:/eu/dnetlib/test/profiles/**/*.xml"
|
||||||
|
/> -->
|
||||||
|
<!-- <entry key="schemas" value="${services.schemas}" /> -->
|
||||||
|
<!-- <entry key="resourceLoader" value-ref="resourceLoaderHelper" /> -->
|
||||||
|
<!-- <entry key="bulkImporter" value-ref="bulkResourceImporter" /> -->
|
||||||
|
<!-- <entry key="snDisable" value-ref="issnInhibitionCondition" /> -->
|
||||||
|
<!-- </map> -->
|
||||||
|
<!-- </property> -->
|
||||||
|
<!-- </bean> -->
|
||||||
|
<!-- </property> -->
|
||||||
|
<!-- </bean> -->
|
||||||
|
|
||||||
|
<bean id="resourceLoaderHelper" class="eu.dnetlib.enabling.tools.ResourceLoaderHelper" />
|
||||||
|
|
||||||
|
<!-- <bean id="storeJobSchedulerAccessor" -->
|
||||||
|
<!-- class="org.springframework.scheduling.quartz.SchedulerAccessorBean" -->
|
||||||
|
<!-- p:scheduler-ref="jobScheduler"> -->
|
||||||
|
<!-- <property name="triggers"> -->
|
||||||
|
<!-- <list> -->
|
||||||
|
<!-- <ref bean="testContentLoaderTrigger" /> -->
|
||||||
|
<!-- </list> -->
|
||||||
|
<!-- </property> -->
|
||||||
|
<!-- </bean> -->
|
||||||
|
|
||||||
|
<!-- endpoints -->
|
||||||
|
<jaxws:endpoint id="isStoreServiceEndpoint" implementor="#isStoreService"
|
||||||
|
implementorClass="eu.dnetlib.enabling.is.store.rmi.ISStoreService"
|
||||||
|
address="/isStore" />
|
||||||
|
|
||||||
|
<template:instance name="serviceRegistrationManager"
|
||||||
|
t:serviceRegistrationManagerClass="eu.dnetlib.enabling.tools.registration.ValidatingServiceRegistrationManagerImpl"
|
||||||
|
t:name="isStoreServiceRegistrationManager" t:service="isStoreService"
|
||||||
|
t:endpoint="isStoreServiceEndpoint" t:jobScheduler="jobScheduler" />
|
||||||
|
|
||||||
|
|
||||||
|
</beans>
|
|
@ -0,0 +1,10 @@
|
||||||
|
xquery version "1.0";
|
||||||
|
|
||||||
|
module namespace dnet="http://namespace.dnetlib.eu/xquery/dnet";
|
||||||
|
declare namespace xmldb="http://exist-db.org/xquery/xmldb";
|
||||||
|
|
||||||
|
declare function dnet:deleteDocument($x as element()) {
|
||||||
|
|
||||||
|
xmldb:remove(replace($x/base-uri(),'/[^/]*$', ''), replace($x/base-uri(),'^.*/([^/]*)$', '$1'))
|
||||||
|
|
||||||
|
};
|
|
@ -0,0 +1,14 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jaxws="http://cxf.apache.org/jaxws"
|
||||||
|
xmlns:sec="http://cxf.apache.org/configuration/security" xmlns:wsa="http://cxf.apache.org/ws/addressing"
|
||||||
|
xmlns:p="http://www.springframework.org/schema/p" xmlns:http="http://cxf.apache.org/transports/http/configuration"
|
||||||
|
|
||||||
|
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
|
||||||
|
http://cxf.apache.org/ws/addressing http://cxf.apache.org/schemas/ws-addr-conf.xsd
|
||||||
|
http://cxf.apache.org/configuration/security http://cxf.apache.org/schemas/configuration/security.xsd
|
||||||
|
http://cxf.apache.org/transports/http/configuration http://cxf.apache.org/schemas/configuration/http-conf.xsd
|
||||||
|
http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd">
|
||||||
|
|
||||||
|
<bean id="xqueryUtils" class="eu.dnetlib.enabling.tools.XQueryUtilsImpl" />
|
||||||
|
</beans>
|
|
@ -0,0 +1,85 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<exist xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:noNamespaceSchemaLocation="schema/conf.xsd">
|
||||||
|
|
||||||
|
<db-connection cacheSize="48M" collectionCache="24M"
|
||||||
|
database="native" files="data" pageSize="4096">
|
||||||
|
|
||||||
|
<recovery enabled="yes" group-commit="no" journal-dir="data"
|
||||||
|
size="100M" sync-on-commit="no" />
|
||||||
|
<watchdog output-size-limit="10000" query-timeout="-1" />
|
||||||
|
|
||||||
|
</db-connection>
|
||||||
|
|
||||||
|
<serializer add-exist-id="none" compress-output="no"
|
||||||
|
enable-xinclude="no" enable-xsl="no" indent="no"
|
||||||
|
match-tagging-attributes="no" match-tagging-elements="no" />
|
||||||
|
|
||||||
|
<xquery enable-java-binding="no" enable-query-rewriting="yes"
|
||||||
|
backwardCompatible="no">
|
||||||
|
<builtin-modules>
|
||||||
|
<!-- Default Modules -->
|
||||||
|
<module class="org.exist.xquery.functions.util.UtilModule"
|
||||||
|
uri="http://exist-db.org/xquery/util" />
|
||||||
|
<module class="org.exist.xquery.functions.transform.TransformModule"
|
||||||
|
uri="http://exist-db.org/xquery/transform" />
|
||||||
|
<module class="org.exist.xquery.functions.xmldb.XMLDBModule"
|
||||||
|
uri="http://exist-db.org/xquery/xmldb" />
|
||||||
|
<!-- <module class="org.exist.xquery.functions.request.RequestModule"-->
|
||||||
|
<!-- uri="http://exist-db.org/xquery/request" />-->
|
||||||
|
<!-- <module class="org.exist.xquery.functions.response.ResponseModule"-->
|
||||||
|
<!-- uri="http://exist-db.org/xquery/response" />-->
|
||||||
|
<!-- <module class="org.exist.xquery.functions.session.SessionModule"-->
|
||||||
|
<!-- uri="http://exist-db.org/xquery/session" />-->
|
||||||
|
<!-- <module class="org.exist.xquery.functions.text.TextModule"-->
|
||||||
|
<!-- uri="http://exist-db.org/xquery/text" />-->
|
||||||
|
<!-- <module class="org.exist.xquery.modules.example.ExampleModule"-->
|
||||||
|
<!-- uri="http://exist-db.org/xquery/examples" />-->
|
||||||
|
<!-- <module class="org.exist.xquery.functions.validation.ValidationModule"-->
|
||||||
|
<!-- uri="http://exist-db.org/xquery/validation" />-->
|
||||||
|
<!-- <module class="org.exist.xquery.functions.system.SystemModule"-->
|
||||||
|
<!-- uri="http://exist-db.org/xquery/system" />-->
|
||||||
|
|
||||||
|
<!-- New Modularized Indexes -->
|
||||||
|
<!-- <module class="org.exist.xquery.modules.ngram.NGramModule"-->
|
||||||
|
<!-- uri="http://exist-db.org/xquery/ngram" />-->
|
||||||
|
|
||||||
|
<!--
|
||||||
|
<module class="org.exist.xquery.modules.spatial.SpatialModule"
|
||||||
|
uri="http://exist-db.org/xquery/spatial" />
|
||||||
|
-->
|
||||||
|
<!-- Optional Modules -->
|
||||||
|
<!--
|
||||||
|
<module
|
||||||
|
class="org.exist.xquery.modules.compression.CompressionModule"
|
||||||
|
uri="http://exist-db.org/xquery/compression" /> <module
|
||||||
|
class="org.exist.xquery.modules.datetime.DateTimeModule"
|
||||||
|
uri="http://exist-db.org/xquery/datetime" /> <module
|
||||||
|
class="org.exist.xquery.modules.example.ExampleModule"
|
||||||
|
uri="http://exist-db.org/xquery/examples" /> <module
|
||||||
|
class="org.exist.xquery.modules.httpclient.HTTPClientModule"
|
||||||
|
uri="http://exist-db.org/xquery/httpclient" /> <module
|
||||||
|
class="org.exist.xquery.modules.image.ImageModule"
|
||||||
|
uri="http://exist-db.org/xquery/image" /> <module
|
||||||
|
class="org.exist.xquery.modules.mail.MailModule"
|
||||||
|
uri="http://exist-db.org/xquery/mail" /> <module
|
||||||
|
class="org.exist.xquery.modules.math.MathModule"
|
||||||
|
uri="http://exist-db.org/xquery/math" /> <module
|
||||||
|
class="org.exist.xquery.modules.scheduler.SchedulerModule"
|
||||||
|
uri="http://exist-db.org/xquery/scheduler" /> <module
|
||||||
|
class="org.exist.xquery.modules.simpleql.SimpleQLModule"
|
||||||
|
uri="http://exist-db.org/xquery/simple-ql" /> <module
|
||||||
|
class="org.exist.xquery.modules.sql.SQLModule"
|
||||||
|
uri="http://exist-db.org/xquery/sql" /> <module
|
||||||
|
class="org.exist.xquery.modules.xslfo.XSLFOModule"
|
||||||
|
uri="http://exist-db.org/xquery/xslfo" /> <module
|
||||||
|
class="org.exist.xquery.modules.xmldiff.XmlDiffModule"
|
||||||
|
uri="http://exist-db.org/xquery/xmldiff" />
|
||||||
|
-->
|
||||||
|
</builtin-modules>
|
||||||
|
</xquery>
|
||||||
|
|
||||||
|
<xupdate allowed-fragmentation="5" enable-consistency-checks="no" />
|
||||||
|
|
||||||
|
|
||||||
|
</exist>
|
|
@ -0,0 +1,145 @@
|
||||||
|
package eu.dnetlib.enabling.is.lookup;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertNotNull;
|
||||||
|
import static org.mockito.Matchers.anyString;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.StringReader;
|
||||||
|
import java.io.StringWriter;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.apache.commons.io.IOUtils;
|
||||||
|
import org.dom4j.Document;
|
||||||
|
import org.dom4j.DocumentException;
|
||||||
|
import org.dom4j.io.SAXReader;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.mockito.Mock;
|
||||||
|
import org.mockito.junit.MockitoJUnitRunner;
|
||||||
|
|
||||||
|
import eu.dnetlib.enabling.is.lookup.rmi.ISLookUpDocumentNotFoundException;
|
||||||
|
import eu.dnetlib.enabling.is.lookup.rmi.ISLookUpException;
|
||||||
|
import eu.dnetlib.enabling.is.store.rmi.ISStoreException;
|
||||||
|
import eu.dnetlib.enabling.is.store.rmi.ISStoreService;
|
||||||
|
import eu.dnetlib.enabling.tools.XQueryUtilsImpl;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ISLookUpService test.
|
||||||
|
*
|
||||||
|
* @author marko
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@RunWith(MockitoJUnitRunner.class)
|
||||||
|
public class ISLookUpServiceImplTest {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* test profile id.
|
||||||
|
*/
|
||||||
|
private static final String PROF_ID = "first_c2Vjb25k";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List of ids.
|
||||||
|
*/
|
||||||
|
private static final List<String> ID_LIST = Arrays.asList(new String[] { "fff", "ggg", "hhh" });
|
||||||
|
|
||||||
|
/**
|
||||||
|
* class under test.
|
||||||
|
*/
|
||||||
|
private transient ISLookUpServiceImpl lookup;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* is store service mock.
|
||||||
|
*/
|
||||||
|
@Mock
|
||||||
|
private transient ISStoreService storeService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* common test case init.
|
||||||
|
*/
|
||||||
|
@Before
|
||||||
|
public void setUp() {
|
||||||
|
lookup = new ISLookUpServiceImpl();
|
||||||
|
lookup.setXqueryUtils(new XQueryUtilsImpl());
|
||||||
|
lookup.setIsStore(storeService);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* test get file name from id.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testGetFileNameForId() {
|
||||||
|
assertEquals("check", "first", lookup.getFileNameForId(PROF_ID));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* test get file coll from id.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testGetFileCollForId() {
|
||||||
|
assertEquals("check", "second", lookup.getFileCollForId(PROF_ID));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* test get resource profile.
|
||||||
|
*
|
||||||
|
* @throws ISLookUpException
|
||||||
|
* shouldn't happen
|
||||||
|
* @throws ISStoreException
|
||||||
|
* shouldn't happen
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testGetResourceProfile() throws ISLookUpException, ISStoreException {
|
||||||
|
when(storeService.getXML("first", "/db/DRIVER/second")).thenReturn("<someResult/>");
|
||||||
|
|
||||||
|
assertNotNull("get profile", lookup.getResourceProfile(PROF_ID));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* test get resource profile when no such document exists.
|
||||||
|
*
|
||||||
|
* @throws ISLookUpException
|
||||||
|
* expected
|
||||||
|
*/
|
||||||
|
@Test(expected = ISLookUpDocumentNotFoundException.class)
|
||||||
|
public void testGetResourceProfileNonExisting() throws ISLookUpException {
|
||||||
|
lookup.getResourceProfile(PROF_ID);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* test getCollection.
|
||||||
|
*
|
||||||
|
* @throws IOException
|
||||||
|
* could happen
|
||||||
|
* @throws ISStoreException
|
||||||
|
* could happen
|
||||||
|
* @throws ISLookUpException
|
||||||
|
* could happen
|
||||||
|
* @throws DocumentException
|
||||||
|
* could happen
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testGetCollection() throws IOException, ISStoreException, ISLookUpException, DocumentException {
|
||||||
|
final StringWriter writer = new StringWriter();
|
||||||
|
IOUtils.copy(getClass().getResourceAsStream("collProfile.xml"), writer);
|
||||||
|
final String simpleProf = writer.getBuffer().toString();
|
||||||
|
|
||||||
|
when(storeService.getXML(anyString(), anyString())).thenReturn(simpleProf);
|
||||||
|
when(
|
||||||
|
storeService.quickSearchXML("for $x in collection('/db/DRIVER/CollectionDSResources') where $x//FATHER/@id = '" + PROF_ID
|
||||||
|
+ "' return $x//RESOURCE_IDENTIFIER/@value/string()")).thenReturn(ID_LIST);
|
||||||
|
|
||||||
|
final String profile = lookup.retrieveCollection(PROF_ID);
|
||||||
|
final SAXReader reader = new SAXReader();
|
||||||
|
final Document doc = reader.read(new StringReader(profile));
|
||||||
|
|
||||||
|
assertEquals("children", ID_LIST.size(), doc.selectNodes("//CHILDREN/CHILD").size());
|
||||||
|
for (final String id : ID_LIST) {
|
||||||
|
assertNotNull("child", doc.selectSingleNode("//CHILDREN/CHILD[@id='" + id + "']"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,29 @@
|
||||||
|
package eu.dnetlib.enabling.is.registry;
|
||||||
|
|
||||||
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
|
import javax.xml.xpath.XPathExpressionException;
|
||||||
|
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
public class ApplicationProfileResourceKindResolverTest {
|
||||||
|
|
||||||
|
private ApplicationProfileResourceKindResolver resolver;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() throws Exception {
|
||||||
|
resolver = new ApplicationProfileResourceKindResolver();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = NoSuchPendingCategoryException.class)
|
||||||
|
public void testPending() throws XPathExpressionException {
|
||||||
|
resolver.getPendingKindForType("TestType");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testPendingExisting() throws XPathExpressionException {
|
||||||
|
assertEquals("PendingServiceResources", resolver.getPendingKindForType("IndexServiceResourceType"));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,149 @@
|
||||||
|
package eu.dnetlib.enabling.is.registry;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertNotNull;
|
||||||
|
import static org.junit.Assert.assertNull;
|
||||||
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
|
import static org.mockito.Matchers.anyObject;
|
||||||
|
import static org.mockito.Matchers.anyString;
|
||||||
|
import static org.mockito.Matchers.eq;
|
||||||
|
import static org.mockito.Mockito.verify;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
import javax.xml.xpath.XPathExpressionException;
|
||||||
|
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.mockito.Mock;
|
||||||
|
import org.mockito.junit.MockitoJUnitRunner;
|
||||||
|
|
||||||
|
import eu.dnetlib.enabling.is.registry.rmi.ISRegistryException;
|
||||||
|
import eu.dnetlib.enabling.is.registry.rmi.ISRegistryService;
|
||||||
|
import eu.dnetlib.enabling.is.registry.schema.ValidationException;
|
||||||
|
import eu.dnetlib.enabling.is.registry.validation.ProfileValidationStrategy;
|
||||||
|
import eu.dnetlib.enabling.is.registry.validation.RegistrationPhase;
|
||||||
|
import eu.dnetlib.enabling.tools.OpaqueResource;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* test compatibility pending resource manager implementation.
|
||||||
|
*
|
||||||
|
* @author marko
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@RunWith(MockitoJUnitRunner.class)
|
||||||
|
public class CompatPendingResourceManagerImplTest {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* instance under test.
|
||||||
|
*/
|
||||||
|
private transient CompatPendingResourceManagerImpl pendingManager;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* registry service mock.
|
||||||
|
*/
|
||||||
|
@Mock
|
||||||
|
private transient ISRegistryService registryService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* resource mock.
|
||||||
|
*/
|
||||||
|
@Mock
|
||||||
|
private transient OpaqueResource resource;
|
||||||
|
/**
|
||||||
|
* used to validate resources w.r.t. a set of defined properties.
|
||||||
|
*/
|
||||||
|
@Mock
|
||||||
|
private ProfileValidationStrategy profileValidationStrategy;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* prepare instance for testing.
|
||||||
|
*/
|
||||||
|
@Before
|
||||||
|
public void setUp() {
|
||||||
|
pendingManager = new CompatPendingResourceManagerImpl();
|
||||||
|
pendingManager.setIsRegistry(registryService);
|
||||||
|
pendingManager.setResourceKindResolver(new ApplicationProfileResourceKindResolver());
|
||||||
|
pendingManager.setProfileValidationStrategy(profileValidationStrategy);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* test that the application profile can be queried correctly.
|
||||||
|
*
|
||||||
|
* @throws XPathExpressionException
|
||||||
|
* shouldn't happen
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testGetPendingKindForType() throws XPathExpressionException {
|
||||||
|
assertEquals("check pending", "PendingRepositoryResources", pendingManager.getPendingKindForType("RepositoryServiceResourceType"));
|
||||||
|
assertEquals("check pending", "PendingDSResources", pendingManager.getPendingKindForType("UserDSResourceType"));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* check that unexistent types throw an exception.
|
||||||
|
*
|
||||||
|
* @throws XPathExpressionException
|
||||||
|
* shouldn't happen
|
||||||
|
*/
|
||||||
|
@Test(expected = IllegalStateException.class)
|
||||||
|
public void testGetPendingKindForNoSuchType() throws XPathExpressionException {
|
||||||
|
pendingManager.getPendingKindForType("NoSuchType");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* test that the application profile can be queried correctly.
|
||||||
|
*
|
||||||
|
* @throws XPathExpressionException
|
||||||
|
* shouldn't happen
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testGetNormalKindForType() throws XPathExpressionException {
|
||||||
|
assertEquals("check kind", "RepositoryServiceResources", pendingManager.getNormalKindForType("RepositoryServiceResourceType"));
|
||||||
|
assertEquals("check kind", "UserDSResources", pendingManager.getNormalKindForType("UserDSResourceType"));
|
||||||
|
assertNull("check unexisting type", pendingManager.getNormalKindForType("NoSuchType"));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* test that the resource is correctly moved from the pending collection to the new collection.
|
||||||
|
*
|
||||||
|
* @throws ISRegistryException
|
||||||
|
* shoudn't happen
|
||||||
|
* @throws ValidationException
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testSetValid() throws ISRegistryException, ValidationException {
|
||||||
|
final String profId = "123";
|
||||||
|
when(resource.asString()).thenReturn("");
|
||||||
|
when(resource.getResourceId()).thenReturn(profId);
|
||||||
|
//when(profileValidationStrategy.accept(any(OpaqueResource.class), eq(RegistrationPhase.Register))).thenReturn(true);
|
||||||
|
|
||||||
|
pendingManager.setValid(resource);
|
||||||
|
|
||||||
|
verify(registryService).deleteProfile(profId);
|
||||||
|
verify(registryService).registerProfile(anyString());
|
||||||
|
|
||||||
|
assertNotNull("dummy", registryService);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* test that the resource is correctly moved from the current collection to the correct pending collection.
|
||||||
|
*
|
||||||
|
* @throws ISRegistryException
|
||||||
|
* shoudn't happen
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testSetPending() throws ISRegistryException {
|
||||||
|
final String profId = "321";
|
||||||
|
when(resource.asString()).thenReturn("");
|
||||||
|
when(resource.getResourceId()).thenReturn(profId);
|
||||||
|
when(resource.getResourceType()).thenReturn("RepositoryServiceResourceType");
|
||||||
|
|
||||||
|
pendingManager.setPending(resource);
|
||||||
|
|
||||||
|
verify(registryService).deleteProfile(profId);
|
||||||
|
verify(registryService).registerProfile(anyString());
|
||||||
|
|
||||||
|
assertNotNull("dummy", registryService);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,489 @@
|
||||||
|
package eu.dnetlib.enabling.is.registry; // NOPMD
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertFalse;
|
||||||
|
import static org.junit.Assert.assertNotNull;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
import static org.mockito.Matchers.anyObject;
|
||||||
|
import static org.mockito.Matchers.anyString;
|
||||||
|
import static org.mockito.Matchers.eq;
|
||||||
|
import static org.mockito.Mockito.doThrow;
|
||||||
|
import static org.mockito.Mockito.never;
|
||||||
|
import static org.mockito.Mockito.verify;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.StringWriter;
|
||||||
|
|
||||||
|
import javax.xml.parsers.ParserConfigurationException;
|
||||||
|
import javax.xml.xpath.XPathExpressionException;
|
||||||
|
|
||||||
|
import org.apache.commons.io.IOUtils;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.mockito.Mock;
|
||||||
|
import org.mockito.junit.MockitoJUnitRunner;
|
||||||
|
import org.xml.sax.SAXException;
|
||||||
|
|
||||||
|
import eu.dnetlib.enabling.is.lookup.rmi.ISLookUpException;
|
||||||
|
import eu.dnetlib.enabling.is.lookup.rmi.ISLookUpService;
|
||||||
|
import eu.dnetlib.enabling.is.registry.rmi.ISRegistryException;
|
||||||
|
import eu.dnetlib.enabling.is.registry.schema.OpaqueResourceValidator;
|
||||||
|
import eu.dnetlib.enabling.is.registry.schema.ValidationException;
|
||||||
|
import eu.dnetlib.enabling.is.registry.validation.ProfileValidationStrategy;
|
||||||
|
import eu.dnetlib.enabling.is.registry.validation.RegistrationPhase;
|
||||||
|
import eu.dnetlib.enabling.is.store.rmi.ISStoreException;
|
||||||
|
import eu.dnetlib.enabling.is.store.rmi.ISStoreService;
|
||||||
|
import eu.dnetlib.enabling.tools.CompatResourceIdentifierResolverImpl;
|
||||||
|
import eu.dnetlib.enabling.tools.OpaqueResource;
|
||||||
|
import eu.dnetlib.enabling.tools.ResourceType;
|
||||||
|
import eu.dnetlib.enabling.tools.StringOpaqueResource;
|
||||||
|
import eu.dnetlib.enabling.tools.XQueryUtils;
|
||||||
|
import eu.dnetlib.enabling.tools.XQueryUtilsImpl;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* test registry service.
|
||||||
|
*
|
||||||
|
* @author marko
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@RunWith(MockitoJUnitRunner.class)
|
||||||
|
public class ISRegistryServiceImplTest { // NOPMD
|
||||||
|
|
||||||
|
/**
|
||||||
|
* a test resource type.
|
||||||
|
*/
|
||||||
|
private static final String REPOSITORY_TYPE = "RepositoryServiceResourceType";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO: use a shared constant for this.
|
||||||
|
*/
|
||||||
|
private static final String DB_DRIVER = "/db/DRIVER/";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* class under test.
|
||||||
|
*/
|
||||||
|
private transient ISRegistryServiceImpl registry;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* store service mock.
|
||||||
|
*/
|
||||||
|
@Mock
|
||||||
|
private transient ISStoreService storeService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* lookup service mock.
|
||||||
|
*/
|
||||||
|
@Mock
|
||||||
|
private transient ISLookUpService lookUpService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* xml source of a test profile, loaded from test-profile.xml.
|
||||||
|
*/
|
||||||
|
private transient String profileSource;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* resource identifier resolver, converts IDs to filename/collection pairs.
|
||||||
|
*/
|
||||||
|
private transient CompatResourceIdentifierResolverImpl resIdResolver;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* schema validator.
|
||||||
|
*/
|
||||||
|
@Mock
|
||||||
|
private transient OpaqueResourceValidator validator;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* xquery utils, used for xmldb root path.
|
||||||
|
*/
|
||||||
|
private final transient XQueryUtils xqueryUtils = new XQueryUtilsImpl();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* used to validate resources w.r.t. a set of defined properties.
|
||||||
|
*/
|
||||||
|
@Mock
|
||||||
|
private ProfileValidationStrategy profileValidationStrategy;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* common initialization.
|
||||||
|
*
|
||||||
|
* @throws IOException
|
||||||
|
* shouldn't happen
|
||||||
|
*/
|
||||||
|
@Before
|
||||||
|
public void setUp() throws IOException {
|
||||||
|
registry = new ISRegistryServiceImpl();
|
||||||
|
registry.setXqueryUtils(new XQueryUtilsImpl());
|
||||||
|
resIdResolver = new CompatResourceIdentifierResolverImpl();
|
||||||
|
registry.setResIdResolver(resIdResolver);
|
||||||
|
|
||||||
|
final CompatPendingResourceManagerImpl pendingManager = new CompatPendingResourceManagerImpl();
|
||||||
|
pendingManager.setResourceKindResolver(new ApplicationProfileResourceKindResolver());
|
||||||
|
pendingManager.setProfileValidationStrategy(profileValidationStrategy);
|
||||||
|
|
||||||
|
registry.setPendingManager(pendingManager);
|
||||||
|
pendingManager.setIsRegistry(registry);
|
||||||
|
registry.setIsStore(storeService);
|
||||||
|
registry.setIsLookup(lookUpService);
|
||||||
|
|
||||||
|
registry.setResourceValidator(validator);
|
||||||
|
|
||||||
|
final StringWriter writer = new StringWriter();
|
||||||
|
IOUtils.copy(getClass().getResourceAsStream("test-profile.xml"), writer);
|
||||||
|
profileSource = writer.getBuffer().toString();
|
||||||
|
|
||||||
|
registry.setProfileValidationStrategy(profileValidationStrategy);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* test the deletion of a profile.
|
||||||
|
*
|
||||||
|
* @throws ISRegistryException
|
||||||
|
* shouldn't happen
|
||||||
|
* @throws XPathExpressionException
|
||||||
|
* shouldn't happen
|
||||||
|
* @throws SAXException
|
||||||
|
* shouldn't happen
|
||||||
|
* @throws IOException
|
||||||
|
* shouldn't happen
|
||||||
|
* @throws ParserConfigurationException
|
||||||
|
* shouldn't happen
|
||||||
|
* @throws ISStoreException
|
||||||
|
* shouldn't happen
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testDeleteProfile() throws ISRegistryException, XPathExpressionException, SAXException, IOException, ParserConfigurationException,
|
||||||
|
ISStoreException {
|
||||||
|
final OpaqueResource resource = new StringOpaqueResource(profileSource);
|
||||||
|
final String resId = resource.getResourceId();
|
||||||
|
|
||||||
|
boolean catched = false; // NOPMD
|
||||||
|
try {
|
||||||
|
registry.deleteProfile(resId);
|
||||||
|
} catch (ISRegistryDocumentNotFoundException e) {
|
||||||
|
catched = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
assertTrue("exception raised", catched);
|
||||||
|
verify(storeService).deleteXML(registry.getResIdResolver().getFileName(resId), DB_DRIVER + registry.getResIdResolver().getCollectionName(resId));
|
||||||
|
|
||||||
|
assertNotNull("dummy", storeService);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* test the deletion of an inexitent profile. It should throwa specific exception
|
||||||
|
*
|
||||||
|
* @throws ISRegistryException
|
||||||
|
* shouldn't happen
|
||||||
|
* @throws XPathExpressionException
|
||||||
|
* shouldn't happen
|
||||||
|
* @throws SAXException
|
||||||
|
* shouldn't happen
|
||||||
|
* @throws IOException
|
||||||
|
* shouldn't happen
|
||||||
|
* @throws ParserConfigurationException
|
||||||
|
* shouldn't happen
|
||||||
|
* @throws ISStoreException
|
||||||
|
* shouldn't happen
|
||||||
|
*/
|
||||||
|
@Test(expected = ISRegistryDocumentNotFoundException.class)
|
||||||
|
public void testDeleteInexistentProfile() throws ISRegistryException, XPathExpressionException, SAXException, IOException,
|
||||||
|
ParserConfigurationException, ISStoreException {
|
||||||
|
final OpaqueResource resource = new StringOpaqueResource(profileSource);
|
||||||
|
final String resId = resource.getResourceId();
|
||||||
|
final String wrongId = "xx" + resId;
|
||||||
|
|
||||||
|
when(storeService.deleteXML(registry.getResIdResolver().getFileName(wrongId), DB_DRIVER + registry.getResIdResolver().getCollectionName(wrongId)))
|
||||||
|
.thenReturn(false);
|
||||||
|
|
||||||
|
registry.deleteProfile(wrongId);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* test register profile.
|
||||||
|
*
|
||||||
|
* @throws ISRegistryException
|
||||||
|
* shouldn't happen
|
||||||
|
* @throws ISStoreException
|
||||||
|
* shouldn't happen
|
||||||
|
* @throws IOException
|
||||||
|
* shouldn't happen
|
||||||
|
* @throws ParserConfigurationException
|
||||||
|
* shouldn't happen
|
||||||
|
* @throws SAXException
|
||||||
|
* shouldn't happen
|
||||||
|
* @throws XPathExpressionException
|
||||||
|
* shouldn't happen
|
||||||
|
* @throws ValidationException
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testRegisterProfile() throws ISRegistryException, ISStoreException, IOException, XPathExpressionException, SAXException,
|
||||||
|
ParserConfigurationException, ValidationException {
|
||||||
|
|
||||||
|
when(profileValidationStrategy.accept((OpaqueResource) anyObject(), eq(RegistrationPhase.Register))).thenReturn(true);
|
||||||
|
final String newId = registry.registerProfile(profileSource);
|
||||||
|
|
||||||
|
verify(storeService).insertXML(eq(resIdResolver.getFileName(newId)), eq(DB_DRIVER + resIdResolver.getCollectionName(newId)), anyString());
|
||||||
|
|
||||||
|
final OpaqueResource resource = new StringOpaqueResource(profileSource);
|
||||||
|
assertFalse("new identifier is generated", newId.equals(resource.getResourceId()));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* test update profile.
|
||||||
|
*
|
||||||
|
* @throws XPathExpressionException
|
||||||
|
* should'nt happen
|
||||||
|
* @throws SAXException
|
||||||
|
* should'nt happen
|
||||||
|
* @throws IOException
|
||||||
|
* should'nt happen
|
||||||
|
* @throws ParserConfigurationException
|
||||||
|
* should'nt happen
|
||||||
|
* @throws ISRegistryException
|
||||||
|
* should'nt happen
|
||||||
|
* @throws ISStoreException
|
||||||
|
* should'nt happen
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testUpdateProfile() throws XPathExpressionException, SAXException, IOException, ParserConfigurationException, ISRegistryException,
|
||||||
|
ISStoreException {
|
||||||
|
final OpaqueResource resource = new StringOpaqueResource(profileSource);
|
||||||
|
|
||||||
|
final String fileName = resIdResolver.getFileName(resource.getResourceId());
|
||||||
|
final String fileColl = resIdResolver.getCollectionName(resource.getResourceId());
|
||||||
|
when(storeService.updateXML(eq(fileName), eq(DB_DRIVER + fileColl), anyString())).thenReturn(true);
|
||||||
|
|
||||||
|
when(storeService.getXML(fileName, DB_DRIVER + fileColl)).thenReturn(resource.asString());
|
||||||
|
|
||||||
|
final boolean res = registry.updateProfile(resource.getResourceId(), resource.asString(), resource.getResourceType());
|
||||||
|
assertTrue("success", res);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check that the xml schema is correctly validated even on updateProfile.
|
||||||
|
*
|
||||||
|
* @throws XPathExpressionException
|
||||||
|
* cannot happen
|
||||||
|
* @throws SAXException
|
||||||
|
* cannot happen
|
||||||
|
* @throws IOException
|
||||||
|
* cannot happen
|
||||||
|
* @throws ParserConfigurationException
|
||||||
|
* cannot happen
|
||||||
|
* @throws ISRegistryException
|
||||||
|
* mock
|
||||||
|
* @throws ValidationException
|
||||||
|
* mock
|
||||||
|
*/
|
||||||
|
@Test(expected = ISRegistryException.class)
|
||||||
|
public void testUpdateProfileSchemaValidate() throws XPathExpressionException, SAXException, IOException, ParserConfigurationException,
|
||||||
|
ISRegistryException, ValidationException {
|
||||||
|
final OpaqueResource resource = new StringOpaqueResource(profileSource);
|
||||||
|
|
||||||
|
//doThrow(new ValidationException("invalid xml")).when(validator).validate((OpaqueResource) anyObject());
|
||||||
|
|
||||||
|
registry.updateProfile(resource.getResourceId(), "<invalid/>", resource.getResourceType());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* test profile validation.
|
||||||
|
*
|
||||||
|
* @throws XPathExpressionException
|
||||||
|
* shouldn't happen
|
||||||
|
* @throws SAXException
|
||||||
|
* shouldn't happen
|
||||||
|
* @throws IOException
|
||||||
|
* shouldn't happen
|
||||||
|
* @throws ParserConfigurationException
|
||||||
|
* shouldn't happen
|
||||||
|
* @throws ISRegistryException
|
||||||
|
* shouldn't happen
|
||||||
|
* @throws ISStoreException
|
||||||
|
* shouldn't happen
|
||||||
|
* @throws ISLookUpException
|
||||||
|
* shouldn't happen
|
||||||
|
* @throws ValidationException
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testValidateProfile() throws XPathExpressionException, SAXException, IOException, ParserConfigurationException, ISRegistryException,
|
||||||
|
ISStoreException, ISLookUpException, ValidationException {
|
||||||
|
final OpaqueResource resource = new StringOpaqueResource(profileSource);
|
||||||
|
|
||||||
|
final String oldId = registry.insertProfileForValidation(resource.getResourceType(), resource.asString());
|
||||||
|
resource.setResourceKind("PendingRepositoryResources"); // simulate the validation
|
||||||
|
|
||||||
|
resource.setResourceId(oldId);
|
||||||
|
when(lookUpService.getResourceProfile(oldId)).thenReturn(resource.asString());
|
||||||
|
when(storeService.deleteXML(resIdResolver.getFileName(oldId), DB_DRIVER + resIdResolver.getCollectionName(oldId))).thenReturn(true);
|
||||||
|
when(profileValidationStrategy.accept((OpaqueResource) anyObject(), eq(RegistrationPhase.Register))).thenReturn(true);
|
||||||
|
|
||||||
|
final String newId = registry.validateProfile(oldId);
|
||||||
|
|
||||||
|
verify(storeService).deleteXML(resIdResolver.getFileName(oldId), DB_DRIVER + resIdResolver.getCollectionName(oldId));
|
||||||
|
verify(storeService).insertXML(eq(resIdResolver.getFileName(newId)), eq(DB_DRIVER + resIdResolver.getCollectionName(newId)), anyString());
|
||||||
|
|
||||||
|
assertFalse("the id should be be unstable", resIdResolver.getFileName(oldId).equals(resIdResolver.getFileName(newId)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* test invalidate profile.
|
||||||
|
*
|
||||||
|
* @throws XPathExpressionException
|
||||||
|
* shouldn't happen
|
||||||
|
* @throws SAXException
|
||||||
|
* shouldn't happen
|
||||||
|
* @throws IOException
|
||||||
|
* shouldn't happen
|
||||||
|
* @throws ParserConfigurationException
|
||||||
|
* shouldn't happen
|
||||||
|
* @throws ISRegistryException
|
||||||
|
* shouldn't happen
|
||||||
|
* @throws ISStoreException
|
||||||
|
* shouldn't happen
|
||||||
|
* @throws ISLookUpException
|
||||||
|
* shouldn't happen
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testInvalidateProfile() throws XPathExpressionException, SAXException, IOException, ParserConfigurationException, ISRegistryException,
|
||||||
|
ISStoreException, ISLookUpException {
|
||||||
|
|
||||||
|
final OpaqueResource resource = new StringOpaqueResource(profileSource);
|
||||||
|
resource.setResourceKind("PendingResources");
|
||||||
|
|
||||||
|
final String oldId = registry.registerProfile(resource.asString());
|
||||||
|
|
||||||
|
resource.setResourceId(oldId);
|
||||||
|
when(lookUpService.getResourceProfile(oldId)).thenReturn(resource.asString());
|
||||||
|
when(storeService.deleteXML(resIdResolver.getFileName(oldId), DB_DRIVER + resIdResolver.getCollectionName(oldId))).thenReturn(true);
|
||||||
|
|
||||||
|
final String newId = registry.invalidateProfile(oldId);
|
||||||
|
|
||||||
|
verify(storeService).deleteXML(resIdResolver.getFileName(oldId), DB_DRIVER + resIdResolver.getCollectionName(oldId));
|
||||||
|
verify(storeService).insertXML(eq(resIdResolver.getFileName(newId)), eq(DB_DRIVER + resIdResolver.getCollectionName(newId)), anyString());
|
||||||
|
|
||||||
|
assertFalse("the id should be be unstable", resIdResolver.getFileName(oldId).equals(resIdResolver.getFileName(newId)));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* test that the resource kind is correctly changed when inserting for validation.
|
||||||
|
*
|
||||||
|
* @throws IOException
|
||||||
|
* shouldn't happen
|
||||||
|
* @throws ISRegistryException
|
||||||
|
* shouldn't happen
|
||||||
|
* @throws ISStoreException
|
||||||
|
* shouldn't happen
|
||||||
|
* @throws XPathExpressionException
|
||||||
|
* shouldn't happen
|
||||||
|
* @throws SAXException
|
||||||
|
* shouldn't happen
|
||||||
|
* @throws ParserConfigurationException
|
||||||
|
* shouldn't happen
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testInsertProfileForValidation() throws IOException, ISRegistryException, ISStoreException, XPathExpressionException, SAXException,
|
||||||
|
ParserConfigurationException {
|
||||||
|
|
||||||
|
final OpaqueResource resource = new StringOpaqueResource(profileSource);
|
||||||
|
final String newId = registry.insertProfileForValidation(resource.getResourceType(), resource.asString());
|
||||||
|
|
||||||
|
verify(storeService).insertXML(eq(resIdResolver.getFileName(newId)), eq(DB_DRIVER + "PendingRepositoryResources/RepositoryServiceResourceType"),
|
||||||
|
anyString());
|
||||||
|
|
||||||
|
verify(storeService, never()).deleteXML(anyString(), anyString());
|
||||||
|
|
||||||
|
assertEquals("check pending id", "PendingRepositoryResources/RepositoryServiceResourceType", resIdResolver.getCollectionName(newId));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The ISRegistry's insertProfileForValidation contract specifies that an exception should be raised if the argument doesn't match the
|
||||||
|
* type.
|
||||||
|
*
|
||||||
|
* @throws IOException
|
||||||
|
* shouldn't happen
|
||||||
|
* @throws ISRegistryException
|
||||||
|
* expected
|
||||||
|
*/
|
||||||
|
@Test(expected = ISRegistryException.class)
|
||||||
|
public void testInsertProfileForValidationInvalid() throws IOException, ISRegistryException {
|
||||||
|
registry.insertProfileForValidation("WrongRepositoryServiceResourceType", profileSource);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* test resource type addition.
|
||||||
|
*
|
||||||
|
* @throws ISRegistryException
|
||||||
|
* shouldn't happen
|
||||||
|
* @throws IOException
|
||||||
|
* shouldn't happen
|
||||||
|
* @throws ISStoreException
|
||||||
|
* cannot happen, mock
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testAddResourceType() throws ISRegistryException, IOException, ISStoreException {
|
||||||
|
final StringWriter resourceSchema = new StringWriter();
|
||||||
|
|
||||||
|
IOUtils.copy(getClass().getResourceAsStream("RepositoryServiceResourceType.xsd"), resourceSchema);
|
||||||
|
assertNotNull("check schema", resourceSchema.toString());
|
||||||
|
|
||||||
|
registry.addResourceType(REPOSITORY_TYPE, resourceSchema.toString());
|
||||||
|
|
||||||
|
verify(storeService).insertXML(REPOSITORY_TYPE, xqueryUtils.getRootCollection() + ResourceType.RESOURCE_TYPES, resourceSchema.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* test resource type deletion.
|
||||||
|
*
|
||||||
|
* @throws ISRegistryException
|
||||||
|
* shouldn't happen
|
||||||
|
* @throws ISStoreException
|
||||||
|
* cannot happen, mock
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testDeleteResourceType() throws ISRegistryException, ISStoreException {
|
||||||
|
assertNotNull("dummy", registry);
|
||||||
|
|
||||||
|
registry.deleteResourceType(REPOSITORY_TYPE, false);
|
||||||
|
|
||||||
|
verify(storeService).deleteXML(REPOSITORY_TYPE, xqueryUtils.getRootCollection() + ResourceType.RESOURCE_TYPES);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* register secure profile.
|
||||||
|
*
|
||||||
|
* @throws ISRegistryException
|
||||||
|
* shouldn't happen
|
||||||
|
* @throws ISLookUpException
|
||||||
|
* mocked
|
||||||
|
* @throws IOException
|
||||||
|
* shouldn't happen
|
||||||
|
* @throws ISStoreException
|
||||||
|
* mock
|
||||||
|
* @throws ValidationException
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testRegisterSecureProfile() throws ISRegistryException, ISLookUpException, IOException, ISStoreException, ValidationException { // NOPMD
|
||||||
|
final String resourceProfId = "12-70b2a9e0-7d53-4ffb-be43-f3c571ae21a6_VXNlckRTUmVzb3VyY2VzL1VzZXJEU1Jlc291cmNlVHlwZQ==";
|
||||||
|
final String secureProfId = "sec123_U2VjdXJpdHlQcm9maWxlRFNSZXNvdXJjZXMvU2VjdXJpdHlQcm9maWxlRFNSZXNvdXJjZVR5cGU=";
|
||||||
|
|
||||||
|
final StringWriter profile = new StringWriter();
|
||||||
|
IOUtils.copy(getClass().getResourceAsStream("userProfile.xml"), profile);
|
||||||
|
when(lookUpService.getResourceProfile(resourceProfId)).thenReturn(profile.toString());
|
||||||
|
when(profileValidationStrategy.accept((OpaqueResource) anyObject(), eq(RegistrationPhase.Register))).thenReturn(true);
|
||||||
|
|
||||||
|
final StringWriter secure = new StringWriter();
|
||||||
|
IOUtils.copy(getClass().getResourceAsStream("securityProfile.xml"), secure);
|
||||||
|
when(lookUpService.getResourceProfile(secureProfId)).thenReturn(secure.toString());
|
||||||
|
when(storeService.deleteXML(resIdResolver.getFileName(resourceProfId), DB_DRIVER + resIdResolver.getCollectionName(resourceProfId))).thenReturn(
|
||||||
|
true);
|
||||||
|
when(storeService.updateXML(eq("sec123"), eq(DB_DRIVER + "SecurityProfileDSResources/SecurityProfileDSResourceType"), anyString())).thenReturn(
|
||||||
|
true);
|
||||||
|
when(storeService.getXML("sec123", DB_DRIVER + "SecurityProfileDSResources/SecurityProfileDSResourceType")).thenReturn("<RESOURCE_PROFILE/>");
|
||||||
|
|
||||||
|
registry.registerSecureProfile(resourceProfId, secureProfId);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,41 @@
|
||||||
|
package eu.dnetlib.enabling.is.registry;
|
||||||
|
|
||||||
|
|
||||||
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
|
import javax.xml.xpath.XPathExpressionException;
|
||||||
|
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test the name based resource kind resolver.
|
||||||
|
*
|
||||||
|
* @author marko
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class NameBasedResourceKindResolverTest {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* instance under test.
|
||||||
|
*/
|
||||||
|
private NameBasedResourceKindResolver resolver;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() throws Exception {
|
||||||
|
resolver = new NameBasedResourceKindResolver();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testService() throws XPathExpressionException {
|
||||||
|
assertEquals("ServiceResources", resolver.getNormalKindForType("MyNewServiceResourceType"));
|
||||||
|
assertEquals("PendingServiceResources", resolver.getPendingKindForType("MyNewServiceResourceType"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGeneric() throws XPathExpressionException {
|
||||||
|
assertEquals("MyNewResources", resolver.getNormalKindForType("MyNewResourceType"));
|
||||||
|
assertEquals("PendingDSResources", resolver.getPendingKindForType("MyNewResourceType"));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,293 @@
|
||||||
|
package eu.dnetlib.enabling.is.registry; // NOPMD
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertNull;
|
||||||
|
import static org.junit.Assert.fail;
|
||||||
|
import static org.mockito.Matchers.anyString;
|
||||||
|
import static org.mockito.Matchers.argThat;
|
||||||
|
import static org.mockito.Matchers.eq;
|
||||||
|
import static org.mockito.Mockito.verify;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.StringWriter;
|
||||||
|
|
||||||
|
import javax.xml.bind.JAXBException;
|
||||||
|
import javax.xml.transform.dom.DOMSource;
|
||||||
|
import javax.xml.xpath.XPathConstants;
|
||||||
|
import javax.xml.xpath.XPathFactory;
|
||||||
|
|
||||||
|
import org.apache.commons.io.IOUtils;
|
||||||
|
import org.apache.commons.logging.Log;
|
||||||
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.mockito.ArgumentMatcher;
|
||||||
|
import org.mockito.Mock;
|
||||||
|
import org.mockito.junit.MockitoJUnitRunner;
|
||||||
|
import org.w3c.dom.Element;
|
||||||
|
import org.w3c.dom.Node;
|
||||||
|
|
||||||
|
import eu.dnetlib.enabling.is.lookup.rmi.ISLookUpException;
|
||||||
|
import eu.dnetlib.enabling.is.lookup.rmi.ISLookUpService;
|
||||||
|
import eu.dnetlib.enabling.is.registry.rmi.ISRegistryException;
|
||||||
|
import eu.dnetlib.enabling.is.registry.rmi.ISRegistryService;
|
||||||
|
import eu.dnetlib.enabling.tools.OpaqueResource;
|
||||||
|
import eu.dnetlib.enabling.tools.StringOpaqueResource;
|
||||||
|
import eu.dnetlib.enabling.tools.blackboard.ActionStatus;
|
||||||
|
import eu.dnetlib.enabling.tools.blackboard.BlackboardMessage;
|
||||||
|
import eu.dnetlib.enabling.tools.blackboard.BlackboardMessageImpl;
|
||||||
|
import eu.dnetlib.enabling.tools.blackboard.BlackboardParameter;
|
||||||
|
import eu.dnetlib.enabling.tools.blackboard.BlackboardParameterImpl;
|
||||||
|
import eu.dnetlib.miscutils.jaxb.JaxbFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* RegistryBlackboardManagerImpl test.
|
||||||
|
*
|
||||||
|
* @author marko
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@RunWith(MockitoJUnitRunner.class)
|
||||||
|
public class RegistryBlackboardManagerImplTest {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* logger.
|
||||||
|
*/
|
||||||
|
private static final Log log = LogFactory.getLog(RegistryBlackboardManagerImplTest.class); // NOPMD by marko on 11/24/08 5:02 PM
|
||||||
|
|
||||||
|
/**
|
||||||
|
* test message id.
|
||||||
|
*/
|
||||||
|
private static final String MSG_ID = "xxx";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fake message date.
|
||||||
|
*/
|
||||||
|
private static final String MSG_DATE = "2009-03-19T17:55:45+01:00";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* service profile ID.
|
||||||
|
*/
|
||||||
|
private static final String PROF_ID = "123";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* lookup service mock.
|
||||||
|
*/
|
||||||
|
@Mock
|
||||||
|
private transient ISLookUpService lookupService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* registry service mock.
|
||||||
|
*/
|
||||||
|
@Mock
|
||||||
|
private transient ISRegistryService registryService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* instance under test.
|
||||||
|
*/
|
||||||
|
private transient RegistryBlackboardManagerImpl manager;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* common setup.
|
||||||
|
*
|
||||||
|
* @throws JAXBException
|
||||||
|
* could happen
|
||||||
|
* @throws IOException
|
||||||
|
* shouldn't happen
|
||||||
|
* @throws ISLookUpException
|
||||||
|
* mock
|
||||||
|
*/
|
||||||
|
@Before
|
||||||
|
public void setUp() throws JAXBException, IOException, ISLookUpException {
|
||||||
|
manager = new RegistryBlackboardManagerImpl();
|
||||||
|
manager.setIsLookup(lookupService);
|
||||||
|
manager.setRegistryService(registryService);
|
||||||
|
|
||||||
|
manager.setMessageFactory(new JaxbFactory<BlackboardMessage>(BlackboardMessageImpl.class));
|
||||||
|
|
||||||
|
manager.setMessageDater(new RegistryBlackboardManagerImpl.MessageDater() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getCurrentDate() {
|
||||||
|
return MSG_DATE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getNumericStamp() {
|
||||||
|
return "1237483712.666000";
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* add message.
|
||||||
|
*
|
||||||
|
* @throws JAXBException
|
||||||
|
* could happen
|
||||||
|
* @throws ISRegistryException
|
||||||
|
* could happen
|
||||||
|
* @throws IOException
|
||||||
|
* could happen
|
||||||
|
* @throws ISLookUpException
|
||||||
|
* mock
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testAddMessage() throws JAXBException, ISRegistryException, IOException, ISLookUpException {
|
||||||
|
final StringWriter serviceProfile = new StringWriter();
|
||||||
|
IOUtils.copy(getClass().getResourceAsStream("serviceProfile.xml"), serviceProfile);
|
||||||
|
when(lookupService.getResourceProfile(PROF_ID)).thenReturn(serviceProfile.toString());
|
||||||
|
|
||||||
|
final BlackboardMessage message = manager.getMessageFactory().newInstance();
|
||||||
|
message.setId(MSG_ID);
|
||||||
|
message.setDate(MSG_DATE);
|
||||||
|
message.setAction("CREATE");
|
||||||
|
message.setActionStatus(ActionStatus.ASSIGNED);
|
||||||
|
|
||||||
|
final BlackboardParameter param1 = new BlackboardParameterImpl();
|
||||||
|
param1.setName("format");
|
||||||
|
param1.setValue("DMF");
|
||||||
|
message.getParameters().add(param1);
|
||||||
|
|
||||||
|
final BlackboardParameter param2 = new BlackboardParameterImpl();
|
||||||
|
param1.setName("id");
|
||||||
|
param1.setValue("");
|
||||||
|
message.getParameters().add(param2);
|
||||||
|
|
||||||
|
manager.addMessage(PROF_ID, MSG_ID, manager.getMessageFactory().serialize(message));
|
||||||
|
|
||||||
|
verify(registryService).updateProfile(eq(PROF_ID), argThat(new ArgumentMatcher<String>() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean matches(final String argument) {
|
||||||
|
log.info("arg: " + argument);
|
||||||
|
|
||||||
|
try {
|
||||||
|
final OpaqueResource updatedResource = new StringOpaqueResource((String) argument);
|
||||||
|
final Node messageNode = (Node) XPathFactory.newInstance().newXPath().evaluate("//BLACKBOARD/MESSAGE[last()]",
|
||||||
|
updatedResource.asDom(), XPathConstants.NODE);
|
||||||
|
|
||||||
|
final BlackboardMessage updatedMessage = manager.getMessageFactory().parse(new DOMSource(messageNode));
|
||||||
|
|
||||||
|
assertEquals("messages should match", message, updatedMessage);
|
||||||
|
|
||||||
|
final Element lastUpdated = (Element) XPathFactory.newInstance().newXPath().evaluate("//BLACKBOARD/LAST_REQUEST",
|
||||||
|
updatedResource.asDom(), XPathConstants.NODE);
|
||||||
|
assertEquals("stamp date", manager.getMessageDater().getNumericStamp(), lastUpdated.getAttribute("date"));
|
||||||
|
assertEquals("stamp message", MSG_ID, lastUpdated.getTextContent());
|
||||||
|
} catch (Exception e) {
|
||||||
|
fail("got exception" + e);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}), anyString());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* delete message.
|
||||||
|
*
|
||||||
|
* @throws ISLookUpException
|
||||||
|
* mock
|
||||||
|
* @throws IOException
|
||||||
|
* could happen
|
||||||
|
* @throws ISRegistryException
|
||||||
|
* mock
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testDeleteMessage() throws ISLookUpException, IOException, ISRegistryException {
|
||||||
|
final StringWriter serviceProfile = new StringWriter();
|
||||||
|
|
||||||
|
IOUtils.copy(getClass().getResourceAsStream("serviceProfileWithMessage.xml"), serviceProfile);
|
||||||
|
when(lookupService.getResourceProfile(PROF_ID)).thenReturn(serviceProfile.toString());
|
||||||
|
|
||||||
|
manager.deleteMessage(PROF_ID, MSG_ID);
|
||||||
|
|
||||||
|
verify(registryService).updateProfile(eq(PROF_ID), argThat(new ArgumentMatcher<String>() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean matches(final String argument) {
|
||||||
|
log.debug("arg: " + argument);
|
||||||
|
|
||||||
|
try {
|
||||||
|
final OpaqueResource updatedResource = new StringOpaqueResource((String) argument);
|
||||||
|
|
||||||
|
final Node messageNode = (Node) XPathFactory.newInstance().newXPath().evaluate("//BLACKBOARD/MESSAGE[last()]",
|
||||||
|
updatedResource.asDom(), XPathConstants.NODE);
|
||||||
|
|
||||||
|
assertNull("message should be deleted", messageNode);
|
||||||
|
} catch (Exception e) {
|
||||||
|
fail("got exception" + e);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}), anyString());
|
||||||
|
|
||||||
|
// assertNotNull("dummy", manager);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* replay message.
|
||||||
|
*
|
||||||
|
* @throws ISLookUpException
|
||||||
|
* mock
|
||||||
|
* @throws IOException
|
||||||
|
* shouldn't happen
|
||||||
|
* @throws ISRegistryException
|
||||||
|
* mock
|
||||||
|
* @throws JAXBException
|
||||||
|
* could happen
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testReplyMessage() throws ISLookUpException, IOException, ISRegistryException, JAXBException {
|
||||||
|
final StringWriter serviceProfile = new StringWriter();
|
||||||
|
|
||||||
|
IOUtils.copy(getClass().getResourceAsStream("serviceProfileWithMessage.xml"), serviceProfile);
|
||||||
|
when(lookupService.getResourceProfile(PROF_ID)).thenReturn(serviceProfile.toString());
|
||||||
|
|
||||||
|
final BlackboardMessage message = manager.getMessageFactory().newInstance();
|
||||||
|
message.setId(MSG_ID);
|
||||||
|
message.setDate(MSG_DATE);
|
||||||
|
message.setAction("CREATE");
|
||||||
|
message.setActionStatus(ActionStatus.ONGOING);
|
||||||
|
|
||||||
|
final BlackboardParameter param1 = new BlackboardParameterImpl();
|
||||||
|
param1.setName("format");
|
||||||
|
param1.setValue("DMF");
|
||||||
|
message.getParameters().add(param1);
|
||||||
|
|
||||||
|
final BlackboardParameter param2 = new BlackboardParameterImpl();
|
||||||
|
param1.setName("id");
|
||||||
|
param1.setValue("");
|
||||||
|
message.getParameters().add(param2);
|
||||||
|
|
||||||
|
manager.replyMessage(PROF_ID, manager.getMessageFactory().serialize(message));
|
||||||
|
|
||||||
|
verify(registryService).updateProfile(eq(PROF_ID), argThat(new ArgumentMatcher<String>() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean matches(final String argument) {
|
||||||
|
log.info("arg: " + argument);
|
||||||
|
|
||||||
|
try {
|
||||||
|
final OpaqueResource updatedResource = new StringOpaqueResource((String) argument);
|
||||||
|
|
||||||
|
final Node messageNode = (Node) XPathFactory.newInstance().newXPath().evaluate("//BLACKBOARD/MESSAGE[last()]",
|
||||||
|
updatedResource.asDom(), XPathConstants.NODE);
|
||||||
|
|
||||||
|
final BlackboardMessage updatedMessage = manager.getMessageFactory().parse(new DOMSource(messageNode));
|
||||||
|
|
||||||
|
assertEquals("messages should match", message, updatedMessage);
|
||||||
|
|
||||||
|
final Element lastUpdated = (Element) XPathFactory.newInstance().newXPath().evaluate("//BLACKBOARD/LAST_RESPONSE",
|
||||||
|
updatedResource.asDom(), XPathConstants.NODE);
|
||||||
|
assertEquals("stamp date", manager.getMessageDater().getNumericStamp(), lastUpdated.getAttribute("date"));
|
||||||
|
assertEquals("stamp message", MSG_ID, lastUpdated.getTextContent());
|
||||||
|
} catch (Exception e) {
|
||||||
|
fail("got exception" + e);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}), anyString());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,36 @@
|
||||||
|
package eu.dnetlib.enabling.is.registry;
|
||||||
|
|
||||||
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
|
import javax.xml.xpath.XPathExpressionException;
|
||||||
|
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import com.google.common.collect.Lists;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test if the kind resolver chain correctly fails back.
|
||||||
|
*
|
||||||
|
* @author marko
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class ResourceKindResolverChainTest {
|
||||||
|
|
||||||
|
private ResourceKindResolverChain chain;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() throws Exception {
|
||||||
|
chain = new ResourceKindResolverChain();
|
||||||
|
chain.setResolvers(Lists.newArrayList(new ApplicationProfileResourceKindResolver(), new NameBasedResourceKindResolver()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testChain() throws XPathExpressionException {
|
||||||
|
assertEquals("ServiceResources", chain.getNormalKindForType("MyServiceResourceType"));
|
||||||
|
assertEquals("PendingServiceResources", chain.getPendingKindForType("MyServiceResourceType"));
|
||||||
|
|
||||||
|
assertEquals("RepositoryServiceResources", chain.getNormalKindForType("RepositoryServiceResourceType"));
|
||||||
|
assertEquals("PendingRepositoryResources", chain.getPendingKindForType("RepositoryServiceResourceType"));
|
||||||
|
}
|
||||||
|
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue