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

org.codehaus.enunciate.modules.amf.AMFValidator Maven / Gradle / Ivy

Go to download

The Enunciate AMF module generates the artifacts needed for mounting AMF endpoints.

The newest version!
/*
 * Copyright 2006-2008 Web Cohesion
 *
 * 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 org.codehaus.enunciate.modules.amf;

import com.sun.mirror.declaration.*;
import com.sun.mirror.type.DeclaredType;
import com.sun.mirror.type.TypeMirror;
import net.sf.jelly.apt.decorations.TypeMirrorDecorator;
import net.sf.jelly.apt.decorations.type.DecoratedDeclaredType;
import net.sf.jelly.apt.decorations.type.DecoratedTypeMirror;
import org.codehaus.enunciate.contract.jaxb.*;
import org.codehaus.enunciate.contract.jaxb.adapters.Adaptable;
import org.codehaus.enunciate.contract.jaxws.EndpointImplementation;
import org.codehaus.enunciate.contract.jaxws.EndpointInterface;
import org.codehaus.enunciate.contract.jaxws.WebMethod;
import org.codehaus.enunciate.contract.jaxws.WebParam;
import org.codehaus.enunciate.contract.validation.BaseValidator;
import org.codehaus.enunciate.contract.validation.ConfigurableRules;
import org.codehaus.enunciate.contract.validation.ValidationResult;

import javax.xml.datatype.XMLGregorianCalendar;
import java.util.*;

/**
 * The validator for the amf module.
 *
 * @author Ryan Heaton
 */
public class AMFValidator extends BaseValidator implements ConfigurableRules {

  private final Set unsupportedTypes = new HashSet();
  private Set disabledRules = new TreeSet();
  private final boolean enforceNoFieldAccessors;

  public AMFValidator( boolean enforceNoFieldAccessors ) {
    unsupportedTypes.add(XMLGregorianCalendar.class.getName());
    unsupportedTypes.add(javax.xml.datatype.Duration.class.getName());
    unsupportedTypes.add(java.awt.Image.class.getName());
    unsupportedTypes.add(javax.xml.transform.Source.class.getName());
    this.enforceNoFieldAccessors = enforceNoFieldAccessors;
  }

  @Override
  public ValidationResult validateEndpointInterface(EndpointInterface ei) {
    ValidationResult result = super.validateEndpointInterface(ei);

    if (!isAMFTransient(ei)) {
      for (WebMethod webMethod : ei.getWebMethods()) {
        if (!isAMFTransient(webMethod)) {
          if (!isSupported(webMethod.getWebResult())) {
            result.addError(webMethod, "AMF doesn't support '" + webMethod.getWebResult() + "' as a return type.");
          }
          for (WebParam webParam : webMethod.getWebParameters()) {
            if (!isSupported(webParam.getType())) {
              result.addError(webParam, "AMF doesn't support '" + webParam.getType() + "' as a parameter type.");
            }
          }
        }
      }

      if (ei.getEndpointImplementations().size() > 1) {
        ArrayList impls = new ArrayList();
        for (EndpointImplementation impl : ei.getEndpointImplementations()) {
          impls.add(impl.getQualifiedName());
        }
        result.addError(ei, "Sorry, AMF doesn't support two endpoint implementations for interface '" + ei.getQualifiedName() +
          "'.  Found " + ei.getEndpointImplementations().size() + " implementations (" + impls.toString() + ").");
      }
      else if (ei.getEndpointImplementations().isEmpty()) {
        result.addError(ei, "AMF requires an implementation for each service interface.");
      }
    }
    
    return result;
  }

  @Override
  public ValidationResult validateComplexType(ComplexTypeDefinition complexType) {
    ValidationResult result = super.validateComplexType(complexType);
    if (!isAMFTransient(complexType)) {
      if (!hasDefaultConstructor(complexType)) {
        result.addError(complexType, "The mapping from AMF to JAXB requires a public no-arg constructor.");
      }

      if (!disabledRules.contains("as3.conflicting.names")) {
        if ("Date".equals(complexType.getClientSimpleName())) {
          result.addError(complexType, "ActionScript can't handle a class named 'Date'.  It conflicts with the top-level ActionScript class of the same name. Either rename the class, or use the @org.codehaus.enunciate.ClientName annotation to rename the class on the client-side.");
        }
        else if ("Event".equals(complexType.getClientSimpleName())) {
          result.addError(complexType, "The Enunciate-generated ActionScript code can't handle a class named 'Event'.  It conflicts with the ActionScript remoting class of the same name. Either rename the class, or use the @org.codehaus.enunciate.ClientName annotation to rename the class on the client-side.");
        }
      }

      for (Attribute attribute : complexType.getAttributes()) {
        if (!isAMFTransient(attribute)) {
          if ( (attribute.getDelegate() instanceof FieldDeclaration ) && enforceNoFieldAccessors ) {
            result.addError(attribute, "If you're mapping to AMF, you can't use fields for your accessors. ");
          }

          if (!isSupported(attribute.getAccessorType())) {
            result.addError(attribute, "AMF doesn't support the '" + attribute.getAccessorType() + "' type.");
          }
        }
      }

      for (Element element : complexType.getElements()) {
        if (!isAMFTransient(element)) {
          if ( (element.getDelegate() instanceof FieldDeclaration ) && enforceNoFieldAccessors ) {
            result.addError(element, "If you're mapping to AMF, you can't use fields for your accessors. ");
          }

          if (!isSupported(element.getAccessorType())) {
            result.addError(element, "AMF doesn't support the '" + element.getAccessorType() + "' type.");
          }
        }
      }

      Value value = complexType.getValue();
      if (value != null) {
        if (!isAMFTransient(value)) {
          if ( (value.getDelegate() instanceof FieldDeclaration ) && enforceNoFieldAccessors ) {
            result.addError(value, "If you're mapping to AMF, you can't use fields for your accessors. ");
          }

          if (!isSupported(value.getAccessorType())) {
            result.addError(value, "AMF doesn't support the '" + value.getAccessorType() + "' type.");
          }
        }
      }
    }

    if (((DecoratedTypeMirror) complexType.getSuperclass()).isInstanceOf(Map.class.getName())) {
      result.addError(complexType, "Enunciate can't generate AMF code that handles types that implement java.util.Map. I'm afraid you'll have to disable the AMF module or use @XmlJavaTypeAdapter to adapt the type.");
    }

    return result;
  }


