juzu.impl.metamodel.MetaModelContext Maven / Gradle / Ivy
/*
* 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 Julien Viet */
public final class MetaModelContext, M extends MetaModel
>
implements Serializable, Iterable {
/** . */
private ProcessingContext processingContext;
/** The meta model. */
private ArrayList metaModels;
/** The plugins. */
private LinkedHashMap pluginMap;
/** The supported annotations per plugin. */
private HashMap> supportedAnnotationsMap;
/** All supported annotations. */
private Set> supportedAnnotations;
/** . */
private final Class pluginType;
/** All known annotations. */
final LinkedHashMap knownAnnotations = new LinkedHashMap();
public MetaModelContext(Class pluginType) {
this.pluginType = pluginType;
this.metaModels = new ArrayList();
}
public void init(ProcessingContext env) throws NullPointerException {
this.processingContext = env;
//
HashMap> supportedAnnotationsMap = new HashMap
>();
LinkedHashMap pluginMap = new LinkedHashMap();
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> supportedAnnotations = new HashSet>();
for (P plugin : pluginMap.values()) {
HashSet pluginSupportedAnnotations = new HashSet();
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 iterator() {
return metaModels.iterator();
}
public Set> getSupportedAnnotations() {
return supportedAnnotations;
}
public Collection 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 annotation : knownAnnotations.entrySet()) {
change = new AnnotationChange(annotation.getKey(), null, annotation.getValue());
for (P plugin : pluginMap.values()) {
HashSet supportedAnnotations = supportedAnnotationsMap.get(plugin);
if (supportedAnnotations.contains(change.key.type)) {
plugin.processAnnotationChange(metaModel, change);
}
}
}
} else {
for (P plugin : pluginMap.values()) {
HashSet supportedAnnotations = supportedAnnotationsMap.get(plugin);
if (supportedAnnotations.contains(change.key.type)) {
plugin.processAnnotationChange(metaModel, change);
}
}
}
}
}
public void processAnnotationChanges(Iterable changes) {
for (AnnotationChange change : changes) {
processAnnotationChange(change);
}
}
void processAnnotations(Iterable> annotations) {
ArrayList delta = new ArrayList();
for (Map.Entry 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 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 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;
}
}
}