You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@shindig.apache.org by li...@apache.org on 2010/09/07 10:02:18 UTC

svn commit: r993268 [2/8] - in /shindig/branches/2.0.x: ./ config/ content/container/ content/samplecontainer/ content/sampledata/ extras/src/main/java/org/apache/shindig/extras/ extras/src/main/java/org/apache/shindig/extras/as/ extras/src/main/java/o...

Modified: shindig/branches/2.0.x/extras/src/main/java/org/apache/shindig/extras/as/opensocial/model/ActivityObject.java
URL: http://svn.apache.org/viewvc/shindig/branches/2.0.x/extras/src/main/java/org/apache/shindig/extras/as/opensocial/model/ActivityObject.java?rev=993268&r1=993267&r2=993268&view=diff
==============================================================================
--- shindig/branches/2.0.x/extras/src/main/java/org/apache/shindig/extras/as/opensocial/model/ActivityObject.java (original)
+++ shindig/branches/2.0.x/extras/src/main/java/org/apache/shindig/extras/as/opensocial/model/ActivityObject.java Tue Sep  7 08:02:11 2010
@@ -25,106 +25,245 @@ import org.apache.shindig.extras.as.core
 
 import com.google.inject.ImplementedBy;
 
+/**
+ * A representation of an ActivityStream object, a thing which participates in an Activity.
+ */
 @ImplementedBy(ActivityObjectImpl.class)
 @Exportablebean
 public interface ActivityObject {
-	
-	/*
-	 * Fields that represent JSON elements for an activity entry.
-	 */
-	public static enum Field {
-		ID("id"),
-		NAME("name"),
-		SUMMARY("summary"),
-		MEDIA("media"),
-		PERMALINK("permalink"),
-		TYPE("type"),
-		IN_REPLY_TO("inReplyTo"),
-		ATTACHED("attached"),
-		REPLY("reply"),
-		REACTION("reaction"),
-		ACTION("action"),
-		UPSTREAM_DUPLICATE_ID("upstreamDuplicateId"),
-		DOWNSTREAM_DUPLICATE_ID("downstreamDuplicateId"),
-		STANDARD_LINK("standardLink");
-		
-		/*
-		 * The name of the JSON element.
-		 */
-		private final String jsonString;
-		
-		/*
-		 * Constructs the field base for the JSON element.
-		 * 
-		 * @param jsonString the name of the element
-		 */
-		private Field(String jsonString) {
-			this.jsonString = jsonString;
-		}
-		
-		/*
-		 * Returns the name of the JSON element.
-		 * 
-		 * @return String the name of the JSON element
-		 */
-		public String toString() {
-			return jsonString;
-		}
-	}
-	
-	String getId();
-
-	void setId(String id);
-
-	String getName();
-
-	void setName(String name);
-
-	String getSummary();
-
-	void setSummary(String summary);
-
-	MediaLink getMedia();
-
-	void setMedia(MediaLink media);
-
-	String getPermalink();
-
-	void setPermalink(String permalink);
-
-	List<String> getType();
-
-	void setType(List<String> type);
-
-	ActivityObject getInReplyTo();
-
-	void setInReplyTo(ActivityObject inReplyTo);
-
-	List<ActivityObject> getAttached();
-
-	void setAttached(List<ActivityObject> attached);
-
-	List<ActivityObject> getReply();
-
-	void setReply(List<ActivityObject> reply);
-
-	List<ActivityObject> getReaction();
-
-	void setReaction(List<ActivityObject> reaction);
-
-	ActionLink getAction();
-
-	void setAction(ActionLink action);
-
-	List<String> getUpstreamDuplicateId();
-
-	void setUpstreamDuplicateId(List<String> upstreamDuplicateId);
-
-	List<String> getDownstreamDuplicateId();
-
-	void setDownstreamDuplicateId(List<String> downstreamDuplicateId);
-
-	String getStandardLink();
-
-	void setStandardLink(String standardLink);
-}
\ No newline at end of file
+  
+  /*
+   * Fields that represent JSON elements for an activity entry.
+   */
+  public static enum Field {
+    ID("id"),
+    NAME("name"),
+    SUMMARY("summary"),
+    MEDIA("media"),
+    PERMALINK("permalink"),
+    TYPE("type"),
+    IN_REPLY_TO("inReplyTo"),
+    ATTACHED("attached"),
+    REPLY("reply"),
+    REACTION("reaction"),
+    ACTION("action"),
+    UPSTREAM_DUPLICATE_ID("upstreamDuplicateId"),
+    DOWNSTREAM_DUPLICATE_ID("downstreamDuplicateId"),
+    STANDARD_LINK("standardLink");
+    
+    /*
+     * The name of the JSON element.
+     */
+    private final String jsonString;
+    
+    /**
+     * Constructs the field base for the JSON element.
+     * 
+     * @param jsonString the name of the element
+     */
+    private Field(String jsonString) {
+      this.jsonString = jsonString;
+    }
+    
+    /**
+     * Returns the name of the JSON element.
+     * 
+     * @return String the name of the JSON element
+     */
+    public String toString() {
+      return jsonString;
+    }
+  }
+  
+  /**
+   * Gets the absolute URI that uniquely identifies the object
+   *
+   * @return a non-null string
+   */
+  String getId();
+
+  /**
+   * Set the absolute URI that uniquely identifies the object
+   *
+   * @param id a non-null string
+   */
+  void setId(String id);
+
+  /**
+   * @return the human-readable name fo the object
+   */
+  String getName();
+
+  /**
+   * Sets the name
+   * @param name a human-readable name
+   */
+  void setName(String name);
+
+  /**
+   * Gets the human-readable summary for this object.
+   * @return the summary
+   */
+  String getSummary();
+
+  /**
+   * Sets the human-readable summary for this object.
+   *
+   * @param summary a summary
+   */
+  void setSummary(String summary);
+
+  /**
+   * Get the link to a media item
+   *
+   * @return a {@link org.apache.shindig.extras.as.opensocial.model.MediaLink} object.
+   */
+  MediaLink getMedia();
+
+  /**
+   * Set the link to a media item
+   *
+   * @param media a {@link org.apache.shindig.extras.as.opensocial.model.MediaLink} object.
+   */
+  void setMedia(MediaLink media);
+
+  /**
+   * Get the permanent link
+   *
+   * @return a permalink string, possibly null
+   */
+  String getPermalink();
+
+  /**
+   * Set the permanent link
+   *
+   * @param permalink a permalink string, possibly null
+   */
+  void setPermalink(String permalink);
+
+  /**
+   * Returns a list of Type strings
+   *
+   * @return a list of Type strings
+   */
+  List<String> getType();
+
+  /**
+   * set the list of Type strings
+   *
+   * @param type a list of Type strings
+   */
+  void setType(List<String> type);
+
+  /**
+   * Get the Activity this item is a response to
+   *
+   * @return a {@link org.apache.shindig.extras.as.opensocial.model.ActivityObject} 
+   */
+  ActivityObject getInReplyTo();
+
+  /**
+   * Set the Activity this item is a response to
+   *
+   * @param inReplyTo a {@link org.apache.shindig.extras.as.opensocial.model.ActivityObject} object.
+   */
+  void setInReplyTo(ActivityObject inReplyTo);
+
+  /**
+   * Gets the list of Attached Activities for this entry
+   *
+   * @return a list of ActivityObjects
+   */
+  List<ActivityObject> getAttached();
+
+  /**
+   * Sets the list of Attached Activities for this entry
+   *
+   * @param attached a list of ActivityObjects
+   */
+  void setAttached(List<ActivityObject> attached);
+
+  /**
+   * Gets the list of reply Activities for this entry
+   *
+   * @return a list of ActivityObjects
+   */
+  List<ActivityObject> getReply();
+
+  /**
+   * Sets the list of reply Activities for this entry
+   *
+   * @param reply a list of ActivityObjects
+   */
+  void setReply(List<ActivityObject> reply);
+
+  /**
+   * Gets the list of reaction Activities for this entry
+   *
+   * @return a list of ActivityObjects
+   */
+  List<ActivityObject> getReaction();
+
+  /**
+   * Sets the list of reaction Activities for this entry
+   *
+   * @param reaction a list of ActivityObjects
+   */
+  void setReaction(List<ActivityObject> reaction);
+
+  /**
+   * Returns an ActionLink for this object
+   *
+   * @return a {@link org.apache.shindig.extras.as.opensocial.model.ActionLink} object.
+   */
+  ActionLink getAction();
+
+  /**
+   * Sets the ActionLink for this object
+   *
+   * @param action a {@link org.apache.shindig.extras.as.opensocial.model.ActionLink} object.
+   */
+  void setAction(ActionLink action);
+
+  /**
+   * Get the list of upstream duplicate Ids
+   *
+   * @return a list of strings
+   */
+  List<String> getUpstreamDuplicateId();
+
+  /**
+   * Set the list of upstream duplicate Ids
+   *
+   * @param upstreamDuplicateId a list of strings containing duplicate Ids
+   */
+  void setUpstreamDuplicateId(List<String> upstreamDuplicateId);
+
+  /**
+   * Get the list of downstream duplicate Ids
+   *
+   * @return a list of strings
+   */
+  List<String> getDownstreamDuplicateId();
+
+  /**
+   * Set the list of downstream duplicate Ids
+   *
+   * @param downstreamDuplicateId a list of strings containing duplicate Ids
+   */
+  void setDownstreamDuplicateId(List<String> downstreamDuplicateId);
+
+  /**
+   * Return a standard link string
+   *
+   * @return the standard link
+   */
+  String getStandardLink();
+
+  /**
+   * Set the standard link string
+   *
+   * @param standardLink the standard link
+   */
+  void setStandardLink(String standardLink);
+}

Modified: shindig/branches/2.0.x/extras/src/main/java/org/apache/shindig/extras/as/opensocial/model/ActivityStream.java
URL: http://svn.apache.org/viewvc/shindig/branches/2.0.x/extras/src/main/java/org/apache/shindig/extras/as/opensocial/model/ActivityStream.java?rev=993268&r1=993267&r2=993268&view=diff
==============================================================================
--- shindig/branches/2.0.x/extras/src/main/java/org/apache/shindig/extras/as/opensocial/model/ActivityStream.java (original)
+++ shindig/branches/2.0.x/extras/src/main/java/org/apache/shindig/extras/as/opensocial/model/ActivityStream.java Tue Sep  7 08:02:11 2010
@@ -25,7 +25,7 @@ import org.apache.shindig.protocol.model
 
 import com.google.inject.ImplementedBy;
 
