Package juzu.impl.plugin.controller.metamodel

Source Code of juzu.impl.plugin.controller.metamodel.ControllerMetaModel

/*
* Copyright 2013 eXo Platform SAS
*
* 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 juzu.impl.plugin.controller.metamodel;

import juzu.Mapped;
import juzu.Param;
import juzu.impl.compiler.ProcessingContext;
import juzu.impl.plugin.module.metamodel.ModuleMetaModel;
import juzu.impl.metamodel.AnnotationKey;
import juzu.impl.metamodel.AnnotationState;
import juzu.impl.compiler.ElementHandle;
import juzu.impl.compiler.MessageCode;
import juzu.impl.metamodel.Key;
import juzu.impl.metamodel.MetaModelEvent;
import juzu.impl.metamodel.MetaModelObject;
import juzu.impl.common.Cardinality;
import juzu.impl.common.JSON;
import juzu.request.Phase;

import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.TypeElement;
import javax.lang.model.element.VariableElement;
import javax.lang.model.type.ArrayType;
import javax.lang.model.type.DeclaredType;
import javax.lang.model.type.ExecutableType;
import javax.lang.model.type.TypeKind;
import javax.lang.model.type.TypeMirror;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.logging.Level;

/** @author <a href="mailto:julien.viet@exoplatform.com">Julien Viet</a> */
public class ControllerMetaModel extends MetaModelObject implements Iterable<HandlerMetaModel> {

  /** . */
  public static final MessageCode CANNOT_WRITE_CONTROLLER_COMPANION = new MessageCode("CANNOT_WRITE_CONTROLLER_COMPANION", "The controller companion %1$s cannot be written");

  /** . */
  public static final MessageCode CONTROLLER_METHOD_PARAMETER_NOT_RESOLVED = new MessageCode("CONTROLLER_METHOD_PARAMETER_NOT_RESOLVED", "The method parameter type %1s should be a string or annotated with @juzu.Param");

  /** . */
  public static final MessageCode CONTROLLER_IS_ABSTRACT = new MessageCode("CONTROLLER_IS_ABSTRACT", "The controller class %1s cannot be abstract");

  /** A flag for handling modified event. */
  boolean modified;

  /** The application. */
  ControllersMetaModel controllers;

  /** . */
  final ElementHandle.Type handle;

  public ControllerMetaModel(ElementHandle.Type handle) {
    this.handle = handle;
    this.modified = false;
  }

  public Iterator<HandlerMetaModel> iterator() {
    return getHandlers().iterator();
  }

  public JSON toJSON() {
    JSON json = new JSON();
    json.set("handle", handle);
    json.map("methods", getHandlers());
    return json;
  }

  public ControllersMetaModel getControllers() {
    return controllers;
  }

  public ElementHandle.Type getHandle() {
    return handle;
  }

  public Collection<HandlerMetaModel> getHandlers() {
    return getChildren(HandlerMetaModel.class);
  }

  private PhaseParameterMetaModel foo(
      VariableElement parameterVariableElt,
      String parameterName,
      Cardinality parameterCardinality,
      String type,
      String valueType) {
    // Not sure we should use @Param for this (i.e for now it looks hackish)
    // however it does make sense later to use the regex part for non router
    // parameters
    Param param = parameterVariableElt.getAnnotation(Param.class);
    String alias = param != null && param.name().length() > 0 ? param.name() : null;
    return new PhaseParameterMetaModel(parameterName, parameterCardinality, type, valueType, alias);
  }

