abdera-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From jmsn...@apache.org
Subject svn commit: r567319 - in /incubator/abdera/java/trunk/extensions/src: main/java/org/apache/abdera/ext/sharing/ main/resources/META-INF/services/ test/java/org/apache/abdera/test/sharing/
Date Sat, 18 Aug 2007 19:35:47 GMT
Author: jmsnell
Date: Sat Aug 18 12:35:45 2007
New Revision: 567319

URL: http://svn.apache.org/viewvc?view=rev&rev=567319
Log:
An initial implementation of Simple Sharing Extensions support.

Added:
    incubator/abdera/java/trunk/extensions/src/main/java/org/apache/abdera/ext/sharing/
    incubator/abdera/java/trunk/extensions/src/main/java/org/apache/abdera/ext/sharing/Conflicts.java
    incubator/abdera/java/trunk/extensions/src/main/java/org/apache/abdera/ext/sharing/History.java
    incubator/abdera/java/trunk/extensions/src/main/java/org/apache/abdera/ext/sharing/Related.java
    incubator/abdera/java/trunk/extensions/src/main/java/org/apache/abdera/ext/sharing/Sharing.java
    incubator/abdera/java/trunk/extensions/src/main/java/org/apache/abdera/ext/sharing/SharingExtensionFactory.java
    incubator/abdera/java/trunk/extensions/src/main/java/org/apache/abdera/ext/sharing/SharingHelper.java
    incubator/abdera/java/trunk/extensions/src/main/java/org/apache/abdera/ext/sharing/Sync.java
    incubator/abdera/java/trunk/extensions/src/main/java/org/apache/abdera/ext/sharing/Unpublished.java
    incubator/abdera/java/trunk/extensions/src/test/java/org/apache/abdera/test/sharing/
    incubator/abdera/java/trunk/extensions/src/test/java/org/apache/abdera/test/sharing/SharingTest.java
Modified:
    incubator/abdera/java/trunk/extensions/src/main/resources/META-INF/services/org.apache.abdera.factory.ExtensionFactory

