Author: zhoresh
Date: Sat Aug 21 00:52:53 2010
New Revision: 987680
URL: http://svn.apache.org/viewvc?rev=987680&view=rev
Log:
http://codereview.appspot.com/1925042/
GadgetHandler restructure step 2: separate data construction
(GadgetHandlerService) and JSON api (GadgetHandler)
Added:
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
Modified:
shindig/trunk/java/common/src/main/java/org/apache/shindig/protocol/conversion/BeanDelegator.java
shindig/trunk/java/common/src/main/java/org/apache/shindig/protocol/conversion/BeanFilter.java
shindig/trunk/java/common/src/test/java/org/apache/shindig/protocol/conversion/BeanDelegatorTest.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/test/java/org/apache/shindig/gadgets/servlet/GadgetsHandlerTest.java
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=987680&r1=987679&r2=987680&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 Aug 21 00:52:53 2010
@@ -48,6 +48,11 @@ import java.util.Map;
*/
public class BeanDelegator {
+ /** Indicate NULL value for a field (To overcome shortcome of immutable map)
*/
+ public static final String NULL = "NULL";
+
+ private static final Map<String, Object> EMPTY_FIELDS = ImmutableMap.of();
+
/** List of Classes that are considered primitives and are not proxied **/
public static final ImmutableSet<Class<?>> PRIMITIVE_TYPE_CLASSES =
ImmutableSet.of(
String.class, Integer.class, Long.class, Boolean.class, Uri.class);
@@ -57,6 +62,11 @@ public class BeanDelegator {
private final Map<Enum<?>, Enum<?>> enumConvertionMap;
+ public BeanDelegator() {
+ this(ImmutableMap.<Class<?>, Class<?>>of(),
+ ImmutableMap.<Enum<?>, Enum<?>>of());
+ }
+
public BeanDelegator(Map<Class<?>, Class<?>> delegatedClasses,
Map<Enum<?>, Enum<?>> enumConvertionMap) {
this.delegatedClasses = delegatedClasses;
@@ -69,7 +79,7 @@ public class BeanDelegator {
* @return proxied object according to map of classes to proxy
*/
public Object createDelegator(Object source) {
- if (source == null || delegatedClasses == null || delegatedClasses.size()
== 0) {
+ if (source == null || delegatedClasses == null) {
return null;
}
@@ -113,12 +123,23 @@ public class BeanDelegator {
if (delegatedClasses.containsKey(source.getClass())) {
Class<?> apiInterface = delegatedClasses.get(source.getClass());
- return Proxy.newProxyInstance( apiInterface.getClassLoader(),
- new Class[] { apiInterface }, new DelegateInvocationHandler(source));
+ return createDelegator(source, apiInterface);
}
return source;
}
+ @SuppressWarnings("unchecked")
+ public <T> T createDelegator(Object source, Class<T> apiInterface) {
+ return createDelegator(source, apiInterface, EMPTY_FIELDS);
+ }
+
+ @SuppressWarnings("unchecked")
+ public <T> T createDelegator(Object source, Class<T> apiInterface,
+ Map<String, Object> extraFields) {
+ return (T) Proxy.newProxyInstance( apiInterface.getClassLoader(),
+ new Class[] { apiInterface }, new DelegateInvocationHandler(source,
extraFields));
+ }
+
public Enum<?> convertEnum(Enum<?> value) {
if (enumConvertionMap.containsKey(value)) {
return enumConvertionMap.get(value);
@@ -129,10 +150,18 @@ public class BeanDelegator {
protected class DelegateInvocationHandler implements InvocationHandler {
/** Proxied object */
private final Object source;
+ /** Use the next values instead of proxying source */
+ private final Map<String, Object> extraFields;
public DelegateInvocationHandler(Object source) {
+ this(source, EMPTY_FIELDS);
+ }
+
+ public DelegateInvocationHandler(Object source, Map<String, Object>
extraFields) {
Preconditions.checkNotNull(source);
+ Preconditions.checkNotNull(extraFields);
this.source = source;
+ this.extraFields = extraFields;
}
/**
@@ -141,6 +170,14 @@ public class BeanDelegator {
*/
public Object invoke(Object proxy, Method method, Object[] args) {
Class<?> sourceClass = source.getClass();
+ // Return proxy fields if available
+ if (!extraFields.isEmpty() && method.getName().startsWith("get")) {
+ String field = method.getName().substring(3).toLowerCase();
+ if (extraFields.containsKey(field)) {
+ Object data = extraFields.get(field);
+ return (data == NULL ? null : data);
+ }
+ }
try {
Method sourceMethod = sourceClass.getMethod(
method.getName(), method.getParameterTypes());
@@ -162,6 +199,7 @@ public class BeanDelegator {
/**
* Validate all proxied classes to see that all required functions are
implemented.
* Throws exception if failed validation.
+ * Note that it ignore the extra fields support.
* @throws SecurityException
* @throws NoSuchMethodException
* @throws NoSuchFieldException
Modified:
shindig/trunk/java/common/src/main/java/org/apache/shindig/protocol/conversion/BeanFilter.java
URL:
http://svn.apache.org/viewvc/shindig/trunk/java/common/src/main/java/org/apache/shindig/protocol/conversion/BeanFilter.java?rev=987680&r1=987679&r2=987680&view=diff
==============================================================================
---
shindig/trunk/java/common/src/main/java/org/apache/shindig/protocol/conversion/BeanFilter.java
(original)
+++
shindig/trunk/java/common/src/main/java/org/apache/shindig/protocol/conversion/BeanFilter.java
Sat Aug 21 00:52:53 2010
@@ -34,6 +34,7 @@ import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Proxy;
import java.lang.reflect.Type;
+import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -60,7 +61,7 @@ public class BeanFilter {
/** Annotation for required field that should not be filtered */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
- public @interface Required {}
+ public @interface Unfiltered {}
/**
* Create a proxy object that filter object fields according to set of
fields.
@@ -131,7 +132,7 @@ public class BeanFilter {
// Do not filter out primitive types, it will result in NPE
&& !method.getReturnType().isPrimitive()) {
// Look for Required annotation
- boolean required = (method.getAnnotation(Required.class) != null);
+ boolean required = (method.getAnnotation(Unfiltered.class) != null);
fieldName = prefix + method.getName().substring(3).toLowerCase();
if (!required && !fields.contains(fieldName)) {
return null;
@@ -157,7 +158,7 @@ public class BeanFilter {
}
}
- public Set<String> processBeanFields(Set<String> fields) {
+ public Set<String> processBeanFields(Collection<String> fields) {
ImmutableSet.Builder<String> builder = ImmutableSet.builder();
for (String field : fields) {
builder.add(field.toLowerCase());
Modified:
shindig/trunk/java/common/src/test/java/org/apache/shindig/protocol/conversion/BeanDelegatorTest.java
URL:
http://svn.apache.org/viewvc/shindig/trunk/java/common/src/test/java/org/apache/shindig/protocol/conversion/BeanDelegatorTest.java?rev=987680&r1=987679&r2=987680&view=diff
==============================================================================
---
shindig/trunk/java/common/src/test/java/org/apache/shindig/protocol/conversion/BeanDelegatorTest.java
(original)
+++
shindig/trunk/java/common/src/test/java/org/apache/shindig/protocol/conversion/BeanDelegatorTest.java
Sat Aug 21 00:52:53 2010
@@ -23,10 +23,11 @@ import com.google.common.collect.Immutab
import junit.framework.Assert;
-import org.apache.shindig.protocol.conversion.BeanFilter.Required;
+import org.apache.shindig.protocol.conversion.BeanFilter.Unfiltered;
import org.junit.Before;
import org.junit.Test;
+import java.beans.BeanInfo;
import java.util.List;
import java.util.Map;
@@ -53,7 +54,7 @@ public class BeanDelegatorTest extends A
public Style getStyle();
// Test of required
- @Required
+ @Unfiltered
public String getRequired();
}
@@ -197,6 +198,26 @@ public class BeanDelegatorTest extends A
assertEquals(item.getS(), interMap.get("item").getS());
}
+ class TokenData {
+ public String getId() { return "id"; }
+ }
+
+ interface TokenInter {
+ public String getId();
+ public String getContainer();
+ }
+
+ @Test
+ public void testExtraFields() {
+ TokenData data = new TokenData();
+ String container = "data";
+ TokenInter p = beanDelegator.createDelegator(data, TokenInter.class,
+ ImmutableMap.<String, Object>of("container", container));
+
+ assertSame(data.getId(), p.getId());
+ assertSame(container, p.getContainer());
+ }
+
// Make sure validate will actually fail
@Test(expected = NoSuchMethodException.class)
public void tesValidate() throws Exception {
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=987680&r1=987679&r2=987680&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 Aug 21 00:52:53 2010
@@ -20,25 +20,14 @@ package org.apache.shindig.gadgets.servl
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.shindig.auth.SecurityToken;
-import org.apache.shindig.auth.SecurityTokenCodec;
import org.apache.shindig.common.uri.Uri;
-import org.apache.shindig.gadgets.Gadget;
import org.apache.shindig.gadgets.GadgetContext;
-import org.apache.shindig.gadgets.RenderingContext;
-import org.apache.shindig.gadgets.process.Processor;
-import org.apache.shindig.gadgets.spec.Feature;
import org.apache.shindig.gadgets.spec.GadgetSpec;
-import org.apache.shindig.gadgets.spec.LinkSpec;
-import org.apache.shindig.gadgets.spec.ModulePrefs;
-import org.apache.shindig.gadgets.spec.UserPref;
-import org.apache.shindig.gadgets.spec.View;
-import org.apache.shindig.gadgets.spec.UserPref.EnumValuePair;
-import org.apache.shindig.gadgets.uri.IframeUriManager;
import org.apache.shindig.protocol.BaseRequestItem;
import org.apache.shindig.protocol.Operation;
import org.apache.shindig.protocol.ProtocolException;
@@ -47,6 +36,7 @@ import org.apache.shindig.protocol.Servi
import org.apache.shindig.protocol.conversion.BeanDelegator;
import org.apache.shindig.protocol.conversion.BeanFilter;
+import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
@@ -65,63 +55,29 @@ public class GadgetsHandler {
@VisibleForTesting
static final String FAILURE_TOKEN = "Failed to get gadget token.";
- private static final Set<String> DEFAULT_METADATA_FIELDS =
- ImmutableSet.of("iframeUrl", "userPrefs.*", "modulePrefs.*", "views.*",
"token");
+ private static final List<String> DEFAULT_METADATA_FIELDS =
+ ImmutableList.of("iframeUrl", "userPrefs.*", "modulePrefs.*", "views.*",
"token");
+
+ private static final List<String> DEFAULT_TOKEN_FIELDS =
ImmutableList.of("token");
protected final ExecutorService executor;
- protected final Processor processor;
- protected final IframeUriManager iframeUriManager;
- protected final SecurityTokenCodec securityTokenCodec;
+ protected final GadgetsHandlerService handlerService;
- protected final BeanDelegator beanDelegator;
protected final BeanFilter beanFilter;
-
- // Map shindig data class to API interfaces
- @VisibleForTesting
- static final Map<Class<?>, Class<?>> apiClasses =
- new ImmutableMap.Builder<Class<?>, Class<?>>()
- .put(BaseResponseData.class, GadgetsHandlerApi.BaseResponse.class)
- .put(MetadataResponseData.class,
GadgetsHandlerApi.MetadataResponse.class)
- .put(TokenResponseData.class, GadgetsHandlerApi.TokenResponse.class)
- .put(View.class, GadgetsHandlerApi.View.class)
- .put(UserPref.class, GadgetsHandlerApi.UserPref.class)
- .put(EnumValuePair.class, GadgetsHandlerApi.EnumValuePair.class)
- .put(ModulePrefs.class, GadgetsHandlerApi.ModulePrefs.class)
- .put(Feature.class, GadgetsHandlerApi.Feature.class)
- .put(LinkSpec.class, GadgetsHandlerApi.LinkSpec.class)
- // Enums
- .put(View.ContentType.class, GadgetsHandlerApi.ViewContentType.class)
- .put(UserPref.DataType.class,
GadgetsHandlerApi.UserPrefDataType.class)
- .build();
-
- // Provide mapping for internal enums to api enums
- @VisibleForTesting
- static final Map<Enum<?>, Enum<?>> enumConversionMap =
- new ImmutableMap.Builder<Enum<?>, Enum<?>>()
- // View.ContentType mapping
- .putAll(BeanDelegator.createDefaultEnumMap(View.ContentType.class,
- GadgetsHandlerApi.ViewContentType.class))
- // UserPref.DataType mapping
- .putAll(BeanDelegator.createDefaultEnumMap(UserPref.DataType.class,
- GadgetsHandlerApi.UserPrefDataType.class))
- .build();
+ protected final BeanDelegator beanDelegator;
@Inject
- public GadgetsHandler(ExecutorService executor, Processor processor,
- IframeUriManager iframeUriManager, SecurityTokenCodec securityTokenCodec,
- BeanFilter beanFilter) {
+ public GadgetsHandler(ExecutorService executor, GadgetsHandlerService
handlerService,
+ BeanFilter beanFilter) {
this.executor = executor;
- this.processor = processor;
- this.iframeUriManager = iframeUriManager;
- this.securityTokenCodec = securityTokenCodec;
+ this.handlerService = handlerService;
this.beanFilter = beanFilter;
- // TODO: maybe make this injectable
- this.beanDelegator = new BeanDelegator(apiClasses, enumConversionMap);
+ this.beanDelegator = new BeanDelegator();
}
@Operation(httpMethods = {"POST", "GET"}, path = "metadata.get")
- public Map<String, GadgetsHandlerApi.MetadataResponse>
metadata(BaseRequestItem request)
+ public Map<String, GadgetsHandlerApi.BaseResponse> metadata(BaseRequestItem
request)
throws ProtocolException {
return new AbstractExecutor<GadgetsHandlerApi.MetadataResponse>() {
@Override
@@ -133,7 +89,7 @@ public class GadgetsHandler {
}
@Operation(httpMethods = {"POST", "GET"}, path = "token.get")
- public Map<String, GadgetsHandlerApi.TokenResponse> token(BaseRequestItem
request)
+ public Map<String, GadgetsHandlerApi.BaseResponse> token(BaseRequestItem
request)
throws ProtocolException {
return new AbstractExecutor<GadgetsHandlerApi.TokenResponse>() {
@Override
@@ -158,7 +114,7 @@ public class GadgetsHandler {
private abstract class AbstractExecutor<R extends
GadgetsHandlerApi.BaseResponse> {
@SuppressWarnings("unchecked")
- public Map<String, R> execute(BaseRequestItem request) {
+ public Map<String, GadgetsHandlerApi.BaseResponse> execute(BaseRequestItem
request) {
Set<String> gadgetUrls =
ImmutableSet.copyOf(request.getListParameter("ids"));
if (gadgetUrls.isEmpty()) {
return ImmutableMap.of();
@@ -170,12 +126,12 @@ public class GadgetsHandler {
completionService.submit(job);
}
- ImmutableMap.Builder<String, R> builder = ImmutableMap.builder();
+ ImmutableMap.Builder<String, GadgetsHandlerApi.BaseResponse> builder =
ImmutableMap.builder();
for (int numJobs = gadgetUrls.size(); numJobs > 0; numJobs--) {
R response;
try {
response = completionService.take().get();
- builder.put(response.getUrl(), response);
+ builder.put(response.getUrl().toString(), response);
} catch (InterruptedException e) {
throw new
ProtocolException(HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
"Processing interrupted.", e);
@@ -187,10 +143,10 @@ public class GadgetsHandler {
RpcException cause = (RpcException) e.getCause();
GadgetContext context = cause.getContext();
if (context != null) {
- String url = context.getUrl().toString();
- R errorResponse =
- (R) beanDelegator.createDelegator(new BaseResponseData(url,
cause.getMessage()));
- builder.put(url, errorResponse);
+ Uri url = context.getUrl();
+ GadgetsHandlerApi.BaseResponse errorResponse =
+ handlerService.createBaseResponse(url, cause.getMessage());
+ builder.put(url.toString(), errorResponse);
}
}
}
@@ -203,23 +159,14 @@ public class GadgetsHandler {
// Hook to override in sub-class.
protected Callable<GadgetsHandlerApi.MetadataResponse>
createMetadataJob(String url,
BaseRequestItem request) {
- final GadgetContext context = new MetadataGadgetContext(url, request);
- final Set<String> fields =
-
beanFilter.processBeanFields(request.getFields(DEFAULT_METADATA_FIELDS));
+ final MetadataRequestData metadataRequest = new MetadataRequestData(url,
request);
return new Callable<GadgetsHandlerApi.MetadataResponse>() {
public GadgetsHandlerApi.MetadataResponse call() throws Exception {
try {
- Gadget gadget = processor.process(context);
- String iframeUrl =
- fields.contains("iframeurl") ?
iframeUriManager.makeRenderingUri(gadget).toString()
- : null;
- MetadataResponseData response =
- new MetadataResponseData(context.getUrl().toString(),
gadget.getSpec(), iframeUrl);
- return (GadgetsHandlerApi.MetadataResponse)
beanFilter.createFilteredBean(beanDelegator
- .createDelegator(response), fields);
+ return handlerService.getMetadata(metadataRequest);
} catch (Exception e) {
- // Note: this error message is publicly visible in JSON-RPC response.
- throw new RpcException(context, FAILURE_METADATA, e);
+ sendError(metadataRequest.getUrl(), e, FAILURE_METADATA);
+ return null;
}
}
};
@@ -228,63 +175,87 @@ public class GadgetsHandler {
// Hook to override in sub-class.
protected Callable<GadgetsHandlerApi.TokenResponse> createTokenJob(String
url,
BaseRequestItem request) {
- final TokenGadgetContext context = new TokenGadgetContext(url, request);
- final Set<String> fields =
-
beanFilter.processBeanFields(request.getFields(DEFAULT_METADATA_FIELDS));
+ final TokenRequestData tokenRequest = new TokenRequestData(url, request);
return new Callable<GadgetsHandlerApi.TokenResponse>() {
public GadgetsHandlerApi.TokenResponse call() throws Exception {
try {
- String token = securityTokenCodec.encodeToken(context.getToken());
- TokenResponseData response = new
TokenResponseData(context.getUrl().toString(), token);
- return (GadgetsHandlerApi.TokenResponse)
beanFilter.createFilteredBean(beanDelegator
- .createDelegator(response), fields);
+ return handlerService.getToken(tokenRequest);
} catch (Exception e) {
- // Note: this error message is publicly visible in JSON-RPC response.
- throw new RpcException(context, FAILURE_TOKEN, e);
+ sendError(tokenRequest.getUrl(), e, FAILURE_TOKEN);
+ return null;
}
}
};
}
+ 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.
*/
-
- private abstract class AbstractGadgetContext extends GadgetContext {
+ private abstract class AbstractRequest implements
GadgetsHandlerApi.BaseRequest {
protected final Uri uri;
protected final String container;
+ protected final List<String> fields;
protected final BaseRequestItem request;
- public AbstractGadgetContext(String url, 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"));
+ this.fields = processFields(request, defaultFields);
}
- @Override
public Uri getUrl() {
return uri;
}
- @Override
public String getContainer() {
return container;
}
- @Override
- public RenderingContext getRenderingContext() {
- return RenderingContext.METADATA;
+ public List<String> getFields() {
+ return fields;
+ }
+
+ private List<String> processFields(BaseRequestItem request, List<String>
defaultList) {
+ List<String> value = request.getListParameter(BaseRequestItem.FIELDS);
+ return ((value == null || value.size() == 0) ? defaultList : value);
}
}
- protected class MetadataGadgetContext extends AbstractGadgetContext {
+
+ protected class TokenRequestData extends AbstractRequest
+ implements GadgetsHandlerApi.TokenRequest {
+
+ public TokenRequestData(String url, BaseRequestItem request) {
+ super(url, request, DEFAULT_TOKEN_FIELDS);
+ }
+
+ public GadgetsHandlerApi.TokenData getToken() {
+ return beanDelegator.createDelegator(
+ request.getToken(), GadgetsHandlerApi.TokenData.class);
+ }
+ }
+
+
+ protected class MetadataRequestData extends AbstractRequest
+ implements GadgetsHandlerApi.MetadataRequest {
protected final Locale locale;
protected final boolean ignoreCache;
protected final boolean debug;
- public MetadataGadgetContext(String url, BaseRequestItem request) {
- super(url, request);
+ public MetadataRequestData(String url, BaseRequestItem request) {
+ super(url, request, DEFAULT_METADATA_FIELDS);
String lang = request.getParameter("language");
String country = request.getParameter("country");
this.locale =
@@ -294,120 +265,29 @@ public class GadgetsHandler {
this.debug = Boolean.valueOf(request.getParameter("debug"));
}
- @Override
public int getModuleId() {
return 1; // TODO calculate?
}
- @Override
public Locale getLocale() {
return locale;
}
- @Override
public boolean getIgnoreCache() {
return ignoreCache;
}
- @Override
public boolean getDebug() {
return debug;
}
- @Override
public String getView() {
return request.getParameter("view", "default");
}
- @Override
- public SecurityToken getToken() {
- return request.getToken();
- }
- }
-
- protected class TokenGadgetContext extends AbstractGadgetContext {
- public TokenGadgetContext(String url, BaseRequestItem request) {
- super(url, request);
- }
-
- @Override
- public SecurityToken getToken() {
- return request.getToken();
- }
- }
-
- /**
- * Response classes to represent data structure returned in JSON to common
- * container JS. They must be public for reflection to work.
- */
-
- public static class BaseResponseData {
- private final String url;
- private final String error;
-
- // Call this to indicate an error.
- public BaseResponseData(String url, String error) {
- this.url = url;
- this.error = error;
- }
-
- // Have sub-class call this to indicate a success response.
- protected BaseResponseData(String url) {
- this(url, null);
- }
-
- public String getUrl() {
- return url;
- }
-
- public String getError() {
- return error;
+ public GadgetsHandlerApi.TokenData getToken() {
+ return beanDelegator.createDelegator(
+ request.getToken(), GadgetsHandlerApi.TokenData.class);
}
}
-
- public static class MetadataResponseData extends BaseResponseData {
- private final GadgetSpec spec;
- private final String iframeUrl;
-
- public MetadataResponseData(String url, GadgetSpec spec, String iframeUrl)
{
- super(url);
- this.spec = spec;
- this.iframeUrl = iframeUrl;
- }
-
- public String getIframeUrl() {
- return iframeUrl;
- }
-
- public String getChecksum() {
- return spec.getChecksum();
- }
-
- public ModulePrefs getModulePrefs() {
- return spec.getModulePrefs();
- }
-
- public Map<String, UserPref> getUserPrefs() {
- return spec.getUserPrefs();
- }
-
- public Map<String, View> getViews() {
- return spec.getViews();
- }
- }
-
-
- public static class TokenResponseData extends BaseResponseData {
- private final String token;
-
- public TokenResponseData(String url, String token) {
- super(url);
- this.token = token;
- }
-
- public String getToken() {
- return token;
- }
- }
-
}
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=987680&r1=987679&r2=987680&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 Aug 21 00:52:53 2010
@@ -19,10 +19,11 @@
package org.apache.shindig.gadgets.servlet;
import org.apache.shindig.common.uri.Uri;
-import org.apache.shindig.protocol.conversion.BeanFilter.Required;
+import org.apache.shindig.protocol.conversion.BeanFilter.Unfiltered;
// Keep imports clean, so it is clear what is used by API
import java.util.List;
+import java.util.Locale;
import java.util.Map;
/**
@@ -33,10 +34,33 @@ import java.util.Map;
*/
public class GadgetsHandlerApi {
+ public interface BaseRequest {
+ public Uri getUrl();
+ public String getContainer();
+ public List<String> getFields();
+ }
+
+ public interface MetadataRequest extends BaseRequest {
+ public Locale getLocale();
+ public boolean getIgnoreCache();
+ public boolean getDebug();
+ public String getView();
+ public TokenData getToken();
+ }
+
+ public interface TokenData {
+ public String getOwnerId();
+ public String getViewerId();
+ }
+
+ public interface TokenRequest extends BaseRequest {
+ public TokenData getToken();
+ }
+
public interface BaseResponse {
- @Required
- public String getUrl();
- @Required
+ @Unfiltered
+ public Uri getUrl();
+ @Unfiltered
public String getError();
}
Added:
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=987680&view=auto
==============================================================================
---
shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/GadgetsHandlerService.java
(added)
+++
shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/GadgetsHandlerService.java
Sat Aug 21 00:52:53 2010
@@ -0,0 +1,220 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.shindig.gadgets.servlet;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.collect.ImmutableMap;
+import com.google.inject.Inject;
+
+import org.apache.shindig.auth.SecurityToken;
+import org.apache.shindig.auth.SecurityTokenCodec;
+import org.apache.shindig.auth.SecurityTokenException;
+import org.apache.shindig.common.uri.Uri;
+import org.apache.shindig.gadgets.Gadget;
+import org.apache.shindig.gadgets.GadgetContext;
+import org.apache.shindig.gadgets.RenderingContext;
+import org.apache.shindig.gadgets.process.ProcessingException;
+import org.apache.shindig.gadgets.process.Processor;
+import org.apache.shindig.gadgets.spec.Feature;
+import org.apache.shindig.gadgets.spec.GadgetSpec;
+import org.apache.shindig.gadgets.spec.LinkSpec;
+import org.apache.shindig.gadgets.spec.ModulePrefs;
+import org.apache.shindig.gadgets.spec.UserPref;
+import org.apache.shindig.gadgets.spec.View;
+import org.apache.shindig.gadgets.spec.UserPref.EnumValuePair;
+import org.apache.shindig.gadgets.uri.IframeUriManager;
+import org.apache.shindig.protocol.conversion.BeanDelegator;
+import org.apache.shindig.protocol.conversion.BeanFilter;
+
+import java.util.Locale;
+import java.util.Map;
+import java.util.Set;
+
+public class GadgetsHandlerService {
+
+ // Map shindig data class to API interfaces
+ @VisibleForTesting
+ static final Map<Class<?>, Class<?>> apiClasses =
+ new ImmutableMap.Builder<Class<?>, Class<?>>()
+ .put(View.class, GadgetsHandlerApi.View.class)
+ .put(UserPref.class, GadgetsHandlerApi.UserPref.class)
+ .put(EnumValuePair.class, GadgetsHandlerApi.EnumValuePair.class)
+ .put(ModulePrefs.class, GadgetsHandlerApi.ModulePrefs.class)
+ .put(Feature.class, GadgetsHandlerApi.Feature.class)
+ .put(LinkSpec.class, GadgetsHandlerApi.LinkSpec.class)
+ // Enums
+ .put(View.ContentType.class, GadgetsHandlerApi.ViewContentType.class)
+ .put(UserPref.DataType.class,
GadgetsHandlerApi.UserPrefDataType.class)
+ .build();
+
+ // Provide mapping for internal enums to api enums
+ @VisibleForTesting
+ static final Map<Enum<?>, Enum<?>> enumConversionMap =
+ new ImmutableMap.Builder<Enum<?>, Enum<?>>()
+ // View.ContentType mapping
+ .putAll(BeanDelegator.createDefaultEnumMap(View.ContentType.class,
+ GadgetsHandlerApi.ViewContentType.class))
+ // UserPref.DataType mapping
+ .putAll(BeanDelegator.createDefaultEnumMap(UserPref.DataType.class,
+ GadgetsHandlerApi.UserPrefDataType.class))
+ .build();
+
+ protected final Processor processor;
+ protected final IframeUriManager iframeUriManager;
+ protected final SecurityTokenCodec securityTokenCodec;
+
+ protected final BeanDelegator beanDelegator;
+ protected final BeanFilter beanFilter;
+
+
+
+ @Inject
+ public GadgetsHandlerService(Processor processor,
+ IframeUriManager iframeUriManager, SecurityTokenCodec securityTokenCodec,
+ BeanFilter beanFilter) {
+ this.processor = processor;
+ this.iframeUriManager = iframeUriManager;
+ this.securityTokenCodec = securityTokenCodec;
+ this.beanFilter = beanFilter;
+
+ this.beanDelegator = new BeanDelegator(apiClasses, enumConversionMap);
+ }
+
+ /**
+ * Get gadget metadata information and iframe url. Support filtering of
fields
+ * @param request request parameters
+ * @return gadget metadata nd iframe url
+ * @throws ProcessingException
+ */
+ public GadgetsHandlerApi.MetadataResponse
getMetadata(GadgetsHandlerApi.MetadataRequest request)
+ throws ProcessingException {
+ Set<String> fields = beanFilter.processBeanFields(request.getFields());
+ GadgetContext context = new MetadataGadgetContext(request);
+ Gadget gadget = processor.process(context);
+ String iframeUrl =
+ fields.contains("iframeurl") ?
iframeUriManager.makeRenderingUri(gadget).toString()
+ : null;
+ return createMetadataResponse(context.getUrl(), gadget.getSpec(),
iframeUrl, fields);
+ }
+
+ /**
+ * Create security token
+ * @param request token paramaters (gadget, owner and viewer)
+ * @return Security token
+ * @throws SecurityTokenException
+ */
+ public GadgetsHandlerApi.TokenResponse
getToken(GadgetsHandlerApi.TokenRequest request)
+ throws SecurityTokenException {
+ Set<String> fields = beanFilter.processBeanFields(request.getFields());
+
+ SecurityToken tokenData = convertToken(request.getToken(),
request.getContainer(),
+ request.getUrl().toString());
+ String token = securityTokenCodec.encodeToken(tokenData);
+ return createTokenResponse(request.getUrl(), token, fields);
+ }
+
+ /**
+ * GadgetContext for metadata request. Used by the gadget processor
+ */
+ protected class MetadataGadgetContext extends GadgetContext {
+
+ private final GadgetsHandlerApi.MetadataRequest request;
+ private final SecurityToken token;
+
+ public MetadataGadgetContext(GadgetsHandlerApi.MetadataRequest request) {
+ this.request = request;
+ this.token = convertToken(
+ request.getToken(), request.getContainer(),
request.getUrl().toString());
+ }
+
+ @Override
+ public Uri getUrl() {
+ return request.getUrl();
+ }
+
+ @Override
+ public String getContainer() {
+ return request.getContainer();
+ }
+
+ @Override
+ public RenderingContext getRenderingContext() {
+ return RenderingContext.METADATA;
+ }
+
+ @Override
+ public int getModuleId() {
+ return 1;
+ }
+
+ @Override
+ public Locale getLocale() {
+ return request.getLocale();
+ }
+
+ @Override
+ public boolean getIgnoreCache() {
+ return request.getIgnoreCache();
+ }
+
+ @Override
+ public boolean getDebug() {
+ return request.getDebug();
+ }
+
+ @Override
+ public String getView() {
+ return request.getView();
+ }
+
+ @Override
+ public SecurityToken getToken() {
+ return token;
+ }
+ }
+
+ private SecurityToken convertToken(GadgetsHandlerApi.TokenData token,
+ String container, String url) {
+ return beanDelegator.createDelegator(token, SecurityToken.class,
+ ImmutableMap.<String, Object>of("container", container,
+ "appid", url, "appurl", url));
+ }
+
+ public GadgetsHandlerApi.BaseResponse createBaseResponse(Uri url, String
error) {
+ return beanDelegator.createDelegator(error,
GadgetsHandlerApi.BaseResponse.class,
+ ImmutableMap.<String, Object>of("url", url, "error", error));
+ }
+
+ private GadgetsHandlerApi.MetadataResponse createMetadataResponse(
+ Uri url, GadgetSpec spec, String iframeUrl, Set<String> fields) {
+ return (GadgetsHandlerApi.MetadataResponse) beanFilter.createFilteredBean(
+ beanDelegator.createDelegator(spec,
GadgetsHandlerApi.MetadataResponse.class,
+ ImmutableMap.<String, Object>of("url", url, "error",
BeanDelegator.NULL,
+ "iframeurl", iframeUrl)),
+ fields);
+ }
+
+ private GadgetsHandlerApi.TokenResponse createTokenResponse(
+ Uri url, String token, Set<String> fields) {
+ return (GadgetsHandlerApi.TokenResponse) beanFilter.createFilteredBean(
+ beanDelegator.createDelegator(token,
GadgetsHandlerApi.TokenResponse.class,
+ ImmutableMap.<String, Object>of("url", url, "error",
BeanDelegator.NULL, "token", token)),
+ fields);
+ }
+}
Added:
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=987680&view=auto
==============================================================================
---
shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/servlet/GadgetHandlerServiceTest.java
(added)
+++
shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/servlet/GadgetHandlerServiceTest.java
Sat Aug 21 00:52:53 2010
@@ -0,0 +1,37 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.shindig.gadgets.servlet;
+
+import org.apache.shindig.common.EasyMockTestCase;
+import org.apache.shindig.protocol.conversion.BeanDelegator;
+import org.junit.Test;
+
+public class GadgetHandlerServiceTest extends EasyMockTestCase {
+
+ // Next test verify that the API data classes are configured correctly.
+ // The mapping is done using reflection in runtime, so this test verify
mapping is complete
+ // this test will prevent from not intended change to the API.
+ // DO NOT REMOVE TEST
+ @Test
+ public void testHandlerDataDelegation() throws Exception {
+ BeanDelegator delegator = new BeanDelegator(
+ GadgetsHandlerService.apiClasses,
GadgetsHandlerService.enumConversionMap);
+ delegator.validate();
+ }
+}
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=987680&r1=987679&r2=987680&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 Aug 21 00:52:53 2010
@@ -21,6 +21,8 @@ import com.google.common.collect.Immutab
import com.google.common.collect.ImmutableSet;
import com.google.inject.Guice;
import com.google.inject.Injector;
+
+import org.apache.shindig.auth.SecurityToken;
import org.apache.shindig.auth.SecurityTokenCodec;
import org.apache.shindig.auth.SecurityTokenException;
import org.apache.shindig.common.EasyMockTestCase;
@@ -33,10 +35,10 @@ import org.apache.shindig.protocol.Defau
import org.apache.shindig.protocol.HandlerExecutionListener;
import org.apache.shindig.protocol.HandlerRegistry;
import org.apache.shindig.protocol.RpcHandler;
-import org.apache.shindig.protocol.conversion.BeanDelegator;
import org.apache.shindig.protocol.conversion.BeanFilter;
import org.apache.shindig.protocol.conversion.BeanJsonConverter;
import org.apache.shindig.protocol.multipart.FormDataItem;
+import org.easymock.Capture;
import org.easymock.EasyMock;
import org.json.JSONArray;
import org.json.JSONException;
@@ -74,9 +76,11 @@ public class GadgetsHandlerTest extends
}
private void registerGadgetsHandler(SecurityTokenCodec codec) {
+ BeanFilter beanFilter = new BeanFilter();
+ GadgetsHandlerService service =
+ new GadgetsHandlerService(processor, urlGenerator, codec, beanFilter);
GadgetsHandler handler =
- new GadgetsHandler(new TestExecutorService(), processor, urlGenerator,
codec,
- new BeanFilter());
+ new GadgetsHandler(new TestExecutorService(), service, beanFilter);
registry = new DefaultHandlerRegistry(
injector, converter, new HandlerExecutionListener.NoOpHandler());
registry.addHandlers(ImmutableSet.<Object> of(handler));
@@ -176,7 +180,8 @@ public class GadgetsHandlerTest extends
@Test
public void testTokenOneGadget() throws Exception {
SecurityTokenCodec codec = EasyMock.createMock(SecurityTokenCodec.class);
- EasyMock.expect(codec.encodeToken(token)).andReturn(TOKEN);
+ Capture<SecurityToken> tokenCapture = new Capture<SecurityToken>();
+
EasyMock.expect(codec.encodeToken(EasyMock.capture(tokenCapture))).andReturn(TOKEN);
replay(codec);
registerGadgetsHandler(codec);
@@ -188,6 +193,12 @@ public class GadgetsHandlerTest extends
JSONObject gadget = response.getJSONObject(GADGET1_URL);
assertEquals(TOKEN, gadget.getString("token"));
assertFalse(gadget.has("error"));
+ // 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());
+ assertEquals(GADGET1_URL, tokenCapture.getValue().getAppUrl());
+ assertSame(token.getOwnerId(), tokenCapture.getValue().getOwnerId());
+ assertSame(token.getViewerId(), tokenCapture.getValue().getViewerId());
}
@Test
@@ -206,7 +217,8 @@ public class GadgetsHandlerTest extends
@Test
public void testTokenOneGadgetFailure() throws Exception {
SecurityTokenCodec codec = EasyMock.createMock(SecurityTokenCodec.class);
- EasyMock.expect(codec.encodeToken(token)).andThrow(new
SecurityTokenException("blah"));
+ EasyMock.expect(codec.encodeToken(EasyMock.isA(SecurityToken.class)))
+ .andThrow(new SecurityTokenException("blah"));
replay(codec);
registerGadgetsHandler(codec);
@@ -238,8 +250,10 @@ public class GadgetsHandlerTest extends
@Test
public void testTokenMultipleGadgetsWithSuccessAndFailure() throws Exception
{
SecurityTokenCodec codec = EasyMock.createMock(SecurityTokenCodec.class);
- EasyMock.expect(codec.encodeToken(token)).andReturn(TOKEN);
- EasyMock.expect(codec.encodeToken(token)).andThrow(new
SecurityTokenException("blah"));
+ EasyMock.expect(codec.encodeToken(EasyMock.isA(SecurityToken.class)))
+ .andReturn(TOKEN);
+ EasyMock.expect(codec.encodeToken(EasyMock.isA(SecurityToken.class)))
+ .andThrow(new SecurityTokenException("blah"));
replay(codec);
registerGadgetsHandler(codec);
@@ -275,16 +289,4 @@ public class GadgetsHandlerTest extends
assertNotNull("got gadget2", gadget2);
assertEquals(GadgetsHandler.FAILURE_METADATA, gadget2.getString("error"));
}
-
- // Next test verify that the API data classes are configured correctly.
- // The mapping is done using reflection in runtime, so this test verify
mapping is complete
- // this test will prevent from not intended change to the API.
- // DO NOT REMOVE TEST
- @Test
- public void testHandlerDataDelegation() throws Exception {
- BeanDelegator delegator = new BeanDelegator(
- GadgetsHandler.apiClasses, GadgetsHandler.enumConversionMap);
- delegator.validate();
- }
-
}