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 2011/11/04 23:42:12 UTC

svn commit: r1197810 - in /abdera/abdera2: activities/src/main/java/org/apache/abdera2/activities/extra/ activities/src/main/java/org/apache/abdera2/activities/model/ activities/src/main/java/org/apache/abdera2/activities/model/objects/ common/src/main...

Author: jmsnell
Date: Fri Nov  4 22:42:11 2011
New Revision: 1197810

URL: http://svn.apache.org/viewvc?rev=1197810&view=rev
Log: (empty)

Added:
    abdera/abdera2/activities/src/main/java/org/apache/abdera2/activities/model/objects/EmbeddedExperience.java   (contents, props changed)
      - copied, changed from r1187164, abdera/abdera2/activities/src/main/java/org/apache/abdera2/activities/model/EmbeddedExperience.java
    abdera/abdera2/common/src/main/java/org/apache/abdera2/common/misc/MapRed.java   (with props)
    abdera/abdera2/examples/src/main/java/org/apache/abdera2/examples/activities/MapRedExample.java   (with props)
Removed:
    abdera/abdera2/activities/src/main/java/org/apache/abdera2/activities/model/EmbeddedExperience.java
Modified:
    abdera/abdera2/activities/src/main/java/org/apache/abdera2/activities/extra/Extra.java
    abdera/abdera2/activities/src/main/java/org/apache/abdera2/activities/model/ASBase.java
    abdera/abdera2/activities/src/main/java/org/apache/abdera2/activities/model/ASObject.java
    abdera/abdera2/activities/src/main/java/org/apache/abdera2/activities/model/Activity.java
    abdera/abdera2/activities/src/main/java/org/apache/abdera2/activities/model/Collection.java
    abdera/abdera2/activities/src/main/java/org/apache/abdera2/activities/model/IO.java
    abdera/abdera2/common/src/main/java/org/apache/abdera2/common/misc/MoreFunctions.java
    abdera/abdera2/examples/src/main/java/org/apache/abdera2/examples/activities/MiscellaneousExamples.java

Modified: abdera/abdera2/activities/src/main/java/org/apache/abdera2/activities/extra/Extra.java
URL: http://svn.apache.org/viewvc/abdera/abdera2/activities/src/main/java/org/apache/abdera2/activities/extra/Extra.java?rev=1197810&r1=1197809&r2=1197810&view=diff
==============================================================================
--- abdera/abdera2/activities/src/main/java/org/apache/abdera2/activities/extra/Extra.java (original)
+++ abdera/abdera2/activities/src/main/java/org/apache/abdera2/activities/extra/Extra.java Fri Nov  4 22:42:11 2011
@@ -2,6 +2,7 @@ package org.apache.abdera2.activities.ex
 
 import java.lang.reflect.Method;
 import java.util.Comparator;
+import java.util.Set;
 
 import net.sf.cglib.proxy.Enhancer;
 import net.sf.cglib.proxy.MethodInterceptor;
