| /* | |
| * 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.server; | |
| import com.google.web.bindery.requestfactory.shared.BaseProxy; | |
| import com.google.web.bindery.requestfactory.shared.Locator; | |
| import com.google.web.bindery.requestfactory.shared.RequestContext; | |
| import com.google.web.bindery.requestfactory.shared.RequestFactory; | |
| import com.google.web.bindery.requestfactory.shared.ServiceLocator; | |
| import java.lang.reflect.Method; | |
| import java.lang.reflect.Type; | |
| import java.util.ArrayList; | |
| import java.util.Arrays; | |
| import java.util.List; | |
| import java.util.Set; | |
| import javax.validation.ConstraintViolation; | |
| /** | |
| * The ServiceLayer mediates all interactions between the | |
| * {@link SimpleRequestProcessor} and the domain environment. The core service | |
| * logic can be decorated by extending an {@link ServiceLayerDecorator}. | |
| * <p> | |
| * This API is subject to change in future releases. | |
| */ | |
| public abstract class ServiceLayer { | |
| /* | |
| * NB: This type cannot be directly extended by the user since it has a | |
| * package-protected constructor. This means that any API-compatibility work | |
| * that needs to happen can be done in ServiceLayerDecorator in order to keep | |
| * this interface as clean as possible. | |
| */ | |
| /** | |
| * Provides a flag to disable the ServiceLayerCache for debugging purposes. | |
| */ | |
| private static final boolean ENABLE_CACHE = Boolean.valueOf(System.getProperty( | |
| "gwt.rf.ServiceLayerCache", "true")); | |
| /** | |
| * Create a RequestFactory ServiceLayer that is optionally modified by the | |
| * given decorators. | |
| * | |
| * @param decorators the decorators that will modify the behavior of the core | |
| * service layer implementation | |
| * @return a ServiceLayer instance | |
| */ | |
| public static ServiceLayer create(ServiceLayerDecorator... decorators) { | |
| List<ServiceLayerDecorator> list = new ArrayList<ServiceLayerDecorator>(); | |
| // Always hit the cache first | |
| ServiceLayerDecorator cache = | |
| ENABLE_CACHE ? new ServiceLayerCache() : new ServiceLayerDecorator(); | |
| list.add(cache); | |
| // The user-provided decorators | |
| if (decorators != null) { | |
| list.addAll(Arrays.asList(decorators)); | |
| } | |
| // Support for Locator objects | |
| list.add(new LocatorServiceLayer()); | |
| // Interact with domain objects | |
| list.add(new ReflectiveServiceLayer()); | |
| // Add shortcut for find's operation | |
| list.add(new FindServiceLayer()); | |
| // Locate domain objects | |
| list.add(new ResolverServiceLayer()); | |
| // Make the last layer point to the cache | |
| list.get(list.size() - 1).top = cache; | |
| // Point each entry at the next | |
| for (int i = list.size() - 2; i >= 0; i--) { | |
| ServiceLayerDecorator layer = list.get(i); | |
| layer.next = list.get(i + 1); | |
| layer.top = cache; | |
| } | |
| return cache; | |
| } | |
| /** | |
| * A pointer to the top-most ServiceLayer instance. | |
| */ | |
| ServiceLayer top; | |
| /** | |
| * Not generally-extensible. | |
| */ | |
| ServiceLayer() { | |
| } | |
| /** | |
| * Create an instance of the requested domain type. | |
| * | |
| * @param <T> the requested domain type | |
| * @param clazz the requested domain type | |
| * @return an instance of the requested domain type | |
| */ | |
| public abstract <T> T createDomainObject(Class<T> clazz); | |
| /** | |
| * Create an instance of the requested {@link Locator} type. | |
| * | |
| * @param <T> the requested Locator type | |
| * @param clazz the requested Locator type | |
| * @return an instance of the requested Locator type | |
| */ | |
| public abstract <T extends Locator<?, ?>> T createLocator(Class<T> clazz); | |
| /** | |
| * Create an instance of a service object that can be used as the target for | |
| * the given method invocation. | |
| * | |
| * @param requestContext the RequestContext type for which a service object | |
| * must be instantiated. | |
| * @return an instance of the requested service object | |
| */ | |
| public abstract Object createServiceInstance(Class<? extends RequestContext> requestContext); | |
| /** | |
| * Create an instance of the requested {@link ServiceLocator} type. | |
| * | |
| * @param <T> the requested ServiceLocator type | |
| * @param clazz the requested ServiceLocator type | |
| * @return an instance of the requested ServiceLocator type | |
| */ | |
| public abstract <T extends ServiceLocator> T createServiceLocator(Class<T> clazz); | |
| /** | |
| * Returns the ClassLoader that should be used when attempting to access | |
| * domain classes or resources. | |
| * <p> | |
| * The default implementation returns | |
| * {@code Thread.currentThread().getContextClassLoader()}. | |
| */ | |
| public abstract ClassLoader getDomainClassLoader(); | |
| /** | |
| * Determine the method to invoke when retrieving the given property. | |
| * | |
| * @param domainType a domain entity type | |
| * @param property the name of the property to be retrieved | |
| * @return the Method that should be invoked to retrieve the property or | |
| * {@code null} if the method could not be located | |
| */ | |
| public abstract Method getGetter(Class<?> domainType, String property); | |
| /** | |
| * Return the persistent id for a domain object. May return {@code null} to | |
| * indicate that the domain object has not been persisted. The value returned | |
| * from this method must be a simple type (e.g. Integer, String) or a domain | |
| * type for which a mapping to an EntityProxy or Value proxy exists. | |
| * <p> | |
| * The values returned from this method may be passed to | |
| * {@link #loadDomainObject(Class, Object)} in the future. | |
| * | |
| * @param domainObject a domain object | |
| * @return the persistent id of the domain object or {@code null} if the | |
| * object is not persistent | |
| */ | |
| public abstract Object getId(Object domainObject); | |
| /** | |
| * Returns the type of object the domain type's {@code findFoo()} or | |
| * {@link com.google.web.bindery.requestfactory.shared.Locator#getId(Object) | |
| * Locator.getId()} expects to receive. | |
| * | |
| * @param domainType a domain entity type | |
| * @return the type of the persistent id value used to represent the domain | |
| * type | |
| */ | |
| public abstract Class<?> getIdType(Class<?> domainType); | |
| /** | |
| * Retrieve the named property from the domain object. | |
| * | |
| * @param domainObject the domain object being examined | |
| * @param property the property name | |
| * @return the value of the property | |
| */ | |
| public abstract Object getProperty(Object domainObject, String property); | |
| /** | |
| * Compute the return type for a method declared in a RequestContext by | |
| * analyzing the generic method declaration. | |
| */ | |
| public abstract Type getRequestReturnType(Method contextMethod); | |
| /** | |
| * Determine the method to invoke when setting the given property. | |
| * | |
| * @param domainType a domain entity type | |
| * @param property the name of the property to be set | |
| * @return the Method that should be invoked to set the property or | |
| * {@code null} if the method could not be located | |
| */ | |
| public abstract Method getSetter(Class<?> domainType, String property); | |
| /** | |
| * May return {@code null} to indicate that the domain object has not been | |
| * persisted. The value returned from this method must be a simple type (e.g. | |
| * Integer, String) or a domain type for which a mapping to an EntityProxy or | |
| * Value proxy exists. | |
| * | |
| * @param domainObject a domain object | |
| * @return the version of the domain object or {@code null} if the object is | |
| * not persistent | |
| */ | |
| public abstract Object getVersion(Object domainObject); | |
| /** | |
| * Invoke a domain service method. The underlying eventually calls | |
| * {@link Method#invoke(Object, Object...)}. | |
| * | |
| * @param domainMethod the method to invoke | |
| * @param args the arguments to pass to the method | |
| * @return the value returned from the method invocation | |
| */ | |
| public abstract Object invoke(Method domainMethod, Object... args); | |
| /** | |
| * Returns {@code true} if the given domain object is still live (i.e. not | |
| * deleted) in the backing store. | |
| * | |
| * @param domainObject a domain entity | |
| * @return {@code true} if {@code domainObject} could be retrieved at a later | |
| * point in time | |
| */ | |
| public abstract boolean isLive(Object domainObject); | |
| /** | |
| * Load an object from the backing store. This method may return {@code null} | |
| * to indicate that the requested object is no longer available. | |
| * | |
| * @param <T> the type of object to load | |
| * @param clazz the type of object to load | |
| * @param domainId an id previously returned from {@link #getId(Object)} | |
| * @return the requested object or {@code null} if it is irretrievable | |
| */ | |
| public abstract <T> T loadDomainObject(Class<T> clazz, Object domainId); | |
| /** | |
| * Load multiple objects from the backing store. This method is intended to | |
| * allow more efficient access to the backing store by providing all objects | |
| * referenced in an incoming payload. | |
| * <p> | |
| * The default implementation of this method will delegate to | |
| * {@link #loadDomainObject(Class, Object)}. | |
| * | |
| * @param classes type type of each object to load | |
| * @param domainIds the ids previously returned from {@link #getId(Object)} | |
| * @return the requested objects, elements of which may be {@code null} if the | |
| * requested objects were irretrievable | |
| */ | |
| public abstract List<Object> loadDomainObjects(List<Class<?>> classes, List<Object> domainIds); | |
| /** | |
| * Determines if the invocation of a domain method requires a | |
| * {@link ServiceLocator} as the 0th parameter when passed into | |
| * {@link #invoke(Method, Object...)}. | |
| * | |
| * @param contextMethod a method defined in a RequestContext | |
| * @param domainMethod a domain method | |
| * @return {@code true} if a ServiceLocator is required | |
| */ | |
| public abstract boolean requiresServiceLocator(Method contextMethod, Method domainMethod); | |
| /** | |
| * Given a type token previously returned from | |
| * {@link #resolveTypeToken(Class)}, return the Class literal associated with | |
| * the token. | |
| * | |
| * @param typeToken a string token | |
| * @return the type represented by the token | |
| */ | |
| public abstract Class<? extends BaseProxy> resolveClass(String typeToken); | |
| /** | |
| * Determine the type used by the client code to represent a given domain | |
| * type. If multiple proxy types have been mapped to the same domain type, the | |
| * {@code clientType} parameter is used to ensure assignability. | |
| * | |
| * @param domainClass the server-side type to be transported to the client | |
| * @param clientType the type to which the returned type must be assignable | |
| * @param required if {@code true} and no mapping is available, throw an | |
| * exception, otherwise the method will return {@code null} | |
| * @return a class that represents {@code domainClass} on the client which is | |
| * assignable to {@code clientType} | |
| */ | |
| public abstract <T> Class<? extends T> resolveClientType(Class<?> domainClass, | |
| Class<T> clientType, boolean required); | |
| /** | |
| * Determine the domain (server-side) type that the given client type is | |
| * mapped to. | |
| * | |
| * @param clientType a client-side type | |
| * @return the domain type that {@code clientType} represents | |
| */ | |
| public abstract Class<?> resolveDomainClass(Class<?> clientType); | |
| /** | |
| * Return the domain service method associated with a RequestContext method | |
| * declaration. The {@code requestContextMethod} will have been previously | |
| * resolved by {@link #resolveRequestContextMethod(String, String)}. | |
| * | |
| * @param requestContext the RequestContext requested by the client | |
| * @param requestContextMethod a RequestContext method declaration. Note that | |
| * this Method may be defined in a supertype of | |
| * {@code requestContext} | |
| * @return the domain service method that should be invoked | |
| */ | |
| public abstract Method resolveDomainMethod(String operation); | |
| /** | |
| * Return the type of {@link Locator} that should be used to access the given | |
| * domain type. | |
| * | |
| * @param domainType a domain (server-side) type | |
| * @return the type of Locator to use, or {@code null} if the type conforms to | |
| * the RequestFactory entity protocol | |
| */ | |
| public abstract Class<? extends Locator<?, ?>> resolveLocator(Class<?> domainType); | |
| /** | |
| * Find a RequestContext that should be used to fulfill the requested | |
| * operation. | |
| * | |
| * @param operation the operation | |
| * @return the RequestContext or {@code null} if no RequestContext exists that | |
| * can fulfill the operation | |
| */ | |
| public abstract Class<? extends RequestContext> resolveRequestContext(String operation); | |
| /** | |
| * Find a RequestContext method declaration by name. | |
| * | |
| * @param operation the operation's name | |
| * @return the method declaration, or {@code null} if the method does not | |
| * exist | |
| */ | |
| public abstract Method resolveRequestContextMethod(String operation); | |
| /** | |
| * Loads and validates a RequestFactory interface. | |
| * | |
| * @param token the RequestFactory's type token (usually the type's binary | |
| * name) | |
| * @return the RequestFactory type | |
| */ | |
| public abstract Class<? extends RequestFactory> resolveRequestFactory(String token); | |
| /** | |
| * Given a {@link RequestContext} method, find the service class referenced in | |
| * the {@link com.google.web.bindery.requestfactory.shared.Service Service} or | |
| * {@link com.google.web.bindery.requestfactory.shared.ServiceName | |
| * ServiceName} annotation. | |
| * | |
| * @param requestContextClass a RequestContext interface | |
| * @return the type of service to use | |
| */ | |
| public abstract Class<?> resolveServiceClass(Class<? extends RequestContext> requestContextClass); | |
| /** | |
| * Given a RequestContext method declaration, resolve the | |
| * {@link ServiceLocator} that should be used when invoking the domain method. | |
| * This method will only be called if | |
| * {@link #requiresServiceLocator(Method, Method)} returned {@code true} for | |
| * the associated domain method. | |
| * | |
| * @param requestContext the RequestContext for which a ServiceLocator must be | |
| * located | |
| * @return the type of ServiceLocator to use | |
| */ | |
| public abstract Class<? extends ServiceLocator> resolveServiceLocator( | |
| Class<? extends RequestContext> requestContext); | |
| /** | |
| * Return a string used to represent the given type in the wire protocol. | |
| * | |
| * @param proxyType a client-side EntityProxy or ValueProxy type | |
| * @return the type token used to represent the proxy type | |
| */ | |
| public abstract String resolveTypeToken(Class<? extends BaseProxy> proxyType); | |
| /** | |
| * Sets a property on a domain object. | |
| * | |
| * @param domainObject the domain object to operate on | |
| * @param property the name of the property to set | |
| * @param expectedType the type of the property | |
| * @param value the new value | |
| */ | |
| public abstract void setProperty(Object domainObject, String property, Class<?> expectedType, | |
| Object value); | |
| /** | |
| * Invoke a JSR 303 validator on the given domain object. If no validator is | |
| * available, this method is a no-op. | |
| * | |
| * @param <T> the type of data being validated | |
| * @param domainObject the domain objcet to validate | |
| * @return the violations associated with the domain object | |
| */ | |
| public abstract <T> Set<ConstraintViolation<T>> validate(T domainObject); | |
| } |