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

[8/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/util/FallbackConfiguration.java
----------------------------------------------------------------------
diff --git a/lmf-core/src/main/java/kiwi/core/util/FallbackConfiguration.java b/lmf-core/src/main/java/kiwi/core/util/FallbackConfiguration.java
new file mode 100644
index 0000000..9171b5d
--- /dev/null
+++ b/lmf-core/src/main/java/kiwi/core/util/FallbackConfiguration.java
@@ -0,0 +1,59 @@
+/**
+ * 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 org.apache.commons.configuration.CompositeConfiguration;
+import org.apache.commons.configuration.Configuration;
+
+import java.util.Collection;
+import java.util.List;
+
+public class FallbackConfiguration extends CompositeConfiguration {
+
+    public FallbackConfiguration() {
+        super();
+    }
+
+    public FallbackConfiguration(Collection<? extends Configuration> configurations) {
+        super(configurations);
+    }
+
+    public FallbackConfiguration(Configuration inMemoryConfiguration, Collection<? extends Configuration> configurations) {
+        super(inMemoryConfiguration, configurations);
+    }
+
+    public FallbackConfiguration(Configuration inMemoryConfiguration) {
+        super(inMemoryConfiguration);
+    }
+
+    @Override
+    public List<Object> getList(String key, List<Object> defaultValue) {
+        final Configuration mem = getInMemoryConfiguration();
+        if (mem.containsKey(key))
+            return mem.getList(key, defaultValue);
+        else
+            return super.getList(key, defaultValue);
+    }
+
+    @Override
+    public List<Object> getList(String key) {
+        final Configuration mem = getInMemoryConfiguration();
+        if (mem.containsKey(key))
+            return mem.getList(key);
+        else
+            return super.getList(key);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/c32963d5/lmf-core/src/main/java/kiwi/core/util/JerseyUtils.java
----------------------------------------------------------------------
diff --git a/lmf-core/src/main/java/kiwi/core/util/JerseyUtils.java b/lmf-core/src/main/java/kiwi/core/util/JerseyUtils.java
new file mode 100644
index 0000000..c8b0c48
--- /dev/null
+++ b/lmf-core/src/main/java/kiwi/core/util/JerseyUtils.java
@@ -0,0 +1,43 @@
+/**
+ * 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.ws.rs.Path;
+
+/**
+ * Utilities for working with Jersey
+ * 
+ * @author Sergio Fernández
+ * 
+ */
+public class JerseyUtils {
+
+    /**
+     * Get the resource's path
+     * 
+     * @param resource target resource
+     * @return path
+     */
+    public static String getResourcePath(Object resource) {
+        try {
+            return (String) ReflectionUtils.getAnnotationValue(resource, Path.class, "value");
+        } catch (Exception e) {
+            e.printStackTrace();
+            return null;
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/c32963d5/lmf-core/src/main/java/kiwi/core/util/KiWiContext.java
----------------------------------------------------------------------
diff --git a/lmf-core/src/main/java/kiwi/core/util/KiWiContext.java b/lmf-core/src/main/java/kiwi/core/util/KiWiContext.java
new file mode 100644
index 0000000..71a6e0e
--- /dev/null
+++ b/lmf-core/src/main/java/kiwi/core/util/KiWiContext.java
@@ -0,0 +1,124 @@
+/**
+ * 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 org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.enterprise.context.spi.CreationalContext;
+import javax.enterprise.inject.spi.Bean;
+import javax.enterprise.inject.spi.BeanManager;
+import javax.naming.*;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * KiWi (LMF) Content Util
+ * 
+ * @author Sebastian Schaffert
+ */
+public class KiWiContext {
+    private static BeanManager beanManager;
+
+    private static final List<String> beanManagerLocations;
+
+    private static Logger log = LoggerFactory.getLogger(KiWiContext.class);
+
+    static {
+        beanManagerLocations = new ArrayList<String>();
+        beanManagerLocations.add("java:comp/env/BeanManager");
+        beanManagerLocations.add("java:comp/BeanManager");
+        beanManagerLocations.add("java:app/BeanManager");
+    }
+
+
+    protected static BeanManager getBeanManager() {
+        if (beanManager == null)
+        {
+            beanManager = lookupBeanManager();
+        }
+        return beanManager;
+    }
+
+
+    private static BeanManager lookupBeanManager() {
+        for (String location : beanManagerLocations) {
+            try {
+                return (BeanManager) new InitialContext().lookup(location);
+            } catch (NameNotFoundException e) {
+                // do nothing
+            } catch (NamingException e) {
+                log.error(
+                        "naming exception for path {}; this probably means that JNDI is not set up properly (see e.g. http://code.google.com/p/lmf/wiki/InstallationSetup#Specific_Settings_for_Tomcat )",
+                        location, e);
+            }
+        }
+        // in case no JNDI resource for the bean manager is found, display the JNDI context for debugging
+        try {
+            log.info("Could not find BeanManager in {}; list of JNDI context follows", beanManagerLocations);
+            showJndiContext(new InitialContext(),"java:", "");
+        } catch (NamingException e) {
+            log.error("error listing JNDI context",e);
+        }
+        throw new IllegalArgumentException("Could not find BeanManager in " + beanManagerLocations);
+    }
+
+    @SuppressWarnings("unchecked")
+    public static <T> T getInstance(Class<T> type) {
+
+        BeanManager beanManager = getBeanManager();
+        Bean<T> bean = (Bean<T>) beanManager.getBeans(type).iterator().next();
+        CreationalContext<T> context = beanManager.createCreationalContext(bean);
+        return (T) beanManager.getReference(bean, type, context);
+    }
+
+    /**
+     * Return all injectable instances of the given type.
+     * @param type
+     * @param <T>
+     * @return
+     */
+    @SuppressWarnings("unchecked")
+    public static <T> List<T> getInstances(Class<T> type) {
+
+        BeanManager beanManager = getBeanManager();
+
+        List<T> result = new ArrayList<T>();
+        for(Bean<?> bean :  beanManager.getBeans(type)) {
+            CreationalContext<T> context = beanManager.createCreationalContext((Bean<T>)bean);
+            result.add((T) beanManager.getReference(bean, type, context));
+        }
+
+        return result;
+    }
+
+
+    public static void showJndiContext(Context ctx, String name, String path) {
+        try {
+            NamingEnumeration<NameClassPair> bindings = ctx.list(name);
+            while(bindings.hasMoreElements()) {
+                NameClassPair pair = bindings.nextElement();
+                log.info("Found JNDI resource: {}{} = {}", path,pair.getName(),pair.getClassName());
+                if(pair.getClassName().endsWith("NamingContext")) {
+                    showJndiContext((Context)ctx.lookup(name+ (name.length()>5?"/":"")+pair.getName()),"",path+"--");
+                }
+            }
+        }catch ( NamingException ex ) {}
+    }
+
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/c32963d5/lmf-core/src/main/java/kiwi/core/util/KiWiIO.java
----------------------------------------------------------------------
diff --git a/lmf-core/src/main/java/kiwi/core/util/KiWiIO.java b/lmf-core/src/main/java/kiwi/core/util/KiWiIO.java
new file mode 100644
index 0000000..f7c8197
--- /dev/null
+++ b/lmf-core/src/main/java/kiwi/core/util/KiWiIO.java
@@ -0,0 +1,114 @@
+/**
+ * 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.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.math.BigInteger;
+import java.security.DigestInputStream;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+
+import com.google.common.base.Preconditions;
+
+/**
+ * Add file description here!
+ * <p/>
+ * Author: Sebastian Schaffert
+ */
+public class KiWiIO {
+
+	/**
+	 * Deletes all the files within a directory. Does not delete the directory
+	 * itself.
+	 * 
+	 * <p>
+	 * If the file argument is a symbolic link or there is a symbolic link in
+	 * the path leading to the directory, this method will do nothing. Symbolic
+	 * links within the directory are not followed.
+	 * 
+	 * @param directory
+	 *            the directory to delete the contents of
+	 * @throws IllegalArgumentException
+	 *             if the argument is not a directory
+	 * @throws IOException
+	 *             if an I/O error occurs
+	 * @see #deleteRecursively
+	 */
+	public static void deleteDirectoryContents(File directory)
+			throws IOException {
+		Preconditions.checkArgument(directory.isDirectory(),
+				"Not a directory: %s", directory);
+		File[] files = directory.listFiles();
+		if (files == null) {
+			throw new IOException("Error listing files for " + directory);
+		}
+		for (File file : files) {
+			deleteRecursively(file);
+		}
+	}
+
+	/**
+	 * Deletes a file or directory and all contents recursively.
+	 * 
+	 * <p>
+	 * If the file argument is a symbolic link the link will be deleted but not
+	 * the target of the link. If the argument is a directory, symbolic links
+	 * within the directory will not be followed.
+	 * 
+	 * @param file
+	 *            the file to delete
+	 * @throws IOException
+	 *             if an I/O error occurs
+	 * @see #deleteDirectoryContents
+	 */
+	public static void deleteRecursively(File file) throws IOException {
+		if (file.isDirectory()) {
+			deleteDirectoryContents(file);
+		}
+		if (!file.delete()) {
+			throw new IOException("Failed to delete " + file);
+		}
+	}
+
+	public static String md5sum(File file) throws FileNotFoundException, IOException {
+		FileInputStream fis = new FileInputStream(file);
+		return md5sum(fis);
+	}
+
+	public static String md5sum(InputStream input) throws IOException {
+		try {
+			MessageDigest md;
+			md = MessageDigest.getInstance("MD5");
+			DigestInputStream dis = new DigestInputStream(input, md);
+			try {
+				byte[] buff = new byte[1024];
+				// just read to get the Digest filled...
+				while (dis.read(buff) > 0)
+					;
+				return new BigInteger(1, md.digest()).toString(16);
+			} finally {
+				dis.close();
+			}
+		} catch (NoSuchAlgorithmException e) {
+			// this should not happen
+			return null;
+		}
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/c32963d5/lmf-core/src/main/java/kiwi/core/util/LinkedHashSetBlockingQueue.java
----------------------------------------------------------------------
diff --git a/lmf-core/src/main/java/kiwi/core/util/LinkedHashSetBlockingQueue.java b/lmf-core/src/main/java/kiwi/core/util/LinkedHashSetBlockingQueue.java
new file mode 100644
index 0000000..d32ab6a
--- /dev/null
+++ b/lmf-core/src/main/java/kiwi/core/util/LinkedHashSetBlockingQueue.java
@@ -0,0 +1,415 @@
+/**
+ * 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.util.AbstractQueue;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.LinkedHashSet;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.locks.Condition;
+import java.util.concurrent.locks.ReentrantLock;
+
+/**
+ * A blocking queue implementation backed by a linked hash set for predictable iteration order and
+ * constant time addition, removal and contains operations.
+ * <p/>
+ * Author: Sebastian Schaffert
+ */
+public class LinkedHashSetBlockingQueue<E> extends AbstractQueue<E> implements BlockingQueue<E> {
+
+    private int capacity = Integer.MAX_VALUE;
+
+    /** Current number of elements */
+    private final AtomicInteger count = new AtomicInteger(0);
+
+    /** Lock held by take, poll, etc */
+    private final ReentrantLock takeLock = new ReentrantLock();
+
+    /** Wait queue for waiting takes */
+    private final Condition notEmpty = takeLock.newCondition();
+
+    /** Lock held by put, offer, etc */
+    private final ReentrantLock putLock = new ReentrantLock();
+
+    /** Wait queue for waiting puts */
+    private final Condition notFull = putLock.newCondition();
+
+    private final LinkedHashSet<E> delegate;
+
+    public LinkedHashSetBlockingQueue() {
+        delegate = new LinkedHashSet<E>();
+    }
+
+    public LinkedHashSetBlockingQueue(int capacity) {
+        this.delegate = new LinkedHashSet<E>(capacity);
+        this.capacity = capacity;
+    }
+
+
+    @Override
+    public boolean offer(E e) {
+        if (e == null) throw new NullPointerException();
+        final AtomicInteger count = this.count;
+        if (count.get() == capacity)
+            return false;
+        int c = -1;
+        final ReentrantLock putLock = this.putLock;
+        putLock.lock();
+        try {
+            if (count.get() < capacity) {
+                final boolean wasAdded = enqueue(e);
+                c = wasAdded?count.getAndIncrement():count.get();
+                if (c + 1 < capacity)
+                    notFull.signal();
+            }
+        } finally {
+            putLock.unlock();
+        }
+        if (c == 0)
+            signalNotEmpty();
+        return c >= 0;
+    }
+
+    @Override
+    public void put(E e) throws InterruptedException {
+        if (e == null) throw new NullPointerException();
+
+        int c = -1;
+        final ReentrantLock putLock = this.putLock;
+        final AtomicInteger count = this.count;
+        putLock.lockInterruptibly();
+        try {
+            while (count.get() == capacity) {
+                notFull.await();
+            }
+            final boolean wasAdded = enqueue(e);
+            c = wasAdded?count.getAndIncrement():count.get();
+            if (c + 1 < capacity)
+                notFull.signal();
+        } finally {
+            putLock.unlock();
+        }
+        if (c == 0)
+            signalNotEmpty();
+    }
+
+    @Override
+    public boolean offer(E e, long timeout, TimeUnit unit) throws InterruptedException {
+        if (e == null) throw new NullPointerException();
+        long nanos = unit.toNanos(timeout);
+        int c = -1;
+        final ReentrantLock putLock = this.putLock;
+        final AtomicInteger count = this.count;
+        putLock.lockInterruptibly();
+        try {
+            while (count.get() == capacity) {
+
+                if (nanos <= 0)
+                    return false;
+                nanos = notFull.awaitNanos(nanos);
+            }
+            final boolean wasAdded = enqueue(e);
+            c = wasAdded?count.getAndIncrement():count.get();
+            if (c + 1 < capacity)
+                notFull.signal();
+        } finally {
+            putLock.unlock();
+        }
+        if (c == 0)
+            signalNotEmpty();
+        return true;
+    }
+
+    @Override
+    public E take() throws InterruptedException {
+        E x;
+        int c = -1;
+        final AtomicInteger count = this.count;
+        final ReentrantLock takeLock = this.takeLock;
+        takeLock.lockInterruptibly();
+        try {
+            while (count.get() == 0) {
+                notEmpty.await();
+            }
+            x = dequeue();
+            c = count.getAndDecrement();
+            if (c > 1)
+                notEmpty.signal();
+        } finally {
+            takeLock.unlock();
+        }
+        if (c == capacity)
+            signalNotFull();
+        return x;
+    }
+
+    @Override
+    public E poll(long timeout, TimeUnit unit) throws InterruptedException {
+        E x = null;
+        int c = -1;
+        long nanos = unit.toNanos(timeout);
+        final AtomicInteger count = this.count;
+        final ReentrantLock takeLock = this.takeLock;
+        takeLock.lockInterruptibly();
+        try {
+            while (count.get() == 0) {
+                if (nanos <= 0)
+                    return null;
+                nanos = notEmpty.awaitNanos(nanos);
+            }
+            x = dequeue();
+            c = count.getAndDecrement();
+            if (c > 1)
+                notEmpty.signal();
+        } finally {
+            takeLock.unlock();
+        }
+        if (c == capacity)
+            signalNotFull();
+        return x;
+    }
+
+    @Override
+    public int remainingCapacity() {
+        return Integer.MAX_VALUE - size();
+    }
+
+    @Override
+    public int drainTo(Collection<? super E> c) {
+        return drainTo(c,Integer.MAX_VALUE);
+    }
+
+    @Override
+    public int drainTo(Collection<? super E> c, int maxElements) {
+        if (c == null)
+            throw new NullPointerException();
+        if (c == this)
+            throw new IllegalArgumentException();
+        boolean signalNotFull = false;
+        final ReentrantLock takeLock = this.takeLock;
+        takeLock.lock();
+        try {
+            int n = Math.min(maxElements, count.get());
+            Iterator<E> it = delegate.iterator();
+            for(int i=0; i<n && it.hasNext(); i++) {
+                E x = it.next();
+                c.add(x);
+            }
+            count.getAndAdd(-n);
+            return n;
+        } finally {
+            takeLock.unlock();
+            if (signalNotFull)
+                signalNotFull();
+        }
+    }
+
+    @Override
+    public E poll() {
+        final AtomicInteger count = this.count;
+        if (count.get() == 0)
+            return null;
+        E x = null;
+        int c = -1;
+        final ReentrantLock takeLock = this.takeLock;
+        takeLock.lock();
+        try {
+            if (count.get() > 0) {
+                x = dequeue();
+                c = count.getAndDecrement();
+                if (c > 1)
+                    notEmpty.signal();
+            }
+        } finally {
+            takeLock.unlock();
+        }
+        if (c == capacity)
+            signalNotFull();
+        return x;
+    }
+
+
+    @Override
+    public E peek() {
+        if (count.get() == 0)
+            return null;
+        final ReentrantLock takeLock = this.takeLock;
+        takeLock.lock();
+        try {
+            Iterator<E> it = delegate.iterator();
+            if(it.hasNext()) {
+                return it.next();
+            } else {
+                return null;
+            }
+        } finally {
+            takeLock.unlock();
+        }
+    }
+
+
+    /**
+     * Creates a node and links it at end of queue.
+     * @param x the item
+     * @return <code>true</code> if this set did not already contain <code>x</code>
+     */
+    private boolean enqueue(E x) {
+        synchronized (delegate) {
+            return delegate.add(x);
+        }
+    }
+
+    /**
+     * Removes a node from head of queue.
+     * @return the node
+     */
+    private E dequeue() {
+        synchronized (delegate) {
+            Iterator<E> it = delegate.iterator();
+            E x = it.next();
+            it.remove();
+            return x;
+        }
+    }
+
+
+
+    /**
+     * Lock to prevent both puts and takes.
+     */
+    void fullyLock() {
+        putLock.lock();
+        takeLock.lock();
+    }
+
+    /**
+     * Unlock to allow both puts and takes.
+     */
+    void fullyUnlock() {
+        takeLock.unlock();
+        putLock.unlock();
+    }
+
+    /**
+     * Signals a waiting take. Called only from put/offer (which do not
+     * otherwise ordinarily lock takeLock.)
+     */
+    private void signalNotEmpty() {
+        final ReentrantLock takeLock = this.takeLock;
+        takeLock.lock();
+        try {
+            notEmpty.signal();
+        } finally {
+            takeLock.unlock();
+        }
+    }
+
+    /**
+     * Signals a waiting put. Called only from take/poll.
+     */
+    private void signalNotFull() {
+        final ReentrantLock putLock = this.putLock;
+        putLock.lock();
+        try {
+            notFull.signal();
+        } finally {
+            putLock.unlock();
+        }
+    }
+
+    /**
+     * Tells whether both locks are held by current thread.
+     */
+    boolean isFullyLocked() {
+        return (putLock.isHeldByCurrentThread() &&
+                takeLock.isHeldByCurrentThread());
+    }
+
+    @Override
+    public Iterator<E> iterator() {
+        final Iterator<E> it = delegate.iterator();
+        return new Iterator<E>() {
+            @Override
+            public boolean hasNext() {
+                fullyLock();
+                try {
+                    return it.hasNext();
+                } finally {
+                    fullyUnlock();
+                }
+            }
+
+            @Override
+            public E next() {
+                fullyLock();
+                try {
+                    return it.next();
+                } finally {
+                    fullyUnlock();
+                }
+            }
+
+            @Override
+            public void remove() {
+                fullyLock();
+                try {
+                    it.remove();
+                } finally {
+                    fullyUnlock();
+                }
+            }
+        };
+    }
+
+    @Override
+    public int size() {
+        return count.get();
+    }
+
+    @Override
+    public boolean remove(Object o) {
+        if (o == null) return false;
+
+        fullyLock();
+        try {
+            if(delegate.remove(o)) {
+                if(count.getAndDecrement() == capacity) {
+                    notFull.signal();
+                }
+                return true;
+            }
+        } finally {
+            fullyUnlock();
+        }
+
+        return false;
+    }
+
+    @Override
+    public void clear() {
+        fullyLock();
+        try {
+            delegate.clear();
+        } finally {
+            fullyUnlock();
+        }
+    }
+
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/c32963d5/lmf-core/src/main/java/kiwi/core/util/ReflectionUtils.java
----------------------------------------------------------------------
diff --git a/lmf-core/src/main/java/kiwi/core/util/ReflectionUtils.java b/lmf-core/src/main/java/kiwi/core/util/ReflectionUtils.java
new file mode 100644
index 0000000..a804ea6
--- /dev/null
+++ b/lmf-core/src/main/java/kiwi/core/util/ReflectionUtils.java
@@ -0,0 +1,160 @@
+/**
+ * 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.lang.annotation.Annotation;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+/**
+ * Utilities for working with reflection
+ * 
+ * @author Sergio Fernández
+ *
+ */
+public class ReflectionUtils {
+
+    /**
+     * Get the actual class
+     * 
+     * @param obj target object
+     * @return actual class
+     */
+    public static Class<?> getClass(Object obj) {
+        Class<?> cls = obj.getClass();
+        while (isProxied(cls)) {
+            cls = cls.getSuperclass();
+        }
+        return cls;
+    }
+
+    /**
+     * Check is the class is proxies
+     * 
+     * @param cls class
+     * @return proxied
+     */
+    public static boolean isProxied(Class<?> cls) {
+        return cls.getName().contains("$$EnhancerByCGLIB$$") ||
+                cls.getName().contains("$$FastClassByCGLIB$$") ||
+                cls.getName().contains("_$$_javassist") ||
+                cls.getName().contains("_$$_WeldSubclass") ||
+                cls.getName().contains("$Proxy$");
+    }
+
+    /**
+     * Retrieve the value of the annotation
+     * 
+     * @param obj target object
+     * @param annotation target annotation
+     * @param field annotation field
+     * @return value (null if object not annotated)
+     * @throws NoSuchMethodException
+     * @throws InvocationTargetException
+     * @throws IllegalAccessException
+     * @throws IllegalArgumentException
+     */
+    public static Object getAnnotationValue(Object obj, Class<? extends Annotation> annotation, String field) throws IllegalArgumentException,
+    IllegalAccessException, InvocationTargetException, NoSuchMethodException {
+        Class<?> cls = getClass(obj);
+        if (cls.isAnnotationPresent(annotation))
+            return invokeMethod(cls.getAnnotation(annotation), field);
+        else
+            return null;
+    }
+
+    /**
+     * Get the method based on its name
+     * 
+     * @param cls target class
+     * @param method method name
+     * @param params parameters
+     * @return method
+     * @throws NoSuchMethodException
+     */
+    public static Method getMethod(Class<?> cls, String method, Object[] params) throws NoSuchMethodException {
+        Class<?>[] classes = new Class[params.length];
+        for (int i = 0; i < params.length; i++) {
+            classes[i] = params[i].getClass();
+        }
+        return cls.getMethod(method, classes);
+    }
+
+    /**
+     * Invoke the method without parameters over the target object
+     * 
+     * @param obj target object
+     * @param method method name
+     * @return value returned by the method invocation
+     * @throws IllegalArgumentException
+     * @throws IllegalAccessException
+     * @throws InvocationTargetException
+     * @throws NoSuchMethodException
+     */
+    public static Object invokeMethod(Object obj, String method) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException,
+    NoSuchMethodException {
+        return invokeMethod(obj, method, new Object[0]);
+    }
+
+    /**
+     * Invoke the method over the target object
+     * 
+     * @param obj target object
+     * @param method method name
+     * @param params parameters
+     * @return value returned by the method invocation
+     * @throws IllegalArgumentException
+     * @throws IllegalAccessException
+     * @throws InvocationTargetException
+     * @throws NoSuchMethodException
+     */
+    public static Object invokeMethod(Object obj, String method, Object[] params) throws IllegalArgumentException, IllegalAccessException,
+    InvocationTargetException, NoSuchMethodException {
+        return invokeMethod(obj, getMethod(getClass(obj), method, params), params);
+    }
+
+    /**
+     * Invoke the method without parameters over the target object
+     * 
+     * @param obj target object
+     * @param method method
+     * @return value returned by the method invocation
+     * @throws IllegalArgumentException
+     * @throws IllegalAccessException
+     * @throws InvocationTargetException
+     */
+    public static Object invokeMethod(Object obj, Method method) throws IllegalArgumentException, IllegalAccessException,
+    InvocationTargetException {
+        return invokeMethod(obj, method, new Object[0]);
+    }
+
+    /**
+     * Invoke the method over the target object
+     * 
+     * @param obj target object
+     * @param method method
+     * @param params parameters
+     * @return value returned by the method invocation
+     * @throws IllegalArgumentException
+     * @throws IllegalAccessException
+     * @throws InvocationTargetException
+     */
+    public static Object invokeMethod(Object obj, Method method, Object[] params) throws IllegalArgumentException, IllegalAccessException,
+    InvocationTargetException {
+        return method.invoke(obj, params);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/c32963d5/lmf-core/src/main/java/kiwi/core/util/WebServiceUtil.java
----------------------------------------------------------------------
diff --git a/lmf-core/src/main/java/kiwi/core/util/WebServiceUtil.java b/lmf-core/src/main/java/kiwi/core/util/WebServiceUtil.java
new file mode 100644
index 0000000..f576e59
--- /dev/null
+++ b/lmf-core/src/main/java/kiwi/core/util/WebServiceUtil.java
@@ -0,0 +1,77 @@
+/**
+ * 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 org.codehaus.jackson.map.ObjectMapper;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Utility methods for web services
+ * <p/>
+ * Author: Sebastian Schaffert
+ */
+public class WebServiceUtil {
+
+
+    /**
+     * Create a JSON representation of an exception, to be returned to the client. The JSON object will be formatted
+     * as follows:
+     * <code>
+     * {
+     *     type: 'JAVA CLASS NAME',
+     *     message: 'EXCEPTION MESSAGE'
+     * }
+     * </code>
+     */
+    public static String jsonErrorResponse(Exception ex) {
+        Map<String,Object> result = new HashMap<String, Object>();
+        result.put("type",ex.getClass().getSimpleName());
+        result.put("message",ex.getMessage());
+
+        ObjectMapper mapper = new ObjectMapper();
+        try {
+            return mapper.writeValueAsString(result);
+        } catch (IOException e) {
+            // cannot occur, we write to a string
+            return null;
+        }
+
+    }
+
+    /**
+     * Create a JSON representation of an exception, to be returned to the client. The JSON object will be formatted
+     * as follows:
+     * <code>
+     * {
+     *     type: 'JAVA CLASS NAME',
+     *     message: 'EXCEPTION MESSAGE'
+     * }
+     * </code>
+     */
+    public static void jsonErrorResponse(Exception ex, OutputStream out) throws IOException {
+        Map<String,Object> result = new HashMap<String, Object>();
+        result.put("type",ex.getClass().getSimpleName());
+        result.put("message",ex.getMessage());
+
+        ObjectMapper mapper = new ObjectMapper();
+        mapper.writeValue(out,result);
+
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/c32963d5/lmf-core/src/main/java/kiwi/core/util/http/HttpRequestUtil.java
----------------------------------------------------------------------
diff --git a/lmf-core/src/main/java/kiwi/core/util/http/HttpRequestUtil.java b/lmf-core/src/main/java/kiwi/core/util/http/HttpRequestUtil.java
new file mode 100644
index 0000000..cbf8b9a
--- /dev/null
+++ b/lmf-core/src/main/java/kiwi/core/util/http/HttpRequestUtil.java
@@ -0,0 +1,91 @@
+/**
+ * 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.http;
+
+import kiwi.core.api.http.HttpClientService;
+import org.apache.http.HttpHeaders;
+import org.apache.http.client.cache.HeaderConstants;
+import org.apache.http.client.methods.HttpRequestBase;
+import org.apache.http.client.params.ClientPNames;
+import org.apache.http.params.CoreProtocolPNames;
+
+/**
+ * Utility methods, to be used in conjunction with {@link HttpClientService}.
+ * 
+ */
+public class HttpRequestUtil {
+
+    private HttpRequestUtil() {
+        // static util class;
+    }
+
+    /**
+     * Configure whether redirects for this request should be handled automatically.
+     * 
+     * @param request the request to modify
+     * @param followRedirect <code>true</code> if redirects (HTTP response code 3xx) should be
+     *            handled automatically.
+     */
+    public static void setFollowRedirect(HttpRequestBase request, boolean followRedirect) {
+        request.getParams().setBooleanParameter(ClientPNames.HANDLE_REDIRECTS, followRedirect);
+    }
+
+    /**
+     * Set the <i>local part</i> of the User-Agent Header String. It will be suffixed with the
+     * global part of the User-Agent, which is handled by the corresponding
+     * {@link HttpClientService} implementation.
+     * 
+     * @param request the request to modify
+     * @param userAgentString the prefix of the User-Agent string which will be suffixed with a
+     *            LMF-global part handled b< the {@link HttpClientService} implementation.
+     */
+    public static void setUserAgentString(HttpRequestBase request, String userAgentString) {
+        request.getParams().setParameter(CoreProtocolPNames.USER_AGENT, userAgentString);
+    }
+
+    /**
+     * Set the <code>Cache-Control</code>-header for the provided request.
+     * 
+     * @param request the request to modify
+     * @param cacheControl the cache-control directive
+     * 
+     * @see HeaderConstants#CACHE_CONTROL_NO_CACHE
+     * @see HeaderConstants#CACHE_CONTROL_NO_STORE
+     * @see HeaderConstants#CACHE_CONTROL_MAX_AGE
+     * @see HeaderConstants#CACHE_CONTROL_MAX_STALE
+     * @see HeaderConstants#CACHE_CONTROL_MUST_REVALIDATE
+     * @see <a
+     *      href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9">RFC2616#Cache-Control</a>
+     * 
+     */
+    public static void setCacheControl(HttpRequestBase request, String cacheControl) {
+        if (cacheControl != null) {
+            request.setHeader(HttpHeaders.CACHE_CONTROL, cacheControl);
+        } else {
+            request.removeHeaders(HttpHeaders.CACHE_CONTROL);
+        }
+    }
+
+    /**
+     * Set the <code>Cache-Control</code>-header for the provided request to <code>no-cache</code>.
+     * 
+     * @param request the request to modify
+     */
+    public static void setCacheControl_NoCache(HttpRequestBase request) {
+        setCacheControl(request, HeaderConstants.CACHE_CONTROL_NO_CACHE);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/c32963d5/lmf-core/src/main/java/kiwi/core/webservices/CoreApplication.java
----------------------------------------------------------------------
diff --git a/lmf-core/src/main/java/kiwi/core/webservices/CoreApplication.java b/lmf-core/src/main/java/kiwi/core/webservices/CoreApplication.java
new file mode 100644
index 0000000..ab93362
--- /dev/null
+++ b/lmf-core/src/main/java/kiwi/core/webservices/CoreApplication.java
@@ -0,0 +1,106 @@
+/**
+ * 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.webservices;
+
+import org.apache.commons.configuration.Configuration;
+import org.apache.commons.configuration.ConfigurationException;
+import org.apache.commons.configuration.PropertiesConfiguration;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.ws.rs.core.Application;
+import java.io.IOException;
+import java.net.URL;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * CoreApplication
+ *
+ * TODO: manage this by reading kiwi-module.properties file in each of the KiWi modules and looking for a property
+ * "webservices"
+ *
+ * @author Sebastian Schaffert
+ *
+ */
+public class CoreApplication extends Application {
+
+    private Logger log = LoggerFactory.getLogger(CoreApplication.class);
+
+
+    private static Set<Class<?>> classes = null;
+
+    /**
+     * 
+     */
+    public CoreApplication() {
+        super();
+    }
+
+    /* (non-Javadoc)
+     * @see javax.ws.rs.core.Application#getClasses()
+     */
+    @Override
+    public synchronized Set<Class<?>> getClasses() {
+
+
+        if(classes == null) {
+            classes = new HashSet<Class<?>>();
+
+            try {
+                Enumeration<URL> modulePropertiesEnum = this.getClass().getClassLoader().getResources("kiwi-module.properties");
+
+                while(modulePropertiesEnum.hasMoreElements()) {
+                    URL moduleUrl = modulePropertiesEnum.nextElement();
+
+                    Configuration moduleProperties = null;
+                    try {
+                        moduleProperties = new PropertiesConfiguration(moduleUrl);
+
+                        for(Object clsName : moduleProperties.getList("webservices")) {
+
+                            if(!"".equals(clsName)) {
+                                try {
+                                    Class<?> cls = Class.forName(clsName.toString());
+
+                                    classes.add(cls);
+
+                                    log.debug("module {}: registered webservice {}", moduleProperties.getString("name"), cls.getCanonicalName());
+                                } catch (ClassNotFoundException e) {
+                                    log.error("could not load class {}, it was not found",clsName.toString());
+                                }
+                            }
+                        }
+
+                    } catch (ConfigurationException e) {
+                        log.error("configuration exception: {}",e.getMessage());
+                    }
+
+                }
+
+
+            } catch (IOException e) {
+                log.error("I/O error while trying to load kiwi-module.properties file: {}",e.getMessage());
+            }
+        }
+
+        return classes;
+    }
+
+
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/c32963d5/lmf-core/src/main/java/kiwi/core/webservices/config/ConfigurationWebService.java
----------------------------------------------------------------------
diff --git a/lmf-core/src/main/java/kiwi/core/webservices/config/ConfigurationWebService.java b/lmf-core/src/main/java/kiwi/core/webservices/config/ConfigurationWebService.java
new file mode 100644
index 0000000..e5f0146
--- /dev/null
+++ b/lmf-core/src/main/java/kiwi/core/webservices/config/ConfigurationWebService.java
@@ -0,0 +1,238 @@
+/**
+ * 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.webservices.config;
+
+import kiwi.core.api.config.ConfigurationService;
+import org.codehaus.jackson.JsonParseException;
+import org.codehaus.jackson.map.JsonMappingException;
+import org.codehaus.jackson.map.ObjectMapper;
+import org.codehaus.jackson.type.TypeReference;
+import org.slf4j.Logger;
+
+import javax.enterprise.context.ApplicationScoped;
+import javax.inject.Inject;
+import javax.servlet.http.HttpServletRequest;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.Response;
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ *  Manage the system configuration of the LMF Server. Provides methods for displaying and updating the configuration
+ *  values.
+ */
+@ApplicationScoped
+@Path("/config")
+public class ConfigurationWebService {
+
+    @Inject
+    private ConfigurationService configurationService;
+
+    @Inject
+    private Logger log;
+
+    /**
+     * Retrieve all entries in the system configuration as key-value pairs.
+     *
+     *
+     * @return a map mapping all configuration keys to the respective string or list values
+     * @HTTP 200 when the list of settings is retrieved successfully
+     */
+    @GET
+    @Path("/list")
+    @Produces("application/json")
+    public Map<String,Map<String,Object>> listConfiguration(@QueryParam("prefix")String prefix) {
+        HashMap<String,Map<String,Object>> result = new HashMap<String,Map<String,Object>>();
+        if(prefix==null) {
+            for(String key : configurationService.listConfigurationKeys()) {
+                Map<String,Object> config = new HashMap<String, Object>();
+                config.put("value",configurationService.getConfiguration(key));
+                config.put("comment",configurationService.getComment(key));
+                config.put("type",configurationService.getType(key));
+                result.put(key, config);
+            }
+        } else {
+            for(String key : configurationService.listConfigurationKeys(prefix)) {
+                Map<String,Object> config = new HashMap<String, Object>();
+                config.put("value",configurationService.getConfiguration(key));
+                config.put("comment",configurationService.getComment(key));
+                config.put("type",configurationService.getType(key));
+                result.put(key, config);
+            }
+        }
+        return result;
+    }
+
+    /**
+     * stores a list of configuration
+     * @HTTP 200 if the configuration was set
+     * @HTTP 400 if the input sent in the body could not be parsed
+     * @param request
+     * @return HTTP 200 or 400
+     */
+    @POST
+    @Path("/list")
+    @Produces("application/json")
+    public Response setListConfiguration(@Context HttpServletRequest request) {
+        ObjectMapper mapper = new ObjectMapper();
+        try {
+            //log.info(getContentData(request.getReader()));
+            Map<String,String> values = mapper.readValue(request.getInputStream(), new TypeReference<HashMap<String,String>>(){});
+            configurationService.setConfigurations(values);
+        } catch (IOException e) {
+            return Response.serverError().build();
+        }
+        return Response.ok().build();
+    }
+
+    /**
+     * Return the string or list value for the configuration key passed as argument.
+     *
+     * @param key the configuration key for which to return the value
+     * @return the value of the requested configuration
+     * @HTTP 200 if the configuration key exists
+     * @HTTP 404 if the configuration key does not exist
+     */
+    @GET
+    @Path("/data/{key}")
+    @Produces("application/json")
+    public Response getConfiguration(@PathParam("key") String key) {
+        Object value = configurationService.getConfiguration(key);
+        if(value != null) {
+            HashMap<String,Object> result = new HashMap<String,Object>();
+            result.put(key, value);
+            return Response.status(200).entity(result).build();
+        } else
+            return Response.status(404).build();
+    }
+
+    /**
+     * Return the description for the configuration key passed as argument.
+     *
+     * @param key the configuration key for which to return the value
+     * @return the description of the requested configuration
+     * @HTTP 200 if the configuration key exists
+     * @HTTP 404 if the configuration key does not exist
+     */
+    @GET
+    @Path("/comment/{key}")
+    @Produces("application/json")
+    public Response getConfigurationComment(@PathParam("key") String key) {
+        String value = configurationService.getComment(key);
+        if(value != null) return Response.status(200).entity(Collections.singletonList(value)).build();
+        else
+            return Response.status(404).build();
+    }
+
+
+    /**
+     * Return the data type for the configuration key passed as argument.
+     *
+     * @param key the configuration key for which to return the value
+     * @return the data type of the requested configuration
+     * @HTTP 200 if the configuration key exists
+     * @HTTP 404 if the configuration key does not exist
+     */
+    @GET
+    @Path("/type/{key}")
+    @Produces("application/json")
+    public Response getConfigurationType(@PathParam("key") String key) {
+        String value = configurationService.getType(key);
+        if(value != null) return Response.status(200).entity(Collections.singletonList(value)).build();
+        else
+            return Response.status(404).build();
+    }
+
+    /**
+     * Set the configuration with the key passed in the path argument. The input has to be a
+     * JSON list of String values sent in the body of the request
+     *
+     * @param key the configuration key to set
+     * @param request the request body as JSON list
+     * @return OK if the value was set correctly, ERROR if parsing failed
+     * @HTTP 200 if the configuration was set
+     * @HTTP 400 if the input sent in the body could not be parsed
+     */
+    @POST
+    @Path("/data/{key}")
+    @Consumes("application/json")
+    public Response setConfiguration(@PathParam("key") String key, @QueryParam("type") String type, @QueryParam("comment") String comment, @Context HttpServletRequest request) {
+        try {
+            //log.info(getContentData(request.getReader()));
+            ObjectMapper mapper = new ObjectMapper();
+            List<String> values = mapper.readValue(request.getInputStream(), new TypeReference<ArrayList<String>>(){});
+            configurationService.setConfiguration(key,values);
+            if(type!=null) configurationService.setType(key,type);
+            if(comment!=null) configurationService.setComment(key,comment);
+            return Response.status(200).build();
+        } catch (JsonMappingException e) {
+            log.error("cannot parse input into json",e);
+        } catch (JsonParseException e) {
+            log.error("cannot parse input into json",e);
+        } catch (IOException e) {
+            log.error("cannot parse input into json",e);
+        }
+        return Response.status(400).build(); // bad request
+    }
+
+    /**
+     * Delete the configuration with the key passed in the path argument.
+     * @param key the configuration to remove
+     * @return 200 (OK) if the configuration was removed successfully, 500 (server error) otherwise
+     * @HTTP 200 if the configuration was removed successfully
+     * @HTTP 500 if there was an error while removing the configuration
+     */
+    @DELETE
+    @Path("/data/{key}")
+    public Response deleteConfiguration(@PathParam("key") String key) {
+        if(configurationService.getConfiguration(key) != null) {
+            try {
+                configurationService.removeConfiguration(key);
+                return Response.status(200).build();
+            } catch (Exception e) {
+                log.error("cannot delete configuration",e);
+                return Response.status(500).build();
+            }
+        } else
+            return Response.status(404).build();
+    }
+
+    public String getContent(BufferedReader r) {
+        String s;StringBuffer b = new StringBuffer();
+        try {
+            while((s = r.readLine()) != null) {
+                b.append(s);
+            }
+        } catch (IOException e) {
+            e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
+        }
+        return b.toString();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/c32963d5/lmf-core/src/main/java/kiwi/core/webservices/config/DependenciesWebService.java
----------------------------------------------------------------------
diff --git a/lmf-core/src/main/java/kiwi/core/webservices/config/DependenciesWebService.java b/lmf-core/src/main/java/kiwi/core/webservices/config/DependenciesWebService.java
new file mode 100644
index 0000000..21c3d5a
--- /dev/null
+++ b/lmf-core/src/main/java/kiwi/core/webservices/config/DependenciesWebService.java
@@ -0,0 +1,62 @@
+/**
+ * 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.webservices.config;
+
+import kiwi.core.api.config.DependenciesService;
+
+import javax.enterprise.context.ApplicationScoped;
+import javax.inject.Inject;
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Exposes details about the current core dependencies
+ * 
+ * @author Sergio Fernández
+ */
+@ApplicationScoped
+@Path("/dependencies")
+public class DependenciesWebService {
+
+    @Inject
+    private DependenciesService dependenciesService;
+
+    @GET
+    @Path("/")
+    @Produces("application/json")
+    public List<Map<String, String>> getArtifacs() {
+        return dependenciesService.getArtifacs();
+    }
+
+    @GET
+    @Path("/{groupId: [a-z]+(\\.[a-z]+)*}")
+    @Produces("application/json")
+    public List<Map<String, String>> getArtifacs(@PathParam("groupId") String groupId) {
+        return dependenciesService.getArtifacs(groupId);
+    }
+
+    @GET
+    @Path("/{groupId: [a-z]+(\\.[a-z]+)*}/{artifactId: [a-z]+(\\.[a-z]+)*}")
+    @Produces("application/json")
+    public String getVersion(@PathParam("groupId") String groupId, @PathParam("artifactId") String artifactId) {
+        return dependenciesService.getVersion(groupId, artifactId);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/c32963d5/lmf-core/src/main/java/kiwi/core/webservices/io/ExportWebService.java
----------------------------------------------------------------------
diff --git a/lmf-core/src/main/java/kiwi/core/webservices/io/ExportWebService.java b/lmf-core/src/main/java/kiwi/core/webservices/io/ExportWebService.java
new file mode 100644
index 0000000..5587a33
--- /dev/null
+++ b/lmf-core/src/main/java/kiwi/core/webservices/io/ExportWebService.java
@@ -0,0 +1,169 @@
+/**
+ * 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.webservices.io;
+
+import static at.newmedialab.sesame.commons.repository.ExceptionUtils.handleRepositoryException;
+
+import at.newmedialab.sesame.commons.repository.ResourceUtils;
+import at.newmedialab.sesame.commons.util.DateUtils;
+import kiwi.core.api.exporter.ExportService;
+import kiwi.core.api.triplestore.SesameService;
+import kiwi.core.exception.io.UnsupportedExporterException;
+import org.apache.marmotta.commons.http.ContentType;
+import org.apache.marmotta.commons.http.LMFHttpUtils;
+import org.openrdf.model.URI;
+import org.openrdf.repository.RepositoryConnection;
+import org.openrdf.repository.RepositoryException;
+import org.openrdf.rio.RDFFormat;
+import org.slf4j.Logger;
+
+import javax.enterprise.context.ApplicationScoped;
+import javax.inject.Inject;
+import javax.ws.rs.*;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.StreamingOutput;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * A web service for exporting data from the LMF triple store
+ * <p/>
+ * Author: Sebastian Schaffert
+ */
+@ApplicationScoped
+@Path("/export")
+public class ExportWebService {
+
+    @Inject
+    private Logger log;
+
+    @Inject
+    private ExportService exportService;
+
+    @Inject
+    private SesameService sesameService;
+
+    /**
+     * Return a set of all mime types that are acceptable by the importer.
+     * @return a set of all mime types that are acceptable by the importer.
+     */
+    @GET
+    @Path("/types")
+    @Produces("application/json")
+    public List<String> getTypes() {
+        ArrayList<String> result = new ArrayList<String>(exportService.getProducedTypes());
+        Collections.sort(result);
+
+        return result;
+    }
+
+    /**
+     * Download the triple data contained in the (optional) context (named graph) in the format specified by the Accept
+     * header of the request. If the context parameter is not given, all triples contained in this LMF installation will
+     * be written to the response.
+     *
+     * @param types          list of MIME types the client accepts
+     * @param context_string URI of the named graph to export; if null, all named graphs will be exported
+     * @param qFormat        MIME type for return format, overrides accept header
+     * @return the HTTP response
+     * @throws IOException   in case writing to the output stream of the connection fails
+     *
+     * @HTTP 200 in case the triples were written to the output stream correctly
+     * @HTTP 404 in case the context passed as argument could not be found
+     * @HTTP 406 in case the LMF could not find any matching serializer for the MIME types in the Accept header
+     */
+    @GET
+    @Path("/download")
+    public Response downloadData(@HeaderParam("Accept") String types, @QueryParam("format") String qFormat, @QueryParam("context") String context_string) throws IOException {
+        List<ContentType> acceptedTypes;
+        if(qFormat != null) {
+            acceptedTypes = LMFHttpUtils.parseAcceptHeader(qFormat);
+        } else {
+            acceptedTypes = LMFHttpUtils.parseAcceptHeader(types);
+        }
+        List<ContentType> offeredTypes  = LMFHttpUtils.parseStringList(exportService.getProducedTypes());
+
+        final ContentType bestType = LMFHttpUtils.bestContentType(offeredTypes,acceptedTypes);
+
+        // create a file name for the export, preferrably with a good extension ...
+        String fileName;
+        if(context_string != null) {
+            String[] components = context_string.split("/");
+            fileName = components[components.length-1] + "-export-" + DateUtils.FILENAME_FORMAT.format(new Date());
+        } else {
+            fileName = "lmf-export-" + DateUtils.FILENAME_FORMAT.format(new Date());
+        }
+
+        if(bestType != null) {
+            RDFFormat format = RDFFormat.forMIMEType(bestType.getMime());
+            if(format != null) {
+                fileName += "." + format.getDefaultFileExtension();
+            }
+
+            URI context = null;
+            if(context_string != null) {
+                try {
+                    RepositoryConnection conn = sesameService.getConnection();
+                    try {
+                        conn.begin();
+                        context = ResourceUtils.getUriResource(conn,context_string);
+                    } finally {
+                        conn.commit();
+                        conn.close();
+                    }
+                } catch (RepositoryException e) {
+                    handleRepositoryException(e,ExportWebService.class);
+                }
+
+                if(context == null) return Response.status(Response.Status.NOT_FOUND).entity("the context given as argument could not be found").build();
+
+            } else {
+                context = null;
+            }
+            final URI fcontext = context;
+
+            StreamingOutput entity = new StreamingOutput() {
+                @Override
+                public void write(OutputStream output) throws IOException, WebApplicationException {
+                    try {
+                        //FIXME: html should not be exported, but rendered?
+                        exportService.exportData(output,fcontext,bestType.getMime());
+                    } catch (UnsupportedExporterException e) {
+                        throw new WebApplicationException(e, Response.Status.NOT_ACCEPTABLE);
+                    }
+                }
+            };
+
+            return Response
+                    .status(Response.Status.OK)
+                    .header("Content-Type", bestType.getMime())
+                    .header("Content-Disposition", "attachment; filename=\""+fileName+"\"")
+                    .entity(entity)
+                    .build();
+
+        } else
+            return Response.status(406)
+                    .header("Content-Type", exportService.getProducedTypes())
+                    .entity("could not find matching type for " + acceptedTypes + "; see Content-Type header for possible types")
+                    .build();
+
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/c32963d5/lmf-core/src/main/java/kiwi/core/webservices/io/ImportWebService.java
----------------------------------------------------------------------
diff --git a/lmf-core/src/main/java/kiwi/core/webservices/io/ImportWebService.java b/lmf-core/src/main/java/kiwi/core/webservices/io/ImportWebService.java
new file mode 100644
index 0000000..98fb93b
--- /dev/null
+++ b/lmf-core/src/main/java/kiwi/core/webservices/io/ImportWebService.java
@@ -0,0 +1,310 @@
+/**
+ * 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.webservices.io;
+
+import kiwi.core.api.importer.ImportService;
+import kiwi.core.api.task.Task;
+import kiwi.core.api.task.TaskInfo;
+import kiwi.core.api.task.TaskManagerService;
+import kiwi.core.api.triplestore.ContextService;
+import kiwi.core.api.user.UserService;
+import kiwi.core.exception.io.LMFImportException;
+import org.openrdf.model.URI;
+import org.openrdf.rio.RDFFormat;
+import org.openrdf.rio.Rio;
+import org.slf4j.Logger;
+
+import javax.enterprise.context.ApplicationScoped;
+import javax.inject.Inject;
+import javax.servlet.http.HttpServletRequest;
+import javax.ws.rs.*;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.Response;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.UnsupportedEncodingException;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLConnection;
+import java.net.URLDecoder;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * A webservice offering functionality to import data from the KiWi knowledge base.
+ * <p/>
+ * User: sschaffe
+ */
+@ApplicationScoped
+@Path("/import")
+public class ImportWebService {
+
+    @Inject
+    private Logger log;
+
+    @Inject
+    private ImportService importService;
+
+    @Inject
+    private ContextService contextService;
+
+    @Inject
+    private TaskManagerService taskManagerService;
+
+    @Inject
+    private UserService userService;
+
+    private static final ThreadGroup IMPORTER_THREADS = new ThreadGroup("asynchronous imports");
+    private static final String TASK_GROUP_NAME = "Imports";
+
+    /**
+     * Return a set of all mime types that are acceptable by the importer.
+     * @return a set of all mime types that are acceptable by the importer.
+     */
+    @GET
+    @Path("/types")
+    @Produces("application/json")
+    public List<String> getTypes(@QueryParam("filename") String filename) {
+        if(filename == null)
+            return new ArrayList<String>(importService.getAcceptTypes());
+        else {
+            List<String> result = new ArrayList<String>();
+            RDFFormat format = Rio.getParserFormatForFileName(filename);
+            if(format != null) {
+                result.addAll(format.getMIMETypes());
+            }
+            return result;
+        }
+    }
+
+    /**
+     * Upload content and import it into the LMF system. The importer is selected based on the Content-Type header
+     * of the HTTP request. Calling the service spawns a separate asynchronous thread. Its status can be queried by
+     * calling the /status webservice.
+     *
+     * @param type the content type of the uploaded content
+     * @param request the request data of the uploaded file
+     * @return OK after starting a thread for importing the data, or error if the import cannot be started
+     * @HTTP 200 if the import was successfully started
+     * @HTTP 412 if the content-type header is not present or contains unsupported mime types
+     */
+    @POST
+    @Path("/upload")
+    public Response uploadData(@HeaderParam("Content-Type") String type, @Context HttpServletRequest request, @QueryParam("context") String context_string) throws IOException, LMFImportException {
+        if(type != null && type.lastIndexOf(';') >= 0) {
+            type = type.substring(0,type.lastIndexOf(';'));
+        }
+        if (type == null || !importService.getAcceptTypes().contains(type)) return Response.status(412).entity("define a valid content-type (types: "+importService.getAcceptTypes()+")").build();
+        final String finalType = type;
+        final InputStream in = request.getInputStream();
+
+        Task t = taskManagerService.createTask(String.format("Upload-Import from %s (%s)", request.getRemoteHost(), finalType), TASK_GROUP_NAME);
+        t.updateMessage("preparing import...");
+        t.updateDetailMessage("type", finalType);
+        try {
+            //create context
+            URI context = getContext(context_string);
+            if (context != null) {
+                t.updateDetailMessage("context", context.toString());
+            }
+
+            t.updateMessage("importing data...");
+            importService.importData(in,finalType, userService.getCurrentUser(), context);
+            t.updateMessage("import complete");
+
+            return Response.ok().entity("import of content successful\n").build();
+        } catch(Exception ex) {
+            log.error("error while importing", ex);
+            return Response.status(500).entity("error while importing: " + ex.getMessage()).build();
+        } finally {
+            taskManagerService.endTask(t);
+        }
+    }
+
+    /**
+     * Fetch content from an external resource and import it into the LMF system. The importer is selected based on
+     * the Content-Type header of the HTTP request. Calling the service spawns a separate asynchronous thread. Its
+     * status can be queried by calling the /status webservice.
+     *
+     * @param type the content type of the uploaded content
+     * @param url an optional URL of a remote resource to import
+     * @return OK if the import was successfully started
+     * @HTTP 200 if the import was successfully started
+     * @HTTP 400 if the URL argument is not valid
+     * @HTTP 412 if the content-type header is not present or contains unsupported mime types
+     * @HTTP 502 if a connection to the URL of the external source cannot be established
+     */
+    @POST
+    @Path("/external")
+    public Response externalData(@HeaderParam("Content-Type") String type, @QueryParam("url") String url, @QueryParam("context") String context_string) throws IOException, LMFImportException {
+        try {
+            log.debug("Received 'external' request for {} with {}%n", type, url);
+            if(type != null && type.lastIndexOf(';') >= 0) {
+                type = type.substring(0,type.lastIndexOf(';'));
+            }
+            if(type==null || !importService.getAcceptTypes().contains(type)) return Response.status(412).entity("define a valid content-type (types: "+importService.getAcceptTypes()+")").build();
+            final URL finalUrl = new URL(url);
+            final URI context = getContext(context_string);
+
+            try {
+                URLConnection con = finalUrl.openConnection();
+                con.connect();
+            } catch(IOException ex) {
+                return Response.status(502).entity("the URL passed as argument cannot be retrieved").build();
+            }
+
+            final String finalType = type;
+            Runnable r = new Runnable() {
+
+                @Override
+                public void run() {
+                    Task task = taskManagerService.createTask("Import from external source", TASK_GROUP_NAME);
+                    task.updateDetailMessage("source", finalUrl.toExternalForm());
+                    task.updateDetailMessage("type", finalType);
+                    if (context != null) {
+                        task.updateDetailMessage("context", context.toString());
+                    }
+                    try {
+                        importService.importData(finalUrl,finalType,userService.getCurrentUser(),context);
+                    } catch(Exception e) {
+                        log.error("exception while asynchronously importing data",e);
+                    } finally {
+                        taskManagerService.endTask(task);
+                    }
+                }
+            };
+
+            Thread t = new Thread(IMPORTER_THREADS, r);
+            t.setName("Import(start:" + new Date() + ",url:" + url + ")");
+            t.setDaemon(true);
+            t.start();
+
+            return Response.ok().entity(String.format("{\"tname\":\"%s\"}", t.getName())).build();
+        } catch(MalformedURLException ex) {
+            return Response.status(400).entity("the URL passed as argument is not valid").build();
+        }
+    }
+
+    /**
+     * Stop the importer thread with the ID passed as query argument.
+     *
+     * @param tname the thread ID of the importer thread to stop
+     * @return OK if thread has been stopped or no longer exists
+     * @throws UnsupportedEncodingException
+     */
+    @DELETE
+    @Path("/cancel")
+    public Response stopArticleXMLImport(@QueryParam("tname")String tname) throws UnsupportedEncodingException {
+        tname = URLDecoder.decode(tname, "utf-8");
+        Thread[] threads = new Thread[IMPORTER_THREADS.activeCount()];
+        IMPORTER_THREADS.enumerate(threads);
+        for(Thread t : threads) {
+            if(t!=null&&t.getName().equals(tname)) {
+                //TODO
+                t.interrupt();
+                return Response.ok().build();
+            }
+        }
+        return Response.ok().entity("thread does not exist or is already stopped").build();
+    }
+
+    /**
+     * Get the status of the importer thread with the ID passed as query argument.
+     *
+     * @param tname the thread ID of the importer thread to query
+     * @return the status of the importer thread as a JSON object
+     * @throws UnsupportedEncodingException
+     */
+    @GET
+    @Path("/status")
+    @Produces("application/json")
+    public Status isActiveImport(@QueryParam("tname")String tname) throws UnsupportedEncodingException {
+        tname = URLDecoder.decode(tname,"utf-8");
+        Thread[] threads = new Thread[IMPORTER_THREADS.activeCount()];
+        IMPORTER_THREADS.enumerate(threads);
+        for(Thread t : threads) {
+            if(t!=null&&t.getName().equals(tname)) {
+                if(t.isAlive())
+                    return new Status(tname,true,"success","import is running");
+                else if(t.isInterrupted()) return new Status(tname,false,"error","import was not successful");
+                return new Status(tname,false,"success","import was successful");
+            }
+        }
+        return new Status(tname,false,"undefined","thread does not exist or is already stopped");
+    }
+
+    @GET
+    @Path("/list")
+    @Produces("application/json")
+    public List<TaskInfo> listRunningImport() throws UnsupportedEncodingException {
+        return taskManagerService.getTasksByGroup().get(TASK_GROUP_NAME);
+        // List<String> running = new LinkedList<String>();
+        // for (Task t : taskManagerService.listTasks(TASK_GROUP_NAME)) {
+        // running.add(String.format("[%d] %s (%s) %.2f%% ETA: %tF %<tT",
+        // t.getId(), t.getName(), t.getStatus(), 100 * t.getRelProgress(),
+        // t.getETA()));
+        // }
+        // return running;
+    }
+
+    private URI getContext(String context_string) {
+        if(context_string != null)
+            return contextService.createContext(context_string);
+        else
+            return contextService.getDefaultContext();
+    }
+
+    protected static class Status {
+        boolean isRunning;
+        String status;
+        String message;
+        String tname;
+
+        Status(String tname, boolean running, String status, String message) {
+            this.tname = tname;
+            isRunning = running;
+            this.message = message;
+            this.status = status;
+        }
+
+        public boolean isRunning() {
+            return isRunning;
+        }
+
+        public void setRunning(boolean running) {
+            isRunning = running;
+        }
+
+        public String getMessage() {
+            return message;
+        }
+
+        public void setMessage(String message) {
+            this.message = message;
+        }
+
+        public String getStatus() {
+            return status;
+        }
+
+        public void setStatus(String status) {
+            this.status = status;
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/c32963d5/lmf-core/src/main/java/kiwi/core/webservices/modules/ModuleWebService.java
----------------------------------------------------------------------
diff --git a/lmf-core/src/main/java/kiwi/core/webservices/modules/ModuleWebService.java b/lmf-core/src/main/java/kiwi/core/webservices/modules/ModuleWebService.java
new file mode 100644
index 0000000..110e185
--- /dev/null
+++ b/lmf-core/src/main/java/kiwi/core/webservices/modules/ModuleWebService.java
@@ -0,0 +1,137 @@
+/**
+ * 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.webservices.modules;
+
+import kiwi.core.api.modules.ModuleService;
+import kiwi.core.model.module.ModuleConfiguration;
+import org.apache.commons.configuration.Configuration;
+
+import javax.inject.Inject;
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import java.io.UnsupportedEncodingException;
+import java.net.URLDecoder;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Give information about modules registered in the system.
+ * <p/>
+ * User: sschaffe
+ */
+@Path("/modules")
+public class ModuleWebService {
+
+    @Inject
+    private ModuleService moduleService;
+
+
+    /**
+     * Return a list of names of the LMF modules that are currently enabled in the LMF installation.
+     *
+     * @return  a JSON list of strings
+     */
+    @Path("/list")
+    @GET
+    @Produces("application/json")
+    public Collection<String> listModules() {
+        return moduleService.listModules();
+    }
+
+
+    /**
+     * Return the configuration of the module identified by the name passed as query argument. The module will be
+     * a map containing the values specified in the kiwi-module.properties file of the module.
+     *
+     * @param moduleName the name of the module for which to return the configuration
+     * @return a map with key/value pairs representing the module configuration as contained in kiwi-module.properties
+     */
+    @Path("/module")
+    @GET
+    @Produces("application/json")
+    public Map<String,Object> getConfiguration(@QueryParam("name") String moduleName) {
+        Configuration cfg = null;
+        try {
+            cfg = moduleService.getModuleConfiguration(URLDecoder.decode(moduleName, "UTF-8")).getConfiguration();
+        } catch (UnsupportedEncodingException e) {
+            return null;
+        }
+        if(cfg != null) {
+            Map<String,Object> result = new HashMap<String, Object>();
+            for(Iterator<String> it = cfg.getKeys() ; it.hasNext(); ) {
+                String key = it.next();
+                result.put(key,cfg.getProperty(key));
+            }
+            return result;
+        } else
+            return null;
+    }
+
+    /**
+     * Return the configuration of the module identified by the name passed as query argument. The
+     * module will be
+     * a map containing the values specified in the kiwi-module.properties file of the module.
+     * 
+     * @return a map with key/value pairs representing the module configuration as contained in
+     *         kiwi-module.properties
+     */
+    @Path("/buildinfo")
+    @GET
+    @Produces("application/json")
+    public Map<String, Map<String, String>> getBuildInfo() {
+        HashMap<String, Map<String, String>> mods = new HashMap<String, Map<String, String>>();
+
+        for (String moduleName : moduleService.listModules()) {
+            Configuration cfg = moduleService.getModuleConfiguration(moduleName).getConfiguration();
+            if (cfg != null) {
+                ModuleConfiguration mCfg = new ModuleConfiguration(cfg);
+                if (mCfg.hasBuildInfo()) {
+                    Map<String, String> result = new LinkedHashMap<String, String>();
+
+                    result.put("id", mCfg.getModuleId());
+                    result.put("version", mCfg.getModuleVersion());
+                    result.put("timestamp", mCfg.getBuildTimestamp());
+                    result.put("revNumber", mCfg.getBuildRevisionNumber());
+                    result.put("revHash", mCfg.getBuildRevisionHash());
+                    result.put("user", mCfg.getBuildUser());
+                    result.put("host", mCfg.getBuildHost());
+                    result.put("os", mCfg.getBuildOS());
+
+                    final List<String> adminPages = moduleService.getAdminPages(moduleName);
+                    if (adminPages != null && adminPages.size() > 0 && adminPages.get(0).trim().length() > 0) {
+                        result.put("admin",
+                                moduleService.getModuleWeb(moduleName) +
+                                adminPages.get(0));
+                    }
+
+                    mods.put(moduleName, result);
+                } else {
+                    mods.put(moduleName, null);
+                }
+            } else {
+                mods.put(moduleName, null);
+            }
+        }
+        return mods;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/c32963d5/lmf-core/src/main/java/kiwi/core/webservices/prefix/PrefixWebService.java
----------------------------------------------------------------------
diff --git a/lmf-core/src/main/java/kiwi/core/webservices/prefix/PrefixWebService.java b/lmf-core/src/main/java/kiwi/core/webservices/prefix/PrefixWebService.java
new file mode 100644
index 0000000..d24672c
--- /dev/null
+++ b/lmf-core/src/main/java/kiwi/core/webservices/prefix/PrefixWebService.java
@@ -0,0 +1,132 @@
+/**
+ * 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.webservices.prefix;
+
+import kiwi.core.api.prefix.PrefixService;
+import org.apache.commons.lang.StringUtils;
+import org.slf4j.Logger;
+
+import javax.enterprise.context.ApplicationScoped;
+import javax.inject.Inject;
+import javax.validation.constraints.NotNull;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.Response;
+
+import java.net.URISyntaxException;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Prefix web service
+ * 
+ * @author Sergio Fernández
+ * 
+ */
+@ApplicationScoped
+@Path("/prefix")
+public class PrefixWebService {
+
+    @Inject
+    private Logger log;
+
+    @Inject
+    private PrefixService prefixService;
+
+    private static final String PREFIX_PATTERN = "{prefix: [a-z][a-zA-Z0-9]+}";
+
+    /**
+     * Get all prefixes mappings
+     * 
+     * @return all current prefixes mappings
+     */
+    @GET
+    @Produces("application/json")
+    public Response getMappings() {
+        Map<String, String> mappings = (prefixService != null ? prefixService.getMappings() : new HashMap<String,String>());
+        return Response.ok().entity(mappings).build();
+    }
+
+    /**
+     * Get namespace
+     * 
+     * @param prefix prefix
+     * @return Response with the mapping, if exists
+     */
+    @GET
+    @Path("/" + PREFIX_PATTERN)
+    @Produces("application/json")
+    public Response getMapping(@PathParam("prefix") String prefix) {
+        if (prefixService.containsPrefix(prefix)) {
+            Map<String, String> result = new HashMap<String, String>();
+            result.put(prefix, prefixService.getNamespace(prefix));
+            return Response.ok().entity(result).build();
+        } else {
+            log.error("prefix " + prefix + " mapping not found");
+            return Response.status(Response.Status.NOT_FOUND).entity("prefix " + prefix + " mapping not found").build();
+        }
+    }
+
+    /**
+     * Add new mapping
+     * 
+     * @param prefix prefix
+     * @param namespace uri
+     * @return operation result
+     */
+    @POST
+    @Path("/" + PREFIX_PATTERN)
+    public Response addMapping(@PathParam("prefix") String prefix, @QueryParam("uri") @NotNull String namespace) {
+        try {
+            prefixService.add(prefix, namespace);
+            return Response.status(Response.Status.CREATED).build();
+        } catch (URISyntaxException e) {
+            return Response.status(Response.Status.NOT_ACCEPTABLE).entity(e.getMessage()).build();
+        } catch (IllegalArgumentException e) {
+            return Response.status(Response.Status.CONFLICT).entity(e.getMessage()).build();
+        }
+    }
+
+    /**
+     * Reverse prefix lookup
+     * 
+     * @param uri namespace
+     * @return Response with the result of the reverse search
+     */
+    @GET
+    @Path("/reverse")
+    @Produces("application/json")
+    public Response getPrefix(@QueryParam("uri") @NotNull String uri) {
+        if (StringUtils.isNotBlank(uri)) {
+            if (prefixService.containsNamespace(uri)) {
+                Map<String, String> result = new HashMap<String, String>();
+                result.put(uri, prefixService.getPrefix(uri));
+                return Response.ok().entity(result).build();
+            } else {
+                log.error("namespace " + uri + " mapping not found");
+                return Response.status(Response.Status.NOT_FOUND).entity("namespace " + uri + " mapping not found").build();
+            }
+        } else {
+            log.error("Empty namespace requested");
+            return Response.status(Response.Status.BAD_REQUEST).build();
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/c32963d5/lmf-core/src/main/java/kiwi/core/webservices/resource/AnonResourceWebService.java
----------------------------------------------------------------------
diff --git a/lmf-core/src/main/java/kiwi/core/webservices/resource/AnonResourceWebService.java b/lmf-core/src/main/java/kiwi/core/webservices/resource/AnonResourceWebService.java
new file mode 100644
index 0000000..f5ad4cb
--- /dev/null
+++ b/lmf-core/src/main/java/kiwi/core/webservices/resource/AnonResourceWebService.java
@@ -0,0 +1,38 @@
+/**
+ * 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.webservices.resource;
+
+import javax.enterprise.context.ApplicationScoped;
+import javax.ws.rs.Path;
+
+import kiwi.core.api.config.ConfigurationService;
+
+/**
+ * The AnonResourceWebService offers functionality to work with resources, i.e. creation, updating, retrieval and
+ * deletion. The ids of anonymous resources created by the KiWi system always can be used to reach the resource via
+ * this webservice.
+ * <p>
+ * User: Thomas Kurz
+ * Date: 24.01.11
+ * Time: 12:32
+ */
+@ApplicationScoped
+@Path("/" + ConfigurationService.ANONYMOUS_PATH)
+public class AnonResourceWebService {
+
+	//TODO implement
+
+}