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

[08/52] [partial] Reverting the erroneous merge by Sebastian according to the instructions in INFRA-6876

http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/582abb5b/platform/marmotta-core/src/main/java/org/apache/marmotta/platform/core/services/config/ConfigurationServiceImpl.java
----------------------------------------------------------------------
diff --git a/platform/marmotta-core/src/main/java/org/apache/marmotta/platform/core/services/config/ConfigurationServiceImpl.java b/platform/marmotta-core/src/main/java/org/apache/marmotta/platform/core/services/config/ConfigurationServiceImpl.java
index 02cdd81..9642b78 100644
--- a/platform/marmotta-core/src/main/java/org/apache/marmotta/platform/core/services/config/ConfigurationServiceImpl.java
+++ b/platform/marmotta-core/src/main/java/org/apache/marmotta/platform/core/services/config/ConfigurationServiceImpl.java
@@ -49,6 +49,7 @@ import org.apache.commons.configuration.Configuration;
 import org.apache.commons.configuration.ConfigurationException;
 import org.apache.commons.configuration.MapConfiguration;
 import org.apache.commons.configuration.PropertiesConfiguration;
+import org.apache.commons.lang3.ObjectUtils;
 import org.apache.marmotta.platform.core.api.config.ConfigurationService;
 import org.apache.marmotta.platform.core.events.ConfigurationChangedEvent;
 import org.apache.marmotta.platform.core.events.ConfigurationServiceInitEvent;
@@ -78,7 +79,7 @@ import com.google.common.io.Resources;
 @ApplicationScoped
 public class ConfigurationServiceImpl implements ConfigurationService {
 
-    private String home;
+	private String home;
 
     private static Logger log = LoggerFactory.getLogger(ConfigurationService.class);
 
@@ -180,16 +181,23 @@ public class ConfigurationServiceImpl implements ConfigurationService {
                     f1.mkdirs();
                 }
                 // ensure directory for user configuration files
-                File f2 = new File(getHome() + File.separator + "config");
+                File f2 = new File(getHome() + File.separator + DIR_CONFIG);
                 if(!f2.exists()) {
                     f2.mkdirs();
                 }
 
                 // ensure directory for logging messages
-                File f3 = new File(getHome() + File.separator + "log");
+                File f3 = new File(getHome() + File.separator + DIR_LOG);
                 if(!f3.exists()) {
                     f3.mkdirs();
                 }
+                
+                // ensure directory for importing data
+                File f4 = new File(getHome() + File.separator + DIR_IMPORT);
+                if(!f4.exists()) {
+                    f4.mkdirs();
+                }
+                
             }
 
             // the save configuration will be in the  home directory
@@ -307,14 +315,30 @@ public class ConfigurationServiceImpl implements ConfigurationService {
             log.info("Apache Marmotta Configuration Service: initialisation completed");
 
             configurationInitEvent.fire(new ConfigurationServiceInitEvent());
-
-            initialising = false;
+            
         } finally {
             lock.writeLock().unlock();
         }
 
     }
 
