You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@abdera.apache.org by da...@apache.org on 2007/10/29 22:59:42 UTC

svn commit: r589880 - in /incubator/abdera/java/trunk: ./ jcr/ jcr/src/ jcr/src/main/ jcr/src/main/java/ jcr/src/main/java/org/ jcr/src/main/java/org/apache/ jcr/src/main/java/org/apache/abdera/ jcr/src/main/java/org/apache/abdera/jcr/ jcr/src/main/res...

Author: dandiep
Date: Mon Oct 29 14:59:40 2007
New Revision: 589880

URL: http://svn.apache.org/viewvc?rev=589880&view=rev
Log:
Add a basic JCR based provider. Limitations:
 - no transactions right now
 - no media entries yet (soon, I need them)

Various cleanups to CollectionProvider bits to make this work. Including,
the addition of the RequestContext to most methods per the mailing list discussion.



Added:
    incubator/abdera/java/trunk/jcr/
    incubator/abdera/java/trunk/jcr/pom.xml   (with props)
    incubator/abdera/java/trunk/jcr/src/
    incubator/abdera/java/trunk/jcr/src/main/
    incubator/abdera/java/trunk/jcr/src/main/java/
    incubator/abdera/java/trunk/jcr/src/main/java/org/
    incubator/abdera/java/trunk/jcr/src/main/java/org/apache/
    incubator/abdera/java/trunk/jcr/src/main/java/org/apache/abdera/
    incubator/abdera/java/trunk/jcr/src/main/java/org/apache/abdera/jcr/
    incubator/abdera/java/trunk/jcr/src/main/java/org/apache/abdera/jcr/JcrCollectionProvider.java   (with props)
    incubator/abdera/java/trunk/jcr/src/main/resources/
    incubator/abdera/java/trunk/jcr/src/test/
    incubator/abdera/java/trunk/jcr/src/test/java/
    incubator/abdera/java/trunk/jcr/src/test/java/org/
    incubator/abdera/java/trunk/jcr/src/test/java/org/apache/
    incubator/abdera/java/trunk/jcr/src/test/java/org/apache/abdera/
    incubator/abdera/java/trunk/jcr/src/test/java/org/apache/abdera/jcr/
    incubator/abdera/java/trunk/jcr/src/test/java/org/apache/abdera/jcr/JcrCollectionProviderTest.java   (with props)
    incubator/abdera/java/trunk/jcr/src/test/resources/
Modified:
    incubator/abdera/java/trunk/pom.xml
    incubator/abdera/java/trunk/server/src/main/java/org/apache/abdera/protocol/server/CollectionProvider.java
    incubator/abdera/java/trunk/server/src/main/java/org/apache/abdera/protocol/server/impl/AbstractCollectionProvider.java
    incubator/abdera/java/trunk/server/src/main/java/org/apache/abdera/protocol/server/impl/AbstractWorkspaceProvider.java
    incubator/abdera/java/trunk/server/src/test/java/org/apache/abdera/protocol/server/CustomerContentProvider.java

Added: incubator/abdera/java/trunk/jcr/pom.xml
URL: http://svn.apache.org/viewvc/incubator/abdera/java/trunk/jcr/pom.xml?rev=589880&view=auto
==============================================================================
--- incubator/abdera/java/trunk/jcr/pom.xml (added)
+++ incubator/abdera/java/trunk/jcr/pom.xml Mon Oct 29 14:59:40 2007
@@ -0,0 +1,83 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  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.  For additional information regarding
+  copyright in this work, please see the NOTICE file in the top level
+  directory of this distribution. -->
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+  <parent>
+    <groupId>org.apache.abdera</groupId>
+    <artifactId>abdera</artifactId>
+    <version>0.4.0-incubating-SNAPSHOT</version>
+  </parent>
+  <modelVersion>4.0.0</modelVersion>
+  <artifactId>abdera-jcr</artifactId>
+  <packaging>jar</packaging>
+  <name>Abdera JCR Server</name>
+  <version>0.4.0-incubating-SNAPSHOT</version>
+  <description>JCR AtomPub Server implementation Abdera</description>
+  <inceptionYear>2006</inceptionYear>
+  <url>http://incubator.apache.org/abdera</url>
+  <scm>
+    <connection>
+      scm:svn:http://svn.apache.org/repos/asf/incubator/abdera/java/trunk/jcr/
+    </connection>
+    <developerConnection>
+      scm:svn:https://svn.apache.org/repos/asf/incubator/abdera/java/trunk/jcr/
+    </developerConnection>
+    <url>
+      http://svn.apache.org/repos/asf/incubator/abdera/java/trunk/jcr/
+    </url>
+  </scm>
+  
+  <dependencies>
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+    </dependency>
+
+    <dependency>
+      <groupId>org.apache.abdera</groupId>
+      <artifactId>abdera-server</artifactId>
+      <version>0.4.0-incubating-SNAPSHOT</version>
+    </dependency>
+    
+    <dependency>
+      <groupId>org.apache.abdera</groupId>
+      <artifactId>abdera-client</artifactId>
+      <version>0.4.0-incubating-SNAPSHOT</version>
+      <scope>test</scope>
+    </dependency>
+    
+    <dependency>
+      <groupId>org.apache.jackrabbit</groupId>
+      <artifactId>jackrabbit-core</artifactId>
+      <version>1.3.1</version>
+    </dependency>
+
+    <dependency>
+      <groupId>org.mortbay.jetty</groupId>
+      <artifactId>jetty</artifactId>
+      <version>6.1.5</version>
+    </dependency>
+
+    <dependency>
+      <groupId>org.slf4j</groupId>
+      <artifactId>slf4j-jdk14</artifactId>
+      <version>1.4.3</version>
+    </dependency>
+  </dependencies>
+</project>

Propchange: incubator/abdera/java/trunk/jcr/pom.xml
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: incubator/abdera/java/trunk/jcr/pom.xml
------------------------------------------------------------------------------
    svn:keywords = Rev Date

Propchange: incubator/abdera/java/trunk/jcr/pom.xml
------------------------------------------------------------------------------
    svn:mime-type = text/xml

