abdera-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From calav...@apache.org
Subject svn commit: r679302 - in /incubator/abdera/java/trunk: build/ core/src/main/java/org/apache/abdera/model/ core/src/main/java/org/apache/abdera/util/ dependencies/ parser/src/main/java/org/apache/abdera/parser/stax/ parser/src/test/java/org/apache/abder...
Date Thu, 24 Jul 2008 08:33:03 GMT
Author: calavera
Date: Thu Jul 24 01:32:59 2008
New Revision: 679302

URL: http://svn.apache.org/viewvc?rev=679302&view=rev
Log:
ABDERA-166: Support multipart/related packaging

It allows to decode multipart/related objects that contain the media resource and the media link entry. It follows the Joe Gregorio draft:

http://atompub-mulitpart-spec.googlecode.com/svn/trunk/draft-gregorio-atompub-multipart-02.txt

I've wrotten a little howto into the wiki:

http://cwiki.apache.org/confluence/display/ABDERA/Support+for+AtomPub-multipart


Added:
    incubator/abdera/java/trunk/parser/src/main/java/org/apache/abdera/parser/stax/FOMMultipartCollection.java
    incubator/abdera/java/trunk/server/src/main/java/org/apache/abdera/protocol/server/multipart/
    incubator/abdera/java/trunk/server/src/main/java/org/apache/abdera/protocol/server/multipart/AbstractMultipartCollectionAdapter.java
    incubator/abdera/java/trunk/server/src/main/java/org/apache/abdera/protocol/server/multipart/MultipartInputStream.java
    incubator/abdera/java/trunk/server/src/main/java/org/apache/abdera/protocol/server/multipart/MultipartRelatedCollectionInfo.java
    incubator/abdera/java/trunk/server/src/main/java/org/apache/abdera/protocol/server/processors/MultipartRelatedServiceRequestProcessor.java
    incubator/abdera/java/trunk/server/src/test/java/org/apache/abdera/protocol/server/test/multipart/
    incubator/abdera/java/trunk/server/src/test/java/org/apache/abdera/protocol/server/test/multipart/MultipartRelatedAdapter.java
    incubator/abdera/java/trunk/server/src/test/java/org/apache/abdera/protocol/server/test/multipart/MultipartRelatedTest.java
    incubator/abdera/java/trunk/server/src/test/resources/org/
    incubator/abdera/java/trunk/server/src/test/resources/org/apache/
    incubator/abdera/java/trunk/server/src/test/resources/org/apache/abdera/
    incubator/abdera/java/trunk/server/src/test/resources/org/apache/abdera/protocol/
    incubator/abdera/java/trunk/server/src/test/resources/org/apache/abdera/protocol/server/
    incubator/abdera/java/trunk/server/src/test/resources/org/apache/abdera/protocol/server/test/
    incubator/abdera/java/trunk/server/src/test/resources/org/apache/abdera/protocol/server/test/multipart/
    incubator/abdera/java/trunk/server/src/test/resources/org/apache/abdera/protocol/server/test/multipart/info.png   (with props)
Modified:
    incubator/abdera/java/trunk/build/build.xml
    incubator/abdera/java/trunk/core/src/main/java/org/apache/abdera/model/Workspace.java
    incubator/abdera/java/trunk/core/src/main/java/org/apache/abdera/util/Constants.java
    incubator/abdera/java/trunk/core/src/main/java/org/apache/abdera/util/MimeTypeHelper.java
    incubator/abdera/java/trunk/dependencies/deps.properties
    incubator/abdera/java/trunk/parser/src/main/java/org/apache/abdera/parser/stax/FOMFactory.java
    incubator/abdera/java/trunk/parser/src/main/java/org/apache/abdera/parser/stax/FOMWorkspace.java
    incubator/abdera/java/trunk/parser/src/test/java/org/apache/abdera/test/parser/ServiceDocumentTest.java
    incubator/abdera/java/trunk/server/pom.xml
    incubator/abdera/java/trunk/server/src/main/java/org/apache/abdera/protocol/server/processors/ServiceRequestProcessor.java
    incubator/abdera/java/trunk/server/src/test/java/org/apache/abdera/protocol/server/test/TestSuite.java

Modified: incubator/abdera/java/trunk/build/build.xml
URL: http://svn.apache.org/viewvc/incubator/abdera/java/trunk/build/build.xml?rev=679302&r1=679301&r2=679302&view=diff
==============================================================================
--- incubator/abdera/java/trunk/build/build.xml (original)
+++ incubator/abdera/java/trunk/build/build.xml Thu Jul 24 01:32:59 2008
@@ -180,6 +180,7 @@
           <available file="${dependencies}/${htmlserializer.jar}" />
           <available file="${dependencies}/${easymock.jar}" />
           <available file="${dependencies}/${easymockclassextension.jar}" />
+          <available file="${dependencies}/${javamail.jar}" />
         </and>
       </not>
     </condition>
@@ -600,6 +601,7 @@
       <get src="${easymock.dir}/${easymock.jar}" dest="${dependencies}/${easymock.jar}" usetimestamp="true" />
       <get src="${easymockclassextension.dir}/${easymockclassextension.jar}" dest="${dependencies}/${easymockclassextension.jar}" usetimestamp="true" />
        <get src="${cglib.dir}/${cglib.jar}" dest="${dependencies}/${cglib.jar}" usetimestamp="true" />
+      <get src="${javamail.dir}/${javamail.jar}" dest="${dependencies}/${javamail.jar}" usetimestamp="true" />
     </parallel>
   </target>
 