  @Override
  public ValidationResult validateSimpleType(SimpleTypeDefinition simpleType) {
    ValidationResult result = super.validateSimpleType(simpleType);
    if (!isAMFTransient(simpleType)) {
      if (!hasDefaultConstructor(simpleType)) {
        result.addError(simpleType, "The mapping from AMF to JAXB requires a public no-arg constructor.");
      }

      if (!disabledRules.contains("as3.conflicting.names")) {
        if ("Date".equals(simpleType.getClientSimpleName())) {
          result.addError(simpleType, "ActionScript can't handle a class named 'Date'.  It conflicts with the top-level ActionScript class of the same name. Either rename the class, or use the @org.codehaus.enunciate.ClientName annotation to rename the class on the client-side.");
        }
        else if ("Event".equals(simpleType.getClientSimpleName())) {
          result.addError(simpleType, "The Enunciate-generated ActionScript code can't handle a class named 'Event'.  It conflicts with the ActionScript remoting class of the same name. Either rename the class, or use the @org.codehaus.enunciate.ClientName annotation to rename the class on the client-side.");
        }
      }
    }
    return result;
  }

  @Override
  public ValidationResult validateEnumType(EnumTypeDefinition enumType) {
    ValidationResult result = super.validateEnumType(enumType);
    if (!isAMFTransient(enumType)) {
      if (!disabledRules.contains("as3.conflicting.names")) {
        if ("Date".equals(enumType.getClientSimpleName())) {
          result.addError(enumType, "ActionScript can't handle a class named 'Date'.  It conflicts with the top-level ActionScript class of the same name. Either rename the class, or use the @org.codehaus.enunciate.ClientName annotation to rename the class on the client-side.");
        }
        else if ("Event".equals(enumType.getClientSimpleName())) {
          result.addError(enumType, "The Enunciate-generated ActionScript code can't handle a class named 'Event'.  It conflicts with the ActionScript remoting class of the same name. Either rename the class, or use the @org.codehaus.enunciate.ClientName annotation to rename the class on the client-side.");
        }
      }
    }
    return result;
  }

  private boolean hasDefaultConstructor(TypeDefinition typeDefinition) {
    Collection constructors = typeDefinition.getConstructors();
    for (ConstructorDeclaration constructor : constructors) {
      if ((constructor.getModifiers().contains(Modifier.PUBLIC)) && (constructor.getParameters().isEmpty())) {
        return true;
      }
    }
    return false;
  }

  /**
   * Whether the given type is supported.
   *
   * @param type The type to test for supportability.
   * @return Whether the given type is supported.
   */
  protected boolean isSupported(TypeMirror type) {
    if ((type instanceof Adaptable) && ((Adaptable) type).isAdapted()) {
      return isSupported(((Adaptable) type).getAdapterType().getAdaptingType());
    }
    else if (type instanceof DeclaredType) {
      DecoratedDeclaredType declaredType = (DecoratedDeclaredType) TypeMirrorDecorator.decorate(type);
      if ((declaredType.getDeclaration() != null) && (isAMFTransient(declaredType.getDeclaration()))) {
        return false;
      }
      else if ((declaredType.isInstanceOf(Collection.class.getName())) || (declaredType.isInstanceOf(java.util.Map.class.getName()))) {
        boolean supported = true;
        for (TypeMirror typeArgument : declaredType.getActualTypeArguments()) {
          supported &= isSupported(typeArgument);
        }
        return supported;
      }
      else {
        return declaredType.getDeclaration() != null && !unsupportedTypes.contains(declaredType.getDeclaration().getQualifiedName());
      }
    }

    //by default, we're going to assume that the type is complex and is supported.
    return true;
  }

  /**
   * Whether the given type declaration is AMF-transient.
   *
   * @param declaration The type declaration.
   * @return Whether the given tyep declaration is AMF-transient.
   */
  protected boolean isAMFTransient(TypeDeclaration declaration) {
    return isAMFTransient((Declaration) declaration) || isAMFTransient(declaration.getPackage());
  }

  /**
   * Whether the given type declaration is AMF-transient.
   *
   * @param declaration The type declaration.
   * @return Whether the given tyep declaration is AMF-transient.
   */
  protected boolean isAMFTransient(Declaration declaration) {
    return declaration != null && declaration.getAnnotation(AMFTransient.class) != null;
  }

  /**
   * Disables the specified rules.
   * 
   * @param ruleIds The ids of the rules to disable.
   */
  public void disableRules(Set ruleIds) {
    this.disabledRules.addAll(ruleIds);
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy