You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@abdera.apache.org by jm...@apache.org on 2007/08/21 02:51:29 UTC

svn commit: r567888 [4/4] - in /incubator/abdera/java/trunk: ./ build/ extensions/ extensions/gdata/ extensions/gdata/src/ extensions/gdata/src/main/ extensions/gdata/src/main/java/ extensions/gdata/src/main/java/org/ extensions/gdata/src/main/java/org...

Added: incubator/abdera/java/trunk/extensions/media/src/main/resources/META-INF/services/org.apache.abdera.factory.ExtensionFactory
URL: http://svn.apache.org/viewvc/incubator/abdera/java/trunk/extensions/media/src/main/resources/META-INF/services/org.apache.abdera.factory.ExtensionFactory?rev=567888&view=auto
==============================================================================
--- incubator/abdera/java/trunk/extensions/media/src/main/resources/META-INF/services/org.apache.abdera.factory.ExtensionFactory (added)
+++ incubator/abdera/java/trunk/extensions/media/src/main/resources/META-INF/services/org.apache.abdera.factory.ExtensionFactory Mon Aug 20 17:51:20 2007
@@ -0,0 +1 @@
+org.apache.abdera.ext.media.MediaExtensionFactory

Added: incubator/abdera/java/trunk/extensions/media/src/test/java/org/apache/abdera/test/ext/media/MediaTest.java
URL: http://svn.apache.org/viewvc/incubator/abdera/java/trunk/extensions/media/src/test/java/org/apache/abdera/test/ext/media/MediaTest.java?rev=567888&view=auto
==============================================================================
--- incubator/abdera/java/trunk/extensions/media/src/test/java/org/apache/abdera/test/ext/media/MediaTest.java (added)
+++ incubator/abdera/java/trunk/extensions/media/src/test/java/org/apache/abdera/test/ext/media/MediaTest.java Mon Aug 20 17:51:20 2007
@@ -0,0 +1,84 @@
+/*
+* 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.test.ext.media;
+
+import junit.framework.TestCase;
+import org.apache.abdera.Abdera;
+import org.apache.abdera.factory.Factory;
+import org.apache.abdera.parser.Parser;
+import org.apache.abdera.model.Document;
+import org.apache.abdera.model.Entry;
+import org.apache.abdera.ext.media.MediaGroup;
+import org.apache.abdera.ext.media.MediaContent;
+import org.apache.abdera.ext.media.MediaTitle;
+
+import java.io.ByteArrayOutputStream;
+import java.io.ByteArrayInputStream;
+import java.util.List;
+
+import static org.apache.abdera.ext.media.MediaConstants.*;
+
+public class MediaTest extends TestCase {
+
+  public static void testMedia() throws Exception {
+    
+    Abdera abdera = new Abdera();
+    Factory factory = abdera.getFactory();
+    Entry entry = factory.newEntry();
+    MediaGroup group = entry.addExtension(GROUP);
+    MediaContent content = group.addExtension(CONTENT);
+    content.setUrl("http://example.org");
+    content.setBitrate(123);
+    content.setChannels(2);
+    content.setDuration(123);
+    content.setExpression(Expression.SAMPLE);
+    content.setFilesize(12345);
+    content.setFramerate(123);
+    content.setLanguage("en");
+    MediaTitle title = content.addExtension(TITLE);
+    title.setType(Type.PLAIN);
+    title.setText("This is a sample");
+    
+    ByteArrayOutputStream out = new ByteArrayOutputStream();
+    entry.writeTo(out);
+    
+    ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray());
+    Parser parser = abdera.getParser();
+    Document<Entry> doc = parser.parse(in);
+    entry = doc.getRoot();
+    
+    group = entry.getExtension(GROUP);
+    List<MediaContent> list = entry.getExtensions(CONTENT);
+    for (MediaContent item : list) {
+      assertEquals(item.getUrl().toString(), "http://example.org");
+      assertEquals(item.getBitrate(), 123);
+      assertEquals(item.getChannels(), 2);
+      assertEquals(item.getDuration(), 123);
+      assertEquals(item.getExpression(), Expression.SAMPLE);
+      assertEquals(item.getFilesize(), 12345);
+      assertEquals(item.getFramerate(), 123);
+      assertEquals(item.getLang(), "en");
+      title = item.getExtension(TITLE);
+      assertNotNull(title);
+      assertEquals(title.getType(), Type.PLAIN);
+      assertEquals(title.getText(), "This is a sample");
+    }
+  }
+  
+}
+ 
\ No newline at end of file

Added: incubator/abdera/java/trunk/extensions/media/src/test/java/org/apache/abdera/test/ext/media/TestSuite.java
URL: http://svn.apache.org/viewvc/incubator/abdera/java/trunk/extensions/media/src/test/java/org/apache/abdera/test/ext/media/TestSuite.java?rev=567888&view=auto
==============================================================================
--- incubator/abdera/java/trunk/extensions/media/src/test/java/org/apache/abdera/test/ext/media/TestSuite.java (added)
+++ incubator/abdera/java/trunk/extensions/media/src/test/java/org/apache/abdera/test/ext/media/TestSuite.java Mon Aug 20 17:51:20 2007
@@ -0,0 +1,30 @@
+/*
+* 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.test.ext.media;
+
+public class TestSuite extends junit.framework.TestSuite {
+  public static void main(String[] args)
+  {
+    junit.textui.TestRunner.run(new TestSuite());
+  }
+
+  public TestSuite()
+  {
+    addTestSuite(MediaTest.class);
+  }
+}

Added: incubator/abdera/java/trunk/extensions/opensearch/pom.xml
URL: http://svn.apache.org/viewvc/incubator/abdera/java/trunk/extensions/opensearch/pom.xml?rev=567888&view=auto
==============================================================================
--- incubator/abdera/java/trunk/extensions/opensearch/pom.xml (added)
+++ incubator/abdera/java/trunk/extensions/opensearch/pom.xml Mon Aug 20 17:51:20 2007
@@ -0,0 +1,92 @@
+<?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.3.0-incubating-SNAPSHOT</version>
+  </parent>  
+  <modelVersion>4.0.0</modelVersion>
+  <artifactId>abdera-extensions-opensearch</artifactId>
+  <packaging>jar</packaging>
+  <name>Abdera Extensions - OpenSearch</name>
+  <version>0.3.0-incubating-SNAPSHOT</version>
+  <description>Atom Specification Extensions - OpenSearch</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/extensions/opensearch</connection>
+    <developerConnection>scm:svn:https://svn.apache.org/repos/asf/incubator/abdera/java/trunk/extensions/opensearch</developerConnection>
+    <url>http://svn.apache.org/repos/asf/incubator/abdera/java/trunk/extensions/opensearch</url>
+  </scm>
+  <dependencies>
+    <dependency>
+      <groupId>org.apache.abdera</groupId>
+      <artifactId>abdera-core</artifactId>
+      <version>0.3.0-incubating-SNAPSHOT</version>
+      <scope>compile</scope>
+    </dependency>    
+    <dependency>
+      <groupId>org.apache.abdera</groupId>
+      <artifactId>abdera-parser</artifactId>
+      <version>0.3.0-incubating-SNAPSHOT</version>
+      <scope>compile</scope>
+    </dependency>   
+    <dependency>
+      <groupId>org.apache.abdera</groupId>
+      <artifactId>abdera-protocol</artifactId>
+      <version>0.3.0-incubating-SNAPSHOT</version>
+      <scope>compile</scope>
+    </dependency>  
+    <dependency>
+      <groupId>org.apache.abdera</groupId>
+      <artifactId>abdera-client</artifactId>
+      <version>0.3.0-incubating-SNAPSHOT</version>
+      <scope>compile</scope>
+    </dependency>  
+    <dependency>
+      <groupId>org.apache.abdera</groupId>
+      <artifactId>json</artifactId>
+      <version>1.0</version>
+      <scope>compile</scope>
+    </dependency>   
+    <dependency>
+      <groupId>org.apache.ws.commons.axiom</groupId>
+      <artifactId>axiom-api</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.ws.commons.axiom</groupId>
+      <artifactId>axiom-impl</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>stax</groupId>
+      <artifactId>stax-api</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.codehaus.woodstox</groupId>
+      <artifactId>wstx-asl</artifactId>
+    </dependency> 
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+    </dependency>
+  </dependencies>
+</project>

Added: incubator/abdera/java/trunk/extensions/opensearch/src/main/java/org/apache/abdera/ext/opensearch/IntegerElement.java
URL: http://svn.apache.org/viewvc/incubator/abdera/java/trunk/extensions/opensearch/src/main/java/org/apache/abdera/ext/opensearch/IntegerElement.java?rev=567888&view=auto
==============================================================================
--- incubator/abdera/java/trunk/extensions/opensearch/src/main/java/org/apache/abdera/ext/opensearch/IntegerElement.java (added)
+++ incubator/abdera/java/trunk/extensions/opensearch/src/main/java/org/apache/abdera/ext/opensearch/IntegerElement.java Mon Aug 20 17:51:20 2007
@@ -0,0 +1,46 @@
+/*
+* 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.ext.opensearch;
+
+import javax.xml.namespace.QName;
+
+import org.apache.abdera.factory.Factory;
+import org.apache.abdera.model.Element;
+import org.apache.abdera.model.ElementWrapper;
+
+public class IntegerElement 
+  extends ElementWrapper {
+
+  public IntegerElement(Element internal) {
+    super(internal);
+  }
+
+  public IntegerElement(Factory factory, QName qname) {
+    super(factory, qname);
+  }
+
+  public int getValue() {
+    String val = getText();
+    return (val != null) ? Integer.parseInt(val) : -1;
+  }
+  
+  public void setValue(int value) {
+    setText(String.valueOf(value));
+  }
+  
+}

Added: incubator/abdera/java/trunk/extensions/opensearch/src/main/java/org/apache/abdera/ext/opensearch/OpenSearchConstants.java
URL: http://svn.apache.org/viewvc/incubator/abdera/java/trunk/extensions/opensearch/src/main/java/org/apache/abdera/ext/opensearch/OpenSearchConstants.java?rev=567888&view=auto
==============================================================================
--- incubator/abdera/java/trunk/extensions/opensearch/src/main/java/org/apache/abdera/ext/opensearch/OpenSearchConstants.java (added)
+++ incubator/abdera/java/trunk/extensions/opensearch/src/main/java/org/apache/abdera/ext/opensearch/OpenSearchConstants.java Mon Aug 20 17:51:20 2007
@@ -0,0 +1,44 @@
+/*
+* 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.ext.opensearch;
+
+import javax.xml.namespace.QName;
+
+public interface OpenSearchConstants {
+
+  public static final String OPENSEARCH_V10_NS = "http://a9.com/-/spec/opensearchrss/1.0/";
+  public static final String OPENSEARCH_NS = "http://a9.com/-/spec/opensearchrss/1.1/";
+
+  public static final String TOTAL_RESULTS_LN  = "totalResults";
+  public static final String ITEMS_PER_PAGE_LN = "itemsPerPage";
+  public static final String START_INDEX_LN    = "startIndex";
+  public static final String QUERY_LN          = "Query";
+
+  public static final String OS_PREFIX = "os";
+  
+  public static final QName TOTAL_RESULTS_V10  = new QName(OPENSEARCH_V10_NS, TOTAL_RESULTS_LN);
+  public static final QName ITEMS_PER_PAGE_V10 = new QName(OPENSEARCH_V10_NS, ITEMS_PER_PAGE_LN);
+  public static final QName START_INDEX_V10    = new QName(OPENSEARCH_V10_NS, START_INDEX_LN);
+  public static final QName QUERY_V10          = new QName(OPENSEARCH_V10_NS, QUERY_LN, OS_PREFIX);
+  
+  public static final QName TOTAL_RESULTS  = new QName(OPENSEARCH_NS, TOTAL_RESULTS_LN, OS_PREFIX);
+  public static final QName ITEMS_PER_PAGE = new QName(OPENSEARCH_NS, ITEMS_PER_PAGE_LN, OS_PREFIX);
+  public static final QName START_INDEX    = new QName(OPENSEARCH_NS, START_INDEX_LN, OS_PREFIX);
+  public static final QName QUERY          = new QName(OPENSEARCH_NS, QUERY_LN, OS_PREFIX);
+
+}

Added: incubator/abdera/java/trunk/extensions/opensearch/src/main/java/org/apache/abdera/ext/opensearch/OpenSearchExtensionFactory.java
URL: http://svn.apache.org/viewvc/incubator/abdera/java/trunk/extensions/opensearch/src/main/java/org/apache/abdera/ext/opensearch/OpenSearchExtensionFactory.java?rev=567888&view=auto
==============================================================================
--- incubator/abdera/java/trunk/extensions/opensearch/src/main/java/org/apache/abdera/ext/opensearch/OpenSearchExtensionFactory.java (added)
+++ incubator/abdera/java/trunk/extensions/opensearch/src/main/java/org/apache/abdera/ext/opensearch/OpenSearchExtensionFactory.java Mon Aug 20 17:51:20 2007
@@ -0,0 +1,40 @@
+/*
+* 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.ext.opensearch;
+
+import org.apache.abdera.util.AbstractExtensionFactory;
+
+public final class OpenSearchExtensionFactory 
+  extends AbstractExtensionFactory
+  implements OpenSearchConstants {
+
+  public OpenSearchExtensionFactory() {
+    super(
+      OpenSearchConstants.OPENSEARCH_NS, 
+      OpenSearchConstants.OPENSEARCH_V10_NS);
+    addImpl(QUERY,Query.class);
+    addImpl(QUERY_V10,Query.class);
+    addImpl(ITEMS_PER_PAGE, IntegerElement.class);
+    addImpl(START_INDEX, IntegerElement.class);
+    addImpl(TOTAL_RESULTS, IntegerElement.class);
+    addImpl(ITEMS_PER_PAGE_V10, IntegerElement.class);
+    addImpl(START_INDEX_V10, IntegerElement.class);
+    addImpl(TOTAL_RESULTS_V10, IntegerElement.class);
+  }
+  
+}

Added: incubator/abdera/java/trunk/extensions/opensearch/src/main/java/org/apache/abdera/ext/opensearch/Query.java
URL: http://svn.apache.org/viewvc/incubator/abdera/java/trunk/extensions/opensearch/src/main/java/org/apache/abdera/ext/opensearch/Query.java?rev=567888&view=auto
==============================================================================
--- incubator/abdera/java/trunk/extensions/opensearch/src/main/java/org/apache/abdera/ext/opensearch/Query.java (added)
+++ incubator/abdera/java/trunk/extensions/opensearch/src/main/java/org/apache/abdera/ext/opensearch/Query.java Mon Aug 20 17:51:20 2007
@@ -0,0 +1,197 @@
+/*
+* 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.ext.opensearch;
+
+import javax.xml.namespace.QName;
+
+import org.apache.abdera.Abdera;
+import org.apache.abdera.factory.Factory;
+import org.apache.abdera.model.Element;
+import org.apache.abdera.model.ElementWrapper;
+import org.apache.abdera.model.ExtensibleElement;
+
+public class Query 
+  extends ElementWrapper {
+
+  public enum Role {
+    CORRECTION,
+    EXAMPLE,
+    RELATED,
+    REQUEST,
+    SUBSET,
+    SUPERSET;
+  }
+  
+  public Query(Element internal) {
+    super(internal);
+  }
+  
+  public Query(Factory factory) {
+    super(factory, OpenSearchConstants.QUERY);
+  }
+  
+  public Query(Abdera abdera) {
+    this(abdera.getFactory());
+  }
+  
+  public Query(ExtensibleElement parent) {
+    this(parent.getFactory());
+    parent.declareNS(
+      OpenSearchConstants.OPENSEARCH_NS, 
+      OpenSearchConstants.OS_PREFIX);
+  }
+  
+  public Role getRole() {
+    String role = getInternal().getAttributeValue("role");
+    if (role == null) return null;
+    try {
+      return Role.valueOf(role.toUpperCase());
+    } catch (Exception e) {
+      return null; // role is likely an extension. we don't currently support extension roles
+    }
+  }
+  
+  public void setRole(Role role) {
+    if (role != null) {
+      getInternal().setAttributeValue("role", role.name().toLowerCase());
+    } else {
+      getInternal().removeAttribute(new QName("role"));
+    }
+  }
+  
+  public String getTitle() {
+    return getInternal().getAttributeValue("title");
+  }
+  
+  public void setTitle(String title) {
+    if (title != null) {
+      if (title.length() > 256) throw new IllegalArgumentException("Title too long (max 256 characters)");
+      getInternal().setAttributeValue("title", title);
+    } else {
+      getInternal().removeAttribute(new QName("title"));
+    }
+  }
+
+  public int getTotalResults() {
+    String val = getInternal().getAttributeValue("totalResults");
+    return (val != null) ? Integer.parseInt(val) : -1;
+  }
+  
+  public void setTotalResults(int totalResults) {
+    if (totalResults > -1) {
+      getInternal().setAttributeValue("totalResults", String.valueOf(totalResults));
+    } else {
+      getInternal().removeAttribute(new QName("totalResults"));
+    }
+  }
+  
+  public String getSearchTerms() {
+    return getInternal().getAttributeValue("searchTerms");
+  }
+  
+  public void setSearchTerms(String terms) {
+    if (terms != null) {
+      getInternal().setAttributeValue("searchTerms", terms);
+    } else {
+      getInternal().removeAttribute(new QName("searchTerms"));
+    }
+  }
+  
+  public int getCount() {
+    String val = getInternal().getAttributeValue("count");
+    return (val != null) ? Integer.parseInt(val) : -1;
+  }
+  
+  public void setCount(int count) {
+    if (count > -1) {
+      getInternal().setAttributeValue("count", String.valueOf(count));
+    } else {
+      getInternal().removeAttribute(new QName("count"));
+    }
+  }
+  
+  public int getStartIndex() {
+    String val = getInternal().getAttributeValue("startIndex");
+    return (val != null) ? Integer.parseInt(val) : -1;
+  }
+  
+  public void setStartIndex(int startIndex) {
+    if (startIndex > -1) {
+      getInternal().setAttributeValue("startIndex", String.valueOf(startIndex));
+    } else {
+      getInternal().removeAttribute(new QName("startIndex"));
+    }
+  }
+  
+  public int getStartPage() {
+    String val = getInternal().getAttributeValue("startPage");
+    return (val != null) ? Integer.parseInt(val) : -1;
+  }
+  
+  public void setStartPage(int startPage) {
+    if (startPage > -1) {
+      getInternal().setAttributeValue("startPage", String.valueOf(startPage));
+    } else {
+      getInternal().removeAttribute(new QName("startPage"));
+    }
+  }
+  
+  public String getLanguage() {
+    return getInternal().getAttributeValue("language");
+  }
+  
+  public void setLanguage(String language) {
+    if (language != null) {
+      getInternal().setAttributeValue("language", language);
+    } else {
+      getInternal().removeAttribute(new QName("language"));
+    }
+  }
+  
+  public String getInputEncoding() {
+    return getInternal().getAttributeValue("inputEncoding");
+  }
+  
+  public void setInputEncoding(String encoding) {
+    if (encoding != null) {
+      getInternal().setAttributeValue("inputEncoding", encoding);
+    } else {
+      getInternal().removeAttribute(new QName("inputEncoding"));
+    }
+  }
+
+  public String getOutputEncoding() {
+    return getInternal().getAttributeValue("outputEncoding");
+  }
+  
+  public void setOutputEncoding(String encoding) {
+    if (encoding != null) {
+      getInternal().setAttributeValue("outputEncoding", encoding);
+    } else {
+      getInternal().removeAttribute(new QName("outputEncoding"));
+    }
+  }
+  
+  public int hashCode() {
+    final int PRIME = 31;
+    int result = super.hashCode();
+    result = PRIME * result + ((getInternal() == null) ? 0 : getInternal().hashCode());
+    return result;
+  }
+
+}

Added: incubator/abdera/java/trunk/extensions/opensearch/src/main/resources/META-INF/services/org.apache.abdera.factory.ExtensionFactory
URL: http://svn.apache.org/viewvc/incubator/abdera/java/trunk/extensions/opensearch/src/main/resources/META-INF/services/org.apache.abdera.factory.ExtensionFactory?rev=567888&view=auto
==============================================================================
--- incubator/abdera/java/trunk/extensions/opensearch/src/main/resources/META-INF/services/org.apache.abdera.factory.ExtensionFactory (added)
+++ incubator/abdera/java/trunk/extensions/opensearch/src/main/resources/META-INF/services/org.apache.abdera.factory.ExtensionFactory Mon Aug 20 17:51:20 2007
@@ -0,0 +1 @@
+org.apache.abdera.ext.opensearch.OpenSearchExtensionFactory

Added: incubator/abdera/java/trunk/extensions/opensearch/src/test/java/org/apache/abdera/test/ext/opensearch/OpenSearchTest.java
URL: http://svn.apache.org/viewvc/incubator/abdera/java/trunk/extensions/opensearch/src/test/java/org/apache/abdera/test/ext/opensearch/OpenSearchTest.java?rev=567888&view=auto
==============================================================================
--- incubator/abdera/java/trunk/extensions/opensearch/src/test/java/org/apache/abdera/test/ext/opensearch/OpenSearchTest.java (added)
+++ incubator/abdera/java/trunk/extensions/opensearch/src/test/java/org/apache/abdera/test/ext/opensearch/OpenSearchTest.java Mon Aug 20 17:51:20 2007
@@ -0,0 +1,53 @@
+/*
+* 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.test.ext.opensearch;
+
+import junit.framework.TestCase;
+
+import org.apache.abdera.Abdera;
+import org.apache.abdera.model.Element;
+import org.apache.abdera.model.Document;
+
+import org.apache.abdera.parser.Parser;
+
+import org.apache.abdera.ext.opensearch.IntegerElement;
+import org.apache.abdera.ext.opensearch.OpenSearchConstants;
+
+import java.io.InputStream;
+
+public class OpenSearchTest extends TestCase {
+  public void testBasics() throws Exception
+  {
+    Parser parser = Abdera.getNewParser();
+    
+    InputStream stream = OpenSearchTest.class.getResourceAsStream("/opensearch.xml");
+    Document<Element> doc = parser.parse(stream);
+
+    IntegerElement tr = doc.getRoot().getFirstChild(OpenSearchConstants.TOTAL_RESULTS_V10);
+    assertNotNull(tr);
+    assertEquals(tr.getValue(), 47);
+
+    IntegerElement ipp = doc.getRoot().getFirstChild(OpenSearchConstants.ITEMS_PER_PAGE_V10);
+    assertNotNull(ipp);
+    assertEquals(ipp.getValue(), 1);
+
+    IntegerElement si = doc.getRoot().getFirstChild(OpenSearchConstants.START_INDEX_V10);
+    assertNotNull(si);
+    assertEquals(si.getValue(), 1);
+  }
+}

Added: incubator/abdera/java/trunk/extensions/opensearch/src/test/java/org/apache/abdera/test/ext/opensearch/TestSuite.java
URL: http://svn.apache.org/viewvc/incubator/abdera/java/trunk/extensions/opensearch/src/test/java/org/apache/abdera/test/ext/opensearch/TestSuite.java?rev=567888&view=auto
==============================================================================
--- incubator/abdera/java/trunk/extensions/opensearch/src/test/java/org/apache/abdera/test/ext/opensearch/TestSuite.java (added)
+++ incubator/abdera/java/trunk/extensions/opensearch/src/test/java/org/apache/abdera/test/ext/opensearch/TestSuite.java Mon Aug 20 17:51:20 2007
@@ -0,0 +1,30 @@
+/*
+* 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.test.ext.opensearch;
+
+public class TestSuite extends junit.framework.TestSuite {
+  public static void main(String[] args)
+  {
+    junit.textui.TestRunner.run(new TestSuite());
+  }
+
+  public TestSuite()
+  {
+    addTestSuite(OpenSearchTest.class);
+  }
+}

Added: incubator/abdera/java/trunk/extensions/opensearch/src/test/resources/opensearch.xml
URL: http://svn.apache.org/viewvc/incubator/abdera/java/trunk/extensions/opensearch/src/test/resources/opensearch.xml?rev=567888&view=auto
==============================================================================
--- incubator/abdera/java/trunk/extensions/opensearch/src/test/resources/opensearch.xml (added)
+++ incubator/abdera/java/trunk/extensions/opensearch/src/test/resources/opensearch.xml Mon Aug 20 17:51:20 2007
@@ -0,0 +1,21 @@
+<feed xmlns="http://www.w3.org/2005/Atom"
+      xmlns:opensearch="http://a9.com/-/spec/opensearchrss/1.0/">
+  <title>An OpenSearch Example</title>
+  <link href="http://example.com/opensearch+example"/>
+  <updated>1978-12-13T18:30:02Z</updated>
+  <author>
+    <name>Garrett Rooney</name>
+  </author>
+  <id>http;//example.com/opensearch+example</id>
+  <opensearch:totalResults>47</opensearch:totalResults>
+  <opensearch:startIndex>1</opensearch:startIndex>
+  <opensearch:itemsPerPage>1</opensearch:itemsPerPage>
+  <entry>
+    <title>The entry's title</title>
+    <id>http://example.com/opensearch+example/entry</id>
+    <updated>2003-11-13T18:30:02Z</updated>
+    <content type="text">
+      Some content goes here...
+    </content>
+  </entry>
+</feed>

Added: incubator/abdera/java/trunk/extensions/sharing/pom.xml
URL: http://svn.apache.org/viewvc/incubator/abdera/java/trunk/extensions/sharing/pom.xml?rev=567888&view=auto
==============================================================================
--- incubator/abdera/java/trunk/extensions/sharing/pom.xml (added)
+++ incubator/abdera/java/trunk/extensions/sharing/pom.xml Mon Aug 20 17:51:20 2007
@@ -0,0 +1,92 @@
+<?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.3.0-incubating-SNAPSHOT</version>
+  </parent>  
+  <modelVersion>4.0.0</modelVersion>
+  <artifactId>abdera-extensions-sharing</artifactId>
+  <packaging>jar</packaging>
+  <name>Abdera Extensions - Sharing</name>
+  <version>0.3.0-incubating-SNAPSHOT</version>
+  <description>Atom Specification Extensions - Sharing</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/extensions/sharing</connection>
+    <developerConnection>scm:svn:https://svn.apache.org/repos/asf/incubator/abdera/java/trunk/extensions/sharing</developerConnection>
+    <url>http://svn.apache.org/repos/asf/incubator/abdera/java/trunk/extensions/sharing</url>
+  </scm>
+  <dependencies>
+    <dependency>
+      <groupId>org.apache.abdera</groupId>
+      <artifactId>abdera-core</artifactId>
+      <version>0.3.0-incubating-SNAPSHOT</version>
+      <scope>compile</scope>
+    </dependency>    
+    <dependency>
+      <groupId>org.apache.abdera</groupId>
+      <artifactId>abdera-parser</artifactId>
+      <version>0.3.0-incubating-SNAPSHOT</version>
+      <scope>compile</scope>
+    </dependency>   
+    <dependency>
+      <groupId>org.apache.abdera</groupId>
+      <artifactId>abdera-protocol</artifactId>
+      <version>0.3.0-incubating-SNAPSHOT</version>
+      <scope>compile</scope>
+    </dependency>  
+    <dependency>
+      <groupId>org.apache.abdera</groupId>
+      <artifactId>abdera-client</artifactId>
+      <version>0.3.0-incubating-SNAPSHOT</version>
+      <scope>compile</scope>
+    </dependency>  
+    <dependency>
+      <groupId>org.apache.abdera</groupId>
+      <artifactId>json</artifactId>
+      <version>1.0</version>
+      <scope>compile</scope>
+    </dependency>   
+    <dependency>
+      <groupId>org.apache.ws.commons.axiom</groupId>
+      <artifactId>axiom-api</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.ws.commons.axiom</groupId>
+      <artifactId>axiom-impl</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>stax</groupId>
+      <artifactId>stax-api</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.codehaus.woodstox</groupId>
+      <artifactId>wstx-asl</artifactId>
+    </dependency> 
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+    </dependency>
+  </dependencies>
+</project>

Added: incubator/abdera/java/trunk/extensions/sharing/src/main/java/org/apache/abdera/ext/sharing/Conflicts.java
URL: http://svn.apache.org/viewvc/incubator/abdera/java/trunk/extensions/sharing/src/main/java/org/apache/abdera/ext/sharing/Conflicts.java?rev=567888&view=auto
==============================================================================
--- incubator/abdera/java/trunk/extensions/sharing/src/main/java/org/apache/abdera/ext/sharing/Conflicts.java (added)
+++ incubator/abdera/java/trunk/extensions/sharing/src/main/java/org/apache/abdera/ext/sharing/Conflicts.java Mon Aug 20 17:51:20 2007
@@ -0,0 +1,52 @@
+/*
+* 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.ext.sharing;
+
+import java.util.List;
+
+import javax.xml.namespace.QName;
+
+import org.apache.abdera.factory.Factory;
+import org.apache.abdera.model.Element;
+import org.apache.abdera.model.Entry;
+import org.apache.abdera.model.ExtensibleElementWrapper;
+import org.apache.abdera.util.Constants;
+
+public class Conflicts 
+  extends ExtensibleElementWrapper {
+
+  public Conflicts(
+    Element internal) {
+      super(internal);
+  }
+
+  public Conflicts(
+    Factory factory,
+    QName qname) {
+      super(factory, qname);
+  }
+   
+  public List<Entry> getEntries() {
+    return getExtensions(Constants.ENTRY);
+  }
+  
+  public void addEntry(Entry entry) {
+    addExtension((Entry)entry.clone());
+  }
+  
+}

Added: incubator/abdera/java/trunk/extensions/sharing/src/main/java/org/apache/abdera/ext/sharing/History.java
URL: http://svn.apache.org/viewvc/incubator/abdera/java/trunk/extensions/sharing/src/main/java/org/apache/abdera/ext/sharing/History.java?rev=567888&view=auto
==============================================================================
--- incubator/abdera/java/trunk/extensions/sharing/src/main/java/org/apache/abdera/ext/sharing/History.java (added)
+++ incubator/abdera/java/trunk/extensions/sharing/src/main/java/org/apache/abdera/ext/sharing/History.java Mon Aug 20 17:51:20 2007
@@ -0,0 +1,78 @@
+/*
+* 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.ext.sharing;
+
+import java.util.Date;
+
+import javax.xml.namespace.QName;
+
+import org.apache.abdera.factory.Factory;
+import org.apache.abdera.model.AtomDate;
+import org.apache.abdera.model.Element;
+import org.apache.abdera.model.ElementWrapper;
+
+public class History
+  extends ElementWrapper {
+
+  public History(Element internal) {
+    super(internal);
+  }
+
+  public History(Factory factory, QName qname) {
+    super(factory, qname);
+  }
+
+  public int getSequence() {
+    String sequence = getAttributeValue("sequence");
+    return sequence != null ? Integer.parseInt(sequence) : 0;
+  }
+  
+  public void setSequence(int sequence) {
+    if (sequence > 0) {
+      setAttributeValue("sequence",Integer.toString(sequence));
+    } else {
+      removeAttribute(new QName("sequence"));
+    }
+  }
+  
+  public Date getWhen() {
+    String when = getAttributeValue("when");
+    return when != null ? AtomDate.parse(when) : null;
+  }
+  
+  public void setWhen(Date when) {
+    if (when != null) {
+      setAttributeValue("when", AtomDate.format(when));
+    } else {
+      removeAttribute(new QName("when"));
+    }
+  }
+  
+  public String getBy() {
+    return getAttributeValue("by");
+  }
+  
+  public void setBy(String by) {
+    if (by != null) {
+      setAttributeValue("by", by);
+    } else {
+      removeAttribute(new QName("by"));
+    }
+  }
+  
+}

Added: incubator/abdera/java/trunk/extensions/sharing/src/main/java/org/apache/abdera/ext/sharing/Related.java
URL: http://svn.apache.org/viewvc/incubator/abdera/java/trunk/extensions/sharing/src/main/java/org/apache/abdera/ext/sharing/Related.java?rev=567888&view=auto
==============================================================================
--- incubator/abdera/java/trunk/extensions/sharing/src/main/java/org/apache/abdera/ext/sharing/Related.java (added)
+++ incubator/abdera/java/trunk/extensions/sharing/src/main/java/org/apache/abdera/ext/sharing/Related.java Mon Aug 20 17:51:20 2007
@@ -0,0 +1,78 @@
+/*
+* 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.ext.sharing;
+
+import javax.xml.namespace.QName;
+
+import org.apache.abdera.factory.Factory;
+import org.apache.abdera.i18n.iri.IRI;
+import org.apache.abdera.model.Element;
+import org.apache.abdera.model.ElementWrapper;
+
+public class Related
+  extends ElementWrapper {
+
+  public static enum Type { COMPLETE, AGGREGATED };
+  
+  public Related(Element internal) {
+    super(internal);
+  }
+
+  public Related(Factory factory, QName qname) {
+    super(factory, qname);
+  }
+
+  public IRI getLink() {
+    String link = getAttributeValue("link");
+    return link != null ? new IRI(link) : null;
+  }
+  
+  public void setLink(String link) {
+    if (link != null) {
+      setAttributeValue("link",new IRI(link).toString());
+    } else {
+      removeAttribute(new QName("link"));
+    }
+  }
+  
+  public String getTitle() {
+    return getAttributeValue("title");
+  }
+  
+  public void setTitle(String title) {
+    if (title != null) {
+      setAttributeValue("title",title);
+    } else {
+      removeAttribute(new QName("title"));
+    }
+  }
+  
+  public Type getType() {
+    String type = getAttributeValue("type");
+    return type != null ? Type.valueOf(type.toUpperCase()) : null;
+  }
+  
+  public void setType(Type type) {
+    if (type != null) {
+      setAttributeValue("type",type.name().toLowerCase());
+    } else {
+      removeAttribute(new QName("type"));
+    }
+  }
+  
+}

Added: incubator/abdera/java/trunk/extensions/sharing/src/main/java/org/apache/abdera/ext/sharing/Sharing.java
URL: http://svn.apache.org/viewvc/incubator/abdera/java/trunk/extensions/sharing/src/main/java/org/apache/abdera/ext/sharing/Sharing.java?rev=567888&view=auto
==============================================================================
--- incubator/abdera/java/trunk/extensions/sharing/src/main/java/org/apache/abdera/ext/sharing/Sharing.java (added)
+++ incubator/abdera/java/trunk/extensions/sharing/src/main/java/org/apache/abdera/ext/sharing/Sharing.java Mon Aug 20 17:51:20 2007
@@ -0,0 +1,99 @@
+/*
+* 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.ext.sharing;
+
+import java.util.Date;
+import java.util.List;
+
+import javax.xml.namespace.QName;
+
+import org.apache.abdera.factory.Factory;
+import org.apache.abdera.model.AtomDate;
+import org.apache.abdera.model.Element;
+import org.apache.abdera.model.ExtensibleElementWrapper;
+
+public class Sharing
+  extends ExtensibleElementWrapper {
+
+  public Sharing(Element internal) {
+    super(internal);
+  }
+
+  public Sharing(Factory factory, QName qname) {
+    super(factory, qname);
+  }
+
+  public Date getSince() {
+    String since = getAttributeValue("since");
+    return since != null ? AtomDate.parse(since) : null;
+  }
+  
+  public void setSince(Date since) {
+    if (since != null) {
+      setAttributeValue("since", AtomDate.format(since));
+    } else {
+      removeAttribute(new QName("since"));
+    }
+  }
+  
+  public Date getUntil() {
+    String until = getAttributeValue("until");
+    return until != null ? AtomDate.parse(until) : null;
+  }
+  
+  public void setUntil(Date until) {
+    if (until != null) {
+      setAttributeValue("until", AtomDate.format(until));
+    } else {
+      removeAttribute(new QName("until"));
+    }
+  }
+  
+  public Date getExpires() {
+    String expires = getAttributeValue("expires");
+    return expires != null ? AtomDate.parse(expires) : null;
+  }
+  
+  public void setExpires(Date expires) {
+    if (expires != null) {
+      setAttributeValue("expires", AtomDate.format(expires));
+    } else {
+      removeAttribute(new QName("expires"));
+    }
+  }
+ 
+  public List<Related> getRelated() {
+    return getExtensions(SharingHelper.SSE_RELATED);
+  }
+  
+  public void addRelated(Related related) {
+    addExtension(related);
+  }
+  
+  public Related addRelated() {
+    return getFactory().newElement(SharingHelper.SSE_RELATED, this);
+  }
+  
+  public Related addRelated(String link, String title, Related.Type type) {
+    Related related = addRelated();
+    related.setLink(link);
+    related.setTitle(title);
+    related.setType(type);
+    return related;
+  }
+}

Added: incubator/abdera/java/trunk/extensions/sharing/src/main/java/org/apache/abdera/ext/sharing/SharingExtensionFactory.java
URL: http://svn.apache.org/viewvc/incubator/abdera/java/trunk/extensions/sharing/src/main/java/org/apache/abdera/ext/sharing/SharingExtensionFactory.java?rev=567888&view=auto
==============================================================================
--- incubator/abdera/java/trunk/extensions/sharing/src/main/java/org/apache/abdera/ext/sharing/SharingExtensionFactory.java (added)
+++ incubator/abdera/java/trunk/extensions/sharing/src/main/java/org/apache/abdera/ext/sharing/SharingExtensionFactory.java Mon Aug 20 17:51:20 2007
@@ -0,0 +1,35 @@
+/*
+* 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.ext.sharing;
+
+import org.apache.abdera.util.AbstractExtensionFactory;
+
+public class SharingExtensionFactory
+    extends AbstractExtensionFactory {
+
+  public SharingExtensionFactory() {
+    super(SharingHelper.SSENS);
+    addImpl(SharingHelper.SSE_CONFLICTS,Conflicts.class);
+    addImpl(SharingHelper.SSE_HISTORY,History.class);
+    addImpl(SharingHelper.SSE_RELATED,Related.class);
+    addImpl(SharingHelper.SSE_SHARING,Sharing.class);
+    addImpl(SharingHelper.SSE_SYNC,Sync.class);
+    addImpl(SharingHelper.SSE_UNPUBLISHED,Unpublished.class);
+  }
+  
+}

Added: incubator/abdera/java/trunk/extensions/sharing/src/main/java/org/apache/abdera/ext/sharing/SharingHelper.java
URL: http://svn.apache.org/viewvc/incubator/abdera/java/trunk/extensions/sharing/src/main/java/org/apache/abdera/ext/sharing/SharingHelper.java?rev=567888&view=auto
==============================================================================
--- incubator/abdera/java/trunk/extensions/sharing/src/main/java/org/apache/abdera/ext/sharing/SharingHelper.java (added)
+++ incubator/abdera/java/trunk/extensions/sharing/src/main/java/org/apache/abdera/ext/sharing/SharingHelper.java Mon Aug 20 17:51:20 2007
@@ -0,0 +1,384 @@
+/*
+* 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.ext.sharing;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.xml.namespace.QName;
+
+import org.apache.abdera.Abdera;
+import org.apache.abdera.model.Base;
+import org.apache.abdera.model.Entry;
+import org.apache.abdera.model.Feed;
+import org.apache.abdera.model.Source;
+
+public class SharingHelper {
+
+  public static final String SSENS = "http://www.microsoft.com/schemas/sse";
+  public static final String SSEPFX = "sx";
+  
+  public static final QName SSE_SHARING = new QName(SSENS, "sharing", SSEPFX);
+  public static final QName SSE_RELATED = new QName(SSENS, "related", SSEPFX);
+  public static final QName SSE_CONFLICTS = new QName(SSENS, "conflicts", SSEPFX);
+  public static final QName SSE_HISTORY = new QName(SSENS, "history", SSEPFX);
+  public static final QName SSE_SYNC = new QName(SSENS, "sync", SSEPFX);
+  public static final QName SSE_UNPUBLISHED = new QName(SSENS, "unpublished", SSEPFX);
+  
+  
+  protected static boolean isTrue(String value) {
+    return value.equalsIgnoreCase("true") || 
+           value.equals("1") || 
+           value.equals("-1") || 
+           value.equals("yes");
+  }
+  
+  public static <T extends Source>Sharing getSharing(T source) {
+    return getSharing(source,false);
+  }
+  
+  public static <T extends Source>Sharing getSharing(T source, boolean create) {
+    Sharing sharing = source.getExtension(SSE_SHARING);
+    if (sharing == null && create) sharing = source.addExtension(SSE_SHARING);
+    return sharing;
+  }
+  
+  public static <T extends Source>boolean hasSharing(T source) {
+    return getSharing(source) != null;
+  }
+  
+  public static Unpublished getUnpublished(Feed feed) {
+    return getUnpublished(feed,false);
+  }
+  
+  public static Unpublished getUnpublished(Feed feed, boolean create) {
+    Unpublished unpub = feed.getExtension(SSE_UNPUBLISHED);
+    if (unpub == null && create) unpub = feed.addExtension(SSE_UNPUBLISHED);
+    return unpub;
+  }
+  
+  public static Sync getSync(Entry entry) {
+    return getSync(entry,false);
+  }
+  
+  public static Sync getSync(Entry entry, boolean create) {
+    Sync sync = entry.getExtension(SSE_SYNC);
+    if (sync == null && create) sync = entry.addExtension(SSE_SYNC);
+    return sync;
+  }
+
+  public static boolean hasSync(Entry entry) {
+    return getSync(entry,false) != null;
+  }
+  
+  public static Entry createEntry(Abdera abdera, String by) {
+    return createEntry(abdera, by, null);
+  }
+  
+  public static Entry createEntry(Abdera abdera, String by, Feed feed) {
+    Entry entry = feed != null ? feed.addEntry() : abdera.newEntry();
+    entry.newId();
+    Sync sync = getSync(entry,true);
+    sync.setId(entry.getId().toString());
+    sync.setUpdates(1);
+    History history = sync.addHistory();
+    history.setSequence(sync.getUpdates());
+    history.setWhen(new Date());
+    history.setBy(by);
+    return entry;
+  }
+  
+  public static void deleteEntry(Entry entry, String by) {
+    Sync sync = getSync(entry,true);
+    sync.incrementUpdates();
+    sync.setDeleted(true);
+    History history = sync.addHistory();
+    history.setSequence(sync.getUpdates());
+    history.setWhen(new Date());
+    history.setBy(by);
+  }
+  
+  public static void updateEntry(Entry entry, String by) {
+    Sync sync = getSync(entry,true);
+    sync.incrementUpdates();
+    History history = sync.addHistory();
+    history.setSequence(sync.getUpdates());
+    history.setWhen(new Date());
+    history.setBy(by);
+  }
+  
+  public static Map<String,Entry> getSyncIdMap(Feed feed) {
+    Map<String,Entry> entries = new HashMap<String,Entry>();
+    for (Entry entry : feed.getEntries()) {
+      Sync sync = getSync(entry,false);
+      if (sync != null) {
+        String id = sync.getId();
+        if (id != null) {
+          entries.put(id,entry);
+        }
+      }
+    }
+    return entries;
+  }
+  
+  public static boolean isSubsumed(Sync s1, Sync s2) {
+    if (s1 == null && s2 == null) return false;
+    if (s1 == null && s2 != null) return true;
+    if (s1 != null && s2 == null) return false;
+    if (s1.equals(s2)) return false;
+    if (!s1.getId().equals(s2.getId())) return false;
+    History h1 = s1.getFirstChild(SSE_HISTORY);
+    for (History h2 : s2.getHistory()) {
+      if (isSubsumed(h1,h2)) return true;
+    }
+    return false;
+  }
+  
+  public static boolean isSubsumed(History h1, History h2) {
+    if (h1 == null && h2 == null) return false;
+    if (h1 == null && h2 != null) return true;
+    if (h1 != null && h2 == null) return false;
+    if (h1.equals(h2)) return false;
+    String h1by = h1.getBy();
+    String h2by = h2.getBy();
+    if (h1by != null) {
+      if (h2by != null && 
+          h1by.equals(h2by) && 
+          h2.getSequence() >= h1.getSequence()) 
+            return true;
+    } else {
+      if (h2by == null && 
+          h1.getWhen().equals(h2.getWhen()) && 
+          h1.getSequence() == h2.getSequence()) 
+            return true;
+    }
+    return false;
+  }
+  
+  public static Sync pickWinner(Sync s1, Sync s2) {
+    if (s1 == null && s2 == null) return null;
+    if (s1 == null && s2 != null) return s2;
+    if (s1 != null && s2 == null) return s1;
+    if (s1.equals(s2)) return s1;
+    if (!s1.getId().equals(s2.getId())) return null;
+    if (s1.getUpdates() > s2.getUpdates()) return s1;
+    if (s1.getUpdates() == s2.getUpdates()) {
+      History h1 = s1.getTopmostHistory();
+      History h2 = s2.getTopmostHistory();
+      Date d1 = h1.getWhen();
+      Date d2 = h2.getWhen();
+      if (d1 != null && d2 == null) return s1;
+      if (d1.after(d2)) return s1;
+      if (d1.equals(d2)) {
+        String b1 = h1.getBy();
+        String b2 = h2.getBy();
+        if (b1 != null && b2 == null) return s1;
+        if (b1.compareTo(b2) > 0) return s1;
+      }
+    }
+    return s2;
+  }
+  
+  private static List<Entry> getConflicts(Entry entry) {
+    List<Entry> list = new ArrayList<Entry>();
+    Sync sync = getSync(entry,false);
+    if (sync != null) {
+      Conflicts conflicts = sync.getConflicts(false);
+      if (conflicts != null) {
+        list.addAll(conflicts.getEntries());
+      }
+    }
+    list.add(entry);
+    return list;
+  }
+  
+  private static Entry compareConflicts(
+    Entry w,
+    List<Entry> outerList, 
+    List<Entry> innerList, 
+    List<Entry> results) {
+      Entry[] outer = outerList.toArray(new Entry[outerList.size()]);
+      Entry[] inner = innerList.toArray(new Entry[innerList.size()]);
+      for (Entry x : outer) {
+        Sync s1 = getSync(x,false);
+        boolean ok = true;
+        for (Entry y : inner) {
+          Sync s2 = getSync(y,false);
+          if (isSubsumed(s1,s2)) {
+            outerList.remove(s1);
+            ok = false;
+            break;
+          }
+        }
+        if (ok) {
+          results.add(x);
+          if (w == null) w = x;
+          else {
+            Sync s2 = getSync(w);
+            if (pickWinner(s1,s2) == s1) w = x;
+          }
+        }
+      }
+      return w;
+  }
+  
+  public static void mergeFeeds(Feed source, Feed dest) {
+    Map<String,Entry> destentries = getSyncIdMap(dest);
+    for (Entry entry : source.getEntries()) {
+      Sync s2 = getSync(entry,false);
+      if (s2 != null) {
+        String id = s2.getId();
+        if (id != null) {
+          Entry existing = destentries.get(id);
+          if (existing == null) {
+            dest.addEntry((Entry)entry.clone());
+          } else {
+            Sync s1 = getSync(existing,false);
+            List<Entry> c1 = getConflicts(existing);
+            List<Entry> c2 = getConflicts(entry);
+            List<Entry> m = new ArrayList<Entry>();
+            Entry w = null;
+            w = compareConflicts(w, c1,c2,m);
+            w = compareConflicts(w, c2,c1,m);
+            if (w != null) dest.addEntry(w);
+            if (s1.isNoConflicts()) return;
+            if (m.size() > 0) {
+              Sync sync = getSync(w,true);
+              sync.setConflicts(null);
+              Conflicts conflicts = sync.getConflicts(true);
+              for (Entry e : m) {
+                if (e != w) conflicts.addEntry(e);
+              }
+            }
+          }
+        }
+      } // otherwise skip the entry
+    }
+  }
+  
+  private static void mergeConflictItems(Entry entry, List<Entry> conflicts) {
+    Sync sync = getSync(entry,true);
+    for (Entry x : conflicts) {
+      Sync xsync = getSync(x,false);
+      if (xsync != null) {
+        for (History h1 : xsync.getHistory()) {
+          boolean ok = true;
+          for (History h2 : sync.getHistory()) {
+            if (isSubsumed(h1,h2)) {
+              ok = false;
+              break;
+            }
+          }
+          if (ok) sync.addHistory(h1);
+        }
+      }
+    }
+  }
+  
+  public static Entry resolveConflicts(Entry entry, ConflictResolver resolver, String by) {
+    List<Entry> conflicts = getConflicts(entry);
+    entry = resolver.resolve(entry, conflicts);
+    updateEntry(entry, by);
+    mergeConflictItems(entry,conflicts);
+    return entry;
+  }
+  
+  public static interface ConflictResolver {
+    Entry resolve(Entry entry, List<Entry> conflicts);
+  }
+  
+  public static Entry unpublish(Entry entry) {
+    if (entry == null) return null;
+    Base base = entry.getParentElement();
+    if (base == null || !(base instanceof Feed)) return null;
+    Feed feed = (Feed) base;
+    Unpublished unpub = getUnpublished(feed, true);
+    Entry newentry = (Entry)entry.clone();
+    newentry.setParentElement(unpub);
+    unpub.addEntry(newentry);
+    entry.discard();
+    return newentry;
+  }
+  
+  public static Entry republish(Entry entry) {
+    if (entry == null) return null;
+    Base base = entry.getParentElement();
+    if (base == null || !(base instanceof Unpublished)) return null;
+    Unpublished unpub = (Unpublished)base;
+    Feed feed = unpub.getParentElement();
+    Entry newentry = (Entry)entry.clone();
+    newentry.setParentElement(feed);
+    feed.addEntry(newentry);
+    entry.discard();
+    return newentry;
+  }
+  
+  public static void publish(Feed feed, Date expires, boolean initial) {
+    if (initial) {
+      Sharing sharing = getSharing(feed,true);
+      Date since = getMin(feed);
+      Date until = getMax(feed);
+      sharing.setSince(since);
+      sharing.setUntil(until);
+      sharing.setExpires(expires);
+    } else {
+      Sharing sharing = getSharing(feed,false);
+      if (sharing != null) {
+        sharing.setExpires(expires);
+      } else {
+        publish(feed, expires, true);
+      }
+    }
+  }
+  
+  private static Date getMax(Feed feed) {
+    Date d = null;
+    for (Entry entry : feed.getEntries()) {
+      Date updated = entry.getUpdated();
+      if (d == null) d = updated;
+      if (updated.after(d)) d = updated;
+    }
+    return d;
+  }
+  
+  private static Date getMin(Feed feed) {
+    Date d = null;
+    for (Entry entry : feed.getEntries()) {
+      Date updated = entry.getUpdated();
+      if (d == null) d = updated;
+      if (updated.before(d)) d = updated;
+    }
+    return d;
+  }
+  
+  public boolean hasConflicts(Entry entry) {
+    Sync sync = getSync(entry);
+    if (sync != null) {
+      Conflicts conflicts = sync.getConflicts();
+      if (conflicts != null) {
+        if (conflicts.getEntries().size() > 0) {
+          return true;
+        }
+      }
+    }
+    return false;
+  }
+}

Added: incubator/abdera/java/trunk/extensions/sharing/src/main/java/org/apache/abdera/ext/sharing/Sync.java
URL: http://svn.apache.org/viewvc/incubator/abdera/java/trunk/extensions/sharing/src/main/java/org/apache/abdera/ext/sharing/Sync.java?rev=567888&view=auto
==============================================================================
--- incubator/abdera/java/trunk/extensions/sharing/src/main/java/org/apache/abdera/ext/sharing/Sync.java (added)
+++ incubator/abdera/java/trunk/extensions/sharing/src/main/java/org/apache/abdera/ext/sharing/Sync.java Mon Aug 20 17:51:20 2007
@@ -0,0 +1,139 @@
+/*
+* 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.ext.sharing;
+
+import java.util.Date;
+import java.util.List;
+
+import javax.xml.namespace.QName;
+
+import org.apache.abdera.factory.Factory;
+import org.apache.abdera.model.Element;
+import org.apache.abdera.model.ExtensibleElementWrapper;
+
+public class Sync
+  extends ExtensibleElementWrapper {
+
+  public Sync(Element internal) {
+    super(internal);
+  }
+
+  public Sync(Factory factory, QName qname) {
+    super(factory, qname);
+  }
+
+  public String getId() {
+    return getAttributeValue("id");
+  }
+  
+  public void setId(String id) {
+    if (id != null) {
+      setAttributeValue("id",id);
+    } else {
+      removeAttribute(new QName("id"));
+    }
+  }
+  
+  public int getUpdates() {
+    String updates = getAttributeValue("updates");
+    return updates != null ? Integer.parseInt(updates) : 0;
+  }
+  
+  public void setUpdates(int updates) {
+    if (updates > 0) {
+      setAttributeValue("updates",Integer.toString(updates));
+    } else {
+      removeAttribute(new QName("updates"));
+    }
+  }
+  
+  public void incrementUpdates() {
+    setUpdates(getUpdates() + 1);
+  }
+  
+  public boolean isDeleted() {
+    String deleted = getAttributeValue("deleted");
+    return deleted != null ? SharingHelper.isTrue(deleted) : false;
+  }
+  
+  public void setDeleted(boolean deleted) {
+    if (deleted) {
+      setAttributeValue("deleted","true");
+    } else {
+      removeAttribute(new QName("deleted"));
+    }
+  }
+  
+  public boolean isNoConflicts() {
+    String noconflicts = getAttributeValue("noconflicts");
+    return noconflicts != null ? SharingHelper.isTrue(noconflicts) : false;
+  }
+  
+  public void setNoConflicts(boolean noconflicts) {
+    if (noconflicts) {
+      setAttributeValue("noconflicts","true");
+    } else {
+      removeAttribute(new QName("noconflicts"));
+    }
+  }
+  
+  public List<History> getHistory() {
+    return getExtensions(SharingHelper.SSE_HISTORY);
+  }
+  
+  public void addHistory(History history) {
+    this.addExtension(history);
+  }
+  
+  public History addHistory() {
+    return this.addExtension(
+      SharingHelper.SSE_HISTORY, 
+      SharingHelper.SSE_HISTORY);
+  }
+  
+  public History addHistory(int sequence, Date when, String by) {
+    History history = addHistory();
+    history.setSequence(sequence);
+    history.setWhen(when);
+    history.setBy(by);
+    return history;
+  }
+  
+  public History getTopmostHistory() {
+    return this.getFirstChild(SharingHelper.SSE_HISTORY);
+  }
+  
+  public Conflicts getConflicts() {
+    return getConflicts(false);
+  }
+  
+  public void setConflicts(Conflicts conflicts) {
+    Conflicts con = getConflicts();
+    if (con != null) con.discard();
+    if (conflicts != null) addExtension(conflicts);
+  }
+  
+  public Conflicts getConflicts(boolean create) {
+    Conflicts con = getExtension(SharingHelper.SSE_CONFLICTS);
+    if (con == null && create) 
+      con = getFactory().newElement(
+        SharingHelper.SSE_CONFLICTS, this.getInternal());
+    return con;
+  }
+  
+}

Added: incubator/abdera/java/trunk/extensions/sharing/src/main/java/org/apache/abdera/ext/sharing/Unpublished.java
URL: http://svn.apache.org/viewvc/incubator/abdera/java/trunk/extensions/sharing/src/main/java/org/apache/abdera/ext/sharing/Unpublished.java?rev=567888&view=auto
==============================================================================
--- incubator/abdera/java/trunk/extensions/sharing/src/main/java/org/apache/abdera/ext/sharing/Unpublished.java (added)
+++ incubator/abdera/java/trunk/extensions/sharing/src/main/java/org/apache/abdera/ext/sharing/Unpublished.java Mon Aug 20 17:51:20 2007
@@ -0,0 +1,48 @@
+/*
+* 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.ext.sharing;
+
+import java.util.List;
+
+import javax.xml.namespace.QName;
+
+import org.apache.abdera.factory.Factory;
+import org.apache.abdera.model.Element;
+import org.apache.abdera.model.Entry;
+import org.apache.abdera.model.ExtensibleElementWrapper;
+import org.apache.abdera.util.Constants;
+
+public class Unpublished
+  extends ExtensibleElementWrapper {
+
+  public Unpublished(Element internal) {
+    super(internal);
+  }
+
+  public Unpublished(Factory factory, QName qname) {
+    super(factory, qname);
+  }
+  
+  public List<Entry> getEntries() {
+    return getExtensions(Constants.ENTRY);
+  }
+  
+  public void addEntry(Entry entry) {
+    addExtension((Entry)entry.clone());
+  }
+}

Added: incubator/abdera/java/trunk/extensions/sharing/src/main/resources/META-INF/services/org.apache.abdera.factory.ExtensionFactory
URL: http://svn.apache.org/viewvc/incubator/abdera/java/trunk/extensions/sharing/src/main/resources/META-INF/services/org.apache.abdera.factory.ExtensionFactory?rev=567888&view=auto
==============================================================================
--- incubator/abdera/java/trunk/extensions/sharing/src/main/resources/META-INF/services/org.apache.abdera.factory.ExtensionFactory (added)
+++ incubator/abdera/java/trunk/extensions/sharing/src/main/resources/META-INF/services/org.apache.abdera.factory.ExtensionFactory Mon Aug 20 17:51:20 2007
@@ -0,0 +1 @@
+org.apache.abdera.ext.sharing.SharingExtensionFactory

Added: incubator/abdera/java/trunk/extensions/sharing/src/test/java/org/apache/abdera/test/ext/sharing/SharingTest.java
URL: http://svn.apache.org/viewvc/incubator/abdera/java/trunk/extensions/sharing/src/test/java/org/apache/abdera/test/ext/sharing/SharingTest.java?rev=567888&view=auto
==============================================================================
--- incubator/abdera/java/trunk/extensions/sharing/src/test/java/org/apache/abdera/test/ext/sharing/SharingTest.java (added)
+++ incubator/abdera/java/trunk/extensions/sharing/src/test/java/org/apache/abdera/test/ext/sharing/SharingTest.java Mon Aug 20 17:51:20 2007
@@ -0,0 +1,247 @@
+/*
+* 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.test.ext.sharing;
+
+import java.io.StringReader;
+import java.util.Date;
+import java.util.List;
+
+import org.apache.abdera.Abdera;
+import org.apache.abdera.ext.sharing.Conflicts;
+import org.apache.abdera.ext.sharing.History;
+import org.apache.abdera.ext.sharing.Related;
+import org.apache.abdera.ext.sharing.Sharing;
+import org.apache.abdera.ext.sharing.SharingHelper;
+import org.apache.abdera.ext.sharing.Sync;
+import org.apache.abdera.ext.sharing.Unpublished;
+import org.apache.abdera.ext.sharing.SharingHelper.ConflictResolver;
+import org.apache.abdera.factory.Factory;
+import org.apache.abdera.model.AtomDate;
+import org.apache.abdera.model.Document;
+import org.apache.abdera.model.Entry;
+import org.apache.abdera.model.Feed;
+
+import junit.framework.TestCase;
+
+public class SharingTest
+    extends TestCase {
+  
+  public static void testSharingFactory() throws Exception {
+    Abdera abdera = new Abdera();
+    Factory factory = abdera.getFactory();
+    Conflicts conflicts = factory.newElement(SharingHelper.SSE_CONFLICTS);
+    assertNotNull(conflicts);
+    History history = factory.newElement(SharingHelper.SSE_HISTORY);
+    assertNotNull(history);
+    Related related = factory.newElement(SharingHelper.SSE_RELATED);
+    assertNotNull(related);
+    Sharing sharing = factory.newElement(SharingHelper.SSE_SHARING);
+    assertNotNull(sharing);
+    Sync sync = factory.newElement(SharingHelper.SSE_SYNC);
+    assertNotNull(sync);
+    Unpublished unpub = factory.newElement(SharingHelper.SSE_UNPUBLISHED);
+    assertNotNull(unpub);
+  }
+
+  public static void testSimpleExample() throws Exception {
+    
+    String ex = "<?xml version=\"1.0\" encoding=\"utf-8\"?>" +
+                "<feed xmlns=\"http://www.w3.org/2005/Atom\" " +
+                "xmlns:sx=\"http://www.microsoft.com/schemas/sse\">" +
+                "<title>To Do List</title>" +
+                "<subtitle>A list of items to do</subtitle>" + 
+                "<link rel=\"self\" href=\"http://example.com/partial.xml\"/>" +
+                "<author>" + 
+                "<name>Ray Ozzie</name>" + 
+                "</author>" +
+                "<updated>2005-05-21T11:43:33Z</updated>" + 
+                "<id>urn:uuid:60a76c80-d399-11d9-b93C-0003939e0aaa</id>" + 
+                "<sx:sharing since=\"2005-02-13T18:30:02Z\" " + 
+                "until=\"2005-05-23T18:30:02Z\" >" +
+                "<sx:related link=\"http://example.com/all.xml\" type=\"complete\" />" +
+                "<sx:related link=\"http://example.com/B.xml\" type=\"aggregated\" " +
+                "title=\"To Do List (Jacks Copy)\" />" +
+                "</sx:sharing>" + 
+                "<entry>" + 
+                "<title>Buy groceries</title>" + 
+                "<content>Get milk, eggs, butter and bread</content>" + 
+                "<id>urn:uuid:60a76c80-d399-11d9-b93C-0003939e0aa0</id>" + 
+                "<author>" +
+                "<name>Ray Ozzie</name>" + 
+                "</author>" +
+                "<updated>2005-05-21T11:43:33Z</updated>" + 
+                "<sx:sync id=\"item 1_myapp_2005-05-21T11:43:33Z\" updates=\"3\">" +
+                "<sx:history sequence=\"3\" when=\"2005-05-21T11:43:33Z\" by=\"JEO2000\"/>" +
+                "<sx:history sequence=\"2\" when=\"2005-05-21T10:43:33Z\" by=\"REO1750\"/>" +
+                "<sx:history sequence=\"1\" when=\"2005-05-21T09:43:33Z\" by=\"REO1750\"/>" +
+                "</sx:sync>" + 
+                "</entry></feed>";
+    
+    StringReader rdr = new StringReader(ex);
+    Abdera abdera = new Abdera();
+    Document<Feed> doc = abdera.getParser().parse(rdr);
+    Feed feed = doc.getRoot();
+    assertTrue(SharingHelper.hasSharing(feed));
+    
+    Sharing sharing = SharingHelper.getSharing(feed, false);
+    assertNotNull(sharing);
+    
+    Date since = AtomDate.parse("2005-02-13T18:30:02Z");
+    Date until = AtomDate.parse("2005-05-23T18:30:02Z");
+    
+    assertEquals(sharing.getSince(),since);
+    assertEquals(sharing.getUntil(),until);
+    
+    assertEquals(sharing.getRelated().size(),2);
+    
+    Related rel = sharing.getRelated().get(0);
+    assertEquals(rel.getLink().toString(),"http://example.com/all.xml");
+    assertEquals(rel.getType(),Related.Type.COMPLETE);
+    
+    rel = sharing.getRelated().get(1);
+    assertEquals(rel.getLink().toString(),"http://example.com/B.xml");
+    assertEquals(rel.getType(),Related.Type.AGGREGATED);
+    
+    Entry entry = feed.getEntries().get(0);
+    Sync sync = SharingHelper.getSync(entry, false);
+    assertNotNull(sync);
+    assertEquals(sync.getId(),"item 1_myapp_2005-05-21T11:43:33Z");
+    assertEquals(sync.getUpdates(),3);
+    
+    assertEquals(sync.getHistory().size(),3);
+    
+    Date d1 = AtomDate.parse("2005-05-21T11:43:33Z");
+    Date d2 = AtomDate.parse("2005-05-21T10:43:33Z");
+    Date d3 = AtomDate.parse("2005-05-21T09:43:33Z");
+    
+    History history = sync.getHistory().get(0);
+    assertEquals(history.getSequence(),3);
+    assertEquals(history.getWhen(),d1);
+    assertEquals(history.getBy(),"JEO2000");
+    
+    history = sync.getHistory().get(1);
+    assertEquals(history.getSequence(),2);
+    assertEquals(history.getWhen(),d2);
+    assertEquals(history.getBy(),"REO1750");
+    
+    history = sync.getHistory().get(2);
+    assertEquals(history.getSequence(),1);
+    assertEquals(history.getWhen(),d3);
+    assertEquals(history.getBy(),"REO1750");
+  }
+  
+  public void testCreateOperation() throws Exception  {
+    Abdera abdera = new Abdera();
+    Entry entry = SharingHelper.createEntry(abdera, "jms");
+    Sync sync = SharingHelper.getSync(entry, false);
+    assertNotNull(sync);
+    assertNotNull(sync.getId());
+    assertEquals(sync.getUpdates(),1);
+    assertEquals(sync.getHistory().size(),1);
+    History history = sync.getTopmostHistory();
+    assertEquals(history.getSequence(),1);
+    assertEquals(history.getBy(),"jms");
+  }
+  
+  public void testUpdateOperation() throws Exception {
+    Abdera abdera = new Abdera();
+    Entry entry = SharingHelper.createEntry(abdera, "jms");
+    SharingHelper.updateEntry(entry, "jms");
+    Sync sync = SharingHelper.getSync(entry, false);
+    assertNotNull(sync);
+    assertNotNull(sync.getId());
+    assertEquals(sync.getUpdates(),2);
+    assertEquals(sync.getHistory().size(),2);
+    History history = sync.getTopmostHistory();
+    assertEquals(history.getSequence(),2);
+    assertEquals(history.getBy(),"jms");
+  }
+  
+  public void testDeleteOperation() throws Exception {
+    Abdera abdera = new Abdera();
+    Entry entry = SharingHelper.createEntry(abdera, "jms");
+    Sync sync = SharingHelper.getSync(entry, false);
+    assertNotNull(sync);
+    assertFalse(sync.isDeleted());
+    SharingHelper.deleteEntry(entry, "jms");
+    sync = SharingHelper.getSync(entry, false);
+    assertNotNull(sync);
+    assertTrue(sync.isDeleted());
+    assertNotNull(sync.getId());
+    assertEquals(sync.getUpdates(),2);
+    assertEquals(sync.getHistory().size(),2);
+    History history = sync.getTopmostHistory();
+    assertEquals(history.getSequence(),2);
+    assertEquals(history.getBy(),"jms");
+  }
+  
+  public void testConflict() throws Exception  {
+    
+    Abdera abdera = new Abdera();
+    Feed f1 = abdera.newFeed();
+    Feed f2 = abdera.newFeed();
+    Entry e1 = SharingHelper.createEntry(abdera, "jms", f1);
+    Entry e2 = SharingHelper.createEntry(abdera, "jms", f2);
+    Sync s1 = SharingHelper.getSync(e1, false);
+    Sync s2 = SharingHelper.getSync(e2, false);
+    s2.setId(s1.getId());
+    SharingHelper.updateEntry(e1, "bob");
+    SharingHelper.updateEntry(e2, "jms");
+    
+    SharingHelper.mergeFeeds(f1, f2);
+    
+    assertEquals(f2.getEntries().size(),1);
+    Entry entry = f2.getEntries().get(0);
+    Sync sync = SharingHelper.getSync(entry);
+    Conflicts conflicts = sync.getConflicts();
+    assertNotNull(conflicts);
+    assertEquals(conflicts.getEntries().size(),1);
+    Entry conflict = conflicts.getEntries().get(0);
+    assertNotNull(conflict);
+    
+    ConflictResolver r = new ConflictResolver() {
+      public Entry resolve(Entry entry, List<Entry> conflicts) {
+        Sync sync = SharingHelper.getSync(entry,false);
+        Conflicts c = sync.getConflicts(false);
+        if (c != null) c.discard();
+        return entry; // take the latest
+      }
+    };
+    entry = SharingHelper.resolveConflicts(entry, r, "jms");
+    sync = SharingHelper.getSync(entry);
+    conflicts = sync.getConflicts();
+    assertNull(conflicts);
+    assertEquals(sync.getHistory().size(),4);
+  }
+  
+  public void testUnpublish() throws Exception {
+    
+    Abdera abdera = new Abdera();
+    Feed feed = abdera.newFeed();
+    Entry entry = feed.addEntry();
+    assertEquals(feed.getEntries().size(),1);
+    entry = SharingHelper.unpublish(entry);
+    assertEquals(feed.getEntries().size(),0);
+    Unpublished unpub = SharingHelper.getUnpublished(feed);
+    assertEquals(unpub.getEntries().size(),1);
+    SharingHelper.republish(entry);
+    unpub = SharingHelper.getUnpublished(feed);
+    assertEquals(unpub.getEntries().size(),0);
+    assertEquals(feed.getEntries().size(),1);
+  }
+}

Added: incubator/abdera/java/trunk/extensions/sharing/src/test/java/org/apache/abdera/test/ext/sharing/TestSuite.java
URL: http://svn.apache.org/viewvc/incubator/abdera/java/trunk/extensions/sharing/src/test/java/org/apache/abdera/test/ext/sharing/TestSuite.java?rev=567888&view=auto
==============================================================================
--- incubator/abdera/java/trunk/extensions/sharing/src/test/java/org/apache/abdera/test/ext/sharing/TestSuite.java (added)
+++ incubator/abdera/java/trunk/extensions/sharing/src/test/java/org/apache/abdera/test/ext/sharing/TestSuite.java Mon Aug 20 17:51:20 2007
@@ -0,0 +1,30 @@
+/*
+* 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.test.ext.sharing;
+
+public class TestSuite extends junit.framework.TestSuite {
+  public static void main(String[] args)
+  {
+    junit.textui.TestRunner.run(new TestSuite());
+  }
+
+  public TestSuite()
+  {
+    addTestSuite(SharingTest.class);
+  }
+}

Added: incubator/abdera/java/trunk/extensions/wsse/src/main/java/org/apache/abdera/ext/wsse/WSSEAuthScheme.java
URL: http://svn.apache.org/viewvc/incubator/abdera/java/trunk/extensions/wsse/src/main/java/org/apache/abdera/ext/wsse/WSSEAuthScheme.java?rev=567888&view=auto
==============================================================================
--- incubator/abdera/java/trunk/extensions/wsse/src/main/java/org/apache/abdera/ext/wsse/WSSEAuthScheme.java (added)
+++ incubator/abdera/java/trunk/extensions/wsse/src/main/java/org/apache/abdera/ext/wsse/WSSEAuthScheme.java Mon Aug 20 17:51:20 2007
@@ -0,0 +1,124 @@
+/*
+* 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.ext.wsse;
+
+import java.security.MessageDigest;
+import java.security.SecureRandom;
+import java.util.Date;
+
+import org.apache.abdera.model.AtomDate;
+import org.apache.abdera.protocol.client.AbderaClient;
+import org.apache.commons.codec.binary.Base64;
+import org.apache.commons.codec.binary.Hex;
+import org.apache.commons.httpclient.Credentials;
+import org.apache.commons.httpclient.HttpMethod;
+import org.apache.commons.httpclient.UsernamePasswordCredentials;
+import org.apache.commons.httpclient.auth.AuthScheme;
+import org.apache.commons.httpclient.auth.AuthenticationException;
+import org.apache.commons.httpclient.auth.RFC2617Scheme;
+
+/**
+ * WSSE Auth Scheme implementation for use with HTTP Commons AbderaClient
+ * Some APP implementations use WSSE for authentication
+ * 
+ * @see http://www.xml.com/pub/a/2003/12/17/dive.html
+ */
+public class WSSEAuthScheme
+  extends RFC2617Scheme
+  implements AuthScheme {
+
+  private final int NONCE_LENGTH = 16;
+  
+  public static void register(AbderaClient abderaClient, boolean exclusive) {
+    AbderaClient.registerScheme("WSSE", WSSEAuthScheme.class);
+    if (exclusive)
+      ((AbderaClient)abderaClient).setAuthenticationSchemePriority("WSSE");
+    else
+      ((AbderaClient)abderaClient).setAuthenticationSchemeDefaults();
+  }
+  
+  public String authenticate(
+    Credentials credentials, 
+    HttpMethod method) 
+      throws AuthenticationException {
+    if (credentials instanceof UsernamePasswordCredentials) {
+      UsernamePasswordCredentials creds = (UsernamePasswordCredentials) credentials;
+      AtomDate now = new AtomDate(new Date());
+      String nonce = generateNonce();
+      String digest = generatePasswordDigest(creds.getPassword(), nonce, now);
+      String username = creds.getUserName();
+      
+      String wsse = "UsernameToken Username=\"" + username + "\", " +
+                    "PasswordDigest=\"" + digest + "\", " +
+                    "Nonce=\"" + nonce + "\", " +
+                    "Created=\"" + now.getValue() + "\"";
+      if (method != null) method.addRequestHeader("X-WSSE", wsse);
+      return "WSSE profile=\"UsernameToken\"";
+    } else {
+      return null;
+    }
+  }
+  
+  private String generatePasswordDigest(
+    String password, 
+    String nonce, 
+    AtomDate date) 
+      throws AuthenticationException {
+    String temp = nonce + date.getValue() + password;
+    try {
+      MessageDigest md = MessageDigest.getInstance("SHA1");
+      return new String(Base64.encodeBase64(md.digest(temp.getBytes())));
+    } catch (Exception e) {
+      throw new AuthenticationException(e.getMessage(), e);
+    }
+  }
+  
+  private String generateNonce()
+    throws AuthenticationException {
+      try {
+        SecureRandom sr = SecureRandom.getInstance("SHA1PRNG");
+        byte[] temp = new byte[NONCE_LENGTH];
+        sr.nextBytes(temp);
+        String n = new String(Hex.encodeHex(temp));
+        return n;
+      } catch (Exception e) {
+        throw new AuthenticationException(e.getMessage(),e);
+      }
+  }
+
+  public String authenticate(
+    Credentials credentials, 
+    String method, 
+    String uri) 
+      throws AuthenticationException {
+    return authenticate(credentials, null);
+  }
+
+  public String getSchemeName() {
+    return "WSSE";
+  }
+
+  public boolean isComplete() {
+    return true;
+  }
+
+  public boolean isConnectionBased() {
+    return false;
+  } 
+
+}

Modified: incubator/abdera/java/trunk/pom.xml
URL: http://svn.apache.org/viewvc/incubator/abdera/java/trunk/pom.xml?rev=567888&r1=567887&r2=567888&view=diff
==============================================================================
--- incubator/abdera/java/trunk/pom.xml (original)
+++ incubator/abdera/java/trunk/pom.xml Mon Aug 20 17:51:20 2007
@@ -276,7 +276,14 @@
     <module>security</module>
     <module>server</module>
     <module>client</module>
-    <module>extensions</module>
+    <module>extensions/gdata</module>
+    <module>extensions/geo</module>
+    <module>extensions/json</module>
+    <module>extensions/main</module>
+    <module>extensions/media</module>
+    <module>extensions/opensearch</module>
+    <module>extensions/sharing</module>
+    <module>extensions/wsse</module>
     <module>spring</module>
     <module>examples</module>
   </modules>