Modified: incubator/abdera/java/trunk/core/src/main/java/org/apache/abdera/model/Workspace.java
URL: http://svn.apache.org/viewvc/incubator/abdera/java/trunk/core/src/main/java/org/apache/abdera/model/Workspace.java?rev=679302&r1=679301&r2=679302&view=diff
==============================================================================
--- incubator/abdera/java/trunk/core/src/main/java/org/apache/abdera/model/Workspace.java (original)
+++ incubator/abdera/java/trunk/core/src/main/java/org/apache/abdera/model/Workspace.java Thu Jul 24 01:32:59 2008
@@ -110,6 +110,15 @@
     String href);
   
   /**
+   * Adds a multipart collection to this workspace
+   * @param title The collection title
+   * @param href The collection HREF
+   * @return The newly created app:collection
+   * @throws IRISyntaxException if the href is malformed
+   */
+  public Collection addMultipartCollection(String title, String href);
+  
+  /**
    * Returns a collection that accepts the specified media types
    * @param a listing of media types the collection must accept
    * @return A matching app:collection element

Modified: incubator/abdera/java/trunk/core/src/main/java/org/apache/abdera/util/Constants.java
URL: http://svn.apache.org/viewvc/incubator/abdera/java/trunk/core/src/main/java/org/apache/abdera/util/Constants.java?rev=679302&r1=679301&r2=679302&view=diff
==============================================================================
--- incubator/abdera/java/trunk/core/src/main/java/org/apache/abdera/util/Constants.java (original)
+++ incubator/abdera/java/trunk/core/src/main/java/org/apache/abdera/util/Constants.java Thu Jul 24 01:32:59 2008
@@ -46,6 +46,7 @@
   public static final String APP_MEDIA_TYPE       = "application/atomsvc+xml";
   public static final String XML_MEDIA_TYPE       = "application/xml";
   public static final String CAT_MEDIA_TYPE       = "application/atomcat+xml";
+  public static final String MULTIPART_RELATED_TYPE = "Multipart/Related";
   
   public static final String ATOM_NS              = "http://www.w3.org/2005/Atom";
   public static final String APP_NS               = "http://www.w3.org/2007/app";
@@ -103,6 +104,8 @@
   public static final String LN_DRAFT             = "draft";
   public static final String LN_CATEGORIES        = "categories";
   public static final String LN_FIXED             = "fixed";
+  public static final String LN_ALTERNATE = "alternate";
+  public static final String LN_ALTERNATE_MULTIPART_RELATED = "multipart-related";
   
   public static final QName DIV                   = new QName(XHTML_NS, LN_DIV, "");
   
@@ -172,6 +175,7 @@
   public static final QName SRC                   = new QName(LN_SRC);
   public static final QName AID                   = new QName(LN_ID);
   public static final QName CLASS                 = new QName(LN_CLASS);
+  public static final QName ALTERNATE = new QName(LN_ALTERNATE);
   
   public static final String TEXT  = "text";
   public static final String HTML  = "html";

Modified: incubator/abdera/java/trunk/core/src/main/java/org/apache/abdera/util/MimeTypeHelper.java
URL: http://svn.apache.org/viewvc/incubator/abdera/java/trunk/core/src/main/java/org/apache/abdera/util/MimeTypeHelper.java?rev=679302&r1=679301&r2=679302&view=diff
==============================================================================
--- incubator/abdera/java/trunk/core/src/main/java/org/apache/abdera/util/MimeTypeHelper.java (original)
+++ incubator/abdera/java/trunk/core/src/main/java/org/apache/abdera/util/MimeTypeHelper.java Thu Jul 24 01:32:59 2008
@@ -184,8 +184,7 @@
    * Returns true if media type a matches text/*
    */
   public static boolean isText(String a) {
-    boolean answer = isMatch("text/*", a);
-    return answer;
+    return isMatch("text/*", a);    
   }
   
   /**
@@ -307,6 +306,13 @@
     } catch (Exception e) {}
     return 0;
   }
+  
+  /**
+   * Returns true if media type is a multiparted file.
+   */
+  public static boolean isMultipart(String a) {
+    return isMatch(Constants.MULTIPART_RELATED_TYPE, a);    
+  }
 
 }
 

Modified: incubator/abdera/java/trunk/dependencies/deps.properties
URL: http://svn.apache.org/viewvc/incubator/abdera/java/trunk/dependencies/deps.properties?rev=679302&r1=679301&r2=679302&view=diff
==============================================================================
--- incubator/abdera/java/trunk/dependencies/deps.properties (original)
+++ incubator/abdera/java/trunk/dependencies/deps.properties Thu Jul 24 01:32:59 2008
@@ -48,6 +48,10 @@
 geronimo.servlet.dir=http://www.apache.org/dist/java-repository/org.apache.geronimo.specs/jars
 geronimo.servlet.jar=geronimo-servlet_2.4_spec-1.0.jar
 
+#### Required for build ####
+javamail.dir=https://maven-repository.dev.java.net/nonav/repository/javax.mail/jars/
+javamail.jar=mail-1.4.1.jar
+
 #### Required for build and JDK 1.4.2 support ####
 retroweaver.version=2.0
 retroweaver.dir=http://people.apache.org/~jmsnell

Modified: incubator/abdera/java/trunk/parser/src/main/java/org/apache/abdera/parser/stax/FOMFactory.java
URL: http://svn.apache.org/viewvc/incubator/abdera/java/trunk/parser/src/main/java/org/apache/abdera/parser/stax/FOMFactory.java?rev=679302&r1=679301&r2=679302&view=diff
==============================================================================
--- incubator/abdera/java/trunk/parser/src/main/java/org/apache/abdera/parser/stax/FOMFactory.java (original)
+++ incubator/abdera/java/trunk/parser/src/main/java/org/apache/abdera/parser/stax/FOMFactory.java Thu Jul 24 01:32:59 2008
@@ -160,6 +160,10 @@
     Element parent) {
       return new FOMCollection((OMContainer)parent,this);
   }
