All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.google.web.bindery.requestfactory.server.ResolverServiceLayer Maven / Gradle / Ivy

There is a newer version: 2.10.0
Show newest version
/*
 * 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.autobean.vm.impl.TypeUtils;
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.ProxyFor;
import com.google.web.bindery.requestfactory.shared.ProxyForName;
import com.google.web.bindery.requestfactory.shared.RequestContext;
import com.google.web.bindery.requestfactory.shared.Service;
import com.google.web.bindery.requestfactory.shared.ServiceName;
import com.google.web.bindery.requestfactory.shared.ValueProxy;

import java.lang.reflect.Method;
import java.util.List;
import java.util.Set;
import java.util.logging.Logger;

/**
 * Implements all of the resolution methods in ServiceLayer.
 */
final class ResolverServiceLayer extends ServiceLayerDecorator {

  private static final Logger log = Logger.getLogger(ServiceLayer.class.getName());

  /**
   * All instances of the service layer that are loaded by the same classloader
   * can use a shared validator. The use of the validator should be
   * synchronized, since it is stateful.
   */
  private static final RequestFactoryInterfaceValidator validator =
      new RequestFactoryInterfaceValidator(log,
          new RequestFactoryInterfaceValidator.ClassLoaderLoader(ServiceLayer.class
              .getClassLoader()));

  @Override
  public ClassLoader getDomainClassLoader() {
    return Thread.currentThread().getContextClassLoader();
  }

  @Override
  public Class resolveClass(String typeToken) {
    Class found = forName(typeToken);
    if (!EntityProxy.class.isAssignableFrom(found) && !ValueProxy.class.isAssignableFrom(found)) {
      die(null, "The requested type %s is not assignable to %s or %s", typeToken, EntityProxy.class
          .getCanonicalName(), ValueProxy.class.getCanonicalName());
    }
    synchronized (validator) {
      validator.antidote();
      validator.validateProxy(found.getName());
      if (validator.isPoisoned()) {
        die(null, "The type %s did not pass RequestFactory validation", found.getCanonicalName());
      }
    }
    return found.asSubclass(BaseProxy.class);
  }

  @Override
  public  Class resolveClientType(Class domainClass, Class clientClass,
      boolean required) {
    String name;
    synchronized (validator) {
      name = validator.getEntityProxyTypeName(domainClass.getName(), clientClass.getName());
    }
    if (name != null) {
      return forName(name).asSubclass(clientClass);
    }
    if (List.class.isAssignableFrom(domainClass)) {
      return List.class.asSubclass(clientClass);
    }
    if (Set.class.isAssignableFrom(domainClass)) {
      return Set.class.asSubclass(clientClass);
    }
    if (TypeUtils.isValueType(domainClass)) {
      return domainClass.asSubclass(clientClass);
    }
    if (required) {
      die(null, "The domain type %s cannot be sent to the client", domainClass.getCanonicalName());
    }
    return null;
  }

  @Override
  public Class resolveDomainClass(Class clazz) {
    if (List.class.equals(clazz)) {
      return List.class;
    } else if (Set.class.equals(clazz)) {
      return Set.class;
    } else if (BaseProxy.class.isAssignableFrom(clazz)) {
      ProxyFor pf = clazz.getAnnotation(ProxyFor.class);
      if (pf != null) {
        return pf.value();
      }
      ProxyForName pfn = clazz.getAnnotation(ProxyForName.class);
      if (pfn != null) {
        Class toReturn = forName(pfn.value());
        return toReturn;
      }
    }
    return die(null, "Could not resolve a domain type for client type %s", clazz.getCanonicalName());
  }

  @Override
  public Method resolveDomainMethod(Method requestContextMethod) {
    Class declaringClass = requestContextMethod.getDeclaringClass();
    Class searchIn =
        getTop().resolveServiceClass(declaringClass.asSubclass(RequestContext.class));
    Class[] parameterTypes = requestContextMethod.getParameterTypes();
    Class[] domainArgs = new Class[parameterTypes.length];
    for (int i = 0, j = domainArgs.length; i < j; i++) {
      if (BaseProxy.class.isAssignableFrom(parameterTypes[i])) {
        domainArgs[i] = getTop().resolveDomainClass(parameterTypes[i].asSubclass(BaseProxy.class));
      } else if (EntityProxyId.class.isAssignableFrom(parameterTypes[i])) {
        domainArgs[i] =
            TypeUtils.ensureBaseType(TypeUtils.getSingleParameterization(EntityProxyId.class,
                requestContextMethod.getGenericParameterTypes()[i]));
      } else {
        domainArgs[i] = parameterTypes[i];
      }
    }

    Throwable ex;
    try {
      return searchIn.getMethod(requestContextMethod.getName(), domainArgs);
    } catch (SecurityException e) {
      ex = e;
    } catch (NoSuchMethodException e) {
      return report("Could not locate domain method %s", requestContextMethod.getName());
    }
    return die(ex, "Could not get domain method %s in type %s", requestContextMethod.getName(),
        searchIn.getCanonicalName());
  }

  @Override
  public Method resolveRequestContextMethod(String requestContextClass, String methodName) {
    synchronized (validator) {
      validator.antidote();
      validator.validateRequestContext(requestContextClass);
      if (validator.isPoisoned()) {
        die(null, "The RequestContext type %s did not pass validation", requestContextClass);
      }
    }
    Class searchIn = forName(requestContextClass);
    for (Method method : searchIn.getMethods()) {
      if (method.getName().equals(methodName)) {
        return method;
      }
    }
    return report("Could not locate %s method %s::%s", RequestContext.class.getSimpleName(),
        requestContextClass, methodName);
  }

  @Override
  public Class resolveServiceClass(Class requestContextClass) {
    Class searchIn = null;
    Service s = requestContextClass.getAnnotation(Service.class);
    // TODO Handle case when both annotations are present
    if (s != null) {
      searchIn = s.value();
    }
    ServiceName sn = requestContextClass.getAnnotation(ServiceName.class);
    if (sn != null) {
      searchIn = forName(sn.value());
    }
    if (searchIn == null) {
      die(null, "The %s type %s did not specify a service type", RequestContext.class
          .getSimpleName(), requestContextClass.getCanonicalName());
    }
    return searchIn;
  }

  @Override
  public String resolveTypeToken(Class clazz) {
    return clazz.getName();
  }

  /**
   * Call {@link Class#forName(String)} and report any errors through
   * {@link #die()}.
   */
  private Class forName(String name) {
    try {
      return Class.forName(name, false, getTop().getDomainClassLoader());
    } catch (ClassNotFoundException e) {
      return die(e, "Could not locate class %s", name);
    }
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy