Package juzu.impl.metamodel

Source Code of juzu.impl.metamodel.MetaModelContext

/*
* 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.metamodel;

import juzu.impl.common.Name;
import juzu.impl.compiler.ProcessingContext;
import juzu.impl.compiler.ProcessingException;

import javax.annotation.processing.Completion;
import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.element.Element;
import javax.lang.model.element.TypeElement;
import java.io.Serializable;
import java.lang.annotation.Annotation;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;
import java.util.logging.Level;

/** @author <a href="mailto:julien.viet@exoplatform.com">Julien Viet</a> */
public final class MetaModelContext<P extends MetaModelPlugin<M, P>, M extends MetaModel<P, M>>
    implements Serializable, Iterable<M> {

  /** . */
  private ProcessingContext processingContext;

  /** The meta model. */
  private ArrayList<M> metaModels;

  /** The plugins. */
  private LinkedHashMap<String, P> pluginMap;

  /** The supported annotations per plugin. */
  private HashMap<P, HashSet<Name>> supportedAnnotationsMap;

  /** All supported annotations. */
  private Set<Class<? extends java.lang.annotation.Annotation>> supportedAnnotations;

  /** . */
  private final Class<P> pluginType;

  /** All known annotations. */
  final LinkedHashMap<AnnotationKey, AnnotationState> knownAnnotations = new LinkedHashMap<AnnotationKey, AnnotationState>();

  public MetaModelContext(Class<P> pluginType) {
    this.pluginType = pluginType;
    this.metaModels = new ArrayList<M>();
  }

  public void init(ProcessingContext env) throws NullPointerException {
    this.processingContext = env;

    //
    HashMap<P, HashSet<Name>> supportedAnnotationsMap = new HashMap<P, HashSet<Name>>();
    LinkedHashMap<String, P> pluginMap = new LinkedHashMap<String, P>();
    StringBuilder msg = new StringBuilder("Using plugins:");
    for (P plugin : env.loadServices(pluginType)) {
      msg.append(" ").append(plugin.getName());
      pluginMap.put(plugin.getName(), plugin);
    }
    env.info(msg);

    // Collect processed annotations
    HashSet<Class<? extends java.lang.annotation.Annotation>> supportedAnnotations = new HashSet<Class<? extends java.lang.annotation.Annotation>>();
    for (P plugin : pluginMap.values()) {
      HashSet<Name> pluginSupportedAnnotations = new HashSet<Name>();
      for (Class<? extends Annotation> annotationType : plugin.init(env)) {
        pluginSupportedAnnotations.add(Name.create(annotationType));
        supportedAnnotations.add(annotationType);
      }
      env.info("Plugin " + plugin.getName() + " supports " + pluginSupportedAnnotations);
      supportedAnnotationsMap.put(plugin, pluginSupportedAnnotations);
    }

    //
    this.pluginMap = pluginMap;
    this.supportedAnnotationsMap = supportedAnnotationsMap;
    this.supportedAnnotations = supportedAnnotations;
  }

  public Iterator<M> iterator() {
    return metaModels.iterator();
  }

  public Set<Class<? extends java.lang.annotation.Annotation>> getSupportedAnnotations() {
    return supportedAnnotations;
  }

  public Collection<P> getPlugins() {
    return pluginMap.values();
  }

  public void add(M metaModel) {
    metaModel.processingContext = processingContext;
    metaModel.forward = true;
    metaModel.context = this;
    metaModel.init(processingContext);
    for (P plugin : pluginMap.values()) {
      plugin.init(metaModel);
    }
    metaModels.add(metaModel);
  }

  public final void postActivate(ProcessingContext processingContext) throws NullPointerException {
    this.processingContext = processingContext;
    for (M metaModel : metaModels) {
      metaModel.processingContext = processingContext;
      for (P plugin : pluginMap.values()) {
        plugin.postActivate(metaModel);
      }
    }
  }

  public void processAnnotationChange(AnnotationChange change) {

    // Update state
    if (change.getAdded() == null) {
      knownAnnotations.remove(change.getKey());
    } else {
      knownAnnotations.put(change.getKey(), change.getAdded());
    }

    //
    for (M metaModel : metaModels) {
      if (metaModel.forward) {
        metaModel.forward = false;
        for (Map.Entry<AnnotationKey, AnnotationState> annotation : knownAnnotations.entrySet()) {
          change = new AnnotationChange(annotation.getKey(), null, annotation.getValue());
          for (P plugin : pluginMap.values()) {
            HashSet<Name> supportedAnnotations = supportedAnnotationsMap.get(plugin);
            if (supportedAnnotations.contains(change.key.type)) {
              plugin.processAnnotationChange(metaModel, change);
            }
          }
        }
      } else {
        for (P plugin : pluginMap.values()) {
          HashSet<Name> supportedAnnotations = supportedAnnotationsMap.get(plugin);
          if (supportedAnnotations.contains(change.key.type)) {
            plugin.processAnnotationChange(metaModel, change);
          }
        }
      }
    }
  }

  public void processAnnotationChanges(Iterable<AnnotationChange> changes) {
    for (AnnotationChange change : changes) {
      processAnnotationChange(change);
    }
  }

  void processAnnotations(Iterable<Map.Entry<AnnotationKey, AnnotationState>> annotations) {
    ArrayList<AnnotationChange> delta = new ArrayList<AnnotationChange>();
    for (Map.Entry<AnnotationKey, AnnotationState> entry : knownAnnotations.entrySet()) {
      AnnotationKey key = entry.getKey();
      Element element = processingContext.get(key.element);
      if (element == null) {
        delta.add(new AnnotationChange(key, entry.getValue(), null));
        processingContext.log(Level.FINER, "Annotation removed " + key);
      } else {
        AnnotationMirror found = null;
        for (AnnotationMirror mirror : element.getAnnotationMirrors()) {
          Name f = Name.parse(((TypeElement)mirror.getAnnotationType().asElement()).getQualifiedName().toString());
          if (key.getType().equals(f)) {
            found = mirror;
            break;
          }
        }
        if (found == null) {
          delta.add(new AnnotationChange(key, entry.getValue(), null));
          processingContext.log(Level.FINER, "Annotation removed " + key);
        }
      }
    }
    for (Map.Entry<AnnotationKey, AnnotationState> annotation : annotations) {
      AnnotationState knownAnnotation = knownAnnotations.get(annotation.getKey());
      if (knownAnnotation != null) {
        processingContext.log(Level.FINER, "Annotation updated " + annotation.getKey());
      } else {
        processingContext.log(Level.FINER, "Annotation added " + annotation.getKey());
      }
      delta.add(new AnnotationChange(annotation.getKey(), knownAnnotation, annotation.getValue()));
    }
    processAnnotationChanges(delta);
  }

  public Iterable<? extends Completion> getCompletions(
      AnnotationKey annotationKey,
      AnnotationState annotationState,
      String member,
      String userText) {
    Iterable<? extends Completion> completions = null;
    for (M metaModel : metaModels) {
      for (P plugin : pluginMap.values()) {
        HashSet<Name> supportedAnnotations = supportedAnnotationsMap.get(plugin);
        if (supportedAnnotations.contains(annotationKey.type)) {
          completions = plugin.getCompletions(metaModel, annotationKey, annotationState, member, userText);
          if (completions != null) {
            break;
          }
        }
      }
    }
    return completions;
  }

  public void postProcessAnnotations() throws ProcessingException {
    for (M metaModel : metaModels) {
      for (P plugin : pluginMap.values()) {
        plugin.postProcessAnnotations(metaModel);
      }
    }
  }

  public void processEvents() {
    for (M metaModel : metaModels) {
      for (P plugin : pluginMap.values()) {
        plugin.processEvents(metaModel, new EventQueue(metaModel.dispatch));
      }
      metaModel.dispatch.clear();
    }
  }

  public void postProcessEvents() {
    for (M metaModel : metaModels) {
      for (P plugin : pluginMap.values()) {
        plugin.postProcessEvents(metaModel);
      }
    }
  }

  public void prePassivate() {
    for (M metaModel : metaModels) {
      for (P plugin : pluginMap.values()) {
        plugin.prePassivate(metaModel);
      }
      metaModel.processingContext = null;
    }
    this.processingContext = null;
  }

  public void remove(M metaModel) {
    try {
      metaModel.processingContext = processingContext;

      //
      metaModels.remove(metaModel);

      // Initialize plugins
      for (P plugin : pluginMap.values()) {
        plugin.destroy(metaModel);
      }
    }
    finally {
      metaModel.processingContext = null;
    }
  }
}
TOP

Related Classes of juzu.impl.metamodel.MetaModelContext

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.