+    @Override
+    public boolean isInitialising() {
+        return initialising;
+    }
+
+    /**
+     * Signal that initialisation of the system has completed and configuration events are now enabled.
+     *
+     * @param initialising
+     */
+    @Override
+    public void setInitialising(boolean initialising) {
+        this.initialising = initialising;
+
+        log.info("Initialisation completed, enabling configuration events");
+    }
+
     /**
      * Initialise the Apache Marmotta Logging Configuration.
      * <ul>
@@ -570,16 +594,18 @@ public class ConfigurationServiceImpl implements ConfigurationService {
         Preconditions.checkNotNull(key);
         Preconditions.checkState(initialised,"ConfigurationService not yet initialised; call initialise() manually");
 
-        lock.writeLock().lock();
-        try {
-            config.setProperty(key, value);
-            save();
-        } finally {
-            lock.writeLock().unlock();
-        }
+        if(!config.containsKey(key) || !ObjectUtils.equals(value,config.getProperty(key))) {
+            lock.writeLock().lock();
+            try {
+                config.setProperty(key, value);
+                save();
+            } finally {
+                lock.writeLock().unlock();
+            }
 
-        if (!initialising) {
-            configurationEvent.fire(new ConfigurationChangedEvent(key));
+            if (!initialising) {
+                configurationEvent.fire(new ConfigurationChangedEvent(key));
+            }
         }
     }
 
@@ -703,16 +729,18 @@ public class ConfigurationServiceImpl implements ConfigurationService {
         Preconditions.checkNotNull(key);
         Preconditions.checkState(initialised,"ConfigurationService not yet initialised; call initialise() manually");
 
-        lock.writeLock().lock();
-        try {
-            config.setProperty(key, value);
-            save();
-        } finally {
-            lock.writeLock().unlock();
-        }
+        if(!config.containsKey(key) || !ObjectUtils.equals(value,config.getDouble(key))) {
+            lock.writeLock().lock();
+            try {
+                config.setProperty(key, value);
+                save();
+            } finally {
+                lock.writeLock().unlock();
+            }
 
-        if (!initialising) {
-            configurationEvent.fire(new ConfigurationChangedEvent(key));
+            if (!initialising) {
+                configurationEvent.fire(new ConfigurationChangedEvent(key));
+            }
         }
     }
 
@@ -752,16 +780,18 @@ public class ConfigurationServiceImpl implements ConfigurationService {
         Preconditions.checkNotNull(key);
         Preconditions.checkState(initialised,"ConfigurationService not yet initialised; call initialise() manually");
 
-        lock.writeLock().lock();
-        try {
-            config.setProperty(key, value);
-            save();
-        } finally {
-            lock.writeLock().unlock();
-        }
+        if(!config.containsKey(key) || !ObjectUtils.equals(value,config.getInt(key))) {
+            lock.writeLock().lock();
+            try {
+                config.setProperty(key, value);
+                save();
+            } finally {
+                lock.writeLock().unlock();
+            }
 
-        if (!initialising) {
-            configurationEvent.fire(new ConfigurationChangedEvent(key));
+            if (!initialising) {
+                configurationEvent.fire(new ConfigurationChangedEvent(key));
+            }
         }
     }
 
@@ -817,16 +847,18 @@ public class ConfigurationServiceImpl implements ConfigurationService {
         Preconditions.checkNotNull(key);
         Preconditions.checkState(initialised,"ConfigurationService not yet initialised; call initialise() manually");
 
-        lock.writeLock().lock();
-        try {
-            config.setProperty(key, value);
-            save();
-        } finally {
-            lock.writeLock().unlock();
-        }
+        if(!config.containsKey(key) || !ObjectUtils.equals(value,config.getLong(key))) {
+            lock.writeLock().lock();
+            try {
+                config.setProperty(key, value);
+                save();
+            } finally {
+                lock.writeLock().unlock();
+            }
 
-        if (!initialising) {
-            configurationEvent.fire(new ConfigurationChangedEvent(key));
+            if (!initialising) {
+                configurationEvent.fire(new ConfigurationChangedEvent(key));
+            }
         }
     }
 
@@ -868,17 +900,20 @@ public class ConfigurationServiceImpl implements ConfigurationService {
         Preconditions.checkNotNull(key);
         Preconditions.checkState(initialised,"ConfigurationService not yet initialised; call initialise() manually");
 
-        lock.writeLock().lock();
-        try {
-            config.setProperty(key, value);
-            save();
-        } finally {
-            lock.writeLock().unlock();
-        }
+        if(!config.containsKey(key) || value != config.getBoolean(key)) {
 
+            lock.writeLock().lock();
+            try {
+                config.setProperty(key, value);
+                save();
+            } finally {
+                lock.writeLock().unlock();
+            }
 
-        if (!initialising) {
-            configurationEvent.fire(new ConfigurationChangedEvent(key));
+
+            if (!initialising) {
+                configurationEvent.fire(new ConfigurationChangedEvent(key));
+            }
         }
     }
 
@@ -961,17 +996,19 @@ public class ConfigurationServiceImpl implements ConfigurationService {
         Preconditions.checkNotNull(key);
         Preconditions.checkState(initialised,"ConfigurationService not yet initialised; call initialise() manually");
 
-        lock.writeLock().lock();
-        try {
-            config.setProperty(key, value);
-            save();
-        } finally {
-            lock.writeLock().unlock();
-        }
+        if(!config.containsKey(key) || !ObjectUtils.equals(value,config.getList(key))) {
+            lock.writeLock().lock();
+            try {
+                config.setProperty(key, value);
+                save();
+            } finally {
+                lock.writeLock().unlock();
+            }
 
 
-        if (!initialising) {
-            configurationEvent.fire(new ConfigurationChangedEvent(key));
+            if (!initialising) {
+                configurationEvent.fire(new ConfigurationChangedEvent(key));
+            }
         }
     }
 
@@ -996,23 +1033,26 @@ public class ConfigurationServiceImpl implements ConfigurationService {
         Preconditions.checkNotNull(key);
         Preconditions.checkState(initialised,"ConfigurationService not yet initialised; call initialise() manually");
 
-        lock.writeLock().lock();
-        try {
-            if (config instanceof AbstractConfiguration) {
-                ((AbstractConfiguration) config).setDelimiterParsingDisabled(true);
-            }
-            config.setProperty(key, value);
-            if (config instanceof AbstractConfiguration) {
-                ((AbstractConfiguration) config).setDelimiterParsingDisabled(false);
+        if(!config.containsKey(key) || !ObjectUtils.equals(value,config.getString(key))) {
+
+            lock.writeLock().lock();
+            try {
+                if (config instanceof AbstractConfiguration) {
+                    ((AbstractConfiguration) config).setDelimiterParsingDisabled(true);
+                }
+                config.setProperty(key, value);
+                if (config instanceof AbstractConfiguration) {
+                    ((AbstractConfiguration) config).setDelimiterParsingDisabled(false);
+                }
+                save();
+            } finally {
+                lock.writeLock().unlock();
             }
-            save();
-        } finally {
-            lock.writeLock().unlock();
-        }
 
 
-        if (!initialising) {
-            configurationEvent.fire(new ConfigurationChangedEvent(key));
+            if (!initialising) {
+                configurationEvent.fire(new ConfigurationChangedEvent(key));
+            }
         }
     }
 
@@ -1077,17 +1117,19 @@ public class ConfigurationServiceImpl implements ConfigurationService {
         Preconditions.checkNotNull(key);
         Preconditions.checkState(initialised,"ConfigurationService not yet initialised; call initialise() manually");
 
-        lock.writeLock().lock();
-        try {
-            config.setProperty(key, values);
-            save();
-        } finally {
-            lock.writeLock().unlock();
-        }
+        if(!config.containsKey(key) || !ObjectUtils.equals(values,config.getList(key))) {
+            lock.writeLock().lock();
+            try {
+                config.setProperty(key, values);
+                save();
+            } finally {
+                lock.writeLock().unlock();
+            }
 
 
-        if (!initialising) {
-            configurationEvent.fire(new ConfigurationChangedEvent(key));
+            if (!initialising) {
+                configurationEvent.fire(new ConfigurationChangedEvent(key));
+            }
         }
     }
 

http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/582abb5b/platform/marmotta-core/src/main/java/org/apache/marmotta/platform/core/services/config/DependenciesServiceImpl.java
----------------------------------------------------------------------
diff --git a/platform/marmotta-core/src/main/java/org/apache/marmotta/platform/core/services/config/DependenciesServiceImpl.java b/platform/marmotta-core/src/main/java/org/apache/marmotta/platform/core/services/config/DependenciesServiceImpl.java
index 3a0cf94..d004676 100644
--- a/platform/marmotta-core/src/main/java/org/apache/marmotta/platform/core/services/config/DependenciesServiceImpl.java
+++ b/platform/marmotta-core/src/main/java/org/apache/marmotta/platform/core/services/config/DependenciesServiceImpl.java
@@ -18,7 +18,7 @@
 package org.apache.marmotta.platform.core.services.config;
 
 import org.apache.marmotta.platform.core.api.config.DependenciesService;
-import org.apache.commons.lang.StringUtils;
+import org.apache.commons.lang3.StringUtils;
 import org.slf4j.Logger;
 
 import javax.annotation.PostConstruct;

http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/582abb5b/platform/marmotta-core/src/main/java/org/apache/marmotta/platform/core/services/content/FileSystemContentReader.java
----------------------------------------------------------------------
diff --git a/platform/marmotta-core/src/main/java/org/apache/marmotta/platform/core/services/content/FileSystemContentReader.java b/platform/marmotta-core/src/main/java/org/apache/marmotta/platform/core/services/content/FileSystemContentReader.java
index d793a1a..3c2510e 100644
--- a/platform/marmotta-core/src/main/java/org/apache/marmotta/platform/core/services/content/FileSystemContentReader.java
+++ b/platform/marmotta-core/src/main/java/org/apache/marmotta/platform/core/services/content/FileSystemContentReader.java
@@ -134,6 +134,7 @@ public class FileSystemContentReader implements ContentReader {
         try {
             RepositoryConnection conn = sesameService.getConnection();
             try {
+                conn.begin();
                 MediaContentItem mci = FacadingFactory.createFacading(conn).createFacade(resource, MediaContentItem.class);
 
                 String path = mci.getContentPath();
@@ -187,6 +188,7 @@ public class FileSystemContentReader implements ContentReader {
         try {
             RepositoryConnection conn = sesameService.getConnection();
             try {
+                conn.begin();
                 MediaContentItem mci = FacadingFactory.createFacading(conn).createFacade(resource, MediaContentItem.class);
 
                 String path = mci.getContentPath();
@@ -229,6 +231,7 @@ public class FileSystemContentReader implements ContentReader {
         try {
             RepositoryConnection conn = sesameService.getConnection();
             try {
+                conn.begin();
                 MediaContentItem mci = FacadingFactory.createFacading(conn).createFacade(resource, MediaContentItem.class);
 
                 String path = mci.getContentPath();
@@ -285,6 +288,7 @@ public class FileSystemContentReader implements ContentReader {
         try {
             RepositoryConnection conn = sesameService.getConnection();
             try {
+                conn.begin();
                 MediaContentItem mci = FacadingFactory.createFacading(conn).createFacade(resource, MediaContentItem.class);
 
                 String path = mci.getContentPath();

http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/582abb5b/platform/marmotta-core/src/main/java/org/apache/marmotta/platform/core/services/content/FileSystemContentWriter.java
----------------------------------------------------------------------
diff --git a/platform/marmotta-core/src/main/java/org/apache/marmotta/platform/core/services/content/FileSystemContentWriter.java b/platform/marmotta-core/src/main/java/org/apache/marmotta/platform/core/services/content/FileSystemContentWriter.java
index 62935f8..d26f2cc 100644
--- a/platform/marmotta-core/src/main/java/org/apache/marmotta/platform/core/services/content/FileSystemContentWriter.java
+++ b/platform/marmotta-core/src/main/java/org/apache/marmotta/platform/core/services/content/FileSystemContentWriter.java
@@ -93,6 +93,7 @@ public class FileSystemContentWriter implements ContentWriter {
         try {
             RepositoryConnection conn = sesameService.getConnection();
             try {
+                conn.begin();
                 MediaContentItem mci = FacadingFactory.createFacading(conn).createFacade(resource, MediaContentItem.class);
 
                 String path = mci.getContentPath();
@@ -164,6 +165,7 @@ public class FileSystemContentWriter implements ContentWriter {
         try {
             RepositoryConnection conn = sesameService.getConnection();
             try {
+                conn.begin();
                 MediaContentItem mci = FacadingFactory.createFacading(conn).createFacade(resource, MediaContentItem.class);
 
                 String path = mci.getContentPath();

http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/582abb5b/platform/marmotta-core/src/main/java/org/apache/marmotta/platform/core/services/importer/ImportServiceImpl.java
----------------------------------------------------------------------
diff --git a/platform/marmotta-core/src/main/java/org/apache/marmotta/platform/core/services/importer/ImportServiceImpl.java b/platform/marmotta-core/src/main/java/org/apache/marmotta/platform/core/services/importer/ImportServiceImpl.java
index 5d088ce..2c95d3b 100644
--- a/platform/marmotta-core/src/main/java/org/apache/marmotta/platform/core/services/importer/ImportServiceImpl.java
+++ b/platform/marmotta-core/src/main/java/org/apache/marmotta/platform/core/services/importer/ImportServiceImpl.java
@@ -17,6 +17,7 @@
  */
 package org.apache.marmotta.platform.core.services.importer;
 
+import org.apache.commons.lang3.StringUtils;
 import org.apache.marmotta.platform.core.api.importer.ImportService;
 import org.apache.marmotta.platform.core.api.importer.Importer;
 import org.apache.marmotta.platform.core.exception.io.MarmottaImportException;
@@ -28,6 +29,7 @@ import javax.enterprise.context.ApplicationScoped;
 import javax.enterprise.inject.Any;
 import javax.enterprise.inject.Instance;
 import javax.inject.Inject;
+
 import java.io.InputStream;
 import java.io.Reader;
 import java.net.URL;
@@ -71,21 +73,39 @@ public class ImportServiceImpl implements ImportService{
 
 	@Override
 	public int importData(URL url, String format, Resource user, URI context) throws MarmottaImportException {
-		return getImporterInstance(format).importData(url,format,user,context);
+        long start = System.currentTimeMillis();
+		int result = getImporterInstance(format).importData(url,format,user,context);
+        long end = System.currentTimeMillis();
+        log.info("data import finished ({} ms}", end-start);
+        return result;
 	}
 
 	@Override
 	public int importData(InputStream is, String format, Resource user, URI context) throws MarmottaImportException {
-		return getImporterInstance(format).importData(is,format,user,context);
+        long start = System.currentTimeMillis();
+        int result = getImporterInstance(format).importData(is,format,user,context);
+        long end = System.currentTimeMillis();
+        log.info("data import finished ({} ms}", end-start);
+        return result;
 	}
 
 	@Override
 	public int importData(Reader reader, String format, Resource user, URI context) throws MarmottaImportException {
-		return getImporterInstance(format).importData(reader,format,user,context);
+        long start = System.currentTimeMillis();
+        int result = getImporterInstance(format).importData(reader,format,user,context);
+        long end = System.currentTimeMillis();
+        log.info("data import finished ({} ms}", end-start);
+        return result;
 	}
 
 	private Importer getImporterInstance(String type) throws MarmottaImportException {
-		if(!importerMap.containsKey(type)) throw new MarmottaImportException("no importer defined for type "+type);
+		if (StringUtils.contains(type, ';')) { 
+			type = type.split(";")[0];
+		}
+		if(!importerMap.containsKey(type)) { 
+			throw new MarmottaImportException("no importer defined for type " + type);
+		}
 		return importerMap.get(type);
 	}
+	
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/582abb5b/platform/marmotta-core/src/main/java/org/apache/marmotta/platform/core/services/importer/ImportWatchServiceImpl.java
----------------------------------------------------------------------
diff --git a/platform/marmotta-core/src/main/java/org/apache/marmotta/platform/core/services/importer/ImportWatchServiceImpl.java b/platform/marmotta-core/src/main/java/org/apache/marmotta/platform/core/services/importer/ImportWatchServiceImpl.java
new file mode 100644
index 0000000..06e9106
--- /dev/null
+++ b/platform/marmotta-core/src/main/java/org/apache/marmotta/platform/core/services/importer/ImportWatchServiceImpl.java
@@ -0,0 +1,265 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 org.apache.marmotta.platform.core.services.importer;
+
+import java.io.BufferedInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.net.URLDecoder;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.StandardWatchEventKinds;
+import java.nio.file.WatchEvent;
+import java.nio.file.WatchEvent.Kind;
+import java.nio.file.WatchKey;
+import java.nio.file.WatchService;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.enterprise.context.ApplicationScoped;
+import javax.enterprise.event.Observes;
+import javax.inject.Inject;
+
+import org.apache.commons.lang3.StringUtils;
+import org.apache.marmotta.platform.core.api.config.ConfigurationService;
+import org.apache.marmotta.platform.core.api.importer.ImportService;
+import org.apache.marmotta.platform.core.api.importer.ImportWatchService;
+import org.apache.marmotta.platform.core.api.task.Task;
+import org.apache.marmotta.platform.core.api.task.TaskManagerService;
+import org.apache.marmotta.platform.core.api.triplestore.ContextService;
+import org.apache.marmotta.platform.core.api.user.UserService;
+import org.apache.marmotta.platform.core.events.SystemStartupEvent;
+import org.apache.marmotta.platform.core.exception.io.MarmottaImportException;
+import org.openrdf.model.URI;
+import org.openrdf.rio.RDFFormat;
+import org.openrdf.rio.Rio;
+import org.slf4j.Logger;
+
+import com.ibm.icu.text.CharsetDetector;
+import com.ibm.icu.text.CharsetMatch;
+
+/**
+ * Implementation for watching import directory
+ * 
+ * @author Sergio Fernández
+ * 
+ */
+@ApplicationScoped
+public class ImportWatchServiceImpl implements ImportWatchService {
+
+	private static final String TASK_GROUP = "Import Watch";
+
+	private static final String TASK_DETAIL_PATH = "path";
+	
+	private static final String TASK_DETAIL_CONTEXT = "context";
+	
+	@Inject
+	private Logger log;
+
+	@Inject
+	private TaskManagerService taskManagerService;
+
+	@Inject
+	private ConfigurationService configurationService;
+
+	@Inject
+	private ImportService importService;
+
+	@Inject
+	private ContextService contextService;
+
+	@Inject
+	private UserService userService;
+	
+	private Map<WatchKey,Path> keys;
+
+	private String path;
+
+	private int count;
+
+	public ImportWatchServiceImpl() {
+		this.keys = new HashMap<WatchKey,Path>();
+		count = 0;
+	}
+
+	@Override
+	public void initialize(@Observes SystemStartupEvent event) {
+		this.path = configurationService.getHome() + File.separator + ConfigurationService.DIR_IMPORT;
+
+		Runnable r = new Runnable() {
+
+			@Override
+			public void run() {
+				final Task task = taskManagerService.createTask("Directory import watch", TASK_GROUP);
+				task.updateMessage("watching...");
+				task.updateDetailMessage(TASK_DETAIL_PATH, path);
+
+				try {
+					Path root = Paths.get(path);
+					WatchService watcher = root.getFileSystem().newWatchService();
+					register(root, watcher, StandardWatchEventKinds.ENTRY_CREATE, StandardWatchEventKinds.ENTRY_DELETE);
+					while (true) {
+						final WatchKey key = watcher.take();
+						for (WatchEvent<?> event : key.pollEvents()) {
+							
+							@SuppressWarnings("unchecked")
+							Path item = ((WatchEvent<Path>) event).context();
+							Path dir = keys.get(key);
+							File file = new File(dir.toString(), item.toString()).getAbsoluteFile();
+							
+							if (StandardWatchEventKinds.ENTRY_CREATE.equals(event.kind())) {
+								if (file.isDirectory()) {
+									//recursive registration of sub-directories
+									register(Paths.get(dir.toString(), item.toString()), watcher, StandardWatchEventKinds.ENTRY_CREATE, StandardWatchEventKinds.ENTRY_DELETE);
+									task.updateProgress(++count);
+								} else {
+									URI context = getTargetContext(file);
+									log.debug("Importing '{}'...", file.getAbsolutePath());
+									task.updateMessage("importing...");
+									task.updateDetailMessage(TASK_DETAIL_PATH, file.getAbsolutePath());
+									task.updateDetailMessage(TASK_DETAIL_CONTEXT, context.stringValue());
+									if (execImport(file, context)) {
+										log.info("Sucessfully imported file '{}' into {}", file.getAbsolutePath(), context.stringValue());
+										try {
+											//delete the imported file
+											log.debug("Deleting {}...", file.getAbsolutePath());
+											file.delete();
+										} catch (Exception ex) {
+											log.error("Error deleing {}: {}", file.getAbsolutePath(), ex.getMessage());
+										}
+									}
+									task.updateProgress(++count);
+									task.updateMessage("watching...");
+									task.updateDetailMessage(TASK_DETAIL_PATH, path);
+									task.removeDetailMessage(TASK_DETAIL_CONTEXT);
+								}
+							} else if (StandardWatchEventKinds.ENTRY_DELETE.equals(event.kind()) && Files.isDirectory(item)) {
+								//TODO: unregister deleted directories?
+								task.updateProgress(++count);
+							}
+							
+						}
+						if (!key.reset()) {
+							// exit loop if the key is not valid
+							// e.g. if the directory was deleted
+							break;
+						}
+					}
+				} catch (IOException e) {
+					log.error("Error registering the import watch service over '{}': {}", path, e.getMessage());
+				} catch (InterruptedException e) {
+					log.error("Import watch service has been interrupted");
+				}
+			}
+
+		};
+
+		Thread t = new Thread(r);
+		t.setName(TASK_GROUP + "(start:" + new Date() + ",path:" + this.path + ")");
+		t.setDaemon(true);
+		t.start();
+
+	}
+
+	@Override
+	public boolean execImport(File file, URI context) {
+		try {
+			String format = detectFormat(file);
+			FileInputStream is = new FileInputStream(file);
+			URI user = userService.getAdminUser();
+			importService.importData(is, format, user, context);
+			return true;
+		} catch (MarmottaImportException e) {
+			log.error("Error importing file {} from the local directory: {}", file.getAbsolutePath(), e.getMessage());
+			return false;
+		} catch (IOException e) {
+			log.error("Error retrieving file {} from the local directory: {}", file.getAbsolutePath(), e.getMessage());
+			return false;
+		}
+	}
+
+	private String detectFormat(File file) throws MarmottaImportException {
+		String format = null;
+		String fileName = file.getName();
+		
+		//mimetype detection
+		RDFFormat rdfFormat = Rio.getParserFormatForFileName(fileName);
+		if (rdfFormat != null && importService.getAcceptTypes().contains(rdfFormat.getDefaultMIMEType())) {
+			format = rdfFormat.getDefaultMIMEType();
+		} else {
+			throw new MarmottaImportException("Suitable RDF parser not found");
+		}
+
+	    //encoding detection
+		try {
+			BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file));
+			CharsetDetector cd = new CharsetDetector();
+			cd.setText(bis);
+			CharsetMatch cm = cd.detect();
+			if (cm != null) {
+				format += "; charset=" + cm.getName();
+			}
+		} catch (IOException e) {
+			log.error("Error detecting charset for '{}': {}", fileName, e.getMessage());
+		}
+
+		return format;
+	}
+	
+	/**
+	 * Get the target context, according the path relative to the base import directory
+	 * 
+	 * @param file
+	 * @return
+	 */
+	private URI getTargetContext(File file) {
+		String subdir = StringUtils.removeStart(file.getParentFile().getAbsolutePath(), this.path);
+		if (StringUtils.isBlank(subdir)) {
+			return contextService.getDefaultContext();
+		} else {
+			subdir = subdir.substring(1); //remove initial slash
+			if (StringUtils.startsWith(subdir, "http%3A%2F%2F")) {
+				try {
+					return contextService.createContext(URLDecoder.decode(subdir, "UTF-8"));
+				} catch (UnsupportedEncodingException e) {
+					log.error("Error url-decoding context name '{}', so using the default one: {}", subdir, e.getMessage());
+					return contextService.getDefaultContext();
+				}
+			} else {
+				return contextService.createContext(configurationService.getBaseContext() + subdir);
+			}
+		}
+	}
+	
+	/**
+	 * Registers a new path in the watcher, keeping the path mapping for future uses
+	 * 
+	 * @param path
+	 * @param watcher
+	 * @param events
+	 * @throws IOException
+	 */
+	private void register(Path path, WatchService watcher, Kind<?>... events) throws IOException {
+		keys.put(path.register(watcher, events), path);
+	}
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/582abb5b/platform/marmotta-core/src/main/java/org/apache/marmotta/platform/core/services/importer/rdf/RDFImporterImpl.java
----------------------------------------------------------------------
diff --git a/platform/marmotta-core/src/main/java/org/apache/marmotta/platform/core/services/importer/rdf/RDFImporterImpl.java b/platform/marmotta-core/src/main/java/org/apache/marmotta/platform/core/services/importer/rdf/RDFImporterImpl.java
index c51c49e..06d869a 100644
--- a/platform/marmotta-core/src/main/java/org/apache/marmotta/platform/core/services/importer/rdf/RDFImporterImpl.java
+++ b/platform/marmotta-core/src/main/java/org/apache/marmotta/platform/core/services/importer/rdf/RDFImporterImpl.java
@@ -62,7 +62,6 @@ public class RDFImporterImpl implements Importer {
     @Inject
     private Logger log;
 
-
     @Inject
     private ConfigurationService configurationService;
 
@@ -76,9 +75,6 @@ public class RDFImporterImpl implements Importer {
 
     private List<String> acceptTypes;
 
-
-
-
     /**
      * Get a collection of all mime types accepted by this io. Used for automatically
      * selecting the appropriate io in ImportService.

http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/582abb5b/platform/marmotta-core/src/main/java/org/apache/marmotta/platform/core/services/io/MarmottaIOServiceImpl.java
----------------------------------------------------------------------
diff --git a/platform/marmotta-core/src/main/java/org/apache/marmotta/platform/core/services/io/MarmottaIOServiceImpl.java b/platform/marmotta-core/src/main/java/org/apache/marmotta/platform/core/services/io/MarmottaIOServiceImpl.java
index f96de33..3c8d9b6 100644
--- a/platform/marmotta-core/src/main/java/org/apache/marmotta/platform/core/services/io/MarmottaIOServiceImpl.java
+++ b/platform/marmotta-core/src/main/java/org/apache/marmotta/platform/core/services/io/MarmottaIOServiceImpl.java
@@ -65,12 +65,8 @@ public class MarmottaIOServiceImpl implements MarmottaIOService {
             producedTypes.addAll(format.getMIMETypes());
         }
         log.info(" - available writers: {}", Arrays.toString(producedTypes.toArray()));
-
-
-
     }
 
-
 	/**
 	 * returns a list of all mimetypes which can be parsed by implemented parsers
 	 * @return
@@ -108,4 +104,5 @@ public class MarmottaIOServiceImpl implements MarmottaIOService {
 	public RDFFormat getParser(String mimetype) {
 		return parserRegistry.getFileFormatForMIMEType(mimetype);
 	}
+	
 }

http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/582abb5b/platform/marmotta-core/src/main/java/org/apache/marmotta/platform/core/services/jaxrs/ExceptionMapperServiceImpl.java
----------------------------------------------------------------------
diff --git a/platform/marmotta-core/src/main/java/org/apache/marmotta/platform/core/services/jaxrs/ExceptionMapperServiceImpl.java b/platform/marmotta-core/src/main/java/org/apache/marmotta/platform/core/services/jaxrs/ExceptionMapperServiceImpl.java
new file mode 100644
index 0000000..0b6e93b
--- /dev/null
+++ b/platform/marmotta-core/src/main/java/org/apache/marmotta/platform/core/services/jaxrs/ExceptionMapperServiceImpl.java
@@ -0,0 +1,73 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.marmotta.platform.core.services.jaxrs;
+
+import org.apache.marmotta.platform.core.api.jaxrs.ExceptionMapperService;
+import org.apache.marmotta.platform.core.events.SystemStartupEvent;
+import org.apache.marmotta.platform.core.jaxrs.CDIExceptionMapper;
+import org.jboss.resteasy.spi.ResteasyProviderFactory;
+import org.slf4j.Logger;
+
+import javax.annotation.PostConstruct;
+import javax.enterprise.context.ApplicationScoped;
+import javax.enterprise.event.Observes;
+import javax.enterprise.inject.Instance;
+import javax.inject.Inject;
+
+/**
+ * This service auto-registers JAX-RS exception mappers implementing the CDIExceptionMapper interface and
+ * registers them with RESTEasy. This allows applications based on Marmotta to easily implement and register their
+ * own ExceptionMapppers without needing to go into RESTEasy.
+ * <p/>
+ * Note that ExceptionMappers that are injected via CDI need to be annotated with @Dependent, or otherwise
+ * they will be proxied by the CDI implementation and then the generic type cannot be determined.
+ *
+ * @author Sebastian Schaffert (sschaffert@apache.org)
+ */
+@ApplicationScoped
+public class ExceptionMapperServiceImpl implements ExceptionMapperService {
+
+    @Inject
+    private Logger log;
+
+    @Inject
+    private Instance<CDIExceptionMapper<?>> mappers;
+
+    /**
+     * Register Exception Mappers
+     */
+    @PostConstruct
+    public void initialise() {
+        log.info("initialising JAX-RS exception mappers");
+
+        ResteasyProviderFactory factory = ResteasyProviderFactory.getInstance();
+
+        for(CDIExceptionMapper<?> mapper : mappers) {
+            log.debug("registering exception mapper: {}", mapper.getClass().getName());
+
+            factory.registerProviderInstance(mapper);
+        }
+    }
+
+    // trigger startup once configuration service is finished with initialisation
+    public void initEvent(@Observes SystemStartupEvent e) {
+
+    }
+
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/582abb5b/platform/marmotta-core/src/main/java/org/apache/marmotta/platform/core/services/modules/ModuleServiceImpl.java
----------------------------------------------------------------------
diff --git a/platform/marmotta-core/src/main/java/org/apache/marmotta/platform/core/services/modules/ModuleServiceImpl.java b/platform/marmotta-core/src/main/java/org/apache/marmotta/platform/core/services/modules/ModuleServiceImpl.java
index b7e4d63..c54ffa1 100644
--- a/platform/marmotta-core/src/main/java/org/apache/marmotta/platform/core/services/modules/ModuleServiceImpl.java
+++ b/platform/marmotta-core/src/main/java/org/apache/marmotta/platform/core/services/modules/ModuleServiceImpl.java
@@ -37,13 +37,7 @@ import java.net.JarURLConnection;
 import java.net.MalformedURLException;
 import java.net.URL;
 import java.net.URLConnection;
-import java.util.Collection;
-import java.util.Enumeration;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
+import java.util.*;
 
 /**
  * Add file description here!
@@ -53,16 +47,29 @@ import java.util.Set;
 @ApplicationScoped
 public class ModuleServiceImpl implements ModuleService {
 
+    private String default_container_name = "Others";
+
     private Logger log = LoggerFactory.getLogger(ModuleServiceImpl.class);
 
     private Set<String> modules;
 
+    private HashMap<String,ArrayList<String>> containers;
+
+    private HashMap<String,Integer> container_weight;
+
     private Map<String,Configuration> configurationMap;
     private Map<String, Configuration> jarURLs;
 
     @PostConstruct
     public void initialize() {
+
+        //default_container_name = configurationService.getStringConfiguration("kiwi.pages.default_container.name",default_container_name);
+        //default_container_number = configurationService.getIntConfiguration("kiwi.pages.default_container.number",default_container_number);
+
         modules = new HashSet<String>();
+        containers = new HashMap<String,ArrayList<String>>();
+        container_weight = new HashMap<String, Integer>();
+
         configurationMap = new HashMap<String, Configuration>();
         jarURLs = new HashMap<String, Configuration>();
 
@@ -83,6 +90,20 @@ public class ModuleServiceImpl implements ModuleService {
                     String moduleName = moduleProperties.getString("name");
                     modules.add(moduleName);
 
+                    String c_name = moduleProperties.getString("container") != null ? moduleProperties.getString("container") : default_container_name;
+
+                    if(containers.get(c_name) == null) {
+                        containers.put(c_name, new ArrayList<String>());
+                    }
+                    containers.get(c_name).add(moduleName);
+
+                    if(container_weight.get(c_name) == null ) {
+                        container_weight.put(c_name,-1);
+                    }
+
+                    if(moduleProperties.getString("container.weight") != null) {
+                        container_weight.put(c_name,Math.max(container_weight.get(c_name),moduleProperties.getInt("container.weight",-1)));
+                    }
 
                     URLConnection urlConnection = moduleUrl.openConnection();
                     URL jarUrl;
@@ -112,8 +133,6 @@ public class ModuleServiceImpl implements ModuleService {
                     } catch(ConfigurationException ex) {
                     }
 
-
-
                     // create runtime configuration
                     MapConfiguration runtimeConfiguration = new MapConfiguration(new HashMap<String, Object>());
                     runtimeConfiguration.setProperty("runtime.jarfile", jarUrl.toString());
@@ -130,6 +149,7 @@ public class ModuleServiceImpl implements ModuleService {
 
 
             }
+            //TODO container should be sortable
         } catch (IOException ex) {
             log.error("I/O error while trying to retrieve kiwi-module.properties file",ex);
         }
@@ -173,6 +193,7 @@ public class ModuleServiceImpl implements ModuleService {
      * @param moduleName
      * @return
      */
+    @Deprecated
     @Override
     public Collection<String> getEntities(String moduleName) {
         Configuration config = getModuleConfiguration(moduleName).getConfiguration();
@@ -191,6 +212,64 @@ public class ModuleServiceImpl implements ModuleService {
         return modules;
     }
 
+    public List<String> listSortedModules() {
+        return sortModules(modules);
+    }
+
+    /**
+     * returns all modules within a container
+     * @param container
+     * @return
+     */
+    public Collection<String> listModules(String container) {
+        if(containers.containsKey(container)) {
+            return containers.get(container);
+        } else return null;
+    }
+
+    @Override
+    public List<String> listSortedModules(String container) {
+        if(containers.containsKey(container)) {
+            return sortModules(containers.get(container));
+        } else return null;
+    }
+
+    /**
+     * sort modules
+     * @param m
+     * @return
+     */
+    private List<String> sortModules(Collection<String> m) {
+        List<String> sorted = new ArrayList<String>(m);
+        Collections.sort(sorted,new Comparator<String>() {
+            @Override
+            public int compare(String o, String o2) {
+                return ((Integer) getWeight(o)).compareTo(getWeight(o2));
+            }
+        });
+        return sorted;
+    }
+
+    /**
+     * Lists containers and underlying modules
+     * @return
+     */
+    public Collection<String> listContainers() {
+        return containers.keySet();
+    }
+
+    @Override
+    public List<String> listSortedContainers() {
+        List sorted = new ArrayList(containers.keySet());
+        Collections.sort(sorted,new Comparator<String>() {
+            @Override
+            public int compare(String o, String o2) {
+                return container_weight.get(o2).compareTo(container_weight.get(o));
+            }
+        });
+        return sorted;
+    }
+
     /**
      * Return the configuration for the module identified by the name given as argument. Returns an
      * immutable Apache Commons Configuration object, or null if the module is not found.
@@ -269,18 +348,73 @@ public class ModuleServiceImpl implements ModuleService {
     }
 
     /**
-     * Return a list of admin pages (paths)
+     * returns the icon (if set), null otherwise
      * @param moduleName
      * @return
      */
     @Override
-    public List<String> getAdminPages(String moduleName) {
+    public String getIcon(String moduleName) {
         Configuration config = getModuleConfiguration(moduleName).getConfiguration();
-        if(config != null) return ImmutableList.copyOf(config.getStringArray("adminpages"));
+        if(config != null) return config.getString("icon");
         else
             return null;
     }
 
+    /**
+     * Return a list of admin pages (links)
+     * @param moduleName
+     * @return
+     */
+    @Override
+    public List<String> getAdminPages(String moduleName) {
+        Configuration config = getModuleConfiguration(moduleName).getConfiguration();
+        if(config != null) {
+            if(!config.subset("adminpage.").isEmpty()) {
+                ArrayList<String> l = new ArrayList<String>();
+                while(config.getString("adminpage."+l.size()+".link") != null) {
+                    l.add(config.getString("adminpage."+l.size()+".link"));
+                }
+                return l;
+            } else return ImmutableList.copyOf(config.getStringArray("adminpages"));
+        } else
+            return null;
+    }
+
+    /**
+     * returns  more complex admin page description
+     * @param moduleName
+     * @return
+     */
+    @Override
+    public List<HashMap<String,String>> getAdminPageObjects(String moduleName) {
+        Configuration config = getModuleConfiguration(moduleName).getConfiguration();
+        if(config != null) {
+            ArrayList<HashMap<String,String>> l = new ArrayList<HashMap<String,String>>();
+            if(!config.subset("adminpage").isEmpty()) {
+                while(config.getString("adminpage."+l.size()+".link") != null) {
+                    HashMap<String,String> map = new HashMap<String, String>();
+                    map.put("link",config.getString("baseurl")+config.getString("adminpage."+l.size()+".link"));
+                    map.put("title",config.getString("adminpage."+l.size()+".title"));
+                    l.add(map);
+                }
+            } else {
+                for(String path : config.getStringArray("adminpages")) {
+                    HashMap<String,String> map = new HashMap<String, String>();
+                    map.put("link",config.getString("baseurl")+path);
+                    String title;
+                    if(path.lastIndexOf(".") > path.lastIndexOf("/")+1)
+                        title = path.substring(path.lastIndexOf("/")+1,path.lastIndexOf(".")).replaceAll("_"," ");
+                    else
+                        title = path.substring(path.lastIndexOf("/")+1);
+                    map.put("title",title);
+                    l.add(map);
+                }
+            }
+            return l;
+        } else
+            return null;
+    }
+
     @Override
     public int getWeight(String moduleName) {
         Configuration config = getModuleConfiguration(moduleName).getConfiguration();
@@ -290,4 +424,4 @@ public class ModuleServiceImpl implements ModuleService {
             return 50;
     }
 
-}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/582abb5b/platform/marmotta-core/src/main/java/org/apache/marmotta/platform/core/services/prefix/PrefixCC.java
----------------------------------------------------------------------
diff --git a/platform/marmotta-core/src/main/java/org/apache/marmotta/platform/core/services/prefix/PrefixCC.java b/platform/marmotta-core/src/main/java/org/apache/marmotta/platform/core/services/prefix/PrefixCC.java
index d80e055..b231800 100644
--- a/platform/marmotta-core/src/main/java/org/apache/marmotta/platform/core/services/prefix/PrefixCC.java
+++ b/platform/marmotta-core/src/main/java/org/apache/marmotta/platform/core/services/prefix/PrefixCC.java
@@ -18,31 +18,29 @@
 package org.apache.marmotta.platform.core.services.prefix;
 
 import java.io.IOException;
-import java.util.HashMap;
+import java.net.URLEncoder;
+import java.nio.charset.Charset;
 
 import javax.enterprise.context.ApplicationScoped;
 import javax.inject.Inject;
 
-import org.apache.http.Header;
+import org.apache.commons.io.IOUtils;
+import org.apache.commons.io.LineIterator;
 import org.apache.http.HttpEntity;
 import org.apache.http.HttpResponse;
 import org.apache.http.client.ClientProtocolException;
 import org.apache.http.client.ResponseHandler;
 import org.apache.http.client.methods.HttpGet;
-import org.apache.http.client.methods.HttpHead;
-import org.apache.http.util.EntityUtils;
 import org.apache.marmotta.platform.core.api.http.HttpClientService;
 import org.apache.marmotta.platform.core.api.prefix.PrefixProvider;
 import org.apache.marmotta.platform.core.util.http.HttpRequestUtil;
-import org.codehaus.jackson.JsonFactory;
-import org.codehaus.jackson.map.ObjectMapper;
-import org.codehaus.jackson.type.TypeReference;
 import org.slf4j.Logger;
 
 /**
  * Prefix.cc Provider
  * 
  * @author Sergio Fernández
+ * @author Jakob Frank <ja...@apache.org>
  *
  */
 @ApplicationScoped
@@ -59,9 +57,9 @@ public class PrefixCC implements PrefixProvider {
 
     @Override
     public String getNamespace(final String prefix) {
-        HttpGet get = new HttpGet(URI + prefix + ".file.json");
+        HttpGet get = new HttpGet(URI + prefix + ".file.txt");
         HttpRequestUtil.setUserAgentString(get, USER_AGENT);
-        get.setHeader("Accept", "application/json");
+        get.setHeader("Accept", "text/plain");
         try {
             return httpClientService.execute(get, new ResponseHandler<String>() {
 
@@ -69,20 +67,21 @@ public class PrefixCC implements PrefixProvider {
                 public String handleResponse(HttpResponse response) throws ClientProtocolException, IOException {
                     if (200 == response.getStatusLine().getStatusCode()) {
                         HttpEntity entity = response.getEntity();
-                        JsonFactory factory = new JsonFactory(); 
-                        ObjectMapper mapper = new ObjectMapper(factory); 
-                        TypeReference<HashMap<String,String>> typeRef = new TypeReference<HashMap<String,String>>() {}; 
-                        HashMap<String,String> result = mapper.readValue(EntityUtils.toString(entity), typeRef); 
-                        if (result.containsKey(prefix)) {
-                        	return result.get(prefix);
-                        } else {
-                        	log.error("Error: prefix '" + prefix + "' not found at prefix.cc");
-                            return null;
+
+                        final LineIterator it = IOUtils.lineIterator(entity.getContent(), Charset.defaultCharset());
+                        try {
+                            while (it.hasNext()) {
+                                final String l = it.next();
+                                if (l.startsWith(prefix + "\t")) {
+                                    return l.substring(prefix.length()+1);
+                                }
+                            }
+                        } finally {
+                            it.close();
                         }
-                    } else {
-                        log.error("Error: prefix '" + prefix + "' not found at prefix.cc");
-                        return null;
                     }
+                    log.error("Error: prefix '" + prefix + "' not found at prefix.cc");
+                    return null;
                 }
             });
         } catch (Exception e) {
@@ -93,20 +92,32 @@ public class PrefixCC implements PrefixProvider {
 
     @Override
     public String getPrefix(final String namespace) {
-        HttpHead head = new HttpHead(URI + "reverse?uri=" + namespace);
-        HttpRequestUtil.setFollowRedirect(head, false);
-        HttpRequestUtil.setUserAgentString(head, USER_AGENT);
         try {
-            return httpClientService.execute(head, new ResponseHandler<String>() {
+            HttpGet get = new HttpGet(URI + "reverse?format=txt&uri=" + URLEncoder.encode(namespace, "utf-8"));
+            HttpRequestUtil.setUserAgentString(get, USER_AGENT);
+            get.setHeader("Accept", "text/plain");
+
+            return httpClientService.execute(get, new ResponseHandler<String>() {
+
                 @Override
                 public String handleResponse(HttpResponse response) throws ClientProtocolException, IOException {
-                    if (response.containsHeader("location")) {
-                        Header location = response.getFirstHeader("location");
-                        return location.getValue().substring(URI.length());
-                    } else {
-                    	log.error("Error: reverse namespace lookup for '" + namespace + "' not found at prefix.cc");
-                        return null;
+                    if (200 == response.getStatusLine().getStatusCode()) {
+                        HttpEntity entity = response.getEntity();
+
+                        final LineIterator it = IOUtils.lineIterator(entity.getContent(), Charset.defaultCharset());
+                        try {
+                            while (it.hasNext()) {
+                                final String l = it.next();
+                                if (l.endsWith("\t" + namespace)) {
+                                    return l.substring(0, l.indexOf("\t"));
+                                }
+                            }
+                        } finally {
+                            it.close();
+                        }
                     }
+                    log.error("Error: reverse namespace lookup for '" + namespace + "' not found at prefix.cc");
+                    return null;
                 }
             });
         } catch (Exception e) {

http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/582abb5b/platform/marmotta-core/src/main/java/org/apache/marmotta/platform/core/services/prefix/PrefixServiceCC.java
----------------------------------------------------------------------
diff --git a/platform/marmotta-core/src/main/java/org/apache/marmotta/platform/core/services/prefix/PrefixServiceCC.java b/platform/marmotta-core/src/main/java/org/apache/marmotta/platform/core/services/prefix/PrefixServiceCC.java
index bc1d667..5442d60 100644
--- a/platform/marmotta-core/src/main/java/org/apache/marmotta/platform/core/services/prefix/PrefixServiceCC.java
+++ b/platform/marmotta-core/src/main/java/org/apache/marmotta/platform/core/services/prefix/PrefixServiceCC.java
@@ -20,7 +20,7 @@ package org.apache.marmotta.platform.core.services.prefix;
 import java.net.URISyntaxException;
 
 import org.apache.marmotta.platform.core.api.prefix.PrefixProvider;
-import org.apache.commons.lang.StringUtils;
+import org.apache.commons.lang3.StringUtils;
 
 import javax.enterprise.context.ApplicationScoped;
 import javax.enterprise.inject.Alternative;

http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/582abb5b/platform/marmotta-core/src/main/java/org/apache/marmotta/platform/core/services/prefix/PrefixServiceImpl.java
----------------------------------------------------------------------
diff --git a/platform/marmotta-core/src/main/java/org/apache/marmotta/platform/core/services/prefix/PrefixServiceImpl.java b/platform/marmotta-core/src/main/java/org/apache/marmotta/platform/core/services/prefix/PrefixServiceImpl.java
index ac136fe..b26afe3 100644
--- a/platform/marmotta-core/src/main/java/org/apache/marmotta/platform/core/services/prefix/PrefixServiceImpl.java
+++ b/platform/marmotta-core/src/main/java/org/apache/marmotta/platform/core/services/prefix/PrefixServiceImpl.java
@@ -29,7 +29,7 @@ import org.apache.marmotta.platform.core.api.config.ConfigurationService;
 import org.apache.marmotta.platform.core.api.prefix.PrefixService;
 import org.apache.marmotta.platform.core.events.ConfigurationChangedEvent;
 import org.apache.marmotta.platform.core.events.SesameStartupEvent;
-import org.apache.commons.lang.StringUtils;
+import org.apache.commons.lang3.StringUtils;
 import org.apache.marmotta.commons.http.UriUtil;
 import org.slf4j.Logger;
 
@@ -127,6 +127,17 @@ public class PrefixServiceImpl implements PrefixService {
     public Map<String, String> getMappings() {
         return Collections.unmodifiableMap(cache);
     }
+    
+	@Override
+	public boolean remove(String prefix) {
+		if (cache.containsKey(prefix)) {
+			cache.remove(prefix);
+			configurationService.removeConfiguration(CONFIGURATION_PREFIX + "." + prefix);
+			return true;
+		} else {
+			return false;
+		}
+	}
 
     @Override
     public boolean containsPrefix(String prefix) {

http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/582abb5b/platform/marmotta-core/src/main/java/org/apache/marmotta/platform/core/services/task/TaskImpl.java
----------------------------------------------------------------------
diff --git a/platform/marmotta-core/src/main/java/org/apache/marmotta/platform/core/services/task/TaskImpl.java b/platform/marmotta-core/src/main/java/org/apache/marmotta/platform/core/services/task/TaskImpl.java
index 56db715..f0ce2b5 100644
--- a/platform/marmotta-core/src/main/java/org/apache/marmotta/platform/core/services/task/TaskImpl.java
+++ b/platform/marmotta-core/src/main/java/org/apache/marmotta/platform/core/services/task/TaskImpl.java
@@ -20,7 +20,6 @@ package org.apache.marmotta.platform.core.services.task;
 import org.apache.marmotta.platform.core.api.task.Task;
 import org.apache.marmotta.platform.core.api.task.TaskManagerService;
 
-
 class TaskImpl extends Task {
 
     private static final String WAITING_DETAIL = "Waiting in status";
@@ -49,4 +48,5 @@ class TaskImpl extends Task {
     public void subTaskEnded() {
         updateMessage(detailMessages.remove(WAITING_DETAIL));
     }
+    
 }

http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/582abb5b/platform/marmotta-core/src/main/java/org/apache/marmotta/platform/core/services/task/TaskManagerServiceImpl.java
----------------------------------------------------------------------
diff --git a/platform/marmotta-core/src/main/java/org/apache/marmotta/platform/core/services/task/TaskManagerServiceImpl.java b/platform/marmotta-core/src/main/java/org/apache/marmotta/platform/core/services/task/TaskManagerServiceImpl.java
index 69d9d12..13d874c 100644
--- a/platform/marmotta-core/src/main/java/org/apache/marmotta/platform/core/services/task/TaskManagerServiceImpl.java
+++ b/platform/marmotta-core/src/main/java/org/apache/marmotta/platform/core/services/task/TaskManagerServiceImpl.java
@@ -17,17 +17,6 @@
  */
 package org.apache.marmotta.platform.core.services.task;
 
-import org.apache.marmotta.platform.core.api.task.Task;
-import org.apache.marmotta.platform.core.api.task.TaskInfo;
-import org.apache.marmotta.platform.core.api.task.TaskManagerService;
-
-import org.apache.marmotta.commons.util.HashUtils;
-import org.slf4j.Logger;
-
-import javax.annotation.PostConstruct;
-import javax.annotation.PreDestroy;
-import javax.enterprise.context.ApplicationScoped;
-import javax.inject.Inject;
 import java.lang.ref.WeakReference;
 import java.util.Collections;
 import java.util.Date;
@@ -37,23 +26,36 @@ import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
 import java.util.Stack;
-import java.util.WeakHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+import javax.annotation.PostConstruct;
+import javax.annotation.PreDestroy;
+import javax.enterprise.context.ApplicationScoped;
+import javax.inject.Inject;
+
+import org.apache.marmotta.commons.util.HashUtils;
+import org.apache.marmotta.platform.core.api.task.Task;
+import org.apache.marmotta.platform.core.api.task.TaskInfo;
+import org.apache.marmotta.platform.core.api.task.TaskManagerService;
+import org.slf4j.Logger;
+
+import com.google.common.collect.MapMaker;
 
 @ApplicationScoped
 public class TaskManagerServiceImpl implements TaskManagerService {
 
-    private static final String                        DEFAULT_GROUP = "default";
+    private static final String  DEFAULT_GROUP = "default";
 
-    private final WeakHashMap<Thread, Stack<TaskImpl>> tasks;
+    private final ConcurrentMap<Thread, Stack<TaskImpl>> tasks;
 
     private final ThreadWatchdog watchdog;
 
     @Inject
-    private Logger                                     log;
+    private Logger log;
 
     @Inject
     public TaskManagerServiceImpl() {
-        tasks = new WeakHashMap<Thread, Stack<TaskImpl>>();
+        tasks = new MapMaker().makeMap();
         watchdog = new ThreadWatchdog(15000);
     }
 

http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/582abb5b/platform/marmotta-core/src/main/java/org/apache/marmotta/platform/core/services/templating/AdminTemplatingServiceImpl.java
----------------------------------------------------------------------
diff --git a/platform/marmotta-core/src/main/java/org/apache/marmotta/platform/core/services/templating/AdminTemplatingServiceImpl.java b/platform/marmotta-core/src/main/java/org/apache/marmotta/platform/core/services/templating/AdminTemplatingServiceImpl.java
index 2a0279d..86c3d4e 100644
--- a/platform/marmotta-core/src/main/java/org/apache/marmotta/platform/core/services/templating/AdminTemplatingServiceImpl.java
+++ b/platform/marmotta-core/src/main/java/org/apache/marmotta/platform/core/services/templating/AdminTemplatingServiceImpl.java
@@ -38,6 +38,7 @@ import org.apache.marmotta.platform.core.api.templating.AdminInterfaceService;
 import org.apache.marmotta.platform.core.api.templating.TemplatingService;
 import org.apache.marmotta.platform.core.exception.TemplatingException;
 import org.apache.marmotta.platform.core.model.template.MenuItem;
+import org.apache.marmotta.platform.core.model.template.MenuItemType;
 
 /**
  * User: Thomas Kurz
@@ -53,7 +54,7 @@ public class AdminTemplatingServiceImpl implements AdminInterfaceService {
 
     @Inject
     private ModuleService moduleService;
-    
+
     @Inject
     private TemplatingService templatingService;
 
@@ -61,15 +62,11 @@ public class AdminTemplatingServiceImpl implements AdminInterfaceService {
     private ConfigurationService configurationService;
 
     //some statics
-    private static final String TEMPLATE_STRING = "admin.ftl";
-    private static final String DEFAULT_REST_PATH = "/doc/rest/";
-    private static final String DEFAULT_REST_FILE = "overview-summary.html";
-    private static final String DEFAULT_TITLE_FOR_WEBSERVICES = "webservices";
-
+    private static final String DEFAULT_ICON = "icon-beaker";
 
     //pattern to filter comments content
     private static final Pattern PATTERN = Pattern.compile("\\<!--###BEGIN_([^#]+)###--\\>(.+)\\<!--###END_\\1###--\\>",Pattern.DOTALL);
-    private Menu menu;
+    private MenuItem menu;
 
     /**
      * inits a freemarker template service with a servlet context
@@ -77,31 +74,17 @@ public class AdminTemplatingServiceImpl implements AdminInterfaceService {
      */
     @Override
     public void init(ServletContext context) throws TemplatingException {
-    	menu = new Menu();
+        menu = buildMenu();
         this.context = context;
         try {
-        	 //try-run to check it from the very beginning
-            templatingService.getTemplate(TEMPLATE_STRING);
+            //try-run to check it from the very beginning
+            templatingService.getTemplate(TemplatingService.ADMIN_TPL);
         } catch (Exception e) {
             throw new TemplatingException("Severe Error: admin template cannot be found: " + e.getMessage());
         }
     }
 
     /**
-     * Check whether the templating service considers the resource passed in the path as a menu entry it is
-     * responsible for.
-     *
-     * @param path a url path
-     * @return if the give path points to an admin page
-     */
-    @Override
-    public boolean isMenuEntry(String path) {
-        if(menu.path_titles.keySet().contains(configurationService.getPath()+path)) return true;
-        if(path.contains(DEFAULT_REST_PATH)) return true;
-        else return false;
-    }
-
-    /**
      * this method wraps a file with a specified admin template. If the file is not a admin page,
      * the bytes are returned unprocessed
      * @param bytes content represented in a byte array
@@ -113,21 +96,21 @@ public class AdminTemplatingServiceImpl implements AdminInterfaceService {
         if(!configurationService.getBooleanConfiguration("templating.cache.enabled",true) && context!=null) {
             init(context);
         }
-        //apply template
-        if(!isMenuEntry(path)) return bytes;
-        //activate
-        String module = menu.getCurrentModule(configurationService.getPath() + path);
+
+        //set active
+        menu.setActive(path);
+
         //fill data model
         Map<String, Object> datamodel = new HashMap<String,Object>();
-    	for(Properties p : Properties.values()) {
-    		datamodel.put(p.name(),"<!-- "+p.name()+" not defined -->");
-    	}
+        for(Properties p : Properties.values()) {
+            datamodel.put(p.name(),"<!-- "+p.name()+" not defined -->");
+        }
         //begin hack!!!
         datamodel.put("USER_MODULE_IS_ACTIVE", moduleService.listModules().contains("Users"));
         //end hack!!!
-        datamodel.put("MODULE_MENU",menu.menuItems);
-        datamodel.put("CURRENT_TITLE", getNameFromPath(path));
-        datamodel.put("CURRENT_MODULE", module);
+
+        //add menu
+        datamodel.put("MENU",menu.getProperties());
         try {
             String s = new String(bytes);
             Matcher m = PATTERN.matcher(s);
@@ -141,7 +124,7 @@ public class AdminTemplatingServiceImpl implements AdminInterfaceService {
         //make magic happen
         try {
             ByteArrayOutputStream bos = new ByteArrayOutputStream();
-        	templatingService.process(TEMPLATE_STRING, datamodel, new OutputStreamWriter(bos));
+            templatingService.process(TemplatingService.ADMIN_TPL, datamodel, new OutputStreamWriter(bos));
             bytes = bos.toByteArray();
             bos.flush();
             bos.close();
@@ -151,133 +134,49 @@ public class AdminTemplatingServiceImpl implements AdminInterfaceService {
         return bytes;
     }
 
+    @Override
+    public boolean isMenuEntry(String path) {
+        return menu.setActive(path);
+    }
+
     /**
-     * This object represents a menu for the admin interface. It is build using the ModuleService.
+     * build menu
+     * @return
      */
-    class Menu {
-
-        public List<MenuItem> menuItems;
-        public Map<String,String> path_titles;
-
-        public Menu() {
-            //instantiate
-            menuItems = new ArrayList<MenuItem>();
-            path_titles = new HashMap<String, String>();
-            //sort menu
-            ArrayList<String> menuSorted = new ArrayList<String>(moduleService.listModules());
-            if(configurationService.getBooleanConfiguration("templating.sort_by_weight", true)) {
-                Collections.sort(menuSorted, new Comparator<String>() {
-                    @Override
-                    public int compare(String o1, String o2) {
-                        final int w1 = moduleService.getWeight(o1), w2 = moduleService.getWeight(o2);
-                        if (w1 == w2) return o1.compareTo(o2);
-                        return w1 - w2;
-                    }
-                });
-            } else {
-                Collections.sort(menuSorted);
-            }
-
-            //build structure
-            for(String module : menuSorted) {
-                String path = configurationService.getPath() + moduleService.getModuleWeb(module);
-                if(moduleHasAdminPages(module)) {
-                    MenuItem menu_item = new MenuItem();
-                    menu_item.getProperties().put("title",module);
-                    menu_item.getProperties().put("baseurl",moduleService.getModuleConfiguration(module).getConfiguration().getString("baseurl","/"+module));
-                    for(String page : moduleService.getAdminPages(module)) {
-                        if(page.equals("")) {
-                            continue;
-                        }
-                        MenuItem submenu = new MenuItem();
-                        submenu.getProperties().put("title",getNameFromPath(page));
-                        submenu.getProperties().put("path",path+page);
-                        //test if it is active
-                        menu_item.getSubmenu().add(submenu);
-                        path_titles.put(path+page,page);
-                    }
-                    if(moduleService.getWebservices(module)!=null &&
-                            !moduleService.getWebservices(module).isEmpty() &&
-                            !moduleService.getWebservices(module).iterator().next().equals("")) {
-                        MenuItem submenu = new MenuItem();
-                        submenu.getProperties().put("title",DEFAULT_TITLE_FOR_WEBSERVICES);
-                        submenu.getProperties().put("path",path+DEFAULT_REST_PATH+DEFAULT_REST_FILE);
-                        //test if it is active
-                        menu_item.getSubmenu().add(submenu);
-                        path_titles.put(path+DEFAULT_REST_PATH+DEFAULT_REST_FILE,DEFAULT_TITLE_FOR_WEBSERVICES);
-                    }
-                    menuItems.add(menu_item);
+    private MenuItem buildMenu() {
+        MenuItem menu = new MenuItem("MENU", MenuItemType.ROOT);
+
+        for(String container_string : moduleService.listSortedContainers()) {
+            MenuItem container = new MenuItem(container_string, MenuItemType.CONTAINER);
+
+            //add modules
+            for(String module_string : moduleService.listSortedModules(container_string)) {
+                MenuItem module = new MenuItem(module_string, MenuItemType.MODULE);
+                module.set("path",moduleService.getModuleWeb(module_string));
+                if(moduleService.getIcon(module_string) != null)
+                    module.set("icon",moduleService.getIcon(module_string));
+
+                //add pages
+                for(HashMap<String,String> page_object : moduleService.getAdminPageObjects(module_string)) {
+                    MenuItem page = new MenuItem(page_object.get("title"), MenuItemType.PAGE);
+                    page.set("path",page_object.get("link"));
+                    module.addItem(page);
                 }
-            }
-        }
 
-        /**
-         * get current module and set submenu to active
-         * @param path the current system path
-         * @return current module name
-         */
-        public String getCurrentModule(String path) {
-            String module = "";
-            boolean active = false;
-            //test with module and submenu must be active
-            for(MenuItem menuItem : menuItems) {
-                if(path.startsWith((String)menuItem.getProperties().get("baseurl"))) {
-                    module = (String)menuItem.getProperties().get("title");
-                }
-                menuItem.getProperties().put("active",false);
-                for(MenuItem submenu : menuItem.getSubmenu()) {
-                    if(submenu.getProperties().get("path").equals(path)) {
-                        submenu.getProperties().put("active",true);
-                        menuItem.getProperties().put("active",true);
-                        module = (String)menuItem.getProperties().get("title");
-                        active = true;
-                    } else {
-                        submenu.getProperties().put("active",false);
-                    }
-                }
-            }
-            //workaround for webservices (autogenerated pages that are nit fix stored in the menu structure)
-            if(!active) {
-                for(MenuItem menuItem : menuItems) {
-                    if(module.equals(menuItem.getProperties().get("title"))) {
-                        for(MenuItem submenu : menuItem.getSubmenu()) {
-                            if(submenu.getProperties().get("title").equals(DEFAULT_TITLE_FOR_WEBSERVICES)) {
-                                submenu.getProperties().put("active",true);
-                                menuItem.getProperties().put("active",true);
-                            }
-                        }
-                    }
+                //add webservice
+                if(!moduleService.getWebservices(module_string).isEmpty()) {
+                    MenuItem page = new MenuItem(TemplatingService.DEFAULT_WEBSERVICE_TITLE, MenuItemType.WEBSERVICE);
+                    page.set("path",module.get("path")+TemplatingService.DEFAULT_REST_PATH+TemplatingService.DEFAULT_REST_FILE);
+                    module.addItem(page);
                 }
-            }
-            return module;
-        }
 
-        /**
-         * Tests if a module should appear in the menu
-         * @param module a module name
-         * @return true is module should appear, false if not
-         */
-        private boolean moduleHasAdminPages(String module) {
-            if(moduleService.getAdminPages(module)!=null &&
-                    !moduleService.getAdminPages(module).isEmpty() &&
-                    !moduleService.getAdminPages(module).get(0).equals(""))
-                return true;
-            else if(moduleService.getWebservices(module)!=null &&
-                    !moduleService.getWebservices(module).isEmpty() &&
-                    !moduleService.getWebservices(module).iterator().next().equals("")) return true;
-            return false;
+                //add if there are pages to display
+                if(!module.isEmpty()) container.addItem(module);
+            }
+            menu.addItem(container);
         }
 
+        return menu;
     }
 
-    /**
-     * returns a proper name for a path by using the filename.
-     * @param path
-     * @return
-     */
-    private String getNameFromPath(String path) {
-        if(path.contains(DEFAULT_REST_PATH)) return DEFAULT_TITLE_FOR_WEBSERVICES;
-        return path.substring(path.lastIndexOf("/")).replaceAll("/"," ").replaceAll("_"," ").replaceAll(".html","").replaceAll(".jsp","");
-    }
-
-}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/582abb5b/platform/marmotta-core/src/main/java/org/apache/marmotta/platform/core/services/templating/TemplatingServiceImpl.java
----------------------------------------------------------------------
diff --git a/platform/marmotta-core/src/main/java/org/apache/marmotta/platform/core/services/templating/TemplatingServiceImpl.java b/platform/marmotta-core/src/main/java/org/apache/marmotta/platform/core/services/templating/TemplatingServiceImpl.java
index 56728cc..6942443 100644
--- a/platform/marmotta-core/src/main/java/org/apache/marmotta/platform/core/services/templating/TemplatingServiceImpl.java
+++ b/platform/marmotta-core/src/main/java/org/apache/marmotta/platform/core/services/templating/TemplatingServiceImpl.java
@@ -31,6 +31,7 @@ import javax.enterprise.context.ApplicationScoped;
 import javax.enterprise.event.Observes;
 import javax.inject.Inject;
 
+import com.google.common.base.Preconditions;
 import org.apache.marmotta.platform.core.api.config.ConfigurationService;
 import org.apache.marmotta.platform.core.api.templating.TemplatingService;
 import org.apache.marmotta.platform.core.events.ConfigurationChangedEvent;
@@ -38,6 +39,7 @@ import org.apache.marmotta.platform.core.events.ConfigurationChangedEvent;
 import freemarker.template.Configuration;
 import freemarker.template.Template;
 import freemarker.template.TemplateException;
+import org.apache.marmotta.platform.core.startup.MarmottaStartupService;
 
 /**
  * Template Service Implementation
@@ -52,13 +54,18 @@ public class TemplatingServiceImpl implements TemplatingService {
     @Inject
     private ConfigurationService configurationService;
 
+    @Inject
+    private MarmottaStartupService startupService;
+
 	public TemplatingServiceImpl() {
 		super();
 		common = new HashMap<String,String>();
 	}
 
 	@PostConstruct
-	public void initDataModel() {        
+	public void initDataModel() {
+        Preconditions.checkState(startupService.isHostStarted());
+
         String project = configurationService.getStringConfiguration("kiwi.pages.project", DEFAULT_PROJECT);
         common.put("PROJECT", project);
         common.put("DEFAULT_STYLE", configurationService.getStringConfiguration("kiwi.pages.style_path", DEFAULT_STYLE));

http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/582abb5b/platform/marmotta-core/src/main/java/org/apache/marmotta/platform/core/services/triplestore/ContextServiceImpl.java
----------------------------------------------------------------------
diff --git a/platform/marmotta-core/src/main/java/org/apache/marmotta/platform/core/services/triplestore/ContextServiceImpl.java b/platform/marmotta-core/src/main/java/org/apache/marmotta/platform/core/services/triplestore/ContextServiceImpl.java
index 189c566..afe1792 100644
--- a/platform/marmotta-core/src/main/java/org/apache/marmotta/platform/core/services/triplestore/ContextServiceImpl.java
+++ b/platform/marmotta-core/src/main/java/org/apache/marmotta/platform/core/services/triplestore/ContextServiceImpl.java
@@ -30,7 +30,7 @@ import javax.enterprise.inject.Produces;
 import javax.inject.Inject;
 import javax.inject.Named;
 
-import org.apache.commons.lang.StringUtils;
+import org.apache.commons.lang3.StringUtils;
 import org.apache.marmotta.commons.sesame.repository.ResourceUtils;
 import org.apache.marmotta.platform.core.api.config.ConfigurationService;
 import org.apache.marmotta.platform.core.api.importer.ImportService;
@@ -45,6 +45,8 @@ import org.apache.marmotta.platform.core.qualifiers.kspace.InferredKnowledgeSpac
 import org.apache.marmotta.platform.core.qualifiers.kspace.SystemKnowledgeSpace;
 import org.openrdf.model.Resource;
 import org.openrdf.model.URI;
+import org.openrdf.model.ValueFactory;
+import org.openrdf.model.util.Literals;
 import org.openrdf.model.vocabulary.RDFS;
 import org.openrdf.repository.RepositoryConnection;
 import org.openrdf.repository.RepositoryException;
@@ -178,9 +180,10 @@ public class ContextServiceImpl implements ContextService {
             try {
                 conn.begin();
                 checkConnectionNamespace(conn);
-                URI ctx = conn.getValueFactory().createURI(uri);
+                ValueFactory valueFactory = conn.getValueFactory();
+				URI ctx = valueFactory.createURI(uri);
                 if (StringUtils.isNotBlank(label)) {
-                    conn.add(ctx, RDFS.LABEL, conn.getValueFactory().createLiteral(label), ctx);
+                    conn.add(ctx, RDFS.LABEL, Literals.createLiteral(valueFactory, label), ctx);
                 }
                 return ctx;
             } finally {