You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@marmotta.apache.org by wi...@apache.org on 2013/02/19 13:52:01 UTC

[9/52] [partial] code contribution, initial import of relevant modules of LMF-3.0.0-SNAPSHOT based on revision 4bf944319368 of the default branch at https://code.google.com/p/lmf/

http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/c32963d5/lmf-core/src/main/java/kiwi/core/services/triplestore/LdpServiceImpl.java
----------------------------------------------------------------------
diff --git a/lmf-core/src/main/java/kiwi/core/services/triplestore/LdpServiceImpl.java b/lmf-core/src/main/java/kiwi/core/services/triplestore/LdpServiceImpl.java
new file mode 100644
index 0000000..9bd9b30
--- /dev/null
+++ b/lmf-core/src/main/java/kiwi/core/services/triplestore/LdpServiceImpl.java
@@ -0,0 +1,357 @@
+/**
+ * Copyright (C) 2013 Salzburg Research.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package kiwi.core.services.triplestore;
+
+import static at.newmedialab.sesame.commons.repository.ExceptionUtils.handleRepositoryException;
+
+import java.net.URISyntaxException;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+
+import javax.annotation.PostConstruct;
+import javax.enterprise.context.ApplicationScoped;
+import javax.inject.Inject;
+
+import kiwi.core.api.config.ConfigurationService;
+import kiwi.core.api.prefix.PrefixService;
+import kiwi.core.api.triplestore.ContextService;
+import kiwi.core.api.triplestore.LdpService;
+import kiwi.core.api.triplestore.SesameService;
+
+import org.openrdf.model.Resource;
+import org.openrdf.model.URI;
+import org.openrdf.model.ValueFactory;
+import org.openrdf.model.vocabulary.RDF;
+import org.openrdf.model.vocabulary.RDFS;
+import org.openrdf.repository.RepositoryConnection;
+import org.openrdf.repository.RepositoryException;
+import org.slf4j.Logger;
+
+import at.newmedialab.sesame.commons.repository.ResourceUtils;
+
+/**
+ * (Experimental) Implementation for supporting LDP (WIP)
+ * 
+ * @author Sergio Fernández
+ *
+ */
+@ApplicationScoped
+public class LdpServiceImpl implements LdpService {
+    
+    private URI context;
+    
+    @Inject
+    private Logger log;
+    
+    @Inject
+    private ConfigurationService configurationService;
+    
+    @Inject
+    private SesameService sesameService;
+    
+    @Inject
+    private ContextService contextService;
+    
+    @Inject
+    private PrefixService prefixService;
+    
+    @PostConstruct
+    public void initialize() {
+        String uri = getBaseContainer();
+        try {
+            this.context = contextService.createContext(uri, "ldp (experimental context)");
+            createContainer(uri, "ldp base container");
+        } catch (URISyntaxException e) {
+            log.error("Root LDP Container {} cannot be created: {}", uri, e.getMessage());
+        }        
+    }
+    
+    @Override
+    public String getBaseContainer() {
+        return configurationService.getBaseContext() + ConfigurationService.LDP_PATH;
+    }
+    
+    @Override
+    public List<URI> list() {
+        List<URI> containers = new ArrayList<URI>();
+        try {
+            RepositoryConnection conn = sesameService.getConnection();
+            try {
+                checkConnectionNamespace(conn);
+                conn.begin();
+                Iterable<Resource> results = ResourceUtils.listResources(conn, conn.getValueFactory().createURI(prefixService.getNamespace("ldp"), "Container"));
+                for (Resource result : results) {
+                    if(result instanceof URI) {
+                        containers.add((URI)result);
+                    }  
+                }
+            } finally {
+                conn.commit();
+                conn.close();
+            }
+        } catch (RepositoryException e) {
+            handleRepositoryException(e, LdpServiceImpl.class);
+        }
+        return containers;
+    }
+    
+    @Override
+    public URI get(String uri) {
+        try {
+            RepositoryConnection conn = sesameService.getConnection();
+            try {
+                checkConnectionNamespace(conn);
+                conn.begin();
+                return (ResourceUtils.existsResource(conn, uri) ? ResourceUtils.getUriResource(conn, uri) : null);
+            } finally {
+                conn.commit();
+                conn.close();
+            }
+        } catch(RepositoryException ex) {
+            handleRepositoryException(ex, LdpServiceImpl.class);
+        }
+        return null;
+    }
+
+    @Override
+    public boolean create(String uri) throws URISyntaxException {
+        return create(uri, null);
+    }
+
+    @Override
+    public boolean create(String uri, String title) throws URISyntaxException {
+        URI parent = getParentContainer(uri);
+        if (parent != null) {
+            return createResource(uri, parent);
+        } else {
+           throw new URISyntaxException(uri, "Non suitable parent container found");
+        }
+    }
+    
+    private boolean createResource(String uri, URI container) {
+        //TODO: refactor this code, already implemented at the ResourceWebService, 
+        //by moving all business logic to a service
+        try {
+            RepositoryConnection conn = sesameService.getConnection();
+            try {
+                checkConnectionNamespace(conn);
+                conn.begin();
+                ValueFactory factory = conn.getValueFactory();
+                URI resource = ResourceUtils.getUriResource(conn, uri);
+                //TODO: chek if already exists
+                conn.add(resource, RDF.TYPE, factory.createURI(prefixService.getNamespace("ldp"), "Resource"), container);
+                conn.add(resource, factory.createURI(prefixService.getNamespace("dct"), "created"), factory.createLiteral(new Date()), container);
+                conn.add(container, RDFS.MEMBER, resource, container);
+                return true; //FIXME: 201 vs 200
+            } finally {
+                conn.commit();
+                conn.close();
+            }
+        } catch (RepositoryException ex) {
+            return false;
+        }
+    }
+
+    private boolean createContainer(String container, String title) throws URISyntaxException {
+        try {
+            RepositoryConnection conn = sesameService.getConnection();
+            try {
+                checkConnectionNamespace(conn);
+                conn.begin();
+                ValueFactory factory = conn.getValueFactory();
+                URI uri = ResourceUtils.getUriResource(conn, container);
+                conn.add(uri, RDF.TYPE, factory.createURI(prefixService.getNamespace("ldp"), "Container"), context);
+                conn.add(uri, RDFS.LABEL, factory.createLiteral(title), context);
+                conn.add(uri, factory.createURI(prefixService.getNamespace("dct"), "created"), factory.createLiteral(new Date()), context);
+                log.info("Created new container <{}>", uri.stringValue());
+                return true;
+            } finally {
+                conn.commit();
+                conn.close();
+            }
+        } catch(RepositoryException ex) {
+            handleRepositoryException(ex, LdpServiceImpl.class);
+        }
+        return false;
+    }
+    
+//    @Override
+//    public boolean addMember(String container, String member) {
+//        //TODO: check parent relationship
+//        try {
+//            RepositoryConnection conn = sesameService.getConnection();
+//            try {
+//                checkConnectionNamespace(conn);
+//                URI parent = ResourceUtils.getUriResource(conn, container);
+//                URI uri = ResourceUtils.getUriResource(conn, member);
+//                URI context = parent; //TODO: for the moment, every container is also a context (named graph) for us
+//                conn.add(parent, RDFS.MEMBER, uri, context);
+//                log.info("Created new container <{}>", uri.stringValue());
+//            } finally {
+//                conn.commit();
+//                conn.close();path
+//            }
+//            return true;
+//        } catch(RepositoryException ex) {
+//            handleRepositoryException(ex, LdpServiceImpl.class);
+//            return false;
+//        }
+//    }
+
+    @Override
+    public boolean delete(String uri) throws RepositoryException {
+        if (isContainer(uri)) {
+            return deleteContainer(uri);
+        } else {
+            return deleteResource(uri);
+        }
+    }
+
+    /**
+     * Resource deletion
+     * 
+     * @todo refactor this code, already implemented at the ResourceWebService, by moving all business logic to a service
+     * 
+     * @param uri
+     * @return
+     * @throws RepositoryException
+     */
+    private boolean deleteResource(String uri) throws RepositoryException {
+        //TODO: refactor this code, already implemented at the ResourceWebService, 
+        //by moving all business logic to a service
+        RepositoryConnection conn = sesameService.getConnection();
+        URI parent;
+        try {
+            parent = getParentContainer(uri);
+        } catch (URISyntaxException e) {
+            parent = null;
+        }
+        try {
+            conn.begin();
+            URI resource = conn.getValueFactory().createURI(uri);
+            conn.remove(resource, null, null, parent);
+            return true;
+        } finally {
+            conn.commit();
+            conn.close();
+        }
+    }
+
+    /**
+     * Container deleteion
+     * (using a composition model)
+     * 
+     * @param uri
+     * @return
+     * @throws RepositoryException 
+     */
+    private boolean deleteContainer(String uri) throws RepositoryException {
+        RepositoryConnection conn = sesameService.getConnection();
+        try {
+            conn.begin();
+            URI context = conn.getValueFactory().createURI(uri);
+            conn.remove((Resource)null, null, null, context);
+            return true;
+        } finally {
+            conn.commit();
+            conn.close();
+        }
+    }
+
+    /**
+     * Check the connection's namespace, using the base context when needed
+     * 
+     * @param conn
+     * @throws RepositoryException
+     */
+    private void checkConnectionNamespace(RepositoryConnection conn)
+            throws RepositoryException {
+        if(conn.getNamespace(DEFAULT_PREFIX) == null) {
+            conn.setNamespace(DEFAULT_PREFIX, getBaseContainer());
+        }
+    }
+    
+    /**
+     * Check whenever this URI represents a PDPC
+     * 
+     * @param uri
+     * @return
+     */
+    private boolean isContainer(String uri) {
+        try {
+            RepositoryConnection conn = sesameService.getConnection();
+            try {
+                checkConnectionNamespace(conn);
+                conn.begin();
+                Iterable<Resource> results = ResourceUtils.listResources(conn, conn.getValueFactory().createURI(prefixService.getNamespace("ldp"), "Container"),  conn.getValueFactory().createURI(uri));
+                for (Resource result : results) {
+                    if(result instanceof URI) {
+                        if (uri.equals(result.stringValue())) {
+                            return true;
+                        }
+                    }  
+                }
+                return false;
+            } finally {
+                conn.commit();
+                conn.close();
+            }
+        } catch (RepositoryException e) {
+            handleRepositoryException(e, LdpServiceImpl.class);
+            return false;
+        }
+    }
+    
+    /**
+     * Get the parent container for a resource
+     * 
+     * @param uri
+     * @return
+     * @throws URISyntaxException
+     */
+    private URI getParentContainer(String uri) throws URISyntaxException {
+        String base = this.getBaseContainer();
+        if (!uri.startsWith(base)) {
+            throw new URISyntaxException(uri, "Invalid URI: base URI does not matches with " + base);
+        }
+        if (base.equals(uri)) {
+            log.error("{} is already the base container", uri);
+            return null;
+        }
+        String parent = uri.substring(0, uri.lastIndexOf('/'));
+        try {
+            RepositoryConnection conn = sesameService.getConnection();
+            try {
+                checkConnectionNamespace(conn);
+                conn.begin();
+                if (!ResourceUtils.existsResource(conn, parent)) {
+                    log.warn("Container {} does not exist, so creating it...", parent);
+                    createContainer(parent, parent);
+                }
+                return ResourceUtils.getUriResource(conn, parent);
+            } finally {
+                conn.commit();
+                conn.close();
+            }
+        } catch (RepositoryException e) {
+            log.error("Error checking context {}: {}", parent, e.getMessage());
+            return null;
+        }
+        
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/c32963d5/lmf-core/src/main/java/kiwi/core/services/triplestore/SesameServiceImpl.java
----------------------------------------------------------------------
diff --git a/lmf-core/src/main/java/kiwi/core/services/triplestore/SesameServiceImpl.java b/lmf-core/src/main/java/kiwi/core/services/triplestore/SesameServiceImpl.java
new file mode 100644
index 0000000..7664cf7
--- /dev/null
+++ b/lmf-core/src/main/java/kiwi/core/services/triplestore/SesameServiceImpl.java
@@ -0,0 +1,313 @@
+/**
+ * Copyright (C) 2013 Salzburg Research.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package kiwi.core.services.triplestore;
+
+import kiwi.core.api.config.ConfigurationService;
+import kiwi.core.api.triplestore.NotifyingSailProvider;
+import kiwi.core.api.triplestore.SesameService;
+import kiwi.core.api.triplestore.StandardSailProvider;
+import kiwi.core.api.triplestore.TransactionalSailProvider;
+import kiwi.core.events.ConfigurationServiceInitEvent;
+import kiwi.core.events.SystemStartupEvent;
+import kiwi.core.qualifiers.event.transaction.AfterCommit;
+import kiwi.core.qualifiers.event.transaction.AfterRollback;
+import kiwi.core.qualifiers.event.transaction.BeforeCommit;
+import org.apache.marmotta.kiwi.persistence.KiWiDialect;
+import org.apache.marmotta.kiwi.persistence.h2.H2Dialect;
+import org.apache.marmotta.kiwi.persistence.mysql.MySQLDialect;
+import org.apache.marmotta.kiwi.persistence.pgsql.PostgreSQLDialect;
+import org.apache.marmotta.kiwi.sail.KiWiStore;
+import org.apache.marmotta.kiwi.transactions.api.TransactionListener;
+import org.apache.marmotta.kiwi.transactions.api.TransactionalSail;
+import org.apache.marmotta.kiwi.transactions.model.TransactionData;
+import org.apache.marmotta.kiwi.transactions.sail.KiWiTransactionalSail;
+import org.openrdf.model.ValueFactory;
+import org.openrdf.repository.RepositoryConnection;
+import org.openrdf.repository.RepositoryException;
+import org.openrdf.repository.sail.SailRepository;
+import org.openrdf.sail.NotifyingSail;
+import org.openrdf.sail.Sail;
+import org.slf4j.Logger;
+
+import javax.annotation.PreDestroy;
+import javax.enterprise.context.ApplicationScoped;
+import javax.enterprise.event.Event;
+import javax.enterprise.event.Observes;
+import javax.enterprise.inject.Instance;
+import javax.enterprise.inject.Produces;
+import javax.inject.Inject;
+
+/**
+ * Offers access to the Sesame repository underlying this LMF instance. The activation/deactivation methods
+ * of this service make sure the repository is properly initialised and shut down.
+ * <p/>
+ * Usage: to access the triple store properly through Sesame, you should follow the following
+ * pattern:
+ * <pre>
+ *     RespositoryConnection con = sesameService.getConnection();
+ *
+ *     URI subject = con.getValueFactory().createURI(...);
+ *     ...
+ *     RepositoryResult&lt;Statement> result = con.getStatemenrs(subject,predicate,object,inferred,context);
+ *     while(result.hasNext()) {
+ *         Statement triple = result.next();
+ *         ...
+ *     }
+ *
+ *     con.close();
+ * </pre>
+ *
+ * <p/>
+ * Will replace the existing TripleStore at some point.
+ * <p/>
+ * Author: Sebastian Schaffert
+ */
+@ApplicationScoped
+public class SesameServiceImpl implements SesameService {
+
+    @Inject
+    private Logger log;
+
+    @Inject
+    private ConfigurationService configurationService;
+
+    @Inject @BeforeCommit
+    private Event<TransactionData> beforeCommitEvent;
+
+    @Inject @AfterCommit
+    private Event<TransactionData> afterCommitEvent;
+
+    @Inject @AfterRollback
+    private Event<TransactionData> afterRollbackEvent;
+
+    /**
+     * notifying sail providers from other modules
+     */
+    @Inject
+    private Instance<NotifyingSailProvider> notifyingSailProviders;
+
+    /**
+     * transactional sail providers from other modules
+     */
+    @Inject
+    private Instance<TransactionalSailProvider> transactionalSailProviders;
+
+    /**
+     * normal sail providers from other modules
+     */
+    @Inject
+    private Instance<StandardSailProvider> standardSailProviders;
+
+
+    private KiWiStore  store;
+
+    private KiWiTransactionalSail tsail;
+
+    private SailRepository repository;
+
+    /**
+     * Initialise the Sesame repository. Should be called on service activation.
+     */
+    @Override
+    public synchronized void initialise() {
+        log.info("LMF Sesame Repository Service starting up ...");
+
+        if(repository != null) {
+            log.warn("RDF repository has already been initialized");
+        }
+
+        String database = configurationService.getStringConfiguration("database.type");
+        KiWiDialect dialect;
+        if("h2".equalsIgnoreCase(database)) {
+            dialect = new H2Dialect();
+        } else if("mysql".equalsIgnoreCase(database)) {
+            dialect = new MySQLDialect();
+        } else if("postgres".equalsIgnoreCase(database)) {
+            dialect = new PostgreSQLDialect();
+        } else
+            throw new IllegalStateException("database type "+database+" currently not supported!");
+        String jdbcUrl = configurationService.getStringConfiguration("database.url");
+        String dbUser  = configurationService.getStringConfiguration("database.user");
+        String dbPass  = configurationService.getStringConfiguration("database.password");
+
+        store = new KiWiStore("lmf", jdbcUrl, dbUser, dbPass, dialect, configurationService.getDefaultContext(), configurationService.getInferredContext());
+
+        tsail = new KiWiTransactionalSail(store);
+        tsail.addTransactionListener(new LMFTransactionEventProxy());
+
+
+        log.info("initialising repository plugins ...");
+
+        // wrap all stackable transactional sails
+        TransactionalSail transactionalSail = tsail;
+        for(TransactionalSailProvider provider : transactionalSailProviders) {
+            if(provider.isEnabled()) {
+                log.info("- transaction plugin: {}",provider.getName());
+                transactionalSail = provider.createSail(transactionalSail);
+            } else {
+                log.info("- transaction plugin: {} (DISABLED)", provider.getName());
+            }
+        }
+
+        // wrap all stackable notifying sails
+        NotifyingSail notifyingSail = transactionalSail;
+        for(NotifyingSailProvider provider : notifyingSailProviders) {
+            if(provider.isEnabled()) {
+                log.info("- notifying plugin: {}",provider.getName());
+                notifyingSail = provider.createSail(notifyingSail);
+            } else {
+                log.info("- notifying plugin: {} (DISABLED)", provider.getName());
+            }
+        }
+
+        // wrap all standard sails
+        Sail standardSail = notifyingSail;
+        for(StandardSailProvider provider : standardSailProviders) {
+            if(provider.isEnabled()) {
+                log.info("- standard plugin: {}",provider.getName());
+                standardSail = provider.createSail(standardSail);
+            } else {
+                log.info("- standard plugin: {} (DISABLED)", provider.getName());
+            }
+        }
+
+        repository = new SailRepository(standardSail);
+
+        try {
+            repository.initialize();
+        } catch (RepositoryException e) {
+            log.error("error while initialising LMF Sesame repository",e);
+        }
+    }
+
+    /**
+     * Shutdown the Sesame repository. Should be called on service deactivation.
+     */
+    @Override
+    @PreDestroy
+    public synchronized void shutdown() {
+        if(repository != null) {
+            log.info("LMF Sesame Repository Service shutting down ...");
+            try {
+                repository.shutDown();
+            } catch (RepositoryException e) {
+                log.error("error while shutting down LMF Sesame repository",e);
+            }
+            repository = null;
+        }
+    }
+
+    /**
+     * Reinit Sesame repository when the configuration has been initialised
+     *
+     * @param e
+     */
+    /*
+    public void onConfigurationChange(@Observes ConfigurationChangedEvent e) {
+        if(e.containsChangedKeyWithPrefix("database")) {
+            shutdown();
+            initialise();
+        }
+    }
+    */
+
+    /**
+     * Return the Sesame Repository underlying this service. Callers should be careful with modifying
+     * this object directly.
+     *
+     * @return the Sesame Repository instance used by this service
+     */
+    @Override
+    @Produces
+    public SailRepository getRepository() {
+        return repository;
+    }
+
+    /**
+     * Return a Sesame RepositoryConnection to the underlying repository. The connection has auto-commit disabled,
+     * all transaction management must be performed explicitly.
+     *
+     * @return a RepositoryConnection to the underlying Sesame repository.
+     */
+    @Override
+    @Produces
+    public RepositoryConnection getConnection() throws RepositoryException {
+        RepositoryConnection connection = repository.getConnection();
+        // connection.setAutoCommit(false);
+        return connection;
+    }
+
+    /**
+     * Return a Sesame ValueFactory for creating new RDF objects.
+     *
+     * @return the Sesame ValueFactory belonging to the repository that is used by the service
+     */
+    @Override
+    @Produces
+    public ValueFactory getValueFactory() {
+        return repository.getValueFactory();
+    }
+
+    private class LMFTransactionEventProxy implements TransactionListener {
+
+        /**
+         * Called before a transaction commits. The transaction data will contain all changes done in the transaction since
+         * the last commit. This method should be used in case the transaction listener aims to perform additional activities
+         * in the same transaction, like inserting or updating database tables.
+         * <p/>
+         * The implementation in lmf-core simply wraps the KiWi transaction data in a CDI transaction to notify other
+         * services in the system.
+         *
+         * @param data
+         */
+        @Override
+        public void beforeCommit(TransactionData data) {
+            log.debug("transaction: before commit event");
+            beforeCommitEvent.fire(data);
+        }
+
+        /**
+         * Called after a transaction has committed. The transaction data will contain all changes done in the transaction since
+         * the last commit. This method should be used in case the transaction listener aims to perform additional activities
+         * in a new transaction or outside the transaction management, e.g. notifying a server on the network, adding
+         * data to a cache, or similar.
+         * <p/>
+         * The implementation in lmf-core simply wraps the KiWi transaction data in a CDI transaction to notify other
+         * services in the system.
+         *
+         * @param data
+         */
+        @Override
+        public void afterCommit(TransactionData data) {
+            log.debug("transaction: after commit event");
+            afterCommitEvent.fire(data);
+        }
+
+        /**
+         * Called when a transaction rolls back.
+         * <p/>
+         * The implementation in lmf-core simply wraps the KiWi transaction data in a CDI transaction to notify other
+         * services in the system.
+         */
+        @Override
+        public void rollback(TransactionData data) {
+            log.debug("transaction: rollback event");
+            afterRollbackEvent.fire(data);
+        }
+
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/c32963d5/lmf-core/src/main/java/kiwi/core/services/user/UserServiceImpl.java
----------------------------------------------------------------------
diff --git a/lmf-core/src/main/java/kiwi/core/services/user/UserServiceImpl.java b/lmf-core/src/main/java/kiwi/core/services/user/UserServiceImpl.java
new file mode 100644
index 0000000..6c8a30f
--- /dev/null
+++ b/lmf-core/src/main/java/kiwi/core/services/user/UserServiceImpl.java
@@ -0,0 +1,372 @@
+/**
+ * Copyright (C) 2013 Salzburg Research.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package kiwi.core.services.user;
+
+import static at.newmedialab.sesame.commons.model.Namespaces.ADMIN_LOGIN;
+import static at.newmedialab.sesame.commons.model.Namespaces.ANONYMOUS_LOGIN;
+import static at.newmedialab.sesame.commons.repository.ExceptionUtils.handleRepositoryException;
+
+import at.newmedialab.sesame.commons.repository.ResourceUtils;
+import at.newmedialab.sesame.facading.FacadingFactory;
+import kiwi.core.api.config.ConfigurationService;
+import kiwi.core.api.triplestore.SesameService;
+import kiwi.core.api.user.UserService;
+import kiwi.core.events.SystemRestartedEvent;
+import kiwi.core.events.SystemRestartingEvent;
+import kiwi.core.exception.UserExistsException;
+import kiwi.core.model.user.KiWiUser;
+import kiwi.core.qualifiers.user.AdminUser;
+import kiwi.core.qualifiers.user.AnonymousUser;
+import kiwi.core.qualifiers.user.CurrentUser;
+import org.openrdf.model.URI;
+import org.openrdf.repository.RepositoryConnection;
+import org.openrdf.repository.RepositoryException;
+import org.slf4j.Logger;
+
+import javax.annotation.PostConstruct;
+import javax.enterprise.context.ApplicationScoped;
+import javax.enterprise.event.Observes;
+import javax.enterprise.inject.Produces;
+import javax.inject.Inject;
+import javax.inject.Named;
+
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
+
+/**
+ * Add file description here!
+ * <p/>
+ * User: sschaffe
+ */
+@Named("kiwi.core.userService")
+@ApplicationScoped
+public class UserServiceImpl implements UserService {
+
+    @Inject
+    private Logger log;
+
+    @Inject
+    private SesameService sesameService;
+
+    @Inject
+    private ConfigurationService configurationService;
+
+    /**
+     * Each thread gets its own User. By using {@link InheritableThreadLocal}, the user is inherited
+     * by from the parent thread unless it is explicitly set.
+     */
+    private static InheritableThreadLocal<URI> currentUser = new InheritableThreadLocal<URI>();
+
+    // marker to ensure that no other thread interferes while setting up default users ...
+    private boolean initialised = false;
+    private boolean users_created = false;
+
+    private final Lock lock = new ReentrantLock();
+
+
+    private URI adminUser;
+    private URI anonUser;
+
+
+    /**
+     * initialize() initializes the anonymous and admin user
+     * if the database has not yet been set up.
+     */
+    @PostConstruct
+    public void initialize() {
+        log.info("initialising user service ...");
+    }
+
+
+    /**
+     * Create the admin and anonymous user in the database. Must be called before any other method can be used.
+     */
+    @Override
+    public  void createDefaultUsers() {
+        lock.lock();
+        try  {
+            initialised = true; // set marker so that functions can work; we still hold the lock!
+
+            if (!userExists(ANONYMOUS_LOGIN)) {
+                log.debug("Initializing anonymous user.");
+                try {
+                    anonUser = createUser(ANONYMOUS_LOGIN);
+                } catch(UserExistsException e) {
+                    log.debug("Anonymous user already exists.");
+                }
+            } else {
+                anonUser = getUserByLogin(ANONYMOUS_LOGIN);
+            }
+
+            if (!userExists(ADMIN_LOGIN)) {
+                log.debug("Initializing admin.");
+                try {
+                    adminUser = createUser(ADMIN_LOGIN);
+                } catch(UserExistsException e) {
+                    log.debug("Admin already exists.");
+                }
+            } else {
+                adminUser = getUserByLogin(ADMIN_LOGIN);
+            }
+
+            users_created = true;
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    /**
+     * When system is restarted, flush all cache data
+     * @param e
+     */
+    public void systemRestart(@Observes SystemRestartingEvent e) {
+        log.warn("system restarted, clearing user caches");
+
+        clearCurrentUser();
+        adminUser = null;
+        anonUser  = null;
+        initialised = false;
+        users_created = false;
+    }
+
+    /**
+     * When database is re-initialised, create default users
+     * @param e
+     */
+    public void systemRestarted(@Observes SystemRestartedEvent e) {
+        log.warn("system finished restarting, recreating default users");
+        createDefaultUsers();
+    }
+
+    /**
+     * Return the currently active user. The method tries to determine the current user using the following means:
+     * - the user stored in the session, if existent
+     * - the user authenticated using HTTP authentication, if existent
+     * - the anonymous user
+     *
+     * @return
+     */
+    @Override
+    @Produces @CurrentUser
+    public URI getCurrentUser() {
+        if(currentUser.get() == null)
+            return getAnonymousUser();
+        else
+            return currentUser.get();
+    }
+
+
+
+    /**
+     * Set the current user to the user  passed as argument. The current user should be associated with
+     * the current session in a thread local variable that is cleared again when the request finishes
+     * (KiWiUserTokenFilter)
+     *
+     * @param user - the resource that represents the user
+     */
+    @Override
+    public void setCurrentUser(URI user) {
+        currentUser.set(user);
+    }
+
+    /**
+     * Clear a current user setting for the current thread. Clears the thread local variable set for the
+     * currently running thread.
+     */
+    @Override
+    public void clearCurrentUser() {
+        currentUser.remove();
+    }
+
+
+
+    /**
+     * Return the anonymous user. If it does not exist yet, it is created in the database and stored.
+     *
+     * @return
+     */
+    @Override
+    @Produces @AnonymousUser
+    public URI getAnonymousUser() {
+        while(anonUser == null && !users_created) {
+            try {
+                Thread.sleep(1000);
+            } catch (InterruptedException e) {}
+            log.warn("anonymous user not yet created; waiting for creation to finish");
+        }
+
+        return anonUser;
+    }
+
+    @Override
+    public boolean isAnonymous(URI user) {
+        return getAnonymousUser().equals(user);
+    }
+
+    @Override
+    @Produces @AdminUser
+    public URI getAdminUser() {
+        while(adminUser == null && !users_created) {
+            try {
+                Thread.sleep(1000);
+            } catch (InterruptedException e) {}
+            log.warn("admin user not yet created; waiting for creation to finish");
+        }
+
+        return adminUser;
+    }
+
+
+    /**
+     * Create a new user with the provided login. The method first
+     * checks of a user with this login already exists; if yes, an exception is thrown. The
+     * method does not persist the user; this needs to be done by the caller.
+     *
+     *
+     *
+     * @param login login of the user to create
+     * @return the newly created user.
+     */
+    @Override
+    public URI createUser(String login) throws UserExistsException {
+        return createUser(login, null, null);
+    }
+
+
+
+    /**
+     * Create a new user with the provided login, first name and last name. The method first
+     * checks of a user with this login already exists; if yes, an exception is thrown. The
+     * method does not persist the user; this needs to be done by the caller.
+     *
+     *
+     *
+     * @param login login of the user to create
+     * @param firstName first name of the user to create
+     * @param lastName last name of the user to create
+     * @return the newly created user.
+     */
+    @Override
+    public URI createUser(final String login, final String firstName, final String lastName) throws UserExistsException {
+        lock.lock();
+        try {
+            if(!userExists(login)) {
+
+                String webId_str = buildUserUri(login);
+
+                try {
+                    RepositoryConnection conn = sesameService.getConnection();
+
+                    URI webId = conn.getValueFactory().createURI(webId_str);
+
+                    log.info("creating user with webId: {} ", webId.stringValue());
+
+                    if (!login.equals(ANONYMOUS_LOGIN) && !login.equals(ADMIN_LOGIN)) {
+                        KiWiUser u = FacadingFactory.createFacading(conn).createFacade(webId, KiWiUser.class);
+                        u.setFirstName(firstName);
+                        u.setLastName(lastName);
+                        u.setNick(login);
+                    }
+
+                    if(login.equals(ANONYMOUS_LOGIN)) {
+                        anonUser = webId;
+                    }
+                    if(login.equals(ADMIN_LOGIN)) {
+                        adminUser = webId;
+                    }
+
+                    conn.commit();
+                    conn.close();
+
+                    return webId;
+                } catch(RepositoryException ex) {
+                    handleRepositoryException(ex);
+                    return null;
+                }
+
+            } else
+                throw new UserExistsException("User "+login+" already exists, cannot create!");
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    private String buildUserUri(final String login) {
+        return configurationService.getBaseUri() + "user/" + login;
+    }
+
+
+    /**
+     * Return a user by login. The user is looked up in the database and returned. In case
+     * no user with this login is found, this method returns null.
+     *
+     *
+     *
+     * @param login the login to look for
+     * @return the user with the given login, or null if no such user exists
+     */
+    @Override
+    public URI getUser(String login) {
+        return getUserByLogin(login);
+    }
+
+    /**
+     * Return a user by login. The user is looked up in the database and returned. In case
+     * no user with this login is found, this method returns null. The second parameter
+     * specifies whether a failure should be logged or accepted silently. A silent progress
+     * may be useful in case we just want to check whether a user exists.
+     *
+     *
+     * @param login the login to look for
+     * @return the user with the given login, or null if no such user exists
+     */
+    private URI getUserByLogin(String login) {
+        try {
+            RepositoryConnection conn = sesameService.getConnection();
+            try {
+                conn.begin();
+                String userUri = buildUserUri(login);
+                if (ResourceUtils.existsResource(conn, userUri))
+                    return conn.getValueFactory().createURI(userUri);
+                else
+                    return null;
+            } finally {
+                // TODO: this is not the perfect way to do it, but the only way to avoid cycles
+                // with the versioning
+                conn.rollback();
+                conn.close();
+            }
+        } catch (RepositoryException e) {
+            handleRepositoryException(e, UserServiceImpl.class);
+
+            return null;
+        }
+    }
+
+    /**
+     * Check whether a user with the given login already exists. If so,
+     * returns true. Otherwise returns false.
+     *
+     * @param login the login to look for
+     * @return true if a user with this login already exists, false otherwise
+     * @see kiwi.core.api.user.UserService#userExists(java.lang.String)
+     */
+    @Override
+    public boolean userExists(String login) {
+        return getUserByLogin(login) != null;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/c32963d5/lmf-core/src/main/java/kiwi/core/servlet/KiWiH2ConsoleFilter.java
----------------------------------------------------------------------
diff --git a/lmf-core/src/main/java/kiwi/core/servlet/KiWiH2ConsoleFilter.java b/lmf-core/src/main/java/kiwi/core/servlet/KiWiH2ConsoleFilter.java
new file mode 100644
index 0000000..7e0f641
--- /dev/null
+++ b/lmf-core/src/main/java/kiwi/core/servlet/KiWiH2ConsoleFilter.java
@@ -0,0 +1,89 @@
+/**
+ * Copyright (C) 2013 Salzburg Research.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package kiwi.core.servlet;
+
+import kiwi.core.api.config.ConfigurationService;
+import org.slf4j.Logger;
+
+import javax.inject.Inject;
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+
+/**
+ * This filter injects the database configuration into the H2 console using the LMF Configuration settings
+ * <p/>
+ * User: sschaffe
+ */
+public class KiWiH2ConsoleFilter implements Filter {
+
+    @Inject
+    private Logger log;
+
+    @Inject
+    private ConfigurationService configurationService;
+
+    @Override
+    public void init(FilterConfig filterConfig) throws ServletException {
+
+    }
+
+    @Override
+    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
+
+
+        if(servletRequest instanceof HttpServletRequest) {
+            HttpServletRequest req = (HttpServletRequest)servletRequest;
+
+            if(req.getPathInfo() != null && req.getPathInfo().endsWith("login.jsp")) {
+                // we redirect immediately to the action, since the login screen is not needed
+                String origUri = req.getRequestURI();
+                String redirectUri = origUri.substring(0,origUri.lastIndexOf("/")) + "/login.do?jsessionid="+req.getParameter("jsessionid");
+
+                ((HttpServletResponse)servletResponse).sendRedirect(redirectUri);
+            }
+
+            if(req.getPathInfo() != null && req.getPathInfo().endsWith("login.do")) {
+                // set the database configuration from system configuration
+                String db_type = configurationService.getStringConfiguration("database.type","h2");
+                String db_driver = configurationService.getStringConfiguration("database."+db_type+".driver");
+                String db_url =  configurationService.getStringConfiguration("database.url");
+                String db_user =  configurationService.getStringConfiguration("database.user");
+                String db_password =  configurationService.getStringConfiguration("database.password");
+
+                servletRequest.setAttribute("driver",db_driver);
+                servletRequest.setAttribute("url",db_url);
+                servletRequest.setAttribute("user",db_user);
+                servletRequest.setAttribute("password",db_password);
+            }
+        }
+
+        filterChain.doFilter(servletRequest,servletResponse);
+
+
+    }
+
+    @Override
+    public void destroy() {
+        //To change body of implemented methods use File | Settings | File Templates.
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/c32963d5/lmf-core/src/main/java/kiwi/core/servlet/KiWiPostStartupFilter.java
----------------------------------------------------------------------
diff --git a/lmf-core/src/main/java/kiwi/core/servlet/KiWiPostStartupFilter.java b/lmf-core/src/main/java/kiwi/core/servlet/KiWiPostStartupFilter.java
new file mode 100644
index 0000000..1f22d95
--- /dev/null
+++ b/lmf-core/src/main/java/kiwi/core/servlet/KiWiPostStartupFilter.java
@@ -0,0 +1,121 @@
+/**
+ * Copyright (C) 2013 Salzburg Research.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package kiwi.core.servlet;
+
+import java.io.IOException;
+
+import javax.enterprise.event.Event;
+import javax.enterprise.inject.Any;
+import javax.inject.Inject;
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+
+import kiwi.core.api.config.ConfigurationService;
+import kiwi.core.api.user.UserService;
+import kiwi.core.events.SystemStartupEvent;
+import kiwi.core.model.module.ModuleConfiguration;
+
+import org.slf4j.Logger;
+
+/**
+ * This filter is currently only used to indicate that the LMF server has been started successfully.
+ * <p/>
+ * User: sschaffe
+ */
+public class KiWiPostStartupFilter implements Filter {
+
+    @Inject
+    private Logger log;
+
+    @Inject
+    private ConfigurationService configurationService;
+
+    @Inject
+    private UserService userService;
+
+    @Inject
+    private ModuleConfiguration moduleConfiguration;
+
+    @Inject @Any
+    private Event<SystemStartupEvent> startupEvent;
+
+    /**
+     * Called by the web container to indicate to a filter that it is being placed into
+     * service. The servlet container calls the init method exactly once after instantiating the
+     * filter. The init method must complete successfully before the filter is asked to do any
+     * filtering work. <br><br>
+     * <p/>
+     * The web container cannot place the filter into service if the init method either<br>
+     * 1.Throws a ServletException <br>
+     * 2.Does not return within a time period defined by the web container
+     */
+    @Override
+    public void init(FilterConfig filterConfig) throws ServletException {
+        // if the system is already configured, we can safely trigger a startup event
+        if(configurationService.getBooleanConfiguration("kiwi.setup.host",false)) {
+            // startupEvent.fire(new SystemStartupEvent());
+        }
+
+        if(moduleConfiguration.hasBuildInfo()) {
+            log.warn("LMF Core Version {} has started up successfully!", moduleConfiguration.getModuleVersion());
+        } else {
+            log.warn("LMF Core (Development Version) has started up successfully!");
+        }
+
+        log.warn("You can access the system now at the URL {}", "http://"+configurationService.getServerName()+":"+configurationService.getServerPort()+configurationService.getServerContext()+"/");
+    }
+
+    /**
+     * The <code>doFilter</code> method of the Filter is called by the container
+     * each time a request/response pair is passed through the chain due
+     * to a client request for a resource at the end of the chain. The FilterChain passed in to this
+     * method allows the Filter to pass on the request and response to the next entity in the
+     * chain.<p>
+     * A typical implementation of this method would follow the following pattern:- <br>
+     * 1. Examine the request<br>
+     * 2. Optionally wrap the request object with a custom implementation to
+     * filter content or headers for input filtering <br>
+     * 3. Optionally wrap the response object with a custom implementation to
+     * filter content or headers for output filtering <br>
+     * 4. a) <strong>Either</strong> invoke the next entity in the chain using the FilterChain object (<code>chain.doFilter()</code>), <br>
+     * * 4. b) <strong>or</strong> not pass on the request/response pair to the next entity in the filter chain to block the request processing<br>
+     * * 5. Directly set headers on the response after invocation of the next entity in the filter chain.
+     */
+    @Override
+    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
+        chain.doFilter(request, response);
+    }
+
+    /**
+     * Called by the web container to indicate to a filter that it is being taken out of service. This
+     * method is only called once all threads within the filter's doFilter method have exited or after
+     * a timeout period has passed. After the web container calls this method, it will not call the
+     * doFilter method again on this instance of the filter. <br><br>
+     * <p/>
+     * This method gives the filter an opportunity to clean up any resources that are being held (for
+     * example, memory, file handles, threads) and make sure that any persistent state is synchronized
+     * with the filter's current state in memory.
+     */
+    @Override
+    public void destroy() {
+        //To change body of implemented methods use File | Settings | File Templates.
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/c32963d5/lmf-core/src/main/java/kiwi/core/servlet/KiWiPreStartupFilter.java
----------------------------------------------------------------------
diff --git a/lmf-core/src/main/java/kiwi/core/servlet/KiWiPreStartupFilter.java b/lmf-core/src/main/java/kiwi/core/servlet/KiWiPreStartupFilter.java
new file mode 100644
index 0000000..7c22180
--- /dev/null
+++ b/lmf-core/src/main/java/kiwi/core/servlet/KiWiPreStartupFilter.java
@@ -0,0 +1,116 @@
+/**
+ * Copyright (C) 2013 Salzburg Research.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package kiwi.core.servlet;
+
+import kiwi.core.api.config.ConfigurationService;
+import kiwi.core.startup.LMFStartupService;
+import org.slf4j.Logger;
+
+import javax.inject.Inject;
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+import java.io.IOException;
+
+/**
+ * This filter is evaluated when the LMF system is accessed for the very first time using an HTTP client (e.g. a
+ * browser). Its purpose is to set configuration variables that cannot be determined when the server is starting
+ * up because they need information how the server is accessed. In particular, it will set the following
+ * configuration variables in case the system has not yet been configured:
+ * <ul>
+ *  <li>kiwi.context - will be set to the base URI of this KiWi installation; used for constructing resource URIs</li>
+ *  <li>kiwi.host    - will be set to the base URL of the KiWi installation; used for accessing additional web services like SOLR and H2</li>
+ * </ul>
+ * <p/>
+ * User: Sebastian Schaffert
+ */
+public class KiWiPreStartupFilter implements Filter {
+
+    @Inject
+    private Logger log;
+
+    @Inject
+    private LMFStartupService startupService;
+
+    @Inject
+    private ConfigurationService configurationService;
+
+    private boolean started = false;
+
+    /**
+     * If the hostname (config properties kiwi.host and kiwi.context) of the system has not been configured yet, we
+     * try to automatically determine the correct values from the first request. The config variable
+     * kiwi.setup.host indicates whether setup has already been carried out.
+     * @param request
+     */
+    private String getBaseUrl(ServletRequest request) {
+        // check whether we need to perform setup
+        if (request instanceof HttpServletRequest) {
+            HttpServletRequest hreq = (HttpServletRequest) request;
+
+            String contextName = hreq.getContextPath();
+            String hostName    = hreq.getServerName();
+            int hostPort       = hreq.getServerPort();
+            String hostScheme  = hreq.getScheme();
+
+            String baseUrl = hostScheme + "://" + hostName;
+            if( hostPort == 80 && "http".equals(hostScheme) ||
+                    hostPort == 443 && "https".equals(hostScheme)  ) {
+                baseUrl = baseUrl + contextName + "/";
+            } else {
+                baseUrl = baseUrl + ":" + hostPort + contextName + "/";
+            }
+
+            return baseUrl;
+        } else {
+            return null;
+        }
+    }
+
+    @Override
+    public void init(FilterConfig filterConfig) throws ServletException {
+
+    }
+
+    @Override
+    public void doFilter(ServletRequest request, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
+
+        if(!started) {
+            synchronized (this) {
+                started = true;
+
+                String baseUrl = getBaseUrl(request);
+                if(baseUrl != null) {
+                    startupService.startupHost(baseUrl, baseUrl);
+                } else {
+                    log.error("could not determine host name; cannot startup LMF");
+                }
+            }
+        }
+
+        filterChain.doFilter(request,servletResponse);
+    }
+
+
+    @Override
+    public void destroy() {
+
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/c32963d5/lmf-core/src/main/java/kiwi/core/servlet/KiWiPreStartupListener.java
----------------------------------------------------------------------
diff --git a/lmf-core/src/main/java/kiwi/core/servlet/KiWiPreStartupListener.java b/lmf-core/src/main/java/kiwi/core/servlet/KiWiPreStartupListener.java
new file mode 100644
index 0000000..c811ae4
--- /dev/null
+++ b/lmf-core/src/main/java/kiwi/core/servlet/KiWiPreStartupListener.java
@@ -0,0 +1,61 @@
+/**
+ * Copyright (C) 2013 Salzburg Research.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package kiwi.core.servlet;
+
+import kiwi.core.startup.LMFStartupService;
+import kiwi.core.util.KiWiContext;
+
+import javax.servlet.ServletContextEvent;
+import javax.servlet.ServletContextListener;
+
+/**
+ * This filter is executed first in the startup chain. It initialises the LMF system variables if necessary and
+ * starts up the configuration service.
+ */
+public class KiWiPreStartupListener implements ServletContextListener {
+
+    private LMFStartupService lmfStartupService;
+
+    /**
+     * * Notification that the web application initialization
+     * * process is starting.
+     * * All ServletContextListeners are notified of context
+     * * initialization before any filter or servlet in the web
+     * * application is initialized.
+     */
+    @Override
+    public void contextInitialized(ServletContextEvent sce) {
+
+        if(lmfStartupService == null) {
+            lmfStartupService = KiWiContext.getInstance(LMFStartupService.class);
+        }
+
+        lmfStartupService.startupConfiguration(null,null,sce.getServletContext());
+
+    }
+
+    /**
+     * * Notification that the servlet context is about to be shut down.
+     * * All servlets and filters have been destroy()ed before any
+     * * ServletContextListeners are notified of context
+     * * destruction.
+     */
+    @Override
+    public void contextDestroyed(ServletContextEvent sce) {
+        lmfStartupService.shutdown();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/c32963d5/lmf-core/src/main/java/kiwi/core/servlet/KiWiResourceFilter.java
----------------------------------------------------------------------
diff --git a/lmf-core/src/main/java/kiwi/core/servlet/KiWiResourceFilter.java b/lmf-core/src/main/java/kiwi/core/servlet/KiWiResourceFilter.java
new file mode 100644
index 0000000..b418bae
--- /dev/null
+++ b/lmf-core/src/main/java/kiwi/core/servlet/KiWiResourceFilter.java
@@ -0,0 +1,218 @@
+/**
+ * Copyright (C) 2013 Salzburg Research.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package kiwi.core.servlet;
+
+import kiwi.core.api.config.ConfigurationService;
+import kiwi.core.api.modules.LMFHttpFilter;
+import kiwi.core.api.modules.ModuleService;
+import org.slf4j.Logger;
+
+import javax.enterprise.inject.Any;
+import javax.enterprise.inject.Instance;
+import javax.inject.Inject;
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+import java.io.IOException;
+import java.io.Serializable;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * This filter is used by KiWi for initialisation of the KiWi system on startup of the server. It does not perform
+ * any actual filtering. For this purpose, a listener would have been better, but CDI in Jetty does not support
+ * injection into listeners, so we "abuse" a filter for this purpose. Filters always get initialised before servlets,
+ * so by adding the KiWiFilter as the first entry into web.xml, we can ensure that the KiWi initialisation is done
+ * before everything else.
+ * <p/>
+ * User: sschaffe
+ */
+public class KiWiResourceFilter implements Filter {
+
+    @Inject
+    private Logger log;
+
+    @Inject
+    private ConfigurationService configurationService;
+
+    @Inject
+    private ModuleService moduleService;
+
+    @Inject @Any
+    private Instance<LMFHttpFilter> filters;
+
+    private List<LMFHttpFilter> filterList;
+
+    /**
+     * Called by the web container to indicate to a filter that it is being placed into
+     * service. The servlet container calls the init method exactly once after instantiating the
+     * filter. The init method must complete successfully before the filter is asked to do any
+     * filtering work. <br><br>
+     * <p/>
+     * The web container cannot place the filter into service if the init method either<br>
+     * 1.Throws a ServletException <br>
+     * 2.Does not return within a time period defined by the web container
+     */
+    @Override
+    public void init(FilterConfig filterConfig) throws ServletException {
+        log.info("LMF Resource Filter {} starting up ... ", configurationService.getConfiguration("kiwi.version"));
+
+
+        // initialise filter chain and sort it according to priority
+        this.filterList  = new ArrayList<LMFHttpFilter>();
+
+        for(LMFHttpFilter filter : filters) {
+            try {
+                filter.init(filterConfig);
+                filterList.add(filter);
+
+                log.debug("module {}: registered filter {}", moduleService.getModuleConfiguration(filter.getClass()).getModuleName(), filter.getClass().getCanonicalName());
+            } catch (ServletException ex) {
+                log.error("could not instantiate filter {}, servlet exception during initialisation ({})",filter.getClass(),ex.getMessage());
+            }
+        }
+
+        Collections.sort(filterList,new FilterComparator());
+
+    }
+
+
+
+    /**
+     * The <code>doFilter</code> method of the Filter is called by the container
+     * each time a request/response pair is passed through the chain due
+     * to a client request for a resource at the end of the chain. The FilterChain passed in to this
+     * method allows the Filter to pass on the request and response to the next entity in the
+     * chain.<p>
+     * A typical implementation of this method would follow the following pattern:- <br>
+     * 1. Examine the request<br>
+     * 2. Optionally wrap the request object with a custom implementation to
+     * filter content or headers for input filtering <br>
+     * 3. Optionally wrap the response object with a custom implementation to
+     * filter content or headers for output filtering <br>
+     * 4. a) <strong>Either</strong> invoke the next entity in the chain using the FilterChain object (<code>chain.doFilter()</code>), <br>
+     * * 4. b) <strong>or</strong> not pass on the request/response pair to the next entity in the filter chain to block the request processing<br>
+     * * 5. Directly set headers on the response after invocation of the next entity in the filter chain.
+     */
+    @Override
+    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
+        URL url = null;
+        String prefix = null, path = null;
+        if (request instanceof HttpServletRequest) {
+            url    = new URL(((HttpServletRequest)request).getRequestURL().toString());
+            prefix = ((HttpServletRequest)request).getContextPath();
+            if(url.getPath().startsWith(prefix)) {
+                path = url.getPath().substring(prefix.length());
+            }
+        }
+
+        new LMFFilterChain(path,chain).doFilter(request,response);
+
+    }
+
+
+
+
+    /**
+     * Called by the web container to indicate to a filter that it is being taken out of service. This
+     * method is only called once all threads within the filter's doFilter method have exited or after
+     * a timeout period has passed. After the web container calls this method, it will not call the
+     * doFilter method again on this instance of the filter. <br><br>
+     * <p/>
+     * This method gives the filter an opportunity to clean up any resources that are being held (for
+     * example, memory, file handles, threads) and make sure that any persistent state is synchronized
+     * with the filter's current state in memory.
+     */
+    @Override
+    public void destroy() {
+        for(LMFHttpFilter filter : filterList) {
+            filter.destroy();
+        }
+    }
+
+
+    /**
+     * A special filter chain that implements the LMFHttpFilter calls
+     */
+    private class LMFFilterChain implements FilterChain {
+
+        private Iterator<LMFHttpFilter> filters;
+
+        private String path;
+
+        private FilterChain originalChain;
+
+        LMFFilterChain(String path, FilterChain originalChain) {
+            this.path     = path;
+            this.filters = filterList.iterator();
+            this.originalChain = originalChain;
+        }
+
+
+        @Override
+        public void doFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException {
+            if(filters.hasNext()) {
+                LMFHttpFilter filter = filters.next();
+
+                if(path.matches(filter.getPattern())) {
+                    filter.doFilter(request,response,this);
+                } else {
+                    doFilter(request,response);
+                }
+            } else {
+                originalChain.doFilter(request,response);
+            }
+        }
+    }
+
+
+
+    private static class FilterComparator implements Comparator<LMFHttpFilter>, Serializable {
+
+        private static final long serialVersionUID = -7264645592168345092L;
+
+        /**
+         * Compares its two arguments for order.  Returns a negative integer,
+         * zero, or a positive integer as the first argument is less than, equal
+         * to, or greater than the second.<p>
+         * <p/>
+         *
+         * @param o1 the first object to be compared.
+         * @param o2 the second object to be compared.
+         * @return a negative integer, zero, or a positive integer as the
+         *         first argument is less than, equal to, or greater than the
+         *         second.
+         * @throws ClassCastException if the arguments' types prevent them from
+         *                            being compared by this comparator.
+         */
+        @Override
+        public int compare(LMFHttpFilter o1, LMFHttpFilter o2) {
+            if(o1.getPriority() < o2.getPriority())
+                return -1;
+            else if(o1.getPriority() > o2.getPriority()) return 1;
+            else
+                return 0;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/c32963d5/lmf-core/src/main/java/kiwi/core/servlet/LMFOptionsFilter.java
----------------------------------------------------------------------
diff --git a/lmf-core/src/main/java/kiwi/core/servlet/LMFOptionsFilter.java b/lmf-core/src/main/java/kiwi/core/servlet/LMFOptionsFilter.java
new file mode 100644
index 0000000..da274bc
--- /dev/null
+++ b/lmf-core/src/main/java/kiwi/core/servlet/LMFOptionsFilter.java
@@ -0,0 +1,168 @@
+/**
+ * Copyright (C) 2013 Salzburg Research.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package kiwi.core.servlet;
+
+import kiwi.core.api.config.ConfigurationService;
+import org.jboss.resteasy.spi.DefaultOptionsMethodException;
+import org.jboss.resteasy.spi.ResteasyProviderFactory;
+import org.slf4j.Logger;
+
+import javax.inject.Inject;
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.ext.ExceptionMapper;
+import javax.ws.rs.ext.Provider;
+import java.io.IOException;
+import java.util.Arrays;
+
+/**
+ * This filter checks for OPTIONS requests. If the response returned by the other filters throws an exception
+ * org.jboss.resteasy.spi.DefaultOptionsMethodException, the filter writes to the response the default options
+ * of the LMF system, in particular the following headers:
+ *
+ * Access-Control-Allow-Origin: * (or as configured in config.properties)
+ * Access-Control-Allow-Methods: POST, PUT, GET, DELETE, HEAD, OPTIONS
+ *
+ * <p/>
+ * Author: Sebastian Schaffert
+ */
+public class LMFOptionsFilter implements Filter {
+
+    @Inject
+    private Logger log;
+
+    @Inject
+    private ConfigurationService configurationService;
+
+    /**
+     * Called by the web container to indicate to a filter that it is being placed into
+     * service. The servlet container calls the init method exactly once after instantiating the
+     * filter. The init method must complete successfully before the filter is asked to do any
+     * filtering work. <br><br>
+     * <p/>
+     * The web container cannot place the filter into service if the init method either<br>
+     * 1.Throws a ServletException <br>
+     * 2.Does not return within a time period defined by the web container
+     */
+    @Override
+    public void init(FilterConfig filterConfig) throws ServletException {
+        ResteasyProviderFactory.getInstance().addExceptionMapper(new OptionsMapper());
+    }
+
+    /**
+     * The <code>doFilter</code> method of the Filter is called by the container
+     * each time a request/response pair is passed through the chain due
+     * to a client request for a resource at the end of the chain. The FilterChain passed in to this
+     * method allows the Filter to pass on the request and response to the next entity in the
+     * chain.<p>
+     * A typical implementation of this method would follow the following pattern:- <br>
+     * 1. Examine the request<br>
+     * 2. Optionally wrap the request object with a custom implementation to
+     * filter content or headers for input filtering <br>
+     * 3. Optionally wrap the response object with a custom implementation to
+     * filter content or headers for output filtering <br>
+     * 4. a) <strong>Either</strong> invoke the next entity in the chain using the FilterChain object (<code>chain.doFilter()</code>), <br>
+     * * 4. b) <strong>or</strong> not pass on the request/response pair to the next entity in the filter chain to block the request processing<br>
+     * * 5. Directly set headers on the response after invocation of the next entity in the filter chain.
+     */
+    @Override
+    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
+
+
+        try {
+
+            chain.doFilter(request,response);
+//			DG: The addition of the response header fails because the respons is already committed - so remote the code
+//             
+/*            if(response instanceof HttpServletResponse) {
+                HttpServletResponse resp = (HttpServletResponse)response;
+                HttpServletRequest  req  = (HttpServletRequest)request;
+
+                // adjust the header only when the request is not yet com
+                if (! resp.isCommitted() ) {
+	                if(!"OPTIONS".equalsIgnoreCase(req.getMethod()) && !resp.containsHeader("Access-Control-Allow-Origin")) {
+	                    resp.setHeader("Access-Control-Allow-Origin",configurationService.getStringConfiguration("kiwi.allow_origin","*"));
+	                }
+                }
+
+            }
+*/          
+        } catch (DefaultOptionsMethodException ex) {
+            if(response instanceof HttpServletResponse) {
+                HttpServletResponse resp = (HttpServletResponse)response;
+                HttpServletRequest req  = (HttpServletRequest)request;
+
+                if(req.getMethod().equalsIgnoreCase("OPTIONS")) {
+                    resp.setStatus(200);
+                    resp.resetBuffer();
+
+
+                    if(!resp.containsHeader("Access-Control-Allow-Origin")) {
+                        resp.setHeader("Access-Control-Allow-Origin",configurationService.getStringConfiguration("kiwi.allow_origin","*"));
+                    }
+                    if(!resp.containsHeader("Access-Control-Allow-Methods")) {
+                        for(String method : configurationService.getListConfiguration("kiwi.allow_methods", Arrays.asList("POST, PUT, GET, DELETE, HEAD".split(",")))) {
+                            resp.addHeader("Access-Control-Allow-Methods",method);
+                        }
+                    }
+                    if(req.getHeader("Access-Control-Request-Headers") != null) {
+                        String header = req.getHeader("Access-Control-Request-Headers");
+                        String[] values = header.split(",");
+                        for(String value : values) {
+                            resp.addHeader("Access-Control-Allow-Headers",value.trim());
+                        }
+                    }
+
+                }
+            }
+        }
+
+
+
+    }
+
+    /**
+     * Called by the web container to indicate to a filter that it is being taken out of service. This
+     * method is only called once all threads within the filter's doFilter method have exited or after
+     * a timeout period has passed. After the web container calls this method, it will not call the
+     * doFilter method again on this instance of the filter. <br><br>
+     * <p/>
+     * This method gives the filter an opportunity to clean up any resources that are being held (for
+     * example, memory, file handles, threads) and make sure that any persistent state is synchronized
+     * with the filter's current state in memory.
+     */
+    @Override
+    public void destroy() {
+        //To change body of implemented methods use File | Settings | File Templates.
+    }
+
+    @Provider
+    protected static class OptionsMapper implements ExceptionMapper<DefaultOptionsMethodException> {
+
+        @Override
+        public Response toResponse(DefaultOptionsMethodException exception) {
+            throw exception;
+        }
+
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/c32963d5/lmf-core/src/main/java/kiwi/core/startup/LMFStartupService.java
----------------------------------------------------------------------
diff --git a/lmf-core/src/main/java/kiwi/core/startup/LMFStartupService.java b/lmf-core/src/main/java/kiwi/core/startup/LMFStartupService.java
new file mode 100644
index 0000000..929081f
--- /dev/null
+++ b/lmf-core/src/main/java/kiwi/core/startup/LMFStartupService.java
@@ -0,0 +1,244 @@
+/**
+ * Copyright (C) 2013 Salzburg Research.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package kiwi.core.startup;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.locks.ReentrantLock;
+
+import javax.annotation.PostConstruct;
+import javax.enterprise.context.ApplicationScoped;
+import javax.enterprise.event.Event;
+import javax.enterprise.inject.Any;
+import javax.inject.Inject;
+import javax.servlet.ServletContext;
+
+import kiwi.core.api.config.ConfigurationService;
+import kiwi.core.api.modules.ModuleService;
+import kiwi.core.api.triplestore.SesameService;
+import kiwi.core.api.ui.LMFSystrayLink;
+import kiwi.core.api.user.UserService;
+import kiwi.core.events.SesameStartupEvent;
+import kiwi.core.events.SystemStartupEvent;
+import kiwi.core.model.module.ModuleConfiguration;
+import kiwi.core.util.KiWiContext;
+
+import org.apache.commons.configuration.Configuration;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * This service unifies the different steps in the LMF startup. It offers several methods
+ * for triggering the different startup sequences and can be used e.g. by web applications or
+ * embedded applications to initiate LMF startup. Note that the LMF Startup requires a running
+ * CDI/Weld environment before being used.
+ * <p/>
+ * Author: Sebastian Schaffert
+ */
+@ApplicationScoped
+public class LMFStartupService {
+
+    private static final String DEFAULT_KIWI_VERSION = "undefined";
+
+    private Logger log  = LoggerFactory.getLogger(LMFStartupService.class);
+
+    @Inject
+    private ConfigurationService configurationService;
+
+    @Inject
+    private ModuleService moduleService;
+
+    @Inject @Any
+    private Event<SystemStartupEvent> startupEvent;
+
+    @Inject @Any
+    private Event<SesameStartupEvent> sesameEvent;
+
+    private boolean configurationStarted = false;
+
+    private boolean hostStarted = false;
+
+    private ReentrantLock lock;
+
+    @PostConstruct
+    public void initialise() {
+        lock = new ReentrantLock();
+    }
+
+    /**
+     * Startup the LMF Configuration. This method ensures that the LMF home directory is created and the
+     * ConfigurationService is properly initialised. It must be called first in the startup sequence.
+     * The parameters lmfHome and configurationOverride can be used to override the default settings
+     * of the LMF.
+     *
+     * @param lmfHome                 home directory of the LMF instance (may be null, in which case the default will be used)
+     * @param configurationOverride   configuration options that should override the default values from default-config.properties (may be null)
+     * @param context                 the servlet context the LMF is running in (may be null)
+     */
+    public void startupConfiguration(String lmfHome, Configuration configurationOverride, ServletContext context) {
+        lock.lock();
+
+        //to set config version number
+        String versionNumber = DEFAULT_KIWI_VERSION;
+
+        try {
+            if(configurationStarted) {
+                log.warn("LMF Startup: configuration already started; ignoring second request");
+                return;
+            }
+
+            ModuleConfiguration coreConfiguration = moduleService.getModuleConfiguration(this.getClass());
+
+            if(coreConfiguration.hasBuildInfo()) {
+                log.info("LMF Core Version {} starting up ... ", coreConfiguration.getModuleVersion());
+                log.info("Build Information:");
+                log.info(" - Build User: {}", coreConfiguration.getBuildUser());
+                log.info(" - Build Host: {}", coreConfiguration.getBuildHost());
+                log.info(" - Build Time: {}", coreConfiguration.getBuildTimestamp());
+                log.info(" - Build OS:   {}", coreConfiguration.getBuildOS());
+                log.info(" - Revision:   {}:{}", coreConfiguration.getBuildRevisionNumber(), coreConfiguration.getBuildRevisionHash());
+                versionNumber = coreConfiguration.getModuleVersion();
+            } else {
+                log.info("LMF Core (Development Version) starting up ... ");
+            }
+
+            String kiwiHome = lmfHome;
+
+            if(kiwiHome != null) {
+
+            } else {
+                kiwiHome = System.getProperty("kiwi.home");
+
+                if(kiwiHome != null) {
+                    log.info("Configured working directory {} from system property kiwi.home",kiwiHome);
+                } else {
+                    kiwiHome = System.getenv("LMF_HOME");
+                    if(kiwiHome != null) {
+                        log.info("Configured working directory {} from environment variable LMF_HOME",kiwiHome);
+                    } else {
+                        kiwiHome = System.getenv("KIWI_HOME");
+                        if(kiwiHome != null) {
+                            log.info("Configured working directory {} from environment variable KIWI_HOME",kiwiHome);
+                        } else if (context != null) {
+                            kiwiHome = context.getInitParameter("kiwi.home");
+                            if(kiwiHome != null) {
+                                log.info("Configured working directory {} from servlet context parameter kiwi.home",kiwiHome);
+                            }
+                        } else {
+                            log.error("could not determine LMF home directory, please set the environment variable LMF_HOME");
+                        }
+                    }
+                }
+            }
+
+            if(kiwiHome != null) {
+                configurationService.setLMFHome(kiwiHome);
+            }
+
+            if(context != null) {
+                configurationService.setServletContext(context);
+            }
+
+            configurationService.initialize(kiwiHome,configurationOverride);
+
+
+            configurationService.setConfiguration("kiwi.version",versionNumber);
+
+            if(context != null) {
+                configurationService.setConfiguration("kiwi.path",context.getContextPath());
+
+                // register the systray links provided by the different components
+                Map<String, String> demoLinks  = new HashMap<String, String>();
+                Map<String, String> adminLinks = new HashMap<String, String>();
+
+                for(LMFSystrayLink link : KiWiContext.getInstances(LMFSystrayLink.class)) {
+                    if(link.getSection() == LMFSystrayLink.Section.DEMO) {
+                        demoLinks.put(link.getLabel(), link.getLink());
+                    } else if(link.getSection() == LMFSystrayLink.Section.ADMIN) {
+                        adminLinks.put(link.getLabel(), link.getLink());
+                    }
+                }
+                context.setAttribute("systray.admin", adminLinks);
+                context.setAttribute("systray.demo", demoLinks);
+            }
+
+            configurationStarted = true;
+        } finally {
+            lock.unlock();
+        }
+
+    }
+
+
+    /**
+     * Start up the LMF server environment. This method ensures that the base URL for the host (used by the
+     * web interface) and the context (used for creating local Linked Data URIs) is properly set and thus
+     * the services depending on this configuration can start up. This method must be called in the second
+     * phase of LMF startup, i.e. when the configuration service is already configured.
+     * <p/>
+     * The method expects a host URL and a context URL to be given. In case the context URL is not given,
+     * it will be the same as the host URL.
+     *
+     * @param hostUrl     the URL of the host, used as based URL for building the LMF web interface
+     * @param contextUrl  the base URL used to construct Linked Data resources
+     */
+    public void startupHost(String hostUrl, String contextUrl) {
+        lock.lock();
+
+        try {
+            if(hostStarted) {
+                log.warn("LMF Startup: host already started; ignoring subsequent startup requests");
+                return;
+            }
+ 
+            // check whether this is a first-time initialization
+            boolean isSetup = configurationService.getBooleanConfiguration("kiwi.setup.host");
+
+            // carry out initializations that need the server URI to be set properly
+            if(!isSetup) {
+                log.info("SETUP: Setting up initial host and resource configuration ({}) ...", hostUrl);
+
+                configurationService.setConfiguration("kiwi.context", contextUrl);
+                configurationService.setConfiguration("kiwi.host", hostUrl);
+
+                configurationService.setConfiguration("kiwi.setup.host", true);
+            }
+
+            // trigger startup of the sesame service once the hostname is ready (we need the correct URIs for
+            // default, cache and inferred context)
+            SesameService sesameService  = KiWiContext.getInstance(SesameService.class);
+            sesameService.initialise();
+            sesameEvent.fire(new SesameStartupEvent());
+
+            // trigger startup of the user service once the sesame service is ready
+            UserService   userService    = KiWiContext.getInstance(UserService.class);
+
+            userService.createDefaultUsers();
+
+            hostStarted = true;
+
+            startupEvent.fire(new SystemStartupEvent());
+        } finally {
+            lock.unlock();
+        }
+
+    }
+
+    public void shutdown() {
+        log.info("LMF Core shutting down ...");
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/c32963d5/lmf-core/src/main/java/kiwi/core/util/CdiUtils.java
----------------------------------------------------------------------
diff --git a/lmf-core/src/main/java/kiwi/core/util/CdiUtils.java b/lmf-core/src/main/java/kiwi/core/util/CdiUtils.java
new file mode 100644
index 0000000..d45a42e
--- /dev/null
+++ b/lmf-core/src/main/java/kiwi/core/util/CdiUtils.java
@@ -0,0 +1,44 @@
+/**
+ * Copyright (C) 2013 Salzburg Research.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package kiwi.core.util;
+
+import javax.enterprise.inject.Instance;
+import javax.inject.Named;
+import java.lang.annotation.Annotation;
+
+public abstract class CdiUtils {
+
+    public static <T> Instance<T> selectNamed(Instance<T> instance, String name) {
+        if (name != null)
+            return instance.select(createNamedLiteral(name));
+        return instance;
+    }
+
+    private static Annotation createNamedLiteral(final String name) {
+        return new Named() {
+            @Override
+            public Class<? extends Annotation> annotationType() {
+                return Named.class;
+            }
+
+            @Override
+            public String value() {
+                return name;
+            }
+        };
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/c32963d5/lmf-core/src/main/java/kiwi/core/util/DateUtil.java
----------------------------------------------------------------------
diff --git a/lmf-core/src/main/java/kiwi/core/util/DateUtil.java b/lmf-core/src/main/java/kiwi/core/util/DateUtil.java
new file mode 100644
index 0000000..4762894
--- /dev/null
+++ b/lmf-core/src/main/java/kiwi/core/util/DateUtil.java
@@ -0,0 +1,50 @@
+/**
+ * Copyright (C) 2013 Salzburg Research.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package kiwi.core.util;
+
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.TimeZone;
+
+public class DateUtil {
+    
+    public static final String XSD_DATETIME = "yyyy-MM-dd'T'HH:mm:ssZ";
+
+    public static Date parse(String xmlDateTime) throws ParseException  {
+        if ( xmlDateTime.length() != 25 )  {
+            throw new ParseException("Date not in expected xsd:datetime format", 0);
+        }
+        StringBuilder sb = new StringBuilder(xmlDateTime);
+        sb.deleteCharAt(22);
+        SimpleDateFormat simpleDateFormat = new SimpleDateFormat(XSD_DATETIME);
+        return simpleDateFormat.parse(sb.toString());
+    }
+    
+    public static String serializeXsdDateTime(Date date) {
+        return serializeXsdDateTime(date, TimeZone.getDefault());
+    }
+    
+    public static String serializeXsdDateTime(Date date, TimeZone timezone) {
+        SimpleDateFormat simpleDateFormat = new SimpleDateFormat(XSD_DATETIME);
+        simpleDateFormat.setTimeZone(timezone);
+        String s =  simpleDateFormat.format(date);
+        StringBuilder sb = new StringBuilder(s);
+        sb.insert(22, ':');
+        return sb.toString();
+    }
+
+}