Added: incubator/abdera/java/trunk/jcr/src/main/java/org/apache/abdera/jcr/JcrCollectionProvider.java
URL: http://svn.apache.org/viewvc/incubator/abdera/java/trunk/jcr/src/main/java/org/apache/abdera/jcr/JcrCollectionProvider.java?rev=589880&view=auto
==============================================================================
--- incubator/abdera/java/trunk/jcr/src/main/java/org/apache/abdera/jcr/JcrCollectionProvider.java (added)
+++ incubator/abdera/java/trunk/jcr/src/main/java/org/apache/abdera/jcr/JcrCollectionProvider.java Mon Oct 29 14:59:40 2007
@@ -0,0 +1,444 @@
+package org.apache.abdera.jcr;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Calendar;
+import java.util.Collections;
+import java.util.Date;
+import java.util.List;
+
+import javax.jcr.AccessDeniedException;
+import javax.jcr.Credentials;
+import javax.jcr.InvalidItemStateException;
+import javax.jcr.ItemExistsException;
+import javax.jcr.ItemNotFoundException;
+import javax.jcr.Node;
+import javax.jcr.NodeIterator;
+import javax.jcr.PathNotFoundException;
+import javax.jcr.Property;
+import javax.jcr.PropertyIterator;
+import javax.jcr.Repository;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import javax.jcr.Value;
+import javax.jcr.ValueFormatException;
+import javax.jcr.lock.LockException;
+import javax.jcr.nodetype.ConstraintViolationException;
+import javax.jcr.nodetype.NoSuchNodeTypeException;
+import javax.jcr.query.Query;
+import javax.jcr.query.QueryManager;
+import javax.jcr.query.QueryResult;
+import javax.jcr.version.VersionException;
+
+import org.apache.abdera.i18n.iri.IRI;
+import org.apache.abdera.model.Content;
+import org.apache.abdera.model.Person;
+import org.apache.abdera.model.Text;
+import org.apache.abdera.protocol.server.RequestContext;
+import org.apache.abdera.protocol.server.ResponseContext;
+import org.apache.abdera.protocol.server.RequestContext.Scope;
+import org.apache.abdera.protocol.server.impl.AbstractCollectionProvider;
+import org.apache.abdera.protocol.server.impl.EmptyResponseContext;
+import org.apache.abdera.protocol.server.impl.ResponseContextException;
+import org.apache.abdera.protocol.util.EncodingUtil;
+
+public class JcrCollectionProvider extends AbstractCollectionProvider<Node> {
+
+  private static final String TITLE = "title";
+
+  private static final String SUMMARY = "summary";
+
+  private static final String ENTRY = "entry";
+
+  private static final String UPDATED = "updated";
+
+  private static final String AUTHOR = "author";
+
+  private static final String AUTHOR_EMAIL = "author.email";
+
+  private static final String AUTHOR_LANGUAGE = "author.language";
+
+  private static final String AUTHOR_NAME = "author.name";
+
+  private static final String CONTENT = "content";
+
+  private static final String RESOURCE_NAME = "resourceName";
+
+  private static final String SESSION = "jcrSession";
+
+  private Repository repository;
+
+  private String collectionNodePath;
+
+  private String id;
+
+  private String title;
+
+  private String author;
+
+  private Credentials credentials;
+
+  private String collectionNodeId;
+
+  public JcrCollectionProvider(String title, String author, String collectionNodePath, Repository repository,
+                               Credentials credentials) throws RepositoryException {
+    super();
+    this.title = title;
+    this.author = author;
+    this.collectionNodePath = collectionNodePath;
+    this.credentials = credentials;
+    this.repository = repository;
+  }
+
+  public void initialize() throws RepositoryException {
+    Session session = createSession();
+
+    Node collectionNode = null;
+    try {
+      collectionNode = session.getRootNode().getNode(collectionNodePath);
+    } catch (PathNotFoundException e) {
+      collectionNode = session.getRootNode().addNode(collectionNodePath);
+      collectionNode.addMixin("mix:referenceable");
+      session.save();
+    }
+
+    this.collectionNodeId = collectionNode.getUUID();
+    this.id = "urn:" + collectionNodeId;
+
+    session.logout();
+  }
+
+  @Override
+  public void begin(RequestContext request) throws ResponseContextException {
+    super.begin(request);
+
+    try {
+      Session session = createSession();
+
+      request.setAttribute(Scope.REQUEST, SESSION, session);
+    } catch (RepositoryException e) {
+      throw new ResponseContextException(500, e);
+    }
+  }
+
+  @Override
+  public void end(RequestContext request, ResponseContext response) {
+    // Logout of the JCR session
+    Session session = getSession(request);
+    if (session != null) {
+     // session.logout();
+    }
+
+    super.end(request, response);
+  }
+
+  protected Session createSession() throws RepositoryException {
+    return repository.login(credentials);
+  }
+
+  @Override
+  public Node createEntry(String title, IRI id, String summary, Date updated, List<Person> authors,
+                          Content content, RequestContext request) throws ResponseContextException {
+    try {
+      Session session = getSession(request);
+
+      Node collectionNode = session.getNodeByUUID(collectionNodeId);
+      Node entry = collectionNode.addNode(ENTRY);
+      entry.addMixin("mix:referenceable");
+
+      return mapEntryToNode(entry, title, summary, updated, authors, content, session);
+    } catch (RepositoryException e) {
+      throw new ResponseContextException(500, e);
+    }
+  }
+
+  private Node mapEntryToNode(Node entry, String title, String summary, Date updated, List<Person> authors,
+                              Content content, Session session) throws ResponseContextException,
+    ValueFormatException, VersionException, LockException, ConstraintViolationException, RepositoryException,
+    ItemExistsException, PathNotFoundException, AccessDeniedException, InvalidItemStateException,
+    NoSuchNodeTypeException {
+    if (title == null) {
+      EmptyResponseContext ctx = new EmptyResponseContext(500);
+      ctx.setStatusText("Entry title cannot be empty.");
+      throw new ResponseContextException(ctx);
+    }
+
+    entry.setProperty(TITLE, title);
+
+    // TODO: figure out a full proof way to check for entries with this same
+    // resource name
+    String resourceName = EncodingUtil.sanitize(title);
+    entry.setProperty(RESOURCE_NAME, resourceName);
+
+    entry.setProperty(SUMMARY, summary);
+
+    Calendar upCal = Calendar.getInstance();
+    upCal.setTime(updated);
+    entry.setProperty(UPDATED, upCal);
+
+    for (Person p : authors) {
+      Node addNode = entry.addNode(AUTHOR);
+      addNode.setProperty(AUTHOR_EMAIL, p.getEmail());
+      addNode.setProperty(AUTHOR_LANGUAGE, p.getLanguage());
+      addNode.setProperty(AUTHOR_NAME, p.getName());
+    }
+
+    if (content != null) {
+      entry.setProperty(CONTENT, content.getText());
+    }
+
+    if (summary != null) {
+      entry.setProperty(SUMMARY, summary);
+    }
+    
+    session.save();
+    
+    return entry;
+  }
+
+  private Session getSession(RequestContext request) {
+    return (Session)request.getAttribute(Scope.REQUEST, SESSION);
+  }
+
+  @Override
+  public void deleteEntry(String resourceName, RequestContext request) throws ResponseContextException {
+    try {
+      Session session = getSession(request);
+
+      Node node = getNode(session, resourceName);
+
+      node.remove();
+    } catch (RepositoryException e) {
+      throw new ResponseContextException(500, e);
+    }
+
+  }
+
+  private Node getNode(Session session, String resourceName) throws ResponseContextException,
+    RepositoryException {
+    QueryManager qm = session.getWorkspace().getQueryManager();
+
+    StringBuffer qStr = new StringBuffer();
+    qStr.append("//*[@jcr:uuid='").append(collectionNodeId).append("']/entry[@").append(RESOURCE_NAME)
+      .append("='").append(resourceName).append("']");
+
+    System.out.println("QUery" + qStr.toString());
+    
+    Query query = qm.createQuery(qStr.toString(), Query.XPATH);
+
+    QueryResult execute = query.execute();
+
+    NodeIterator nodes = execute.getNodes();
+    if (!nodes.hasNext()) {
+      throw new ResponseContextException(404);
+    }
+
+    return nodes.nextNode();
+  }
+
+  /** Recursively outputs the contents of the given node. */
+  public static void dump(Node node) throws RepositoryException {
+      // First output the node path
+      System.out.println(node.getPath());
+      // Skip the virtual (and large!) jcr:system subtree
+      if (node.getName().equals("jcr:system")) {
+          return;
+      }
+
+      // Then output the properties
+      PropertyIterator properties = node.getProperties();
+      while (properties.hasNext()) {
+          Property property = properties.nextProperty();
+          if (property.getDefinition().isMultiple()) {
+              // A multi-valued property, print all values
+              Value[] values = property.getValues();
+              for (int i = 0; i < values.length; i++) {
+                  System.out.println(
+                      property.getPath() + " = " + values[i].getString());
+              }
+          } else {
+              // A single-valued property
+              System.out.println(
+                  property.getPath() + " = " + property.getString());
+          }
+      }
+
+      // Finally output all the child nodes recursively
+      NodeIterator nodes = node.getNodes();
+      while (nodes.hasNext()) {
+          dump(nodes.nextNode());
+      }
+  }
+
+  @Override
+  public String getAuthor() throws ResponseContextException {
+    return author;
+  }
+
+  @Override
+  public List<Person> getAuthors(Node entry, RequestContext request) throws ResponseContextException {
+    try {
+      ArrayList<Person> authors = new ArrayList<Person>();
+      for (NodeIterator nodes = entry.getNodes(); nodes.hasNext();) {
+        Node n = nodes.nextNode();
+        
+        if (n.getName().equals(AUTHOR)) {
+          Person author = request.getAbdera().getFactory().newAuthor();
+          author.setName(getStringOrNull(entry, AUTHOR_NAME));
+          author.setEmail(getStringOrNull(entry, AUTHOR_EMAIL));
+          author.setLanguage(getStringOrNull(entry, AUTHOR_LANGUAGE));
+          authors.add(author);
+        }
+      }
+      return authors;
+    } catch (RepositoryException e) {
+      throw new ResponseContextException(500, e);
+    }
+  }
+
+  @Override
+  public Object getContent(Node entry) throws ResponseContextException {
+    return getStringOrNull(entry, CONTENT);
+  }
+
+  @Override
+  public Iterable<Node> getEntries(RequestContext request) throws ResponseContextException {
+    ArrayList<Node> entries = new ArrayList<Node>();
+
+    Session session = getSession(request);
+    try {
+      Node n = session.getNodeByUUID(collectionNodeId);
+      for (NodeIterator nodes = n.getNodes(); nodes.hasNext();) {
+        entries.add(nodes.nextNode());
+      }
+    } catch (RepositoryException e) {
+      throw new ResponseContextException(500, e);
+    }
+
+    return entries;
+  }
+
+  @Override
+  public Node getEntry(String resourceName, RequestContext request) throws ResponseContextException {
+    try {
+      return getNode(getSession(request), resourceName);
+    } catch (RepositoryException e) {
+      throw new ResponseContextException(500, e);
+    }
+  }
+
+  @Override
+  public Node getEntryFromId(String id, RequestContext request) throws ResponseContextException {
+    if (!id.startsWith("urn:")) {
+      EmptyResponseContext res = new EmptyResponseContext(404);
+      res.setStatusText("Invalid entry id.");
+      throw new ResponseContextException(res);
+    }
+    
+    id = id.substring(4);
+    
+    try {
+      return getSession(request).getNodeByUUID(id);
+    } catch (RepositoryException e) {
+      throw new ResponseContextException(500, e);
+    }
+  }
+
+  @Override
+  public String getId() {
+    return id;
+  }
+
+  @Override
+  public String getId(Node entry) throws ResponseContextException {
+    try {
+      return "urn:" + entry.getUUID();
+    } catch (RepositoryException e) {
+      throw new ResponseContextException(500, e);
+    }
+  }
+
+  @Override
+  public String getName(Node entry) throws ResponseContextException {
+    return getStringOrNull(entry, RESOURCE_NAME);
+  }
+
+  @Override
+  public String getSummary(Node entry) {
+    return getStringOrNull(entry, SUMMARY);
+  }
+
+  @Override
+  public String getTitle() {
+    return title;
+  }
+
+  @Override
+  public String getTitle(Node entry) throws ResponseContextException {
+    return getStringOrNull(entry, TITLE);
+  }
+
+  @Override
+  public Date getUpdated(Node entry) throws ResponseContextException {
+    return getDateOrNull(entry, UPDATED).getTime();
+  }
+
+  @Override
+  public void updateEntry(Node entry, String title, Date updated,
+                          List<Person> authors, String summary,
+                          Content content, RequestContext request) throws ResponseContextException {
+    Session session = getSession(request);
+    try {
+      mapEntryToNode(entry, title, summary, updated, authors, content, session);
+    } catch (RepositoryException e) {
+      throw new ResponseContextException(500, e);
+    }
+  }
+
+  public static String getStringOrNull(Node node, String propName) {
+    try {
+      Value v = getValueOrNull(node, propName);
+      if (v != null) {
+        return v.getString();
+      }
+    } catch (ValueFormatException e) {
+      throw new RuntimeException(e);
+    } catch (RepositoryException e) {
+      throw new RuntimeException(e);
+    }
+
+    return null;
+  }
+
+  public static Calendar getDateOrNull(Node node, String propName) {
+    try {
+      Value v = getValueOrNull(node, propName);
+      if (v != null) {
+        return v.getDate();
+      }
+    } catch (ValueFormatException e) {
+      throw new RuntimeException(e);
+    } catch (RepositoryException e) {
+      throw new RuntimeException(e);
+    }
+
+    return null;
+  }
+
+  public static Value getValueOrNull(Node node, String propName) throws PathNotFoundException,
+    RepositoryException {
+    Property p = null;
+    try {
+      p = node.getProperty(propName);
+    } catch (PathNotFoundException e) {
+      return null;
+    }
+
+    if (p == null) {
+      return null;
+    }
+
+    return p.getValue();
+  }
+
+}