-/*
+/**
  * Interface for an Activity Stream.
  * <p>
  * See the Activity Streams specification for more detail:
@@ -34,58 +34,106 @@ import com.google.inject.ImplementedBy;
 @ImplementedBy(ActivityStreamImpl.class)
 @Exportablebean
 public interface ActivityStream {
-	
-	/*
-	 * Fields that represent JSON elements for an activity entry.
-	 */
-	public static enum Field {
-		DISPLAY_NAME("displayName"),
-		LANGUAGE("language"),
-		ENTRIES("entries"),
-		ID("id"),
-		SUBJECT("subject");
-		
-		/*
-		 * The name of the JSON element.
-		 */
-		private final String jsonString;
-		
-		/*
-		 * Constructs the field base for the JSON element.
-		 * 
-		 * @param jsonString the name of the element
-		 */
-		private Field(String jsonString) {
-			this.jsonString = jsonString;
-		}
-		
-		/*
-		 * Returns the name of the JSON element.
-		 * 
-		 * @return String the name of the JSON element
-		 */
-		public String toString() {
-			return jsonString;
-		}
-	}
-	
-	void setId(String id);
-	
-	String getId();
-	
-	void setEntries(List<ActivityEntry> entries);
-	
-	List<ActivityEntry> getEntries();
-	
-	void setLanguage(String language);
-	
-	String getLanguage();
-	
-	void setSubject(String subject);
-	
-	String getSubject();
-	
-	void setDisplayName(String displayName);
-	
-	String getDisplayName();
-}
\ No newline at end of file
+  
+  /*
+   * Fields that represent JSON elements for an activity entry.
+   */
+  public static enum Field {
+    DISPLAY_NAME("displayName"),
+    LANGUAGE("language"),
+    ENTRIES("entries"),
+    ID("id"),
+    SUBJECT("subject");
+    
+    /*
+     * The name of the JSON element.
+     */
+    private final String jsonString;
+    
+    /*
+     * Constructs the field base for the JSON element.
+     * 
+     * @param jsonString the name of the element
+     */
+    private Field(String jsonString) {
+      this.jsonString = jsonString;
+    }
+    
+    /*
+     * Returns the name of the JSON element.
+     * 
+     * @return String the name of the JSON element
+     */
+    public String toString() {
+      return jsonString;
+    }
+  }
+  
+  /**
+   * Sets the Id for this stream
+   * @param id a string
+   */
+  void setId(String id);
+  
+  /**
+         * Return the id string
+   *
+   * @return a string
+   */
+  String getId();
+  
+  /**
+   * Set the list of ActivityEntry objects
+   * @param entries a list of ActivityEntry
+   */
+  void setEntries(List<ActivityEntry> entries);
+  
+  /**
+   * Get the list of ActivityEntry objects
+   *
+   * @return a list of ActivityEntry
+   */
+  List<ActivityEntry> getEntries();
+  
+  /**
+   * Set the language for this stream
+   *
+   * @param language a language string
+   */
+  void setLanguage(String language);
+  
+  /**
+   * Get the language for this stream
+   *
+   * @return a language string
+   */
+  String getLanguage();
+  
+  /**
+   * Set the subject for this stream
+   *
+   * @param subject a subject string
+   */
+  void setSubject(String subject);
+  
+  /**
+   * Get the subject for this stream
+   *
+   * @return a subject string
+   */
+  String getSubject();
+  
+  /**
+   * Get the display name for this stream
+   *
+   * @param displayName a display name
+   */
+  void setDisplayName(String displayName);
+  
+  /**
+   * Get the human readable name for this stream
+   *
+   * @return a display name
+   */
+  String getDisplayName();
+}

Modified: shindig/branches/2.0.x/extras/src/main/java/org/apache/shindig/extras/as/opensocial/model/MediaLink.java
URL: http://svn.apache.org/viewvc/shindig/branches/2.0.x/extras/src/main/java/org/apache/shindig/extras/as/opensocial/model/MediaLink.java?rev=993268&r1=993267&r2=993268&view=diff
==============================================================================
--- shindig/branches/2.0.x/extras/src/main/java/org/apache/shindig/extras/as/opensocial/model/MediaLink.java (original)
+++ shindig/branches/2.0.x/extras/src/main/java/org/apache/shindig/extras/as/opensocial/model/MediaLink.java Tue Sep  7 08:02:11 2010
@@ -24,61 +24,115 @@ import com.google.inject.ImplementedBy;
 /*
  * TODO: comment this class.
  */
+/**
+ * <p>MediaLink interface.</p>
+ *
+ */
 @ImplementedBy(MediaLinkImpl.class)
 @Exportablebean
 public interface MediaLink {
 
-	/*
-	 * Fields that represent the JSON elements.
-	 */
-	public static enum Field {
-		TARGET("target"),
-		TYPE("type"),
-		WIDTH("width"),
-		HEIGHT("height"),
-		DURATION("duration");
-		
-		/*
-		 * The name of the JSON element.
-		 */
-		private final String jsonString;
-		
-		/*
-		 * Constructs the field base for the JSON element.
-		 * 
-		 * @param jsonString the name of the element
-		 */
-		private Field(String jsonString) {
-			this.jsonString = jsonString;
-		}
-		
-		/*
-		 * Returns the name of the JSON element.
-		 * 
-		 * @return String the name of the JSON element
-		 */
-		public String toString() {
-			return jsonString;
-		}
-	}
-	
-	String getTarget();
-
-	void setTarget(String target);
-
-	String getType();
-
-	void setType(String type);
-
-	String getWidth();
-
-	void setWidth(String width);
-
-	String getHeight();
-
-	void setHeight(String height);
-
-	String getDuration();
-
-	void setDuration(String duration);
+  /**
+   * Fields that represent the JSON elements.
+   */
+  public static enum Field {
+    TARGET("target"),
+    TYPE("type"),
+    WIDTH("width"),
+    HEIGHT("height"),
+    DURATION("duration");
+    
+    /**
+     * The name of the JSON element.
+     */
+    private final String jsonString;
+    
+    /**
+     * Constructs the field base for the JSON element.
+     * 
+     * @param jsonString the name of the element
+     */
+    private Field(String jsonString) {
+      this.jsonString = jsonString;
+    }
+    
+    /**
+     * Returns the name of the JSON element.
+     * 
+     * @return String the name of the JSON element
+     */
+    public String toString() {
+      return jsonString;
+    }
+  }
+  
+  /**
+   * Returns the target of this MediaLink
+   *
+   * @return a target
+   */
+  String getTarget();
+
+  /**
+   * Sets the target for this MediaLink
+   *
+   * @param target a target linke
+   */
+  void setTarget(String target);
+
+  /**
+   * Returns the type of the MediaLink
+   *
+   * @return a type
+   */
+  String getType();
+
+  /**
+   * Sets the type of the MediaLink
+   *
+   * @param type a type
+   */
+  void setType(String type);
+
+  /**
+   * <p>getWidth</p>
+   *
+   * @return a {@link java.lang.String} object.
+   */
+  String getWidth();
+
+  /**
+   * Sets the Width of this mediaLink
+   *
+   * @param width a width
+   */
+  void setWidth(String width);
+
+  /**
+   * Sets the Height of this mediaLink
+   *
+   * @return a height
+   */
+  String getHeight();
+
+  /**
+   * Sets the Height of this mediaLink
+   *
+   * @param height a height
+   */
+  void setHeight(String height);
+
+  /**
+   * Returns the duration of this mediaLink
+   *
+   * @return a duration
+   */
+  String getDuration();
+
+  /**
+   * Sets the duration of this mediaLink
+   *
+   * @param duration a duration
+   */
+  void setDuration(String duration);
 }

Modified: shindig/branches/2.0.x/extras/src/main/java/org/apache/shindig/extras/as/opensocial/service/ActivityStreamsHandler.java
URL: http://svn.apache.org/viewvc/shindig/branches/2.0.x/extras/src/main/java/org/apache/shindig/extras/as/opensocial/service/ActivityStreamsHandler.java?rev=993268&r1=993267&r2=993268&view=diff
==============================================================================
--- shindig/branches/2.0.x/extras/src/main/java/org/apache/shindig/extras/as/opensocial/service/ActivityStreamsHandler.java (original)
+++ shindig/branches/2.0.x/extras/src/main/java/org/apache/shindig/extras/as/opensocial/service/ActivityStreamsHandler.java Tue Sep  7 08:02:11 2010
@@ -38,12 +38,22 @@ import com.google.common.collect.Immutab
 import com.google.common.collect.Iterables;
 import com.google.inject.Inject;
 
