abdera-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From jmsn...@apache.org
Subject svn commit: r1225378 - in /abdera/abdera2: common/src/main/java/org/apache/abdera2/common/templates/Template.java common/src/main/java/org/apache/abdera2/common/text/CodepointIterator.java docs/Getting.Started/common.xml
Date Wed, 28 Dec 2011 23:09:16 GMT
Author: jmsnell
Date: Wed Dec 28 23:09:16 2011
New Revision: 1225378

URL: http://svn.apache.org/viewvc?rev=1225378&view=rev
Log:
Documentation, Improvements

Modified:
    abdera/abdera2/common/src/main/java/org/apache/abdera2/common/templates/Template.java
    abdera/abdera2/common/src/main/java/org/apache/abdera2/common/text/CodepointIterator.java
    abdera/abdera2/docs/Getting.Started/common.xml

Modified: abdera/abdera2/common/src/main/java/org/apache/abdera2/common/templates/Template.java
URL: http://svn.apache.org/viewvc/abdera/abdera2/common/src/main/java/org/apache/abdera2/common/templates/Template.java?rev=1225378&r1=1225377&r2=1225378&view=diff
==============================================================================
--- abdera/abdera2/common/src/main/java/org/apache/abdera2/common/templates/Template.java
(original)
+++ abdera/abdera2/common/src/main/java/org/apache/abdera2/common/templates/Template.java
Wed Dec 28 23:09:16 2011
@@ -36,6 +36,7 @@ import com.google.common.base.Function;
 import com.google.common.base.Supplier;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Multimap;
 
 import static com.google.common.base.Preconditions.*;
 
@@ -235,7 +236,9 @@ public final class Template 
           (Context)obj : 
          obj instanceof Map ? 
            new MapContext((Map)obj, isiri) : 