Propchange: incubator/abdera/java/trunk/jcr/src/main/java/org/apache/abdera/jcr/JcrCollectionProvider.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: incubator/abdera/java/trunk/jcr/src/main/java/org/apache/abdera/jcr/JcrCollectionProvider.java
------------------------------------------------------------------------------
    svn:executable = *

Propchange: incubator/abdera/java/trunk/jcr/src/main/java/org/apache/abdera/jcr/JcrCollectionProvider.java
------------------------------------------------------------------------------
    svn:keywords = Rev Date

Added: incubator/abdera/java/trunk/jcr/src/test/java/org/apache/abdera/jcr/JcrCollectionProviderTest.java
URL: http://svn.apache.org/viewvc/incubator/abdera/java/trunk/jcr/src/test/java/org/apache/abdera/jcr/JcrCollectionProviderTest.java?rev=589880&view=auto
==============================================================================
--- incubator/abdera/java/trunk/jcr/src/test/java/org/apache/abdera/jcr/JcrCollectionProviderTest.java (added)
+++ incubator/abdera/java/trunk/jcr/src/test/java/org/apache/abdera/jcr/JcrCollectionProviderTest.java Mon Oct 29 14:59:40 2007
@@ -0,0 +1,198 @@
+package org.apache.abdera.jcr;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.jcr.Node;
+import javax.jcr.NodeIterator;
+import javax.jcr.PathNotFoundException;
+import javax.jcr.Repository;
+import javax.jcr.Session;
+import javax.jcr.SimpleCredentials;
+
+import org.apache.abdera.Abdera;
+import org.apache.abdera.factory.Factory;
+import org.apache.abdera.i18n.iri.IRI;
+import org.apache.abdera.model.Base;
+import org.apache.abdera.model.Entry;
+import org.apache.abdera.model.Feed;
+import org.apache.abdera.model.Person;
+import org.apache.abdera.protocol.client.AbderaClient;
+import org.apache.abdera.protocol.client.ClientResponse;
+import org.apache.abdera.protocol.client.RequestOptions;
+import org.apache.abdera.protocol.server.CollectionProvider;
+import org.apache.abdera.protocol.server.ServiceContext;
+import org.apache.abdera.protocol.server.TargetType;
+import org.apache.abdera.protocol.server.WorkspaceInfo;
+import org.apache.abdera.protocol.server.impl.DefaultServiceContext;
+import org.apache.abdera.protocol.server.impl.RegexTargetResolver;
+import org.apache.abdera.protocol.server.impl.SimpleWorkspaceInfo;
+import org.apache.abdera.protocol.server.impl.SingletonProviderManager;
+import org.apache.abdera.protocol.server.impl.WorkspaceProvider;
+import org.apache.abdera.protocol.server.servlet.AbderaServlet;
+import org.apache.jackrabbit.core.TransientRepository;
+import org.mortbay.jetty.Server;
+import org.mortbay.jetty.servlet.Context;
+import org.mortbay.jetty.servlet.ServletHolder;
+
+import junit.framework.TestCase;
+
+public class JcrCollectionProviderTest extends TestCase {
+
+    private Server server;
+    private DefaultServiceContext abderaServiceContext;
+    private Repository repository;
+
+    @Override
+    protected void setUp() throws Exception {
+      super.setUp();
+      
+      abderaServiceContext = new DefaultServiceContext();
+
+      RegexTargetResolver resolver = new RegexTargetResolver();
+      resolver.setPattern("/acme(\\?[^#]*)?", TargetType.TYPE_SERVICE);
+      resolver.setPattern("/acme/feed(\\?[^#]*)?", TargetType.TYPE_COLLECTION);
+      resolver.setPattern("/acme/feed/([^/#?]+)(\\?[^#]*)?", TargetType.TYPE_ENTRY);
+      abderaServiceContext.setTargetResolver(resolver);
+      
+      SingletonProviderManager pm = new SingletonProviderManager();
+      abderaServiceContext.setProviderManager(pm);
+
+      WorkspaceProvider wp = new WorkspaceProvider();
+
+      SimpleWorkspaceInfo wi = new SimpleWorkspaceInfo();
+      wi.setId("acme");
+      
+      repository = new TransientRepository();
+      JcrCollectionProvider cp = 
+          new JcrCollectionProvider("My Entries", 
+                                    "Apache Abdera", 
+                                    "entries", 
+                                    repository,
+                                    new SimpleCredentials("username", "bogus".toCharArray()));
+      cp.initialize();
+      
+      Map<String, CollectionProvider> contentProviders = new HashMap<String, CollectionProvider>();
+      contentProviders.put("feed", cp);
+      
+      wi.setCollectionProviders(contentProviders);
+
+      List<WorkspaceInfo> workspaces = new ArrayList<WorkspaceInfo>();
+      workspaces.add(wi);
+      wp.setWorkspaces(workspaces);
+      pm.setProvider(wp);
+
+      initializeJetty();
+    }
+
+    public void testCustomerProvider() throws Exception {
+
+      Abdera abdera = new Abdera();
+      Factory factory = abdera.getFactory();
+
+      AbderaClient client = new AbderaClient(abdera);
+
+      String base = "http://localhost:9002/";
+
+      // Testing of entry creation
+      IRI colUri = new IRI(base).resolve("acme/feed");
+      Entry entry = factory.newEntry();
+      entry.setTitle("Some Entry");
+      entry.setUpdated(new Date());
+      entry.addAuthor("Dan Diephouse");
+      entry.setId(factory.newUuidUri());
+      entry.setSummary("This is my entry.");
+      entry.setContent("This is my entry. It's swell.");
+      
+      RequestOptions opts = new RequestOptions();
+      opts.setContentType("application/atom+xml;type=entry");
+      ClientResponse res = client.post(colUri.toString(), entry, opts);
+      assertEquals(201, res.getStatus());
+
+      //prettyPrint(abdera, res.getDocument());
+
+      IRI location = res.getLocation();
+      assertEquals(colUri + "/Some%20Entry", 
+                   location.toString());
+
+      // GET the entry
+      res = client.get(location.toString());
+      assertEquals(200, res.getStatus());
+
+      //prettyPrint(abdera, res.getDocument());
+      org.apache.abdera.model.Document<Entry> entry_doc = res.getDocument();
+      Entry entry2 = entry_doc.getRoot();
+
+      assertEquals(entry.getTitle(), entry2.getTitle());
+      assertEquals(entry.getSummary(), entry2.getSummary());
+      assertEquals(entry.getContent(), entry2.getContent());
+      
+      List<Person> authors = entry2.getAuthors();
+      assertEquals(1, authors.size());
+      
+      entry = entry2;
+      entry.setSummary("New Summary");
+      entry.setContent("New Content");
+      res = client.put(location.toString(), entry, opts);
+      assertEquals(204, res.getStatus());
+      
+      res = client.get(colUri.toString());
+      org.apache.abdera.model.Document<Feed> feed_doc = res.getDocument();
+      Feed feed = feed_doc.getRoot();
+      
+      assertEquals(1, feed.getEntries().size());
+      //prettyPrint(abdera, feed_doc);
+    }
+
+    protected void prettyPrint(Abdera abdera, Base doc) throws IOException {
+      abdera.getWriterFactory().getWriter("prettyxml").writeTo(doc, System.out);
+      System.out.println();
+    }
+    
+    private void clearJcrRepository() {
+      try {
+          Session session = repository.login(new SimpleCredentials("username", "password".toCharArray()));
+
+          Node node = session.getRootNode();
+
+          for (NodeIterator itr = node.getNodes(); itr.hasNext();) {
+              Node child = itr.nextNode();
+              if (!child.getName().equals("jcr:system")) {
+                  child.remove();
+              }
+          }
+          session.save();
+          session.logout();
+      } catch (PathNotFoundException t) {
+      } catch (Throwable t) {
+          t.printStackTrace();
+      }
+  }
+
+    private void initializeJetty() throws Exception {
+
+      server = new Server(9002);
+      Context root = new Context(server, "/", Context.NO_SESSIONS);
+      root.addServlet(new ServletHolder(new AbderaServlet() {
+
+        @Override
+        protected ServiceContext createServiceContext() {
+          abderaServiceContext.init(getAbdera(), getProperties(getServletConfig()));
+          return abderaServiceContext;
+        }
+      }), "/*");
+      server.start();
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+      clearJcrRepository();
+
+      if (server != null) server.stop();
+    }
+
+}