+  
+  public Collection newMultipartCollection(Element parent) {
+	  return new FOMMultipartCollection((OMContainer)parent,this);
+  }
 
   public Feed newFeed() {
     Document<Feed> doc = newDocument();

Added: incubator/abdera/java/trunk/parser/src/main/java/org/apache/abdera/parser/stax/FOMMultipartCollection.java
URL: http://svn.apache.org/viewvc/incubator/abdera/java/trunk/parser/src/main/java/org/apache/abdera/parser/stax/FOMMultipartCollection.java?rev=679302&view=auto
==============================================================================
--- incubator/abdera/java/trunk/parser/src/main/java/org/apache/abdera/parser/stax/FOMMultipartCollection.java (added)
+++ incubator/abdera/java/trunk/parser/src/main/java/org/apache/abdera/parser/stax/FOMMultipartCollection.java Thu Jul 24 01:32:59 2008
@@ -0,0 +1,148 @@
+package org.apache.abdera.parser.stax;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+import javax.activation.MimeType;
+import javax.xml.namespace.QName;
+
+import org.apache.abdera.model.Collection;
+import org.apache.abdera.model.Element;
+import org.apache.abdera.util.MimeTypeHelper;
+import org.apache.axiom.om.OMContainer;
+import org.apache.axiom.om.OMFactory;
+import org.apache.axiom.om.OMXMLParserWrapper;
+
+public class FOMMultipartCollection extends FOMCollection {
+	
+	public FOMMultipartCollection() {
+	    super();
+	  }
+	  
+	  public FOMMultipartCollection(
+	    String title, 
+	    String href, 
+	    Map<String, String> accepts) {
+	    this();
+	    setTitle(title);
+	    setHref(href);
+	    setAccept(accepts);
+	  }
+	  
+	  protected FOMMultipartCollection(
+			    QName qname,
+			    OMContainer parent,
+			    OMFactory factory) {
+			      super(qname, parent, factory);
+			  }
+			  
+			  protected FOMMultipartCollection(
+			    QName qname,
+			    OMContainer parent, 
+			    OMFactory factory,
+			    OMXMLParserWrapper builder) {
+			      super(qname, parent, factory, builder);
+			  }
+			  
+			  protected FOMMultipartCollection(
+			    OMContainer parent,
+			    OMFactory factory) {
+			      super(COLLECTION, parent, factory);
+			  }
+
+			  protected FOMMultipartCollection(
+			    OMContainer parent,
+			    OMFactory factory,
+			    OMXMLParserWrapper builder) {
+			      super(COLLECTION, parent, factory, builder);
+			  }
+	
+	public boolean acceptsMultipart(String mediaType) {
+		Map<String, String> accept = getAcceptMultiparted();
+	    if (accept.size() == 0) accept = Collections.singletonMap("application/atom+xml;type=entry", null);
+	    for (Map.Entry<String, String> entry : accept.entrySet()) {
+	      if (MimeTypeHelper.isMatch(entry.getKey(), mediaType)
+	    		  && entry.getValue() != null && entry.getValue().equals(LN_ALTERNATE_MULTIPART_RELATED)) return true;
+	    }
+	    return false;
+	  }
+
+	  public boolean acceptsMultipart(MimeType mediaType) {
+	    return accepts(mediaType.toString());
+	  }
+	
+	public Map<String, String> getAcceptMultiparted(){
+	    Map<String, String> accept = new HashMap<String, String>();
+	    Iterator<?> i = getChildrenWithName(ACCEPT);
+	    if (i == null || !i.hasNext()) i = getChildrenWithName(PRE_RFC_ACCEPT);
+	    while(i.hasNext()) {
+	      Element e = (Element) i.next();
+	      String t = e.getText();
+	      if (t != null) { 
+	    	if (e.getAttributeValue(ALTERNATE) != null && e.getAttributeValue(ALTERNATE).trim().length() > 0) {
+	    		accept.put(t.trim(), e.getAttributeValue(ALTERNATE));
+	    	} else {
+	    		accept.put(t.trim(), null);
+	    	}
+	      }
+	    }
+	    return accept;
+	  }
+	
+	public Collection setAccept(String mediaRange, String alternate) {
+		return setAccept(Collections.singletonMap(mediaRange, alternate));
+	}
+	
+	public Collection setAccept(Map<String, String> mediaRanges) {
+		complete();
+	    if (mediaRanges != null && mediaRanges.size() > 0) {
+	      _removeChildren(ACCEPT, true);
+	      _removeChildren(PRE_RFC_ACCEPT, true);
+	      if (mediaRanges.size() == 1 && mediaRanges.keySet().iterator().next().equals("")) {
+	        addExtension(ACCEPT);
+	      } else {	        
+	        for (Map.Entry<String, String> entry : mediaRanges.entrySet()) {
+	          if (entry.getKey().equalsIgnoreCase("entry")) {
+	            addSimpleExtension(ACCEPT, "application/atom+xml;type=entry");
+	          } else {
+	            try {
+	              Element accept = addSimpleExtension(ACCEPT, new MimeType(entry.getKey()).toString());
+	              if (entry.getValue() != null) {
+	            	  accept.setAttributeValue(ALTERNATE, entry.getValue());
+	              }
+	            } catch (javax.activation.MimeTypeParseException e) {
+	              throw new org.apache.abdera.util.MimeTypeParseException(e);
+	            }
+	          }
+	        }
+	      }
+	    } else {
+	      _removeChildren(ACCEPT, true);
+	      _removeChildren(PRE_RFC_ACCEPT,true);
+	    }
+	    return this;
+	}
+	
+	public Collection addAccepts(String mediaRange, String alternate) {
+		return addAccepts(Collections.singletonMap(mediaRange, alternate));
+	}
+	
+	public Collection addAccepts(Map<String, String> mediaRanges) {
+	    complete();
+	    if (mediaRanges != null) {
+	    	for (Map.Entry<String, String> entry : mediaRanges.entrySet()) {
+	        if (!accepts(entry.getKey())) {
+	          try {
+	            Element accept = addSimpleExtension(ACCEPT, new MimeType(entry.getKey()).toString());
+	            if (entry.getValue() != null) {
+	            	accept.setAttributeValue(ALTERNATE, entry.getValue());
+	            }
+	          } catch (Exception e) {}
+	        }
+	      }
+	    }
+	    return this;
+	  }
+}

Modified: incubator/abdera/java/trunk/parser/src/main/java/org/apache/abdera/parser/stax/FOMWorkspace.java
URL: http://svn.apache.org/viewvc/incubator/abdera/java/trunk/parser/src/main/java/org/apache/abdera/parser/stax/FOMWorkspace.java?rev=679302&r1=679301&r2=679302&view=diff
==============================================================================
--- incubator/abdera/java/trunk/parser/src/main/java/org/apache/abdera/parser/stax/FOMWorkspace.java (original)
+++ incubator/abdera/java/trunk/parser/src/main/java/org/apache/abdera/parser/stax/FOMWorkspace.java Thu Jul 24 01:32:59 2008
@@ -154,6 +154,15 @@
     return collection;
   }
   
+  public Collection addMultipartCollection(String title, String href) {
+	    complete();
+	    FOMFactory fomfactory = (FOMFactory) factory;
+	    Collection collection = fomfactory.newMultipartCollection(this);
+	    collection.setTitle(title);
+	    collection.setHref(href);
+	    return collection;
+	  }
+  
   public Collection getCollectionThatAccepts(MimeType... types) {
     Collection collection = null;
     for (Collection coll : getCollections()) {

Modified: incubator/abdera/java/trunk/parser/src/test/java/org/apache/abdera/test/parser/ServiceDocumentTest.java
URL: http://svn.apache.org/viewvc/incubator/abdera/java/trunk/parser/src/test/java/org/apache/abdera/test/parser/ServiceDocumentTest.java?rev=679302&r1=679301&r2=679302&view=diff
==============================================================================
--- incubator/abdera/java/trunk/parser/src/test/java/org/apache/abdera/test/parser/ServiceDocumentTest.java (original)
+++ incubator/abdera/java/trunk/parser/src/test/java/org/apache/abdera/test/parser/ServiceDocumentTest.java Thu Jul 24 01:32:59 2008
@@ -26,6 +26,7 @@
 import org.apache.abdera.model.Collection;
 import org.apache.abdera.model.Service;
 import org.apache.abdera.model.Workspace;
+import org.apache.abdera.parser.stax.FOMMultipartCollection;
 import org.junit.Test;
 
 
@@ -53,4 +54,28 @@
         assertTrue("Service document does not specify acceptance of entries.", s.contains("application/atom+xml; type=entry"));
         assertTrue("Service document does not specify acceptance of apples.", s.contains("application/apples"));
     }
+  
+  /**
+   * Test whether the <accept> element includes the multipart attribute.
+   */
+  @Test
+  public void testCollectionAcceptsMultipart() throws Exception {
+      Abdera abdera = new Abdera();
+      Factory factory = abdera.getFactory();
+      Service svc = factory.newService();
+      Workspace ws = svc.addWorkspace("test-ws");
+      FOMMultipartCollection coll = (FOMMultipartCollection) ws.addMultipartCollection("test multipart coll", "/test-coll");   
+      coll.setAcceptsEntry();
+      coll.addAccepts("image/*", "multipart-related");            
+      
+      assertTrue("Collection does not accept entries.", coll.acceptsEntry());
+      assertTrue("Collection does not accept multipart related images", coll.acceptsMultipart("image/*"));
+      
+      StringWriter sw = new StringWriter();
+      svc.writeTo(sw);      
+      
+      String s = sw.toString();
+      assertTrue("Service document does not specify acceptance of entries.", s.contains("application/atom+xml; type=entry"));
+      assertTrue("Service document does not specify acceptance of apples.", s.contains("image/*"));
+  }
 }

