blob: aa6c95dbc526087901e28a0360155c34ad177aed [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.gwt.requestfactory.server;
import com.google.gwt.requestfactory.shared.BaseProxy;
import com.google.gwt.requestfactory.shared.Locator;
import com.google.gwt.requestfactory.shared.ProxyFor;
import com.google.gwt.requestfactory.shared.ProxyForName;
import com.google.gwt.requestfactory.shared.Request;
import com.google.gwt.requestfactory.shared.RequestContext;
import com.google.gwt.requestfactory.shared.Service;
import com.google.gwt.requestfactory.shared.ServiceLocator;
import com.google.gwt.requestfactory.shared.ServiceName;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
/**
* Adds support to the ServiceLayer chain for using {@link Locator} and
* {@link ServiceLocator} helper objects.
*/
final class LocatorServiceLayer extends ServiceLayerDecorator {
@Override
public <T> T createDomainObject(Class<T> clazz) {
Locator<T, ?> l = getLocator(clazz);
if (l == null) {
return super.createDomainObject(clazz);
}
return l.create(clazz);
}
@Override
public <T extends Locator<?, ?>> T createLocator(Class<T> clazz) {
return newInstance(clazz, Locator.class);
}
@Override
public Object createServiceInstance(Method contextMethod, Method domainMethod) {
Class<? extends ServiceLocator> locatorType =
getTop().resolveServiceLocator(contextMethod, domainMethod);
ServiceLocator locator = newInstance(locatorType, ServiceLocator.class);
// Enclosing class may be a parent class, so invoke on service class
Class<?> declaringClass = contextMethod.getDeclaringClass();
Class<?> serviceClass =
getTop().resolveServiceClass((Class<? extends RequestContext>) declaringClass);
return locator.getInstance(serviceClass);
}
@Override
public Object getId(Object domainObject) {
return doGetId(domainObject);
}
@Override
public Class<?> getIdType(Class<?> domainType) {
Locator<?, ?> l = getLocator(domainType);
if (l == null) {
return super.getIdType(domainType);
}
return l.getIdType();
}
@Override
public Object getVersion(Object domainObject) {
return doGetVersion(domainObject);
}
@Override
public boolean isLive(Object domainObject) {
return doIsLive(domainObject);
}
@Override
public <T> T loadDomainObject(Class<T> clazz, Object domainId) {
return doLoadDomainObject(clazz, domainId);
}
/**
* Returns true if the context method returns a {@link Request} and the domain
* method is non-static.
*/
@Override
public boolean requiresServiceLocator(Method contextMethod, Method domainMethod) {
return Request.class.isAssignableFrom(contextMethod.getReturnType())
&& !Modifier.isStatic(domainMethod.getModifiers());
}
@Override
public Class<? extends Locator<?, ?>> resolveLocator(Class<?> domainType) {
// Find the matching BaseProxy
Class<?> proxyType = getTop().resolveClientType(domainType, BaseProxy.class, false);
if (proxyType == null) {
return null;
}
// Check it for annotations
Class<? extends Locator<?, ?>> locatorType;
ProxyFor l = proxyType.getAnnotation(ProxyFor.class);
ProxyForName ln = proxyType.getAnnotation(ProxyForName.class);
if (l != null && !Locator.class.equals(l.locator())) {
@SuppressWarnings("unchecked")
Class<? extends Locator<?, ?>> found = (Class<? extends Locator<?, ?>>) l.locator();
locatorType = found;
} else if (ln != null && ln.locator().length() > 0) {
try {
@SuppressWarnings("unchecked")
Class<? extends Locator<?, ?>> found =
(Class<? extends Locator<?, ?>>) Class.forName(ln.locator(), false,
getTop().getDomainClassLoader()).asSubclass(Locator.class);
locatorType = found;
} catch (ClassNotFoundException e) {
return die(e, "Could not find the locator type specified in the @%s annotation %s",
ProxyForName.class.getCanonicalName(), ln.value());
}
} else {
// No locator annotation
locatorType = null;
}
return locatorType;
}
@Override
public Class<? extends ServiceLocator> resolveServiceLocator(Method contextMethod,
Method domainMethod) {
Class<? extends ServiceLocator> locatorType;
// Look at the RequestContext
Class<?> requestContextClass = contextMethod.getDeclaringClass();
Service l = requestContextClass.getAnnotation(Service.class);
ServiceName ln = requestContextClass.getAnnotation(ServiceName.class);
if (l != null && !ServiceLocator.class.equals(l.locator())) {
locatorType = l.locator();
} else if (ln != null && ln.locator().length() > 0) {
try {
locatorType =
Class.forName(ln.locator(), false, getTop().getDomainClassLoader()).asSubclass(
ServiceLocator.class);
} catch (ClassNotFoundException e) {
return die(e, "Could not find the locator type specified in the @%s annotation %s",
ServiceName.class.getCanonicalName(), ln.value());
}
} else {
locatorType = null;
}
return locatorType;
}
private <T> Object doGetId(T domainObject) {
@SuppressWarnings("unchecked")
Class<T> clazz = (Class<T>) domainObject.getClass();
Locator<T, ?> l = getLocator(clazz);
if (l == null) {
return super.getId(domainObject);
}
return l.getId(domainObject);
}
private <T> Object doGetVersion(T domainObject) {
@SuppressWarnings("unchecked")
Class<T> clazz = (Class<T>) domainObject.getClass();
Locator<T, ?> l = getLocator(clazz);
if (l == null) {
return super.getVersion(domainObject);
}
return l.getVersion(domainObject);
}
private <T> boolean doIsLive(T domainObject) {
@SuppressWarnings("unchecked")
Class<T> clazz = (Class<T>) domainObject.getClass();
Locator<T, ?> l = getLocator(clazz);
if (l == null) {
return super.isLive(domainObject);
}
return l.isLive(domainObject);
}
private <T, I> T doLoadDomainObject(Class<T> clazz, Object domainId) {
@SuppressWarnings("unchecked")
Locator<T, I> l = (Locator<T, I>) getLocator(clazz);
if (l == null) {
return super.loadDomainObject(clazz, domainId);
}
I id = l.getIdType().cast(domainId);
return l.find(clazz, id);
}
@SuppressWarnings("unchecked")
private <T, I> Locator<T, I> getLocator(Class<T> domainType) {
Class<? extends Locator<?, ?>> locatorType = getTop().resolveLocator(domainType);
if (locatorType == null) {
return null;
}
return (Locator<T, I>) getTop().createLocator(locatorType);
}
private <T> T newInstance(Class<T> clazz, Class<? super T> base) {
Throwable ex;
try {
return clazz.newInstance();
} catch (InstantiationException e) {
ex = e;
} catch (IllegalAccessException e) {
ex = e;
}
return this.<T> die(ex, "Could not instantiate %s %s. Is it default-instantiable?", base
.getSimpleName(), clazz.getCanonicalName());
}
}