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

svn commit: r1001115 - in /shindig/trunk: features/src/main/javascript/features/container/ java/common/src/main/java/org/apache/shindig/protocol/conversion/ java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/ java/gadgets/src/test/java/org/a...

Author: zhoresh
Date: Sat Sep 25 00:59:30 2010
New Revision: 1001115

URL: http://svn.apache.org/viewvc?rev=1001115&view=rev
Log:
Ref: http://codereview.appspot.com/2253044/
Update GadgetHandlerApi and Gadget Handler error handling

Modified:
    shindig/trunk/features/src/main/javascript/features/container/service.js
    shindig/trunk/java/common/src/main/java/org/apache/shindig/protocol/conversion/BeanDelegator.java
    shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/GadgetsHandler.java
    shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/GadgetsHandlerApi.java
    shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/GadgetsHandlerService.java
    shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/servlet/GadgetHandlerServiceTest.java
    shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/servlet/GadgetsHandlerTest.java

Modified: shindig/trunk/features/src/main/javascript/features/container/service.js
URL: http://svn.apache.org/viewvc/shindig/trunk/features/src/main/javascript/features/container/service.js?rev=1001115&r1=1001114&r2=1001115&view=diff
==============================================================================
--- shindig/trunk/features/src/main/javascript/features/container/service.js (original)
+++ shindig/trunk/features/src/main/javascript/features/container/service.js Sat Sep 25 00:59:30 2010
@@ -103,14 +103,13 @@ shindig.container.Service.prototype.getG
       // If response entirely fails, augment individual errors.
       if (response.error) {
         for (var i = 0; i < request.ids.length; i++) {
-          var id = request.ids[i];
-          var message = [ 'Server failure to fetch metadata for gadget ', id, '.' ].join('');
-          finalResponse[id] = { error : message };
+          finalResponse[id] = { 'error' : response.error };
         }
 
       // Otherwise, cache response. Augment final response with server response.
       } else {
         for (var id in response) {
+          response[id]['url'] = id; // make sure url is set
           self.cachedMetadatas_[id] = response[id];
           finalResponse[id] = response[id];
         }
@@ -138,14 +137,13 @@ shindig.container.Service.prototype.getG
     // If response entirely fails, augment individual errors.
     if (response.error) {
       for (var i = 0; i < request.ids.length; i++) {
-        var id = request.ids[i];
-        var message = [ 'Server failure to fetch token for gadget ' + id + '.' ].join('');
-        finalResponse[id] = { error : message };
+        finalResponse[id] = { 'error' : response.error };
       }
 
     // Otherwise, cache response. Augment final response with server response.
     } else {
       for (var id in response) {
+        response[id]['url'] = id; // make sure url is set
         self.cachedTokens_[id] = response[id];
         finalResponse[id] = response[id];
       }

Modified: shindig/trunk/java/common/src/main/java/org/apache/shindig/protocol/conversion/BeanDelegator.java
URL: http://svn.apache.org/viewvc/shindig/trunk/java/common/src/main/java/org/apache/shindig/protocol/conversion/BeanDelegator.java?rev=1001115&r1=1001114&r2=1001115&view=diff
==============================================================================
--- shindig/trunk/java/common/src/main/java/org/apache/shindig/protocol/conversion/BeanDelegator.java (original)
+++ shindig/trunk/java/common/src/main/java/org/apache/shindig/protocol/conversion/BeanDelegator.java Sat Sep 25 00:59:30 2010
@@ -107,6 +107,11 @@ public class BeanDelegator {
   public <T> T createDelegator(Object source, Class<T> apiInterface,
                                Map<String, Object> extraFields) {
 
+    if (source == null && extraFields != null && extraFields.size() > 0) {
+      // Create delegator that is based only on fields, so use dummy object
+      source = new NullClass();
+    }
+
     if (source == null) {
       return null;
     }
@@ -193,6 +198,7 @@ public class BeanDelegator {
           return (data == NULL ? null : data);
         }
       }
+      Exception exc = null;
       try {
         Method sourceMethod = sourceClass.getMethod(
             method.getName(), method.getParameterTypes());
@@ -200,14 +206,18 @@ public class BeanDelegator {
         return createDelegator(result, getParameterizedReturnType(method));
       } catch (NoSuchMethodException e) {
         // Will throw unsupported method below
+        exc = e;
       } catch (IllegalArgumentException e) {
         // Will throw unsupported method below
+        exc = e;
       } catch (IllegalAccessException e) {
         // Will throw unsupported method below
+        exc = e;
       } catch (InvocationTargetException e) {
         // Will throw unsupported method below
+        exc = e;
       }
-      throw new UnsupportedOperationException("Unsupported function: " + method.getName());
+      throw new UnsupportedOperationException("Unsupported function: " + method.getName(), exc);
     }
   }
 
@@ -333,4 +343,7 @@ public class BeanDelegator {
    }
    return mapBuilder.build();
   }
+
+  /** Fake class that does not have fields or method for field base delegator */
+  static class NullClass {}
 }