Modified: incubator/abdera/java/trunk/server/pom.xml
URL: http://svn.apache.org/viewvc/incubator/abdera/java/trunk/server/pom.xml?rev=679302&r1=679301&r2=679302&view=diff
==============================================================================
--- incubator/abdera/java/trunk/server/pom.xml (original)
+++ incubator/abdera/java/trunk/server/pom.xml Thu Jul 24 01:32:59 2008
@@ -1,94 +1,99 @@
-<!--
-   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.
--->
-<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.5.0-incubating-SNAPSHOT</version>
-  </parent>  
-  <modelVersion>4.0.0</modelVersion>
-  <artifactId>abdera-server</artifactId>
-  <packaging>jar</packaging>
-  <name>Abdera Server</name>
-  <version>0.5.0-incubating-SNAPSHOT</version>
-  <description>Atom Publishing Protocol Specification Server-Side Implementation</description>
-
-  <properties>
-    <topDir>${basedir}/..</topDir>
-  </properties>
-  
-  <dependencies>
-    <dependency>
-      <groupId>junit</groupId>
-      <artifactId>junit</artifactId>
-    </dependency>
-    <dependency>
-      <groupId>org.apache.abdera</groupId>
-      <artifactId>abdera-core</artifactId>
-      <version>0.5.0-incubating-SNAPSHOT</version>
-      <scope>compile</scope>
-    </dependency>   
-    <dependency>
-      <groupId>org.apache.abdera</groupId>
-      <artifactId>abdera-parser</artifactId>
-      <version>0.5.0-incubating-SNAPSHOT</version>
-      <scope>compile</scope>
-    </dependency>   
-    <dependency>
-      <groupId>javax.servlet</groupId>
-      <artifactId>servlet-api</artifactId>
-      <version>2.4</version>
-    </dependency>
-    <dependency>
-      <groupId>commons-logging</groupId>
-      <artifactId>commons-logging</artifactId>
-    </dependency>
-    <dependency>
-      <groupId>org.mortbay.jetty</groupId>
-      <artifactId>jetty</artifactId>
-      <version>${jetty.version}</version>
-      <scope>test</scope>
-    </dependency>
-    <dependency>
-      <groupId>org.apache.abdera</groupId>
-      <artifactId>abdera-client</artifactId>
-      <version>0.5.0-incubating-SNAPSHOT</version>
-      <scope>test</scope>
-    </dependency>
-
-    <dependency>
-        <groupId>org.easymock</groupId>
-        <artifactId>easymock</artifactId>
-        <version>2.3</version>
-        <scope>test</scope>
-    </dependency>
-
-    <dependency>
-        <groupId>org.easymock</groupId>
-        <artifactId>easymockclassextension</artifactId>
-        <version>2.3</version>
-        <scope>test</scope>
-    </dependency>
-
-    <dependency>
-        <groupId>cglib</groupId>
-        <artifactId>cglib-nodep</artifactId>
-        <version>2.1_3</version>
-        <scope>test</scope>
-    </dependency>
-  </dependencies>
+<!--
+   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.
+-->
+<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.5.0-incubating-SNAPSHOT</version>
+  </parent>  
+  <modelVersion>4.0.0</modelVersion>
+  <artifactId>abdera-server</artifactId>
+  <packaging>jar</packaging>
+  <name>Abdera Server</name>
+  <version>0.5.0-incubating-SNAPSHOT</version>
+  <description>Atom Publishing Protocol Specification Server-Side Implementation</description>
+
+  <properties>
+    <topDir>${basedir}/..</topDir>
+  </properties>
+  
+  <dependencies>
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.abdera</groupId>
+      <artifactId>abdera-core</artifactId>
+      <version>0.5.0-incubating-SNAPSHOT</version>
+      <scope>compile</scope>
+    </dependency>   
+    <dependency>
+      <groupId>org.apache.abdera</groupId>
+      <artifactId>abdera-parser</artifactId>
+      <version>0.5.0-incubating-SNAPSHOT</version>
+      <scope>compile</scope>
+    </dependency>   
+    <dependency>
+      <groupId>javax.servlet</groupId>
+      <artifactId>servlet-api</artifactId>
+      <version>2.4</version>
+    </dependency>
+    <dependency>
+    	<groupId>javax.mail</groupId>
+    	<artifactId>mail</artifactId>
+    	<version>1.4</version>
+    </dependency>
+    <dependency>
+      <groupId>commons-logging</groupId>
+      <artifactId>commons-logging</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.mortbay.jetty</groupId>
+      <artifactId>jetty</artifactId>
+      <version>${jetty.version}</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.abdera</groupId>
+      <artifactId>abdera-client</artifactId>
+      <version>0.5.0-incubating-SNAPSHOT</version>
+      <scope>test</scope>
+    </dependency>
+
+    <dependency>
+        <groupId>org.easymock</groupId>
+        <artifactId>easymock</artifactId>
+        <version>2.3</version>
+        <scope>test</scope>
+    </dependency>
+
+    <dependency>
+        <groupId>org.easymock</groupId>
+        <artifactId>easymockclassextension</artifactId>
+        <version>2.3</version>
+        <scope>test</scope>
+    </dependency>
+
+    <dependency>
+        <groupId>cglib</groupId>
+        <artifactId>cglib-nodep</artifactId>
+        <version>2.1_3</version>
+        <scope>test</scope>        
+    </dependency>    
+  </dependencies>
 </project>
\ No newline at end of file

