clerezza-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From r...@apache.org
Subject [40/87] [abbrv] [partial] clerezza git commit: CLEREZZA-966: removed platform. prefix of folder names
Date Tue, 14 Apr 2015 13:13:15 GMT
http://git-wip-us.apache.org/repos/asf/clerezza/blob/70220239/platform/content/src/main/java/org/apache/clerezza/platform/content/DiscobitsTypeHandler.java
----------------------------------------------------------------------
diff --git a/platform/content/src/main/java/org/apache/clerezza/platform/content/DiscobitsTypeHandler.java b/platform/content/src/main/java/org/apache/clerezza/platform/content/DiscobitsTypeHandler.java
new file mode 100644
index 0000000..a92ff01
--- /dev/null
+++ b/platform/content/src/main/java/org/apache/clerezza/platform/content/DiscobitsTypeHandler.java
@@ -0,0 +1,556 @@
+/*
+ * 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.clerezza.platform.content;
+
+import org.apache.clerezza.rdf.utils.graphnodeprovider.GraphNodeProvider;
+import org.apache.clerezza.rdf.metadata.MetaDataGenerator;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Method;
+import java.net.URISyntaxException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import java.util.Set;
+import java.util.concurrent.locks.Lock;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.HttpMethod;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriInfo;
+import javax.ws.rs.core.Response.Status;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.transform.TransformerException;
+import javax.xml.transform.TransformerFactoryConfigurationError;
+import javax.xml.transform.dom.DOMSource;
+import org.apache.clerezza.jaxrs.utils.RedirectUtil;
+import org.apache.clerezza.platform.Constants;
+import org.apache.clerezza.platform.content.WebDavUtils.PropertyMap;
+import org.apache.clerezza.platform.content.collections.CollectionCreator;
+import org.apache.clerezza.platform.content.webdav.MKCOL;
+import org.apache.clerezza.platform.content.webdav.MOVE;
+import org.apache.clerezza.platform.content.webdav.PROPFIND;
+import org.apache.clerezza.platform.content.webdav.PROPPATCH;
+
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Property;
+import org.apache.felix.scr.annotations.Reference;
+import org.apache.felix.scr.annotations.ReferenceCardinality;
+import org.apache.felix.scr.annotations.ReferencePolicy;
+import org.apache.felix.scr.annotations.Service;
+import org.apache.felix.scr.annotations.Services;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.apache.clerezza.platform.graphprovider.content.ContentGraphProvider;
+import org.apache.clerezza.platform.typehandlerspace.OPTIONS;
+import org.apache.clerezza.platform.typehandlerspace.SupportedTypes;
+import org.apache.clerezza.rdf.core.MGraph;
+import org.apache.clerezza.rdf.core.Triple;
+import org.apache.clerezza.rdf.core.TripleCollection;
+import org.apache.clerezza.rdf.core.UriRef;
+import org.apache.clerezza.rdf.core.access.LockableMGraph;
+import org.apache.clerezza.rdf.core.impl.TripleImpl;
+import org.apache.clerezza.rdf.ontologies.HIERARCHY;
+import org.apache.clerezza.rdf.ontologies.RDF;
+import org.apache.clerezza.rdf.utils.GraphNode;
+import org.apache.clerezza.rdf.utils.UnionMGraph;
+import org.apache.clerezza.rdf.utils.UriMutatingTripleCollection;
+import org.apache.clerezza.web.fileserver.util.MediaTypeGuesser;
+import org.osgi.service.component.ComponentContext;
+import org.w3c.dom.Document;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+/**
+ * This Class allows getting and putting content structured using the
+ * Discobits ontology.
+ *
+ * Is an implementation of DiscobitsHandler and additionally registers as
+ * TypeHanlder to allow HTTP GET and PUT.
+ *
+ * @author reto, tho, agron, mir
+ */
+@Component(metatype=true)
+@Service({
+    Object.class,
+    DiscobitsHandler.class
+})
+@Property(name="org.apache.clerezza.platform.typehandler", boolValue=true)
+@Reference(name="metaDataGenerator",
+    policy=ReferencePolicy.DYNAMIC,
+    cardinality=ReferenceCardinality.OPTIONAL_MULTIPLE,
+    referenceInterface=MetaDataGenerator.class
+)
+@SupportedTypes(types = { "http://www.w3.org/2000/01/rdf-schema#Resource" }, prioritize = false)
+public class DiscobitsTypeHandler extends AbstractDiscobitsHandler
+        implements DiscobitsHandler {
+@Property(value="600", label="Max-Age", description="Specifies the value of the max-age field"
+        + "set in the cache-control header of InfoDiscoBit-Responses, as per RFC 2616 this is a number of "
+        + "seconds")
+    public static final String MAX_AGE = "max-age";
+
+    @Reference
+    protected ContentGraphProvider cgProvider;
+
+    @Reference
+    PageNotFoundService notFoundPageService;
+
+    @Reference
+    GraphNodeProvider graphNodeProvider;
+
+    private static final Logger logger = LoggerFactory.getLogger(DiscobitsTypeHandler.class);
+
+    private final Set<MetaDataGenerator> metaDataGenerators =
+            Collections.synchronizedSet(new HashSet<MetaDataGenerator>());
+
+    private String cacheControlHeaderValue;
+
+    protected void activate(ComponentContext context) {
+        cacheControlHeaderValue = "max-age="+(String) context.getProperties().get(MAX_AGE);
+    }
+
+    /**
+     * TypeHandle method for rdf types "TitledContext", "InfoDiscoBit",
+     * "OrderedContent" and "XHTMLInfoDiscoBit".
+     * 
+     * @param uriInfo
+     * @return
+     */
+    @GET
+    @Produces({"*/*"})
+    public Object getResource(@Context UriInfo uriInfo) {
+        final UriRef uri = new UriRef(uriInfo.getAbsolutePath().toString());
+            final GraphNode graphNode = getResourceAsGraphNode(uriInfo);
+        if (graphNode == null) {
+            return resourceUnavailable(uri, uriInfo);
+        }
+        InfoDiscobit infoDiscobit = InfoDiscobit.createInstance(graphNode);
+        if (infoDiscobit != null) {
+            Response response = Response.ok().
+                    header(HttpHeaders.CACHE_CONTROL, cacheControlHeaderValue).
+                    entity(infoDiscobit).
+                    build();
+            return response;
+        } else {
+            return graphNode;
+        }
+    }
+
+    private GraphNode getResourceAsGraphNode(UriInfo uriInfo) {
+        final UriRef uri = new UriRef(uriInfo.getAbsolutePath().toString());
+        GraphNode result = graphNodeProvider.getLocal(uri);
+        //could chck if nodeContext > 0, but this would be less efficient
+        TripleCollection tc = result.getGraph();
+        if (tc.filter(uri, null, null).hasNext()) {
+            return result;
+        }
+        if (tc.filter(null, null, uri).hasNext()) {
+            return result;
+        }
+        return null;
+    }
+
+
+    
+    /**
+     * Creates an <code>InfoDiscoBit</code> at the specified location
+     *
+     * @param uriInfo the uri of the InforDiscoBit to be created
+     * @param data the content of the upload
+     */
+    @PUT
+    public Response putInfoDiscobit(@Context UriInfo uriInfo, @Context HttpHeaders headers, byte[] data) {
+        final String contentType;
+        {
+            final List<String> contentTypeHeaders = headers.getRequestHeader(HttpHeaders.CONTENT_TYPE);
+            if (contentTypeHeaders == null) {
+                logger.warn("Content-Type not specified");
+                final MediaType guessTypeForName = MediaTypeGuesser.getInstance().
+                        guessTypeForName(uriInfo.getAbsolutePath().toString());
+                contentType = guessTypeForName == null ?
+                    MediaType.APPLICATION_OCTET_STREAM : guessTypeForName.toString();
+            } else {
+                contentType = contentTypeHeaders.get(0);
+            }
+            
+        }    
+        final UriRef infoDiscoBitUri = new UriRef(uriInfo.getAbsolutePath().toString());
+        put(infoDiscoBitUri, MediaType.valueOf(contentType), data);
+        return Response.status(Status.CREATED).build();
+    }
+
+    /**
+     * Creates a new collection at the specified uri
+     *
+     * @param uriInfo
+     * @return
+     * <ul>
+     *    <li>201 "Created" response if method succeeded
+     *    <li>405 "Method Not Allowed" response if collection already exists
+     * </ul>
+     */
+    @MKCOL
+    public Object mkcol(@Context UriInfo uriInfo) {
+        String uriString = uriInfo.getAbsolutePath().toString();
+        if (uriString.charAt(uriString.length()-1) != '/') {
+            uriString += '/';
+        }
+        UriRef nodeUri = new UriRef(uriString);
+        final MGraph mGraph = cgProvider.getContentGraph();
+        Triple typeTriple = new TripleImpl(nodeUri, RDF.type, HIERARCHY.Collection);
+        if (mGraph.contains(typeTriple)) {
+            return Response.status(405) // Method Not Allowed
+                    .entity("Collection \"" + nodeUri.getUnicodeString()
+                    + "\" already exists.").build();
+        }
+        new CollectionCreator(mGraph).createContainingCollections(nodeUri);
+        return Response.created(uriInfo.getAbsolutePath()).build();
+    }
+
+    /**
+     * Finds all properties of a hierarchy node and returns them in a
+     * {@link DOMSource}
+     *
+     * @param uriInfo
+     * @param headers {@link HttpHeaders}
+     * @param body {@link DOMSource} containing the requested properties, can be null
+     * @return
+     * <ul>
+     *    <li>207 "Multistatus" response if method succeeded
+     *    <li>404 "Not Found" response if the hierarchy node was not found
+     *    <li>400 "Bad Request" response if the body is malformed
+     * </ul>
+     */
+    @PROPFIND
+    @Consumes({"application/xml", "text/xml", "*/*"})
+    @Produces({"application/xml", "text/xml", "*/*"})
+    public Response propfind(@Context UriInfo uriInfo,
+            @Context HttpHeaders headers, DOMSource body) {
+        final UriRef nodeUri = new UriRef(uriInfo.getAbsolutePath().toString());
+        if (!nodeAtUriExists(nodeUri)) {
+            return resourceUnavailable(nodeUri, uriInfo);
+        }
+            Map<UriRef, PropertyMap> result;
+        try {
+            String depthHeader = WebDavUtils.getHeaderAsString(headers, "Depth");
+            if (depthHeader == null) {
+                depthHeader = WebDavUtils.infinite;
+            }
+            final MGraph mGraph = cgProvider.getContentGraph();
+            GraphNode node = new GraphNode(nodeUri, mGraph);
+            if (body != null) {
+                Document requestDoc = WebDavUtils.sourceToDocument(body);
+                Node propfindNode = WebDavUtils.getNode(requestDoc, WebDavUtils.propfind);
+                Node requestNode = WebDavUtils.getFirstChild(propfindNode);
+                String requestType = requestNode.getLocalName();
+                if (requestType.equalsIgnoreCase(WebDavUtils.allprop)) {
+                    result = getAllProps(node, depthHeader);
+                } else if (requestType.equalsIgnoreCase(WebDavUtils.prop)) {
+                    result = getPropsByName(requestNode, node, depthHeader);
+                } else if (requestType.equalsIgnoreCase(WebDavUtils.propname)) {
+                    result = getPropNames(node, depthHeader);
+                } else {
+                    return Response.status(Status.BAD_REQUEST).build();
+                }
+            } else {
+                // returns all properties
+                result = getAllProps(node, depthHeader);
+            }
+            Document responseDoc = WebDavUtils.createResponseDoc(result);
+            return Response.status(207).entity(new DOMSource(responseDoc)).type(
+                    MediaType.APPLICATION_XML_TYPE).build();
+        } catch (TransformerFactoryConfigurationError e) {
+            return Response.status(Status.BAD_REQUEST).build();
+        } catch (TransformerException e) {
+            return Response.status(Status.BAD_REQUEST).build();
+        } catch (ParserConfigurationException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    Map<UriRef, PropertyMap> getPropNames(GraphNode node, String depthHeader) {
+        Map<UriRef, PropertyMap> result = new HashMap<UriRef, PropertyMap>();
+        WebDavUtils.addNodeProperties(result, null, null, node, false);
+        return result;
+    }
+
+    Map<UriRef, PropertyMap> getPropsByName(Node requestNode, GraphNode node,
+            String depthHeader) {
+        Map<UriRef, PropertyMap> result;
+        NodeList children = requestNode.getChildNodes();
+        result = WebDavUtils.getPropsByName(children, node, "0", true);
+        return result;
+    }
+
+    Map<UriRef, PropertyMap> getAllProps(GraphNode node, String depthHeader) {
+        HashMap<UriRef, PropertyMap> result = new HashMap<UriRef, PropertyMap>();
+        WebDavUtils.addNodeProperties(result, null, null, node, true);
+        return result;
+    }
+
+    /**
+     * @param uriInfo
+     * @param body {@link DOMSource} containing properties which should be set
+     * or deleted
+     * @return
+     * <ul>
+     *    <li>207 "Multistatus" response if method succeeded
+     *    <li>404 "Not Found" response if the hierarchy node was not found
+     *    <li>400 "Bad Request" response if the body is malformed
+     * </ul>
+     */
+    @PROPPATCH
+    @Consumes({"application/xml", "text/xml", "*/*"})
+    @Produces({"application/xml", "text/xml", "*/*"})
+    public Response proppatch(@Context UriInfo uriInfo, DOMSource body) {
+        UriRef nodeUri = new UriRef(uriInfo.getAbsolutePath().toString());
+        if (!nodeAtUriExists(nodeUri)) {
+            return resourceUnavailable(nodeUri, uriInfo);
+        }
+        try {
+            Document requestDoc = WebDavUtils.sourceToDocument(body);
+            final MGraph mGraph = cgProvider.getContentGraph();
+            GraphNode node = new GraphNode(nodeUri, mGraph);
+            NodeList propsToSet = null;
+            NodeList propsToRemove = null;
+            Node proppatchNode = WebDavUtils.getNode(requestDoc, WebDavUtils.proppatch);
+            NodeList childNodes = proppatchNode.getChildNodes();
+            for (int i = 0; i < childNodes.getLength(); i++) {
+                Node child = childNodes.item(i);
+                String localName = child.getLocalName();
+                if (localName != null) {
+                    if (localName.equals(WebDavUtils.set)) {
+                        propsToSet = child.getFirstChild().getChildNodes();
+                    } else if (localName.equals(WebDavUtils.remove)) {
+                        propsToRemove = child.getFirstChild().getChildNodes();
+                    }
+                }
+            }
+            Document responseDoc = WebDavUtils.modifyProperties(node, propsToSet, propsToRemove);
+            return Response.status(207).entity(new DOMSource(responseDoc)).type(
+                    MediaType.APPLICATION_XML_TYPE).build();
+        } catch (ParserConfigurationException ex) {
+            throw new RuntimeException(ex);
+        } catch (TransformerFactoryConfigurationError ex) {
+            return Response.status(Status.BAD_REQUEST).build();
+        } catch (TransformerException ex) {
+            return Response.status(Status.BAD_REQUEST).build();
+        } 
+    }
+
+    /**
+     * Moves or renames a hierarchy node
+     *
+     * @param uriInfo
+     * @param headers
+     * @return
+     * <ul>
+     *  <li>201 "Created" response if method succeeded
+     *  <li>412 "Precondition Failed" response if the destination URL is already
+     *    mapped to a resource
+     *  <li>404 "Not Found" response if the hierarchy node was not found
+     *  <li>403 "Forbidden" response if the source and destination resources are the same
+     *  <li>400 "Bad Request" if no "Destination" header was found
+     * </ul>
+     */
+    @MOVE
+    public Response move(@Context UriInfo uriInfo, @Context HttpHeaders headers) {
+        UriRef nodeUri = new UriRef(uriInfo.getAbsolutePath().toString());
+        final LockableMGraph mGraph = cgProvider.getContentGraph();
+        GraphNode node = new GraphNode(nodeUri, mGraph);
+        String targetString = WebDavUtils.getHeaderAsString(headers,
+                    "Destination");
+        UriRef targetUri = new UriRef(targetString);
+        String overwriteHeader = WebDavUtils.getHeaderAsString(headers, "Overwrite");
+        boolean overwriteTarget = "T".equalsIgnoreCase(overwriteHeader);
+        if (nodeAtUriExists(targetUri)) {
+            if (overwriteTarget) {
+                new GraphNode(targetUri, mGraph).deleteNodeContext();
+            } else {
+                return Response.status(Status.PRECONDITION_FAILED).build();
+            }
+        }
+        Lock l = mGraph.getLock().writeLock();
+        l.lock();
+        try {
+            Iterator<Triple> oldParentTripleIter
+                    = mGraph.filter(nodeUri, HIERARCHY.parent, null);
+            if (oldParentTripleIter.hasNext()) {
+                oldParentTripleIter.next();
+                oldParentTripleIter.remove();
+            }
+            while (oldParentTripleIter.hasNext()) {
+                logger.error("more than one parent statement: "+oldParentTripleIter.next());
+                oldParentTripleIter.remove();
+            }
+            Lock writeLock = node.writeLock();
+            writeLock.lock();
+            try {
+                node.replaceWith(targetUri);
+            } finally {
+                writeLock.unlock();
+            }
+            new CollectionCreator(mGraph).createContainingCollections(targetUri);
+            try {
+                return Response.created(new java.net.URI(targetUri.getUnicodeString())).build();
+            } catch (URISyntaxException ex) {
+                throw new IllegalArgumentException(ex);
+            }
+        } finally {
+            l.unlock();
+        }
+    }
+
+    /**
+     * Deletes a hierarchy node
+     *
+     * @param uriInfo
+     * @return
+     * <ul>
+     *    <li>200 "OK" response if method succeeded
+     *    <li>404 "Not Found" response if the hierarchy node was not found
+     * </ul>
+     */
+    @DELETE
+    public Response delete(@Context UriInfo uriInfo) {
+        UriRef nodeUri = new UriRef(uriInfo.getAbsolutePath().toString());
+        if (!nodeAtUriExists(nodeUri)) {
+            return Response.status(Status.NOT_FOUND).entity(
+                    uriInfo.getAbsolutePath()).type(MediaType.TEXT_PLAIN).build();
+        }
+        final LockableMGraph mGraph = cgProvider.getContentGraph();
+        GraphNode node = new GraphNode(nodeUri, mGraph);
+        node.deleteNodeContext();
+        return Response.ok().build();
+    }
+
+    /**
+     * @param uriInfo
+     * @return
+     * <ul>
+     *    <li>200 "OK" response with an "Allow" and a "DAV" header. The "Allow"
+     * header contains all the possible HTTP methods that can be executed on the
+     * resource and the "DAV" header shows if the resource is WebDAV enabled
+     *    <li>404 "Not Found" response if the resource was not found
+     * </ul>
+     */
+    @OPTIONS
+    public Response options(@Context UriInfo uriInfo) {
+        final UriRef nodeUri = new UriRef(uriInfo.getAbsolutePath().toString());
+        if (!nodeAtUriExists(nodeUri)) {
+            return resourceUnavailable(nodeUri, uriInfo);
+        }
+            Response.ResponseBuilder builder = Response.ok();
+            builder.header("Dav", "1");
+            Set<String> allow = new HashSet<String>();
+            Method[] methods = this.getClass().getMethods();
+            for (Method method : methods) {
+                for (Annotation annotation : method.getAnnotations()) {
+                    HttpMethod httpMethod = annotation.annotationType().getAnnotation(HttpMethod.class);
+                    if (httpMethod != null) {
+                        allow.add(httpMethod.value());
+                    }
+                }
+            }
+            if (allow.isEmpty()) {
+                builder.header("Allow", "");
+            } else {
+                final Iterator<String> iterator = allow.iterator();
+                final StringBuffer buffer = new StringBuffer(iterator.next());
+                while (iterator.hasNext()) {
+                    buffer.append(", ");
+                    buffer.append(iterator.next());
+                }
+                builder.header("Allow", buffer.toString());
+            }
+        return builder.build();
+    }
+
+    protected void bindMetaDataGenerator(MetaDataGenerator generator) {
+        metaDataGenerators.add(generator);
+    }
+
+    protected void unbindMetaDataGenerator(MetaDataGenerator generator) {
+        metaDataGenerators.remove(generator);
+    }
+
+    @Override
+    protected MGraph getMGraph() {
+        return cgProvider.getContentGraph();
+    }
+
+    @Override
+    protected Set<MetaDataGenerator> getMetaDataGenerators() {
+        return metaDataGenerators;
+    }
+
+    
+
+    private boolean nodeAtUriExists(UriRef nodeUri) {
+        LockableMGraph mGraph = (LockableMGraph) getMGraph();
+        Lock readLock = mGraph.getLock().readLock();
+        readLock.lock();
+        try {
+            return mGraph.filter(nodeUri, null, null).hasNext()
+                    || mGraph.filter(null, null, nodeUri).hasNext();
+        } finally {
+            readLock.unlock();
+        }
+    }
+
+    private Response resourceUnavailable(UriRef nodeUri,
+            UriInfo uriInfo) {
+        UriRef oppositUri = makeOppositeUriRef(nodeUri);
+        if (nodeAtUriExists(oppositUri)) {
+            return RedirectUtil.createSeeOtherResponse(
+                    oppositUri.getUnicodeString(), uriInfo);
+        } else {
+            return notFoundPageService.createResponse(uriInfo);
+        }
+        //return Response.status(Status.NOT_FOUND).build();
+    }
+    /**
+     * add trailing slash if none present, remove otherwise
+     *
+     * @param uri
+     * @return
+     */
+    private static UriRef makeOppositeUriRef(UriRef uri) {
+        String uriString = uri.getUnicodeString();
+        if (uriString.endsWith("/")) {
+            return new UriRef(uriString.substring(0, uriString.length() - 1));
+        } else {
+            return new UriRef(uriString + "/");
+        }
+    }
+
+    private UriRef createAnyHostUri(UriInfo uriInfo) {
+        return new UriRef(Constants.ALL_HOSTS_URI_PREFIX+uriInfo.getPath());
+    }
+}

http://git-wip-us.apache.org/repos/asf/clerezza/blob/70220239/platform/content/src/main/java/org/apache/clerezza/platform/content/Editor.java
----------------------------------------------------------------------
diff --git a/platform/content/src/main/java/org/apache/clerezza/platform/content/Editor.java b/platform/content/src/main/java/org/apache/clerezza/platform/content/Editor.java
new file mode 100644
index 0000000..5e7940d
--- /dev/null
+++ b/platform/content/src/main/java/org/apache/clerezza/platform/content/Editor.java
@@ -0,0 +1,177 @@
+/*
+ * 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.clerezza.platform.content;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.lang.annotation.Annotation;
+import java.net.URL;
+
+import javax.ws.rs.FormParam;
+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.WebApplicationException;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.UriInfo;
+import javax.ws.rs.ext.MessageBodyReader;
+import javax.ws.rs.ext.Providers;
+import org.apache.clerezza.rdf.utils.MGraphUtils.NoSuchSubGraphException;
+
+import org.osgi.framework.Bundle;
+import org.osgi.service.component.ComponentContext;
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Property;
+import org.apache.felix.scr.annotations.Reference;
+import org.apache.felix.scr.annotations.Service;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.apache.clerezza.jaxrs.utils.TrailingSlash;
+import org.apache.clerezza.platform.graphprovider.content.ContentGraphProvider;
+import org.apache.clerezza.rdf.core.Graph;
+import org.apache.clerezza.rdf.core.MGraph;
+import org.apache.clerezza.rdf.core.UriRef;
+import org.apache.clerezza.rdf.core.access.TcManager;
+import org.apache.clerezza.rdf.core.serializedform.Serializer;
+import org.apache.clerezza.rdf.utils.GraphNode;
+import org.apache.clerezza.rdf.utils.MGraphUtils;
+import org.apache.clerezza.web.fileserver.BundlePathNode;
+import org.apache.clerezza.web.fileserver.FileServer;
+import org.wymiwyg.commons.util.dirbrowser.PathNode;
+
+/**
+ * This Jax-rs root resource provides an ajax edito ro edit content structured
+ * using the Discobits ontology
+ *
+ * @author rbn
+ *
+ */
+@Component
+@Service(Object.class)
+@Property(name="javax.ws.rs", boolValue=true)
+@Path("tools/editor")
+public class Editor extends FileServer {
+
+    @Reference
+    private ContentGraphProvider cgProvider;
+
+    @Reference
+    private TcManager tcManager;
+    
+    @Reference
+    private Serializer serializer;
+
+    
+    private static final Logger logger = LoggerFactory.getLogger(Editor.class);
+
+    private Providers providers;
+    private final String rdfXml = "application/rdf+xml";
+    
+    
+    
+    /**
+     * On activation the {@link FileServer} is prepared
+     *
+     * @param context
+     */
+    protected void activate(ComponentContext context) {
+        configure(context.getBundleContext());
+    }
+
+    
+    /**
+     * The providers are injected by the Jax-rs implementation and used to
+     * locate readers for the RDF content of the body
+     *
+     * @param providers
+     */
+    @Context
+    public void setProviders(Providers providers) {
+        this.providers = providers;
+    }
+
+
+    @GET
+    @Path("get")
+    public GraphNode getDiscobit(@QueryParam("resource") UriRef uri,
+            @QueryParam("graph") UriRef graphUri) {
+        final MGraph mGraph = graphUri == null ? cgProvider.getContentGraph() :
+            tcManager.getMGraph(graphUri);
+        return new GraphNode(uri, mGraph);
+    }
+
+    /**
+     * replaces the subgraph serialized with RDF/XML in <code>revokedString
+     * </code> with the one from <code>assertedString</code>.
+     *
+     * @param graphUri the graph within which the replacement has to take place or null
+     * for the content graph
+     * @param assertedString the asserted Graph as RDF/XML
+     * @param revokedString the revoked Graph as RDF/XML
+     */
+    @POST
+    @Path("post")
+    public void postDiscobit(@QueryParam("graph") UriRef graphUri,
+            @FormParam("assert") String assertedString,
+            @FormParam("revoke") String revokedString,
+            @FormParam("rdfFormat") String rdfFormat) {
+        if (rdfFormat == null) {
+            rdfFormat = rdfXml;
+        }
+        MediaType mediaType = MediaType.valueOf(rdfFormat);
+        MessageBodyReader<Graph> graphReader = providers.getMessageBodyReader(Graph.class, Graph.class, null,mediaType);
+        final Graph assertedGraph;
+        final Graph revokedGraph;
+        try {
+            assertedGraph = graphReader.readFrom(Graph.class, Graph.class, new Annotation[0], mediaType, null, new ByteArrayInputStream(assertedString.getBytes()));
+            revokedGraph = graphReader.readFrom(Graph.class, Graph.class, new Annotation[0], mediaType, null, new ByteArrayInputStream(revokedString.getBytes()));
+        } catch (IOException ex) {
+            logger.error("reading graph {}", ex);
+            throw new WebApplicationException(ex, 500);
+        }
+        final MGraph mGraph = graphUri == null ? cgProvider.getContentGraph() :
+            tcManager.getMGraph(graphUri);
+        try {
+            serializer.serialize(System.out, revokedGraph, "text/turtle");
+            ByteArrayOutputStream baos = new ByteArrayOutputStream();
+            serializer.serialize(baos, revokedGraph, "text/turtle");
+            System.out.println(new String(baos.toByteArray()).contains("\r"));
+            MGraphUtils.removeSubGraph(mGraph, revokedGraph);
+        } catch (NoSuchSubGraphException ex) {
+            throw new RuntimeException(ex);
+        }
+        mGraph.addAll(assertedGraph);
+    }
+
+    @GET
+    //this is to work around
+    @Produces(MediaType.APPLICATION_OCTET_STREAM)
+    public PathNode getStaticFile(@Context UriInfo uriInfo) {
+        TrailingSlash.enforcePresent(uriInfo);
+        final PathNode node = getNode("disco.xhtml");
+        logger.debug("serving static {}", node);
+        return node;
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/clerezza/blob/70220239/platform/content/src/main/java/org/apache/clerezza/platform/content/InfoDiscobit.java
----------------------------------------------------------------------
diff --git a/platform/content/src/main/java/org/apache/clerezza/platform/content/InfoDiscobit.java b/platform/content/src/main/java/org/apache/clerezza/platform/content/InfoDiscobit.java
new file mode 100644
index 0000000..8693216
--- /dev/null
+++ b/platform/content/src/main/java/org/apache/clerezza/platform/content/InfoDiscobit.java
@@ -0,0 +1,105 @@
+/*
+ * 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.clerezza.platform.content;
+
+import java.util.Iterator;
+import java.util.concurrent.locks.Lock;
+import org.apache.clerezza.rdf.core.Literal;
+import org.apache.clerezza.rdf.core.LiteralFactory;
+import org.apache.clerezza.rdf.core.Resource;
+import org.apache.clerezza.rdf.core.TypedLiteral;
+
+import org.apache.clerezza.rdf.utils.GraphNode;
+import org.apache.clerezza.rdf.ontologies.DISCOBITS;
+import org.apache.clerezza.rdf.ontologies.RDF;
+
+/**
+ * Represents an InfoDiscoBit
+ *
+ * @author reto
+ */
+public class InfoDiscobit {
+
+    private GraphNode infoBit;
+
+
+    /**
+     *
+     * @param infoBit
+     * @return an instance of InfoDiscobit or null if node is not an InfoDiscoBit
+     */
+    public static InfoDiscobit createInstance(GraphNode node) {
+        Lock l = node.readLock();
+        l.lock();
+        try {
+            Iterator<Resource> types = node.getObjects(RDF.type);
+            while(types.hasNext()) {
+                if (types.next().equals(DISCOBITS.InfoDiscoBit)){
+                    return new InfoDiscobit(node);
+                }
+            }
+            return null;
+        } finally {
+            l.unlock();
+        }
+    }
+
+    InfoDiscobit(GraphNode infoBit) {
+        this.infoBit = infoBit;
+    }
+
+    public String getContentType() {
+        Lock readLock = infoBit.readLock();
+        readLock.lock();
+        try {
+            Iterator<Literal> mediaTypeLits = infoBit.getLiterals(DISCOBITS.mediaType);
+            if (mediaTypeLits.hasNext()) {
+                return mediaTypeLits.next().getLexicalForm();
+            } else {
+                throw new RuntimeException("InfoDiscobit has no media type property");
+            }
+        } finally {
+            readLock.unlock();
+        }
+    }
+    
+    public byte[] getData() {
+        byte[] result;
+        Lock readLock = infoBit.readLock();
+        readLock.lock();
+        try {
+            Iterator<Literal> infoBitLits = infoBit.getLiterals(DISCOBITS.infoBit);
+            if (infoBitLits.hasNext()) {
+                final Literal literalValue = infoBitLits.next();
+                if (literalValue instanceof TypedLiteral) {
+                    result = LiteralFactory.getInstance().createObject(
+                            (new byte[0]).getClass(), (TypedLiteral) literalValue);
+                } else {
+                    throw new RuntimeException("InfoDiscobit has infoBit value which is not a TypedLiteral but "+literalValue);
+                }
+            } else {
+                throw new RuntimeException("InfoDiscobit has not infoBit property");
+            }
+        } finally {
+            readLock.unlock();
+        }        
+        return result;    
+    };
+
+}

http://git-wip-us.apache.org/repos/asf/clerezza/blob/70220239/platform/content/src/main/java/org/apache/clerezza/platform/content/InfoDiscobitWriter.java
----------------------------------------------------------------------
diff --git a/platform/content/src/main/java/org/apache/clerezza/platform/content/InfoDiscobitWriter.java b/platform/content/src/main/java/org/apache/clerezza/platform/content/InfoDiscobitWriter.java
new file mode 100644
index 0000000..e3a2aa4
--- /dev/null
+++ b/platform/content/src/main/java/org/apache/clerezza/platform/content/InfoDiscobitWriter.java
@@ -0,0 +1,67 @@
+/*
+ * 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.clerezza.platform.content;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Type;
+import javax.ws.rs.Produces;
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.MultivaluedMap;
+import javax.ws.rs.ext.MessageBodyWriter;
+import javax.ws.rs.ext.Provider;
+
+
+/**
+ * 
+ * @scr.component
+ * @scr.service interface="java.lang.Object"
+ * @scr.property name="javax.ws.rs" type="Boolean" value="true"
+ *
+ * @author reto
+ */
+@Provider
+@Produces("*/*")
+public class InfoDiscobitWriter implements MessageBodyWriter<InfoDiscobit> {
+
+    @Override
+    public boolean isWriteable(Class<?> type, Type genericType,
+            Annotation[] annotations, MediaType mediaType) {
+        return InfoDiscobit.class.isAssignableFrom(type);
+    }
+
+    @Override
+    public long getSize(InfoDiscobit t, Class<?> type, Type genericType,
+            Annotation[] annotations, MediaType mediaType) {
+        return t.getData().length;
+    }
+
+    @Override
+    public void writeTo(InfoDiscobit t, Class<?> type, Type genericType,
+            Annotation[] annotations, MediaType mediaType,
+            MultivaluedMap<String, Object> httpHeaders,
+            OutputStream entityStream) throws IOException,
+            WebApplicationException {
+        httpHeaders.putSingle(HttpHeaders.CONTENT_TYPE, t.getContentType());
+        entityStream.write(t.getData());
+    }
+}

http://git-wip-us.apache.org/repos/asf/clerezza/blob/70220239/platform/content/src/main/java/org/apache/clerezza/platform/content/PageNotFoundService.java
----------------------------------------------------------------------
diff --git a/platform/content/src/main/java/org/apache/clerezza/platform/content/PageNotFoundService.java b/platform/content/src/main/java/org/apache/clerezza/platform/content/PageNotFoundService.java
new file mode 100644
index 0000000..ccce889
--- /dev/null
+++ b/platform/content/src/main/java/org/apache/clerezza/platform/content/PageNotFoundService.java
@@ -0,0 +1,40 @@
+/*
+ *  Copyright 2010 reto.
+ * 
+ *  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.
+ *  under the License.
+ */
+
+package org.apache.clerezza.platform.content;
+
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriInfo;
+
+/**
+ * An instance of this service is called by DiscoBitHandler if a resource
+ * is not found in the content graph.
+ *
+ * @author reto
+ */
+public interface PageNotFoundService {
+
+    /**
+     * Creates a response when a resource could not be found in the Content 
+     * Graph, this is a 404 response.
+     * 
+     * @param uriInfo
+     * @return
+     */
+    public Response createResponse(UriInfo uriInfo);
+
+}

http://git-wip-us.apache.org/repos/asf/clerezza/blob/70220239/platform/content/src/main/java/org/apache/clerezza/platform/content/SimpleDiscobitsHandler.java
----------------------------------------------------------------------
diff --git a/platform/content/src/main/java/org/apache/clerezza/platform/content/SimpleDiscobitsHandler.java b/platform/content/src/main/java/org/apache/clerezza/platform/content/SimpleDiscobitsHandler.java
new file mode 100644
index 0000000..69171ff
--- /dev/null
+++ b/platform/content/src/main/java/org/apache/clerezza/platform/content/SimpleDiscobitsHandler.java
@@ -0,0 +1,49 @@
+/*
+ * 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.clerezza.platform.content;
+
+import org.apache.clerezza.rdf.metadata.MetaDataGenerator;
+import java.util.Set;
+import org.apache.clerezza.rdf.core.MGraph;
+
+/**
+ *
+ * @author reto
+ */
+class SimpleDiscobitsHandler extends AbstractDiscobitsHandler {
+    
+    private final MGraph mGraph;
+
+    public SimpleDiscobitsHandler(MGraph mGraph) {
+        this.mGraph = mGraph;
+    }
+
+    @Override
+    protected MGraph getMGraph() {
+        return mGraph;
+    }
+
+    @Override
+    protected Set<MetaDataGenerator> getMetaDataGenerators() {
+        return null;
+    }
+
+
+
+}

http://git-wip-us.apache.org/repos/asf/clerezza/blob/70220239/platform/content/src/main/java/org/apache/clerezza/platform/content/TitledContentRenderlet.java
----------------------------------------------------------------------
diff --git a/platform/content/src/main/java/org/apache/clerezza/platform/content/TitledContentRenderlet.java b/platform/content/src/main/java/org/apache/clerezza/platform/content/TitledContentRenderlet.java
new file mode 100644
index 0000000..094e773
--- /dev/null
+++ b/platform/content/src/main/java/org/apache/clerezza/platform/content/TitledContentRenderlet.java
@@ -0,0 +1,142 @@
+/*
+ * 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.clerezza.platform.content;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.PrintWriter;
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.SortedSet;
+import java.util.TreeSet;
+import javax.ws.rs.core.MediaType;
+import org.apache.clerezza.platform.typerendering.CallbackRenderer;
+import org.apache.clerezza.platform.typerendering.Renderlet;
+import org.apache.clerezza.rdf.core.NonLiteral;
+import org.apache.clerezza.rdf.core.Resource;
+import org.apache.clerezza.rdf.core.UriRef;
+import org.apache.clerezza.rdf.ontologies.DISCOBITS;
+import org.apache.clerezza.rdf.utils.GraphNode;
+
+/**
+ * A renderlet for rendering TitledContent. The contained elements are rendered
+ * calling back to the specified <code>Renderer</code>.
+ *
+ * This renderlet uses a thread-local variable to set the appropriate heading
+ * level (h1 - h6)
+ *
+ * @author rbn, mir
+ *
+ * @scr.component
+ * @scr.service interface="org.apache.clerezza.platform.typerendering.Renderlet"
+ */
+public class TitledContentRenderlet implements Renderlet {
+
+    private static ThreadLocal<Integer> headingLevel  = new ThreadLocal<Integer>() {
+
+        @Override
+        protected Integer initialValue() {
+            return 1;
+        }
+
+    };
+    @Override
+    public void render(GraphNode res, GraphNode context, Map<String, Object> sharedRenderingValues,
+            CallbackRenderer callbackRenderer,
+            URI renderingSpecification,
+            String mode,
+            MediaType mediaType, RequestProperties requestProperties,
+            OutputStream os) throws IOException {
+        PrintWriter writer = new PrintWriter(os);
+        List<GraphNode> containedNodes = getContainedNodes(res);
+        if (containedNodes.size() < 2) {
+            String nodeLabel = res.getNode() instanceof UriRef ?
+                ((UriRef)res.getNode()).getUnicodeString() : " Bnode";
+            writer.print(nodeLabel+": titled and/or content could not be found");
+            writer.flush();
+            return;
+        }
+        writer.print(getHeaderOpen());
+        writer.flush();
+        callbackRenderer.render(
+                containedNodes.get(0),
+                context, mode, os);
+        writer.println(getHeaderClose());
+        headingLevel.set(headingLevel.get()+1);
+        writer.print("<div class='tx-content'>");
+        writer.flush();
+        callbackRenderer.render(
+                containedNodes.get(1),
+                context, mode, os);
+        headingLevel.set(headingLevel.get()-1);
+        writer.println("</div>");
+        writer.flush();
+    }
+
+
+    private List<GraphNode> getContainedNodes(GraphNode titledContent) {
+        final SortedSet<GraphNode> entries = new TreeSet<GraphNode>(new Comparator<GraphNode>() {
+
+            @Override
+            public int compare(GraphNode o1, GraphNode o2) {
+                    int pos1 = getPos(o1);
+                    int pos2 = getPos(o2);
+                    return pos1 - pos2;
+            }
+            private int getPos(GraphNode o) {
+                try {
+                    return Integer.parseInt(o.getLiterals(DISCOBITS.pos).next().getLexicalForm());
+                } catch (NullPointerException e) {
+                    return -1;
+                }
+            }
+
+        });
+        final Iterator<Resource> entriesIter = titledContent.getObjects(DISCOBITS.contains);
+        while (entriesIter.hasNext()) {
+            Resource resource = entriesIter.next();
+            entries.add(new GraphNode((NonLiteral) resource,titledContent.getGraph()));
+        }
+        final List<GraphNode> result = new ArrayList<GraphNode>();
+        for (GraphNode graphNode : entries) {
+            Iterator<Resource> holded = graphNode.getObjects(DISCOBITS.holds);
+            if (!holded.hasNext()) {
+                throw new RuntimeException(
+                        "Titled Content must contain a first element: "+graphNode.getNodeContext());
+            }
+            result.add(new GraphNode(holded.next(),
+                    titledContent.getGraph()));
+        }
+        return result;
+    }
+
+    private String getHeaderOpen() {
+        final Integer level = headingLevel.get();
+        return level < 7 ? "<h"+level+">" : "<div class = \"heading\">";
+    }
+
+    private String getHeaderClose() {
+        final Integer level = headingLevel.get();
+        return level < 7 ? "</h"+level+">" : "</div>";
+    }
+}

http://git-wip-us.apache.org/repos/asf/clerezza/blob/70220239/platform/content/src/main/java/org/apache/clerezza/platform/content/WebDavUtils.java
----------------------------------------------------------------------
diff --git a/platform/content/src/main/java/org/apache/clerezza/platform/content/WebDavUtils.java b/platform/content/src/main/java/org/apache/clerezza/platform/content/WebDavUtils.java
new file mode 100644
index 0000000..aea5190
--- /dev/null
+++ b/platform/content/src/main/java/org/apache/clerezza/platform/content/WebDavUtils.java
@@ -0,0 +1,703 @@
+/*
+ * 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.clerezza.platform.content;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.locks.Lock;
+import javax.ws.rs.HttpMethod;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.Response;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.transform.Source;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerException;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.TransformerFactoryConfigurationError;
+import javax.xml.transform.dom.DOMResult;
+import org.apache.clerezza.rdf.core.Literal;
+import org.apache.clerezza.rdf.core.LiteralFactory;
+import org.apache.clerezza.rdf.core.Resource;
+import org.apache.clerezza.rdf.core.Triple;
+import org.apache.clerezza.rdf.core.TripleCollection;
+import org.apache.clerezza.rdf.core.UriRef;
+import org.apache.clerezza.rdf.core.impl.TripleImpl;
+import org.apache.clerezza.rdf.ontologies.DCTERMS;
+import org.apache.clerezza.rdf.ontologies.HIERARCHY;
+import org.apache.clerezza.rdf.ontologies.RDF;
+import org.apache.clerezza.rdf.utils.GraphNode;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+/**
+ *
+ * @author agron
+ */
+class WebDavUtils {
+
+    static final String infinite = "infinite";
+    static final String prop = "prop";
+    static final String allprop = "allprop";
+    static final String propname = "propname";
+    static final String propfind = "propfind";
+    static final String proppatch = "propertyupdate";
+    static final String set = "set";
+    static final String remove = "remove";
+    private static final String davUri = "DAV:";
+    private static final String multistat = "multistatus";
+    private static final String response = "response";
+    private static final String href = "href";
+    private static final String propstat = "propstat";
+    private static final String status = "status";
+
+    //WebDAV properties
+    private static final String creationdate = "creationdate";
+    private static final String displayname = "displayname";
+    private static final String getcontentlanguage = "getcontentlanguage";
+    private static final String getcontentlength = "getcontentlength";
+    private static final String getcontenttype = "getcontenttype";
+    private static final String getetag = "getetag";
+    private static final String getlastmodified = "getlastmodified";
+    private static final String lockdiscovery = "lockdiscovery";
+    private static final String resourcetype = "resourcetype";
+    private static final String supportedlock = "supportedlock";
+
+    private static final List<String> davProps = new ArrayList<String>(Arrays.asList(
+            creationdate, displayname, getcontentlanguage, getcontentlength,
+            getcontenttype, getetag, getlastmodified, lockdiscovery,
+            resourcetype, supportedlock));
+    
+    private static final List<String> protectedProps = new ArrayList<String>(Arrays.asList(
+            creationdate, getcontentlength, getetag, getlastmodified,
+            lockdiscovery, resourcetype, supportedlock));
+
+
+    /**
+     * Returns the {@link Node} from a given {@link Document}
+     * @param doc
+     * @param nodeName
+     * @return null if Node wasen't found
+     */
+    static Node getNode(Document doc, String nodeName){
+        NodeList nodes = doc.getElementsByTagNameNS(davUri, nodeName);
+        if(nodes.getLength() == 1){
+            return nodes.item(0);
+        }
+        return null;
+    }
+
+    /**
+     * @param node
+     * @return returns the first non Text node or null
+     */
+    static Node getFirstChild(Node node){
+        NodeList nodeList = node.getChildNodes();
+        for (int i = 0; i < nodeList.getLength(); i++) {
+            if(nodeList.item(i).getLocalName() != null){
+                return nodeList.item(i);
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Converts a {@link Source} to a {@link Document}
+     *
+     * @throws ParserConfigurationException
+     * @throws TransformerFactoryConfigurationError
+     * @throws TransformerException
+     */
+    static Document sourceToDocument(Source body)
+            throws ParserConfigurationException,
+            TransformerFactoryConfigurationError, TransformerException {
+        Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder()
+                .newDocument();
+        Transformer transformer = TransformerFactory.newInstance().newTransformer();
+        DOMResult result = new DOMResult(doc);
+        transformer.transform(body, result);
+        return (Document) result.getNode();
+    }
+
+    /**
+     * Returns the content of a requested header as a {@link String}
+     *
+     * @param headers
+     * @param header
+     *            header to be returned
+     * @return returns <code>null</code> if the requested header is empty
+     */
+    static String getHeaderAsString(HttpHeaders headers, String header) {
+        List<String> requestedHeader = headers.getRequestHeader(header);
+        if(requestedHeader == null){
+            return null;
+        }
+        Iterator<String> headerIterator = requestedHeader.iterator();
+        if (headerIterator.hasNext()) {
+            return headerIterator.next();
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * @param clazz
+     * @return returns an ok Response with a DAV: and an ALLOW: header
+     */
+    static Response options(Class<?> clazz){
+        Response.ResponseBuilder builder = Response.ok();
+        builder.header("Dav", "1");
+        Set<String> allow = new HashSet<String>();
+        Method[] methods = clazz.getMethods();
+        for (Method method : methods){
+            for (Annotation annotation : method.getAnnotations()){
+                HttpMethod httpMethod = annotation.annotationType()
+                        .getAnnotation(HttpMethod.class);
+                if(httpMethod != null){
+                    allow.add(httpMethod.value());
+                }
+            }
+        }
+        if (allow.isEmpty()) {
+            builder.header("Allow", "");
+        } else {
+            final Iterator<String> iterator = allow.iterator();
+            final StringBuffer buffer = new StringBuffer(iterator.next());
+            while (iterator.hasNext()) {
+                buffer.append(", ");
+                buffer.append(iterator.next());
+            }
+            builder.header("Allow", buffer.toString());
+        }
+        return builder.build();
+    }
+
+    /*------------------------------------------*
+     * Putting the properties in a DOM Document *
+     *------------------------------------------*/
+
+    static Document createResponseDoc(Map<UriRef, PropertyMap> resultMap)
+            throws ParserConfigurationException {
+        Document responseDoc = DocumentBuilderFactory.newInstance().
+                newDocumentBuilder().newDocument();
+        Set<UriRef> nodeNameSet = resultMap.keySet();
+
+        Element multistatElement = responseDoc.createElementNS(davUri,"D:" + multistat);
+        // add multistat element to response
+        responseDoc.appendChild(multistatElement);
+        for (UriRef nodeName : nodeNameSet) {
+            Element responseElement = responseDoc.createElementNS(davUri, "D:" + response);
+            // add response element to response Document
+            multistatElement.appendChild(responseElement);
+            PropertyMap propertyMap = resultMap.get(nodeName);
+            addElementsToResponse(propertyMap, responseElement, responseDoc, nodeName);
+        }
+        return responseDoc;
+    }
+
+    private static void addElementsToResponse(PropertyMap propertyMap,
+            Element responseElement, Document responseDoc, UriRef nodeName) {
+        Element hrefElement = responseDoc.createElementNS(davUri, "D:" + href);
+        hrefElement.setTextContent(nodeName.getUnicodeString());
+        // add hrefElement element to responseElement
+        responseElement.appendChild(hrefElement);
+        addPropsToPropstat(responseElement, propertyMap, responseDoc);
+
+    }
+
+    private static void addPropsToPropstat(Element responseElement, PropertyMap propertyMap,
+            Document responseDoc) {
+        Set<Property> props = propertyMap.keySet();
+        Element propFoundElement = responseDoc.createElementNS(davUri, "D:" + prop);
+        Element propNotFoundElement = responseDoc.createElementNS(davUri, "D:" + prop);
+        for(Property propVal : props){
+            String propName = propVal.prop;
+            String ns = propVal.ns;
+            String prf = ns.equalsIgnoreCase(davUri) ? "D:":"R:";
+            String value = propertyMap.get(propVal);
+            Element resultElement = responseDoc.createElementNS(ns, prf + propName);
+            if(value != null){
+                if (!(value.isEmpty())){
+                    if (value.equals("collection")) {
+                        resultElement.appendChild(responseDoc.createElementNS(
+                                davUri, "D:collection"));
+                    } else {
+                        resultElement.setTextContent(value);
+                    }
+                }
+                propFoundElement.appendChild(resultElement);
+            } else {
+                propNotFoundElement.appendChild(resultElement);
+            }
+        }
+        Element propstatFoundElement = responseDoc.createElementNS(davUri,
+                "D:" + propstat);
+        Element statusFoundElement = responseDoc.createElementNS(davUri,
+                "D:" + status);
+        propstatFoundElement.appendChild(propFoundElement);
+        statusFoundElement.setTextContent("HTTP/1.1 200 OK");
+        propstatFoundElement.appendChild(statusFoundElement);
+        responseElement.appendChild(propstatFoundElement);
+        if(propNotFoundElement.hasChildNodes()){
+            Element propstatNotFoundElement = responseDoc.createElementNS(davUri,
+                    "D:" + propstat);
+            Element statusNotFoundElement = responseDoc.createElementNS(davUri,
+                    "D:" + status);
+            propstatNotFoundElement.appendChild(propNotFoundElement);
+            statusNotFoundElement.setTextContent("HTTP/1.1 404 Not Found");
+            propstatNotFoundElement.appendChild(statusNotFoundElement);
+            responseElement.appendChild(propstatNotFoundElement);
+        }
+
+    }
+
+    /*------------------------------------------------------------*
+     * Get the properties from the CollectionNode and its members *
+     *------------------------------------------------------------*/
+
+    static Map<UriRef, PropertyMap> getPropsByName(NodeList children,
+            GraphNode node, String depthHeader, boolean includeValues) {
+        List<Property> requestedUserProps = new ArrayList<Property>();
+        List<Property> requestedDavProps = new ArrayList<Property>();
+
+        for (int i = 0; i < children.getLength(); i++) {
+            Node child = children.item(i);
+            String localName = child.getLocalName();
+            if(localName == null){
+                continue;
+            }
+            String nsUri = child.getNamespaceURI();
+            if (nsUri.equals(davUri)) {
+                requestedDavProps.add(new Property(nsUri, localName));
+            } else {
+                requestedUserProps.add(new Property(nsUri, localName));
+            }
+        }
+        Map<UriRef, PropertyMap> allprops = new HashMap<UriRef, PropertyMap>();
+
+        if (node.hasProperty(RDF.type, HIERARCHY.Collection)) {
+            return getCollectionProps(allprops, requestedUserProps, requestedDavProps,
+                    node, depthHeader, includeValues);
+        }else{
+            addNodeProperties(allprops, requestedUserProps, requestedDavProps,
+                    node, includeValues);
+            return allprops;
+        }
+
+    }
+    
+    static Map<UriRef, PropertyMap> getCollectionProps(Map<UriRef, PropertyMap> allprops,
+            List<Property> requestedUserProps, List<Property> requestedDavProps,
+            GraphNode collection, String depthHeader, boolean includeValues) {
+        if(allprops == null){
+            allprops = new HashMap<UriRef, PropertyMap>();
+        }
+        addNodeProperties(allprops, requestedUserProps, requestedDavProps, collection,
+                includeValues);
+        if (depthHeader.equals("1") || depthHeader.equals(infinite)) {
+            Iterator<GraphNode> membersIter = collection.getSubjectNodes(HIERARCHY.parent);
+            List<GraphNode> members = new ArrayList<GraphNode>();
+            while (membersIter.hasNext()) {
+                members.add(membersIter.next());
+            }
+            addMemberProps(allprops, requestedUserProps, requestedDavProps, members,
+                    depthHeader, includeValues);
+        }
+        return allprops;
+    }
+
+    private static void addMemberProps(Map<UriRef, PropertyMap> allprops,
+            List<Property> requestedUserProps, List<Property> requestedDavProps,
+            List<GraphNode> members, String depthHeader, boolean includeValues) {
+        for (GraphNode member : members) {
+            if (depthHeader.equals(infinite) && member.hasProperty(RDF.type, HIERARCHY.Collection)) {
+                getCollectionProps(allprops, requestedUserProps, requestedDavProps,
+                        member, depthHeader, includeValues);
+            } else {
+                addNodeProperties(allprops, requestedUserProps, requestedDavProps,
+                        member,    includeValues);
+            }
+        }
+    }
+
+    static void addNodeProperties(Map<UriRef, PropertyMap> allprops,
+            List<Property> requestedUserProps, List<Property> requestedDavProps,
+            GraphNode node,    boolean includeValues) {
+
+        if (requestedDavProps == null) {
+            requestedDavProps = new ArrayList<Property>();
+            for(String st : davProps){
+                requestedDavProps.add(new Property(davUri, st));
+            }
+        }
+        PropertyMap propertyMap = new PropertyMap();
+        if (includeValues) {
+            addDavProps(node, propertyMap, requestedDavProps);
+            addUserProps(node, propertyMap, requestedUserProps);
+        } else {
+            addDavPropsWithoutValues(propertyMap);
+            addUserPropsWithoutValues(node, propertyMap);
+        }
+        allprops.put((UriRef) node.getNode(), propertyMap);
+
+    }
+
+    private static void addUserProps(GraphNode node, PropertyMap propertyMap,
+            List<Property> requestedProps) {
+        Iterator<UriRef> userPropsIter;
+        Lock readLock = node.readLock();
+        readLock.lock(); 
+        try {
+            userPropsIter = node.getProperties();
+        } finally {
+            readLock.unlock();
+        }
+        Set<UriRef> userProps = new HashSet<UriRef>();
+        while (userPropsIter.hasNext()) {
+            userProps.add(userPropsIter.next());
+        }
+        userProps.remove(HIERARCHY.members);
+        if (requestedProps != null) {
+            for (Property requestedProp : requestedProps) {
+                UriRef predicate = new UriRef(requestedProp.value());
+                if (userProps.contains(predicate)) {
+                    readLock.lock();
+                    try {
+                        Iterator<Resource> value = node.getObjects(predicate);
+                        if (value.hasNext()) {
+                            propertyMap.put(requestedProp, getValue(value.next()));
+                        } else {
+                            propertyMap.put(requestedProp, "");
+                        }
+                    } finally {
+                        readLock.unlock();
+                    }
+                } else {
+                    propertyMap.put(requestedProp, null);
+                }
+            }
+        } else {
+            for (UriRef uri : userProps) {
+                String userProp = uri.getUnicodeString();
+                int index = userProp.lastIndexOf("#");
+                if (index == -1) {
+                    index = userProp.lastIndexOf("/");
+                }
+                Property property = new Property(userProp.substring(0, index + 1),
+                        userProp.substring(index + 1));
+
+                Iterator<Resource> value = node.getObjects(uri);
+                readLock.lock();
+                try {
+                    if (value.hasNext()) {
+                        propertyMap.put(property, getValue(value.next()));
+                    } else {
+                        propertyMap.put(property, "");
+                    }
+                } finally {
+                    readLock.unlock();
+                }
+            }
+        }
+    }
+
+    private static void addUserPropsWithoutValues(GraphNode node,
+            PropertyMap propertyMap) {
+        Iterator<UriRef> userPropsIter;
+        Lock readLock = node.readLock();
+        readLock.lock();
+        try {
+            userPropsIter = node.getProperties();
+        } finally {
+            readLock.unlock();
+        }
+        Set<UriRef> userProps = new HashSet<UriRef>();
+        while (userPropsIter.hasNext()) {
+            userProps.add(userPropsIter.next());
+        }
+        userProps.remove(HIERARCHY.members);
+        for (UriRef uri : userProps) {
+            String userProp = uri.getUnicodeString();
+            int index = userProp.lastIndexOf("#");
+            if (index == -1) {
+                index = userProp.lastIndexOf("/");
+            }
+            Property property = new Property(userProp.substring(0, index + 1),
+                    userProp.substring(index + 1));
+            propertyMap.put(property, "");
+        }
+    }
+
+    /**
+     * @param resource
+     * @return returns the unicode string of an UriRef or the lexical form of a
+     * Literal or the return value of a toString() on a BNode
+     */
+    private static String getValue(Resource resource){
+        if(resource instanceof UriRef){
+            return ((UriRef)resource).getUnicodeString();
+        }else if(resource instanceof Literal){
+            return ((Literal)resource).getLexicalForm();
+        }else {
+            return resource.toString();
+        }
+    }
+
+    /**
+     * FIXME find better implementation
+     * @param node
+     * @param propertyMap
+     * @param includeValues
+     * @param requestedProps
+     */
+    private static void addDavProps(GraphNode node, PropertyMap propertyMap,
+            List<Property> requestedProps) {
+        for (Property property : requestedProps) {
+            if (davProps.contains(property.prop)) {
+                if (property.prop.equalsIgnoreCase(displayname)) {
+                    propertyMap.put(property, getLastSection(((UriRef)node.getNode()).getUnicodeString()));
+                } else if (property.prop.equalsIgnoreCase(resourcetype)) {
+                    if (node.hasProperty(RDF.type, HIERARCHY.Collection)) {
+                        propertyMap.put(property, "collection");
+                    } else {
+                        propertyMap.put(property, "");
+                    }
+                } else if(property.prop.equalsIgnoreCase(creationdate)){
+                    Lock readLock = node.readLock();
+                    readLock.lock();
+                    try {
+                        Iterator<Resource> date = node.getObjects(DCTERMS.dateSubmitted);
+                        if (date.hasNext()) {
+                            String st = getValue(date.next());
+                            propertyMap.put(property, st);
+                        } else {
+                            propertyMap.put(property, "");
+                        }
+                    } finally {
+                        readLock.unlock();
+                    }
+                } else if(property.prop.equalsIgnoreCase(getlastmodified)){
+                    Lock readLock = node.readLock();
+                    readLock.lock();
+                    try {
+                        Iterator<Resource> date = node.getObjects(DCTERMS.modified);
+                        if (date.hasNext()) {
+                            String st = getValue(date.next());
+                            propertyMap.put(property, st);
+                        } else {
+                            propertyMap.put(property, "");
+                        }
+                    } finally {
+                        readLock.unlock();
+                    }
+                } else if(property.prop.equalsIgnoreCase(getcontenttype)){
+                    Lock readLock = node.readLock();
+                    readLock.lock();
+                    try {
+                        Iterator<Resource> mediaType = node.getObjects(DCTERMS.MediaType);
+                        if (mediaType.hasNext()) {
+                            String st = getValue(mediaType.next());
+                            propertyMap.put(property, st);
+                        } else {
+                            propertyMap.put(property, "");
+                        }
+                    } finally {
+                        readLock.unlock();
+                    }
+                } else {
+                    propertyMap.put(property, "");
+                }
+            } else {
+                propertyMap.put(property, null);
+            }
+        }
+    }
+
+    private static void addDavPropsWithoutValues(PropertyMap propertyMap) {
+        for (String property : davProps) {
+                propertyMap.put(new Property(davUri, property), "");
+        }
+    }
+
+    /*-------------------*
+     * Proppatch methods *
+     *-------------------*/
+
+    static Document modifyProperties(GraphNode hierarchyNode, NodeList propsToSet,
+            NodeList propsToRemove) throws ParserConfigurationException {
+        Document responseDoc = DocumentBuilderFactory.newInstance()
+                    .newDocumentBuilder().newDocument();
+        UriRef subject = (UriRef) hierarchyNode.getNode();
+        Element hrefElement = responseDoc.createElementNS(davUri, href);
+        hrefElement.setTextContent(subject.getUnicodeString());
+        Element multistatus = responseDoc.createElementNS(davUri, multistat);
+        Element responseElement = responseDoc.createElementNS(davUri, response);
+        Element propOk = responseDoc.createElementNS(davUri, prop);
+        Element propForbidden = responseDoc.createElementNS(davUri, prop);
+
+        responseDoc.appendChild(multistatus);
+        multistatus.appendChild(responseElement);
+        responseElement.appendChild(hrefElement);
+
+        Map<Property, String> setMap = getNodeListAsMap(propsToSet);
+        Map<Property, String> removeMap = getNodeListAsMap(propsToRemove);
+        TripleCollection contentGraph = hierarchyNode.getGraph();
+        for(Map.Entry<Property, String> entry : setMap.entrySet()){
+            Property property = entry.getKey();
+            if(property.ns.equalsIgnoreCase(davUri)){
+                if(protectedProps.contains(property.prop)){
+                    propForbidden.appendChild(responseDoc
+                            .createElementNS(davUri, property.prop));
+                } else {
+                    UriRef predicate = new UriRef(property.value());
+                    Lock writeLock = hierarchyNode.writeLock();
+                    writeLock.lock();
+                    try {
+                        Iterator<Resource> valIter = hierarchyNode.getObjects(predicate);
+                        replaceProp(subject, predicate, valIter, contentGraph, entry);
+                    } finally {
+                        writeLock.unlock();
+                    }
+                    propOk.appendChild(responseDoc.createElementNS(davUri, property.prop));
+                }
+            } else {
+                UriRef predicate = new UriRef(property.value());
+                Lock writeLock = hierarchyNode.writeLock();
+                writeLock.lock();
+                try {
+                    Iterator<Resource> valIter = hierarchyNode.getObjects(predicate);
+                    replaceProp(subject, predicate, valIter, contentGraph, entry);
+                } finally {
+                    writeLock.unlock();
+                }
+                propOk.appendChild(responseDoc.createElementNS(property.ns, "R:" + property.prop));
+            }
+        }
+
+        for(Map.Entry<Property, String> entry : removeMap.entrySet()){
+            Property property = entry.getKey();
+            if(davProps.contains(property.prop)){
+                propForbidden.appendChild(responseDoc
+                            .createElementNS(davUri, property.prop));
+            } else {
+                UriRef predicate = new UriRef(property.value());
+                Lock writeLock = hierarchyNode.writeLock();
+                writeLock.lock();
+                try {
+                    Iterator<Resource> valIter = hierarchyNode.getObjects(predicate);
+                    Set<Triple> triplesToBeRemoved = new HashSet<Triple>();
+                    while (valIter.hasNext()) {
+                        triplesToBeRemoved.add(new TripleImpl(subject, predicate, valIter.next()));
+                    }
+                    contentGraph.removeAll(triplesToBeRemoved);
+                } finally {
+                    writeLock.unlock();
+                }
+                propOk.appendChild(responseDoc.createElementNS(property.ns, property.prop));
+
+            }
+        }
+
+        if(propOk.hasChildNodes()){
+            Element propstatOk = responseDoc.createElementNS(davUri, propstat);
+            Element statusOk = responseDoc.createElementNS(davUri, status);
+            responseElement.appendChild(propstatOk);
+            propstatOk.appendChild(propOk);
+            propstatOk.appendChild(statusOk);
+            statusOk.setTextContent("HTTP/1.1 200 OK");
+        }
+        if(propForbidden.hasChildNodes()){
+            Element propstatForbidden = responseDoc.createElementNS(davUri, propstat);
+            Element statusForbidden = responseDoc.createElementNS(davUri, status);
+            responseElement.appendChild(propstatForbidden);
+            propstatForbidden.appendChild(propForbidden);
+            propstatForbidden.appendChild(statusForbidden);
+            statusForbidden.setTextContent("HTTP/1.1 403 Forbidden");
+        }
+
+        return responseDoc;
+    }
+
+    private static Map<Property, String> getNodeListAsMap(NodeList nodeList) {
+        if (nodeList == null) {
+            return new HashMap<Property, String>();
+        }
+        Map<Property, String> result = new HashMap<Property, String>();
+        for (int i = 0; i < nodeList.getLength(); i++) {
+            Node node = nodeList.item(i);
+            String propName = node.getLocalName();
+            if (propName != null) {
+                String nsUri = node.getNamespaceURI();
+                result.put(new Property(nsUri, propName), node.getTextContent());
+            }
+        }
+        return result;
+    }
+
+    private static void replaceProp(UriRef subject, UriRef predicate,
+            Iterator<Resource> valIter, TripleCollection contentGraph,
+            Map.Entry<Property, String> entry) {
+        LiteralFactory fac = LiteralFactory.getInstance();
+        Set<Triple> triplesToBeRemoved = new HashSet<Triple>();
+        if (valIter.hasNext()) {
+            triplesToBeRemoved.add(new TripleImpl(subject, predicate, valIter.next()));
+        }
+        contentGraph.removeAll(triplesToBeRemoved);
+        contentGraph.add(new TripleImpl(subject, predicate,
+                fac.createTypedLiteral(entry.getValue())));
+    }
+
+    private static String getLastSection(String s) {
+        return s.substring(s.lastIndexOf('/', s.length()-2));
+    }
+
+    /**
+     * Helper class whicht is a {@link HashMap} that maps {@link Property} to a {@link String}
+     * @author ali
+     */
+    @SuppressWarnings("serial")
+    static class PropertyMap extends HashMap<Property, String> {
+    }
+
+    static class Property {
+        final String ns;
+        final String prop;
+
+        public Property(String ns, String prop) {
+            this.ns = ns;
+            this.prop = prop;
+        }
+
+        public String value(){
+            return ns+prop;
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/clerezza/blob/70220239/platform/content/src/main/java/org/apache/clerezza/platform/content/collections/CollectionCreator.java
----------------------------------------------------------------------
diff --git a/platform/content/src/main/java/org/apache/clerezza/platform/content/collections/CollectionCreator.java b/platform/content/src/main/java/org/apache/clerezza/platform/content/collections/CollectionCreator.java
new file mode 100644
index 0000000..012d917
--- /dev/null
+++ b/platform/content/src/main/java/org/apache/clerezza/platform/content/collections/CollectionCreator.java
@@ -0,0 +1,74 @@
+/*
+ * 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.clerezza.platform.content.collections;
+
+import java.net.URI;
+import java.net.URISyntaxException;
+import org.apache.clerezza.rdf.core.MGraph;
+import org.apache.clerezza.rdf.core.UriRef;
+import org.apache.clerezza.rdf.core.impl.TripleImpl;
+import org.apache.clerezza.rdf.ontologies.HIERARCHY;
+import org.apache.clerezza.rdf.ontologies.RDF;
+
+/**
+ * Creates the collections containing a resource in an underlying MGraph
+ *
+ * @author reto
+ */
+public class CollectionCreator {
+
+    private MGraph mGraph;
+
+    public CollectionCreator(MGraph mGraph) {
+        this.mGraph = mGraph;
+    }
+
+    public void createContainingCollections(UriRef uriRef) {
+        try {
+            URI uri = new URI(uriRef.getUnicodeString());
+            if (uri.getHost() == null) {
+                throw new IllegalArgumentException("Host name missing in " + uriRef);
+            }
+            String[] pathSections = uri.getRawPath().split("/");
+            for (int i = pathSections.length - 1; i >= 0 ; i--) {
+                String section = pathSections[i];
+                if (section.length() == 0) {
+                    if (i == 0) {
+                        return;
+                    } else {
+                        throw new IllegalArgumentException(
+                                uriRef+" contains consequtive slashes in path section");
+                    }
+                }
+                final String unicodeString = uriRef.getUnicodeString();
+                int lastIndexOf = unicodeString.lastIndexOf(section);
+                UriRef parentUriRef = new UriRef(unicodeString.substring(0, lastIndexOf));
+                mGraph.add(new TripleImpl(uriRef, HIERARCHY.parent, parentUriRef));
+                mGraph.add(new TripleImpl(parentUriRef, RDF.type, HIERARCHY.Collection));
+                uriRef = parentUriRef;
+
+            }
+        } catch (URISyntaxException ex) {
+            throw new IllegalArgumentException(ex);
+        }
+    }
+
+
+}

http://git-wip-us.apache.org/repos/asf/clerezza/blob/70220239/platform/content/src/main/java/org/apache/clerezza/platform/content/genericmetadata/GenericMetaDataGenerator.java
----------------------------------------------------------------------
diff --git a/platform/content/src/main/java/org/apache/clerezza/platform/content/genericmetadata/GenericMetaDataGenerator.java b/platform/content/src/main/java/org/apache/clerezza/platform/content/genericmetadata/GenericMetaDataGenerator.java
new file mode 100644
index 0000000..7881a34
--- /dev/null
+++ b/platform/content/src/main/java/org/apache/clerezza/platform/content/genericmetadata/GenericMetaDataGenerator.java
@@ -0,0 +1,53 @@
+/*
+ * 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.clerezza.platform.content.genericmetadata;
+
+import java.util.Date;
+import javax.ws.rs.core.MediaType;
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Service;
+import org.apache.clerezza.rdf.utils.GraphNode;
+import org.apache.clerezza.rdf.metadata.MetaDataGenerator;
+import org.apache.clerezza.rdf.core.LiteralFactory;
+import org.apache.clerezza.rdf.core.TypedLiteral;
+import org.apache.clerezza.rdf.ontologies.DCTERMS;
+
+/**
+ * This class generates metadata about assets.
+ *
+ * @author tio
+ */
+@Component()
+@Service(MetaDataGenerator.class)
+public class GenericMetaDataGenerator implements MetaDataGenerator {
+
+    @Override
+    public void generate(GraphNode node, byte[] data, MediaType mediaType) {
+        TypedLiteral dateLiteral = LiteralFactory.getInstance()
+                    .createTypedLiteral(new Date());
+        if(node.getObjects(DCTERMS.dateSubmitted).hasNext()) {
+            if(node.getObjects(DCTERMS.modified).hasNext()) {
+                node.deleteProperties(DCTERMS.modified);
+            }
+            node.addProperty(DCTERMS.modified, dateLiteral);
+        } else {
+            node.addProperty(DCTERMS.dateSubmitted, dateLiteral);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/clerezza/blob/70220239/platform/content/src/main/java/org/apache/clerezza/platform/content/webdav/COPY.java
----------------------------------------------------------------------
diff --git a/platform/content/src/main/java/org/apache/clerezza/platform/content/webdav/COPY.java b/platform/content/src/main/java/org/apache/clerezza/platform/content/webdav/COPY.java
new file mode 100644
index 0000000..9b7c666
--- /dev/null
+++ b/platform/content/src/main/java/org/apache/clerezza/platform/content/webdav/COPY.java
@@ -0,0 +1,38 @@
+/*
+ * 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.clerezza.platform.content.webdav;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+import javax.ws.rs.HttpMethod;
+
+/**
+ * Indicates that the annotated method responds to HTTP COPY requests
+ * @author ali
+ */
+
+@Target({ElementType.METHOD})
+@Retention(RetentionPolicy.RUNTIME)
+@HttpMethod("COPY")
+public @interface COPY {
+
+}

http://git-wip-us.apache.org/repos/asf/clerezza/blob/70220239/platform/content/src/main/java/org/apache/clerezza/platform/content/webdav/LOCK.java
----------------------------------------------------------------------
diff --git a/platform/content/src/main/java/org/apache/clerezza/platform/content/webdav/LOCK.java b/platform/content/src/main/java/org/apache/clerezza/platform/content/webdav/LOCK.java
new file mode 100644
index 0000000..8fb4630
--- /dev/null
+++ b/platform/content/src/main/java/org/apache/clerezza/platform/content/webdav/LOCK.java
@@ -0,0 +1,38 @@
+/*
+ * 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.clerezza.platform.content.webdav;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+import javax.ws.rs.HttpMethod;
+
+/**
+ * Indicates that the annotated method responds to HTTP LOCK requests
+ * @author ali
+ */
+
+@Target({ElementType.METHOD})
+@Retention(RetentionPolicy.RUNTIME)
+@HttpMethod("LOCK")
+public @interface LOCK {
+
+}


Mime
View raw message