Propchange: incubator/abdera/java/trunk/jcr/src/test/java/org/apache/abdera/jcr/JcrCollectionProviderTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: incubator/abdera/java/trunk/jcr/src/test/java/org/apache/abdera/jcr/JcrCollectionProviderTest.java
------------------------------------------------------------------------------
    svn:executable = *

Propchange: incubator/abdera/java/trunk/jcr/src/test/java/org/apache/abdera/jcr/JcrCollectionProviderTest.java
------------------------------------------------------------------------------
    svn:keywords = Rev Date

Modified: incubator/abdera/java/trunk/pom.xml
URL: http://svn.apache.org/viewvc/incubator/abdera/java/trunk/pom.xml?rev=589880&r1=589879&r2=589880&view=diff
==============================================================================
--- incubator/abdera/java/trunk/pom.xml (original)
+++ incubator/abdera/java/trunk/pom.xml Mon Oct 29 14:59:40 2007
@@ -253,12 +253,12 @@
         <groupId>xerces</groupId>
         <artifactId>xercesImpl</artifactId>
         <version>2.8.1</version>
-      </dependency>
-            
-      <dependency>
-        <groupId>xml-apis</groupId>
-        <artifactId>xml-apis</artifactId>
-        <version>1.3.04</version>
+      </dependency>
+            
+      <dependency>
+        <groupId>xml-apis</groupId>
+        <artifactId>xml-apis</artifactId>
+        <version>1.3.04</version>
       </dependency>
     </dependencies>
   </dependencyManagement>