Added: incubator/abdera/java/trunk/extensions/src/main/java/org/apache/abdera/ext/sharing/Conflicts.java
URL: http://svn.apache.org/viewvc/incubator/abdera/java/trunk/extensions/src/main/java/org/apache/abdera/ext/sharing/Conflicts.java?view=auto&rev=567319
==============================================================================
--- incubator/abdera/java/trunk/extensions/src/main/java/org/apache/abdera/ext/sharing/Conflicts.java
(added)
+++ incubator/abdera/java/trunk/extensions/src/main/java/org/apache/abdera/ext/sharing/Conflicts.java
Sat Aug 18 12:35:45 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/src/main/java/org/apache/abdera/ext/sharing/History.java
URL: http://svn.apache.org/viewvc/incubator/abdera/java/trunk/extensions/src/main/java/org/apache/abdera/ext/sharing/History.java?view=auto&rev=567319
==============================================================================
--- incubator/abdera/java/trunk/extensions/src/main/java/org/apache/abdera/ext/sharing/History.java
(added)
+++ incubator/abdera/java/trunk/extensions/src/main/java/org/apache/abdera/ext/sharing/History.java
Sat Aug 18 12:35:45 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/src/main/java/org/apache/abdera/ext/sharing/Related.java
URL: http://svn.apache.org/viewvc/incubator/abdera/java/trunk/extensions/src/main/java/org/apache/abdera/ext/sharing/Related.java?view=auto&rev=567319
==============================================================================
--- incubator/abdera/java/trunk/extensions/src/main/java/org/apache/abdera/ext/sharing/Related.java
(added)
+++ incubator/abdera/java/trunk/extensions/src/main/java/org/apache/abdera/ext/sharing/Related.java
Sat Aug 18 12:35:45 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/src/main/java/org/apache/abdera/ext/sharing/Sharing.java
URL: http://svn.apache.org/viewvc/incubator/abdera/java/trunk/extensions/src/main/java/org/apache/abdera/ext/sharing/Sharing.java?view=auto&rev=567319
==============================================================================
--- incubator/abdera/java/trunk/extensions/src/main/java/org/apache/abdera/ext/sharing/Sharing.java
(added)
+++ incubator/abdera/java/trunk/extensions/src/main/java/org/apache/abdera/ext/sharing/Sharing.java
Sat Aug 18 12:35:45 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/src/main/java/org/apache/abdera/ext/sharing/SharingExtensionFactory.java
URL: http://svn.apache.org/viewvc/incubator/abdera/java/trunk/extensions/src/main/java/org/apache/abdera/ext/sharing/SharingExtensionFactory.java?view=auto&rev=567319
==============================================================================
--- incubator/abdera/java/trunk/extensions/src/main/java/org/apache/abdera/ext/sharing/SharingExtensionFactory.java
(added)
+++ incubator/abdera/java/trunk/extensions/src/main/java/org/apache/abdera/ext/sharing/SharingExtensionFactory.java
Sat Aug 18 12:35:45 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/src/main/java/org/apache/abdera/ext/sharing/SharingHelper.java
URL: http://svn.apache.org/viewvc/incubator/abdera/java/trunk/extensions/src/main/java/org/apache/abdera/ext/sharing/SharingHelper.java?view=auto&rev=567319
==============================================================================
--- incubator/abdera/java/trunk/extensions/src/main/java/org/apache/abdera/ext/sharing/SharingHelper.java
(added)
+++ incubator/abdera/java/trunk/extensions/src/main/java/org/apache/abdera/ext/sharing/SharingHelper.java
Sat Aug 18 12:35:45 2007
@@ -0,0 +1,373 @@
+/*
+* 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;
+  }
+}

Added: incubator/abdera/java/trunk/extensions/src/main/java/org/apache/abdera/ext/sharing/Sync.java
URL: http://svn.apache.org/viewvc/incubator/abdera/java/trunk/extensions/src/main/java/org/apache/abdera/ext/sharing/Sync.java?view=auto&rev=567319
==============================================================================
--- incubator/abdera/java/trunk/extensions/src/main/java/org/apache/abdera/ext/sharing/Sync.java
(added)
+++ incubator/abdera/java/trunk/extensions/src/main/java/org/apache/abdera/ext/sharing/Sync.java
Sat Aug 18 12:35:45 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/src/main/java/org/apache/abdera/ext/sharing/Unpublished.java
URL: http://svn.apache.org/viewvc/incubator/abdera/java/trunk/extensions/src/main/java/org/apache/abdera/ext/sharing/Unpublished.java?view=auto&rev=567319
==============================================================================
--- incubator/abdera/java/trunk/extensions/src/main/java/org/apache/abdera/ext/sharing/Unpublished.java
(added)
+++ incubator/abdera/java/trunk/extensions/src/main/java/org/apache/abdera/ext/sharing/Unpublished.java
Sat Aug 18 12:35:45 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());
+  }
+}

Modified: incubator/abdera/java/trunk/extensions/src/main/resources/META-INF/services/org.apache.abdera.factory.ExtensionFactory
URL: http://svn.apache.org/viewvc/incubator/abdera/java/trunk/extensions/src/main/resources/META-INF/services/org.apache.abdera.factory.ExtensionFactory?view=diff&rev=567319&r1=567318&r2=567319
==============================================================================
--- incubator/abdera/java/trunk/extensions/src/main/resources/META-INF/services/org.apache.abdera.factory.ExtensionFactory
(original)
+++ incubator/abdera/java/trunk/extensions/src/main/resources/META-INF/services/org.apache.abdera.factory.ExtensionFactory
Sat Aug 18 12:35:45 2007
@@ -2,4 +2,4 @@
 org.apache.abdera.ext.opensearch.OpenSearchExtensionFactory
 org.apache.abdera.ext.media.MediaExtensionFactory
 org.apache.abdera.ext.features.FeaturesExtensionFactory
-org.apache.abdera.ext.sse.SharingExtensionFactory
\ No newline at end of file
+org.apache.abdera.ext.sharing.SharingExtensionFactory

Added: incubator/abdera/java/trunk/extensions/src/test/java/org/apache/abdera/test/sharing/SharingTest.java
URL: http://svn.apache.org/viewvc/incubator/abdera/java/trunk/extensions/src/test/java/org/apache/abdera/test/sharing/SharingTest.java?view=auto&rev=567319
==============================================================================
--- incubator/abdera/java/trunk/extensions/src/test/java/org/apache/abdera/test/sharing/SharingTest.java
(added)
+++ incubator/abdera/java/trunk/extensions/src/test/java/org/apache/abdera/test/sharing/SharingTest.java
Sat Aug 18 12:35:45 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.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);
+  }
+}



Mime
View raw message