refs #1746: Separate Accounting Model and generalize solution
https://support.d4science.org/issues/1746 git-svn-id: https://svn.d4science.research-infrastructures.eu/gcube/trunk/data-publishing/document-store-lib--mongodb@121989 82a268e6-3cf1-43bd-a215-b396298e98cf
This commit is contained in:
commit
28f552106d
|
@ -0,0 +1,28 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<classpath>
|
||||||
|
<classpathentry kind="src" output="target/classes" path="src/main/java">
|
||||||
|
<attributes>
|
||||||
|
<attribute name="optional" value="true"/>
|
||||||
|
<attribute name="maven.pomderived" value="true"/>
|
||||||
|
</attributes>
|
||||||
|
</classpathentry>
|
||||||
|
<classpathentry including="**/*.java" kind="src" path="src/main/resources"/>
|
||||||
|
<classpathentry kind="src" output="target/test-classes" path="src/test/java">
|
||||||
|
<attributes>
|
||||||
|
<attribute name="optional" value="true"/>
|
||||||
|
<attribute name="maven.pomderived" value="true"/>
|
||||||
|
</attributes>
|
||||||
|
</classpathentry>
|
||||||
|
<classpathentry including="**/*.java" kind="src" path="src/test/resources"/>
|
||||||
|
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.7">
|
||||||
|
<attributes>
|
||||||
|
<attribute name="maven.pomderived" value="true"/>
|
||||||
|
</attributes>
|
||||||
|
</classpathentry>
|
||||||
|
<classpathentry kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER">
|
||||||
|
<attributes>
|
||||||
|
<attribute name="maven.pomderived" value="true"/>
|
||||||
|
</attributes>
|
||||||
|
</classpathentry>
|
||||||
|
<classpathentry kind="output" path="target/classes"/>
|
||||||
|
</classpath>
|
|
@ -0,0 +1,23 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<projectDescription>
|
||||||
|
<name>document-store-lib-mongodb</name>
|
||||||
|
<comment></comment>
|
||||||
|
<projects>
|
||||||
|
</projects>
|
||||||
|
<buildSpec>
|
||||||
|
<buildCommand>
|
||||||
|
<name>org.eclipse.jdt.core.javabuilder</name>
|
||||||
|
<arguments>
|
||||||
|
</arguments>
|
||||||
|
</buildCommand>
|
||||||
|
<buildCommand>
|
||||||
|
<name>org.eclipse.m2e.core.maven2Builder</name>
|
||||||
|
<arguments>
|
||||||
|
</arguments>
|
||||||
|
</buildCommand>
|
||||||
|
</buildSpec>
|
||||||
|
<natures>
|
||||||
|
<nature>org.eclipse.jdt.core.javanature</nature>
|
||||||
|
<nature>org.eclipse.m2e.core.maven2Nature</nature>
|
||||||
|
</natures>
|
||||||
|
</projectDescription>
|
|
@ -0,0 +1,6 @@
|
||||||
|
eclipse.preferences.version=1
|
||||||
|
encoding//src/main/java=UTF-8
|
||||||
|
encoding//src/main/resources=UTF-8
|
||||||
|
encoding//src/test/java=UTF-8
|
||||||
|
encoding//src/test/resources=UTF-8
|
||||||
|
encoding/<project>=UTF-8
|
|
@ -0,0 +1,5 @@
|
||||||
|
eclipse.preferences.version=1
|
||||||
|
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.7
|
||||||
|
org.eclipse.jdt.core.compiler.compliance=1.7
|
||||||
|
org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
|
||||||
|
org.eclipse.jdt.core.compiler.source=1.7
|
|
@ -0,0 +1,4 @@
|
||||||
|
activeProfiles=
|
||||||
|
eclipse.preferences.version=1
|
||||||
|
resolveWorkspaceProjects=true
|
||||||
|
version=1
|
|
@ -0,0 +1,104 @@
|
||||||
|
<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/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<parent>
|
||||||
|
<groupId>org.gcube.tools</groupId>
|
||||||
|
<artifactId>maven-parent</artifactId>
|
||||||
|
<version>1.0.0</version>
|
||||||
|
</parent>
|
||||||
|
|
||||||
|
<groupId>org.gcube.data.publishing</groupId>
|
||||||
|
<artifactId>document-store-lib-mongodb</artifactId>
|
||||||
|
<version>1.0.0-SNAPSHOT</version>
|
||||||
|
<name>Document Store MongoDB</name>
|
||||||
|
<description>Document Store MongoDB Implementation</description>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
|
<distroDirectory>${project.basedir}/distro</distroDirectory>
|
||||||
|
</properties>
|
||||||
|
|
||||||
|
<scm>
|
||||||
|
<connection>scm:https://svn.d4science.research-infrastructures.eu/gcube/trunk/data-publishing/${project.artifactId}</connection>
|
||||||
|
<developerConnection>scm:https://svn.d4science.research-infrastructures.eu/gcube/trunk/data-publishing/${project.artifactId}</developerConnection>
|
||||||
|
<url>https://svn.d4science.research-infrastructures.eu/gcube/trunk/data-publishing/${project.artifactId}</url>
|
||||||
|
</scm>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.gcube.data.publishing</groupId>
|
||||||
|
<artifactId>document-store-lib</artifactId>
|
||||||
|
<version>[1.0.0-SNAPSHOT, 2.0.0-SNAPSHOT)</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.slf4j</groupId>
|
||||||
|
<artifactId>slf4j-api</artifactId>
|
||||||
|
<version>1.7.5</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.mongodb</groupId>
|
||||||
|
<artifactId>mongo-java-driver</artifactId>
|
||||||
|
<version>[3.0.0, 3.0.7]</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.reflections</groupId>
|
||||||
|
<artifactId>reflections</artifactId>
|
||||||
|
<version>0.9.9-RC1</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- Test Dependency -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.gcube.accounting</groupId>
|
||||||
|
<artifactId>accounting-lib</artifactId>
|
||||||
|
<version>[2.0.0-SNAPSHOT, 3.0.0-SNAPSHOT)</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.gcube.core</groupId>
|
||||||
|
<artifactId>common-encryption</artifactId>
|
||||||
|
<version>[1.0.2-SNAPSHOT, 2.0.0-SNAPSHOT)</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.gcube.resources</groupId>
|
||||||
|
<artifactId>registry-publisher</artifactId>
|
||||||
|
<version>[1.0.0-SNAPSHOT,)</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>junit</groupId>
|
||||||
|
<artifactId>junit</artifactId>
|
||||||
|
<version>4.11</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>ch.qos.logback</groupId>
|
||||||
|
<artifactId>logback-classic</artifactId>
|
||||||
|
<version>1.0.13</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-assembly-plugin</artifactId>
|
||||||
|
<configuration>
|
||||||
|
<descriptorRefs>
|
||||||
|
<descriptorRef>jar-with-dependencies</descriptorRef>
|
||||||
|
</descriptorRefs>
|
||||||
|
</configuration>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<phase>package</phase>
|
||||||
|
<goals>
|
||||||
|
<goal>single</goal>
|
||||||
|
</goals>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
|
||||||
|
</project>
|
|
@ -0,0 +1,35 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
package org.gcube.documentstore.persistence;
|
||||||
|
|
||||||
|
import org.bson.BsonReader;
|
||||||
|
import org.bson.BsonWriter;
|
||||||
|
import org.bson.codecs.Codec;
|
||||||
|
import org.bson.codecs.DecoderContext;
|
||||||
|
import org.bson.codecs.EncoderContext;
|
||||||
|
|
||||||
|
public class EnumCodec<E extends Enum<E>> implements Codec<E> {
|
||||||
|
|
||||||
|
protected final Class<E> eClass;
|
||||||
|
|
||||||
|
public EnumCodec(Class<E> eClass){
|
||||||
|
this.eClass = eClass;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void encode(BsonWriter writer, E e, EncoderContext ec) {
|
||||||
|
writer.writeString(e.name());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Class<E> getEncoderClass() {
|
||||||
|
return this.eClass;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public E decode(BsonReader reader, DecoderContext dc) {
|
||||||
|
String enumString = reader.readString();
|
||||||
|
return (E) Enum.valueOf(getEncoderClass(), enumString);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,50 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
package org.gcube.documentstore.persistence;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.lang.reflect.Constructor;
|
||||||
|
|
||||||
|
import org.bson.BsonReader;
|
||||||
|
import org.bson.BsonWriter;
|
||||||
|
import org.bson.codecs.Codec;
|
||||||
|
import org.bson.codecs.DecoderContext;
|
||||||
|
import org.bson.codecs.EncoderContext;
|
||||||
|
|
||||||
|
public class GenericCodec<T extends Comparable<? extends Serializable>> implements Codec<T> {
|
||||||
|
|
||||||
|
protected final Class<T> tClass;
|
||||||
|
|
||||||
|
public GenericCodec(Class<T> tClass){
|
||||||
|
this.tClass = tClass;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void encode(BsonWriter writer, T t, EncoderContext ec) {
|
||||||
|
writer.writeString(t.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Class<T> getEncoderClass() {
|
||||||
|
return tClass;
|
||||||
|
}
|
||||||
|
|
||||||
|
public T getFromString(String stringRepresentation) throws Exception {
|
||||||
|
@SuppressWarnings("rawtypes")
|
||||||
|
Class[] argTypes = { String.class };
|
||||||
|
Constructor<T> constructor = getEncoderClass().getDeclaredConstructor(argTypes);
|
||||||
|
Object[] arguments = {stringRepresentation};
|
||||||
|
return constructor.newInstance(arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public T decode(BsonReader reader, DecoderContext dc) {
|
||||||
|
String stringRepresentation = reader.readString();
|
||||||
|
try {
|
||||||
|
return getFromString(stringRepresentation);
|
||||||
|
} catch(Exception e){
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,255 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
package org.gcube.documentstore.persistence;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.net.URI;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Map.Entry;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.bson.Document;
|
||||||
|
import org.bson.codecs.Codec;
|
||||||
|
import org.bson.codecs.configuration.CodecConfigurationException;
|
||||||
|
import org.bson.codecs.configuration.CodecRegistries;
|
||||||
|
import org.bson.codecs.configuration.CodecRegistry;
|
||||||
|
import org.gcube.documentstore.records.Record;
|
||||||
|
import org.gcube.documentstore.records.RecordUtility;
|
||||||
|
import org.reflections.Reflections;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import com.mongodb.MongoClient;
|
||||||
|
import com.mongodb.MongoClientOptions;
|
||||||
|
import com.mongodb.MongoCredential;
|
||||||
|
import com.mongodb.ReadPreference;
|
||||||
|
import com.mongodb.ServerAddress;
|
||||||
|
import com.mongodb.client.MongoDatabase;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Luca Frosini (ISTI - CNR) http://www.lucafrosini.com/
|
||||||
|
*/
|
||||||
|
public class PersistenceMongoDB extends PersistenceBackend {
|
||||||
|
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger(PersistenceMongoDB.class);
|
||||||
|
|
||||||
|
public static final String URL_PROPERTY_KEY = "URL";
|
||||||
|
public static final String USERNAME_PROPERTY_KEY = "username";
|
||||||
|
public static final String PASSWORD_PROPERTY_KEY = "password";
|
||||||
|
public static final String DB_NAME = "dbName";
|
||||||
|
public static final String COLLECTION_NAME = "collectionName";
|
||||||
|
|
||||||
|
protected String collectionName;
|
||||||
|
|
||||||
|
protected static final ReadPreference READ_PREFERENCE;
|
||||||
|
protected static final MongoClientOptions MONGO_CLIENT_OPTIONS;
|
||||||
|
|
||||||
|
static {
|
||||||
|
READ_PREFERENCE = ReadPreference.secondaryPreferred();
|
||||||
|
|
||||||
|
List<? extends Codec<?>> additionalCodecs = discoverAdditionalCodecs();
|
||||||
|
CodecRegistry mongoDefaultCR = MongoClient.getDefaultCodecRegistry();
|
||||||
|
CodecRegistry cr = addCoded(mongoDefaultCR, additionalCodecs);
|
||||||
|
MONGO_CLIENT_OPTIONS = createMongoClientOptions(cr);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
protected PersistenceBackendConfiguration configuration;
|
||||||
|
protected MongoClient mongoClient;
|
||||||
|
protected MongoClientOptions mongoClientOptions;
|
||||||
|
protected MongoDatabase mongoDatabase;
|
||||||
|
|
||||||
|
public static CodecRegistry addCoded(CodecRegistry cr, List<? extends Codec<?>> codecs){
|
||||||
|
CodecRegistry crFromCodes = CodecRegistries.fromCodecs(codecs);
|
||||||
|
return CodecRegistries.fromRegistries(cr, crFromCodes);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static MongoClientOptions createMongoClientOptions(CodecRegistry cr){
|
||||||
|
/*
|
||||||
|
mongoClientOptions = MongoClientOptions.builder().
|
||||||
|
codecRegistry(cr).connectionsPerHost(10).connectTimeout(30000).
|
||||||
|
readPreference(READ_PREFERENCE).build();
|
||||||
|
*/
|
||||||
|
return MongoClientOptions.builder().codecRegistry(cr).build();
|
||||||
|
}
|
||||||
|
|
||||||
|
public PersistenceMongoDB() throws Exception {
|
||||||
|
super();
|
||||||
|
mongoClientOptions = MONGO_CLIENT_OPTIONS;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() throws Exception {
|
||||||
|
mongoClient.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||||
|
public static List<? extends Codec<?>> discoverAdditionalCodecs(){
|
||||||
|
List codecs = new ArrayList();
|
||||||
|
|
||||||
|
Set<Class<? extends Enum>> enumClasses = new HashSet<>();
|
||||||
|
|
||||||
|
Reflections recordClassesReflections = new Reflections();
|
||||||
|
Set<Class<? extends Record>> recordClasses = recordClassesReflections.getSubTypesOf(Record.class);
|
||||||
|
for(Class<? extends Record> recordClass : recordClasses){
|
||||||
|
Class<?> auxClass = recordClass;
|
||||||
|
while(auxClass!=null){
|
||||||
|
Class<?>[] classes = auxClass.getClasses();
|
||||||
|
for(Class<?> clz : classes){
|
||||||
|
if(clz.isEnum()){
|
||||||
|
if(!enumClasses.contains((Class<? extends Enum>) clz)){
|
||||||
|
logger.trace("Found Enum {}", clz);
|
||||||
|
enumClasses.add((Class<? extends Enum>) clz);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
auxClass = auxClass.getSuperclass();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
logger.trace("Found Enums : {}",enumClasses);
|
||||||
|
|
||||||
|
for(Class<? extends Enum> enumClass : enumClasses){
|
||||||
|
EnumCodec<? extends Enum> enumCodec = new EnumCodec<>(enumClass);
|
||||||
|
codecs.add(enumCodec);
|
||||||
|
}
|
||||||
|
|
||||||
|
GenericCodec<URI> uriCodec = new GenericCodec<>(URI.class);
|
||||||
|
codecs.add(uriCodec);
|
||||||
|
return (List<? extends Codec<?>>) codecs;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected void prepareConnection(PersistenceBackendConfiguration configuration) throws Exception {
|
||||||
|
logger.debug("Preparing Connection for {}", this.getClass().getSimpleName());
|
||||||
|
this.configuration = configuration;
|
||||||
|
|
||||||
|
String url = configuration.getProperty(URL_PROPERTY_KEY);
|
||||||
|
String username = configuration.getProperty(USERNAME_PROPERTY_KEY);
|
||||||
|
String password = configuration.getProperty(PASSWORD_PROPERTY_KEY);
|
||||||
|
String dbName = configuration.getProperty(DB_NAME);
|
||||||
|
|
||||||
|
MongoCredential credential = MongoCredential.createScramSha1Credential(
|
||||||
|
username, dbName, password.toCharArray());
|
||||||
|
|
||||||
|
url = url.startsWith("http://") ? url.replace("http://", "") : url;
|
||||||
|
ServerAddress serverAddress = new ServerAddress(url);
|
||||||
|
|
||||||
|
mongoClient = new MongoClient(serverAddress,
|
||||||
|
Arrays.asList(credential), mongoClientOptions); //, MONGO_CLIENT_OPTIONS);
|
||||||
|
|
||||||
|
mongoDatabase = mongoClient.getDatabase(dbName);
|
||||||
|
|
||||||
|
collectionName = configuration.getProperty(COLLECTION_NAME);
|
||||||
|
if(mongoDatabase.getCollection(collectionName)==null){
|
||||||
|
mongoDatabase.createCollection(collectionName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void createItem(Document document) throws Exception {
|
||||||
|
mongoDatabase.getCollection(collectionName).insertOne(document);
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
protected static List<? extends Codec<?>> findMissingCodecs(CodecRegistry cr, Record record){
|
||||||
|
@SuppressWarnings("rawtypes")
|
||||||
|
List<Codec> codecs = new ArrayList<>();
|
||||||
|
Collection<Comparable<? extends Serializable>> properties = record.getResourceProperties().values();
|
||||||
|
for(@SuppressWarnings("rawtypes") Comparable value : properties){
|
||||||
|
try {
|
||||||
|
try {
|
||||||
|
cr.get(value.getClass());
|
||||||
|
logger.trace("Codec found for {} : {}", value.getClass(), value);
|
||||||
|
}catch(CodecConfigurationException cce){
|
||||||
|
logger.trace("No Codec found for {} : {}", value.getClass(), value);
|
||||||
|
if(value.getClass().isEnum()){
|
||||||
|
@SuppressWarnings({ "rawtypes" })
|
||||||
|
EnumCodec<? extends Enum> enumCodec =
|
||||||
|
new EnumCodec<>((Class<? extends Enum>) value.getClass());
|
||||||
|
codecs.add(enumCodec);
|
||||||
|
logger.trace("Adding {} to manage {} : {}", enumCodec, value.getClass(), value);
|
||||||
|
}else{
|
||||||
|
@SuppressWarnings({ "rawtypes" })
|
||||||
|
GenericCodec genericCodec = new GenericCodec<>(value.getClass());
|
||||||
|
try {
|
||||||
|
Comparable<? extends Serializable> recreatedValue = genericCodec.getFromString(value.toString());
|
||||||
|
if(value.compareTo(recreatedValue)==0){
|
||||||
|
codecs.add(genericCodec);
|
||||||
|
logger.trace("Adding {} to manage {} : {}", genericCodec, value.getClass(), value);
|
||||||
|
}else{
|
||||||
|
String message = String.format("%s != %s", value, recreatedValue);
|
||||||
|
throw new Exception(message);
|
||||||
|
}
|
||||||
|
}catch(Exception e){
|
||||||
|
logger.error("{} cannot be used for {} : {}", GenericCodec.class.getSimpleName(), value.getClass(), value, e);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}catch(Exception ex){
|
||||||
|
logger.error("Error evaluating if {} can be serialized as bson Object", value, ex);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return (List<? extends Codec<?>>) codecs;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
protected void checkSerializability(Record record) throws Exception{
|
||||||
|
CodecRegistry cr = mongoClientOptions.getCodecRegistry();
|
||||||
|
List<? extends Codec<?>> codecs = findMissingCodecs(cr, record);
|
||||||
|
|
||||||
|
if(!codecs.isEmpty()){
|
||||||
|
logger.debug("Recreating Mongo CLient to Add Codecs");
|
||||||
|
CodecRegistry newCR = addCoded(cr, (List<? extends Codec<?>>) codecs);
|
||||||
|
mongoClientOptions = createMongoClientOptions(newCR);
|
||||||
|
mongoClient.close();
|
||||||
|
prepareConnection(configuration);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected void reallyAccount(Record record) throws Exception {
|
||||||
|
checkSerializability(record);
|
||||||
|
Document document = usageRecordToDocument(record);
|
||||||
|
createItem(document);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Document usageRecordToDocument(Record record) throws Exception {
|
||||||
|
Document document = new Document();
|
||||||
|
document.putAll(record.getResourceProperties());
|
||||||
|
return document;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static Record documentToUsageRecord(Document document) throws Exception {
|
||||||
|
Map<String, Comparable<? extends Serializable>> map = new
|
||||||
|
HashMap<String, Comparable<? extends Serializable>>();
|
||||||
|
Set<Entry<String, Object>> set = document.entrySet();
|
||||||
|
for(Entry<String, Object> entry : set){
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
Comparable<? extends Serializable> value =
|
||||||
|
(Comparable<? extends Serializable>) entry.getValue();
|
||||||
|
map.put(entry.getKey(), value);
|
||||||
|
}
|
||||||
|
Record record = RecordUtility.getRecord(map);
|
||||||
|
return record;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1 @@
|
||||||
|
org.gcube.documentstore.persistence.PersistenceMongoDB
|
|
@ -0,0 +1,121 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
package org.gcube.accounting.persistence;
|
||||||
|
|
||||||
|
import java.io.StringWriter;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Calendar;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.gcube.common.resources.gcore.Resource;
|
||||||
|
import org.gcube.common.resources.gcore.Resources;
|
||||||
|
import org.gcube.common.resources.gcore.ServiceEndpoint;
|
||||||
|
import org.gcube.common.scope.api.ScopeProvider;
|
||||||
|
import org.gcube.documentstore.persistence.PersistenceMongoDB;
|
||||||
|
import org.gcube.documentstore.persistence.PersistenceBackend;
|
||||||
|
import org.gcube.documentstore.persistence.PersistenceBackendFactory;
|
||||||
|
import org.gcube.informationsystem.publisher.RegistryPublisherFactory;
|
||||||
|
import org.gcube.informationsystem.publisher.ScopedPublisher;
|
||||||
|
import org.gcube.informationsystem.publisher.exception.RegistryNotFoundException;
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Luca Frosini (ISTI - CNR) http://www.lucafrosini.com/
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class PersistenceMongoDBTest {
|
||||||
|
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger(PersistenceMongoDBTest.class);
|
||||||
|
|
||||||
|
public static PersistenceBackend getPersistence(){
|
||||||
|
ScopeProvider.instance.set("/gcube/devNext");
|
||||||
|
PersistenceBackendFactory.setFallbackLocation(null);
|
||||||
|
return PersistenceBackendFactory.getPersistenceBackend(ScopeProvider.instance.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void persistenceIsMongoDB() {
|
||||||
|
PersistenceBackend accountingPersistence = getPersistence();
|
||||||
|
Assert.assertTrue(accountingPersistence instanceof PersistenceMongoDB);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void publishScopedResource(Resource resource, List<String> scopes) throws Exception {
|
||||||
|
StringWriter stringWriter = new StringWriter();
|
||||||
|
Resources.marshal(resource, stringWriter);
|
||||||
|
|
||||||
|
ScopedPublisher scopedPublisher = RegistryPublisherFactory.scopedPublisher();
|
||||||
|
try {
|
||||||
|
logger.debug("Trying to publish to {}:\n{}", scopes, stringWriter);
|
||||||
|
scopedPublisher.create(resource, scopes);
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.error("The resource was not published", e);
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void unPublishScopedResource(Resource resource, List<String> scopes) throws RegistryNotFoundException, Exception {
|
||||||
|
ScopedPublisher scopedPublisher = RegistryPublisherFactory.scopedPublisher();
|
||||||
|
String id = resource.id();
|
||||||
|
logger.debug("Trying to remove {} with ID {} from {}", resource.getClass().getSimpleName(), id, scopes);
|
||||||
|
scopedPublisher.remove(resource, scopes);
|
||||||
|
logger.debug("{} with ID {} removed successfully", resource.getClass().getSimpleName(), id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testScopeRecheck() throws Exception {
|
||||||
|
final String vreScopeToUse = "/gcube/devsec/LucioVRE";
|
||||||
|
final String parentVREScopeToUse = "/gcube/devsec";
|
||||||
|
|
||||||
|
ScopeProvider.instance.set(vreScopeToUse);
|
||||||
|
|
||||||
|
ServiceEndpoint serviceEndpoint = null;
|
||||||
|
try {
|
||||||
|
AccountingPersistenceConfiguration persitenceConfiguration = new AccountingPersistenceConfiguration(PersistenceMongoDB.class);
|
||||||
|
serviceEndpoint = persitenceConfiguration.getServiceEndpoint(
|
||||||
|
AccountingPersistenceConfiguration.SERVICE_ENDPOINT_CATEGORY, AccountingPersistenceConfiguration.SERVICE_ENDPOINT_NAME,
|
||||||
|
PersistenceMongoDB.class);
|
||||||
|
List<String> scopes = new ArrayList<String>();
|
||||||
|
scopes.add(ScopeProvider.instance.get());
|
||||||
|
unPublishScopedResource(serviceEndpoint, scopes);
|
||||||
|
} catch(IndexOutOfBoundsException e){
|
||||||
|
ScopeProvider.instance.set(parentVREScopeToUse);
|
||||||
|
AccountingPersistenceConfiguration persitenceConfiguration = new AccountingPersistenceConfiguration(PersistenceMongoDB.class);
|
||||||
|
serviceEndpoint = persitenceConfiguration.getServiceEndpoint(
|
||||||
|
AccountingPersistenceConfiguration.SERVICE_ENDPOINT_CATEGORY,
|
||||||
|
AccountingPersistenceConfiguration.SERVICE_ENDPOINT_NAME,
|
||||||
|
PersistenceMongoDB.class);
|
||||||
|
ScopeProvider.instance.set(vreScopeToUse);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
long startTime = Calendar.getInstance().getTimeInMillis();
|
||||||
|
long endTime = startTime;
|
||||||
|
while(endTime <= (startTime + 10*1000)){ // 10 sec
|
||||||
|
endTime = Calendar.getInstance().getTimeInMillis();
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.debug("Going to check First Time");
|
||||||
|
PersistenceBackend first = PersistenceBackendFactory.getPersistenceBackend(ScopeProvider.instance.get());
|
||||||
|
logger.debug("First {} : {}", PersistenceBackend.class.getSimpleName(), first);
|
||||||
|
|
||||||
|
List<String> scopes = new ArrayList<String>();
|
||||||
|
scopes.add(ScopeProvider.instance.get());
|
||||||
|
publishScopedResource(serviceEndpoint, scopes);
|
||||||
|
|
||||||
|
startTime = Calendar.getInstance().getTimeInMillis();
|
||||||
|
endTime = startTime;
|
||||||
|
while(endTime <= (startTime + (PersistenceBackendFactory.FALLBACK_RETRY_TIME + 100))){
|
||||||
|
endTime = Calendar.getInstance().getTimeInMillis();
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.debug("Going to check Second Time");
|
||||||
|
PersistenceBackend second = PersistenceBackendFactory.getPersistenceBackend(ScopeProvider.instance.get());
|
||||||
|
logger.debug("Second {} : {}", PersistenceBackend.class.getSimpleName(), second);
|
||||||
|
|
||||||
|
Assert.assertNotEquals(first, second);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,77 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
package org.gcube.documentstore.persistence;
|
||||||
|
|
||||||
|
import java.net.URL;
|
||||||
|
|
||||||
|
import org.bson.Document;
|
||||||
|
import org.gcube.accounting.datamodel.UsageRecord;
|
||||||
|
import org.gcube.accounting.datamodel.basetypes.AbstractStorageUsageRecord.OperationType;
|
||||||
|
import org.gcube.accounting.datamodel.basetypes.TestUsageRecord;
|
||||||
|
import org.gcube.common.scope.api.ScopeProvider;
|
||||||
|
import org.gcube.documentstore.records.Record;
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Luca Frosini (ISTI - CNR) http://www.lucafrosini.com/
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class PersistenceMongoDBTest {
|
||||||
|
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger(PersistenceMongoDBTest.class);
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testJsonNodeUsageRecordConversions() throws Exception {
|
||||||
|
Record record = TestUsageRecord.createTestServiceUsageRecordAutomaticScope();
|
||||||
|
logger.debug("UsageRecord : {}", record.toString());
|
||||||
|
Document document = PersistenceMongoDB.usageRecordToDocument(record);
|
||||||
|
logger.debug("Document : {}", document.toString());
|
||||||
|
Record r = PersistenceMongoDB.documentToUsageRecord(document);
|
||||||
|
Assert.assertEquals(0, record.compareTo(r));
|
||||||
|
Assert.assertEquals(0, r.compareTo(record));
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum AUX {
|
||||||
|
TEST, TESTER, TESTING
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testConfiguration() throws Exception{
|
||||||
|
ScopeProvider.instance.set("/gcube/devNext");
|
||||||
|
URL url = new URL("http://mongo-test.d4science.org");
|
||||||
|
|
||||||
|
PersistenceBackendConfiguration persitenceConfiguration = PersistenceBackendConfiguration.getUnconfiguredInstance();
|
||||||
|
persitenceConfiguration.addProperty(PersistenceMongoDB.URL_PROPERTY_KEY, url.toString());
|
||||||
|
persitenceConfiguration.addProperty(PersistenceMongoDB.USERNAME_PROPERTY_KEY, "accounting");
|
||||||
|
persitenceConfiguration.addProperty(PersistenceMongoDB.PASSWORD_PROPERTY_KEY, "testpwd");
|
||||||
|
persitenceConfiguration.addProperty(PersistenceMongoDB.DB_NAME,"accounting");
|
||||||
|
persitenceConfiguration.addProperty(PersistenceMongoDB.COLLECTION_NAME, UsageRecord.class.getSimpleName());
|
||||||
|
PersistenceMongoDB mongo = new PersistenceMongoDB();
|
||||||
|
mongo.prepareConnection(persitenceConfiguration);
|
||||||
|
|
||||||
|
|
||||||
|
Record record = TestUsageRecord.createTestServiceUsageRecordAutomaticScope();
|
||||||
|
record.setResourceProperty("Test", AUX.TESTER);
|
||||||
|
mongo.reallyAccount(record);
|
||||||
|
|
||||||
|
record = TestUsageRecord.createTestStorageUsageRecordAutomaticScope();
|
||||||
|
record.setResourceProperty("Test", AUX.TESTER);
|
||||||
|
mongo.reallyAccount(record);
|
||||||
|
|
||||||
|
record = TestUsageRecord.createTestJobUsageRecordAutomaticScope();
|
||||||
|
mongo.reallyAccount(record);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test(){
|
||||||
|
EnumCodec<OperationType> enumCodec = new EnumCodec<OperationType>(OperationType.class);
|
||||||
|
Assert.assertEquals(OperationType.class, enumCodec.getEncoderClass());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,16 @@
|
||||||
|
<configuration>
|
||||||
|
|
||||||
|
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
|
||||||
|
<encoder>
|
||||||
|
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{0}: %msg%n</pattern>
|
||||||
|
</encoder>
|
||||||
|
</appender>
|
||||||
|
|
||||||
|
|
||||||
|
<logger name="org.gcube" level="TRACE" />
|
||||||
|
|
||||||
|
<root level="INFO">
|
||||||
|
<appender-ref ref="STDOUT" />
|
||||||
|
</root>
|
||||||
|
|
||||||
|
</configuration>
|
Reference in New Issue