@@ -272,6 +272,7 @@
     <module>security</module>
     <module>server</module>
     <module>client</module>
+    <module>jcr</module>
     <module>extensions/gdata</module>
     <module>extensions/geo</module>
     <module>extensions/json</module>

Modified: incubator/abdera/java/trunk/server/src/main/java/org/apache/abdera/protocol/server/CollectionProvider.java
URL: http://svn.apache.org/viewvc/incubator/abdera/java/trunk/server/src/main/java/org/apache/abdera/protocol/server/CollectionProvider.java?rev=589880&r1=589879&r2=589880&view=diff
==============================================================================
--- incubator/abdera/java/trunk/server/src/main/java/org/apache/abdera/protocol/server/CollectionProvider.java (original)
+++ incubator/abdera/java/trunk/server/src/main/java/org/apache/abdera/protocol/server/CollectionProvider.java Mon Oct 29 14:59:40 2007
@@ -1,20 +1,20 @@
 /*
-* Licensed to the Apache Software Foundation (ASF) under one or more
-* contributor license agreements.  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.  For additional information regarding
-* copyright in this work, please see the NOTICE file in the top level
-* directory of this distribution.
-*/
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  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.  For additional information regarding
+ * copyright in this work, please see the NOTICE file in the top level
+ * directory of this distribution.
+ */
 package org.apache.abdera.protocol.server;
 
 import java.io.InputStream;
@@ -25,23 +25,28 @@
 import org.apache.abdera.i18n.iri.IRI;
 import org.apache.abdera.model.Content;
 import org.apache.abdera.model.Feed;
+import org.apache.abdera.protocol.server.impl.ResponseContextException;
 
 public interface CollectionProvider {
-    
-    String getTitle();
-    
-    ResponseContext getFeed(RequestContext request, Feed feed);
 
-    ResponseContext createEntry(RequestContext request);
+  void begin(RequestContext request) throws ResponseContextException;
+  
+  void end(RequestContext request, ResponseContext response);
+  
+  String getTitle();
 
-    ResponseContext getMedia(RequestContext request);
-    
-    ResponseContext deleteEntry(RequestContext request);
+  ResponseContext getFeed(RequestContext request, Feed feed);
 
-    ResponseContext getEntry(RequestContext request, IRI entryBaseIri);
+  ResponseContext createEntry(RequestContext request);
 
-    ResponseContext getFeed(RequestContext request);
+  ResponseContext getMedia(RequestContext request);
+
+  ResponseContext deleteEntry(RequestContext request);
+
+  ResponseContext getEntry(RequestContext request, IRI entryBaseIri);
+
+  ResponseContext getFeed(RequestContext request);
+
+  ResponseContext updateEntry(RequestContext request, IRI entryBaseIri);
 
-    ResponseContext updateEntry(RequestContext request, IRI entryBaseIri);
-    
 }

Modified: incubator/abdera/java/trunk/server/src/main/java/org/apache/abdera/protocol/server/impl/AbstractCollectionProvider.java
URL: http://svn.apache.org/viewvc/incubator/abdera/java/trunk/server/src/main/java/org/apache/abdera/protocol/server/impl/AbstractCollectionProvider.java?rev=589880&r1=589879&r2=589880&view=diff
==============================================================================
--- incubator/abdera/java/trunk/server/src/main/java/org/apache/abdera/protocol/server/impl/AbstractCollectionProvider.java (original)
+++ incubator/abdera/java/trunk/server/src/main/java/org/apache/abdera/protocol/server/impl/AbstractCollectionProvider.java Mon Oct 29 14:59:40 2007
@@ -62,7 +62,7 @@
     } catch (ClassCastException cce) {
       return new EmptyResponseContext(415);
     } catch (IOException e) {
-      e.printStackTrace();
+      log.warn(e.getMessage(), e);
       return new EmptyResponseContext(500);
     }
   }
@@ -72,7 +72,7 @@
     return ctype != null && !MimeTypeHelper.isAtom(ctype) /*&& !MimeTypeHelper.isXml(ctype)*/;
   }
   