Added: incubator/abdera/java/trunk/server/src/main/java/org/apache/abdera/protocol/server/multipart/AbstractMultipartCollectionAdapter.java
URL: http://svn.apache.org/viewvc/incubator/abdera/java/trunk/server/src/main/java/org/apache/abdera/protocol/server/multipart/AbstractMultipartCollectionAdapter.java?rev=679302&view=auto
==============================================================================
--- incubator/abdera/java/trunk/server/src/main/java/org/apache/abdera/protocol/server/multipart/AbstractMultipartCollectionAdapter.java (added)
+++ incubator/abdera/java/trunk/server/src/main/java/org/apache/abdera/protocol/server/multipart/AbstractMultipartCollectionAdapter.java Thu Jul 24 01:32:59 2008
@@ -0,0 +1,206 @@
+/*
+ * 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.multipart;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.PushbackInputStream;
+import java.util.Collection;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.mail.Header;
+import javax.mail.MessagingException;
+import javax.mail.internet.InternetHeaders;
+
+import org.apache.abdera.model.Document;
+import org.apache.abdera.model.Element;
+import org.apache.abdera.model.Entry;
+import org.apache.abdera.parser.ParseException;
+import org.apache.abdera.parser.Parser;
+import org.apache.abdera.protocol.server.RequestContext;
+import org.apache.abdera.protocol.server.impl.AbstractCollectionAdapter;
+import org.apache.abdera.util.Constants;
+import org.apache.abdera.util.MimeTypeHelper;
+
+import sun.misc.BASE64Decoder;
+
+@SuppressWarnings("unchecked")
+public abstract class AbstractMultipartCollectionAdapter extends AbstractCollectionAdapter
+		implements MultipartRelatedCollectionInfo {	
+	
+	protected Map<String, String> accepts;
+	
+	public String[] getAccepts(RequestContext request) {
+		Collection<String> acceptKeys = getAlternateAccepts(request).keySet();
+		return acceptKeys.toArray(new String[acceptKeys.size()]);
+	}
+	
+	protected MultipartRelatedPost getMultipartRelatedData(
+			RequestContext request) throws IOException, ParseException,
+			MessagingException {
+
+		String boundary = request.getContentType().getParameter("boundary");
+
+		if (boundary == null) {
+			throw new IllegalArgumentException("multipart/related stream invalid, boundary parameter is missing.");
+		}
+
+		boundary = "--" + boundary;
+
+		String type = request.getContentType().getParameter("type");
+		if (!(type != null && MimeTypeHelper.isAtom(type))) {
+			throw new ParseException("multipart/related stream invalid, type parameter should be "
+							+ Constants.ATOM_MEDIA_TYPE);
+		}
+
+		PushbackInputStream pushBackInput = new PushbackInputStream(request.getInputStream(), 2);
+		pushBackInput.unread("\r\n".getBytes());
+
+		MultipartInputStream multipart = new MultipartInputStream(pushBackInput, boundary.getBytes());
+
+		multipart.skipBoundary();
+
+		//get the media link entry
+		Map<String, String> entryHeaders = getHeaders(multipart);
+		if (!(entryHeaders.get("content-type") != null &&
+				MimeTypeHelper.isAtom(entryHeaders.get("content-type")))) {
+			throw new ParseException("multipart/related stream invalid, media link entry content-type is missing");				
+		}
+		Document<Entry> entry = getEntry(multipart, request);
+		
+		multipart.skipBoundary();
+		
+		//get the media resource
+		Map<String, String> dataHeaders = getHeaders(multipart);
+		if (dataHeaders.get("content-type") == null) {
+			throw new ParseException("multipart/related stream invalid, data content-type is missing");				
+		}
+		if (!isContentTypeAccepted(dataHeaders.get("content-type"), request)) {
+			throw new ParseException("multipart/related stream invalid, content-type not accepted into a multipart file");
+		}
+		ByteArrayInputStream data = new ByteArrayInputStream(new BASE64Decoder().decodeBuffer(multipart));;		
+
+		return new MultipartRelatedPost(entry, data, entryHeaders, dataHeaders);
+	}
+	
+	private Map<String, String> getHeaders(MultipartInputStream multipart) throws IOException, MessagingException {
+		Map<String, String> mapHeaders = new HashMap<String, String>();
+		moveToHeaders(multipart);
+		InternetHeaders headers = new InternetHeaders(multipart);
+		
+		Enumeration<Header> allHeaders = headers.getAllHeaders();
+		if (allHeaders != null) {
+			while (allHeaders.hasMoreElements()) {
+				Header header = allHeaders.nextElement();
+				mapHeaders.put(header.getName().toLowerCase(), header.getValue());
+			}
+		}
+		
+		return mapHeaders;
+	}
+
+	private boolean moveToHeaders(InputStream stream) throws IOException {
+		boolean dash = false;
+		boolean cr = false;
+		int byteReaded;
+		
+		while ((byteReaded = stream.read()) != -1) {
+			switch (byteReaded) {
+			case '\r':
+				cr = true;
+				dash = false;
+				break;
+			case '\n':
+				if (cr == true)
+					return true;
+				dash = false;
+				break;
+			case '-':
+				if (dash == true) { // two dashes
+					stream.close();
+					return false;
+				}
+				dash = true;
+				cr = false;
+				break;
+			default:
+				dash = false;
+				cr = false;
+			}
+		}
+		return false;
+	}
+
+	private <T extends Element> Document<T> getEntry(InputStream stream,
+			RequestContext request) throws ParseException, IOException {		
+		Parser parser = request.getAbdera().getParser();
+		if (parser == null)
+			throw new IllegalArgumentException("No Parser implementation was provided");
+		Document<?> document = parser.parse(stream, request.getResolvedUri()
+				.toString(), parser.getDefaultParserOptions());
+		return (Document<T>) document;
+	}
+	
+	private boolean isContentTypeAccepted(String contentType, RequestContext request) {
+		if (getAlternateAccepts(request) == null) {
+			return false;
+		}
+		for (Map.Entry<String, String> accept : getAlternateAccepts(request).entrySet()) {
+			if (accept.getKey().equalsIgnoreCase(contentType) &&
+					accept.getValue() != null && accept.getValue().equalsIgnoreCase(Constants.LN_ALTERNATE_MULTIPART_RELATED)) {
+				return true;
+			}
+		}
+		return false;
+	}
+
+	protected class MultipartRelatedPost {
+		private final Document<Entry> entry;
+		private final InputStream data;
+		private final Map<String, String> entryHeaders;
+		private final Map<String, String> dataHeaders;
+
+		public MultipartRelatedPost(Document<Entry> entry, InputStream data,
+				Map<String, String> entryHeaders, Map<String, String> dataHeaders) {			
+			this.entry = entry;
+			this.data = data;
+			this.entryHeaders = entryHeaders;
+			this.dataHeaders = dataHeaders;
+		}
+
+		public Document<Entry> getEntry() {
+			return entry;
+		}
+
+		public InputStream getData() {
+			return data;
+		}
+
+		public Map<String, String> getEntryHeaders() {
+			return entryHeaders;
+		}
+
+		public Map<String, String> getDataHeaders() {
+			return dataHeaders;
+		}		
+
+	}
+}

Added: incubator/abdera/java/trunk/server/src/main/java/org/apache/abdera/protocol/server/multipart/MultipartInputStream.java
URL: http://svn.apache.org/viewvc/incubator/abdera/java/trunk/server/src/main/java/org/apache/abdera/protocol/server/multipart/MultipartInputStream.java?rev=679302&view=auto
==============================================================================
--- incubator/abdera/java/trunk/server/src/main/java/org/apache/abdera/protocol/server/multipart/MultipartInputStream.java (added)
+++ incubator/abdera/java/trunk/server/src/main/java/org/apache/abdera/protocol/server/multipart/MultipartInputStream.java Thu Jul 24 01:32:59 2008
@@ -0,0 +1,212 @@
+/*
+ * 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.multipart;
+
+import java.io.FilterInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Arrays;
+
+/**
+ * InputStream that reads a given inputStream and skips the boundary tokens.
+ *
+ */
+public class MultipartInputStream extends FilterInputStream {
+
+	private InputStream input;
+	private byte[] boundary;	
+	private byte[] storedBuffer;
+	private int storedBufferPosition;	
+	private boolean fakeEof;
+	private boolean realEof;
+	private boolean bufferEnd;
+	private int[] lastTable = new int[256];	
+
+	public MultipartInputStream(InputStream input, byte[] boundary) {
+		super(input);
+		this.input = input;
+		this.boundary = boundary;
+		computeLastTable();
+	}
+	
+	public void skipBoundary() throws IOException {
+		byte[] buffer = new byte[256];		
+		while (read(buffer) != -1) {}
+	}
+
+	@Override
+	public int read() throws IOException {
+		byte[] b = new byte[1];
+		if (read(b) == -1) {
+			return -1;
+		}
+		return b[0] & 0xff;
+	}
+
+	@Override
+	public int read(byte[] bytes) throws IOException {
+		return read(bytes, 0, bytes.length);		
+	}
+
+	@Override
+	public int read(byte[] buffer, int offset, int length) throws IOException {
+		if (length == 0) {
+			return 0;
+		}
+		
+		int bytesReaded = -1;
+		if (!checkEndOfFile()) {				
+			int bufferLength = Math.max(boundary.length * 3/*number of tokens into the stream*/, length + boundary.length);
+	
+			byte[] newBuffer = new byte[bufferLength];
+	
+			int position = cleanStoredBuffer(newBuffer, 0, bufferLength);
+			if (bufferLength >= position) {
+				position += readBuffer(newBuffer, position, bufferLength - position);
+			}
+	
+			if (realEof && position == 0) {
+				return -1;
+			}
+	
+			bytesReaded = getBytesReaded(buffer, newBuffer, offset, position, length);
+		}
+		return bytesReaded != 0?bytesReaded:-1;
+	}
+	
+	private int readBuffer(byte[] buffer, int offset, int length) throws IOException {
+		int count = 0;
+		int read = 0;
+
+		do {
+			read = input.read(buffer, offset + count, length - count);
+			if (read > 0) {
+				count += read;
+			}
+		} while (read > 0 && count < length);
+
+		if (read < 0) {
+			realEof = true;
+		}
+
+		return count;
+	}		
+	
+	private boolean checkEndOfFile() {
+		if (fakeEof) {
+			fakeEof = false;
+			return true;
+		}
+
+		if (realEof && storedBuffer == null) {			
+				return true;
+		}
+		if (realEof && !bufferEnd) {
+			bufferEnd = true;
+		}
+		
+		return false;
+	}
+	
+	private int getBytesReaded(byte[] buffer, byte[] newBuffer, int offSet, int position, int length) {		
+		int boundaryPosition = locateBoundary(newBuffer, boundary.length - 1, position);
+		int bytesReaded;
+				
+		if (length < boundaryPosition || boundaryPosition == -1) {// boundary not found
+			bytesReaded = Math.min(length, position);
+			createStoredBuffer(newBuffer, bytesReaded, position);
+		} else {
+			bytesReaded = boundaryPosition;
+			createStoredBuffer(newBuffer, bytesReaded + boundary.length, position);
+
+			if (bytesReaded == 0) {
+				return -1;
+			}
+
+			fakeEof = true;
+		}
+		
+		System.arraycopy(newBuffer, 0, buffer, offSet, bytesReaded);
+		return bytesReaded;
+	}
+	
+	private void createStoredBuffer(byte[] buffer, int start, int end) {
+		int length = end - start;
+
+		if (length > 0) {		
+			if (bufferEnd && storedBuffer != null) {
+				storedBufferPosition -= length;				
+			} else {
+				int bufferLength = (storedBuffer == null?0:storedBuffer.length - storedBufferPosition);
+				byte[] newBuffer = new byte[length + bufferLength];
+				System.arraycopy(buffer, start, newBuffer, 0, length);
+		
+				if (storedBuffer != null) {
+					System.arraycopy(storedBuffer, storedBufferPosition, newBuffer, length, bufferLength);
+				}
+		
+				storedBuffer = newBuffer;
+				storedBufferPosition = 0;
+			}
+		}
+	}
+
+	private int cleanStoredBuffer(byte[] buffer, int offset, int length) {
+		int i = 0;
+		
+		if (storedBuffer != null) {
+			for (i = 0; i < length && storedBufferPosition < storedBuffer.length; i++) {
+				buffer[offset + i] = storedBuffer[storedBufferPosition++];
+			}
+
+			if (storedBufferPosition >= storedBuffer.length) {
+				storedBuffer = null;
+				storedBufferPosition = 0;
+			}
+		}
+
+		return i;
+	}
+	
+	/*computation of the last table*/
+	private void computeLastTable() {
+		Arrays.fill(lastTable, boundary.length);
+		for (int i = 0; i < boundary.length - 1; i++) {
+			lastTable[boundary[i] & 0xff] = boundary.length - i - 1;
+		}
+	}
+
+	/*simplified boyer-moore algorithm*/
+	private int locateBoundary(byte[] bytes, int start, int end) {
+		int position = -1;
+		if (end > boundary.length) {			
+			int j = 0;
+			int k = 0;
+			for (int i = start; i < end; i += lastTable[bytes[i] & 0xff]) {			
+				for (k = i, j = boundary.length - 1; j >= 0 && boundary[j] == bytes[k]; j--) {
+					k--;
+				}
+				if (j == -1) {
+					position = k + 1;
+				}
+			}
+		}
+		return position;
+	}
+
+}

