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
+
+}