  private ParameterMetaModel foo(ModuleMetaModel context, VariableElement parameterVariableElt, TypeMirror parameterTypeMirror) {
    String type = context.processingContext.getLiteralName(parameterTypeMirror);

    //
    String parameterName = parameterVariableElt.getSimpleName().toString();

    //
    if (parameterVariableElt.getAnnotation(Mapped.class) != null) {
      return new BeanParameterMetaModel(parameterName, type);
    } else {

      // Determine cardinality
      TypeMirror parameterValueTypeMirror;
      Cardinality parameterCardinality;
      switch (parameterTypeMirror.getKind()) {
        case INT:
          return foo(parameterVariableElt, parameterName, Cardinality.SINGLE, "int", "int");
        case DECLARED:
          DeclaredType dt = (DeclaredType)parameterTypeMirror;
          TypeElement col = context.processingContext.getTypeElement("java.util.List");
          TypeMirror tm = context.processingContext.erasure(col.asType());
          TypeMirror err = context.processingContext.erasure(dt);
          if (err.equals(tm)) {
            if (dt.getTypeArguments().size() != 1) {
              throw CONTROLLER_METHOD_PARAMETER_NOT_RESOLVED.failure(parameterVariableElt);
            } else {
              parameterCardinality = Cardinality.LIST;
              parameterValueTypeMirror = dt.getTypeArguments().get(0);
              if (parameterValueTypeMirror.getKind() != TypeKind.DECLARED) {
                throw CONTROLLER_METHOD_PARAMETER_NOT_RESOLVED.failure(parameterVariableElt);
              }
            }
          } else {
            parameterCardinality = Cardinality.SINGLE;
            parameterValueTypeMirror = parameterTypeMirror;
          }
          break;
        case ARRAY:
          // Unwrap array
          ArrayType arrayType = (ArrayType)parameterTypeMirror;
          parameterCardinality = Cardinality.ARRAY;
          parameterValueTypeMirror = arrayType.getComponentType();
          switch (parameterValueTypeMirror.getKind()) {
            case DECLARED:
              break;
            case INT:
              return foo(parameterVariableElt, parameterName, Cardinality.ARRAY, "int[]", "int");
            default:
              throw CONTROLLER_METHOD_PARAMETER_NOT_RESOLVED.failure(parameterVariableElt);
          }
          break;
        default:
          throw CONTROLLER_METHOD_PARAMETER_NOT_RESOLVED.failure(parameterVariableElt);
      }

      //
      TypeElement valueType = (TypeElement)context.processingContext.asElement(parameterValueTypeMirror);
      ElementHandle.Type valueTypeHandle = ElementHandle.Type.create(valueType);

      //
      if (valueType.toString().equals("java.lang.String") || controllers.plugin.valueTypes.contains(valueTypeHandle)) {
        return foo(parameterVariableElt, parameterName, parameterCardinality, type, valueType.toString());
      } else {
        return new ContextualParameterMetaModel(parameterName, type);
      }
    }
  }

  void addMethod(ModuleMetaModel context, AnnotationKey annotationKey, AnnotationState annotationState) {

    //
    String id = (String)annotationState.get("id");
    ElementHandle.Method methodHandle = (ElementHandle.Method)annotationKey.getElement();
    ExecutableElement methodElt = context.processingContext.get(methodHandle);
    ProcessingContext.log.log(Level.FINE, "Adding method " + methodElt + " to controller class " + handle);

    //
    for (Phase phase : Phase.values()) {
      if (phase.annotation.getName().equals(annotationKey.getType().toString())) {

        // First remove the previous method
        Key<HandlerMetaModel> key = Key.of(methodHandle, HandlerMetaModel.class);
        if (getChild(key) == null) {
          // Parameters
          ArrayList<ParameterMetaModel> parameters = new ArrayList<ParameterMetaModel>();
          List<? extends TypeMirror> parameterTypeMirrors = ((ExecutableType)methodElt.asType()).getParameterTypes();
          List<? extends VariableElement> parameterVariableElements = methodElt.getParameters();
          for (int i = 0;i < parameterTypeMirrors.size();i++) {
            VariableElement parameterVariableElt = parameterVariableElements.get(i);
            TypeMirror parameterTypeMirror = parameterTypeMirrors.get(i);
            ParameterMetaModel parameterMetaModel = foo(context, parameterVariableElt, parameterTypeMirror);
            parameters.add(parameterMetaModel);
          }

          //
          HandlerMetaModel method = new HandlerMetaModel(
            methodHandle,
            id,
            phase,
            methodElt.getSimpleName().toString(),
            parameters);
          addChild(key, method);
          modified = true;
          ProcessingContext.log.log(Level.FINE, "Added method " + methodHandle + " to controller class " + handle);
        }
        break;
      }
    }
  }

  void removeMethod(ElementHandle.Method handle) {
    ProcessingContext.log.log(Level.FINE, "Removing method " + handle + " from controller class " + handle);
    if (removeChild(Key.of(handle, HandlerMetaModel.class)) != null) {
      modified = true;
      ProcessingContext.log.log(Level.FINE, "Removed method " + handle + " from controller class " + handle);
    }
  }

  @Override
  protected void preDetach(MetaModelObject parent) {
    if (parent instanceof ControllersMetaModel) {
      queue(MetaModelEvent.createRemoved(this));
      controllers = null;
    }
  }

  @Override
  protected void postAttach(MetaModelObject parent) {
    if (parent instanceof ControllersMetaModel) {
      controllers = (ControllersMetaModel)parent;
      queue(MetaModelEvent.createAdded(this));
    }
  }
}
TOP

Related Classes of juzu.impl.plugin.controller.metamodel.ControllerMetaModel

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.