/*
* 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.template.metamodel;
import juzu.impl.common.Name;
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.JSON;
import juzu.impl.common.Path;
import juzu.impl.template.spi.TemplateModel;
import javax.lang.model.element.Element;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.Set;
/**
* A template.
*
* @author <a href="mailto:julien.viet@exoplatform.com">Julien Viet</a>
*/
public class TemplateMetaModel extends TemplateRefMetaModel implements Template {
/** . */
public static final MessageCode CANNOT_WRITE_TEMPLATE_STUB = new MessageCode("CANNOT_WRITE_TEMPLATE_STUB", "The template stub %1$s cannot be written");
/** . */
public static final MessageCode CANNOT_WRITE_TEMPLATE_CLASS = new MessageCode("CANNOT_WRITE_TEMPLATE_CLASS", "The template class %1$s cannot be written");
/** . */
public static final MessageCode CANNOT_WRITE_APPLICATION = new MessageCode("CANNOT_WRITE_APPLICATION", "The application %1$s cannot be written");
/** . */
public static final MessageCode TEMPLATE_NOT_RESOLVED = new MessageCode("TEMPLATE_NOT_RESOLVED", "The template %1$s cannot be resolved");
/** . */
public static final MessageCode TEMPLATE_SYNTAX_ERROR = new MessageCode("TEMPLATE_SYNTAX_ERROR", "Template syntax error");
/** . */
public static final MessageCode TEMPLATE_VALIDATION_ERROR = new MessageCode("TEMPLATE_VALIDATION_ERROR", "Template validation error");
/** . */
public static final MessageCode TEMPLATE_ILLEGAL_PATH = new MessageCode("TEMPLATE_ILLEGAL_PATH", "The reference to the template %1$s is malformed");
/** . */
public static final MessageCode CANNOT_WRITE_TEMPLATE_SCRIPT = new MessageCode("CANNOT_WRITE_TEMPLATE_SCRIPT", "The template script %1$s cannot be written");
/** . */
public static final MessageCode TEMPLATE_CYCLE = new MessageCode("TEMPLATE_CYCLE", "Detected a template cycle when registering %1$s conflicting with %2$s");
/** . */
public static final MessageCode CONTROLLER_NOT_RESOLVED = new MessageCode("CONTROLLER_NOT_RESOLVED",
"Controller %1$s not found in template %2$s at (%3$s,%4$s)");
/** . */
public static final MessageCode UNKNOWN_TAG = new MessageCode("UNKNOWN_TAG", "Tag %1$ does not exists");
/** . */
public final static Key<TemplateMetaModel> KEY = Key.of(TemplateMetaModel.class);
/** The related application. */
final AbstractContainerMetaModel container;
/** . */
final Path.Absolute path;
/** The related template. */
TemplateModel<?> templateModel;
public TemplateMetaModel(AbstractContainerMetaModel container, Path.Absolute path) {
this.path = path;
this.container = container;
this.templateModel = null;
}
public AbstractContainerMetaModel getContainer() {
return container;
}
/**
* Compute and return the {@link Element} referencing this template.
*
* @return the elements referencing this template
*/
public Element[] getReferencingElements() {
Set<Name> types = new LinkedHashSet<Name>();
for (ElementMetaModel ref : getElementReferences()) {
ElementHandle.Field handle = ref.getElement();
types.add(handle.getTypeName());
}
final Element[] elements = new Element[types.size()];
int index = 0;
for (Name type : types) {
elements[index++] = container.application.getProcessingContext().getTypeElement(type);
}
return elements;
}
/**
* Compute the element references to this template.
*
* @return the metamodel elements referencing this template
*/
public Collection<ElementMetaModel> getElementReferences() {
Collection<TemplateRefMetaModel> refs = getReferences();
for (Iterator<TemplateRefMetaModel> i = refs.iterator();i.hasNext();) {
if (i.next() instanceof TemplateMetaModel) {
i.remove();
}
}
// Safe cast as the collection now only contains instances of ElementTemplateRefMetaModel
return (Collection)refs;
}
/**
* Compute the references to this template.
*
* @return the ancestors
*/
public Collection<TemplateRefMetaModel> getReferences() {
HashSet<TemplateRefMetaModel> refs = new HashSet<TemplateRefMetaModel>();
buildReferences(refs);
return refs;
}
private void buildReferences(HashSet<TemplateRefMetaModel> refs) {
for (MetaModelObject parent : getParents()) {
if (parent instanceof TemplateRefMetaModel) {
TemplateRefMetaModel parentRef = (TemplateRefMetaModel)parent;
if (!refs.contains(parentRef)) {
refs.add(parentRef);
if (parentRef instanceof TemplateMetaModel) {
TemplateMetaModel parentTemplate = (TemplateMetaModel)parentRef;
parentTemplate.buildReferences(refs);
}
}
}
}
}
public Path.Absolute getPath() {
return path;
}
@Override
public void add(TemplateMetaModel template) {
Key<TemplateMetaModel> key = Key.of(template.getPath(), TemplateMetaModel.class);
if (getChild(key) == null) {
addChild(key, template);
}
}
public JSON toJSON() {
JSON json = new JSON();
json.set("path", path.getCanonical());
return json;
}
@Override
protected void postConstruct() {
container.templates.put(path, this);
queue(MetaModelEvent.createAdded(this));
}
@Override
protected void preRemove() {
ElementHandle.Package handle = container.application.getHandle();
container.templates.remove(path);
queue(MetaModelEvent.createRemoved(this, handle));
}
}