/******************************************************************************* * 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); } } }