Modified: shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/GadgetsHandler.java
URL: http://svn.apache.org/viewvc/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/GadgetsHandler.java?rev=1001115&r1=1001114&r2=1001115&view=diff
==============================================================================
--- shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/GadgetsHandler.java (original)
+++ shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/GadgetsHandler.java Sat Sep 25 00:59:30 2010
@@ -19,14 +19,15 @@
 package org.apache.shindig.gadgets.servlet;
 
 import com.google.common.annotations.VisibleForTesting;
-import com.google.common.base.Preconditions;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.ImmutableSet;
 import com.google.inject.Inject;
 
+import org.apache.commons.lang.StringUtils;
 import org.apache.shindig.common.uri.Uri;
-import org.apache.shindig.gadgets.GadgetContext;
+import org.apache.shindig.common.uri.Uri.UriException;
+import org.apache.shindig.gadgets.process.ProcessingException;
 import org.apache.shindig.gadgets.spec.GadgetSpec;
 import org.apache.shindig.protocol.BaseRequestItem;
 import org.apache.shindig.protocol.Operation;
@@ -61,7 +62,7 @@ public class GadgetsHandler {
   static final String FAILURE_TOKEN = "Failed to get gadget token.";
 
   private static final List<String> DEFAULT_METADATA_FIELDS =
-      ImmutableList.of("iframeUrl", "userPrefs.*", "modulePrefs.*", "views.*", "token");
+      ImmutableList.of("iframeUrl", "userPrefs.*", "modulePrefs.*", "views.*");
 
   private static final List<String> DEFAULT_TOKEN_FIELDS = ImmutableList.of("token");
 
@@ -84,10 +85,10 @@ public class GadgetsHandler {
   @Operation(httpMethods = {"POST", "GET"}, path = "metadata.get")
   public Map<String, GadgetsHandlerApi.BaseResponse> metadata(BaseRequestItem request)
       throws ProtocolException {
-    return new AbstractExecutor<GadgetsHandlerApi.MetadataResponse>() {
+    return new AbstractExecutor() {
       @Override
-      protected Callable<GadgetsHandlerApi.MetadataResponse> createJob(String url,
-          BaseRequestItem request) {
+      protected Callable<CallableData> createJob(String url, BaseRequestItem request)
+          throws ProcessingException {
         return createMetadataJob(url, request);
       }
     }.execute(request);
@@ -96,10 +97,10 @@ public class GadgetsHandler {
   @Operation(httpMethods = {"POST", "GET"}, path = "token.get")
   public Map<String, GadgetsHandlerApi.BaseResponse> token(BaseRequestItem request)
       throws ProtocolException {
-    return new AbstractExecutor<GadgetsHandlerApi.TokenResponse>() {
+    return new AbstractExecutor() {
       @Override
-      protected Callable<GadgetsHandlerApi.TokenResponse> createJob(String url,
-          BaseRequestItem request) {
+      protected Callable<CallableData> createJob(String url, BaseRequestItem request)
+          throws ProcessingException {
         return createTokenJob(url, request);
       }
     }.execute(request);
@@ -117,7 +118,22 @@ public class GadgetsHandler {
         beanFilter.getBeanFields(GadgetsHandlerApi.TokenResponse.class, 5));
   }
 
-  private abstract class AbstractExecutor<R extends GadgetsHandlerApi.BaseResponse> {
+  /**
+   * Class to handle threaded reply.
+   * Mainly it made to support filtering the id (url)
+   */
+  class CallableData {
+    private final String id;
+    private final GadgetsHandlerApi.BaseResponse data;
+    public CallableData(String id, GadgetsHandlerApi.BaseResponse data) {
+      this.id = id;
+      this.data = data;
+    }
+    public String getId() { return id; }
+    public GadgetsHandlerApi.BaseResponse getData() { return data; }
+  }
+
+  private abstract class AbstractExecutor {
     @SuppressWarnings("unchecked")
     public Map<String, GadgetsHandlerApi.BaseResponse> execute(BaseRequestItem request) {
       Set<String> gadgetUrls = ImmutableSet.copyOf(request.getListParameter("ids"));
@@ -125,84 +141,80 @@ public class GadgetsHandler {
         return ImmutableMap.of();
       }
 
-      CompletionService<R> completionService = new ExecutorCompletionService<R>(executor);
-      for (String gadgetUrl : gadgetUrls) {
-        Callable<R> job = createJob(gadgetUrl, request);
-        completionService.submit(job);
+      if (StringUtils.isEmpty(request.getParameter("container"))) {
+        throw new ProtocolException(HttpServletResponse.SC_BAD_REQUEST,
+            "Missing container for request.");
       }
 
       ImmutableMap.Builder<String, GadgetsHandlerApi.BaseResponse> builder = ImmutableMap.builder();
-      for (int numJobs = gadgetUrls.size(); numJobs > 0; numJobs--) {
-        R response;
+      int badReq = 0;
+      CompletionService<CallableData> completionService =
+          new ExecutorCompletionService<CallableData>(executor);
+      for (String gadgetUrl : gadgetUrls) {
+        try {
+          Callable<CallableData> job = createJob(gadgetUrl, request);
+          completionService.submit(job);
+        } catch (ProcessingException e) {
+          // Fail to create and submit job
+          builder.put(gadgetUrl, handlerService.createErrorResponse(null,
+              e.getHttpStatusCode(), e.getMessage()));
+          badReq++;
+        }
+      }
+
+      for (int numJobs = gadgetUrls.size() - badReq; numJobs > 0; numJobs--) {
+        CallableData response;
         try {
           response = completionService.take().get();
-          builder.put(response.getUrl().toString(), response);
+          builder.put(response.getId(), response.getData());
         } catch (InterruptedException e) {
           throw new ProtocolException(HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
               "Processing interrupted.", e);
         } catch (ExecutionException e) {
-          if (!(e.getCause() instanceof RpcException)) {
-            throw new ProtocolException(HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
-                "Processing error.", e);
-          }
-          RpcException cause = (RpcException) e.getCause();
-          GadgetContext context = cause.getContext();
-          if (context != null) {
-            Uri url = context.getUrl();
-            GadgetsHandlerApi.BaseResponse errorResponse =
-                handlerService.createBaseResponse(url, cause.getMessage());
-            builder.put(url.toString(), errorResponse);
-          }
+          throw new ProtocolException(HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
+              "Processing error.", e);
         }
       }
       return builder.build();
     }
 
-    protected abstract Callable<R> createJob(String url, BaseRequestItem request);
+    protected abstract Callable<CallableData> createJob(String url, BaseRequestItem request)
+        throws ProcessingException;
   }
 
   // Hook to override in sub-class.
-  protected Callable<GadgetsHandlerApi.MetadataResponse> createMetadataJob(String url,
-      BaseRequestItem request) {
+  protected Callable<CallableData> createMetadataJob(final String url,
+      BaseRequestItem request) throws ProcessingException {
     final MetadataRequestData metadataRequest = new MetadataRequestData(url, request);
-    return new Callable<GadgetsHandlerApi.MetadataResponse>() {
-      public GadgetsHandlerApi.MetadataResponse call() throws Exception {
+    return new Callable<CallableData>() {
+      public CallableData call() throws Exception {
         try {
-          return handlerService.getMetadata(metadataRequest);
+          return new CallableData(url, handlerService.getMetadata(metadataRequest));
         } catch (Exception e) {
-          sendError(metadataRequest.getUrl(), e, FAILURE_METADATA);
-          return null;
+          return new CallableData(url,
+              handlerService.createErrorResponse(null, e, FAILURE_METADATA));
         }
       }
     };
   }
 
   // Hook to override in sub-class.
-  protected Callable<GadgetsHandlerApi.TokenResponse> createTokenJob(String url,
-      BaseRequestItem request) {
-    final TokenRequestData tokenRequest = new TokenRequestData(url, request);
-    return new Callable<GadgetsHandlerApi.TokenResponse>() {
-      public GadgetsHandlerApi.TokenResponse call() throws Exception {
+  protected Callable<CallableData> createTokenJob(final String url,
+      BaseRequestItem request) throws ProcessingException {
+    // TODO: Get token duration from requests
+    final TokenRequestData tokenRequest = new TokenRequestData(url, request, null);
+    return new Callable<CallableData>() {
+      public CallableData call() throws Exception {
         try {
-          return handlerService.getToken(tokenRequest);
+          return new CallableData(url, handlerService.getToken(tokenRequest));
         } catch (Exception e) {
-          sendError(tokenRequest.getUrl(), e, FAILURE_TOKEN);
-          return null;
+          return new CallableData(url,
+            handlerService.createErrorResponse(null, e, FAILURE_TOKEN));
         }
       }
     };
   }
 
-  private void sendError(final Uri url, Exception e, String msg)
-      throws RpcException {
-    GadgetContext context = new GadgetContext() {
-      @Override
-      public Uri getUrl() { return url; }
-    };
-    // Note: this error message is publicly visible in JSON-RPC response.
-    throw new RpcException(context, msg, e);
-  }
-
   /**
    * Gadget context classes used to translate JSON BaseRequestItem into a more
    * meaningful model objects that Java can work with.
@@ -213,10 +225,15 @@ public class GadgetsHandler {
     protected final List<String> fields;
     protected final BaseRequestItem request;
 
-    public AbstractRequest(String url, BaseRequestItem request, List<String> defaultFields) {
-      this.uri = Uri.parse(Preconditions.checkNotNull(url));
-      this.request = Preconditions.checkNotNull(request);
-      this.container = Preconditions.checkNotNull(request.getParameter("container"));
+    public AbstractRequest(String url, BaseRequestItem request, List<String> defaultFields)
+        throws ProcessingException {
+      try {
+        this.uri = Uri.parse(url);
+      } catch (UriException e) {
+        throw new ProcessingException("Bad url - " + url, HttpServletResponse.SC_BAD_REQUEST);
+      }
+      this.request = request;
+      this.container = request.getParameter("container");
       this.fields = processFields(request, defaultFields);
     }
 
@@ -242,7 +259,8 @@ public class GadgetsHandler {
   protected class TokenRequestData extends AbstractRequest
       implements GadgetsHandlerApi.TokenRequest {
 
-    public TokenRequestData(String url, BaseRequestItem request) {
+    public TokenRequestData(String url, BaseRequestItem request, Long durationSeconds)
+        throws ProcessingException {
       super(url, request, DEFAULT_TOKEN_FIELDS);
     }
 
@@ -259,7 +277,8 @@ public class GadgetsHandler {
     protected final boolean ignoreCache;
     protected final boolean debug;
 
-    public MetadataRequestData(String url, BaseRequestItem request) {
+    public MetadataRequestData(String url, BaseRequestItem request)
+        throws ProcessingException {
       super(url, request, DEFAULT_METADATA_FIELDS);
       String lang = request.getParameter("language");
       String country = request.getParameter("country");

Modified: shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/GadgetsHandlerApi.java
URL: http://svn.apache.org/viewvc/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/GadgetsHandlerApi.java?rev=1001115&r1=1001114&r2=1001115&view=diff
==============================================================================
--- shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/GadgetsHandlerApi.java (original)
+++ shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/GadgetsHandlerApi.java Sat Sep 25 00:59:30 2010
@@ -37,9 +37,26 @@ import java.util.Map;
 public class GadgetsHandlerApi {
 
   public interface BaseRequest {
-    public Uri getUrl();
     public String getContainer();
     public List<String> getFields();
+    public Uri getUrl();
+  }
+
+  public interface Error {
+    public int getCode();
+    public String getMessage();
+  }
+
+  public interface BaseResponse {
+    /** Url of the request, optional (for example for bad url error) */
+    public Uri getUrl();
+    /** Error response (optional) */
+    @Unfiltered
+    public Error getError();
+    /** The response expiration time (miliseconds since epoch), -1 for no caching */
+    public Long getExpireTimeMs();
+    /** The response time (miliseconds since epoch) - usefull for misconfigured client time */
+    public Long getResponseTimeMs();
   }
 
   public interface MetadataRequest extends BaseRequest {
@@ -55,17 +72,6 @@ public class GadgetsHandlerApi {
     public String getViewerId();
   }
 
-  public interface TokenRequest extends BaseRequest {
-    public TokenData getToken();
-  }
-
-  public interface BaseResponse {
-    @Unfiltered
-    public Uri getUrl();
-    @Unfiltered
-    public String getError();
-  }
-
   public interface MetadataResponse extends BaseResponse {
     public String getIframeUrl();
     public String getChecksum();
@@ -157,6 +163,12 @@ public class GadgetsHandlerApi {
     public Uri getHref();
   }
 
+  public interface TokenRequest extends BaseRequest {
+    public TokenData getToken();
+    // TODO: Consider support container controlled token duration
+    // public Long getDurationSeconds();
+  }
+
   public interface TokenResponse extends BaseResponse {
     public String getToken();
   }

Modified: shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/GadgetsHandlerService.java
URL: http://svn.apache.org/viewvc/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/GadgetsHandlerService.java?rev=1001115&r1=1001114&r2=1001115&view=diff
==============================================================================
--- shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/GadgetsHandlerService.java (original)
+++ shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/GadgetsHandlerService.java Sat Sep 25 00:59:30 2010
@@ -26,6 +26,7 @@ import org.apache.shindig.auth.SecurityT
 import org.apache.shindig.auth.SecurityTokenCodec;
 import org.apache.shindig.auth.SecurityTokenException;
 import org.apache.shindig.common.uri.Uri;
+import org.apache.shindig.common.util.TimeSource;
 import org.apache.shindig.gadgets.Gadget;
 import org.apache.shindig.gadgets.GadgetContext;
 import org.apache.shindig.gadgets.RenderingContext;
@@ -47,6 +48,8 @@ import java.util.Locale;
 import java.util.Map;
 import java.util.Set;
 
+import javax.servlet.http.HttpServletResponse;
+
 /**
  * Service that interfaces with the system to provide information about gadgets.
  *
@@ -81,6 +84,7 @@ public class GadgetsHandlerService {
               GadgetsHandlerApi.UserPrefDataType.class))
           .build();
 
+  protected final TimeSource timeSource;
   protected final Processor processor;
   protected final IframeUriManager iframeUriManager;
   protected final SecurityTokenCodec securityTokenCodec;
@@ -88,12 +92,11 @@ public class GadgetsHandlerService {
   protected final BeanDelegator beanDelegator;
   protected final BeanFilter beanFilter;
 
-
-
   @Inject
-  public GadgetsHandlerService(Processor processor,
+  public GadgetsHandlerService(TimeSource timeSource, Processor processor,
       IframeUriManager iframeUriManager, SecurityTokenCodec securityTokenCodec,
       BeanFilter beanFilter) {
+    this.timeSource = timeSource;
     this.processor = processor;
     this.iframeUriManager = iframeUriManager;
     this.securityTokenCodec = securityTokenCodec;
@@ -124,15 +127,19 @@ public class GadgetsHandlerService {
     GadgetContext context = new MetadataGadgetContext(request);
     Gadget gadget = processor.process(context);
     String iframeUrl =
-        (fields.contains("iframeurl") || fields.contains(BeanFilter.ALL_FIELDS)) ?
+        isFieldIncluded(fields, "iframeurl")  ?
             iframeUriManager.makeRenderingUri(gadget).toString() : null;
+    // TODO: Figure out url expiration time
     Boolean needsTokenRefresh =
-        (fields.contains("needstokenrefresh") || fields.contains(BeanFilter.ALL_FIELDS)) ?
+        isFieldIncluded(fields, "needstokenrefresh") ?
             gadget.getAllFeatures().contains("auth-refresh") : null;
     return createMetadataResponse(context.getUrl(), gadget.getSpec(), iframeUrl,
-        needsTokenRefresh, fields);
+        needsTokenRefresh, fields, null);
   }
 
+  private boolean isFieldIncluded(Set<String> fields, String name) {
+    return fields.contains(BeanFilter.ALL_FIELDS) || fields.contains(name.toLowerCase());
+  }
   /**
    * Create security token
    * @param request token paramaters (gadget, owner and viewer)
@@ -155,7 +162,8 @@ public class GadgetsHandlerService {
     SecurityToken tokenData = convertToken(request.getToken(), request.getContainer(),
         request.getUrl().toString());
     String token = securityTokenCodec.encodeToken(tokenData);
-    return createTokenResponse(request.getUrl(), token, fields);
+    // TODO: Calculate token expiration in response
+    return createTokenResponse(request.getUrl(), token, fields, null);
   }
 
   /**
@@ -228,30 +236,49 @@ public class GadgetsHandlerService {
             "appid", url, "appurl", url));
   }
 
-  public GadgetsHandlerApi.BaseResponse createBaseResponse(Uri url, String error) {
+  public GadgetsHandlerApi.BaseResponse createErrorResponse(
+    Uri uri, Exception e, String defaultMsg) {
+    if (e instanceof ProcessingException) {
+      ProcessingException processingExc = (ProcessingException) e;
+      return createErrorResponse(uri, processingExc.getHttpStatusCode(),
+          processingExc.getMessage());
+    }
+    return createErrorResponse(uri, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, defaultMsg);
+  }
+
+  public GadgetsHandlerApi.BaseResponse createErrorResponse(Uri url, int code, String error) {
+    GadgetsHandlerApi.Error errorBean = beanDelegator.createDelegator(
+        null, GadgetsHandlerApi.Error.class, ImmutableMap.<String, Object>of(
+          "message", error, "code", code));
+
     return beanDelegator.createDelegator(error, GadgetsHandlerApi.BaseResponse.class,
-        ImmutableMap.<String, Object>of("url", url, "error", error));
+        ImmutableMap.<String, Object>of("url", BeanDelegator.nullable(url), "error", errorBean,
+            "responsetimems", BeanDelegator.NULL, "expiretimems", BeanDelegator.NULL));
   }
 
   private GadgetsHandlerApi.MetadataResponse createMetadataResponse(
       Uri url, GadgetSpec spec, String iframeUrl, Boolean needsTokenRefresh,
-      Set<String> fields) {
+      Set<String> fields, Long expireTime) {
     return (GadgetsHandlerApi.MetadataResponse) beanFilter.createFilteredBean(
         beanDelegator.createDelegator(spec, GadgetsHandlerApi.MetadataResponse.class,
-            ImmutableMap.<String, Object>of(
-                "url", url,
-                "error", BeanDelegator.NULL,
-                "iframeurl", BeanDelegator.nullable(iframeUrl),
-                "needstokenrefresh", BeanDelegator.nullable(needsTokenRefresh))),
+            ImmutableMap.<String, Object>builder()
+                .put("url", url)
+                .put("error", BeanDelegator.NULL)
+                .put("iframeurl", BeanDelegator.nullable(iframeUrl))
+                .put("needstokenrefresh", BeanDelegator.nullable(needsTokenRefresh))
+                .put("responsetimems", timeSource.currentTimeMillis())
+                .put("expiretimems", BeanDelegator.nullable(expireTime)).build()),
         fields);
   }
 
   private GadgetsHandlerApi.TokenResponse createTokenResponse(
-      Uri url, String token, Set<String> fields) {
+      Uri url, String token, Set<String> fields, Long tokenExpire) {
     return (GadgetsHandlerApi.TokenResponse) beanFilter.createFilteredBean(
         beanDelegator.createDelegator("empty", GadgetsHandlerApi.TokenResponse.class,
             ImmutableMap.<String, Object>of("url", url, "error", BeanDelegator.NULL,
-                "token", BeanDelegator.nullable(token))),
+                "token", BeanDelegator.nullable(token),
+                "responsetimems", timeSource.currentTimeMillis(),
+                "expiretimems", BeanDelegator.nullable(tokenExpire))),
         fields);
   }
 }

Modified: shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/servlet/GadgetHandlerServiceTest.java
URL: http://svn.apache.org/viewvc/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/servlet/GadgetHandlerServiceTest.java?rev=1001115&r1=1001114&r2=1001115&view=diff
==============================================================================
--- shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/servlet/GadgetHandlerServiceTest.java (original)
+++ shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/servlet/GadgetHandlerServiceTest.java Sat Sep 25 00:59:30 2010
@@ -26,6 +26,7 @@ import org.apache.shindig.auth.SecurityT
 import org.apache.shindig.auth.SecurityTokenException;
 import org.apache.shindig.common.EasyMockTestCase;
 import org.apache.shindig.common.uri.Uri;
+import org.apache.shindig.common.util.FakeTimeSource;
 import org.apache.shindig.gadgets.features.FeatureRegistry;
 import org.apache.shindig.gadgets.process.ProcessingException;
 import org.apache.shindig.protocol.conversion.BeanDelegator;
@@ -47,6 +48,7 @@ public class GadgetHandlerServiceTest ex
   private final BeanDelegator delegator = new BeanDelegator(
     GadgetsHandlerService.apiClasses, GadgetsHandlerService.enumConversionMap);
 
+  private final FakeTimeSource timeSource = new FakeTimeSource();
   private final FeatureRegistry mockRegistry = mock(FeatureRegistry.class);
   private final FakeProcessor processor = new FakeProcessor(mockRegistry);
   private final FakeIframeUriManager urlGenerator = new FakeIframeUriManager();
@@ -57,7 +59,7 @@ public class GadgetHandlerServiceTest ex
   @Before
   public void setUp() {
     tokenCodec = new FakeSecurityTokenCodec();
-    gadgetHandler = new GadgetsHandlerService(processor, urlGenerator,
+    gadgetHandler = new GadgetsHandlerService(timeSource, processor, urlGenerator,
         tokenCodec, new BeanFilter());
   }
 
@@ -70,7 +72,7 @@ public class GadgetHandlerServiceTest ex
     delegator.validate();
   }
 
-
+  @SuppressWarnings("unchecked")
   @Test
   public void testGetMetadata() throws Exception {
     GadgetsHandlerApi.MetadataRequest request = createMetadataRequest(
@@ -79,7 +81,8 @@ public class GadgetHandlerServiceTest ex
     EasyMock.expect(mockRegistry.getFeatures(EasyMock.isA(List.class)))
         .andReturn(Lists.newArrayList("auth-refresh"));
     replay();
-    GadgetsHandlerApi.MetadataResponse response = gadgetHandler.getMetadata(request);
+    GadgetsHandlerApi.MetadataResponse response =
+        gadgetHandler.getMetadata(request);
     assertEquals(FakeIframeUriManager.DEFAULT_IFRAME_URI.toString(), response.getIframeUrl());
     assertTrue(response.getNeedsTokenRefresh());
     assertEquals(1, response.getViews().size());
@@ -101,11 +104,12 @@ public class GadgetHandlerServiceTest ex
         FakeProcessor.SPEC_URL, CONTAINER, null,
         createTokenData(null, null), ImmutableList.of("views.*"));
     replay();
-    GadgetsHandlerApi.MetadataResponse response = gadgetHandler.getMetadata(request);
+    GadgetsHandlerApi.MetadataResponse response =
+        gadgetHandler.getMetadata(request);
     assertNull(response.getIframeUrl());
     assertNull(response.getUserPrefs());
     assertNull(response.getModulePrefs());
-    assertEquals(FakeProcessor.SPEC_URL, response.getUrl());
+    assertNull(response.getUrl());
     assertEquals(1, response.getViews().size());
     assertTrue(response.getViews().get("default").getContent().contains("Hello, world" ));
     verify();
@@ -117,7 +121,7 @@ public class GadgetHandlerServiceTest ex
         FakeProcessor.SPEC_URL, null, null,
         createTokenData(null, null), ImmutableList.of("*"));
     replay();
-    GadgetsHandlerApi.MetadataResponse response = gadgetHandler.getMetadata(request);
+    GadgetsHandlerApi.BaseResponse response = gadgetHandler.getMetadata(request);
   }
 
   @Test(expected = ProcessingException.class)
@@ -126,7 +130,8 @@ public class GadgetHandlerServiceTest ex
         null, CONTAINER, null,
         createTokenData(null, null), ImmutableList.of("*"));
     replay();
-    GadgetsHandlerApi.MetadataResponse response = gadgetHandler.getMetadata(request);
+    GadgetsHandlerApi.MetadataResponse response =
+        gadgetHandler.getMetadata(request);
   }
 
   @Test(expected = ProcessingException.class)
@@ -147,6 +152,7 @@ public class GadgetHandlerServiceTest ex
     GadgetsHandlerApi.MetadataResponse response = gadgetHandler.getMetadata(request);
   }
 
+  @SuppressWarnings("unchecked")
   @Test
   public void testGetMetadataNoToken() throws Exception {
     GadgetsHandlerApi.MetadataRequest request = createMetadataRequest(

Modified: shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/servlet/GadgetsHandlerTest.java
URL: http://svn.apache.org/viewvc/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/servlet/GadgetsHandlerTest.java?rev=1001115&r1=1001114&r2=1001115&view=diff
==============================================================================
--- shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/servlet/GadgetsHandlerTest.java (original)
+++ shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/servlet/GadgetsHandlerTest.java Sat Sep 25 00:59:30 2010
@@ -29,6 +29,7 @@ import org.apache.shindig.common.EasyMoc
 import org.apache.shindig.common.JsonAssert;
 import org.apache.shindig.common.testing.FakeGadgetToken;
 import org.apache.shindig.common.testing.TestExecutorService;
+import org.apache.shindig.common.util.FakeTimeSource;
 import org.apache.shindig.gadgets.process.ProcessingException;
 import org.apache.shindig.gadgets.spec.GadgetSpec;
 import org.apache.shindig.protocol.DefaultHandlerRegistry;
@@ -48,7 +49,6 @@ import org.junit.Test;
 
 import java.util.Collections;
 import java.util.Map;
-import java.util.concurrent.ExecutionException;
 
 import javax.servlet.http.HttpServletResponse;
 
@@ -58,6 +58,7 @@ public class GadgetsHandlerTest extends 
   private static final String CONTAINER = "container";
   private static final String TOKEN = "_nekot_";
 
+  private final FakeTimeSource timeSource = new FakeTimeSource();
   private final FakeProcessor processor = new FakeProcessor();
   private final FakeIframeUriManager urlGenerator = new FakeIframeUriManager();
   private final Map<String, FormDataItem> emptyFormItems = Collections.emptyMap();
@@ -78,7 +79,7 @@ public class GadgetsHandlerTest extends 
   private void registerGadgetsHandler(SecurityTokenCodec codec) {
     BeanFilter beanFilter = new BeanFilter();
     GadgetsHandlerService service =
-        new GadgetsHandlerService(processor, urlGenerator, codec, beanFilter);
+        new GadgetsHandlerService(timeSource, processor, urlGenerator, codec, beanFilter);
     GadgetsHandler handler =
         new GadgetsHandler(new TestExecutorService(), service, beanFilter);
     registry = new DefaultHandlerRegistry(
@@ -96,6 +97,14 @@ public class GadgetsHandlerTest extends 
     return req;
   }
 
+  private JSONObject makeMetadataNoContainerRequest(String... uris)
+      throws JSONException {
+    JSONObject req =
+      new JSONObject().put("method", "gadgets.metadata").put("id", "req1").put("params",
+          new JSONObject().put("ids", ImmutableList.copyOf(uris)));
+    return req;
+  }
+
   private JSONObject makeTokenRequest(String... uris) throws JSONException {
     JSONObject req =
         new JSONObject().put("method", "gadgets.token").put("id", "req1").put("params",
@@ -113,6 +122,19 @@ public class GadgetsHandlerTest extends 
   }
 
   @Test
+  public void testMetadataNoContainerRequest() throws Exception {
+    registerGadgetsHandler(null);
+    JSONObject request = makeMetadataNoContainerRequest(GADGET1_URL);
+    RpcHandler operation = registry.getRpcHandler(request);
+    try {
+      Object empty = operation.execute(emptyFormItems, token, converter).get();
+      fail("Missing container");
+    } catch (Exception e) {
+      assertTrue(e.getMessage().contains("Missing container"));
+    }
+  }
+
+  @Test
   public void testTokenEmptyRequest() throws Exception {
     registerGadgetsHandler(null);
     JSONObject request = makeTokenRequest();
@@ -121,20 +143,30 @@ public class GadgetsHandlerTest extends 
     JsonAssert.assertJsonEquals("{}", converter.convertToString(empty));
   }
 
-  @Test(expected = ExecutionException.class)
+  @Test
   public void testMetadataInvalidUrl() throws Exception {
     registerGadgetsHandler(null);
-    JSONObject request = makeMetadataRequest(null, null, "[moo]");
+    String badUrl = "[moo]";
+    JSONObject request = makeMetadataRequest(null, null, badUrl);
     RpcHandler operation = registry.getRpcHandler(request);
-    operation.execute(emptyFormItems, token, converter).get();
+    Object responseObj = operation.execute(emptyFormItems, token, converter).get();
+    JSONObject response = new JSONObject(converter.convertToString(responseObj));
+    JSONObject gadget = response.getJSONObject(badUrl);
+    assertEquals("Bad url - " + badUrl, gadget.getJSONObject("error").getString("message"));
+    assertEquals(400, gadget.getJSONObject("error").getInt("code"));
   }
 
-  @Test(expected = ExecutionException.class)
+  @Test
   public void testTokenInvalidUrl() throws Exception {
     registerGadgetsHandler(null);
-    JSONObject request = makeTokenRequest("[moo]");
+    String badUrl = "[moo]";
+    JSONObject request = makeTokenRequest(badUrl);
     RpcHandler operation = registry.getRpcHandler(request);
-    operation.execute(emptyFormItems, token, converter).get();
+    Object responseObj = operation.execute(emptyFormItems, token, converter).get();
+    JSONObject response = new JSONObject(converter.convertToString(responseObj));
+    JSONObject gadget = response.getJSONObject(badUrl);
+    assertEquals("Bad url - " + badUrl, gadget.getJSONObject("error").getString("message"));
+    assertEquals(400, gadget.getJSONObject("error").getInt("code"));
   }
 
   @Test
@@ -148,7 +180,8 @@ public class GadgetsHandlerTest extends 
     JSONObject gadget = response.getJSONObject(GADGET1_URL);
     assertEquals(FakeIframeUriManager.DEFAULT_IFRAME_URI.toString(), gadget.getString("iframeUrl"));
     assertEquals(FakeProcessor.SPEC_TITLE, gadget.getJSONObject("modulePrefs").getString("title"));
-
+    assertFalse(gadget.has("error"));
+    assertFalse(gadget.has("url")); // filtered out
     JSONObject view = gadget.getJSONObject("views").getJSONObject(GadgetSpec.DEFAULT_VIEW);
     assertEquals(FakeProcessor.PREFERRED_HEIGHT, view.getInt("preferredHeight"));
     assertEquals(FakeProcessor.PREFERRED_WIDTH, view.getInt("preferredWidth"));
@@ -181,7 +214,7 @@ public class GadgetsHandlerTest extends 
   public void testTokenOneGadget() throws Exception {
     SecurityTokenCodec codec = EasyMock.createMock(SecurityTokenCodec.class);
     Capture<SecurityToken> tokenCapture = new Capture<SecurityToken>();
-    EasyMock.expect(codec.encodeToken(EasyMock.capture(tokenCapture))).andReturn(TOKEN);
+    EasyMock.expect(codec.encodeToken(EasyMock.capture(tokenCapture))).andReturn(TOKEN).anyTimes();
     replay(codec);
 
     registerGadgetsHandler(codec);
@@ -193,6 +226,7 @@ public class GadgetsHandlerTest extends 
     JSONObject gadget = response.getJSONObject(GADGET1_URL);
     assertEquals(TOKEN, gadget.getString("token"));
     assertFalse(gadget.has("error"));
+    assertFalse(gadget.has("url")); // filtered out
     // next checks verify all fiels that canbe used for token generation are passed in
     assertEquals("container", tokenCapture.getValue().getContainer());
     assertEquals(GADGET1_URL, tokenCapture.getValue().getAppId());
@@ -211,7 +245,9 @@ public class GadgetsHandlerTest extends 
     JSONObject response = new JSONObject(converter.convertToString(responseObj));
 
     JSONObject gadget = response.getJSONObject(GADGET1_URL);
-    assertEquals(GadgetsHandler.FAILURE_METADATA, gadget.getString("error"));
+    assertEquals(GadgetsHandler.FAILURE_METADATA,
+        gadget.getJSONObject("error").getString("message"));
+    assertEquals(500, gadget.getJSONObject("error").getInt("code"));
   }
 
   @Test
@@ -229,7 +265,9 @@ public class GadgetsHandlerTest extends 
 
     JSONObject gadget = response.getJSONObject(GADGET1_URL);
     assertFalse(gadget.has("token"));
-    assertEquals(GadgetsHandler.FAILURE_TOKEN, gadget.getString("error"));
+    assertEquals(GadgetsHandler.FAILURE_TOKEN,
+        gadget.getJSONObject("error").getString("message"));
+    assertEquals(500, gadget.getJSONObject("error").getInt("code"));
   }
 
   @Test
@@ -269,7 +307,9 @@ public class GadgetsHandlerTest extends 
 
     JSONObject gadget2 = response.getJSONObject(GADGET2_URL);
     assertFalse(gadget2.has("token"));
-    assertEquals(GadgetsHandler.FAILURE_TOKEN, gadget2.getString("error"));
+    assertEquals(GadgetsHandler.FAILURE_TOKEN,
+        gadget2.getJSONObject("error").getString("message"));
+    assertEquals(500, gadget2.getJSONObject("error").getInt("code"));
   }
 
   @Test
@@ -287,6 +327,9 @@ public class GadgetsHandlerTest extends 
 
     JSONObject gadget2 = response.getJSONObject(GADGET2_URL);
     assertNotNull("got gadget2", gadget2);
-    assertEquals(GadgetsHandler.FAILURE_METADATA, gadget2.getString("error"));
+    assertEquals("broken", // Processing exception message is used
+        gadget2.getJSONObject("error").getString("message"));
+    assertEquals(HttpServletResponse.SC_BAD_REQUEST,
+        gadget2.getJSONObject("error").getInt("code"));
   }
 }