+/**
+ * <p>ActivityStreamsHandler class.</p>
+ *
+ */
 @Service(name = "activitystreams", path="/{userId}+/{groupId}/{appId}/{activitystream}/{activityEntryId}+")
 public class ActivityStreamsHandler {
 
   private final ActivityStreamService service;
   private final ContainerConfig config;
 
+  /**
+   * <p>Constructor for ActivityStreamsHandler.</p>
+   *
+   * @param service a {@link org.apache.shindig.extras.as.opensocial.spi.ActivityStreamService} object.
+   * @param config a {@link org.apache.shindig.config.ContainerConfig} object.
+   */
   @Inject
   public ActivityStreamsHandler(ActivityStreamService service, ContainerConfig config) {
     this.service = service;
@@ -54,6 +64,10 @@ public class ActivityStreamsHandler {
    * Allowed end-points /activities/{userId}/@self/{actvityId}+
    *
    * examples: /activities/john.doe/@self/1
+   *
+   * @param request a {@link org.apache.shindig.social.opensocial.service.SocialRequestItem} object.
+   * @return a {@link java.util.concurrent.Future} object.
+   * @throws org.apache.shindig.protocol.ProtocolException if any.
    */
   @Operation(httpMethods="DELETE")
   public Future<?> delete(SocialRequestItem request)
@@ -73,8 +87,12 @@ public class ActivityStreamsHandler {
    * Allowed end-points /activities/{userId}/@self
    *
    * examples: /activities/john.doe/@self - postBody is an activity object
-   * 
+   *
    * TODO: REST end-point
+   *
+   * @param request a {@link org.apache.shindig.social.opensocial.service.SocialRequestItem} object.
+   * @return a {@link java.util.concurrent.Future} object.
+   * @throws org.apache.shindig.protocol.ProtocolException if any.
    */
   @Operation(httpMethods="PUT", bodyParam = "activityEntry")
   public Future<?> update(SocialRequestItem request) throws ProtocolException {
@@ -85,8 +103,12 @@ public class ActivityStreamsHandler {
    * Allowed end-points /activities/{userId}/@self
    *
    * examples: /activities/john.doe/@self - postBody is an activity object
-   * 
+   *
    * TODO: REST end-point
+   *
+   * @param request a {@link org.apache.shindig.social.opensocial.service.SocialRequestItem} object.
+   * @return a {@link java.util.concurrent.Future} object.
+   * @throws org.apache.shindig.protocol.ProtocolException if any.
    */
   @Operation(httpMethods="POST", bodyParam = "activityEntry")
   public Future<?> create(SocialRequestItem request) throws ProtocolException {
@@ -110,6 +132,10 @@ public class ActivityStreamsHandler {
    *
    * examples: /activities/john.doe/@self/1 /activities/john.doe/@self
    * /activities/john.doe,jane.doe/@friends
+   *
+   * @param request a {@link org.apache.shindig.social.opensocial.service.SocialRequestItem} object.
+   * @return a {@link java.util.concurrent.Future} object.
+   * @throws org.apache.shindig.protocol.ProtocolException if any.
    */
   @Operation(httpMethods="GET")
   public Future<?> get(SocialRequestItem request)
@@ -143,6 +169,12 @@ public class ActivityStreamsHandler {
         request.getFields(), options, request.getToken());
   }
 
+  /**
+   * Return a list of supported fields for the ActivityStreams endpoint
+   *
+   * @param request a {@link org.apache.shindig.protocol.RequestItem} object.
+   * @return a List of supported fields
+   */
   @Operation(httpMethods = "GET", path="/@supportedFields")
   public List<Object> supportedFields(RequestItem request) {
     // TODO: Would be nice if name in config matched name of service.

Modified: shindig/branches/2.0.x/extras/src/main/java/org/apache/shindig/extras/as/opensocial/spi/ActivityStreamService.java
URL: http://svn.apache.org/viewvc/shindig/branches/2.0.x/extras/src/main/java/org/apache/shindig/extras/as/opensocial/spi/ActivityStreamService.java?rev=993268&r1=993267&r2=993268&view=diff
==============================================================================
--- shindig/branches/2.0.x/extras/src/main/java/org/apache/shindig/extras/as/opensocial/spi/ActivityStreamService.java (original)
+++ shindig/branches/2.0.x/extras/src/main/java/org/apache/shindig/extras/as/opensocial/spi/ActivityStreamService.java Tue Sep  7 08:02:11 2010
@@ -44,6 +44,7 @@ public interface ActivityStreamService {
    * @param options The sorting/filtering/pagination options
    * @param token   A valid SecurityToken
    * @return a response item with the list of activities.
+   * @throws org.apache.shindig.protocol.ProtocolException if any.
    */
   Future<RestfulCollection<ActivityEntry>> getActivityEntries(Set<UserId> userIds,
       GroupId groupId, String appId, Set<String> fields, CollectionOptions options, SecurityToken token)
@@ -57,10 +58,11 @@ public interface ActivityStreamService {
    * @param groupId     Indicates whether to fetch activities for a group.
    * @param appId       The app id.
    * @param fields      The fields to return. Empty set implies all
-   * @param options The sorting/filtering/pagination options
+   * @param options     The sorting/filtering/pagination options
    * @param activityIds The set of activity ids to fetch.
    * @param token       A valid SecurityToken
    * @return a response item with the list of activities.
+   * @throws org.apache.shindig.protocol.ProtocolException if any.
    */
   Future<RestfulCollection<ActivityEntry>> getActivityEntries(UserId userId, GroupId groupId,
       String appId, Set<String> fields, CollectionOptions options, Set<String> activityIds, SecurityToken token)
@@ -78,6 +80,7 @@ public interface ActivityStreamService {
    * @param activityId The activity id to fetch.
    * @param token      A valid SecurityToken
    * @return a response item with the list of activities.
+   * @throws org.apache.shindig.protocol.ProtocolException if any.
    */
   Future<ActivityEntry> getActivityEntry(UserId userId, GroupId groupId, String appId,
       Set<String> fields, String activityId, SecurityToken token)
@@ -92,6 +95,7 @@ public interface ActivityStreamService {
    * @param activityIds A list of activity ids to delete.
    * @param token       A valid SecurityToken.
    * @return a response item containing any errors
+   * @throws org.apache.shindig.protocol.ProtocolException if any.
    */
   Future<Void> deleteActivityEntries(UserId userId, GroupId groupId, String appId,
       Set<String> activityIds, SecurityToken token) throws ProtocolException;
@@ -107,6 +111,7 @@ public interface ActivityStreamService {
    * @param activity The activity to create.
    * @param token    A valid SecurityToken
    * @return a response item containing any errors
+   * @throws org.apache.shindig.protocol.ProtocolException if any.
    */
   Future<Void> createActivityEntry(UserId userId, GroupId groupId, String appId,
       Set<String> fields, ActivityEntry activity, SecurityToken token) throws ProtocolException;

Modified: shindig/branches/2.0.x/extras/src/main/java/org/apache/shindig/extras/as/sample/ActivityStreamsJsonDbService.java
URL: http://svn.apache.org/viewvc/shindig/branches/2.0.x/extras/src/main/java/org/apache/shindig/extras/as/sample/ActivityStreamsJsonDbService.java?rev=993268&r1=993267&r2=993268&view=diff
==============================================================================
--- shindig/branches/2.0.x/extras/src/main/java/org/apache/shindig/extras/as/sample/ActivityStreamsJsonDbService.java (original)
+++ shindig/branches/2.0.x/extras/src/main/java/org/apache/shindig/extras/as/sample/ActivityStreamsJsonDbService.java Tue Sep  7 08:02:11 2010
@@ -41,11 +41,22 @@ import java.util.List;
 import java.util.Set;
 import java.util.concurrent.Future;
 
+/**
+ * Sample Implementation of the ActivityStreams Service using a JSON 
+ * database.
+ */
 public class ActivityStreamsJsonDbService implements ActivityStreamService {
   JsonDbOpensocialService jsonDb;
   JSONObject db;
   BeanConverter converter;
 
+  /**
+   * Create a new ActivityStreamsJsonDbService instance via Guice injection
+   *
+   * @param jsonDb a {@link org.apache.shindig.social.sample.spi.JsonDbOpensocialService} object.
+   * @param converter a {@link org.apache.shindig.protocol.conversion.BeanConverter} object
+   *     annotated with "shindig.bean.converter.json".
+   */
   @Inject
   public ActivityStreamsJsonDbService(JsonDbOpensocialService jsonDb,
                                       @Named("shindig.bean.converter.json")
@@ -63,69 +74,70 @@ public class ActivityStreamsJsonDbServic
 
 
   // Are fields really needed here?
+  /** {@inheritDoc} */
   public Future<Void> createActivityEntry(UserId userId, GroupId groupId, String appId,
-	      Set<String> fields, ActivityEntry activityEntry, SecurityToken token) throws ProtocolException {
-	try {
-	  JSONObject jsonEntry = convertFromActivityEntry(activityEntry, fields);
-	  JSONObject jsonEntryObject = jsonEntry.getJSONObject(ActivityEntry.Field.OBJECT.toString());
-	  if (!jsonEntryObject.has(ActivityObject.Field.ID.toString())) {
-		  jsonEntryObject.put(ActivityObject.Field.ID.toString(), System.currentTimeMillis());
-		  jsonEntry.put(ActivityEntry.Field.OBJECT.toString(), jsonEntryObject);
-	  }
-
-	  // TODO: bug fixed: jsonArray will not be null; will throw exception!
-	  // Fix in createActivity()
-	  JSONArray jsonArray;
-	  if(db.getJSONObject(ACTIVITYSTREAMS_TABLE).has(userId.getUserId(token))) {
-		  jsonArray = db.getJSONObject(ACTIVITYSTREAMS_TABLE)
-	      				.getJSONArray(userId.getUserId(token));
-	  } else {
-		  jsonArray = new JSONArray();
-		  db.getJSONObject(ACTIVITYSTREAMS_TABLE).put(userId.getUserId(token), jsonArray);
-	  }
-	  jsonArray.put(jsonEntry);
-	  return ImmediateFuture.newInstance(null);
-	} catch (JSONException je) {
-	  throw new ProtocolException(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, je.getMessage(),
-	      je);
-	}
+        Set<String> fields, ActivityEntry activityEntry, SecurityToken token) throws ProtocolException {
+    try {
+      JSONObject jsonEntry = convertFromActivityEntry(activityEntry, fields);
+      JSONObject jsonEntryObject = jsonEntry.getJSONObject(ActivityEntry.Field.OBJECT.toString());
+      if (!jsonEntryObject.has(ActivityObject.Field.ID.toString())) {
+        jsonEntryObject.put(ActivityObject.Field.ID.toString(), System.currentTimeMillis());
+        jsonEntry.put(ActivityEntry.Field.OBJECT.toString(), jsonEntryObject);
+      }
+
+      // TODO: bug fixed: jsonArray will not be null; will throw exception!
+      // Fix in createActivity()
+      JSONArray jsonArray;
+      if (db.getJSONObject(ACTIVITYSTREAMS_TABLE).has(userId.getUserId(token))) {
+        jsonArray = db.getJSONObject(ACTIVITYSTREAMS_TABLE).getJSONArray(userId.getUserId(token));
+      } else {
+        jsonArray = new JSONArray();
+        db.getJSONObject(ACTIVITYSTREAMS_TABLE).put(userId.getUserId(token), jsonArray);
+      }
+      jsonArray.put(jsonEntry);
+      return ImmediateFuture.newInstance(null);
+    } catch (JSONException je) {
+      throw new ProtocolException(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, je.getMessage(), je);
+    }
   }
 
+  /** {@inheritDoc} */
   public Future<Void> deleteActivityEntries(UserId userId, GroupId groupId,
-		  String appId, Set<String> activityIds, SecurityToken token)
-		  throws ProtocolException {
-	try {
-	  String user = userId.getUserId(token);
-	  if (db.getJSONObject(ACTIVITYSTREAMS_TABLE).has(user)) {
-	    JSONArray activityEntries = db.getJSONObject(ACTIVITYSTREAMS_TABLE).getJSONArray(user);
-	    if (activityEntries != null) {
-	      JSONArray newList = new JSONArray();
-	      for (int i = 0; i < activityEntries.length(); i++) {
-	        JSONObject activityEntry = activityEntries.getJSONObject(i);
-	        if (!activityIds.contains(activityEntry.getJSONObject(ActivityEntry.Field.OBJECT.toString()).getString(ActivityObject.Field.ID.toString()))) {
-	          newList.put(activityEntry);
-	        }
-	      }
-	      db.getJSONObject(ACTIVITYSTREAMS_TABLE).put(user, newList);
-	      // TODO: This seems very odd that we return no useful response in this
-	      // case
-	      // There is no way to represent not-found
-	      // if (found) { ??
-	      // }
+      String appId, Set<String> activityIds, SecurityToken token) throws ProtocolException {
+    try {
+      String user = userId.getUserId(token);
+
+      if (db.getJSONObject(ACTIVITYSTREAMS_TABLE).has(user)) {
+        JSONArray activityEntries = db.getJSONObject(ACTIVITYSTREAMS_TABLE).getJSONArray(user);
+
+        if (activityEntries != null) {
+          JSONArray newList = new JSONArray();
+          for (int i = 0; i < activityEntries.length(); i++) {
+            JSONObject activityEntry = activityEntries.getJSONObject(i);
+            if (!activityIds.contains(activityEntry.getJSONObject(ActivityEntry.Field.OBJECT.toString()).getString(ActivityObject.Field.ID.toString()))) {
+              newList.put(activityEntry);
+            }
+          }
+          db.getJSONObject(ACTIVITYSTREAMS_TABLE).put(user, newList);
+          // TODO: This seems very odd that we return no useful response in this
+          // case
+          // There is no way to represent not-found
+          // if (found) { ??
+          // }
         }
-	  }
-	  // What is the appropriate response here??
-	  return ImmediateFuture.newInstance(null);
-      } catch (JSONException je) {
-	      throw new ProtocolException(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, je.getMessage(),
-	          je);
-	  }
+      }
+      // What is the appropriate response here??
+      return ImmediateFuture.newInstance(null);
+    } catch (JSONException je) {
+      throw new ProtocolException(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, je.getMessage(), je);
+    }
   }
 
+  /** {@inheritDoc} */
   public Future<ActivityEntry> getActivityEntry(UserId userId, GroupId groupId,
-		  String appId, Set<String> fields, String activityId, SecurityToken token)
-		  throws ProtocolException {
-    try {	   	
+      String appId, Set<String> fields, String activityId, SecurityToken token)
+      throws ProtocolException {
+    try {       
       String user = userId.getUserId(token);
       if (db.getJSONObject(ACTIVITYSTREAMS_TABLE).has(user)) {
         JSONArray activityEntries = db.getJSONObject(ACTIVITYSTREAMS_TABLE).getJSONArray(user);
@@ -136,93 +148,70 @@ public class ActivityStreamsJsonDbServic
           if (actorId.equals(user)
               && activityEntry.getJSONObject(ActivityEntry.Field.OBJECT.toString()).get(ActivityObject.Field.ID.toString()).toString().equals(activityId)) {
             return ImmediateFuture.newInstance(jsonDb.filterFields(activityEntry, fields, ActivityEntry.class));
-         }
+          }
         }
       }
 
       throw new ProtocolException(HttpServletResponse.SC_BAD_REQUEST, "ActivityEntry not found");
     } catch (JSONException je) {
-      throw new ProtocolException(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, je.getMessage(),
-          je);
+      throw new ProtocolException(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, je.getMessage(), je);
     }
   }
-	
+  
+  /** {@inheritDoc} */
   public Future<RestfulCollection<ActivityEntry>> getActivityEntries(
-		  Set<UserId> userIds, GroupId groupId, String appId, Set<String> fields,
-		  CollectionOptions options, SecurityToken token)
-		  throws ProtocolException {
+      Set<UserId> userIds, GroupId groupId, String appId, Set<String> fields,
+      CollectionOptions options, SecurityToken token)
+      throws ProtocolException {
       List<ActivityEntry> result = Lists.newArrayList();
       
-//    	// Retrieve activities from Lotus Connections
-//		FeedParser parser;
-//		try {
-//			parser = new FeedParser();
-//		    ArrayList<JSONObject> activityEntries = parser.parseFeed("http://w3.ibm.com/connections/news/atom/stories/public");
-//		    for(JSONObject activityEntry : activityEntries) {
-//		    	result.add(jsonDb.filterFields(activityEntry, fields, ActivityEntry.class));
-//		    }
-//		} catch (ParserConfigurationException e) {
-//			e.printStackTrace();
-//		} catch (SAXException e) {
-//			e.printStackTrace();
-//		} catch (JSONException e) {
-//			e.printStackTrace();
-//		}
-		
-      try {
-        Set<String> idSet = jsonDb.getIdSet(userIds, groupId, token);
-        for (String id : idSet) {
-          if (db.getJSONObject(ACTIVITYSTREAMS_TABLE).has(id)) {
-            JSONArray activityEntries = db.getJSONObject(ACTIVITYSTREAMS_TABLE).getJSONArray(id);
-            for (int i = 0; i < activityEntries.length(); i++) {
-              JSONObject activityEntry = activityEntries.getJSONObject(i);
-              result.add(jsonDb.filterFields(activityEntry, fields, ActivityEntry.class));
-              // TODO: ActivityStreams don't have appIds
-//	              if (appId == null || !activitystream.has(ActivityStream.Field.APP_ID.toString())) {
-//	                result.add(jsonDb.filterFields(activitystream, fields, ActivityStream.class));
-//	              } else if (activitystream.get(ActivityStream.Field.APP_ID.toString()).equals(appId)) {
-//	                result.add(jsonDb.filterFields(activitystream, fields, ActivityStream.class));
-//	              }
-            }
+    try {
+      Set<String> idSet = jsonDb.getIdSet(userIds, groupId, token);
+      for (String id : idSet) {
+        if (db.getJSONObject(ACTIVITYSTREAMS_TABLE).has(id)) {
+          JSONArray activityEntries = db.getJSONObject(ACTIVITYSTREAMS_TABLE).getJSONArray(id);
+          for (int i = 0; i < activityEntries.length(); i++) {
+            JSONObject activityEntry = activityEntries.getJSONObject(i);
+            result.add(jsonDb.filterFields(activityEntry, fields, ActivityEntry.class));
+            // TODO: ActivityStreams don't have appIds
           }
         }
-        return ImmediateFuture.newInstance(new RestfulCollection<ActivityEntry>(result));
+      }
+      return ImmediateFuture.newInstance(new RestfulCollection<ActivityEntry>(result));
     } catch (JSONException je) {
-      throw new ProtocolException(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, je.getMessage(),
-          je);
+      throw new ProtocolException(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, je.getMessage(), je);
     }
   }
-	
+  
+  /** {@inheritDoc} */
   public Future<RestfulCollection<ActivityEntry>> getActivityEntries(
-		  UserId userId, GroupId groupId, String appId, Set<String> fields,
-		  CollectionOptions options, Set<String> activityIds, SecurityToken token)
-		  throws ProtocolException {
-	  List<ActivityEntry> result = Lists.newArrayList();
-      try {
-        String user = userId.getUserId(token);
-        if (db.getJSONObject(ACTIVITYSTREAMS_TABLE).has(user)) {
-          JSONArray activityEntries = db.getJSONObject(ACTIVITYSTREAMS_TABLE).getJSONArray(user);
-          for (int i = 0; i < activityEntries.length(); i++) {
-            JSONObject activityEntry = activityEntries.getJSONObject(i);
-            JSONObject actor = new JSONObject(activityEntry.get(ActivityEntry.Field.ACTOR.toString()));
-            String actorId = actor.get(ActivityObject.Field.ID.toString()).toString();
-            if (actorId.equals(user)
-              && activityIds.contains(activityEntry.getJSONObject(ActivityEntry.Field.OBJECT.toString()).getString(ActivityObject.Field.ID.toString()).toString())) {
+      UserId userId, GroupId groupId, String appId, Set<String> fields,
+      CollectionOptions options, Set<String> activityIds, SecurityToken token)
+      throws ProtocolException {
+    List<ActivityEntry> result = Lists.newArrayList();
+    try {
+      String user = userId.getUserId(token);
+      if (db.getJSONObject(ACTIVITYSTREAMS_TABLE).has(user)) {
+        JSONArray activityEntries = db.getJSONObject(ACTIVITYSTREAMS_TABLE).getJSONArray(user);
+        for (int i = 0; i < activityEntries.length(); i++) {
+          JSONObject activityEntry = activityEntries.getJSONObject(i);
+          JSONObject actor = new JSONObject(activityEntry.get(ActivityEntry.Field.ACTOR.toString()));
+          String actorId = actor.get(ActivityObject.Field.ID.toString()).toString();
+          if (actorId.equals(user)
+            && activityIds.contains(activityEntry.getJSONObject(ActivityEntry.Field.OBJECT.toString()).getString(ActivityObject.Field.ID.toString()).toString())) {
             result.add(jsonDb.filterFields(activityEntry, fields, ActivityEntry.class));
           }
         }
       }
       return ImmediateFuture.newInstance(new RestfulCollection<ActivityEntry>(result));
     } catch (JSONException je) {
-      throw new ProtocolException(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, je.getMessage(),
-          je);
+      throw new ProtocolException(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, je.getMessage(), je);
     }
   }
 
   private JSONObject convertFromActivityEntry(ActivityEntry activityEntry, Set<String> fields)
-  throws JSONException {
-	// TODO Not using fields yet
-	return new JSONObject(converter.convertToString(activityEntry));
+    throws JSONException {
+    // TODO Not using fields yet
+    return new JSONObject(converter.convertToString(activityEntry));
   }
-
 }

Modified: shindig/branches/2.0.x/extras/src/main/javascript/features-extras/org.openajax.hub-2.0.4/OpenAjax-mashup.js
URL: http://svn.apache.org/viewvc/shindig/branches/2.0.x/extras/src/main/javascript/features-extras/org.openajax.hub-2.0.4/OpenAjax-mashup.js?rev=993268&r1=993267&r2=993268&view=diff
==============================================================================
--- shindig/branches/2.0.x/extras/src/main/javascript/features-extras/org.openajax.hub-2.0.4/OpenAjax-mashup.js (original)
+++ shindig/branches/2.0.x/extras/src/main/javascript/features-extras/org.openajax.hub-2.0.4/OpenAjax-mashup.js Tue Sep  7 08:02:11 2010
@@ -28,7 +28,7 @@ OpenAjax.hub = function() {
 
     return /** @scope OpenAjax.hub */ {
         implementer: "http://openajax.org",
-        implVersion: "2.0.3",
+        implVersion: "2.0.4",
         specVersion: "2.0",
         implExtraData: {},
         libraries: libs,

Modified: shindig/branches/2.0.x/extras/src/main/javascript/features-extras/org.openajax.hub-2.0.4/feature.xml
URL: http://svn.apache.org/viewvc/shindig/branches/2.0.x/extras/src/main/javascript/features-extras/org.openajax.hub-2.0.4/feature.xml?rev=993268&r1=993267&r2=993268&view=diff
==============================================================================
--- shindig/branches/2.0.x/extras/src/main/javascript/features-extras/org.openajax.hub-2.0.4/feature.xml (original)
+++ shindig/branches/2.0.x/extras/src/main/javascript/features-extras/org.openajax.hub-2.0.4/feature.xml Tue Sep  7 08:02:11 2010
@@ -17,7 +17,7 @@ KIND, either express or implied. See the
 specific language governing permissions and limitations under the License.
 -->
 <feature>
-  <name>org.openajax.hub-2.0.3</name>
+  <name>org.openajax.hub-2.0.4</name>
   <dependency>rpc</dependency>
   <gadget>
     <script src="OpenAjax-mashup.js"/>

Modified: shindig/branches/2.0.x/extras/src/main/javascript/features-extras/org.openajax.hub-2.0.4/iframe.js
URL: http://svn.apache.org/viewvc/shindig/branches/2.0.x/extras/src/main/javascript/features-extras/org.openajax.hub-2.0.4/iframe.js?rev=993268&r1=993267&r2=993268&view=diff
==============================================================================
--- shindig/branches/2.0.x/extras/src/main/javascript/features-extras/org.openajax.hub-2.0.4/iframe.js (original)
+++ shindig/branches/2.0.x/extras/src/main/javascript/features-extras/org.openajax.hub-2.0.4/iframe.js Tue Sep  7 08:02:11 2010
@@ -26,10 +26,10 @@ OpenAjax.gadgets.rpctx = OpenAjax.gadget
     // For now, we only use "oaaConfig" for the global "gadgets" object.  If the "gadgets" global
     // already exists, then there is no reason to check for "oaaConfig".  In the future, if we use
     // "oaaConfig" for other purposes, we'll need to remove the check for "!window.gadgets".
-    if (!window.gadgets) {
+    if (typeof gadgets === 'undefined') {
         // "oaaConfig" can be specified as a global object.  If not found, then look for it as an
         // attribute on the script line for the OpenAjax Hub JS file.
-        if (!window.oaaConfig) {
+        if (typeof oaaConfig === 'undefined') {
             var scripts = document.getElementsByTagName("script");
             // match "OpenAjax-mashup.js", "OpenAjaxManagedHub-all*.js", "OpenAjaxManagedHub-core*.js"
             var reHub = /openajax(?:managedhub-(?:all|core).*|-mashup)\.js$/i;
@@ -44,7 +44,7 @@ OpenAjax.gadgets.rpctx = OpenAjax.gadget
                     var config = scripts[i].getAttribute( "oaaConfig" );
                     if ( config ) {
                         try {
-                            window.oaaConfig = eval( "({ " + config + " })" );
+                            oaaConfig = eval( "({ " + config + " })" );
                         } catch (e) {}
                     }
                     break;
@@ -52,8 +52,8 @@ OpenAjax.gadgets.rpctx = OpenAjax.gadget
             }
         }
         
-        if (window.oaaConfig && window.oaaConfig.gadgetsGlobal) {
-            window.gadgets = OpenAjax.gadgets;
+        if (typeof oaaConfig !== 'undefined' && oaaConfig.gadgetsGlobal) {
+            gadgets = OpenAjax.gadgets;
         }
     }
 })();
@@ -529,13 +529,16 @@ OpenAjax.hub.IframeHubClient = function(
         }
         
         OpenAjax.hub.IframeContainer._rpcRouter.add( "..", this );
-//        securityToken = generateSecurityToken( params, scope, log );    // XXX still necessary?
+// XXX The RPC layer initializes immediately on load, in the child (IframeHubClient). So it is too
+//    late here to specify a security token for the RPC layer.  At the moment, only the NIX
+//    transport requires a child token (IFPC [aka FIM] is not supported).
+//        securityToken = generateSecurityToken( params, scope, log );
 
         var internalID = OpenAjax.gadgets.rpc.RPC_ID;
         if ( ! internalID ) {
             throw new Error( OpenAjax.hub.Error.WrongProtocol );
         }
-        clientID = decodeURIComponent( internalID.substr( internalID.indexOf("_") + 1 ) );
+        clientID = internalID.substr( internalID.indexOf("_") + 1 );
     };
     
   /*** HubClient interface ***/
@@ -802,7 +805,6 @@ OpenAjax.hub.IframeContainer._rpcRouter 
                     return;
                 }
                 
-                id = encodeURIComponent( id );
                 do {
                     // a client with the specified ID already exists on this page;
                     // create a unique ID
@@ -818,9 +820,9 @@ OpenAjax.hub.IframeContainer._rpcRouter 
                 securityCallback: onSecurityAlert
             });
 
-            rpcErrorsToOAA[ OpenAjax.gadgets.rpc.LOAD_TIMEOUT ] = OpenAjax.hub.SecurityAlert.LoadTimeout;
-            rpcErrorsToOAA[ OpenAjax.gadgets.rpc.FRAME_PHISH ] = OpenAjax.hub.SecurityAlert.FramePhish;
-            rpcErrorsToOAA[ OpenAjax.gadgets.rpc.FORGED_MSG ] = OpenAjax.hub.SecurityAlert.ForgedMsg;
+            rpcErrorsToOAA[ OpenAjax.gadgets.rpc.SEC_ERROR_LOAD_TIMEOUT ] = OpenAjax.hub.SecurityAlert.LoadTimeout;
+            rpcErrorsToOAA[ OpenAjax.gadgets.rpc.SEC_ERROR_FRAME_PHISH ] = OpenAjax.hub.SecurityAlert.FramePhish;
+            rpcErrorsToOAA[ OpenAjax.gadgets.rpc.SEC_ERROR_FORGED_MSG ] = OpenAjax.hub.SecurityAlert.ForgedMsg;
             
             this.add = _add;
             return _add( id, receiver );
@@ -836,7 +838,7 @@ var rpcErrorsToOAA = {};
 
 ////////////////////////////////////////////////////////////////////////////////
 
-function generateSecurityToken( params, scope, log, overrideTokenLength ) {
+function generateSecurityToken( params, scope, log ) {
     if ( ! OpenAjax.hub.IframeContainer._prng ) {
         // create pseudo-random number generator with a default seed
         var seed = new Date().getTime() + Math.random() + document.cookie;
@@ -854,7 +856,7 @@ function generateSecurityToken( params, 
         }
     }
     
-    var tokenLength = overrideTokenLength || (p && p.tokenLength) || 6;
+    var tokenLength = (p && p.tokenLength) || 6;
     return OpenAjax.hub.IframeContainer._prng.nextRandomB64Str( tokenLength );
 }
 

Modified: shindig/branches/2.0.x/extras/src/main/javascript/features-extras/pubsub-2/pubsub-2.js
URL: http://svn.apache.org/viewvc/shindig/branches/2.0.x/extras/src/main/javascript/features-extras/pubsub-2/pubsub-2.js?rev=993268&r1=993267&r2=993268&view=diff
==============================================================================
--- shindig/branches/2.0.x/extras/src/main/javascript/features-extras/pubsub-2/pubsub-2.js (original)
+++ shindig/branches/2.0.x/extras/src/main/javascript/features-extras/pubsub-2/pubsub-2.js Tue Sep  7 08:02:11 2010
@@ -21,19 +21,19 @@
  * 
  * Uses OpenAjax Hub in order to do pubsub.  Simple case is to do the following:
  *    
- *    var gadget = gadgets.byId(__MODULE_ID__);
- *    gadget.PubSub.subscribe(topic, callback);
- *    ...
- *    gadget.PubSub.publish(topic2, message);
+ *    gadgets.util.registerOnLoadHandler(function() {
+ *      gadgets.Hub.subscribe(topic, callback);
+ *      // OR
+ *      gadgets.Hub.publish(topic2, message);
+ *    });
  * 
- * The <gadget instance>.PubSub object implements the OpenAjax.hub.HubClient
- * interface.
+ * The gadgets.Hub object implements the OpenAjax.hub.HubClient interface.
  * 
  * By default, a HubClient is instantiated automatically by the pubsub-2 code.
  * If the gadget wants to provide params to the HubClient constructor, it can
- * do so by setting values on <gadget instance>.PubSubSettings object:
+ * do so by setting values on gadgets.HubSettings object:
  * 
- *     <gadget instance>.PubSubSettings = {
+ *     gadgets.HubSettings = {
  *         // Parameters object for HubClient constructor.
  *         // @see http://openajax.org/member/wiki/OpenAjax_Hub_2.0_Specification_Managed_Hub_APIs#OpenAjax.hub.HubClient_constructor
  *         // @see http://openajax.org/member/wiki/OpenAjax_Hub_2.0_Specification_Managed_Hub_APIs#OpenAjax.hub.IframeHubClient_constructor
@@ -46,19 +46,15 @@
  * 
  * For example, to set a security alert callback:
  * 
- *     <gadget instance>.PubSubSettings.params.HubClient.onSecurityCallback =
+ *     gadgets.HubSettings.params.HubClient.onSecurityCallback =
  *             function(alertSource, alertType) { ... };
  * 
  * @see http://openajax.org/member/wiki/OpenAjax_Hub_2.0_Specification_Managed_Hub_APIs#OpenAjax.hub.HubClient
  */
 
 (function() {
-    var params = gadgets.util.getUrlParameters();
-    var moduleId = params.mid || 0;
-    var gadgetInstance = gadgets.byId(moduleId);
-    
     // Create a pubsub settings object
-    gadgetInstance.PubSubSettings = {
+    gadgets.HubSettings = {
         // Set default HubClient constructor params object
         params: {
             HubClient: {
@@ -66,27 +62,26 @@
                     alert( "Gadget stopped attempted security breach: " + alertType );
                     // Forces container to see Frame Phish alert and probably close this gadget
                     window.location.href = "about:blank"; 
-                },
-                scope: gadgetInstance
+                }
             },
             IframeHubClient: {}
         }
     };
-    if (params.forcesecure) {
-        gadgetInstance.PubSubSettings.params.IframeHubClient.requireParentVerifiable = true;
+    if (gadgets.util.getUrlParameters().forcesecure) {
+        gadgets.HubSettings.params.IframeHubClient.requireParentVerifiable = true;
     }
     
     // Register an onLoad handler
     gadgets.util.registerOnLoadHandler(function() {
         try {
             // Create the HubClient.
-            gadgetInstance.PubSub = new OpenAjax.hub.IframeHubClient(gadgetInstance.PubSubSettings.params);
+            gadgets.Hub = new OpenAjax.hub.IframeHubClient(gadgets.HubSettings.params);
             
             // Connect to the ManagedHub
-            gadgetInstance.PubSub.connect(gadgetInstance.PubSubSettings.onConnect); 
+            gadgets.Hub.connect(gadgets.HubSettings.onConnect); 
         } catch(e) {
             // TODO: error handling should be consistent with other OS gadget initialization error handling
-            gadgets.error("ERROR creating or connecting IframeHubClient in gadgets.pubsub [" + e.message + "]");
+            gadgets.error("ERROR creating or connecting IframeHubClient in gadgets.Hub [" + e.message + "]");
         }
     });
 })();

Modified: shindig/branches/2.0.x/features/src/main/javascript/features/container/container.js
URL: http://svn.apache.org/viewvc/shindig/branches/2.0.x/features/src/main/javascript/features/container/container.js?rev=993268&r1=993267&r2=993268&view=diff
==============================================================================
--- shindig/branches/2.0.x/features/src/main/javascript/features/container/container.js (original)
+++ shindig/branches/2.0.x/features/src/main/javascript/features/container/container.js Tue Sep  7 08:02:11 2010
@@ -42,14 +42,24 @@ shindig.container.Container = function(o
   this.sites_ = {};
 
   /**
-   * @type {boolean}
+   * @type {string}
    */
-  this.renderDebug_ = Boolean(shindig.container.util.getSafeJsonValue(config,
-      shindig.container.ContainerConfig.RENDER_DEBUG, false));
+  this.renderDebugParam_ = String(shindig.container.util.getSafeJsonValue(
+      config, shindig.container.ContainerConfig.RENDER_DEBUG_PARAM,
+      shindig.container.ContainerConfig.RENDER_DEBUG));
 
   /**
    * @type {boolean}
    */
+  var param = window.__CONTAINER_URI.getQP(this.renderDebugParam_);
+  this.renderDebug_ = (typeof param === 'undefined')
+      ? Boolean(shindig.container.util.getSafeJsonValue(config,
+          shindig.container.ContainerConfig.RENDER_DEBUG, false))
+      : (param === '1');
+    
+  /**
+   * @type {boolean}
+   */
   this.renderTest_ = Boolean(shindig.container.util.getSafeJsonValue(config,
       shindig.container.ContainerConfig.RENDER_TEST, false));
 
@@ -163,11 +173,7 @@ shindig.container.Container.prototype.na
  */
 shindig.container.Container.prototype.closeGadget = function(site) {
   var id = site.getId();
-  var el = this.siteEls_[id];
   site.close();
-  if (el) {
-    el.parentNode.removeChild(el);
-  }
   delete this.sites_[id];
   this.unscheduleRefreshTokens_();
 };
@@ -242,6 +248,8 @@ shindig.container.Container.prototype.on
 shindig.container.ContainerConfig = {};
 // Whether debug mode is turned on.
 shindig.container.ContainerConfig.RENDER_DEBUG = 'renderDebug';
+// The debug param name to look for in container URL for per-request debugging.
+shindig.container.ContainerConfig.RENDER_DEBUG_PARAM = 'renderDebugParam';
 // Whether test mode is turned on.
 shindig.container.ContainerConfig.RENDER_TEST = 'renderTest';
 // Security token refresh interval (in ms) for debugging.

Modified: shindig/branches/2.0.x/features/src/main/javascript/features/container/gadget_holder.js
URL: http://svn.apache.org/viewvc/shindig/branches/2.0.x/features/src/main/javascript/features/container/gadget_holder.js?rev=993268&r1=993267&r2=993268&view=diff
==============================================================================
--- shindig/branches/2.0.x/features/src/main/javascript/features/container/gadget_holder.js (original)
+++ shindig/branches/2.0.x/features/src/main/javascript/features/container/gadget_holder.js Tue Sep  7 08:02:11 2010
@@ -275,7 +275,7 @@ shindig.container.GadgetHolder.prototype
   // TODO: Share this base container logic
   // TODO: Two SD base URIs - one for container, one for gadgets
   // Need to add parent at end of query due to gadgets parsing bug
-  uri.setQP('parent', window.__CONTAINER_HOST);
+  uri.setQP('parent', window.__CONTAINER_URI.getOrigin());
 
   // Remove existing social token if we have a new one
   if (this.securityToken_) {

Modified: shindig/branches/2.0.x/features/src/main/javascript/features/container/init.js
URL: http://svn.apache.org/viewvc/shindig/branches/2.0.x/features/src/main/javascript/features/container/init.js?rev=993268&r1=993267&r2=993268&view=diff
==============================================================================
--- shindig/branches/2.0.x/features/src/main/javascript/features/container/init.js (original)
+++ shindig/branches/2.0.x/features/src/main/javascript/features/container/init.js Tue Sep  7 08:02:11 2010
@@ -40,12 +40,11 @@
   }
 
   function initializeGlobalVars() {
-    var scriptUri = getLastScriptUri();
-    if (scriptUri) {
-      window.__API_HOST = scriptUri.getOrigin();
-      window.__CONTAINER = scriptUri.getQP('container');
-    }
-    window.__CONTAINER_HOST = shindig.uri(document.location.href).getOrigin();
+    window.__API_URI = getLastScriptUri();
+    window.__CONTAINER = window.__API_URI
+        ? window.__API_URI.getQP('container')
+        : 'default';
+    window.__CONTAINER_URI = shindig.uri(document.location.href);
   }
 
   function getLastScriptUri() {

Modified: shindig/branches/2.0.x/features/src/main/javascript/features/container/service.js
URL: http://svn.apache.org/viewvc/shindig/branches/2.0.x/features/src/main/javascript/features/container/service.js?rev=993268&r1=993267&r2=993268&view=diff
==============================================================================
--- shindig/branches/2.0.x/features/src/main/javascript/features/container/service.js (original)
+++ shindig/branches/2.0.x/features/src/main/javascript/features/container/service.js Tue Sep  7 08:02:11 2010
@@ -34,7 +34,7 @@ shindig.container.Service = function(opt
    * @type {string}
    */
   this.apiHost_ = String(shindig.container.util.getSafeJsonValue(config,
-     shindig.container.ServiceConfig.API_HOST, window.__API_HOST));
+     shindig.container.ServiceConfig.API_HOST, window.__API_URI.getOrigin()));
   
   /**
    * @type {string}

Modified: shindig/branches/2.0.x/features/src/main/javascript/features/core.util/util.js
URL: http://svn.apache.org/viewvc/shindig/branches/2.0.x/features/src/main/javascript/features/core.util/util.js?rev=993268&r1=993267&r2=993268&view=diff
==============================================================================
--- shindig/branches/2.0.x/features/src/main/javascript/features/core.util/util.js (original)
+++ shindig/branches/2.0.x/features/src/main/javascript/features/core.util/util.js Tue Sep  7 08:02:11 2010
@@ -332,9 +332,9 @@ gadgets['util'] = function() {
     /**
      * Attach an event listener to given DOM element (Not a gadget standard)
      * 
-     * @param {object} elem  DOM element on which to attach event.
+     * @param {Object} elem  DOM element on which to attach event.
      * @param {string} eventName  Event type to listen for.
-     * @param {function} callback  Invoked when specified event occurs.
+     * @param {function()} callback  Invoked when specified event occurs.
      * @param {boolean} useCapture  If true, initiates capture.
      */
     'attachBrowserEvent': function(elem, eventName, callback, useCapture) {
@@ -350,9 +350,9 @@ gadgets['util'] = function() {
     /**
      * Remove event listener. (Shindig internal implementation only)
      * 
-     * @param {object} elem  DOM element from which to remove event.
+     * @param {Object} elem  DOM element from which to remove event.
      * @param {string} eventName  Event type to remove.
-     * @param {function} callback  Listener to remove.
+     * @param {function()} callback  Listener to remove.
      * @param {boolean} useCapture  Specifies whether listener being removed was added with
      *                              capture enabled.
      */

Modified: shindig/branches/2.0.x/features/src/main/javascript/features/rpc/nix.transport.js
URL: http://svn.apache.org/viewvc/shindig/branches/2.0.x/features/src/main/javascript/features/rpc/nix.transport.js?rev=993268&r1=993267&r2=993268&view=diff
==============================================================================
--- shindig/branches/2.0.x/features/src/main/javascript/features/rpc/nix.transport.js (original)
+++ shindig/branches/2.0.x/features/src/main/javascript/features/rpc/nix.transport.js Tue Sep  7 08:02:11 2010
@@ -81,6 +81,7 @@ gadgets.rpctx.nix = function() {
   // nix_channels['..'] while containers will have a channel
   // per gadget stored under the gadget's ID.
   var nix_channels = {};
+  var isForceSecure = {};
 
   // Store the ready signal method for use on handshake complete.
   var ready;
@@ -138,12 +139,59 @@ gadgets.rpctx.nix = function() {
                       NIX_SEARCH_PERIOD);
   }
 
+  // Returns current window location, without hash values
+  function getLocationNoHash() {
+    var loc = window.location.href;
+    var idx = loc.indexOf('#');
+    if (idx == -1) {
+      return loc;
+    }
+    return loc.substring(0, idx);
+  }
+
+  // When "forcesecure" is set to true, use the relay file and a simple variant of IFPC to first
+  // authenticate the container and gadget with each other.  Once that is done, then initialize
+  // the NIX protocol. 
+  function setupSecureRelayToParent(rpctoken) {
+    // To the parent, transmit the child's URL, the passed in auth
+    // token, and another token generated by the child.
+    var childToken = (0x7FFFFFFF * Math.random()) | 0;    // TODO expose way to have child set this value
+    var data = [
+      getLocationNoHash(),
+      childToken
+    ];
+    gadgets.rpc._createRelayIframe(rpctoken, data);
+    
+    // listen for response from parent
+    var hash = window.location.href.split('#')[1] || '';
+  
+    function relayTimer() {
+      var newHash = window.location.href.split('#')[1] || '';
+      if (newHash !== hash) {
+        clearInterval(relayTimerId);
+        var params = gadgets.util.getUrlParameters(window.location.href);
+        if (params.childtoken == childToken) {
+          // parent has been authenticated; now init NIX
+          conductHandlerSearch();
+          return;
+        }
+        // security error -- token didn't match
+        ready('..', false);
+      }
+    }
+    var relayTimerId = setInterval( relayTimer, 100 );
+  }
+
   return {
     getCode: function() {
       return 'nix';
     },
 
-    isParentVerifiable: function() {
+    isParentVerifiable: function(opt_receiverId) {
+      // NIX is only parent verifiable if a receiver was setup with "forcesecure" set to TRUE.
+      if (opt_receiverId) {
+        return isForceSecure[opt_receiverId];
+      }
       return false;
     },
 
@@ -249,9 +297,14 @@ gadgets.rpctx.nix = function() {
       return true;
     },
 
-    setup: function(receiverId, token) {
+    setup: function(receiverId, token, forcesecure) {
+      isForceSecure[receiverId] = !!forcesecure;
       if (receiverId === '..') {
-        conductHandlerSearch();
+        if (forcesecure) {
+          setupSecureRelayToParent(token);
+        } else {
+          conductHandlerSearch();
+        }
         return true;
       }
       try {
@@ -274,6 +327,14 @@ gadgets.rpctx.nix = function() {
         return false;
       }
       return true;
+    },
+    
+    // data = [child URL, child auth token]
+    relayOnload: function(receiverId, data) {
+      // transmit childtoken back to child to complete authentication
+      var src = data[0] + '#childtoken=' + data[1];
+      var childIframe = document.getElementById(receiverId);
+      childIframe.src = src;
     }
   };
 }();

Modified: shindig/branches/2.0.x/features/src/main/javascript/features/rpc/rpc.js
URL: http://svn.apache.org/viewvc/shindig/branches/2.0.x/features/src/main/javascript/features/rpc/rpc.js?rev=993268&r1=993267&r2=993268&view=diff
==============================================================================
--- shindig/branches/2.0.x/features/src/main/javascript/features/rpc/rpc.js (original)
+++ shindig/branches/2.0.x/features/src/main/javascript/features/rpc/rpc.js Tue Sep  7 08:02:11 2010
@@ -112,6 +112,11 @@ gadgets.rpc = function() {
   // shadowing of window.name by a "var name" declaration, or similar.
   var rpcId = window.name;
 
+  var securityCallback = function() {};
+  var LOAD_TIMEOUT = 0;
+  var FRAME_PHISH = 1;
+  var FORGED_MSG = 2;
+
   // Fallback transport is simply a dummy impl that emits no errors
   // and logs info on calls it receives, to avoid undesired side-effects
   // from falling back to IFPC or some other transport.
@@ -143,13 +148,6 @@ gadgets.rpc = function() {
     params = gadgets.util.getUrlParameters();
   }
 
-  // Indicates whether to support early-message queueing, which is designed
-  // to ensure that all messages sent by gadgets.rpc.call, irrespective
-  // when they were made (before/after setupReceiver, before/after transport
-  // setup complete), are sent. Hiding behind a query param to allow opt-in
-  // for a time while this technique is proven.
-  var useEarlyQueueing = (params['rpc_earlyq'] === "1");
-
   /**
    * Return a transport representing the best available cross-domain
    * message-passing mechanism available to the browser.
@@ -189,8 +187,7 @@ gadgets.rpc = function() {
     receiverTx[receiverId] = tx;
 
     // If there are any early-queued messages, send them now directly through
-    // the needed transport. This queue will only have contents if
-    // useEarlyQueueing === true (see call method).
+    // the needed transport.
     var earlyQueue = earlyRpcQueue[receiverId] || [];
     for (var i = 0; i < earlyQueue.length; ++i) {
       var rpc = earlyQueue[i];
@@ -203,6 +200,45 @@ gadgets.rpc = function() {
     earlyRpcQueue[receiverId] = [];
   }
 
+  //  Track when this main page is closed or navigated to a different location
+  // ("unload" event).
+  //  NOTE: The use of the "unload" handler here and for the relay iframe
+  // prevents the use of the in-memory page cache in modern browsers.
+  // See: https://developer.mozilla.org/en/using_firefox_1.5_caching
+  // See: http://webkit.org/blog/516/webkit-page-cache-ii-the-unload-event/
+  var mainPageUnloading = false,
+      hookedUnload = false;
+  
+  function hookMainPageUnload() {
+    if ( hookedUnload ) {
+      return;
+    }
+    function onunload() {
+      mainPageUnloading = true;
+    }
+    gadgets.util.attachBrowserEvent(window, 'unload', onunload, false);
+    hookedUnload = true;
+  }
+
+  function relayOnload(targetId, sourceId, token, data, relayWindow) {
+    // Validate auth token.
+    if (!authToken[sourceId] || authToken[sourceId] !== token) {
+      gadgets.error("Invalid auth token. " + authToken[sourceId] + " vs " + token);
+      securityCallback(sourceId, FORGED_MSG);
+    }
+    
+    relayWindow.onunload = function() {
+      if (setup[sourceId] && !mainPageUnloading) {
+        securityCallback(sourceId, FRAME_PHISH);
+        gadgets.rpc.removeReceiver(sourceId);
+      }
+    };
+    hookMainPageUnload();
+    
+    data = gadgets.json.parse(decodeURIComponent(data));
+    transport.relayOnload(sourceId, data);
+  }
+
   /**
    * Helper function to process an RPC request
    * @param {Object} rpc RPC request object
@@ -225,8 +261,8 @@ gadgets.rpc = function() {
         // We don't do type coercion here because all entries in the authToken
         // object are strings, as are all url params. See setupReceiver(...).
         if (authToken[rpc.f] !== rpc.t) {
-          throw new Error("Invalid auth token. " +
-              authToken[rpc.f] + " vs " + rpc.t);
+          gadgets.error("Invalid auth token. " + authToken[rpc.f] + " vs " + rpc.t);
+          securityCallback(rpc.f, FORGED_MSG);
         }
       }
 
@@ -371,7 +407,7 @@ gadgets.rpc = function() {
    * RPC mechanism. Gadgets, in turn, will complete the setup
    * of the channel once they send their first messages.
    */
-  function setupFrame(frameId, token) {
+  function setupFrame(frameId, token, forcesecure) {
     if (setup[frameId] === true) {
       return;
     }
@@ -382,7 +418,7 @@ gadgets.rpc = function() {
 
     var tgtFrame = document.getElementById(frameId);
     if (frameId === '..' || tgtFrame != null) {
-      if (transport.setup(frameId, token) === true) {
+      if (transport.setup(frameId, token, forcesecure) === true) {
         setup[frameId] = true;
         return;
       }
@@ -390,7 +426,7 @@ gadgets.rpc = function() {
 
     if (setup[frameId] !== true && setup[frameId]++ < SETUP_FRAME_MAX_TRIES) {
       // Try again in a bit, assuming that frame will soon exist.
-      window.setTimeout(function() { setupFrame(frameId, token) },
+      window.setTimeout(function() { setupFrame(frameId, token, forcesecure) },
                         SETUP_FRAME_TIMEOUT);
     } else {
       // Fail: fall back for this gadget.
@@ -451,6 +487,17 @@ gadgets.rpc = function() {
    * @deprecated
    */
   function setRelayUrl(targetId, url, opt_useLegacy) {
+    // make URL absolute if necessary
+    if (!/http(s)?:\/\/.+/.test(url)) {
+      if (url.indexOf("//") == 0) {
+        url = window.location.protocol + url;
+      } else if (url.charAt(0) == '/') {
+        url = window.location.protocol + "//" + window.location.host + url;
+      } else if (url.indexOf("://") == -1) {
+        // Assumed to be schemaless. Default to current protocol.
+        url = window.location.protocol + "//" + url;
+      }
+    }
     relayUrl[targetId] = url;
     useLegacyProtocol[targetId] = !!opt_useLegacy;
   }
@@ -474,7 +521,7 @@ gadgets.rpc = function() {
    * @member gadgets.rpc
    * @deprecated
    */
-  function setAuthToken(targetId, token) {
+  function setAuthToken(targetId, token, forcesecure) {
     token = token || "";
 
     // Coerce token to a String, ensuring that all authToken values
@@ -482,10 +529,10 @@ gadgets.rpc = function() {
     // in the process(rpc) method.
     authToken[targetId] = String(token);
 
-    setupFrame(targetId, token);
+    setupFrame(targetId, token, forcesecure);
   }
 
-  function setupContainerGadgetContext(rpctoken) {
+  function setupContainerGadgetContext(rpctoken, opt_forcesecure) {
     /**
      * Initializes gadget to container RPC params from the provided configuration.
      */
@@ -525,7 +572,8 @@ gadgets.rpc = function() {
       }
 
       // Sets the auth token and signals transport to setup connection to container.
-      setAuthToken('..', rpctoken);
+      var forceSecure = opt_forcesecure || params.forcesecure || false;
+      setAuthToken('..', rpctoken, forceSecure);
     }
 
     var requiredConfig = {
@@ -534,19 +582,20 @@ gadgets.rpc = function() {
     gadgets.config.register("rpc", requiredConfig, init);
   }
 
-  function setupContainerGenericIframe(rpctoken, opt_parent) {
+  function setupContainerGenericIframe(rpctoken, opt_parent, opt_forcesecure) {
     // Generic child IFRAME setting up connection w/ its container.
     // Use the opt_parent param if provided, or the "parent" query param
     // if found -- otherwise, do nothing since this call might be initiated
     // automatically at first, then actively later in IFRAME code.
+    var forcesecure = opt_forcesecure || params.forcesecure || false;
     var parent = opt_parent || params.parent;
     if (parent) {
       setRelayUrl('..', parent);
-      setAuthToken('..', rpctoken);
+      setAuthToken('..', rpctoken, forcesecure);
     }
   }
 
-  function setupChildIframe(gadgetId, opt_frameurl, opt_authtoken) {
+  function setupChildIframe(gadgetId, opt_frameurl, opt_authtoken, opt_forcesecure) {
     if (!gadgets.util) {
       return;
     }
@@ -564,7 +613,8 @@ gadgets.rpc = function() {
     // The auth token is parsed from child params (rpctoken) or overridden.
     var childParams = gadgets.util.getUrlParameters(childIframe.src);
     var rpctoken = opt_authtoken || childParams.rpctoken;
-    setAuthToken(gadgetId, rpctoken);
+    var forcesecure = opt_forcesecure || childParams.forcesecure;
+    setAuthToken(gadgetId, rpctoken, forcesecure);
   }
 
   /**
@@ -609,23 +659,30 @@ gadgets.rpc = function() {
    * @param {string} targetId
    * @param {string=} opt_receiverurl
    * @param {string=} opt_authtoken
+   * @param {boolean=} opt_forcesecure
    */
-  function setupReceiver(targetId, opt_receiverurl, opt_authtoken) {
+  function setupReceiver(targetId, opt_receiverurl, opt_authtoken, opt_forcesecure) {
     if (targetId === '..') {
       // Gadget/IFRAME to container.
       var rpctoken = opt_authtoken || params.rpctoken || params.ifpctok || "";
       if (window['__isgadget'] === true) {
-        setupContainerGadgetContext(rpctoken);
+        setupContainerGadgetContext(rpctoken, opt_forcesecure);
       } else {
-        setupContainerGenericIframe(rpctoken, opt_receiverurl);
+        setupContainerGenericIframe(rpctoken, opt_receiverurl, opt_forcesecure);
       }
     } else {
       // Container to child.
-      setupChildIframe(targetId, opt_receiverurl, opt_authtoken);
+      setupChildIframe(targetId, opt_receiverurl, opt_authtoken, opt_forcesecure);
     }
   }
 
   return /** @scope gadgets.rpc */ {
+    config: function(config) {
+      if (typeof config.securityCallback === 'function') {
+        securityCallback = config.securityCallback;
+      }
+    },
+    
     /**
      * Registers an RPC service.
      * @param {string} serviceName Service name to register.
@@ -747,7 +804,7 @@ gadgets.rpc = function() {
       // Attempt to make call via a cross-domain transport.
       // Retrieve the transport for the given target - if one
       // target is misconfigured, it won't affect the others.
-      var channel = receiverTx[targetId] ? receiverTx[targetId] : transport;
+      var channel = receiverTx[targetId];
 
       if (!channel) {
         // Not set up yet. Enqueue the rpc for such time as it is.
@@ -797,6 +854,16 @@ gadgets.rpc = function() {
     setAuthToken: setAuthToken,
     setupReceiver: setupReceiver,
     getAuthToken: getAuthToken,
+    
+    // Note: Does not delete iframe
+    removeReceiver: function(receiverId) {
+      delete relayUrl[receiverId];
+      delete useLegacyProtocol[receiverId];
+      delete authToken[receiverId];
+      delete setup[receiverId];
+      delete sameDomain[receiverId];
+      delete receiverTx[receiverId];
+    },
 
     /**
      * Gets the RPC relay mechanism.
@@ -820,10 +887,12 @@ gadgets.rpc = function() {
      * @member gadgets.rpc
      * @deprecated
      */
-    receive: function(fragment) {
+    receive: function(fragment, otherWindow) {
       if (fragment.length > 4) {
         process(gadgets.json.parse(
             decodeURIComponent(fragment[fragment.length - 1])));
+      } else {
+        relayOnload.apply(null, fragment.concat(otherWindow));
       }
     },
 
@@ -844,6 +913,21 @@ gadgets.rpc = function() {
     // see docs above
     getOrigin: getOrigin,
 
+    getReceiverOrigin: function(receiverId) {
+      var channel = receiverTx[receiverId];
+      if (!channel) {
+        // not set up yet
+        return null;
+      }
+      if (!channel.isParentVerifiable(receiverId)) {
+        // given transport cannot verify receiver origin
+        return null;
+      }
+      var origRelay = gadgets.rpc.getRelayUrl(receiverId) ||
+                      gadgets.util.getUrlParameters().parent;
+      return gadgets.rpc.getOrigin(origRelay);
+    },
+
     /**
      * Internal-only method used to initialize gadgets.rpc.
      * @member gadgets.rpc
@@ -863,9 +947,51 @@ gadgets.rpc = function() {
     /** Returns the window keyed by the ID. null/".." for parent, else child */
     _getTargetWin: getTargetWin,
 
+    /** Create an iframe for loading the relay URL. Used by child only. */ 
+    _createRelayIframe: function(token, data) {
+      var relay = gadgets.rpc.getRelayUrl('..');
+      if (!relay) {
+        return;
+      }
+      
+      // Format: #targetId & sourceId & authToken & data
+      var src = relay + '#..&' + rpcId + '&' + token + '&' +
+          encodeURIComponent(gadgets.json.stringify(data));
+  
+      var iframe = document.createElement('iframe');
+      iframe.style.border = iframe.style.width = iframe.style.height = '0px';
+      iframe.style.visibility = 'hidden';
+      iframe.style.position = 'absolute';
+
+      function appendFn() {
+        // Append the iframe.
+        document.body.appendChild(iframe);
+  
+        // Set the src of the iframe to 'about:blank' first and then set it
+        // to the relay URI. This prevents the iframe from maintaining a src
+        // to the 'old' relay URI if the page is returned to from another.
+        // In other words, this fixes the bfcache issue that causes the iframe's
+        // src property to not be updated despite us assigning it a new value here.
+        iframe.src = 'javascript:"<html></html>"';
+        iframe.src = src;
+      }
+      
+      if (document.body) {
+        appendFn();
+      } else {
+        gadgets.util.registerOnLoadHandler(function() { appendFn(); });
+      }
+      
+      return iframe;
+    },
+
     ACK: ACK,
 
-    RPC_ID: rpcId
+    RPC_ID: rpcId,
+    
+    SEC_ERROR_LOAD_TIMEOUT: LOAD_TIMEOUT,
+    SEC_ERROR_FRAME_PHISH: FRAME_PHISH,
+    SEC_ERROR_FORGED_MSG : FORGED_MSG
   };
 }();
 

Modified: shindig/branches/2.0.x/features/src/main/javascript/features/rpc/wpm.transport.js
URL: http://svn.apache.org/viewvc/shindig/branches/2.0.x/features/src/main/javascript/features/rpc/wpm.transport.js?rev=993268&r1=993267&r2=993268&view=diff
==============================================================================
--- shindig/branches/2.0.x/features/src/main/javascript/features/rpc/wpm.transport.js (original)
+++ shindig/branches/2.0.x/features/src/main/javascript/features/rpc/wpm.transport.js Tue Sep  7 08:02:11 2010
@@ -44,7 +44,64 @@ gadgets.rpctx = gadgets.rpctx || {};
 if (!gadgets.rpctx.wpm) {  // make lib resilient to double-inclusion
 
 gadgets.rpctx.wpm = function() {
-  var ready;
+  var process, ready;
+  var postMessage;
+  var pmSync = false;
+  var pmEventDomain = false;
+  var isForceSecure = false;
+
+  // Some browsers (IE, Opera) have an implementation of postMessage that is
+  // synchronous, although HTML5 specifies that it should be asynchronous.  In
+  // order to make all browsers behave consistently, we run a small test to detect
+  // if postMessage is asynchronous or not.  If not, we wrap calls to postMessage
+  // in a setTimeout with a timeout of 0.
+  // Also, Opera's "message" event does not have an "origin" property (at least,
+  // it doesn't in version 9.64;  presumably, it will in version 10).  If
+  // event.origin does not exist, use event.domain.  The other difference is that
+  // while event.origin looks like <scheme>://<hostname>:<port>, event.domain
+  // consists only of <hostname>.
+  //
+  function testPostMessage() {
+    var hit = false;
+    
+    function receiveMsg(event) {
+      if (event.data == "postmessage.test") {
+        hit = true;
+        if (typeof event.origin === "undefined") {
+          pmEventDomain = true;
+        }
+      }
+    }
+    
+    gadgets.util.attachBrowserEvent(window, "message", receiveMsg, false);
+    window.postMessage("postmessage.test", "*");
+    
+    // if 'hit' is true here, then postMessage is synchronous
+    if (hit) {
+      pmSync = true;
+    }
+    
+    gadgets.util.removeBrowserEvent(window, "message", receiveMsg, false);
+  }
+
+  function onmessage(packet) {
+    var rpc = gadgets.json.parse(packet.data);
+    if (isForceSecure) {
+      if (!rpc || !rpc.f) {
+        return;
+      }
+    
+      // for security, check origin against expected value
+      var origRelay = gadgets.rpc.getRelayUrl(rpc.f) ||
+                      gadgets.util.getUrlParameters()["parent"];
+      var origin = gadgets.rpc.getOrigin(origRelay);
+      if (!pmEventDomain ? packet.origin !== origin :
+                           packet.domain !== /^.+:\/\/([^:]+).*/.exec( origin )[1]) {
+        return;
+      }
+    }
+    process(rpc);
+  }
 
   return {
     getCode: function() {
@@ -56,11 +113,21 @@ gadgets.rpctx.wpm = function() {
     },
 
     init: function(processFn, readyFn) {
+      process = processFn;
       ready = readyFn;
-      var onmessage = function(packet) {
-        // TODO validate packet.domain for security reasons
-        processFn(gadgets.json.parse(packet.data));
-      };
+
+      testPostMessage();
+      if (!pmSync) {
+        postMessage = function(win, msg, origin) {
+          win.postMessage(msg, origin);
+        };
+      } else {
+        postMessage = function(win, msg, origin) {
+          window.setTimeout( function() {
+            win.postMessage(msg, origin);
+          }, 0);
+        };
+      }
  
       // Set up native postMessage handler.
       gadgets.util.attachBrowserEvent(window, 'message', onmessage, false);
@@ -69,11 +136,16 @@ gadgets.rpctx.wpm = function() {
       return true;
     },
 
-    setup: function(receiverId, token) {
+    setup: function(receiverId, token, forceSecure) {
+      isForceSecure = forceSecure;
       // If we're a gadget, send an ACK message to indicate to container
       // that we're ready to receive messages.
       if (receiverId === '..') {
-        gadgets.rpc.call(receiverId, gadgets.rpc.ACK);
+        if (isForceSecure) {
+          gadgets.rpc._createRelayIframe(token);
+        } else {
+          gadgets.rpc.call(receiverId, gadgets.rpc.ACK);
+        }
       }
       return true;
     },
@@ -85,12 +157,16 @@ gadgets.rpctx.wpm = function() {
                       gadgets.util.getUrlParameters()["parent"];
       var origin = gadgets.rpc.getOrigin(origRelay);
       if (origin) {
-        targetWin.postMessage(gadgets.json.stringify(rpc), origin);
+        postMessage(targetWin, gadgets.json.stringify(rpc), origin);
       } else {
         gadgets.error("No relay set (used as window.postMessage targetOrigin)" +
             ", cannot send cross-domain message");
       }
       return true;
+    },
+
+    relayOnload: function(receiverId, data) {
+      ready(receiverId, true);
     }
   };
 }();

Modified: shindig/branches/2.0.x/features/src/main/javascript/features/shindig.container/feature.xml
URL: http://svn.apache.org/viewvc/shindig/branches/2.0.x/features/src/main/javascript/features/shindig.container/feature.xml?rev=993268&r1=993267&r2=993268&view=diff
==============================================================================
--- shindig/branches/2.0.x/features/src/main/javascript/features/shindig.container/feature.xml (original)
+++ shindig/branches/2.0.x/features/src/main/javascript/features/shindig.container/feature.xml Tue Sep  7 08:02:11 2010
@@ -27,6 +27,7 @@ A map of view names to view attributes. 
   <dependency>globals</dependency>
   <dependency>rpc</dependency>
   <dependency>osapi</dependency>
+  <dependency>shindig.uri.ext</dependency>
   <container>
     <script src="util.js"/>
     <script src="cookies.js"/>