blob: fc3802b28af4c10fb455130bc2cc7a38862a3cfe [file] [log] [blame]
/*
* 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.OperationKey;
import com.google.web.bindery.requestfactory.vm.impl.TypeTokenResolver;
import java.io.IOException;
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 TypeTokenResolver deobfuscator;
public InProcessRequestFactory(Class<? extends RequestFactory> requestFactoryInterface) {
this.requestFactoryInterface = requestFactoryInterface;
try {
deobfuscator = TypeTokenResolver.loadFromClasspath();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
@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;
}
TypeTokenResolver getTypeTokenResolver() {
return deobfuscator;
}
}