-  public abstract T createEntry(String title, IRI id, String summary, Date updated, List<Person> authors, Content content) throws ResponseContextException;
+  public abstract T createEntry(String title, IRI id, String summary, Date updated, List<Person> authors, Content content, RequestContext request) throws ResponseContextException;
   
   public T createMediaEntry(MimeType mimeType, String slug, InputStream inputStream) throws ResponseContextException {
     throw new UnsupportedOperationException();
@@ -83,7 +83,7 @@
     if (id != null) {
 
       try {
-        deleteEntry(id);
+        deleteEntry(id, request);
       } catch (ResponseContextException e) {
         return createErrorResponse(e);
       }
@@ -95,10 +95,12 @@
     }
   }
 
-  public abstract void deleteEntry(String resourceName) throws ResponseContextException;
+  public abstract void deleteEntry(String resourceName, RequestContext request) throws ResponseContextException;
 
   public abstract String getAuthor() throws ResponseContextException;
 
+  public abstract List<Person> getAuthors(T entry, RequestContext request) throws ResponseContextException;
+  
   public String getBaseMediaIri() {
     return baseMediaIri;
   }
@@ -111,19 +113,14 @@
     throw new UnsupportedOperationException();
   }
   
-  public abstract Iterable<T> getEntries() throws ResponseContextException;
+  public abstract Iterable<T> getEntries(RequestContext request) throws ResponseContextException;
   
   public ResponseContext getEntry(RequestContext request, IRI entryBaseIri) {
     try {
       Entry entry = getEntryFromCollectionProvider(entryBaseIri,
                                                    request);
       if (entry != null) {
-        Feed feed = createFeed(request.getAbdera());
-        entry.setSource(feed.getAsSource());
-        Document<Entry> entry_doc = entry.getDocument();
-        AbstractResponseContext rc = new BaseResponseContext<Document<Entry>>(entry_doc);
-        rc.setEntityTag(calculateEntityTag(entry));
-        return rc;
+        return buildGetEntryResponse(request, entry);
       } else {
         return new EmptyResponseContext(404);
       }
@@ -131,10 +128,19 @@
       return createErrorResponse(e);
     }
   }
+
+  protected ResponseContext buildGetEntryResponse(RequestContext request, Entry entry) {
+    Feed feed = createFeed(request.getAbdera());
+    entry.setSource(feed.getAsSource());
+    Document<Entry> entry_doc = entry.getDocument();
+    AbstractResponseContext rc = new BaseResponseContext<Document<Entry>>(entry_doc);
+    rc.setEntityTag(calculateEntityTag(entry));
+    return rc;
+  }
   
-  public abstract T getEntry(String resourceName) throws ResponseContextException;
+  public abstract T getEntry(String resourceName, RequestContext request) throws ResponseContextException;
   
-  public abstract T getEntryFromId(String id) throws ResponseContextException;
+  public abstract T getEntryFromId(String id, RequestContext request) throws ResponseContextException;
 
 
   public ResponseContext getFeed(RequestContext request) {
@@ -151,7 +157,7 @@
     IRI entryIri = getEntryBaseFromFeedIRI(baseIri);
     
     try {
-      Iterable<T> entries = getEntries();
+      Iterable<T> entries = getEntries(request);
       if (entries != null) {
         for (T entryObj : entries) {
           Entry e = feed.addEntry();
@@ -166,16 +172,20 @@
         }
       }
   
-      Document<Feed> document = feed.getDocument();
-      AbstractResponseContext rc = new BaseResponseContext<Document<Feed>>(document);
-      rc.setEntityTag(calculateEntityTag(document.getRoot()));
-      return rc;
+      return buildGetFeedResponse(feed);
     } catch (ResponseContextException e) {
       return createErrorResponse(e);
     }
     
   }
 