-           new ObjectContext(obj, isiri);
+           obj instanceof Multimap ?
+             new MapContext(((Multimap)obj).asMap()) :
+             new ObjectContext(obj, isiri);
     }
     
     /**

Modified: abdera/abdera2/common/src/main/java/org/apache/abdera2/common/text/CodepointIterator.java
URL: http://svn.apache.org/viewvc/abdera/abdera2/common/src/main/java/org/apache/abdera2/common/text/CodepointIterator.java?rev=1225378&r1=1225377&r2=1225378&view=diff
==============================================================================
--- abdera/abdera2/common/src/main/java/org/apache/abdera2/common/text/CodepointIterator.java
(original)
+++ abdera/abdera2/common/src/main/java/org/apache/abdera2/common/text/CodepointIterator.java
Wed Dec 28 23:09:16 2011
@@ -31,6 +31,7 @@ import java.util.NoSuchElementException;
 
 
 import com.ibm.icu.text.UCharacterIterator;
+import com.ibm.icu.text.UForwardCharacterIterator;
 
 public abstract class CodepointIterator 
   implements Iterator<Integer> {
@@ -154,14 +155,14 @@ public abstract class CodepointIterator 
           current = i.next();
       }
       protected int get() {
-        if (current != UCharacterIterator.DONE) {
+        if (current != UForwardCharacterIterator.DONE) {
           int v = current;
           current = i.nextCodePoint();
           return v;
         } else throw new NoSuchElementException();
       }
       public boolean hasNext() {
-        return current != UCharacterIterator.DONE;
+        return current != UForwardCharacterIterator.DONE;
       }
 
   }

Modified: abdera/abdera2/docs/Getting.Started/common.xml
URL: http://svn.apache.org/viewvc/abdera/abdera2/docs/Getting.Started/common.xml?rev=1225378&r1=1225377&r2=1225378&view=diff
==============================================================================
--- abdera/abdera2/docs/Getting.Started/common.xml (original)
+++ abdera/abdera2/docs/Getting.Started/common.xml Wed Dec 28 23:09:16 2011
@@ -643,31 +643,309 @@ col.getItems(activityPublished(atOrBetwe
     
     <section title="URI Templates">
     
-      <t>TBD</t>
-    
-    </section>
-    
-    <section title="Text Utilities">
-    
-      <t>TBD</t>
-    
-    </section>
-    
-    <section title="Request Chain API">
-    
-      <t>TBD</t>
+      <t>Abdera2 includes an implementation of the current URI Template
+      <eref target="http://tools.ietf.org/html/draft-gregorio-uritemplate-07">specification</eref>.
+      A URI Template is a specially formatted string containing tokens that 
+      can be replaced to expand into a URI or IRI. For example:</t>
+      
+      <figure><artwork>
+  private static final Template template =
+    new Template(
+      "http://example.org/~{user}{/categories*}{?foo,bar}");
+      </artwork></figure>
+      
+      <figure><preamble>Expanding the template using a java.util.Map:</preamble><artwork><![CDATA[
+  MapContext context = new MapContext();
+  context.put("user", "johndoe");
+  context.put("categories", of("a","b","c"));
+  context.put("foo", "xyz");
+  context.put("bar", "123");
+  
+  System.out.println(template.expand(context));
+      ]]></artwork></figure>
+      
+      <t>The URI generated by this template is: 
+      http://example.org/~johndoe/a/b/c?foo=xyz&bar=123</t>
+      
+      <figure><preamble>Expanding the template using a com.google.common.collect.Multimap:</preamble><artwork<![CDATA[
+  Multimap<String, Object> map = 
+    LinkedHashMultimap.create();
+  map.put("user", "james");
+  map.put("categories", "a");
+  map.put("categories", "b");
+  map.put("categories", "c");
+  map.put("foo", "abc");
+  map.put("bar", "xyz");
+  System.out.println(template.expand(map));
+      ]]></figure>
+      
+      <figure><preamble>Expanding the template using a Java Object:</preamble><artwork><![CDATA[
+  public static class MyObject {
+    public String user = "james";
+    public List<String> getCategories() {
+      return ImmutableList.of("a","b","c");
+    }
+    public Foo getFoo() {
+      return new Foo();
+    }
+    public String getBar() {
+      return "xyz";
+    }
+  }
+  static class Foo {
+    public String toString() {
+      return "xyz";
+    }
+  }
+  
+  System.out.println(template.expand(new MyObject()));
+      ]]></artwork></figure>
     
     </section>
-    
+
     <section title="Lightweight Map-Reduce API">
-    
-      <t>TBD</t>
-    
-    </section>
-    
-    <section title="Guava Extensions">
-    
+
       <t>TBD</t>
+
+    <figure><artwork><![CDATA[
+  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 = 
+    MoreExecutors2.getExitingExecutor();
+  
+  private static final Function<Collection<Activity>,Iterable<Pair<Void, Activity>>>
transform = 
+    new Function<Collection<Activity>,Iterable<Pair<Void, Activity>>>()
{
+      public Iterable<Pair<Void, Activity>> apply(Collection<Activity>
input) {
+        return 
+          Pair.<Void,Activity>make()
+            .index(MoreFunctions.<Activity>alwaysVoid(), input.getItems());
+      }
+  };
+  
+  private final static Function<
+    Collection<Activity>, 
+    Future<Iterable<Pair<Integer,Iterable<String>>>>> ff = 
+    Functions.compose(
+    MoreFunctions.<
+      Iterable<Pair<Void, Activity>>, 
+      Iterable<Pair<Integer,Iterable<String>>>>futureFunction(f3,exec),
+    transform);
+
+  private Activity getActivity(String name,int n) {
+    return Activity.makeActivity()
+      .actor(PersonObject.makePerson(name))
+      .id(String.format("urn:%s:%s",name,n))
+      .get();
+  }
+  
+  @Test
+  public void testMapRed() throws Exception {
+    Collection<Activity> col = 
+      Collection.<Activity>makeCollection()
+       .item(getActivity("Joe",1))
+       .item(getActivity("Joe",2))
+       .item(getActivity("Mark",3))
+       .item(getActivity("Mark",4))
+       .item(getActivity("Sally",5))
+       .get();
+    
+    // This is basically MapReduce contained within a Function,
+    // Runs asynch using exiting executorservice... call to 
+    // ff.apply(gen).get() hides all the magic...
+    // this particular function looks at the activity stream
+    // and counts the number of activities per actor
+    
+    Iterable<Pair<Integer,Iterable<String>>> ret = ff.apply(col).get();
+    Pair<Integer,Iterable<String>> first = Iterables.get(ret,0);
+    Pair<Integer,Iterable<String>> second = Iterables.get(ret,1);
+    assertEquals(Integer.valueOf(2),first.first());
+    assertThat(first.second(),hasItems("Joe","Mark"));
+    assertEquals(Integer.valueOf(1),second.first());
+    assertThat(second.second(),hasItems("Sally"));
+  }
+
+  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());
+    }    
+  }
+    ]]></artwork></figure>
+
+    <figure><preamble>Running this code will result in output like (the value

+    of ret is an iterable containing the following data):</preamble><artwork>
+  2, [Joe, Mark]
+  1, [Sally]
+    </artwork></figure>
+
+    <t>There's quite a bit there... so let's break down exactly what's going on...</t>
+
+    <t>First of all, the Abdera2 MapReduce implementation is integrated tightly 
+    with the Guava Libraries Function interface. Essentially, all of the core 
+    components of the MapReduce operations (e.g. the mapper, the reducer, 
+    combiners, etc) are all implemented as Function objects. </t>
+
+    <figure><preamble>For instance, we define an initial Mapper function with

+    a basic counting reducer using this bit of code:</preamble><artwork><![CDATA[
+  private final static Function<
+    Iterable<Pair<Void, Activity>>, 
+    Iterable<Pair<String, Iterable<Integer>>>> f1 =
+      compose(
+        new MyMapper(),
+        MapRed.<String,ASObject>countingReducer()
+      );
+    ]]></artwork></figure>
+
+    <t>The MyMapper class is straightforward and should be recognizable to 
+    anyone familiar with MapReduce in general...</t>
+    
+    <figure><artwork><![CDATA[
+  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());
+    }    
+  }
+    ]]></artwork></figure>
+
+    <t>If it's not clear what's going on in the mapper, we basically take an 
+    Activity as input, grab the displayName of the Actor object, and collect 
+    using the displayName as key and the actor object as the value.  The 
+    counting reducer, then, goes through and counts the number of unique 
+    values we've collected. This particular implementation doesn't keep track 
+    of different actors who happen to share the same name, but that's not 
+    important for now.</t>
+
+    <t>Note that the mapper and the counting reducer are wrapped inside a 
+    Guava Function object that takes an Iterable of 
+    org.apache.abdera2.common.misc.Pair&lt;Void,Activity&gt; objects and 
+    outputs an Iterable of org.apache.abdera2.common.misc.Pair&lt;String,Iterable&lt;Integer&gt;&gt;

+    objects. The output is a mapping of each actor displayName to the number of 
+    activities in which that name appeared in the input collection.</t>
+
+    <t>That gives us our counts, but doesn't quite give us the output we 
+    want.. so we need to define a bit more...</t>
+
+    <figure><artwork><![CDATA[
+  private final static ReducerFunction<String,Integer,Integer,String> f2 =
+      asFunction(MapRed.<String,Integer>invertReducer(), 
+      Collections.<Integer>reverseOrder()); 
+    ]]></artwork></figure>
+
+    <t>This code creates another function that will take as input the output 
+    of our initial mapper (f1) and perform an inversion mapping (swap the 
+    key and the value), then reverse the order using the natural order of 
+    the keys. Since the keys are integers, the highest numbers will appear 
+    first.</t> 
+
+    <t>So now we have two functions, f1 and f2. We could call these separately, 
+    but since the output of one becomes the output of the second, it's easier 
+    if we just go ahead and compose those into a single function...</t>
+
+    <figure><artwork><![CDATA[
+  private final static Function<
+    Iterable<Pair<Void, Activity>>, 
+    Iterable<Pair<Integer,Iterable<String>>>> f3 = 
+      Functions.compose(f2,f1);
+   ]]></artwork></figure>
+
+    <t>So now we have a function (f3) that takes as input a bunch of Activity 
+    objects and outputs a sorted listing of actor names ordered by number of 
+    occurrences. But we're still not quite done yet... note that the input of 
+    the function is an Iterable of Pair&lt;Void,Activity&gt; objects. That's kind
of 
+    annoying really because what I really want to start off with is an Activity 
+    Stream. So let's create a function that converts an Activity Stream to the 
+    appropriate Iterable...</t>
+
+    <figure><artwork><![CDATA[
+  private static final Function<Collection<Activity>,Iterable<Pair<Void, Activity>>>
transform = 
+    new Function<Collection<Activity>,Iterable<Pair<Void, Activity>>>()
{
+      public Iterable<Pair<Void, Activity>> apply(Collection<Activity>
input) {
+        return 
+          Pair.<Void,Activity>make()
+            .index(MoreFunctions.<Activity>alwaysVoid(), input.getItems());
+      }
+  };
+    ]]></artwork></figure>
+
+    <t>I've marked in bold the important bits.. basically, the Pair object has 
+    a static method called index that takes a collection of items and an 
+    Key-generating Function object (which in this case always returns void) 
+    and generates an Iterable of Pair objects for each of the Activities in 
+    the Stream.</t>
+
+    <t>Once we have our transform function, it's time to do a bit more 
+    composition...</t>
+
+    <figure><artwork><![CDATA[
+  private final static ExecutorService exec = 
+    MoreExecutors2.getExitingExecutor();
+
+  private final static Function<
+    Collection<Activity>, 
+    Future<Iterable<Pair<Integer,Iterable<String>>>>> ff = 
+    Functions.compose(
+    MoreFunctions.<
+      Iterable<Pair<Void, Activity>>, 
+      Iterable<Pair<Integer,Iterable<String>>>>futureFunction(f3,exec),
+    transform);
+    ]]></artwork></figure>
+
+    <t>Note that here, we're creating another Function that takes as input an 
+    Activity Stream Collection object and outputs a java.util.concurrent.Future 
+    whose value, when set, will be our sorted listing of actors. The new 
+    function is composed of two individual functions: our transform created 
+    above, and the combined MapReduce function (f3) that we created previously. 
+    However, first, we wrap f3 within another special Abdera2 construct called 
+    a "futureFunction", which is essentially a Guava Function object that 
+    operates asynchronously using a java.util.concurrent.ExecutorService.</t>
+
+    <t>Once all of this is defined and composed together (note that everything 
+    is stored in static, final, immutable thread-safe constants) and once we've 
+    built our Activity Stream, we can call our analysis operation using a 
+    single simple line of code (shown in bold below):</t>
+
+    <figure><artwork><![CDATA[
+  Collection<Activity> col = 
+   Collection.<Activity>makeCollection()
+       .item(getActivity("Joe",1))
+       .item(getActivity("Joe",2))
+       .item(getActivity("Mark",3))
+       .item(getActivity("Mark",4))
+       .item(getActivity("Sally",5))
+       .get();
+       
+  Iterable<Pair<Integer,Iterable<String>>> ret = ff.apply(col).get();
+    ]]></artwork></figure>
+
+    <t>The call to ff.apply(col) returns our Future object. Calling get() on 
+    that blocks until the asynchronous operation is complete. Obviously this 
+    is just an example; there are a variety of ways we can use that Future 
+    object so that blocking the current thread isn't required (the Future 
+    returned is actually a Guava ListenableFuture).</t>
     
     </section>
     



Mime
View raw message