/******************************************************************************* * Copyright (c) 2006 Oracle Corporation. * 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: * Gerry Kessler/Oracle - initial API and implementation * ********************************************************************************/ package org.eclipse.jst.jsf.metadataprocessors.internal; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import org.eclipse.core.runtime.IExtension; import org.eclipse.core.runtime.IExtensionPoint; import org.eclipse.core.runtime.InvalidRegistryObjectException; import org.eclipse.core.runtime.Platform; import org.eclipse.jst.jsf.core.internal.JSFCorePlugin; import org.eclipse.jst.jsf.metadataprocessors.IType; /** * Registry of <code>AbstractMetaDataEnabledType</code>s loaded from * the <code>MetaDataEnabledFeatures</code> extension point * * A map of features keyed by type id * */ public class MetaDataEnabledFeatureRegistry{ private static final String EXTPTID = "MetaDataEnabledFeatures"; //$NON-NLS-1$ private Map<String, List<IMetaDataEnabledFeatureExtension>> featuresMap; private Map<String, Class> typeCacheMap; private static MetaDataEnabledFeatureRegistry INSTANCE; /** * @return the singleton instance of the MetaDataEnabledFeatureRegistry */ public static synchronized MetaDataEnabledFeatureRegistry getInstance(){ if (INSTANCE == null){ INSTANCE = new MetaDataEnabledFeatureRegistry(); } return INSTANCE; } private MetaDataEnabledFeatureRegistry(){ featuresMap = new HashMap<String, List<IMetaDataEnabledFeatureExtension>>(); typeCacheMap = new HashMap<String, Class>(); readRegistry(); } /** * Reads the MetaDataEnabledFeatures extensions into a registry */ protected void readRegistry() { try { IExtensionPoint point = Platform.getExtensionRegistry().getExtensionPoint(JSFCorePlugin.PLUGIN_ID, EXTPTID); IExtension[] extensions = point.getExtensions(); for (int i=0;i < extensions.length;i++){ IExtension ext = extensions[i]; for (int j=0;j < ext.getConfigurationElements().length;j++){ final String bundleId = ext.getConfigurationElements()[j].getContributor().getName(); final String id = ext.getConfigurationElements()[j].getAttribute("typeid"); //$NON-NLS-1$ final String klass = ext.getConfigurationElements()[j].getAttribute("class"); //$NON-NLS-1$ registerFeature(bundleId, id, klass); } } } catch (InvalidRegistryObjectException e) { JSFCorePlugin.log(e, "Unable to read " + JSFCorePlugin.PLUGIN_ID + EXTPTID + " registry"); //$NON-NLS-1$ //$NON-NLS-2$ } } /** * Create {@link IMetaDataEnabledFeatureExtension}s and add to registry * @param bundleID * @param typeId * @param klass */ protected void registerFeature(String bundleID, String typeId, String klass){ IMetaDataEnabledFeatureExtension aFeature = new MetaDataEnabledFeatureExtension(bundleID, typeId, klass); if (canCreateTypeForFeatureExtension(aFeature)){ if (!featuresMap.containsKey(typeId)){ List list = new ArrayList(); list.add(aFeature); featuresMap.put(typeId, list); } else { List list = featuresMap.get(typeId); if (list != null) { list.add(aFeature); } } } } private boolean canCreateTypeForFeatureExtension(IMetaDataEnabledFeatureExtension feature) { if (! typeCacheMap.containsKey(feature.getTypeID())){ IType type = AttributeValueRuntimeTypeRegistry.getInstance().getType(feature.getTypeID()); if (type != null){ Class typeClass = AttributeValueRuntimeTypeFactory.getInstance().getClassForType(type); typeCacheMap.put(feature.getTypeID(), typeClass); } else return false; } return typeCacheMap.get(feature.getTypeID()) != null; } /** * @param typeId * @return List of <code>AbstractMetaDataEnabledRuntimeTypeExtensions</code> * for a given by type id * * TODO: make more efficient... no need to keep calculating features for subtypes. */ public List<IMetaDataEnabledFeatureExtension> getFeatures(String typeId) { if (!featuresMap.containsKey(typeId)) featuresMap.put(typeId,new ArrayList()); //copy current featuresMapped to typeId into return list List<IMetaDataEnabledFeatureExtension> srcList = getExtensionsForId(typeId); List<IMetaDataEnabledFeatureExtension> ret = new ArrayList<IMetaDataEnabledFeatureExtension>(srcList.size()); copy(ret, srcList); List subs = getFeatureExtensionsForMatchingSubclass(typeId); for (Iterator<IMetaDataEnabledFeatureExtension> it=subs.iterator();it.hasNext();){ IMetaDataEnabledFeatureExtension featureExt = it.next(); if (!ret.contains(featureExt)) ret.add(featureExt); } return ret; } private void copy(List<IMetaDataEnabledFeatureExtension> destList, List<IMetaDataEnabledFeatureExtension> srcList) { for (Iterator<IMetaDataEnabledFeatureExtension> it=srcList.iterator();it.hasNext();){ destList.add(it.next()); } } /** * If the feature adapter is mapped to a type which is a superclass of the type of interest, then the feature adapter is an extension of that type * @param typeId * @return list of IMetaDataEnabledFeatureExtension */ private List<IMetaDataEnabledFeatureExtension> getFeatureExtensionsForMatchingSubclass(String typeId) { IType type = AttributeValueRuntimeTypeRegistry.getInstance().getType(typeId); Class typeClass = AttributeValueRuntimeTypeFactory.getInstance().getClassForType(type); List<IMetaDataEnabledFeatureExtension> ret = new ArrayList<IMetaDataEnabledFeatureExtension>(); // loop thru all of the type classes mapped to feature adapters that are subclasses of the type for (Iterator it=typeCacheMap.keySet().iterator();it.hasNext();){ String featureTypeId = (String)it.next(); Class featureTypeClass = typeCacheMap.get(featureTypeId); if (featureTypeClass != null && featureTypeClass.isAssignableFrom(typeClass)) { ret.addAll(getExtensionsForId(featureTypeId)); } } return ret; } private List<IMetaDataEnabledFeatureExtension> getExtensionsForId(String featureTypeId) { List<IMetaDataEnabledFeatureExtension> list = featuresMap.get(featureTypeId); if (list == null) { return Collections.emptyList(); } return Collections.unmodifiableList(list); } }