+  protected ResponseContext buildGetFeedResponse(Feed feed) {
+    Document<Feed> document = feed.getDocument();
+    AbstractResponseContext rc = new BaseResponseContext<Document<Feed>>(document);
+    rc.setEntityTag(calculateEntityTag(document.getRoot()));
+    return rc;
+  }
+
   /**
    * Create a ResponseContext (or take it from the Exception) for an
    * exception that occurred in the application.
@@ -205,26 +215,31 @@
   public ResponseContext getMedia(RequestContext request) {
     try {
       String id = getEntryID(request);
-      T entryObj = getEntry(id);
+      T entryObj = getEntry(id, request);
 
       if (entryObj == null) {
         return new EmptyResponseContext(404);
       }
 
-      MediaResponseContext ctx = new MediaResponseContext(getMediaStream(entryObj), 
-                                                          getUpdated(entryObj), 
-                                                          200);
-      ctx.setContentType(getContentType(entryObj));
-
-      return ctx;
+      return buildGetMediaResponse(entryObj);
     } catch (ParseException pe) {
       return new EmptyResponseContext(415);
     } catch (ClassCastException cce) {
       return new EmptyResponseContext(415);
     } catch (Exception e) {
+      log.warn(e.getMessage(), e);
       return new EmptyResponseContext(400);
     }
   }
+
+  protected ResponseContext buildGetMediaResponse(T entryObj) throws ResponseContextException {
+    MediaResponseContext ctx = new MediaResponseContext(getMediaStream(entryObj), 
+                                                        getUpdated(entryObj), 
+                                                        200);
+    ctx.setContentType(getContentType(entryObj));
+
+    return ctx;
+  }
   public String getMediaName(T entry) {
     throw new UnsupportedOperationException();
   }
@@ -249,10 +264,16 @@
     this.baseMediaIri = baseMediaIri;
   }
 
-  public ResponseContext updateEntry(RequestContext request, IRI feedUri) {
-    Abdera abdera = request.getAbdera();
+  public ResponseContext updateEntry(RequestContext request, IRI feedIri) {
     try {
-      Entry orig_entry = getEntryFromCollectionProvider(feedUri, request);
+      String id = getEntryID(request);
+      T entryObj = getEntry(id, request);
+      
+      if (entryObj == null) {
+        return new EmptyResponseContext(404);
+      }
+      
+      Entry orig_entry = getEntryFromCollectionProvider(entryObj, feedIri, request);
       if (orig_entry != null) {
 
         MimeType contentType = request.getContentType();
@@ -267,16 +288,8 @@
           if (!isValidEntry(entry))
             return new EmptyResponseContext(400);
 
-          entry.setUpdated(new Date());
-          // TODO: is this really necessary?
-          // entry.getIdElement().setValue(factory.newUuidUri());
-          entry.addLink(feedUri.resolve(entry.getId().toString()).toString(), "edit");
-
-          // entryObjProvider.updateEntry(entry)
-
-          Feed feed = createFeed(abdera);
-          feed.insertEntry(entry);
-          feed.setUpdated(new Date());
+          updateEntry(entryObj, entry.getTitle(), new Date(), entry.getAuthors(), 
+                      entry.getSummary(), entry.getContentElement(), request);
           return new EmptyResponseContext(204);
         } else {
           return new EmptyResponseContext(400);
@@ -291,12 +304,15 @@
     } catch (ClassCastException cce) {
       return new EmptyResponseContext(415);
     } catch (Exception e) {
+      log.warn(e.getMessage(), e);
       return new EmptyResponseContext(400);
     }
     
   }
 
-  public abstract T updateEntry(T entry, Content content);
+  public abstract void updateEntry(T entry, String title, Date updated, 
+                                   List<Person> authors, String summary, 
+                                   Content content, RequestContext request) throws ResponseContextException;
 
   protected void addContent(Entry e, T doc) throws ResponseContextException {
     Object content = getContent(doc);
@@ -315,13 +331,24 @@
     e.setId(getId(entryObj));
     e.setTitle(getTitle(entryObj));
     e.setUpdated(getUpdated(entryObj));
-    Text t = getSummary(entryObj);
-    if (t != null) {
-      e.setSummaryElement(t);
+    
+    List<Person> authors = getAuthors(entryObj, request);
+    if (authors == null || authors.size() == 0) {
+      log.warn("You must specify at least one author for the entry!");
+      throw new ResponseContextException(500);
+    }
+    
+    for (Person a : authors) {
+      e.addAuthor(a);
+    }
+    
+    String s = getSummary(entryObj);
+    if (s != null) {
+      e.setSummary(s);
     }
   }
 
-  public Text getSummary(T entry) {
+  public String getSummary(T entry) {
     return null;
   }
 
@@ -373,12 +400,7 @@
 
       addMediaContent(entryIri, entry, doc);
 
-      BaseResponseContext<Entry> rc = new BaseResponseContext<Entry>(entry);
-      rc.setLocation(entryIri.resolve(entry.getEditLinkResolvedHref()).toString());
-      rc.setContentLocation(rc.getLocation().toString());
-      rc.setEntityTag(calculateEntityTag(entry));
-      rc.setStatus(201);
-      return rc;
+      return buildCreateMediaEntryResponse(entryIri, entry);
     } catch (IOException e) {
       return new EmptyResponseContext(500);
     } catch (ResponseContextException e) {
@@ -386,6 +408,19 @@
     }
   }
 
+  protected ResponseContext buildCreateMediaEntryResponse(IRI entryIri, Entry entry) {
+    return buildCreateEntryResponse(entryIri, entry);
+  }
+
+  protected ResponseContext buildCreateEntryResponse(IRI entryIri, Entry entry) {
+    BaseResponseContext<Entry> rc = new BaseResponseContext<Entry>(entry);
+    rc.setLocation(entryIri.resolve(entry.getEditLinkResolvedHref()).toString());
+    rc.setContentLocation(rc.getLocation().toString());
+    rc.setEntityTag(calculateEntityTag(entry));
+    rc.setStatus(201);
+    return rc;
+  }
+
   protected ResponseContext createNonMediaEntry(RequestContext request)
     throws IOException {
     Entry entry = getEntryFromRequest(request);
@@ -401,7 +436,7 @@
                                  entry.getSummary(),
                                  entry.getUpdated(),
                                  entry.getAuthors(),
-                                 entry.getContentElement());
+                                 entry.getContentElement(), request);
         entry.getIdElement().setValue(getId(entryObj));
       
         IRI entryBaseUri = getEntryBaseFromFeedIRI(resolveBase(request));
@@ -409,12 +444,7 @@
         IRI entryIri = entryBaseUri.resolve(getName(entryObj));
         entry.addLink(entryIri.toString(), "edit");
   
-        BaseResponseContext<Entry> rc = new BaseResponseContext<Entry>(entry);
-        rc.setLocation(entryIri.resolve(entry.getEditLinkResolvedHref()).toString());
-        rc.setContentLocation(rc.getLocation().toString());
-        rc.setEntityTag(calculateEntityTag(entry));
-        rc.setStatus(201);
-        return rc;
+        return buildCreateEntryResponse(entryIri, entry);
       } catch (ResponseContextException e) {
         return createErrorResponse(e);
       }
@@ -430,16 +460,26 @@
   protected Entry getEntryFromCollectionProvider(IRI feedIri, RequestContext request) throws ResponseContextException {
 
     String id = getEntryID(request);
-    T entryObj = getEntry(id);
+    T entryObj = getEntry(id, request);
 
     if (entryObj == null) {
       return null;
     }
 
+    return getEntryFromCollectionProvider(entryObj, feedIri, request);
+  }
+
+  private Entry getEntryFromCollectionProvider(T entryObj, IRI feedIri, RequestContext request)
+    throws ResponseContextException {
     Abdera abdera = request.getAbdera();
     Factory factory = abdera.getFactory();
     Entry entry = factory.newEntry();
 
+    return buildEntry(entryObj, entry, feedIri, request);
+  }
+
+  private Entry buildEntry(T entryObj, Entry entry, IRI feedIri, RequestContext request)
+    throws ResponseContextException {
     addEntryDetails(request, entry, feedIri, entryObj);
 
     if (isMediaEntry(entryObj)) {
@@ -476,5 +516,15 @@
   @Override
   protected IRI resolveBase(RequestContext request) {
     return request.getBaseUri().resolve(request.getUri());
+  }
+
+  public void begin(RequestContext request) throws ResponseContextException {
+    // TODO Auto-generated method stub
+    
+  }
+
+  public void end(RequestContext request, ResponseContext response) {
+    // TODO Auto-generated method stub
+    
   }
 }

Modified: incubator/abdera/java/trunk/server/src/main/java/org/apache/abdera/protocol/server/impl/AbstractWorkspaceProvider.java
URL: http://svn.apache.org/viewvc/incubator/abdera/java/trunk/server/src/main/java/org/apache/abdera/protocol/server/impl/AbstractWorkspaceProvider.java?rev=589880&r1=589879&r2=589880&view=diff
==============================================================================
--- incubator/abdera/java/trunk/server/src/main/java/org/apache/abdera/protocol/server/impl/AbstractWorkspaceProvider.java (original)
+++ incubator/abdera/java/trunk/server/src/main/java/org/apache/abdera/protocol/server/impl/AbstractWorkspaceProvider.java Mon Oct 29 14:59:40 2007
@@ -94,12 +94,20 @@
     public abstract java.util.Collection<WorkspaceInfo> getWorkspaces();
 
     public ResponseContext getFeed(RequestContext request) {
+      CollectionProvider provider = null;
+      ResponseContext res = null;
       try {
-        CollectionProvider provider = getCollectionProvider(resolveBase(request), request);
+        provider = getCollectionProvider(resolveBase(request), request);
         
-        return provider.getFeed(request);
+        provider.begin(request);
+        
+        res = provider.getFeed(request);
+        return res;
       } catch (ResponseContextException e) {
-        return createErrorResponse(e);
+        res = createErrorResponse(e);
+        return res;
+      } finally {
+        end(provider, request, res);
       }
     }
 
@@ -147,24 +155,45 @@
     protected abstract WorkspaceInfo getWorkspaceInfo(String string);
 
     public ResponseContext createEntry(RequestContext request) {
+      CollectionProvider provider = null;
+      ResponseContext response = null;
       try {
-        CollectionProvider provider = getCollectionProvider(request.getUri(), request);
+        provider = getCollectionProvider(request.getUri(), request);
+        provider.begin(request);
         
         return provider.createEntry(request);
       } catch (ResponseContextException e) {
-        return createErrorResponse(e);
+        response = createErrorResponse(e);
+        return response;
+      } finally {
+        end(provider, request, response);
+      }
+    }
+
+    protected void end(CollectionProvider provider, RequestContext request, ResponseContext response) {
+      if (provider != null) {
+        try {
+          provider.end(request, response);
+        } catch (Throwable t) {
+          log.warn("Could not end() CollectionProvider.", t);
+        }
       }
     }
 
     @Override
     public ResponseContext getMedia(RequestContext request) {
+      CollectionProvider provider = null;
+      ResponseContext response = null;
       try {
         IRI entryBaseIri = resolveBase(request).resolve("../");
-        CollectionProvider provider = getCollectionProvider(entryBaseIri, request);
+        provider = getCollectionProvider(entryBaseIri, request);
   
         return provider.getMedia(request);
       } catch (ResponseContextException e) {
-        return createErrorResponse(e);
+        response = createErrorResponse(e);
+        return response;
+      } finally {
+        end(provider, request, response);
       }
     }
 
@@ -176,36 +205,53 @@
     }
 
     public ResponseContext deleteEntry(RequestContext request) {
+      CollectionProvider provider = null;
+      ResponseContext response = null;
       try {
-        CollectionProvider provider = getCollectionProvider(resolveBase(request).resolve("./"), request);
+        provider = getCollectionProvider(resolveBase(request).resolve("./"), request);
       
         return provider.deleteEntry(request);
       } catch (ResponseContextException e) {
-        return createErrorResponse(e);
+        response = createErrorResponse(e);
+        return response;
+      } finally {
+        end(provider, request, response);
       }
     }
 
     
     public ResponseContext getEntry(RequestContext request) {
+      CollectionProvider provider = null;
+      ResponseContext response = null;
       try {
         IRI entryBaseIri = resolveBase(request).resolve("./");
-        CollectionProvider provider = getCollectionProvider(entryBaseIri, request);
-  
+        provider = getCollectionProvider(entryBaseIri, request);
+        provider.begin(request);
+        
         return provider.getEntry(request, entryBaseIri);
       } catch (ResponseContextException e) {
-        return createErrorResponse(e);
+        response = createErrorResponse(e);
+        return response;
+      } finally {
+        end(provider, request, response);
       }
     }
 
     @SuppressWarnings("unchecked")
     public ResponseContext updateEntry(RequestContext request) {
+      CollectionProvider provider = null;
+      ResponseContext response = null;
       try {
         IRI entryBaseIri = resolveBase(request).resolve("./");
-        CollectionProvider provider = getCollectionProvider(entryBaseIri, request);
-  
+        provider = getCollectionProvider(entryBaseIri, request);
+        provider.begin(request);
+        
         return provider.updateEntry(request, entryBaseIri);
       } catch (ResponseContextException e) {
-        return createErrorResponse(e);
+        response = createErrorResponse(e);
+        return response;
+      } finally {
+        end(provider, request, response);
       }
     }
 

Modified: incubator/abdera/java/trunk/server/src/test/java/org/apache/abdera/protocol/server/CustomerContentProvider.java
URL: http://svn.apache.org/viewvc/incubator/abdera/java/trunk/server/src/test/java/org/apache/abdera/protocol/server/CustomerContentProvider.java?rev=589880&r1=589879&r2=589880&view=diff
==============================================================================
--- incubator/abdera/java/trunk/server/src/test/java/org/apache/abdera/protocol/server/CustomerContentProvider.java (original)
+++ incubator/abdera/java/trunk/server/src/test/java/org/apache/abdera/protocol/server/CustomerContentProvider.java Mon Oct 29 14:59:40 2007
@@ -1,5 +1,6 @@
 package org.apache.abdera.protocol.server;
 
+import java.util.Arrays;
 import java.util.Date;
 import java.util.HashMap;
 import java.util.List;
@@ -30,8 +31,11 @@
   }
 
   @Override
-  public Customer createEntry(String title, IRI id, String summary, Date updated, List<Person> authors,
-                              Content content) throws ResponseContextException {
+  public Customer createEntry(String title, IRI id, 
+                              String summary, 
+                              Date updated, 
+                              List<Person> authors,
+                              Content content, RequestContext request) throws ResponseContextException {
     Customer customer = contentToCustomer(content);
     customers.put(customer.getId(), customer);
     
@@ -51,7 +55,7 @@
     return customer;
   }
 
-  public void deleteEntry(String resourceName) throws ResponseContextException {
+  public void deleteEntry(String resourceName, RequestContext request) throws ResponseContextException {
     Integer id = getIdFromResourceName(resourceName);
     customers.remove(id);
   }
@@ -60,6 +64,20 @@
     return "Acme Industries";
   }
 
+  @Override
+  public List<Person> getAuthors(Customer entry, RequestContext request) throws ResponseContextException {
+    Person author = request.getAbdera().getFactory().newAuthor();
+    author.setName("Acme Industries");
+    return Arrays.asList(author);
+  }
+
+  @Override
+  public void updateEntry(Customer entry, String title, Date updated, List<Person> authors, String summary,
+                          Content content, RequestContext request) throws ResponseContextException {
+    // TODO Auto-generated method stub
+    
+  }
+
   public Object getContent(Customer entry) {
     Content content = factory.newContent();
     Element customerEl = factory.newElement(new QName("customer"));
@@ -69,11 +87,11 @@
     return content;
   }
 
-  public Iterable<Customer> getEntries() {
+  public Iterable<Customer> getEntries(RequestContext request) {
     return customers.values();
   }
 
-  public Customer getEntry(String resourceName) throws ResponseContextException {
+  public Customer getEntry(String resourceName, RequestContext request) throws ResponseContextException {
     Integer id = getIdFromResourceName(resourceName);
     return customers.get(id);
   }
@@ -87,7 +105,7 @@
     return id;
   }
 
-  public Customer getEntryFromId(String id) {
+  public Customer getEntryFromId(String id, RequestContext request) {
     return customers.get(new Integer(id));
   }
 
@@ -112,7 +130,7 @@
     return new Date();
   }
 
-  public Customer updateEntry(Customer entry, Content content) {
+  public Customer updateEntry(Customer entry, String title, List<Person> authors, Content content, RequestContext request) {
     contentToCustomer(content, entry);
     
     return entry;