Added: incubator/abdera/java/trunk/server/src/main/java/org/apache/abdera/protocol/server/multipart/MultipartRelatedCollectionInfo.java
URL: http://svn.apache.org/viewvc/incubator/abdera/java/trunk/server/src/main/java/org/apache/abdera/protocol/server/multipart/MultipartRelatedCollectionInfo.java?rev=679302&view=auto
==============================================================================
--- incubator/abdera/java/trunk/server/src/main/java/org/apache/abdera/protocol/server/multipart/MultipartRelatedCollectionInfo.java (added)
+++ incubator/abdera/java/trunk/server/src/main/java/org/apache/abdera/protocol/server/multipart/MultipartRelatedCollectionInfo.java Thu Jul 24 01:32:59 2008
@@ -0,0 +1,17 @@
+package org.apache.abdera.protocol.server.multipart;
+
+import java.util.Map;
+
+import org.apache.abdera.protocol.server.CollectionInfo;
+import org.apache.abdera.protocol.server.RequestContext;
+
+public interface MultipartRelatedCollectionInfo extends CollectionInfo {
+	
+	/**
+	   * Returns a map of MIME media types for the app:collection element's 
+	   * app:accept elements.  These tell a client which media types the collection
+	   * will accept on a POST. 
+	   * The key element is the default media type and the value element is the alternate type or null if it doesn't accept alternates. 
+	   */
+	public Map<String, String> getAlternateAccepts(RequestContext request);
+}