@@ -571,9 +572,17 @@ public class Extra {
   public static final Equivalence<ASObject> IDENTITY_EQUIVALENCE = identity();
   
   /**
+   * Equivalence instance that can be used to check the equivalence of two
+   * ASObjects
+   */
+  public static final Equivalence<ASObject> IDENTITY_WITH_DUPLICATES_EQUIVALENCE = identityWithDuplicates();
+  
+  /**
    * Two ASObject's are considered equivalent in identity if 
    * they share the same objectType and id property
-   * values. 
+   * values. Note: This implementation does not yet take 
+   * the downstreamDuplicates and upstreamDuplicates properties
+   * into account when determining equivalence.
    */
   private static Equivalence<ASObject> identity() {
     return new Equivalence<ASObject>() {
@@ -587,9 +596,16 @@ public class Extra {
         if (!aot.equalsIgnoreCase(bot)) return false;
         String aid = a.getId();
         String bid = b.getId();
-        if (bothAreNull(aid,bid)) return true;
         if (onlyOneIsNull(aid,bid)) return false;
-        if (!aid.equals(bid)) return false;
+        if (neitherIsNull(aid,bid)) {
+          if (aid.equals(bid)) return true;
+          else return false;
+        }
+        String adn = a.getDisplayName();
+        String bdn = b.getDisplayName();
+        if (bothAreNull(adn,bdn)) return true;
+        if (onlyOneIsNull(adn,bdn)) return false;
+        if (!adn.equals(bdn)) return false;
         return true;
       }
       protected int doHash(ASObject t) {
@@ -605,6 +621,33 @@ public class Extra {
     };
   }
   
+  private static Equivalence<ASObject> identityWithDuplicates() {
+    return new Equivalence<ASObject>() {
+      protected boolean doEquivalent(ASObject a, ASObject b) {
+        if (IDENTITY_EQUIVALENCE.equivalent(a, b)) 
+          return true;
+        Iterable<String> aids = a.getKnownIds();
+        Iterable<String> bids = b.getKnownIds();
+        Iterable<String> cids = 
+          Iterables.filter(
+            aids, Predicates.in((Set<String>)bids));
+        // if cids is empty, it's not a duplicate, so return false
+        // if cids isn't empty, they are likely duplicates, return true
+        return !Iterables.isEmpty(cids);
+      }
+      protected int doHash(ASObject t) {
+        String id = t.getId();
+        String objectType = t.getObjectType();
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + ((id == null) ? 0 : id.hashCode());
+        result = prime * result
+            + ((objectType == null) ? 0 : objectType.hashCode());
+        return result;
+      }
+    };
+  }
+  
   public static final Comparator<ASObject> UPDATED_COMPARATOR = 
     new UpdatedComparator();
   public static final Comparator<ASObject> PUBLISHED_COMPARATOR = 

Modified: abdera/abdera2/activities/src/main/java/org/apache/abdera2/activities/model/ASBase.java
URL: http://svn.apache.org/viewvc/abdera/abdera2/activities/src/main/java/org/apache/abdera2/activities/model/ASBase.java?rev=1197810&r1=1197809&r2=1197810&view=diff
==============================================================================
--- abdera/abdera2/activities/src/main/java/org/apache/abdera2/activities/model/ASBase.java (original)
+++ abdera/abdera2/activities/src/main/java/org/apache/abdera2/activities/model/ASBase.java Fri Nov  4 22:42:11 2011
@@ -38,6 +38,7 @@ import org.apache.abdera2.common.mediaty
 
 import static com.google.common.base.Preconditions.*;
 import com.google.common.base.Function;
+import com.google.common.collect.Iterators;
 
 /**
  * Root of the Activity Streams object hierarchy, provides the core property
@@ -57,23 +58,41 @@ public class ASBase 
       Collections.<T>emptySet() : i;
   }
   
+  /**
+   * Set the value of the "lang" property. This optionally establishes
+   * a language context for the other properties in this object. It 
+   * is not inherited by contained objects.
+   */
   public void setLang(Lang lang) {
     setProperty("lang", lang);
   }
   
+  /**
+   * Gets value of the "lang" property. 
+   */
   public Lang getLang() {
     return getProperty("lang");
   }
   
+  /**
+   * Return the value of the named property
+   */
   @SuppressWarnings("unchecked")
   public <T>T getProperty(String name) {
     return (T)exts.get(name);
   }
   
+  /**
+   * Return the value of the named property, using the specified
+   * Transform Function to translate the properties value
+   */
   public <T,R>R getProperty(String name, Function<T,R> transform) {
     return (R)transform.apply(this.<T>getProperty(name));
   }
   
+  /**
+   * Set the value of the named property
+   */
   public void setProperty(String name, Object value) {
     if (value != null)
       exts.put(name, value);
@@ -81,8 +100,11 @@ public class ASBase 
       exts.remove(name);
   }
 
+  /**
+   * Return a listing of all the properties in this object
+   */
   public Iterator<String> iterator() {
-    return exts.keySet().iterator();
+    return Iterators.<String>unmodifiableIterator(exts.keySet().iterator());
   }
 
   @Override

Modified: abdera/abdera2/activities/src/main/java/org/apache/abdera2/activities/model/ASObject.java
URL: http://svn.apache.org/viewvc/abdera/abdera2/activities/src/main/java/org/apache/abdera2/activities/model/ASObject.java?rev=1197810&r1=1197809&r2=1197810&view=diff
==============================================================================
--- abdera/abdera2/activities/src/main/java/org/apache/abdera2/activities/model/ASObject.java (original)
+++ abdera/abdera2/activities/src/main/java/org/apache/abdera2/activities/model/ASObject.java Fri Nov  4 22:42:11 2011
@@ -21,10 +21,12 @@ import org.joda.time.DateTime;
 
 import java.util.ArrayList;
 import java.util.HashSet;
+import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Set;
 
 import org.apache.abdera2.activities.extra.Extra;
+import org.apache.abdera2.activities.model.objects.EmbeddedExperience;
 import org.apache.abdera2.activities.model.objects.Mood;
 import org.apache.abdera2.activities.model.objects.PersonObject;
 import org.apache.abdera2.activities.model.objects.PlaceObject;
@@ -32,6 +34,8 @@ import org.apache.abdera2.common.anno.An
 import org.apache.abdera2.common.iri.IRI;
 import org.apache.abdera2.common.selector.Selector;
 
+import com.google.common.collect.Iterables;
+
 /**
  * Base class for all Activity Streams Objects.
  */
@@ -70,28 +74,48 @@ public class ASObject extends ASBase {
     setObjectType(objectType);
   }
   
+  /**
+   * Returns the value of the "attachments" property
+   */
   public Iterable<ASObject> getAttachments() {
     return checkEmpty((Iterable<ASObject>)getProperty(ATTACHMENTS));
   }
   
-  public void setAttachments(Set<ASObject> attachments) {
-    setProperty(ATTACHMENTS, attachments);
+  /**
+   * Sets the value of the attachments property... note... internally, the
+   * list of attachments does not allow for duplicate entries so the collection
+   * passed in is changed to a LinkedHashSet, maintaining the order of the 
+   * entries but eliminating duplicates. 
+   */
+  public void setAttachments(java.util.Collection<ASObject> attachments) {;
+    setProperty(ATTACHMENTS, new LinkedHashSet<ASObject>(attachments));
   }
   
+  /**
+   * Adds an attachment to the "attachments" property.
+   */
   public void addAttachment(ASObject... attachments) {
     Set<ASObject> list = getProperty(ATTACHMENTS);
     if (list == null) {
-      list = new HashSet<ASObject>();
+      list = new LinkedHashSet<ASObject>();
       setProperty(ATTACHMENTS, list);
     }
     for (ASObject attachment : attachments)
       list.add(attachment); 
   }
   
+  /**
+   * Return the author of this object
+   */
   public <E extends ASObject>E getAuthor() {
     return (E)getProperty(AUTHOR);
   }
   
+  /**
+   * Return the author of this object, if the author has not been
+   * set and create==true, creates a default PersonObject and 
+   * returns that.
+   */
   public <E extends ASObject>E getAuthor(boolean create) {
     ASObject obj = getAuthor();
     if (obj == null && create) {
@@ -101,43 +125,88 @@ public class ASObject extends ASBase {
     return (E)obj;
   }
   
+  /**
+   * Set the author of the object
+   */
   public void setAuthor(ASObject author) {
     setProperty(AUTHOR, author);
   }
   
+  /**
+   * Set the author of the object
+   */
   public <E extends ASObject>E setAuthor(String displayName) {
     ASObject obj = getAuthor(true);
     obj.setDisplayName(displayName);
     return (E)obj;
   }
   
+  /**
+   * Get the content of the object
+   */
   public String getContent() {
     return getProperty(CONTENT);
   }
   
+  /**
+   * Set the content of the object
+   */
   public void setContent(String content) {
     setProperty(CONTENT, content);
     
   }
   
+  /**
+   * Get the displayName of the object
+   */
   public String getDisplayName() {
     return getProperty(DISPLAYNAME);
   }
   
+  /**
+   * Set the displayName of the object
+   */
   public void setDisplayName(String displayName) {
     setProperty(DISPLAYNAME, displayName);
     
   }
   
+  /**
+   * Return the list of downstream duplicate ids for this object. 
+   * When an object is redistributed by third parties, the value of the "id"
+   * property may change. When such changes do occur, it becomes difficult
+   * to track duplicate versions of the same object. The "downstreamDuplicates"
+   * and "upstreamDuplicates" properties on the object can be used to track 
+   * modifications that occur in the "id" of the object in order to make
+   * duplication detection easier
+   */
   public Iterable<String> getDownstreamDuplicates() {
     return checkEmpty((Iterable<String>)getProperty(DOWNSTREAMDUPLICATES));
   }
   
+  /**
+   * Set the list of downstream duplicate ids for this object. 
+   * When an object is redistributed by third parties, the value of the "id"
+   * property may change. When such changes do occur, it becomes difficult
+   * to track duplicate versions of the same object. The "downstreamDuplicates"
+   * and "upstreamDuplicates" properties on the object can be used to track 
+   * modifications that occur in the "id" of the object in order to make
+   * duplication detection easier
+   */
   public void setDownstreamDuplicates(Set<String> downstreamDuplicates) {
     setProperty(DOWNSTREAMDUPLICATES, downstreamDuplicates);
     
   }
   
+  /**
+   * Add an entry to the list of downstream duplicate ids for this object. 
+   * When an object is redistributed by third parties, the value of the "id"
+   * property may change. When such changes do occur, it becomes difficult
+   * to track duplicate versions of the same object. The "downstreamDuplicates"
+   * and "upstreamDuplicates" properties on the object can be used to track 
+   * modifications that occur in the "id" of the object in order to make
+   * duplication detection easier
+   */
   public void addDownstreamDuplicate(String... duplicates) {
     Set<String> downstreamDuplicates = getProperty(DOWNSTREAMDUPLICATES);
     if (downstreamDuplicates == null) {
@@ -148,77 +217,167 @@ public class ASObject extends ASBase {
       downstreamDuplicates.add(downstreamDuplicate);  
   }
   
+  /**
+   * Get the id of this object
+   */
   public String getId() {
     return getProperty(ID);
   }
   
+  /**
+   * Set the id of this object
+   */
   public void setId(String id) {
     setProperty(ID, id);
     
   }
   
+  /**
+   * Get the "image" property
+   */
   public MediaLink getImage() {
     return getProperty(IMAGE);
   }
   
+  /**
+   * Set the "image" property
+   */
   public void setImage(MediaLink image) {
     setProperty(IMAGE, image);
-    
   }
   
+  /**
+   * Set the "image" property
+   */
+  public void setImage(String uri) {
+    if (uri == null) 
+      setImage((MediaLink)null);
+    else {
+      MediaLink link = getImage();
+      if (link == null) {
+        link = new MediaLink();
+        setProperty(IMAGE,link);
+      }
+      link.setUrl(uri);
+    }
+  }
+  
+  /**
+   * Set the "image" property
+   */
+  public void setImage(IRI uri) {
+    setImage(uri != null ? uri.toString() : null);
+  }
+  
+  /**
+   * Get the objectType
+   */
   public String getObjectType() {
     return getProperty(OBJECTTYPE);
   }
   
+  /**
+   * Set the objectType
+   */
   public void setObjectType(String objectType) {
-    if (objectType != null && ASObject.class.getSimpleName().equalsIgnoreCase(objectType))
+    if (objectType != null && 
+        ASObject.class.getSimpleName().equalsIgnoreCase(objectType))
       objectType = null;
     setProperty(OBJECTTYPE, objectType);
-    
   }
   
+  /**
+   * Get the "published" datetime
+   */
   public DateTime getPublished() {
     return getProperty(PUBLISHED);
   }
   
+  /**
+   * Set the "published" datetime
+   */
   public void setPublished(DateTime published) {
     setProperty(PUBLISHED, published);
   }
   
+  /**
+   * Set the "published" property to the current date, time and default timezone
+   */
   public void setPublishedNow() {
     setPublished(DateTime.now());
   }
   
+  /**
+   * Get the "summary" property
+   */
   public String getSummary() {
     return getProperty(SUMMARY);
   }
   
+  /**
+   * Set the "summary" property
+   */
   public void setSummary(String summary) {
     setProperty(SUMMARY, summary);
-    
   }
   
+  /**
+   * Get the "updated" property
+   */
   public DateTime getUpdated() {
     return getProperty(UPDATED);
   }
   
+  /**
+   * Set the "updated" property 
+   */
   public void setUpdated(DateTime updated) {
     setProperty(UPDATED, updated);
   }
   
+  /**
+   * Set the "updated" property to the current date,time and default timezone
+   */
   public void setUpdatedNow() {
     setUpdated(DateTime.now());
   }
   
+  /**
+   * Return the list of upstream duplicate ids for this object. 
+   * When an object is redistributed by third parties, the value of the "id"
+   * property may change. When such changes do occur, it becomes difficult
+   * to track duplicate versions of the same object. The "downstreamDuplicates"
+   * and "upstreamDuplicates" properties on the object can be used to track 
+   * modifications that occur in the "id" of the object in order to make
+   * duplication detection easier
+   */
   public Iterable<String> getUpstreamDuplicates() {
     return checkEmpty((Iterable<String>)getProperty(UPSTREAMDUPLICATES));
   }
   
+  /**
+   * Set the list of upstream duplicate ids for this object. 
+   * When an object is redistributed by third parties, the value of the "id"
+   * property may change. When such changes do occur, it becomes difficult
+   * to track duplicate versions of the same object. The "downstreamDuplicates"
+   * and "upstreamDuplicates" properties on the object can be used to track 
+   * modifications that occur in the "id" of the object in order to make
+   * duplication detection easier
+   */
   public void setUpstreamDuplicates(Set<String> upstreamDuplicates) {
     setProperty(UPSTREAMDUPLICATES, upstreamDuplicates);
     
   }
   
+  /**
+   * Add to the list of upstream duplicate ids for this object. 
+   * When an object is redistributed by third parties, the value of the "id"
+   * property may change. When such changes do occur, it becomes difficult
+   * to track duplicate versions of the same object. The "downstreamDuplicates"
+   * and "upstreamDuplicates" properties on the object can be used to track 
+   * modifications that occur in the "id" of the object in order to make
+   * duplication detection easier
+   */
   public void addUpstreamDuplicate(String... duplicates) {
     Set<String> upstreamDuplicates = getProperty(UPSTREAMDUPLICATES);
     if (upstreamDuplicates == null) {
@@ -229,19 +388,31 @@ public class ASObject extends ASBase {
       upstreamDuplicates.add(upstreamDuplicate);
   }
   
-  
+  /**
+   * Get the url of this object
+   */
   public IRI getUrl() {
     return getProperty(URL);
   }
   
+  /**
+   * Set the url of this object 
+   */
   public void setUrl(IRI url) {
     setProperty(URL,url);
   }
   
+  /**
+   * Get the collection of objects this object is considered a response to
+   */
   public Iterable<ASObject> getInReplyTo() {
     return checkEmpty((Iterable<ASObject>)getProperty(INREPLYTO));
   }
   
+  /**
+   * Get the collection of objects this object is considered a response to
+   * using the specified selector to filter the results
+   */
   public Iterable<ASObject> getInReplyTo(Selector<ASObject> selector) {
     List<ASObject> list= new ArrayList<ASObject>();
     for (ASObject obj : getInReplyTo())
@@ -250,57 +421,92 @@ public class ASObject extends ASBase {
     return list;
   }
   
-  public void setInReplyTo(Set<ASObject> inReplyTo) {
-    setProperty(INREPLYTO, inReplyTo);
+  /**
+   * Set the collection of objects this object is considered a response to.
+   * Note that duplicates are removed
+   */
+  public void setInReplyTo(java.util.Collection<ASObject> inReplyTo) {
+    setProperty(INREPLYTO, new LinkedHashSet<ASObject>(inReplyTo));
   }
   
+  /**
+   * Add a new object this object is considered a response to
+   */
   public void addInReplyTo(ASObject... inReplyTos) {
     Set<ASObject> list = getProperty(INREPLYTO);
     if (list == null) {
-      list = new HashSet<ASObject>();
+      list = new LinkedHashSet<ASObject>();
       setProperty(INREPLYTO, list);
     }
     for (ASObject inReplyTo : inReplyTos)
       list.add(inReplyTo);
   }
   
+  /**
+   * Get the "location" property
+   */
   public PlaceObject getLocation() {
     return getProperty(LOCATION);
   }
   
+  /**
+   * Set the "location" property
+   */
   public void setLocation(PlaceObject location) {
     setProperty(LOCATION, location);
     location.setObjectType(null);
   }
   
+  /**
+   * Get the "mood" property
+   */
   public Mood getMood() {
     return getProperty(MOOD);
   }
   
+  /**
+   * Set the "mood" property
+   */
   public void setMood(Mood mood) {
     setProperty(MOOD, mood);
   }
   
+  /**
+   * Get the "source" property
+   */
   public <E extends ASObject>E getSource() {
     return (E)getProperty(SOURCE);
   }
   
+  /**
+   * Set the "source" property
+   */
   public void setSource(ASObject source) {
     setProperty(SOURCE, source);
   }
 
+  /**
+   * Get the collection of tags for this object
+   */
   public Iterable<ASObject> getTags() {
-    return getProperty(TAGS);
+    return checkEmpty((Iterable<ASObject>)getProperty(TAGS));
   }
   
-  public void setTags(Set<ASObject> tags) {
-    setProperty(TAGS, tags);
+  /**
+   * Set the collection of tags for this object. Duplicates 
+   * will be removed.
+   */
+  public void setTags(java.util.Collection<ASObject> tags) {
+    setProperty(TAGS, new LinkedHashSet<ASObject>(tags));
   }
   
+  /**
+   * Add an object to the collection of tags for this object
+   */
   public void addTag(ASObject... tags) {
     Set<ASObject> list = getProperty(TAGS);
     if (list == null) {
-      list = new HashSet<ASObject>();
+      list = new LinkedHashSet<ASObject>();
       setProperty(TAGS, list);
     }
     for (ASObject tag : tags)
@@ -323,10 +529,16 @@ public class ASObject extends ASBase {
     setProperty(EMBED,embed);
   }
   
+  /**
+   * Get the "rating" property
+   */
   public double getRating() {
     return (Double)getProperty(RATING);
   }
   
+  /**
+   * Set the "rating" property
+   */
   public void setRating(double rating) {
     setProperty(RATING, rating);
   }
@@ -424,6 +636,22 @@ public class ASObject extends ASBase {
     return Extra.sameIdentity(this).apply(obj);
   }
   
+  /**
+   * Returns a union of all known IDs for this object.. specifically,
+   * this is a union of the "id", "downstreamDuplicates" and "upstreamDuplicates"
+   * properties
+   */
+  public Iterable<String> getKnownIds() {
+    Set<String> list = new LinkedHashSet<String>();
+    if (has("id")) list.add(getId());
+    Iterables.addAll(list, checkEmpty(getDownstreamDuplicates()));
+    Iterables.addAll(list, checkEmpty(getUpstreamDuplicates()));
+    return list;
+  }
+  
+  /**
+   * Begins creating a new object using the fluent factory api
+   */
   public static <X extends ASObjectGenerator<T>,T extends ASObject>X make() {
     return (X)new ASObjectGenerator<T>();
   }

Modified: abdera/abdera2/activities/src/main/java/org/apache/abdera2/activities/model/Activity.java
URL: http://svn.apache.org/viewvc/abdera/abdera2/activities/src/main/java/org/apache/abdera2/activities/model/Activity.java?rev=1197810&r1=1197809&r2=1197810&view=diff
==============================================================================
--- abdera/abdera2/activities/src/main/java/org/apache/abdera2/activities/model/Activity.java (original)
+++ abdera/abdera2/activities/src/main/java/org/apache/abdera2/activities/model/Activity.java Fri Nov  4 22:42:11 2011
@@ -57,8 +57,18 @@ public class Activity extends ASObject {
   public static final String URL = "url";
   public static final String VERB = "verb";
   
+  /**
+   * Used to specify the target audience for an Activity.
+   */
   public enum Audience { 
-    TO, BTO, CC, BCC; 
+    /** Identifies the public primary target audience of the Activity **/
+    TO,
+    /** Identifies the private primary target audience of the Activity **/
+    BTO, 
+    /** Identifies the public secondary target audience of the Activity **/
+    CC, 
+    /** Identifies the private secondary target audience of the Activity **/
+    BCC; 
     String label() {
       return name().toLowerCase();
     }
@@ -97,6 +107,12 @@ public class Activity extends ASObject {
     return getProperty(ACTOR);
   }
   
+  /**
+   * Returns the Actor Object... if an actor object 
+   * does not yet exist and create==true, a default
+   * PersonObject will be created and set as the 
+   * object and returned.
+   */
   public <E extends ASObject>E getActor(boolean create) {
     ASObject obj = getActor();
     if (obj == null && create) {
@@ -106,28 +122,54 @@ public class Activity extends ASObject {
     return (E)obj;
   }
   
+  /**
+   * Set the Actor for this Activity.
+   */
   public void setActor(ASObject actor) {
     setProperty(ACTOR, actor);
   }
   
+  /**
+   * Set the Actor's displayName for this activity. 
+   * If the Actor has not yet been set, a default
+   * PersonObject will be created with the specified
+   * displayName. If the Actor object has already 
+   * been set, this will change the displayName to
+   * that specified.
+   */
   public <E extends ASObject>E setActor(String displayName) {
     ASObject obj = getActor(true);
     obj.setDisplayName(displayName);
     return (E)obj;
   }
   
+  /**
+   * Return the value of the "content" property for this activity
+   */
   public String getContent() {
     return getProperty(CONTENT);
   }
   
+  /**
+   * Set the value of the "content" property for this activity
+   */
   public void setContent(String content) {
     setProperty(CONTENT, content);
   }
   
+  /**
+   * Return the ASObject value of the "generator" property for this
+   * activity.
+   */
   public <E extends ASObject>E getGenerator() {
     return (E)getProperty(GENERATOR);
   }
   
+  /**
+   * Return the ASObject value for the "generator" property for this
+   * activity. If the generator has not yet been set and create==true,
+   * a default ServiceObject will be created, set and returned.
+   */
   public <E extends ASObject>E getGenerator(boolean create) {
     ASObject obj = getGenerator();
     if (obj == null && create) {
@@ -137,56 +179,134 @@ public class Activity extends ASObject {
     return (E)obj;
   }
   
+  /**
+   * Set the value of the "generator" property for this Activity
+   */
   public void setGenerator(ASObject generator) {
     setProperty(GENERATOR, generator); 
   }
   
+  /**
+   * Set the value of the "generator" properties displayName.
+   * If the generator has not yet been set, a default ServiceObject
+   * will be created, set and returned. Otherwise, the displayName
+   * of the existing object will be changed to that specified.
+   */
   public <E extends ASObject>E setGenerator(String displayName) {
     ASObject obj = getGenerator(true);
     obj.setDisplayName(displayName);
     return (E)obj;
   }
   
+  /**
+   * Return the value of the "icon" property 
+   */
   public MediaLink getIcon() {
     return getProperty(ICON);
   }
   
+  /**
+   * Set the value of the "icon" property
+   */
   public void setIcon(MediaLink icon) {
     setProperty(ICON, icon);  
   }
   
+  /**
+   * Set the value of the "icon" property. If the
+   * property has not yet been set, the MediaLink
+   * will be created.
+   */
+  public void setIcon(String uri) {
+    if (uri == null) 
+      setProperty(ICON,null);
+    else {
+      MediaLink link = getIcon();
+      if (link == null) {
+        link = new MediaLink();
+        setIcon(link);
+      }
+      link.setUrl(uri);
+    }
+  }
+  
+  /**
+   * Set the value of the "icon" property. If the
+   * property has not yet been set, the MediaLink 
+   * will be created.
+   */
+  public void setIcon(IRI uri) {
+    setIcon(uri != null ? uri.toString() : null);
+  }
+  
+  /**
+   * Get the value of the "id" property
+   */
   public String getId() {
     return getProperty(ID);
   }
   
+  /**
+   * Set the value of the "id" property
+   */
   public void setId(String id) {
     setProperty(ID, id);
   }
   
+  /**
+   * set the value of the "id" property
+   */
+  public void setId(IRI id) {
+    setId(id != null ? id.toString() : null);
+  }
+  
+  /**
+   * Get the Activities Object property
+   */
   public <E extends ASObject>E getObject() {
     return (E)getProperty(OBJECT);
   }
   
+  /**
+   * Set the Activities Object property
+   */
   public void setObject(ASObject object) {
     setProperty(OBJECT, object);
   }
   
+  /**
+   * Get the value of the Activities "published" property
+   */
   public DateTime getPublished() {
     return getProperty(PUBLISHED);
   }
   
+  /**
+   * Set the value of the Activities "published" property
+   */
   public void setPublished(DateTime published) {
     setProperty(PUBLISHED, published);
   }
   
+  /**
+   * Set the value of the Activities "published" property using the current date, time and default timezone
+   */
   public void setPublishedNow() {
     setPublished(DateTime.now());
   }
   
+  /**
+   * Get the value of the Activities "provider" property
+   */
   public <E extends ASObject>E getProvider() {
     return (E)getProperty(PROVIDER);
   }
   
+  /**
+   * Set the value of the Activities "provider" property.
+   * If the value has not yet been set, a default ServiceObject
+   * will be created, set and returned
+   */
   public <E extends ASObject>E getProvider(boolean create) {
     ASObject obj = getProvider();
     if (obj == null && create) {
@@ -196,104 +316,207 @@ public class Activity extends ASObject {
     return (E)obj;
   }
   
+  /**
+   * Set the value of the Activities "provider" property
+   */
   public void setProvider(ASObject provider) {
     setProperty(PROVIDER, provider);
   }
   
+  /**
+   * Set the displayName of the Activities "provider" property.
+   * If the object has not yet been created, a default 
+   * ServiceObject will be created, otherwise the displayName
+   * will be changed to the provided value
+   */
   public <E extends ASObject>E setProvider(String displayName) {
     ASObject obj = getProvider(true);
     obj.setDisplayName(displayName);
     return (E)obj;
   }
   
+  /**
+   * Get the value of Activities "target" property
+   */
   public <E extends ASObject>E getTarget() {
     return (E)getProperty(TARGET);
   }
   
+  /**
+   * Set the value of the Activities "target" property
+   */
   public void setTarget(ASObject target) {
     setProperty(TARGET, target);
-    
   }
   
+  /**
+   * Get the value of the "title" property
+   */
   public String getTitle() {
     return getProperty(TITLE);
   }
   
+  /**
+   * Set the value of the "title" property
+   */
   public void setTitle(String title) {
     setProperty(TITLE, title);
     
   }
   
+  /**
+   * Get the value of the "updated" property
+   */
   public DateTime getUpdated() {
     return getProperty(UPDATED);
   }
   
+  /**
+   * Set the value of the "updated" property
+   */
   public void setUpdated(DateTime updated) {
     setProperty(UPDATED, updated);
   }
   
+  /**
+   * Set the value of the "updated" property to the current date, time and default timezone
+   */
   public void setUpdatedNow() {
     setUpdated(DateTime.now());
   }
   
+  /**
+   * Get the value of the "url" property
+   */
   public IRI getUrl() {
     return getProperty(URL);
   }
   
+  /**
+   * Set the value of the "url" property
+   */
   public void setUrl(IRI url) {
     setProperty(URL, url);
   }
   
+  /**
+   * Get the value of the "verb" property
+   */
   public Verb getVerb() {
     return getProperty(VERB);
   }
   
+  /**
+   * Set the value of the "verb" property
+   */
   public void setVerb(Verb verb) {
     setProperty(VERB, verb);
   }
+  
+  /**
+   * Set the value of the "verb" property
+   */
+  public void setVerb(String verb) {
+    setVerb(verb != null ? Verb.get(verb) : null);
+  }
 
-  @Override
+  /**
+   * Get the value of the "author" property.. for Activity 
+   * objects, the "author" property is mapped to the "actor"
+   * property in order to avoid duplication of content. 
+   * If you want to get the actual "author" property, use
+   * getProperty("author")...
+   */
   public <E extends ASObject>E getAuthor() {
     return (E)getActor();
   }
   
+  /**
+   * Set the value of the "author" property.. for Activity
+   * objects, the "author" property is mapped to the "actor"
+   * property in orde to avoid duplication of content. 
+   * If you want to set the actual "author" property,  use
+   * setProperty("author",val)
+   */
   public <E extends ASObject>E getAuthor(boolean create) {
     return (E)getActor(create);
   }
 
-  @Override
+  /**
+   * Set the value of the "author" property.. for Activity
+   * objects, the "author" property is mapped to the "actor"
+   * property in orde to avoid duplication of content. 
+   * If you want to set the actual "author" property,  use
+   * setProperty("author",val)
+   */
   public void setAuthor(ASObject author) {
     setActor(author); 
   }
   
+  /**
+   * Set the value of the "author" property.. for Activity
+   * objects, the "author" property is mapped to the "actor"
+   * property in order to avoid duplication of content. 
+   * If you want to set the actual "author" property,  use
+   * setProperty("author",val)
+   */
   public <E extends ASObject>E setAuthor(String displayName) {
     return (E)setActor(displayName);
   }
 
-  @Override
+  /**
+   * Get the "displayName" property. For Activity objects, the
+   * "displayName" property is mapped to the "title" property.
+   * If you want to get the actual "displayName" property,
+   * us getProperty("displayName")
+   */
   public String getDisplayName() {
     return getTitle();
   }
 
-  @Override
+  /**
+   * Set the "displayName" property. For Activity objects, the
+   * "displayName" property is mapped to the "title" property.
+   * If you want to set the actual "displayName" property,
+   * us setProperty("displayName",val)
+   */
   public void setDisplayName(String displayName) {
     setTitle(displayName);
   }
 
-  @Override
+  /**
+   * Get the "image" property. For Activity objects, the
+   * "image" property is mapped to the "icon" property.
+   * If you want to get the actual "image" property,
+   * us getProperty("image")
+   */
   public MediaLink getImage() {
     return getIcon();
   }
 
-  @Override
+  /**
+   * Set the "image" property. For Activity objects, the
+   * "image" property is mapped to the "icon" property.
+   * If you want to set the actual "image" property,
+   * us setProperty("image",val)
+   */
   public void setImage(MediaLink image) {
     setIcon(image);
   }
   
+  /**
+   * Get the specified target audience for the activity
+   */
   public Iterable<ASObject> getAudience(Audience audience) {
     return checkEmpty((Iterable<ASObject>)getProperty(audience.label()));
   }
   
+  /**
+   * Get the specified target audience for the activity using the 
+   * specified selector as a filter to limit the results. This 
+   * can be used, for instance, to quickly determine if a particular 
+   * entity is included in the audience of the activity
+   */
   public Iterable<ASObject> getAudience(Audience audience, Selector<ASObject> selector) {
     List<ASObject> list = new ArrayList<ASObject>();
     for (ASObject obj : getAudience(audience))
@@ -302,10 +525,18 @@ public class Activity extends ASObject {
     return list;
   }
   
+  /**
+   * Set the target audience for the activity
+   */
   public void setAudience(Audience audience, Set<ASObject> set) {
     setProperty(audience.label(), set);
   }
   
+  /**
+   * Add one or more entities to the target audience of the activity.
+   * Unlike setAudience, this will not overwrite the existing audience
+   * property values.
+   */
   public void addAudience(Audience audience, ASObject... objs) {
     Set<ASObject> list = getProperty(audience.label());
     if (list == null) {
@@ -316,6 +547,9 @@ public class Activity extends ASObject {
       list.add(obj);
   }
 
+  /**
+   * Begin creating a new Activity object using the fluent factory API
+   */
   public static <T extends Activity>ActivityGenerator<T> makeActivity() {
     return new ActivityGenerator<T>();
   }

Modified: abdera/abdera2/activities/src/main/java/org/apache/abdera2/activities/model/Collection.java
URL: http://svn.apache.org/viewvc/abdera/abdera2/activities/src/main/java/org/apache/abdera2/activities/model/Collection.java?rev=1197810&r1=1197809&r2=1197810&view=diff
==============================================================================
--- abdera/abdera2/activities/src/main/java/org/apache/abdera2/activities/model/Collection.java (original)
+++ abdera/abdera2/activities/src/main/java/org/apache/abdera2/activities/model/Collection.java Fri Nov  4 22:42:11 2011
@@ -44,32 +44,55 @@ public class Collection<T extends ASObje
   public static final String ITEMS = "items";
   public static final String OBJECT_TYPES = "objectTypes";
 
+  /**
+   * Return the value of the "totalItems" property... this does not 
+   * necessarily reflect the actual number of items in the "items" 
+   * iterator.
+   */
   public int getTotalItems() {
     return (Integer)getProperty(TOTAL_ITEMS);
   }
   
+  /**
+   * Set the value of the "totalItems" property
+   */
   public Collection<T> setTotalItems(int totalItems) {
     setProperty(TOTAL_ITEMS, totalItems);
     return this;
   }
   
+  /**
+   * Get the url of this collection
+   */
   public IRI getUrl() {
     return getProperty(URL);
   }
   
+  /**
+   * Set the url of this collection
+   */
   public void setUrl(IRI url) {
     setProperty(URL, url);
   }
 
-  @SuppressWarnings("unchecked")
+  /**
+   * Get the list of objectTypes expected to be found in this collection
+   */
   public Iterable<String> getObjectTypes() {
-    return checkEmpty((Iterable<String>)getProperty(OBJECT_TYPES));
+    return checkEmpty(this.<Iterable<String>>getProperty(OBJECT_TYPES));
   }
   
-  public void setObjectTypes(Set<String> types) {
-    setProperty(OBJECT_TYPES,types);
+  /**
+   * Set the list of objectTypes expected to be found in this collection
+   */
+  public void setObjectTypes(java.util.Collection<String> types) {
+    setProperty(OBJECT_TYPES,new LinkedHashSet<String>(types));
   }
   
+  /**
+   * Add a new objectType to the list of objectTypes expected to be found
+   * in this collection
+   */
   public void addObjectType(String... objectTypes) {
     Set<String> list = getProperty(OBJECT_TYPES);
     if (list == null) {
@@ -80,6 +103,9 @@ public class Collection<T extends ASObje
       list.add(objectType);
   }
   
+  /**
+   * get the items collection using the specified selector as a filter
+   */
   public Iterable<T> getItems(Selector<T> selector) {
     List<T> list = new ArrayList<T>();
     for (T item : getItems()) 
@@ -88,11 +114,19 @@ public class Collection<T extends ASObje
     return list;
   }
   
+  /**
+   * get the items contained in this collection
+   */
   @SuppressWarnings("unchecked")
   public Iterable<T> getItems() {
     return checkEmpty((Iterable<T>)getProperty(ITEMS));
   }
   
+  /**
+   * Get the items contained in this collection. If no "items" 
+   * property exists, a new LinkedHashSet will be created, set 
+   * and returned if create == true;
+   */
   public Iterable<T> getItems(boolean create) {
     Iterable<T> items = getItems();
     if (items == null && create) {
@@ -102,17 +136,32 @@ public class Collection<T extends ASObje
     return items;
   }
   
-  public void setItems(Set<T> items) {
+  /**
+   * Set the items in this collection, overwriting the existing value.
+   * setting this will change the value of the "totalItems" property 
+   * to reflect the number of items passed in.
+   */
+  public void setItems(java.util.Collection<T> items) {
     setProperty(ITEMS, new LinkedHashSet<T>(items));
     setTotalItems(items.size());
   }
   
+  /**
+   * Set the items in this collection, overwriting the existing value.
+   * setting this will change the value of the "totalItems" property 
+   * to reflect the number of items passed in.
+   */
   public void setItems(Iterable<T> items) {
     Set<T> set = new LinkedHashSet<T>();
     for (T item : items) set.add(item);
     setItems(set);
   }
   
+  /**
+   * Add an item to this collection
+   * setting this will change the value of the "totalItems" property 
+   * to reflect the number of items passed in.
+   */
   public void addItem(T... items) {
     Set<T> list = getProperty(ITEMS);
     if (list == null) {
@@ -124,6 +173,9 @@ public class Collection<T extends ASObje
     setTotalItems(list.size());
   }
   
+  /**
+   * Begin making a new collection object using the fluent factory api
+   */
   public static <T extends ASObject>CollectionGenerator<T> makeCollection() {
     return new CollectionGenerator<T>();
   }

Modified: abdera/abdera2/activities/src/main/java/org/apache/abdera2/activities/model/IO.java
URL: http://svn.apache.org/viewvc/abdera/abdera2/activities/src/main/java/org/apache/abdera2/activities/model/IO.java?rev=1197810&r1=1197809&r2=1197810&view=diff
==============================================================================
--- abdera/abdera2/activities/src/main/java/org/apache/abdera2/activities/model/IO.java (original)
+++ abdera/abdera2/activities/src/main/java/org/apache/abdera2/activities/model/IO.java Fri Nov  4 22:42:11 2011
@@ -24,6 +24,9 @@ import java.io.OutputStream;
 import java.io.OutputStreamWriter;
 import java.io.Reader;
 import java.io.Writer;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
 
 import org.apache.abdera2.common.Discover;
 import org.apache.abdera2.common.anno.AnnoUtil;
@@ -169,13 +172,51 @@ public abstract class IO {
   public abstract MediaLink readMediaLink(Reader reader);
   public abstract MediaLink readMediaLink(String json);
   
-  public static IO get(TypeAdapter<?>... adapters) {    
-    String defaultImpl = 
-      AnnoUtil.getDefaultImplementation(IO.class);
-    return Discover.locate(
-        IO.class, 
-        defaultImpl, 
-        (Object)adapters);  
+  private static class CacheKey {
+    private final int hash;
+    CacheKey(TypeAdapter<?>[] adapters) {
+      this.hash = Arrays.hashCode(adapters);
+    }
+    public int hashCode() {
+      return hash;
+    }
+    public boolean equals(Object obj) {
+      if (this == obj)
+        return true;
+      if (obj == null)
+        return false;
+      if (getClass() != obj.getClass())
+        return false;
+      CacheKey other = (CacheKey) obj;
+      if (hash != other.hash)
+        return false;
+      return true;
+    }
+  }
+  private static final Map<CacheKey,IO> map = 
+    new HashMap<CacheKey,IO>();
+  
+  private static synchronized IO get_cached(TypeAdapter<?>... adapters) {
+    return map.get(new CacheKey(adapters));
+  }
+  
+  private static synchronized void set_cached(IO io, TypeAdapter<?>... adapters) {
+    map.put(new CacheKey(adapters),io);
+  }
+  
+  public static IO get(TypeAdapter<?>... adapters) { 
+    IO io = get_cached(adapters);
+    if (io == null) {
+      String defaultImpl = 
+        AnnoUtil.getDefaultImplementation(IO.class);
+      io = Discover.locate(
+          IO.class, 
+          defaultImpl, 
+          (Object)adapters); 
+      if (io != null)
+        set_cached(io,adapters);
+    } 
+    return io;
   }
   
   public void writeCollection(

Copied: abdera/abdera2/activities/src/main/java/org/apache/abdera2/activities/model/objects/EmbeddedExperience.java (from r1187164, abdera/abdera2/activities/src/main/java/org/apache/abdera2/activities/model/EmbeddedExperience.java)
URL: http://svn.apache.org/viewvc/abdera/abdera2/activities/src/main/java/org/apache/abdera2/activities/model/objects/EmbeddedExperience.java?p2=abdera/abdera2/activities/src/main/java/org/apache/abdera2/activities/model/objects/EmbeddedExperience.java&p1=abdera/abdera2/activities/src/main/java/org/apache/abdera2/activities/model/EmbeddedExperience.java&r1=1187164&r2=1197810&rev=1197810&view=diff
==============================================================================
--- abdera/abdera2/activities/src/main/java/org/apache/abdera2/activities/model/EmbeddedExperience.java (original)
+++ abdera/abdera2/activities/src/main/java/org/apache/abdera2/activities/model/objects/EmbeddedExperience.java Fri Nov  4 22:42:11 2011
@@ -1,7 +1,10 @@
-package org.apache.abdera2.activities.model;
+package org.apache.abdera2.activities.model.objects;
 
 import java.util.Map;
 
+import org.apache.abdera2.activities.model.ASBase;
+import org.apache.abdera2.activities.model.ASObject;
+import org.apache.abdera2.activities.model.Generator;
 import org.apache.abdera2.common.iri.IRI;
 
 /**

Propchange: abdera/abdera2/activities/src/main/java/org/apache/abdera2/activities/model/objects/EmbeddedExperience.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: abdera/abdera2/common/src/main/java/org/apache/abdera2/common/misc/MapRed.java
URL: http://svn.apache.org/viewvc/abdera/abdera2/common/src/main/java/org/apache/abdera2/common/misc/MapRed.java?rev=1197810&view=auto
==============================================================================
--- abdera/abdera2/common/src/main/java/org/apache/abdera2/common/misc/MapRed.java (added)
+++ abdera/abdera2/common/src/main/java/org/apache/abdera2/common/misc/MapRed.java Fri Nov  4 22:42:11 2011
@@ -0,0 +1,695 @@
+package org.apache.abdera2.common.misc;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Iterator;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.NoSuchElementException;
+import java.util.Set;
+import java.util.concurrent.ConcurrentSkipListMap;
+import java.util.concurrent.ConcurrentSkipListSet;
+
+import com.google.common.base.Equivalence;
+import com.google.common.base.Function;
+import com.google.common.base.Functions;
+import com.google.common.base.Predicate;
+import com.google.common.base.Supplier;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Iterators;
+
+/**
+ * Provides lightweight, standalone MapReduce functionality without
+ * requiring Hadoop. This is intended to provide *BASIC* support for 
+ * *SIMPLE* MapReduce operations on *SMALL* datasets. If you need 
+ * more intensive support, then Hadoop MapReduce is obviously the 
+ * better option. 
+ * 
+ * The MapRed class provides an number of methods for creating and 
+ * composing MapReduce operations and bridges those with the Guava
+ * Libraries interfaces. For instance, using the various compose()
+ * methods, it is possible to create a com.google.common.base.Function
+ * that wraps a complete MapReduce operation with a single call to 
+ * Function.apply().
+ * 
+ * Heavy use of Generics makes proper set up a bit tricky and complicated,
+ * but once created, the MapReduce functions are immutable and threadsafe
+ * and can safely be stored as static final variables used throughout 
+ * an application.
+ * 
+ * A number of common basic Mapper and Reducer objects are also provided.
+ */
+public final class MapRed {
+  
+  private MapRed() {}
+  
+  /**
+   * Begin constructing the input to a MapReduce Function using a 
+   * fluent factory API.. e.g.
+   * <pre>
+   * MapRed.PairBuilder&lt;Void,Activity> gen = 
+   *   MapRed
+   *    .&lt;Void,String>make()
+   *    .pair(null, "a")
+   *    .pair(null, "b")
+   *    .pair(null, "c");
+   * </pre>
+   * 
+   * The PairBuilder.get() method return an Iterable of MapRed.Pair
+   * objects. That Iterable is used as the input to the MapReduce Function.. 
+   * e.g.
+   * 
+   * <pre>
+   * Function&lt;Iterable&lt;Pair&lt;Void,String>>,Iterable&lt;Pair&lt;String,Iterable&lt;Integer>>>> f1 = ...
+   * Iterable&lt;Pair&lt;String,Iterable&lt;Integer>>> res = f1.apply(gen.get());
+   * </pre>
+   * 
+   * By default, the Function, and the wrapped MapReduce operation, executes 
+   * within the current thread and blocks until completion. If you need async
+   * operation.. first, you should consider whether you need a full MapReduce 
+   * implementation like Hadoop, or, you can use wrap the Function in a 
+   * MoreFunctions.FutureFunction... e.g. 
+   * 
+   * <pre>
+   * ExecutorService exec = 
+   *   MoreExecutors.getExitingExecutorService(
+   *     (ThreadPoolExecutor) Executors.newCachedThreadPool());
+   *
+   * Function&lt;
+   *   Iterable&lt;MapRed.Pair&lt;Void, Activity>>, 
+   *   Future&lt;Iterable&lt;MapRed.Pair&lt;Integer,Iterable&lt;String>>>>> ff = 
+   *   MoreFunctions.&lt;
+   *     Iterable&lt;MapRed.Pair&lt;Void, Activity>>, 
+   *     Iterable&lt;MapRed.Pair&lt;Integer,Iterable&lt;String>>>>futureFunction(f3,exec);
+   * </pre>
+   * 
+   * Note, again, the tricky use of generics but defining things in this way
+   * ensures type-safety throughout the operation. The FutureFunction.apply() 
+   * will submit the operation to the provided Executor and return a Future 
+   * whose value will be set once the operation completes. For greater control 
+   * over the execution, you can call MoreFunctions.functionTask(...) to get
+   * a FutureTask instance that you can submit the ExecutorService yourself.
+   */
+  public static <K,V>PairBuilder<K,V> make() {
+    return new PairBuilder<K,V>();
+  }
+  
+  public static class PairBuilder<K,V> implements Supplier<Iterable<Pair<K,V>>>, PairReader<K,V> {
+    private final List<Pair<K,V>> list = 
+      new ArrayList<Pair<K,V>>();
+    public PairBuilder<K,V> pair(K k, V v) {
+      list.add(MapRed.<K,V>pair(k,v));
+      return this;
+    }
+    public Iterable<Pair<K, V>> get() {
+      return list;
+    }
+    public Iterator<Pair<K, V>> iterator() {
+      return get().iterator();
+    }
+  }
+  
+  public static <K,V>Iterable<Pair<K,V>> pairs(Map<K,V> map) {
+    List<Pair<K,V>> list = new ArrayList<Pair<K,V>>();
+    for (Map.Entry<K,V> entry : map.entrySet())
+      list.add(pair(entry.getKey(),entry.getValue()));
+    return list;
+  }
+  
+  public static <K,V>Pair<K,V> pair(K k, V v) {
+    return new Pair<K,V>(k,v);
+  }
+  
+  public static class Pair<K,V> {
+    private K key;
+    private V val;
+    public Pair(K key, V val) {
+      this.key = key;
+      this.val = val;
+    }
+    public K key() {
+      return key;
+    }
+    public V val() {
+      return val;
+    }
+  }
+  
+  public static interface Reducer<K2,V2,K3,V3> {
+    void reduce(
+      K2 key, 
+      Iterator<V2> vals,
+      Collector<K3,V3> context);
+  }
+  
+  public static interface Mapper<K1,V1,K2,V2> {
+    void map(K1 key, V1 val, Collector<K2,V2> context);
+  }
+  
+  public static interface Collector<K,V> {
+    void collect(K key, V val);
+  }
+  
+  public static interface PairReader<K,V> extends Iterable<Pair<K,V>> {}
+  
+  public static interface MapperFunction<K1,V1,K2,V2>
+    extends Function<Iterable<Pair<K1,V1>>,Iterable<Pair<K2,Iterable<V2>>>> {}
+
+  public static interface ReducerFunction<K1,V1,K2,V2>
+    extends Function<Iterable<Pair<K1,Iterable<V1>>>,Iterable<Pair<K2,Iterable<V2>>>> {}
+
+  public static <K1,V1,K2,V2,K3,V3>Function<Iterable<Pair<K1,V1>>,Iterable<Pair<K3,Iterable<V3>>>> compose(
+    Mapper<K1,V1,K2,V2> mapper, 
+    Reducer<K2,V2,K3,V3> reducer) {
+      return Functions.compose(asFunction(reducer),asFunction(mapper));
+  }
+
+  public static <K1,V1,K2,V2,K3,V3>Function<Iterable<Pair<K1,V1>>,Iterable<Pair<K3,Iterable<V3>>>> compose(
+    Mapper<K1,V1,K2,V2> mapper, 
+    Reducer<K2,V2,K2,V2> combiner,
+    Reducer<K2,V2,K3,V3> reducer) {
+      return Functions
+        .compose(
+          asFunction(reducer),
+          Functions
+            .compose(
+              asFunction(combiner),
+              asFunction(mapper)));
+  }
+  
+  public static <K1,V1,K2,V2,V3>Function<Iterable<Pair<K1,V1>>,Iterable<Pair<K2,Iterable<V3>>>> compose(
+    Mapper<K1,V1,K2,V2> mapper, 
+    Reducer<K2,V2,K2,V3> reducer,
+    Comparator<K2> comparator) {
+      return Functions.compose(asFunction(reducer,comparator),asFunction(mapper,comparator));
+  }
+  
+  public static <K1,V1,K2,V2,K3,V3>Function<Iterable<Pair<K1,V1>>,Iterable<Pair<K3,Iterable<V3>>>> compose(
+    Mapper<K1,V1,K2,V2> mapper, 
+    Reducer<K2,V2,K3,V3> reducer,
+    Comparator<K2> comparator,
+    Comparator<K3> comparator2) {
+      return Functions.compose(asFunction(reducer,comparator2),asFunction(mapper,comparator));
+  }
+  
+  public static <K1,V1,K2,V2,K3,V3>Function<Iterable<Pair<K1,V1>>,Iterable<Pair<K3,Iterable<V3>>>> compose(
+    Mapper<K1,V1,K2,V2> mapper, 
+    Reducer<K2,V2,K2,V2> combiner,
+    Reducer<K2,V2,K3,V3> reducer,
+    Comparator<K2> comparator,
+    Comparator<K3> comparator2) {
+      return Functions
+        .compose(
+          asFunction(reducer, comparator2),
+          Functions
+            .compose(
+              asFunction(combiner, comparator),
+              asFunction(mapper,comparator)));
+  }
+  
+  public static <K1,V1,K2,V2,V3>Function<Iterable<Pair<K1,V1>>,Iterable<Pair<K2,Iterable<V3>>>> compose(
+    Mapper<K1,V1,K2,V2> mapper, 
+    Reducer<K2,V2,K2,V2> combiner,
+    Reducer<K2,V2,K2,V3> reducer,
+    Comparator<K2> comparator) {
+      return Functions
+        .compose(
+          asFunction(reducer, comparator),
+          Functions
+            .compose(
+              asFunction(combiner, comparator),
+              asFunction(mapper,comparator)));
+  }
+  
+  public static <K1,V1,K2,V2,K3,V3>Function<Iterable<Pair<K1,V1>>,Iterable<Pair<K3,Iterable<V3>>>> compose(
+    MapperFunction<K1,V1,K2,V2> mapper, 
+    ReducerFunction<K2,V2,K3,V3> reducer) {
+      return Functions.compose(reducer,mapper);
+  }
+
+  public static <K1,V1,K2,V2,K3,V3>Function<Iterable<Pair<K1,V1>>,Iterable<Pair<K3,Iterable<V3>>>> compose(
+    MapperFunction<K1,V1,K2,V2> mapper, 
+    ReducerFunction<K2,V2,K2,V2> combiner,
+    ReducerFunction<K2,V2,K3,V3> reducer) {
+      return Functions
+        .compose(
+          reducer,
+          Functions
+            .compose(
+              combiner,
+              mapper));
+  }
+  
+  public static <K1,V1,K2,V2>MapperFunction<K1,V1,K2,V2> asFunction(
+      final Mapper<K1,V1,K2,V2> mapper) {
+    return asFunction(mapper,false);
+  }
+  
+  public static <K1,V1,K2,V2>MapperFunction<K1,V1,K2,V2> asFunction(
+    final Mapper<K1,V1,K2,V2> mapper,
+    final Comparator<K2> comparator) {
+    return asFunction(mapper,false, comparator);
+  }
+  
+  public static <K1,V1,K2,V2>MapperFunction<K1,V1,K2,V2> asFunction(
+    final Mapper<K1,V1,K2,V2> mapper,
+    final boolean nulls) {
+    return new MapperFunction<K1,V1,K2,V2>() {
+      public Iterable<Pair<K2,Iterable<V2>>> apply(Iterable<Pair<K1,V1>> input) {
+        SimpleCollector<K2,V2> context = new SimpleCollector<K2,V2>(nulls);
+        List<Pair<K2, Iterable<V2>>> list = new ArrayList<Pair<K2, Iterable<V2>>>();
+        for (Pair<K1, V1> entry : input)
+          mapper.map(entry.key(), entry.val(), context);
+        for (Map.Entry<K2, Iterable<V2>> entry : context.collected())
+          list.add(pair(entry.getKey(), entry.getValue()));
+        return list;
+      }      
+    };
+  }
+  
+  public static <K1,V1,K2,V2>MapperFunction<K1,V1,K2,V2> asFunction(
+    final Mapper<K1,V1,K2,V2> mapper,
+    final boolean nulls,
+    final Comparator<K2> comparator) {
+    return new MapperFunction<K1,V1,K2,V2>() {
+      public Iterable<Pair<K2,Iterable<V2>>> apply(Iterable<Pair<K1,V1>> input) {
+        SimpleCollector<K2,V2> context = new SimpleCollector<K2,V2>(nulls,comparator);
+        List<Pair<K2, Iterable<V2>>> list = new ArrayList<Pair<K2, Iterable<V2>>>();
+        for (Pair<K1, V1> entry : input)
+          mapper.map(entry.key(), entry.val(), context);
+        for (Map.Entry<K2, Iterable<V2>> entry : context.collected())
+          list.add(pair(entry.getKey(), entry.getValue()));
+        return list;
+      }      
+    };
+  }
+
+  public static <K1,V1,K2,V2>ReducerFunction<K1,V1,K2,V2> asFunction(
+      final Reducer<K1,V1,K2,V2> reducer) {
+    return asFunction(reducer,false);
+  }
+  
+  public static <K1,V1,K2,V2>ReducerFunction<K1,V1,K2,V2> asFunction(
+      final Reducer<K1,V1,K2,V2> reducer,
+      final Comparator<K2> comparator) {
+    return asFunction(reducer,false, comparator);
+  }
+
+  public static <K1,V1,K2,V2>ReducerFunction<K1,V1,K2,V2> asFunction(
+    final Reducer<K1,V1,K2,V2> reducer,
+    final boolean nulls,
+    final Comparator<K2> comparator) {
+    return new ReducerFunction<K1,V1,K2,V2>() {
+      public Iterable<Pair<K2,Iterable<V2>>> apply(Iterable<Pair<K1,Iterable<V1>>> input) {
+        SimpleCollector<K2,V2> context = new SimpleCollector<K2,V2>(nulls, comparator);
+        List<Pair<K2, Iterable<V2>>> list = new ArrayList<Pair<K2, Iterable<V2>>>();
+        for (Pair<K1, Iterable<V1>> entry : input)
+          reducer.reduce(entry.key(), entry.val().iterator(), context);
+        for (Map.Entry<K2, Iterable<V2>> entry : context.collected())
+          list.add(pair(entry.getKey(), entry.getValue()));
+        return list;
+      }      
+    };
+  }
+  
+  public static <K1,V1,K2,V2>ReducerFunction<K1,V1,K2,V2> asFunction(
+    final Reducer<K1,V1,K2,V2> reducer,
+    final boolean nulls) {
+    return new ReducerFunction<K1,V1,K2,V2>() {
+      public Iterable<Pair<K2,Iterable<V2>>> apply(Iterable<Pair<K1,Iterable<V1>>> input) {
+        SimpleCollector<K2,V2> context = new SimpleCollector<K2,V2>(nulls);
+        List<Pair<K2, Iterable<V2>>> list = new ArrayList<Pair<K2, Iterable<V2>>>();
+        for (Pair<K1, Iterable<V1>> entry : input)
+          reducer.reduce(entry.key(), entry.val().iterator(), context);
+        for (Map.Entry<K2, Iterable<V2>> entry : context.collected())
+          list.add(pair(entry.getKey(), entry.getValue()));
+        return list;
+      }      
+    };
+  }
+  
+  public static <K,V>Mapper<K,V,V,K> invertMapper() {
+    return new Mapper<K,V,V,K>() {
+      public void map(K key, V val, Collector<V, K> context) {
+        context.collect(val, key);
+      }      
+    };
+  }
+  
+  public static <K,V>Reducer<K,V,V,K> invertReducer() {
+    return new Reducer<K,V,V,K>() {
+      public void reduce(K key, Iterator<V> vals, Collector<V, K> context) {
+        while(vals.hasNext())
+          context.collect(vals.next(), key);
+      }      
+    };
+  }
+  
+  public static <K,V>Mapper<K,V,K,V> identityMapper() {
+    return new Mapper<K,V,K,V>() {
+      public void map(K key, V val, Collector<K, V> context) {
+        context.collect(key, val);
+      }
+    };
+  }
+  
+  public static <K,V>Reducer<K,V,K,V> identityReducer() {
+    return new Reducer<K,V,K,V>() {
+      public void reduce(K key, Iterator<V> vals, Collector<K, V> context) {
+        while(vals.hasNext())
+          context.collect(key,vals.next());
+      }      
+    };
+  }
+  
+  public static <K,V>Mapper<K,V,K,V> identityMapper(
+    final Predicate<V> predicate) {
+    return new Mapper<K,V,K,V>() {
+      public void map(K key, V val, Collector<K, V> context) {
+        if (predicate.apply(val))
+          context.collect(key, val);
+      }
+    };
+  }
+  
+  public static <K,V>Reducer<K,V,K,V> identityReducer(
+    final Predicate<V> predicate) {
+    return new Reducer<K,V,K,V>() {
+      public void reduce(K key, Iterator<V> vals, Collector<K, V> context) {
+        while(vals.hasNext()) {
+          V val = vals.next();
+          if (predicate.apply(val))
+            context.collect(key,val);
+        }
+      }      
+    };
+  }
+  
+  public static <K,V1,V2>Mapper<K,V1,K,V2> functionMapper(
+    final Function<V1,V2> transform) {
+    return new Mapper<K,V1,K,V2>() {
+      public void map(K key, V1 val, Collector<K,V2> context) {
+        context.collect(key, transform.apply(val));
+      }
+    };
+  }
+  
+  public static <K,V1,V2>Reducer<K,V1,K,V2> functionReducer(
+    final Function<Iterator<V1>,V2> transform) {
+      return new Reducer<K,V1,K,V2>() {
+        public void reduce(K key, Iterator<V1> vals, Collector<K, V2> context) {
+          context.collect(key, transform.apply(vals)); 
+        }        
+      };
+  }
+  
+  public static <K,V1,V2>Mapper<K,V1,K,V2> functionMapper(
+    final Function<V1,V2> transform,
+    final Predicate<V1> predicate) {
+    return new Mapper<K,V1,K,V2>() {
+      public void map(K key, V1 val, Collector<K,V2> context) {
+        if (predicate.apply(val))
+          context.collect(key, transform.apply(val));
+      }
+    };
+  }
+  
+  public static <K1,V1,K2,V2>Mapper<K1,V1,K2,V2> functionMapper(
+    final Function<K1,K2> keyTransform,
+    final Function<V1,V2> valTransform) {
+      return new Mapper<K1,V1,K2,V2>() {
+        public void map(K1 key, V1 val, Collector<K2, V2> context) {
+          context.collect(keyTransform.apply(key),valTransform.apply(val));         
+        }
+      };
+  }
+  
+  public static <K1,V1,K2,V2>Reducer<K1,V1,K2,V2> functionReducer(
+    final Function<K1,K2> keyTransform,
+    final Function<Iterator<V1>,V2> valTransform) {
+      return new Reducer<K1,V1,K2,V2>() {
+        public void reduce(K1 key, Iterator<V1> vals, Collector<K2, V2> context) {
+          context.collect(keyTransform.apply(key), valTransform.apply(vals)); 
+        }        
+      };
+  }
+  
+  public static <K1,V1,K2,V2>Mapper<K1,V1,K2,V2> functionMapper(
+    final Function<K1,K2> keyTransform,
+    final Function<V1,V2> valTransform,
+    final Predicate<V1> predicate) {
+      return new Mapper<K1,V1,K2,V2>() {
+        public void map(K1 key, V1 val, Collector<K2, V2> context) {
+          if (predicate.apply(val))
+            context.collect(keyTransform.apply(key),valTransform.apply(val));
+        }        
+      };
+  }
+  
+  public static <K,V>Reducer<K,V,K,Integer> countingReducer() {
+    return new Reducer<K,V,K,Integer>() {
+      public void reduce(K key, Iterator<V> vals, Collector<K, Integer> context) {
+        context.collect(key, Iterators.size(vals));
+      }      
+    };
+  }
+  
+  public static <K,V>Reducer<K,V,K,V> noDuplicatesReducer() {
+    return new Reducer<K,V,K,V>() {
+      final Set<V> set = new LinkedHashSet<V>();
+      public void reduce(K key, Iterator<V> vals, Collector<K, V> context) {
+        while(vals.hasNext()) {
+          V v = vals.next();
+          if (!set.contains(v)) {
+            context.collect(key, v);
+            set.add(v);
+          }
+        }
+      }      
+    };
+  }
+
+  public static <K,V>Reducer<K,V,K,V> noEquivalentsReducer(
+    final Equivalence<V> equivalence) {
+    return new Reducer<K,V,K,V>() {
+      final Set<V> set = new LinkedHashSet<V>();
+      public void reduce(K key, Iterator<V> vals, Collector<K, V> context) {
+        while(vals.hasNext()) {
+          V v = vals.next();
+          Predicate<V> ve = equivalence.equivalentTo(v);
+          try {
+            Iterables.find(set, ve);
+          } catch (NoSuchElementException e) {
+            context.collect(key,v);
+            set.add(v);
+          }
+        }
+      }      
+    };
+  }
+
+  /**
+   * A PartitionFunction is responsible for taking an input Iterable and
+   * splitting it into multiple sub-iterables.
+   */
+  public static interface PartitionFunction<T> 
+    extends Function<Iterable<T>,Iterable<Iterable<T>>> {}
+  
+  /**
+   * A CombinerFunction is responsible for taking multiple Iterables and
+   * combining them into a single Iterable. 
+   */
+  public static interface CombinerFunction<T>
+    extends Function<Iterable<Iterable<T>>,Iterable<T>> {}
+  
+  /**
+   * Return the default basic PartitionFunction that splits the 
+   * input Iterable into multiple unmodifiable Iterables of the 
+   * given size (the final iterable may be smaller)
+   */
+  public static <T>PartitionFunction<T> partitioner(final int size) {
+    return new PartitionFunction<T>() {
+      public Iterable<Iterable<T>> apply(Iterable<T> input) {
+        Iterable<List<T>> i = Iterables.<T>partition(input, size);
+        List<Iterable<T>> l = new ArrayList<Iterable<T>>();
+        Iterables.addAll(l, i);
+        return Iterables.unmodifiableIterable(l);
+      }
+    };
+  }
+  
+  /**
+   * Return the default CombinerFunction that concats the 
+   * given Iterables into a single Iterable without resorting. 
+   * (e.g. and Iterable of [["a","b"],["d","c"]] would be 
+   * combined into a single Iterable ["a","b","d","c"]
+   */
+  public static <T>CombinerFunction<T> combiner() {
+    return new CombinerFunction<T>() {
+      public Iterable<T> apply(Iterable<Iterable<T>> input) {
+        return Iterables.concat(input);
+      }      
+    };
+  }
+  
+  /**
+   * Returns a CombinerFunction that concats the 
+   * given Iterables into a single Iterable without resorting,
+   * with all duplicates removed.
+   * (e.g. and Iterable of [["a","b"],["d","c","b"]] would be 
+   * combined into a single Iterable ["a","b","d","c"]
+   */
+  public static <T>CombinerFunction<T> uniqueCombiner() {
+    return new CombinerFunction<T>() {
+      public Iterable<T> apply(Iterable<Iterable<T>> input) {
+        Iterable<T> c = Iterables.concat(input);
+        LinkedHashSet<T> l = new LinkedHashSet<T>();
+        Iterables.addAll(l, c);
+        return l;
+      }      
+    };
+  }
+  
+  /**
+   * Return the default CombinerFunction that concats the 
+   * given Iterables into a single Iterable using the specified
+   * Comparator for sorting. If Comparator is null, no sorting
+   * will be performed
+   * (e.g. and Iterable of [["a","b"],["d","c"]] would be 
+   * combined into a single Iterable ["a","b","c","d"]
+   */
+  public static <T>CombinerFunction<T> sortingCombiner(final Comparator<T> order) {
+    return new CombinerFunction<T>() {
+      public Iterable<T> apply(Iterable<Iterable<T>> input) {
+        Iterable<T> i = Iterables.concat(input);
+        List<T> l = new ArrayList<T>();
+        Iterables.addAll(l, i);
+        if (order != null)
+          Collections.sort(l,order);
+        return l;
+      }      
+    };
+  }
+  
+  /**
+   * Return the default CombinerFunction that concats the 
+   * given Iterables into a single Iterable using the natural
+   * order of the elements for sorting
+   * (e.g. and Iterable of [["a","b"],["d","c"]] would be 
+   * combined into a single Iterable ["a","b","c","d"]
+   */
+  public static <T extends Comparable<T>>CombinerFunction<T> sortingCombiner() {
+    return new CombinerFunction<T>() {
+      public Iterable<T> apply(Iterable<Iterable<T>> input) {
+        Iterable<T> i = Iterables.concat(input);
+        List<T> l = new ArrayList<T>();
+        Iterables.addAll(l, i);
+        Collections.<T>sort(l);
+        return l;
+      }      
+    };
+  }
+  
+  
+  /**
+   * Return the default CombinerFunction that concats the 
+   * given Iterables into a single Iterable using the specified
+   * Comparator for sorting. If Comparator is null, no sorting
+   * will be performed
+   * (e.g. and Iterable of [["a","b"],["d","c"]] would be 
+   * combined into a single Iterable ["a","b","c","d"]
+   */
+  public static <T>CombinerFunction<T> uniqueSortingCombiner(final Comparator<T> order) {
+    return new CombinerFunction<T>() {
+      public Iterable<T> apply(Iterable<Iterable<T>> input) {
+        Iterable<T> i = Iterables.concat(input);
+        Set<T> l = new ConcurrentSkipListSet<T>(order);
+        Iterables.addAll(l, i);
+        return l;
+      }      
+    };
+  }
+  
+  /**
+   * Return the default CombinerFunction that concats the 
+   * given Iterables into a single Iterable using the natural
+   * order of the elements for sorting
+   * (e.g. and Iterable of [["a","b"],["d","c"]] would be 
+   * combined into a single Iterable ["a","b","c","d"]
+   */
+  public static <T extends Comparable<T>>CombinerFunction<T> uniqueSortingCombiner() {
+    return new CombinerFunction<T>() {
+      public Iterable<T> apply(Iterable<Iterable<T>> input) {
+        Iterable<T> i = Iterables.concat(input);
+        Set<T> l = new ConcurrentSkipListSet<T>();
+        Iterables.addAll(l, i);
+        return l;
+      }      
+    };
+  }
+  
+  /**
+   * Return the default collector impl
+   */
+  public static <K,V>Collector<K,V> collector(boolean nulls, Comparator<K> order) {
+    return new SimpleCollector<K,V>(nulls,order);
+  }
+  
+  /**
+   * Return the default collector impl
+   */
+  public static <K,V>Collector<K,V> collector(boolean nulls) {
+    return new SimpleCollector<K,V>(nulls);
+  }
+  
+  /**
+   * Return the default collector impl
+   */
+  public static <K,V>Collector<K,V> collector(Comparator<K> order) {
+    return new SimpleCollector<K,V>(false,order);
+  }
+  
+  /**
+   * Return the default collector impl
+   */
+  public static <K,V>Collector<K,V> collector() {
+    return new SimpleCollector<K,V>(false);
+  }
+  
+  public static class SimpleCollector<K,V> 
+    implements MapRed.Collector<K, V> {
+    
+    private final Map<K,Iterable<V>> map;
+    private final boolean collectNulls;
+    public SimpleCollector() {
+      this(false);
+    }
+    public SimpleCollector(boolean nulls) {
+      this.collectNulls = nulls;
+      map = new ConcurrentSkipListMap<K,Iterable<V>>();
+    }
+    public SimpleCollector(Comparator<K> comparator) {
+      this(false,comparator);
+    }
+    public SimpleCollector(boolean nulls, Comparator<K> comparator) {
+      this.collectNulls = nulls;
+      map = comparator != null ?
+        new ConcurrentSkipListMap<K,Iterable<V>>(comparator) :
+        new ConcurrentSkipListMap<K,Iterable<V>>();
+    }
+    public void collect(K key, V val) {
+      if (!collectNulls && val == null) return;
+      List<V> set = (List<V>) map.get(key);
+      if (set == null) {
+        set = new ArrayList<V>();
+        map.put(key,set);
+      }
+      set.add(val);
+    }
+    public Iterable<Map.Entry<K,Iterable<V>>> collected() {  
+      return Collections.<Map.Entry<K,Iterable<V>>>unmodifiableSet(map.entrySet());
+    }
+  }
+}

Propchange: abdera/abdera2/common/src/main/java/org/apache/abdera2/common/misc/MapRed.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: abdera/abdera2/common/src/main/java/org/apache/abdera2/common/misc/MoreFunctions.java
URL: http://svn.apache.org/viewvc/abdera/abdera2/common/src/main/java/org/apache/abdera2/common/misc/MoreFunctions.java?rev=1197810&r1=1197809&r2=1197810&view=diff
==============================================================================
--- abdera/abdera2/common/src/main/java/org/apache/abdera2/common/misc/MoreFunctions.java (original)
+++ abdera/abdera2/common/src/main/java/org/apache/abdera2/common/misc/MoreFunctions.java Fri Nov  4 22:42:11 2011
@@ -6,6 +6,10 @@ import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Future;
+import java.util.concurrent.FutureTask;
 
 import org.apache.abdera2.common.Discover;
 
@@ -14,6 +18,7 @@ import com.google.common.base.Predicate;
 import com.google.common.base.Supplier;
 import com.google.common.base.Suppliers;
 import com.google.common.collect.Iterables;
+import com.google.common.util.concurrent.ListenableFutureTask;
 
 public class MoreFunctions {
 
@@ -356,4 +361,62 @@ public class MoreFunctions {
         }
       }
   };
+  
+  public static final Function<String,Integer> parseInt =
+    new Function<String,Integer>() {
+      public Integer apply(String input) {
+        try {
+          return (input != null) ? Integer.valueOf(input) : -1;
+        } catch (NumberFormatException e) {
+          return -1;
+        }
+      }
+  };
+  
+  public static final Function<String,Short> parseShort =
+    new Function<String,Short>() {
+      public Short apply(String input) {
+        try {
+          return (input != null) ? Short.valueOf(input) : -1;
+        } catch (NumberFormatException e) {
+          return -1;
+        }
+      }
+  };
+  
+  public static <I,O>Function<I,Future<O>> futureFunction(
+    Function<I,O> function, 
+    ExecutorService exec) {
+      return new FutureFunction<I,O>(function,exec);
+  }
+  
+  public static <I,O>FutureTask<O> functionTask(
+    final Function<I,O> function, 
+    final I input) {
+    return ListenableFutureTask.<O>create(
+      new Callable<O>() {
+        public O call() throws Exception {
+          return function.apply(input);
+        }            
+      }
+    );
+  }
+  
+  public static class FutureFunction<I,O> 
+    implements Function<I,Future<O>> {
+    final Function<I,O> inner;
+    final ExecutorService exec;
+    public FutureFunction(
+      Function<I,O> inner, 
+      ExecutorService exec) {
+      this.inner = inner;
+      this.exec = exec;
+    }
+    public Future<O> apply(final I input) {
+      FutureTask<O> task = functionTask(inner,input);
+      exec.submit(task);
+      return task;
+    }
+  }
+  
 }

Added: abdera/abdera2/examples/src/main/java/org/apache/abdera2/examples/activities/MapRedExample.java
URL: http://svn.apache.org/viewvc/abdera/abdera2/examples/src/main/java/org/apache/abdera2/examples/activities/MapRedExample.java?rev=1197810&view=auto
==============================================================================
--- abdera/abdera2/examples/src/main/java/org/apache/abdera2/examples/activities/MapRedExample.java (added)
+++ abdera/abdera2/examples/src/main/java/org/apache/abdera2/examples/activities/MapRedExample.java Fri Nov  4 22:42:11 2011
@@ -0,0 +1,132 @@
+package org.apache.abdera2.examples.activities;
+
+import static com.google.common.util.concurrent.MoreExecutors.getExitingExecutorService;
+import static org.apache.abdera2.common.misc.MapRed.asFunction;
+import static org.apache.abdera2.common.misc.MapRed.compose;
+
+import java.io.ByteArrayOutputStream;
+import java.io.StringReader;
+import java.net.URL;
+import java.util.Collections;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+import java.util.concurrent.ThreadPoolExecutor;
+
+import org.apache.abdera2.Abdera;
+import org.apache.abdera2.activities.model.ASObject;
+import org.apache.abdera2.activities.model.Activity;
+import org.apache.abdera2.activities.model.Collection;
+import org.apache.abdera2.activities.model.IO;
+import org.apache.abdera2.common.misc.MapRed;
+import org.apache.abdera2.common.misc.MoreFunctions;
+import org.apache.abdera2.common.misc.MapRed.Collector;
+import org.apache.abdera2.common.misc.MapRed.Mapper;
+import org.apache.abdera2.common.misc.MapRed.Pair;
+import org.apache.abdera2.common.misc.MapRed.PairBuilder;
+import org.apache.abdera2.common.misc.MapRed.ReducerFunction;
+import org.apache.abdera2.model.Document;
+import org.apache.abdera2.model.Feed;
+import org.apache.abdera2.parser.Parser;
+import org.apache.abdera2.parser.ParserOptions;
+
+import com.google.common.base.Function;
+import com.google.common.base.Functions;
+
+/**
+ * A basic example showing the use of the org.apache.abdera2.common.misc.MapRed
+ * lightweight MapReduce functionality. This class is designed to provide a 
+ * general purpose, *lightweight*, *basic*, *simple* MapReduce capability 
+ * designed around working with relatively *small* data sets for basic analysis
+ * operations. It is NOT designed to provide an alternative to a full MapReduce
+ * implementation such as Hadoop. 
+ * 
+ * The MapRed class has been tightly integrated with the Guava Libraries
+ * Function interface to make it possible to encapsulate a mapreduce 
+ * operation within a single Function object. 
+ * 
+ * In this example, we first pull an Atom feed and convert that into an 
+ * Activity Streams. Second, we prepare the input data for the 
+ * MapReduce operation which is composed statically and stored in a 
+ * final static Function variable. Third, we invoke the Function with 
+ * the input data asynchronously using an ExecutorService. The main 
+ * thread waits for the operation to complete, then iterates the output,
+ * which, in this case, is a summarizaton of the total number of posts
+ * per author in the original Atom feed.
+ */
+public class MapRedExample {
+  // Prepare the various functions and store them as static final variables
+  
+  private final static Function<
+    Iterable<Pair<Void, Activity>>, 
+    Iterable<Pair<String, Iterable<Integer>>>> f1 =
+      compose(
+        new MyMapper(),
+        MapRed.<String,ASObject>countingReducer()
+      );
+  
+  private final static ReducerFunction<String,Integer,Integer,String> f2 =
+        asFunction(MapRed.<String,Integer>invertReducer(), 
+        Collections.<Integer>reverseOrder()); 
+    
+  private final static Function<
+      Iterable<Pair<Void, Activity>>, 
+      Iterable<Pair<Integer,Iterable<String>>>> f3 = 
+        Functions.compose(f2,f1);
+     
+  private final static ExecutorService exec = 
+      getExitingExecutorService(
+        (ThreadPoolExecutor) Executors.newCachedThreadPool());
+    
+  private final static Function<
+      Iterable<Pair<Void, Activity>>, 
+      Future<Iterable<Pair<Integer,Iterable<String>>>>> ff = 
+      MoreFunctions.<
+        Iterable<Pair<Void, Activity>>, 
+        Iterable<Pair<Integer,Iterable<String>>>>futureFunction(f3,exec);
+  
+  public static void main(String... args) throws Exception {
+    // Read the Atom Feed
+    Abdera abdera = Abdera.getInstance();
+    URL url = new URL("http://planet.intertwingly.net/atom.xml");
+    Parser parser = abdera.getParser();
+    ParserOptions options = parser.getDefaultParserOptions();
+    options.setCharset("UTF-8");
+    Document<Feed> doc = abdera.getParser().parse(url.openStream(),url.toString(),options);
+    Feed feed = doc.getRoot();    
+    ByteArrayOutputStream out = new ByteArrayOutputStream();
+    feed.writeTo("activity", out);
+    
+    // Converted it to an Activity Stream
+    String r = new String(out.toByteArray(),"UTF-8");
+    Collection<Activity> col = IO.get().readCollection(new StringReader(r));
+    
+    // Prepare the input data
+    PairBuilder<Void,Activity> gen = 
+      MapRed
+      .<Void,Activity>make();
+    for (Activity activity : col.getItems())
+      gen.pair(null, activity);
+        
+    // The Function ff is asynchronous... we apply it, then call get on
+    // the returned Future to wait the result. The mapreduce operation
+    // occurs in a different thread and sets the value of the Future 
+    // when it is complete
+    for (Pair<Integer,Iterable<String>> entry : ff.apply(gen).get())
+      System.out.println(
+        entry.key() + "=" + entry.val());
+    
+    
+  }
+  
+  static class MyMapper 
+    implements Mapper<Void,Activity,String,ASObject> {
+    public void map(
+      Void key, 
+      Activity val, 
+      Collector<String,ASObject> context) {
+        String ot = val.getActor().getDisplayName();
+        context.collect(ot!=null?ot:"", val.getActor());
+    }    
+  }
+}

Propchange: abdera/abdera2/examples/src/main/java/org/apache/abdera2/examples/activities/MapRedExample.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: abdera/abdera2/examples/src/main/java/org/apache/abdera2/examples/activities/MiscellaneousExamples.java
URL: http://svn.apache.org/viewvc/abdera/abdera2/examples/src/main/java/org/apache/abdera2/examples/activities/MiscellaneousExamples.java?rev=1197810&r1=1197809&r2=1197810&view=diff
==============================================================================
--- abdera/abdera2/examples/src/main/java/org/apache/abdera2/examples/activities/MiscellaneousExamples.java (original)
+++ abdera/abdera2/examples/src/main/java/org/apache/abdera2/examples/activities/MiscellaneousExamples.java Fri Nov  4 22:42:11 2011
@@ -1,6 +1,7 @@
 package org.apache.abdera2.examples.activities;
 
 import org.apache.abdera2.activities.extra.ASContext;
+import org.apache.abdera2.activities.extra.Extra;
 import org.apache.abdera2.activities.model.Activity;
 import org.apache.abdera2.activities.model.Collection;
 import org.apache.abdera2.common.templates.Template;
@@ -9,6 +10,45 @@ public class MiscellaneousExamples {
 
   public static void main(String... args) throws Exception {
     
+    // Every object and activity has an "id" property.. when
+    // an object gets passed around through multiple parties,
+    // the "id" of the object may change but the object itself
+    // stays the same. The changing id can make it difficult to
+    // detect duplicates of the same object so the Activity
+    // Streams specification provides two properties called
+    // "downstreamDuplicates" and "upstreamDuplicates", both of
+    // which are arrays that can be used to record to known 
+    // id's of a single object. A basic equals() check on the
+    // Activity cannot determine if the objects are actually
+    // duplicates with different ids. For that, we provide 
+    // two alternative Equivalence functions, one that bases
+    // it's decision solely on the values of the "id" properties,
+    // and another that properly compares all known ids recorded
+    // using the "id", "downstreamDuplicates" and "upsteamDuplicates"
+    // property values.
+    
+    // first we create two activities that have different "id" values,
+    // but share common values in their downstream and upstream duplicates.
+    // basically, we're saying that an object with the "id":"baz" is a 
+    // known derivative of the first Activity object we create with "id":"foo", 
+    // and we're saying that an Activity with the "id":"bar" is itself a 
+    // derivative of "id":"baz" .... so even those our two activities
+    // do not know about each other directly, we can related the two
+    // and detect that they are likely duplicates of one another
+    
+    Activity a1 = new Activity();
+    a1.setId("foo");
+    a1.addDownstreamDuplicate("baz");
+    
+    Activity a2 = new Activity();
+    a2.setId("bar");
+    a2.addUpstreamDuplicate("baz");
+    
+    System.out.println(Extra.IDENTITY_EQUIVALENCE.equivalent(a1, a2)); // false
+    System.out.println(Extra.IDENTITY_WITH_DUPLICATES_EQUIVALENCE.equivalent(a1, a2)); // true
+    
+    
+    
     // Working with URI Templates.. the ASContext class
     // provides a URI Template Context implementation
     // that wraps an Activity Streams object, making it