| /******************************************************************************* |
| * Copyright (c) 2003, 2004 IBM Corporation and others. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v10.html |
| * |
| * Contributors: |
| * IBM Corporation - initial API and implementation |
| *******************************************************************************/ |
| /* |
| * Created on Aug 22, 2003 |
| * |
| * To change the template for this generated file go to |
| * Window>Preferences>Java>Code Generation>Code and Comments |
| */ |
| package org.eclipse.jst.common.internal.annotations.registry; |
| |
| import java.util.ArrayList; |
| import java.util.Collection; |
| import java.util.HashMap; |
| import java.util.Hashtable; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Map; |
| |
| import org.eclipse.core.runtime.CoreException; |
| import org.eclipse.core.runtime.IConfigurationElement; |
| import org.eclipse.core.runtime.IExtension; |
| import org.eclipse.core.runtime.IExtensionPoint; |
| import org.eclipse.core.runtime.IExtensionRegistry; |
| import org.eclipse.core.runtime.Platform; |
| import org.eclipse.jem.util.logger.proxy.Logger; |
| import org.eclipse.osgi.util.NLS; |
| import org.osgi.framework.Bundle; |
| |
| /** |
| * @author kelleyp |
| * |
| * Singleton that parses the annotation tag information from the annotation-taghandler extension |
| * point, and provides an interface for accessing it for other classes. Largely taken from the |
| * AnnotationProcessor builder. |
| */ |
| |
| public class AnnotationTagRegistry { |
| |
| /** |
| * Set to true once we've read in the annotation tag information from the plugin registry. |
| */ |
| private static boolean initialized = false; |
| private static final String ANNOTATION_TAG_INFO = "org.eclipse.jst.common.annotations.controller.AnnotationTagInfo"; //$NON-NLS-1$ |
| |
| /** |
| * List of tag specs for all of the tags. |
| */ |
| private static ArrayList allTagSpecs = new ArrayList() { |
| final private static long serialVersionUID = 8683452581122892190L; |
| |
| private void scopeAll(Collection c, boolean forAdd) { |
| Iterator iter = c.iterator(); |
| while (iter.hasNext()) { |
| TagSpec ts = (TagSpec) iter.next(); |
| if (forAdd) |
| addScope(ts); |
| else |
| removeScope(ts); |
| } |
| } |
| |
| private void addScope(TagSpec ts) { |
| if (ts == null) |
| return; |
| switch (ts.getScope()) { |
| case TagSpec.FIELD : |
| fieldTags.put(ts.getTagName(), ts); |
| break; |
| case TagSpec.METHOD : |
| methodTags.put(ts.getTagName(), ts); |
| break; |
| case TagSpec.TYPE : |
| typeTags.put(ts.getTagName(), ts); |
| break; |
| } |
| } |
| |
| private void removeScope(TagSpec ts) { |
| if (ts == null) |
| return; |
| switch (ts.getScope()) { |
| case TagSpec.FIELD : |
| fieldTags.remove(ts.getTagName()); |
| break; |
| case TagSpec.METHOD : |
| methodTags.remove(ts.getTagName()); |
| break; |
| case TagSpec.TYPE : |
| typeTags.remove(ts.getTagName()); |
| break; |
| } |
| } |
| |
| @Override |
| public void add(int index, Object element) { |
| super.add(index, element); |
| addScope((TagSpec)element); |
| } |
| |
| @Override |
| public boolean add(Object o) { |
| TagSpec newTagSpec = (TagSpec)o; |
| // search for already existing tag spec with same name and same tag set name |
| for (int i=0; i<this.size(); i++) { |
| TagSpec tagSpec = (TagSpec) get(i); |
| if (tagSpec.getTagName().equals(newTagSpec.getTagName()) && tagSpec.getScope() == newTagSpec.getScope()) { |
| remove(tagSpec); |
| removeScope(tagSpec); |
| } |
| } |
| // add the new tag spec |
| addScope(newTagSpec); |
| return super.add(newTagSpec); |
| } |
| |
| @Override |
| public boolean addAll(Collection c) { |
| scopeAll(c, true); |
| return super.addAll(c); |
| } |
| |
| @Override |
| public boolean addAll(int index, Collection c) { |
| scopeAll(c, true); |
| return super.addAll(index, c); |
| } |
| |
| @Override |
| public Object remove(int index) { |
| Object result = super.remove(index); |
| removeScope((TagSpec) result); |
| return result; |
| } |
| |
| @Override |
| public boolean remove(Object o) { |
| removeScope((TagSpec) o); |
| return super.remove(o); |
| } |
| |
| @Override |
| public boolean removeAll(Collection c) { |
| scopeAll(c, false); |
| return super.removeAll(c); |
| } |
| |
| @Override |
| public boolean retainAll(Collection c) { |
| Iterator iter = this.iterator(); |
| while (iter.hasNext()) { |
| TagSpec ts = (TagSpec) iter.next(); |
| if (!c.contains(ts)) |
| removeScope(ts); |
| } |
| return super.retainAll(c); |
| } |
| }; |
| |
| /** |
| * Map from a tag name to a InitTagInfo. Only live during up to the end of the init() method. |
| */ |
| private static Hashtable tagAttribs = new Hashtable(); |
| |
| /** |
| * Division of tag names between allowed scopes. |
| */ |
| private static Map methodTags = new HashMap(); |
| |
| private static Map typeTags = new HashMap(); |
| |
| private static Map fieldTags = new HashMap(); |
| |
| private static final String CLASS_PROP = "class"; //$NON-NLS-1$ |
| private static final String DYNAMIC_INITIALIZER_EX_PT = "annotationTagDynamicInitializer"; //$NON-NLS-1$ |
| private static final String ANNOTATIONS_CONTROLLER_NAMESPACE = "org.eclipse.jst.common.annotations.controller"; //$NON-NLS-1$ |
| |
| /** |
| * Helper for init, parse the tag attributes for a AnnotationTagInfo tag. |
| * |
| * @param elems |
| * Array of "attrib" configuration elements. |
| * @param tagName |
| * Lowercased name of the tag these attributes are associated with. |
| */ |
| private static InitTagInfo parseTagAttribs(IConfigurationElement[] elems, String tagName, String scope) { |
| int i; |
| ArrayList attribList = new ArrayList(); |
| |
| InitTagInfo tagInf = new InitTagInfo(tagName, scope, attribList); |
| |
| for (i = 0; i < elems.length; i++) { |
| IConfigurationElement elem = elems[i]; |
| |
| if (elem.getName().equalsIgnoreCase("attrib")) { //$NON-NLS-1$ |
| TagAttribSpec tas = new TagAttribSpec(elem.getAttribute("name"), elem.getAttribute("description")); //$NON-NLS-1$ //$NON-NLS-2$ |
| String use = elem.getAttribute("use"); //$NON-NLS-1$ |
| |
| tas.setType(elem.getAttribute("type")); //$NON-NLS-1$ |
| |
| // add valid values |
| if ("enum".equals(elem.getAttribute("type"))) { //$NON-NLS-1$ //$NON-NLS-2$ |
| IConfigurationElement[] validValues = elem.getChildren("enumValues"); //$NON-NLS-1$ |
| List valuesList = new ArrayList(); |
| for (int j = 0; j < validValues.length; j++) { |
| String value = validValues[j].getAttribute("value"); //$NON-NLS-1$ |
| valuesList.add(value); |
| } |
| String[] validValuesArray = new String[valuesList.size()]; |
| validValuesArray = (String[]) valuesList.toArray(validValuesArray); |
| |
| tas.setValidValues(validValuesArray); |
| } |
| |
| if (use == null) { |
| tas.clearRequired(); |
| } else if (use.equalsIgnoreCase("required")) { //$NON-NLS-1$ |
| tas.setRequired(); |
| } else if (use.equalsIgnoreCase("optional")) { //$NON-NLS-1$ |
| tas.clearRequired(); |
| } else { |
| // Unlikely, unless annotation extension spec changes |
| // without changes here. |
| System.err.println(AnnotationsControllerResources.AnnotationTagRegistry_9 + use); |
| return null; |
| } |
| |
| IConfigurationElement[] elemUniqueArray = elem.getChildren("unique"); //$NON-NLS-1$ |
| if (elemUniqueArray.length > 0) { |
| tas.setUnique(); |
| if (elemUniqueArray[0].getAttribute("scope") != null) //$NON-NLS-1$ |
| tas.getUnique().setScope(TagAttribSpec.uniqueScopeFromString(elemUniqueArray[0].getAttribute("scope"))); //$NON-NLS-1$ |
| if (elemUniqueArray.length > 1) { |
| Logger.getLogger().logError(AnnotationsControllerResources.TagAttribSpec_2 + elemUniqueArray.length); |
| } |
| } else { |
| tas.clearUnique(); |
| } |
| |
| attribList.add(tas); |
| } |
| } |
| return tagInf; |
| } |
| |
| /** |
| * Return the tag set name from a full tag name. |
| * |
| * @param name |
| * Full tag name (without the '@' at the beginning) |
| * @return |
| */ |
| public static String tagSetFromTagName(String name) { |
| if (name == null) |
| return null; |
| int idx = name.lastIndexOf('.'); |
| |
| if (idx != -1) |
| return name.substring(0, idx); |
| return ""; //$NON-NLS-1$ |
| } |
| |
| /** |
| * Return the short name from a full tag name. |
| * |
| * @param name |
| * Full tag name (without the '@' at the beginning) |
| * @return |
| */ |
| public static String tagFromTagName(String name) { |
| if (name == null) |
| return null; |
| int idx = name.indexOf('.'); |
| |
| if (idx != -1) { |
| return name.substring(idx + 1); |
| } |
| // Default to the whole name being the tagset. |
| return name; |
| } |
| |
| /** |
| * Reads in all of the tag attribute information from all annotation-tag-info extensions defined |
| * in the system, and initializes the tagAttribs hashtable with them. |
| * |
| * @param registry |
| */ |
| private static void readAllAttributeInfo(IExtensionPoint xp) { |
| |
| if (xp == null) { |
| return; |
| } |
| |
| IExtension[] exts = xp.getExtensions(); |
| Bundle bundle = null; |
| for (int i = 0; i < exts.length; i++) { |
| IConfigurationElement[] elems = exts[i].getConfigurationElements(); |
| bundle = Platform.getBundle(exts[i].getNamespace()); |
| String identifier = exts[i].getUniqueIdentifier(); |
| |
| IConfigurationElement elem = null; |
| String tagName = null; |
| String scope = null; |
| String tagSet = null; |
| String fullTagName = null; |
| for (int j = 0; j < elems.length; j++) { |
| elem = elems[j]; |
| if (!elem.getName().equalsIgnoreCase("AnnotationTagInfo")) { //$NON-NLS-1$ |
| continue; |
| } |
| tagSet = elem.getAttribute("tagSet"); //$NON-NLS-1$ |
| tagName = elem.getAttribute("tagName"); //$NON-NLS-1$ |
| scope = elem.getAttribute("scope"); //$NON-NLS-1$ |
| if (isNullOrEmpty(tagSet) || isNullOrEmpty(tagName) || isNullOrEmpty(scope)) { |
| Logger.getLogger().log(NLS.bind(AnnotationsControllerResources.AnnotationTagRegistry_10, new Object[]{identifier})); |
| continue; |
| } |
| fullTagName = tagSet + "." + tagName; //$NON-NLS-1$ |
| |
| InitTagInfo tagInf = parseTagAttribs(elem.getChildren(), fullTagName.toLowerCase(), scope); |
| String key = (fullTagName + "#" + scope).toLowerCase(); //$NON-NLS-1$ |
| /* |
| * There should only ever be one AnnotationTagInfo tag for any one annotation tag. |
| */ |
| if (tagAttribs.containsKey(key)) { |
| Logger.getLogger().log(AnnotationsControllerResources.AnnotationTagRegistry_0 + tagName + "'."); //$NON-NLS-1$ |
| } else { |
| tagInf.bundle = bundle; |
| tagAttribs.put(key, tagInf); |
| } |
| } |
| } |
| } |
| |
| private static boolean isNullOrEmpty(String aString) { |
| return aString == null || aString.length() == 0; |
| } |
| |
| /** |
| * Reads tagSpec information in from the plugin registry. Taken from AnnotationProcessor. |
| * |
| * @return True if initialization completed successfully. |
| * @throws CoreException |
| * If there were problems reading the registry. |
| */ |
| private static/* synchronized */boolean init() throws CoreException { |
| |
| /* Prevent multiple initialization */ |
| if (initialized) { |
| return true; |
| } |
| initializeStaticTagDefinitions(); |
| initiaizeDynamicTagDefinitions(); |
| initialized = true; |
| |
| /* Don't need this anymore */ |
| tagAttribs = null; |
| |
| return true; |
| } |
| |
| private static void initializeStaticTagDefinitions() throws CoreException { |
| IExtensionRegistry registry = Platform.getExtensionRegistry(); |
| |
| // TODO: Not even checking the tagset extension point yet. |
| IExtensionPoint xp = registry.getExtensionPoint(ANNOTATION_TAG_INFO); |
| |
| if (xp == null) |
| return; |
| |
| IExtension[] x = xp.getExtensions(); |
| |
| /* Get all tag attribute information */ |
| readAllAttributeInfo(xp); |
| for (int j = 0; j < x.length; j++) { |
| IConfigurationElement[] tagSpecs = x[j].getConfigurationElements(); |
| for (int i = 0; i < tagSpecs.length; i++) { |
| IConfigurationElement tagSpec = tagSpecs[i]; |
| String tagName = tagSpec.getAttribute("tagSet") + "." + tagSpec.getAttribute("tagName"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ |
| String scope = tagSpec.getAttribute("scope"); //$NON-NLS-1$ |
| String multiplicity = tagSpec.getAttribute("multiplicity"); //$NON-NLS-1$ |
| TagSpec ts = null; |
| if (multiplicity != null) |
| ts = new TagSpec(tagName, TagSpec.scopeFromString(scope), TagSpec.multiplicityFromString(multiplicity)); |
| else |
| ts = new TagSpec(tagName, TagSpec.scopeFromString(scope), TagSpec.Multiplicity.ONE); |
| String key = (tagName + "#" + scope).toLowerCase(); //$NON-NLS-1$ |
| InitTagInfo tagInf = (InitTagInfo) tagAttribs.get(key); |
| |
| allTagSpecs.add(ts); |
| |
| if (tagInf != null) { |
| ts.setAttributes(tagInf.attributes); |
| ts.setBundle(tagInf.bundle); |
| } |
| } |
| } |
| } |
| |
| private static void initiaizeDynamicTagDefinitions() { |
| IExtensionPoint xp = Platform.getExtensionRegistry().getExtensionPoint(ANNOTATIONS_CONTROLLER_NAMESPACE, DYNAMIC_INITIALIZER_EX_PT); |
| if (xp == null) |
| return; |
| IExtension[] extensions = xp.getExtensions(); |
| for (int i = 0; i < extensions.length; i++) { |
| IExtension extension = extensions[i]; |
| IConfigurationElement[] elements = extension.getConfigurationElements(); |
| for (int j = 0; j < elements.length; j++) { |
| try { |
| AnnotationTagDynamicInitializer initializer = (AnnotationTagDynamicInitializer) elements[j].createExecutableExtension(CLASS_PROP); |
| initializer.registerTags(); |
| } catch (CoreException e) { |
| Logger.getLogger().logError(e); |
| } |
| } |
| } |
| } |
| |
| /** |
| * |
| * @return List of AnnotationTagRegistry.TagSpecs for all tags. |
| * @throws CoreException |
| * If there were problems reading the initialization data from the plugin registry. |
| */ |
| public static synchronized List getAllTagSpecs() { |
| return allTagSpecs; |
| } |
| |
| public static synchronized boolean isMethodTag(String tagName) { |
| return methodTags.containsKey(tagName); |
| } |
| |
| public static synchronized boolean isFieldTag(String tagName) { |
| return fieldTags.containsKey(tagName); |
| } |
| |
| public static synchronized boolean isTypeTag(String tagName) { |
| return typeTags.containsKey(tagName); |
| } |
| |
| /** |
| * Answers the tagspec for the specified method tag name. |
| * |
| * @param tagName |
| * Full name for a tag. |
| * @return a TagSpec for the tag name, or null if no tag with that name is registered. |
| */ |
| public static synchronized TagSpec getMethodTag(String tagName) { |
| return (TagSpec) methodTags.get(tagName); |
| } |
| |
| /** |
| * Answers the tagspec for the specified field tag name. |
| * |
| * @param tagName |
| * Full name for a tag. |
| * @return a TagSpec for the tag name, or null if no tag with that name is registered. |
| */ |
| public static synchronized TagSpec getFieldTag(String tagName) { |
| return (TagSpec) fieldTags.get(tagName); |
| } |
| |
| /** |
| * Answers the tagspec for the specified type tag name. |
| * |
| * @param tagName |
| * Full name for a tag. |
| * @return a TagSpec for the tag name, or null if no tag with that name is registered. |
| */ |
| public static synchronized TagSpec getTypeTag(String tagName) { |
| return (TagSpec) typeTags.get(tagName); |
| } |
| |
| private static class InitTagInfo { |
| private String name; |
| |
| private List attributes; |
| |
| private Bundle bundle; |
| |
| private String scope; |
| |
| public InitTagInfo(String name, String scope, List att) { |
| attributes = att; |
| this.name = name; |
| this.scope = scope; |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see java.lang.Object#equals(java.lang.Object) |
| */ |
| @Override |
| public boolean equals(Object obj) { |
| if (this == obj) |
| return true; |
| else if (!(obj instanceof InitTagInfo)) |
| return false; |
| |
| return name.equals(((InitTagInfo) obj).name) || (scope.equals(((InitTagInfo) obj).name)); |
| |
| } |
| |
| @Override |
| public int hashCode() { |
| return super.hashCode() + name.hashCode(); |
| } |
| } |
| |
| static { |
| try { |
| AnnotationTagRegistry.init(); |
| } catch (CoreException e) { |
| Logger.getLogger().logError(AnnotationsControllerResources.AnnotationTagRegistry_ERROR_1); |
| Logger.getLogger().logError(e); |
| } |
| } |
| } |