/* * Copyright 2010 Google Inc. * * Licensed 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 com.google.web.bindery.requestfactory.vm; import com.google.web.bindery.autobean.shared.AutoBeanFactory; import com.google.web.bindery.autobean.vm.AutoBeanFactorySource; import com.google.web.bindery.event.shared.EventBus; import com.google.web.bindery.requestfactory.shared.BaseProxy; import com.google.web.bindery.requestfactory.shared.EntityProxy; import com.google.web.bindery.requestfactory.shared.EntityProxyId; import com.google.web.bindery.requestfactory.shared.JsonRpcService; import com.google.web.bindery.requestfactory.shared.RequestContext; import com.google.web.bindery.requestfactory.shared.RequestFactory; import com.google.web.bindery.requestfactory.shared.ValueProxy; import com.google.web.bindery.requestfactory.shared.impl.AbstractRequestContext.Dialect; import com.google.web.bindery.requestfactory.shared.impl.AbstractRequestFactory; import com.google.web.bindery.requestfactory.shared.impl.BaseProxyCategory; import com.google.web.bindery.requestfactory.shared.impl.EntityProxyCategory; import com.google.web.bindery.requestfactory.shared.impl.ValueProxyCategory; import com.google.web.bindery.requestfactory.vm.InProcessRequestContext.RequestContextHandler; import com.google.web.bindery.requestfactory.vm.impl.Deobfuscator; import com.google.web.bindery.requestfactory.vm.impl.OperationKey; import java.lang.reflect.InvocationHandler; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Proxy; /** * A JRE-compatible implementation of RequestFactory. */ class InProcessRequestFactory extends AbstractRequestFactory { @AutoBeanFactory.Category(value = { EntityProxyCategory.class, ValueProxyCategory.class, BaseProxyCategory.class}) @AutoBeanFactory.NoWrap(EntityProxyId.class) interface Factory extends AutoBeanFactory { } class RequestFactoryHandler implements InvocationHandler { public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { if (Object.class.equals(method.getDeclaringClass()) || RequestFactory.class.equals(method.getDeclaringClass())) { try { return method.invoke(InProcessRequestFactory.this, args); } catch (InvocationTargetException e) { throw e.getCause(); } } Class<? extends RequestContext> context = method.getReturnType().asSubclass(RequestContext.class); Dialect dialect = method.getReturnType().isAnnotationPresent(JsonRpcService.class) ? Dialect.JSON_RPC : Dialect.STANDARD; RequestContextHandler handler = new InProcessRequestContext(InProcessRequestFactory.this, dialect, context).new RequestContextHandler(); return context.cast(Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), new Class<?>[] {context}, handler)); } } private final Class<? extends RequestFactory> requestFactoryInterface; private final Deobfuscator deobfuscator; public InProcessRequestFactory(Class<? extends RequestFactory> requestFactoryInterface) { this.requestFactoryInterface = requestFactoryInterface; deobfuscator = Deobfuscator.Builder.load(requestFactoryInterface, Thread.currentThread().getContextClassLoader()).build(); } public Deobfuscator getDeobfuscator() { return deobfuscator; } @Override public String getFactoryTypeToken() { return requestFactoryInterface.getName(); } @Override public void initialize(EventBus eventBus) { throw new UnsupportedOperationException("An explicit RequestTransport must be provided"); } @Override public boolean isEntityType(Class<?> clazz) { return EntityProxy.class.isAssignableFrom(clazz); } @Override public boolean isValueType(Class<?> clazz) { return ValueProxy.class.isAssignableFrom(clazz); } @Override protected AutoBeanFactory getAutoBeanFactory() { return AutoBeanFactorySource.create(Factory.class); } @Override @SuppressWarnings("unchecked") protected <P extends BaseProxy> Class<P> getTypeFromToken(String typeToken) { String deobfuscated = deobfuscator.getTypeFromToken(typeToken); if (deobfuscated == null) { throw new RuntimeException("Did not have deobfuscation data for " + typeToken); } try { Class<? extends BaseProxy> found = Class.forName(deobfuscated, false, Thread.currentThread().getContextClassLoader()) .asSubclass(BaseProxy.class); return (Class<P>) found; } catch (ClassNotFoundException e) { return null; } } @Override protected String getTypeToken(Class<? extends BaseProxy> clazz) { return isEntityType(clazz) || isValueType(clazz) ? OperationKey.hash(clazz.getName()) : null; } }