You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@clerezza.apache.org by re...@apache.org on 2015/04/14 15:13:15 UTC
[40/87] [abbrv] [partial] clerezza git commit: CLEREZZA-966: removed
platform. prefix of folder names
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 {
+
+}