Added: incubator/abdera/java/trunk/server/src/main/java/org/apache/abdera/protocol/server/processors/MultipartRelatedServiceRequestProcessor.java
URL: http://svn.apache.org/viewvc/incubator/abdera/java/trunk/server/src/main/java/org/apache/abdera/protocol/server/processors/MultipartRelatedServiceRequestProcessor.java?rev=679302&view=auto
==============================================================================
--- incubator/abdera/java/trunk/server/src/main/java/org/apache/abdera/protocol/server/processors/MultipartRelatedServiceRequestProcessor.java (added)
+++ incubator/abdera/java/trunk/server/src/main/java/org/apache/abdera/protocol/server/processors/MultipartRelatedServiceRequestProcessor.java Thu Jul 24 01:32:59 2008
@@ -0,0 +1,81 @@
+package org.apache.abdera.protocol.server.processors;
+
+import java.io.IOException;
+import java.util.Collection;
+import java.util.Map;
+
+import org.apache.abdera.protocol.server.CategoriesInfo;
+import org.apache.abdera.protocol.server.CategoryInfo;
+import org.apache.abdera.protocol.server.CollectionInfo;
+import org.apache.abdera.protocol.server.RequestContext;
+import org.apache.abdera.protocol.server.ResponseContext;
+import org.apache.abdera.protocol.server.WorkspaceInfo;
+import org.apache.abdera.protocol.server.WorkspaceManager;
+import org.apache.abdera.protocol.server.context.StreamWriterResponseContext;
+import org.apache.abdera.protocol.server.multipart.MultipartRelatedCollectionInfo;
+import org.apache.abdera.util.Constants;
+import org.apache.abdera.writer.StreamWriter;
+
+/**
+ * {@link org.apache.abdera.protocol.server.RequestProcessor} implementation which
+ * processes requests for service documents. 
+ * It writes multipart/related accept attributes when is enabled.
+ */
+public class MultipartRelatedServiceRequestProcessor extends ServiceRequestProcessor {
+
+	@Override	
+	protected ResponseContext getServiceDocument(final RequestContext request, final WorkspaceManager workspaceManager) {
+        return new StreamWriterResponseContext(request.getAbdera()) {
+
+            protected void writeTo(StreamWriter sw) throws IOException {
+                sw.startDocument().startService();
+                for (WorkspaceInfo wi : workspaceManager.getWorkspaces(request)) {
+                    sw.startWorkspace().writeTitle(wi.getTitle(request));
+                    Collection<CollectionInfo> collections = wi.getCollections(request);
+                    
+                    if (collections != null) {
+                        for (CollectionInfo ci : collections) {
+                            sw.startCollection(ci.getHref(request)).writeTitle(ci.getTitle(request));                            
+                            if (ci instanceof MultipartRelatedCollectionInfo) {
+                            	MultipartRelatedCollectionInfo multipartCi = (MultipartRelatedCollectionInfo) ci;
+                            	for (Map.Entry<String, String> accept : multipartCi.getAlternateAccepts(request).entrySet()) {
+                            		sw.startElement(Constants.ACCEPT);
+                            		if (accept.getValue() != null && accept.getValue().length() > 0) {
+                            			sw.writeAttribute(Constants.LN_ALTERNATE, accept.getValue());
+                            		}
+                            		sw.writeElementText(accept.getKey()).endElement();
+                            	}
+                            } else {
+                            	sw.writeAccepts(ci.getAccepts(request));
+                            }
+                            CategoriesInfo[] catinfos = ci.getCategoriesInfo(request);
+                            if (catinfos != null) {
+                                for (CategoriesInfo catinfo : catinfos) {
+                                    String cathref = catinfo.getHref(request);
+                                    if (cathref != null) {
+                                        sw.startCategories().writeAttribute("href", request.getTargetBasePath() + cathref).endCategories();
+                                    } else {
+                                        sw.startCategories(
+                                                catinfo.isFixed(request),
+                                                catinfo.getScheme(request));
+                                        for (CategoryInfo cat : catinfo) {
+                                            sw.writeCategory(
+                                                    cat.getTerm(request),
+                                                    cat.getScheme(request),
+                                                    cat.getLabel(request));
+                                        }
+                                        sw.endCategories();
+                                    }
+                                }
+                            }
+                            sw.endCollection();
+                        }
+                    }
+                    sw.endWorkspace();
+                }
+                sw.endService().endDocument();
+            }
+        }.setStatus(200).setContentType(Constants.APP_MEDIA_TYPE);
+    }
+	
+}

Modified: incubator/abdera/java/trunk/server/src/main/java/org/apache/abdera/protocol/server/processors/ServiceRequestProcessor.java
URL: http://svn.apache.org/viewvc/incubator/abdera/java/trunk/server/src/main/java/org/apache/abdera/protocol/server/processors/ServiceRequestProcessor.java?rev=679302&r1=679301&r2=679302&view=diff
==============================================================================
--- incubator/abdera/java/trunk/server/src/main/java/org/apache/abdera/protocol/server/processors/ServiceRequestProcessor.java (original)
+++ incubator/abdera/java/trunk/server/src/main/java/org/apache/abdera/protocol/server/processors/ServiceRequestProcessor.java Thu Jul 24 01:32:59 2008
@@ -51,7 +51,7 @@
         }
     }
 
-    private ResponseContext getServiceDocument(final RequestContext request, final WorkspaceManager workspaceManager) {
+    protected ResponseContext getServiceDocument(final RequestContext request, final WorkspaceManager workspaceManager) {
         return new StreamWriterResponseContext(request.getAbdera()) {
 
             protected void writeTo(

Modified: incubator/abdera/java/trunk/server/src/test/java/org/apache/abdera/protocol/server/test/TestSuite.java
URL: http://svn.apache.org/viewvc/incubator/abdera/java/trunk/server/src/test/java/org/apache/abdera/protocol/server/test/TestSuite.java?rev=679302&r1=679301&r2=679302&view=diff
==============================================================================
--- incubator/abdera/java/trunk/server/src/test/java/org/apache/abdera/protocol/server/test/TestSuite.java (original)
+++ incubator/abdera/java/trunk/server/src/test/java/org/apache/abdera/protocol/server/test/TestSuite.java Thu Jul 24 01:32:59 2008
@@ -20,6 +20,7 @@
 import org.apache.abdera.protocol.server.test.basic.BasicTest;
 import org.apache.abdera.protocol.server.test.custom.CustomProviderTest;
 import org.apache.abdera.protocol.server.test.customer.CustomerAdapterTest;
+import org.apache.abdera.protocol.server.test.multipart.MultipartRelatedTest;
 import org.apache.abdera.protocol.server.test.route.RouteTest;
 import org.junit.internal.runners.TextListener;
 import org.junit.runner.JUnitCore;
@@ -33,6 +34,7 @@
       RouteTest.class,
       CustomerAdapterTest.class,
       CustomProviderTest.class,
-      BasicTest.class);
+      BasicTest.class,
+      MultipartRelatedTest.class);
   }
 }

