diff --git a/bundles/io.github.linkedfactory.service/plugin.xml b/bundles/io.github.linkedfactory.service/plugin.xml new file mode 100644 index 00000000..65a626bb --- /dev/null +++ b/bundles/io.github.linkedfactory.service/plugin.xml @@ -0,0 +1,9 @@ + + + + + + + + \ No newline at end of file diff --git a/bundles/io.github.linkedfactory.service/src/main/java/io/github/linkedfactory/service/config/ConfigModule.java b/bundles/io.github.linkedfactory.service/src/main/java/io/github/linkedfactory/service/config/ConfigModule.java new file mode 100644 index 00000000..a22c03dc --- /dev/null +++ b/bundles/io.github.linkedfactory.service/src/main/java/io/github/linkedfactory/service/config/ConfigModule.java @@ -0,0 +1,11 @@ +package io.github.linkedfactory.service.config; + +import net.enilink.komma.core.KommaModule; + +public class ConfigModule extends KommaModule { + { + // specify dummy type to make KOMMA happy + addConcept(IKvinFactory.class, "plugin://io.github.linkedfactory.service/data/Kvin"); + addBehaviour(KvinLevelDbFactory.class); + } +} diff --git a/bundles/io.github.linkedfactory.service/src/main/java/io/github/linkedfactory/service/config/IKvinFactory.java b/bundles/io.github.linkedfactory.service/src/main/java/io/github/linkedfactory/service/config/IKvinFactory.java new file mode 100644 index 00000000..92323aa0 --- /dev/null +++ b/bundles/io.github.linkedfactory.service/src/main/java/io/github/linkedfactory/service/config/IKvinFactory.java @@ -0,0 +1,14 @@ +package io.github.linkedfactory.service.config; + +import io.github.linkedfactory.core.kvin.Kvin; + +/** + * Factory for creating {@link Kvin} instances. + */ +public interface IKvinFactory { + /** + * Creates a {@link Kvin} instance + * @return an instance of a {@link Kvin} store + */ + Kvin create(); +} diff --git a/bundles/io.github.linkedfactory.service/src/main/java/io/github/linkedfactory/service/config/KvinLevelDbFactory.java b/bundles/io.github.linkedfactory.service/src/main/java/io/github/linkedfactory/service/config/KvinLevelDbFactory.java new file mode 100644 index 00000000..44e62977 --- /dev/null +++ b/bundles/io.github.linkedfactory.service/src/main/java/io/github/linkedfactory/service/config/KvinLevelDbFactory.java @@ -0,0 +1,41 @@ +package io.github.linkedfactory.service.config; + +import io.github.linkedfactory.core.kvin.Kvin; +import io.github.linkedfactory.core.kvin.leveldb.KvinLevelDb; +import net.enilink.composition.annotations.Iri; +import org.eclipse.core.runtime.Platform; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.File; +import java.net.URISyntaxException; + +@Iri("plugin://io.github.linkedfactory.service/data/KvinLevelDb") +public abstract class KvinLevelDbFactory implements IKvinFactory { + private static final Logger log = LoggerFactory.getLogger(KvinLevelDbFactory.class); + + public static String TYPE = "plugin://io.github.linkedfactory.service/data/KvinLevelDb"; + + @Override + public Kvin create() { + String dirName = getDirName(); + if (dirName == null) { + dirName = "linkedfactory-valuestore"; + } + File valueStorePath; + if (new File(dirName).isAbsolute()) { + valueStorePath = new File(dirName); + } else { + try { + valueStorePath = new File(new File(Platform.getInstanceLocation().getURL().toURI()), dirName); + } catch (URISyntaxException e) { + throw new RuntimeException(e); + } + } + log.info("Using store path: {}", valueStorePath); + return new KvinLevelDb(valueStorePath); + } + + @Iri("plugin://io.github.linkedfactory.service/data/dirName") + public abstract String getDirName(); +} diff --git a/bundles/io.github.linkedfactory.service/src/main/resources/OSGI-INF/io.github.linkedfactory.service-default.ttl b/bundles/io.github.linkedfactory.service/src/main/resources/OSGI-INF/io.github.linkedfactory.service-default.ttl index c684f9fa..37408ae7 100644 --- a/bundles/io.github.linkedfactory.service/src/main/resources/OSGI-INF/io.github.linkedfactory.service-default.ttl +++ b/bundles/io.github.linkedfactory.service/src/main/resources/OSGI-INF/io.github.linkedfactory.service-default.ttl @@ -5,5 +5,5 @@ # <> [ 10 ] ; true . @base . - ; - "linkedfactory-valuestore" . +<> . +<> [ a ; "linkedfactory-valuestore" ] . diff --git a/bundles/io.github.linkedfactory.service/src/main/scala/io/github/linkedfactory/service/Data.scala b/bundles/io.github.linkedfactory.service/src/main/scala/io/github/linkedfactory/service/Data.scala index 00ce61b5..14f8c6a9 100644 --- a/bundles/io.github.linkedfactory.service/src/main/scala/io/github/linkedfactory/service/Data.scala +++ b/bundles/io.github.linkedfactory.service/src/main/scala/io/github/linkedfactory/service/Data.scala @@ -17,6 +17,7 @@ package io.github.linkedfactory.service import com.google.common.cache.CacheBuilder import io.github.linkedfactory.core.kvin.{Kvin, KvinListener} +import io.github.linkedfactory.service.config.{IKvinFactory, KvinLevelDbFactory} import io.github.linkedfactory.service.model.ssn._ import io.github.linkedfactory.service.util.ResourceHelpers.withTransaction import net.enilink.komma.core._ @@ -30,6 +31,7 @@ import net.liftweb.common.Box import net.liftweb.http.{RequestVar, S} import org.eclipse.core.runtime.Platform import org.osgi.framework.FrameworkUtil +import org.slf4j.LoggerFactory import java.security.PrivilegedExceptionAction import java.text.SimpleDateFormat @@ -39,10 +41,12 @@ import scala.jdk.CollectionConverters._ import scala.reflect.{ClassTag, classTag} object Data { + val log = LoggerFactory.getLogger(getClass) + val NAMESPACE = "http://linkedfactory.github.io/vocab#" val PROPERTY_CONTAINS = URIs.createURI(NAMESPACE + "contains") - val cfgURI = URIs.createURI("plugin://de.fraunhofer.iwu.linkedfactory.service/data/") + val cfgUri = URIs.createURI("plugin://io.github.linkedfactory.service/data/") val dateFormat = new SimpleDateFormat("dd/MM/yyyy hh:mm:ss") val bundleContext = Option(FrameworkUtil.getBundle(getClass)).map(_.getBundleContext).getOrElse(null) @@ -54,14 +58,16 @@ object Data { private var _modelURI: URI = _ if (bundleContext != null) { - // get configuration settings from plugin config model + // configure default model Globals.withPluginConfig { pcModel => { - val cfg = pcModel.getManager.find(cfgURI.appendLocalPart("store")).asInstanceOf[IResource] - _modelURI = cfg.getSingle(cfgURI.appendLocalPart("model")) match { + val defaultModel = pcModel.getManager.find(cfgUri, classOf[IResource]) + .getSingle(cfgUri.appendLocalPart("defaultModel")); + _modelURI = defaultModel match { case r: IReference if r.getURI != null => r.getURI case s: String => URIs.createURI(s) case _ => URIs.createURI("http://linkedfactory.github.io/data/") } + log.info("Using default data model: {}", _modelURI) } } } @@ -75,10 +81,11 @@ object Data { .build[URI, Any]() val modelURI = _modelURI + // caches currentModel for each request object modelForRequest extends RequestVar[Box[IModel]](currentModel) - def getKvin() : Option[Kvin] = { + def getKvin(): Option[Kvin] = { Option(bundleContext).flatMap(ctx => Option(ctx.getServiceReference(classOf[Kvin])).map(ref => ctx.getService(ref))) } diff --git a/bundles/io.github.linkedfactory.service/src/main/scala/io/github/linkedfactory/service/KvinManager.java b/bundles/io.github.linkedfactory.service/src/main/scala/io/github/linkedfactory/service/KvinManager.java index 2918ec25..f4c22561 100644 --- a/bundles/io.github.linkedfactory.service/src/main/scala/io/github/linkedfactory/service/KvinManager.java +++ b/bundles/io.github.linkedfactory.service/src/main/scala/io/github/linkedfactory/service/KvinManager.java @@ -1,28 +1,30 @@ package io.github.linkedfactory.service; import io.github.linkedfactory.core.kvin.Kvin; -import io.github.linkedfactory.core.kvin.leveldb.KvinLevelDb; +import io.github.linkedfactory.service.config.IKvinFactory; +import io.github.linkedfactory.service.config.KvinLevelDbFactory; import net.enilink.komma.core.URI; import net.enilink.komma.core.URIs; +import net.enilink.komma.em.concepts.IClass; import net.enilink.komma.em.concepts.IResource; import net.enilink.platform.core.PluginConfigModel; - -import java.io.File; -import java.net.URISyntaxException; -import java.util.Hashtable; - -import org.eclipse.core.runtime.Platform; import org.osgi.framework.ServiceRegistration; import org.osgi.service.component.ComponentContext; import org.osgi.service.component.annotations.Activate; import org.osgi.service.component.annotations.Component; import org.osgi.service.component.annotations.Deactivate; import org.osgi.service.component.annotations.Reference; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Hashtable; @Component public class KvinManager { - static final URI cfgUri = URIs.createURI("plugin://de.fraunhofer.iwu.linkedfactory.service/data/"); + static final Logger log = LoggerFactory.getLogger(KvinManager.class); + + static final URI cfgUri = URIs.createURI("plugin://io.github.linkedfactory.service/data/"); PluginConfigModel configModel; ServiceRegistration kvinServiceRegistration; Kvin kvin; @@ -36,30 +38,36 @@ void setConfigModel(PluginConfigModel configModel) { void activate(ComponentContext ctx) { try { configModel.begin(); - IResource cfg = configModel.getManager().find(cfgUri.appendLocalPart("store"), IResource.class); - Object type = cfg.getSingle(cfgUri.appendLocalPart("type")); - if (type == null || "KvinLevelDb".equals(type)) { - String dirName = (String) cfg.getSingle(cfgUri.appendLocalPart("dirName")); - if (dirName == null) { - dirName = "linkedfactory-valuestore"; - } - File valueStorePath; - if (new File(dirName).isAbsolute()) { - valueStorePath = new File(dirName); + Object cfg = configModel.getManager().find(cfgUri, IResource.class) + .getSingle(cfgUri.appendLocalPart("store")); + + if (! (cfg instanceof IResource)) { + log.error("Kvin store is not properly configured in: {}", cfgUri); + return; + } + + IResource cfgResource = (IResource) cfg; + IKvinFactory factory; + if (!(cfg instanceof IKvinFactory)) { + if (cfgResource.getRdfTypes().isEmpty()) { + // fallback to KvinLevelDb + log.info("Using default KvinLevelDb as type is not specified in config: {}", cfgUri); + cfgResource.getRdfTypes().add(configModel.getManager() + .find(URIs.createURI(KvinLevelDbFactory.TYPE), IClass.class)); + factory = cfgResource.as(IKvinFactory.class); } else { - try { - valueStorePath = new File(new File(Platform.getInstanceLocation().getURL().toURI()), dirName); - } catch (URISyntaxException e) { - throw new RuntimeException(e); - } - } - try { - kvin = new KvinLevelDb(valueStorePath); - kvinServiceRegistration = ctx.getBundleContext().registerService(Kvin.class, kvin, new Hashtable<>()); - System.out.println("Value store: using LF w/ path=" + valueStorePath); - } catch (Throwable throwable) { - System.err.println("Value store: FAILURE for LF w/ path=" + valueStorePath + ": " + throwable.getMessage()); + log.error("Invalid Kvin configurations with types: {}", cfgResource.getRdfTypes()); + return; } + } else { + factory = (IKvinFactory) cfg; + } + + try { + kvin = factory.create(); + kvinServiceRegistration = ctx.getBundleContext().registerService(Kvin.class, kvin, new Hashtable<>()); + } catch (Throwable throwable) { + log.error("Failure while creating Kvin store", throwable); } } finally { configModel.end();