/* * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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.apache.flex.compiler.internal.tree.as.metadata; import java.util.List; import org.apache.flex.compiler.definitions.IDefinition; import org.apache.flex.compiler.definitions.metadata.IMetaTag; import org.apache.flex.compiler.definitions.metadata.IMetaTagAttribute; import org.apache.flex.compiler.filespecs.IFileSpecification; import org.apache.flex.compiler.internal.definitions.metadata.MetaTag; import org.apache.flex.compiler.internal.tree.as.IdentifierNode; import org.apache.flex.compiler.internal.tree.as.TreeNode; import org.apache.flex.compiler.tree.ASTNodeID; import org.apache.flex.compiler.tree.as.IASNode; import org.apache.flex.compiler.tree.as.IDefinitionNode; import org.apache.flex.compiler.tree.metadata.IMetaTagNode; import org.apache.flex.utils.CheapArray; /** * MetaAttributeNode is a generic node holding info for one metadata attribute. * The name of the attribute is the meta name ("Inspectable", "Bindable", * "Style", etc.) (not the name of any "name" attribute within the tag) */ public abstract class MetaTagNode extends TreeNode implements IMetaTagNode { private static final IMetaTagAttribute[] EMPTY_ARRAY = new IMetaTagAttribute[0]; static final String NAME = "name"; static final String VALUE = "value"; static final String ATTR_PAIR = "AttrPair"; private static MetaTagValue[] emptyAttrArray = new MetaTagValue[0]; /** * Meta attribute comparator used to assist MetaAttributesNode.equals. Only * used in freeze/thaw unit tests. */ public static class MetaComparator implements java.util.Comparator<Object> { @Override public int compare(Object o1, Object o2) { if (o1 instanceof MetaTagNode && o2 instanceof MetaTagNode) { return ((MetaTagNode)o1).toString().compareTo(((MetaTagNode)o2).toString()); } else if (o1 instanceof MetaTagValue && o2 instanceof MetaTagValue) { return ((MetaTagValue)o1).toString().compareTo(((MetaTagValue)o2).toString()); } return 0; } } protected String tagName; private Object metaAttrs; /** * Constructor * * @param name name of attribute (e.g. Event or IconFile) */ public MetaTagNode(String name) { if (name != null) tagName = name; metaAttrs = CheapArray.create(4); } /** * Copy constructor * * @param other attribute to copy */ public MetaTagNode(MetaTagNode other) { this.metaAttrs = other.metaAttrs; this.tagName = other.tagName; } public void addToMap(String name, String value) { if (!(metaAttrs instanceof List)) metaAttrs = CheapArray.create(2); if (name == null || name.equals(IMetaTagNode.SINGLE_VALUE)) CheapArray.add(new MetaTagValue(value), metaAttrs); else CheapArray.add(new MetaTagValue(name, value), metaAttrs); } @Override protected void optimizeChildren(Object newChildren) { metaAttrs = CheapArray.optimize(metaAttrs, emptyAttrArray); super.optimizeChildren(newChildren); } @Override protected int getInitialChildCount() { return 0; } @Override public IDefinitionNode getDecoratedDefinitionNode() { IASNode parent = getParent(); if (parent instanceof MetaTagsNode) { return ((MetaTagsNode)parent).getDecoratedDefinition(); } return null; } public String getValue(String key) { IMetaTagAttribute attribute = getAttribute(key); if (attribute != null) return attribute.getValue(); return ""; } @Override public IMetaTagAttribute getAttribute(String key) { int size = CheapArray.size(metaAttrs); for (int i = 0; i < size; i++) { Object object = CheapArray.get(i, metaAttrs); if (object instanceof IMetaTagAttribute) { if (key == SINGLE_VALUE && !((IMetaTagAttribute)object).hasKey()) { //just return the first one we find return ((IMetaTagAttribute)object); } String tagKey = ((IMetaTagAttribute)object).getKey(); if (tagKey!= null && tagKey.compareTo(key)==0) { return ((IMetaTagAttribute)object); } } } return null; } @Override public String getAttributeValue(String key) { IMetaTagAttribute attribute = getAttribute(key); return attribute != null ? attribute.getValue() : null; } @Override public IMetaTagAttribute[] getAllAttributes() { return (IMetaTagAttribute[])CheapArray.toArray(metaAttrs, EMPTY_ARRAY); } @Override public boolean equals(Object obj) { if (obj instanceof MetaTagNode) { if (getAbsoluteStart() != ((MetaTagNode)obj).getAbsoluteStart()) return false; if (getAbsoluteEnd() != ((MetaTagNode)obj).getAbsoluteEnd()) return false; return obj.toString().compareTo(this.toString()) == 0; } return super.equals(obj); } /** * For debugging only. Builds a string such as * <code>Event(name="click", type="flash.events.MouseEvent")</code> from the * metadata. */ @Override protected boolean buildInnerString(StringBuilder sb) { sb.append('['); sb.append(getTagName()); sb.append('('); int size = CheapArray.size(metaAttrs); for (int i = 0; i < size; i++) { String key = ((IMetaTagAttribute)CheapArray.get(i, metaAttrs)).getKey(); String value = ((IMetaTagAttribute)CheapArray.get(i, metaAttrs)).getValue(); if (key == null) { sb.append('"'); sb.append(value); sb.append('"'); } else { sb.append(key); sb.append('='); sb.append('"'); sb.append(value); sb.append('"'); if (i + 1 < size) { sb.append(','); sb.append(' '); } } } sb.append(')'); sb.append(']'); return true; } @Override public String getTagName() { return tagName; } protected boolean equals(IdentifierNode left, IdentifierNode right) { if (left == null && right == null) return true; if (left == null) return false; if (right == null) return false; if (left.getName().compareTo(right.getName()) != 0) return false; if (left.getAbsoluteStart() != right.getAbsoluteStart()) return false; if (left.getAbsoluteEnd() != right.getAbsoluteEnd()) return false; return true; } public String getDefaultValue(String name, String defaultValue) { return getValue(defaultValue); } @Override public ASTNodeID getNodeID() { return ASTNodeID.MetaTagID; } public IMetaTag buildMetaTag(IFileSpecification containingFileSpec, IDefinition definition) { String name = getTagName(); MetaTag metaTag = new MetaTag(definition, name, getAllAttributes()); metaTag.setLocation(containingFileSpec, getAbsoluteStart(), getAbsoluteEnd(), getLine(), getColumn()); return metaTag; } }