Added: incubator/abdera/java/trunk/server/src/test/java/org/apache/abdera/protocol/server/test/multipart/MultipartRelatedAdapter.java
URL: http://svn.apache.org/viewvc/incubator/abdera/java/trunk/server/src/test/java/org/apache/abdera/protocol/server/test/multipart/MultipartRelatedAdapter.java?rev=679302&view=auto
==============================================================================
--- incubator/abdera/java/trunk/server/src/test/java/org/apache/abdera/protocol/server/test/multipart/MultipartRelatedAdapter.java (added)
+++ incubator/abdera/java/trunk/server/src/test/java/org/apache/abdera/protocol/server/test/multipart/MultipartRelatedAdapter.java Thu Jul 24 01:32:59 2008
@@ -0,0 +1,84 @@
+package org.apache.abdera.protocol.server.test.multipart;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.mail.MessagingException;
+
+import org.apache.abdera.parser.ParseException;
+import org.apache.abdera.protocol.server.ProviderHelper;
+import org.apache.abdera.protocol.server.RequestContext;
+import org.apache.abdera.protocol.server.ResponseContext;
+import org.apache.abdera.protocol.server.context.EmptyResponseContext;
+import org.apache.abdera.protocol.server.multipart.AbstractMultipartCollectionAdapter;
+import org.apache.abdera.util.Constants;
+import org.apache.abdera.util.MimeTypeHelper;
+
+public class MultipartRelatedAdapter extends AbstractMultipartCollectionAdapter {
+
+	@Override
+	public String getAuthor(RequestContext request) {
+	    return "Acme Industries";
+	}
+
+	@Override
+	public String getId(RequestContext request) {
+		return "tag:example.org,2008:feed";
+	}
+
+	public ResponseContext deleteEntry(RequestContext request) {
+		return ProviderHelper.notallowed(request);
+	}
+
+	public ResponseContext getEntry(RequestContext request) {
+		return ProviderHelper.notallowed(request);
+	}
+
+	public ResponseContext getFeed(RequestContext request) {
+		return ProviderHelper.notallowed(request);
+	}
+
+	public ResponseContext postEntry(RequestContext request) {
+		return ProviderHelper.notallowed(request);
+	}
+
+	public ResponseContext putEntry(RequestContext request) {
+		return ProviderHelper.notallowed(request);
+	}
+	
+	public ResponseContext postMedia(RequestContext request) {
+		try {
+			if (MimeTypeHelper.isMultipart(request.getContentType().toString())) {
+				MultipartRelatedPost post = getMultipartRelatedData(request);
+				//Post object is a wrapper for the media resource and the media link entry.
+				//Once we get it we can save them following the rfc specification.
+			}
+			
+			return new EmptyResponseContext(201);
+		} catch (ParseException pe) {			
+			return new EmptyResponseContext(415, pe.getLocalizedMessage());
+		} catch (IOException ioe) {			
+			return new EmptyResponseContext(500, ioe.getLocalizedMessage());
+		} catch (MessagingException e) {			
+			return new EmptyResponseContext(500, e.getLocalizedMessage());
+		}
+	}
+
+	public String getTitle(RequestContext request) {
+		return "Acme Multipart/related adapter";
+	}
+
+	@SuppressWarnings("serial")
+	public Map<String, String> getAlternateAccepts(RequestContext request) {
+		if (accepts == null) {
+			accepts = new HashMap<String, String>() {{
+				put("video/*", null); /* doesn't accept multipart related */
+				put("image/jpg", ""); /* doesn't accept multipart related */
+				put("image/png", Constants.LN_ALTERNATE_MULTIPART_RELATED /*multipart-related*/);
+			}};
+		}
+		return accepts;
+	}
+
+}

Added: incubator/abdera/java/trunk/server/src/test/java/org/apache/abdera/protocol/server/test/multipart/MultipartRelatedTest.java
URL: http://svn.apache.org/viewvc/incubator/abdera/java/trunk/server/src/test/java/org/apache/abdera/protocol/server/test/multipart/MultipartRelatedTest.java?rev=679302&view=auto
==============================================================================
--- incubator/abdera/java/trunk/server/src/test/java/org/apache/abdera/protocol/server/test/multipart/MultipartRelatedTest.java (added)
+++ incubator/abdera/java/trunk/server/src/test/java/org/apache/abdera/protocol/server/test/multipart/MultipartRelatedTest.java Thu Jul 24 01:32:59 2008
@@ -0,0 +1,110 @@
+package org.apache.abdera.protocol.server.test.multipart;
+
+import java.io.StringWriter;
+import java.util.HashMap;
+
+import junit.framework.Assert;
+
+import org.apache.abdera.Abdera;
+import org.apache.abdera.factory.Factory;
+import org.apache.abdera.i18n.iri.IRI;
+import org.apache.abdera.model.Entry;
+import org.apache.abdera.protocol.client.AbderaClient;
+import org.apache.abdera.protocol.client.ClientResponse;
+import org.apache.abdera.protocol.server.Provider;
+import org.apache.abdera.protocol.server.RequestProcessor;
+import org.apache.abdera.protocol.server.TargetType;
+import org.apache.abdera.protocol.server.impl.DefaultProvider;
+import org.apache.abdera.protocol.server.impl.SimpleWorkspaceInfo;
+import org.apache.abdera.protocol.server.processors.MultipartRelatedServiceRequestProcessor;
+import org.apache.abdera.protocol.server.servlet.AbderaServlet;
+import org.junit.After;
+import org.junit.Test;
+import org.mortbay.jetty.Server;
+import org.mortbay.jetty.servlet.Context;
+import org.mortbay.jetty.servlet.ServletHolder;
+
+@SuppressWarnings("serial")
+public class MultipartRelatedTest extends Assert {
+
+	private Server server;
+
+	private void initializeJetty(String contextPath) throws Exception {
+		server = new Server(9002);
+		Context root = new Context(server, contextPath, Context.NO_SESSIONS);
+		root.addServlet(new ServletHolder(new AbderaServlet() {
+			@Override
+			protected Provider createProvider() {
+				DefaultProvider provider = new DefaultProvider("/");
+				provider.addRequestProcessors(new HashMap<TargetType, RequestProcessor>() {
+					{put(TargetType.TYPE_SERVICE,new MultipartRelatedServiceRequestProcessor());}
+				});
+
+				MultipartRelatedAdapter ca = new MultipartRelatedAdapter();
+				ca.setHref("media");
+
+				SimpleWorkspaceInfo wi = new SimpleWorkspaceInfo();
+				wi.setTitle("multimedia/related Workspace");
+				wi.addCollection(ca);
+
+				provider.addWorkspace(wi);
+
+				provider.init(getAbdera(), null);
+				return provider;
+			}
+		}), "/*");
+		server.start();
+	}
+
+	@After
+	public void tearDown() throws Exception {
+		if (server != null) server.stop();
+	}
+	
+	@Test
+	public void testServiceDocument() throws Exception {
+		initializeJetty("/");		
+		AbderaClient client = new AbderaClient(new Abdera());
+		
+		ClientResponse res = client.get("http://localhost:9002/");
+		assertEquals(200, res.getStatus());
+		StringWriter sw = new StringWriter();
+		res.getDocument().writeTo(sw);	
+				
+		assertTrue(sw.toString().contains("accept alternate=\"multipart-related\">image/png"));
+		assertTrue(sw.toString().contains("accept>video/*"));
+		assertTrue(sw.toString().contains("accept>image/jpg"));
+	}
+
+	@Test
+	public void testPostMedia() throws Exception {
+		execTest(201, "image/png");
+	}
+	
+	@Test
+	public void testPostMediaInvalidContentType() throws Exception {
+		//collection doesn't accept multipart files with this content type
+		execTest(415, "image/jpg");
+	}
+	
+	private void execTest(int status, String contentType) throws Exception {
+		initializeJetty("/");
+
+		Abdera abdera = new Abdera();
+		Factory factory = abdera.getFactory();
+
+		AbderaClient client = new AbderaClient(abdera);
+
+		Entry entry = factory.newEntry();
+
+		entry.setTitle("my image");
+		entry.addAuthor("david");
+		entry.setId("tag:apache.org,2008:234534344");
+		entry.setSummary("multipart test");		
+		entry.setContent(new IRI("cid:234234@example.com"), contentType);
+
+		ClientResponse res = client.post("http://localhost:9002/media", entry,
+				this.getClass().getResourceAsStream("info.png"));
+		assertEquals(status, res.getStatus());
+	}
+}

Added: incubator/abdera/java/trunk/server/src/test/resources/org/apache/abdera/protocol/server/test/multipart/info.png
URL: http://svn.apache.org/viewvc/incubator/abdera/java/trunk/server/src/test/resources/org/apache/abdera/protocol/server/test/multipart/info.png?rev=679302&view=auto
==============================================================================
Binary file - no diff available.

Propchange: incubator/abdera/java/trunk/server/src/test/resources/org/apache/abdera/protocol/server/test/multipart/info.png
------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream



Mime
View raw message