/******************************************************************************* * Copyright (c) 2008 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: * Cameron Bateman - initial API and implementation *******************************************************************************/ package org.eclipse.jst.jsf.facelet.core.internal.cm.strategy; import java.util.Collections; import java.util.HashMap; import java.util.Map; import java.util.concurrent.atomic.AtomicBoolean; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.ISafeRunnable; import org.eclipse.emf.edit.provider.ComposedAdapterFactory; import org.eclipse.jface.util.SafeRunnable; import org.eclipse.jst.jsf.common.dom.TagIdentifier; import org.eclipse.jst.jsf.common.internal.managedobject.IManagedObject; import org.eclipse.jst.jsf.common.internal.managedobject.ObjectManager.ManagedObjectException; import org.eclipse.jst.jsf.common.internal.resource.ResourceSingletonObjectManager; import org.eclipse.jst.jsf.facelet.core.internal.FaceletCorePlugin; import org.eclipse.jst.jsf.facelet.core.internal.cm.AttributeCMAdapter; import org.eclipse.jst.jsf.facelet.core.internal.cm.ExternalTagInfo; import org.eclipse.jst.jsf.facelet.core.internal.cm.TagInfo; import org.eclipse.jst.jsf.facelet.core.internal.cm.addtagmd.AddTagMDPackage; import org.eclipse.jst.jsf.facelet.core.internal.cm.addtagmd.AttributeData; import org.eclipse.jst.jsf.facelet.core.internal.cm.addtagmd.AttributeUsage; import org.eclipse.jst.jsf.facelet.core.internal.cm.addtagmd.ElementData; import org.eclipse.jst.jsf.facelet.core.internal.cm.addtagmd.provider.IResourceProvider; import org.eclipse.jst.jsf.facelet.core.internal.cm.strategy.InternalNamedNodeMap.NullInternalNamedNodeMap; import org.eclipse.jst.jsf.facelet.core.internal.util.TagMetadataLoader; import org.eclipse.wst.xml.core.internal.contentmodel.CMAttributeDeclaration; import org.eclipse.wst.xml.core.internal.contentmodel.CMNamedNodeMap; /** * An external meta-data strategy that uses the JSF meta-data framework. * * @author cbateman * */ public class MDExternalMetadataStrategy extends AbstractExternalMetadataStrategy implements IManagedObject { private static MySingletonManager MANAGER = new MySingletonManager(); /** * @param project * @return the instance of the strategy for project or */ public static IExternalMetadataStrategy create(final IProject project) { try { return MANAGER.getInstance(project); } catch (final ManagedObjectException e) { FaceletCorePlugin.log( "Getting managed instance of tag metadata strategy", e); //$NON-NLS-1$ } return new NullExternalMetadataStrategy(); } /** * The unique identifier for the strategy. */ public final static String STRATEGY_ID = "org.eclipse.jst.jsf.facelet.core.internal.cm.strategy.MDExternalMetadataStrategy"; //$NON-NLS-1$ // private static final String VAR = "var"; //$NON-NLS-1$ // private static final String VALUE = "value"; //$NON-NLS-1$ // private static final String SRC = "src"; //$NON-NLS-1$ // private static final String NAME = "name"; //$NON-NLS-1$ // private static final String HOTKEY = "hotkey"; //$NON-NLS-1$ // private static final String TEMPLATE = "template"; //$NON-NLS-1$ // private static final String BINDING = "binding"; //$NON-NLS-1$ // private static final String ID = "id"; //$NON-NLS-1$ private final IProject _project; private final TagMetadataLoader _tagMetadataLoader; private final Map<String, MDExternalTagInfo> _cached; private final AtomicBoolean _isDisposed = new AtomicBoolean( false); /** * Default constructor * * @param project */ private MDExternalMetadataStrategy(final IProject project) { super(STRATEGY_ID, Messages.MDExternalMetadataStrategy_DisplayName); _project = project; _tagMetadataLoader = new TagMetadataLoader(_project); _cached = new HashMap<String, MDExternalTagInfo>(); } public void checkpoint() { // do nothing } public void destroy() { // currently no persistent state, so just dispose } public void dispose() { if (_isDisposed.compareAndSet(false, true)) { _cached.clear(); } } /* * (non-Javadoc) * * @see org.eclipse.jst.jsf.facelet.core.internal.cm.strategy. * AbstractExternalMetadataStrategy * #perform(org.eclipse.jst.jsf.common.dom.TagIdentifier) */ @Override public TagInfo perform(final TagIdentifier input) throws Exception { MDExternalTagInfo tagInfo = _cached.get(input.getUri()); if (tagInfo == null) { tagInfo = new MDExternalTagInfo(input.getUri(), _tagMetadataLoader); _cached.put(input.getUri(), tagInfo); } return tagInfo; } private static class MDExternalTagInfo extends ExternalTagInfo { private final String _uri; private final TagMetadataLoader _tagMetadataLoader; private final Map<String, InternalNamedNodeMap> _attributes; public MDExternalTagInfo(final String uri, final TagMetadataLoader tagMetadataLoader) { _uri = uri; _tagMetadataLoader = tagMetadataLoader; _attributes = new HashMap<String, InternalNamedNodeMap>(); } @Override public CMNamedNodeMap getAttributes(final String tagName) { final InternalNamedNodeMap nodeMap = _attributes.get(tagName); final InternalNamedNodeMap[] innerClassNodeMap = new InternalNamedNodeMap[1]; innerClassNodeMap[0] = nodeMap; if (nodeMap == null) { SafeRunnable.run(new ISafeRunnable() { public void run() { final ElementData data = _tagMetadataLoader .getElementData(_uri, tagName); if (data != null) { innerClassNodeMap[0] = new InternalNamedNodeMap(); for (final AttributeData attribute : data .getAttributes()) { innerClassNodeMap[0] .add(createAttribute(attribute)); } _attributes.put(tagName, innerClassNodeMap[0]); } // no meta-data found for this tag, so mark as null // instance so future calls don't bother a re-lookup. else { _attributes.put(tagName, MDExternalMetadataStrategy.NULL_INSTANCE); } } public void handleException(final Throwable exception) { FaceletCorePlugin.log( "While loading attribute meta-data", exception); //$NON-NLS-1$ } }); } // don't return the null map instance if (innerClassNodeMap[0] == MDExternalMetadataStrategy.NULL_INSTANCE) { return null; } return innerClassNodeMap[0]; } @Override public Object getTagProperty(final String tagName, final String key) { final Object[] value = new Object[1]; value[0] = null; SafeRunnable.run(new ISafeRunnable() { public void run() { if ("description".equals(key)) //$NON-NLS-1$ { value[0] = _tagMetadataLoader.getDescription(_uri, tagName); } } public void handleException(final Throwable exception) { FaceletCorePlugin.log( "While loading tag property meta-data", exception); //$NON-NLS-1$ } }); return value[0]; } } private final static NullInternalNamedNodeMap NULL_INSTANCE = new NullInternalNamedNodeMap(); // temporary: transfer out to metadata final static Map<String, InternalNamedNodeMap> _faceletData; static { // final String ID_DESCRIPTION = // Messages.MDExternalMetadataStrategy_ID_DESCRIPTION; // final String BINDING_DESCRIPTION = // Messages.MDExternalMetadataStrategy_BINDING_DESCRIPTION; // final String TEMPLATE_DESCRIPTION = // Messages.MDExternalMetadataStrategy_TEMPLATE_DESCRIPTION; // final String HOTKEY_DESCRIPTION = // Messages.MDExternalMetadataStrategy_HOTKEY_DESCRIPTION; // final String DEFINE_NAME_DESCRIPTION = // Messages.MDExternalMetadataStrategy_DEFINE_NAME_DESCRIPTION; // final String SRC_DESCRIPTION = // Messages.MDExternalMetadataStrategy_SRC_DESCRIPTION; // final String INSERT_NAME_DESCRIPTION = // Messages.MDExternalMetadataStrategy_INSERT_NAME_DESCRIPTION; // final String PARAM_NAME_DESCRIPTION = // Messages.MDExternalMetadataStrategy_PARAM_NAME_DESCRIPTION; // final String PARAM_VALUE_DESCRIPTION = // Messages.MDExternalMetadataStrategy_PARAM_VALUE_DESCRIPTION; // final String REPEAT_VAR_DESCRIPTION = // Messages.MDExternalMetadataStrategy_REPEAT_VAR_DESCRIPTION; // final String REPEAT_VALUE_DESCRIPTION = // Messages.MDExternalMetadataStrategy_REPEAT_VALUE_DESCRIPTION; final Map<String, InternalNamedNodeMap> map = new HashMap<String, InternalNamedNodeMap>(); // component // InternalNamedNodeMap nodeMap = new InternalNamedNodeMap(); // nodeMap.add(createAttribute(ID, CMAttributeDeclaration.OPTIONAL, // ID_DESCRIPTION)); // nodeMap.add(createAttribute(BINDING, CMAttributeDeclaration.OPTIONAL, // BINDING_DESCRIPTION)); // map.put(IFaceletTagConstants.TAG_COMPONENT, nodeMap); // // // composition // nodeMap = new InternalNamedNodeMap(); // nodeMap.add(createAttribute(TEMPLATE, // CMAttributeDeclaration.OPTIONAL, // TEMPLATE_DESCRIPTION)); // map.put(IFaceletTagConstants.TAG_COMPOSITION, nodeMap); // debug // nodeMap = new InternalNamedNodeMap(); // nodeMap.add(createAttribute(HOTKEY, CMAttributeDeclaration.OPTIONAL, // HOTKEY_DESCRIPTION)); // map.put(IFaceletTagConstants.TAG_DEBUG, nodeMap); // decorate // nodeMap = new InternalNamedNodeMap(); // nodeMap.add(createAttribute(TEMPLATE, // CMAttributeDeclaration.REQUIRED, // TEMPLATE_DESCRIPTION)); // map.put(IFaceletTagConstants.TAG_DECORATE, nodeMap); // define // nodeMap = new InternalNamedNodeMap(); // nodeMap.add(createAttribute(NAME, CMAttributeDeclaration.REQUIRED, // DEFINE_NAME_DESCRIPTION)); // map.put(IFaceletTagConstants.TAG_DEFINE, nodeMap); // fragment // nodeMap = new InternalNamedNodeMap(); // nodeMap.add(createAttribute(ID, CMAttributeDeclaration.OPTIONAL, // ID_DESCRIPTION)); // nodeMap.add(createAttribute(BINDING, CMAttributeDeclaration.OPTIONAL, // BINDING_DESCRIPTION)); // map.put(IFaceletTagConstants.TAG_FRAGMENT, nodeMap); // include // nodeMap = new InternalNamedNodeMap(); // nodeMap.add(createAttribute(SRC, CMAttributeDeclaration.REQUIRED, // SRC_DESCRIPTION)); // map.put(IFaceletTagConstants.TAG_INCLUDE, nodeMap); // insert // nodeMap = new InternalNamedNodeMap(); // nodeMap.add(createAttribute(NAME, CMAttributeDeclaration.OPTIONAL, // INSERT_NAME_DESCRIPTION)); // map.put(IFaceletTagConstants.TAG_INSERT, nodeMap); // param // nodeMap = new InternalNamedNodeMap(); // nodeMap.add(createAttribute(NAME, CMAttributeDeclaration.REQUIRED, // PARAM_NAME_DESCRIPTION)); // nodeMap.add(createAttribute(VALUE, CMAttributeDeclaration.REQUIRED, // PARAM_VALUE_DESCRIPTION)); // map.put(IFaceletTagConstants.TAG_PARAM, nodeMap); // remove // nodeMap = new InternalNamedNodeMap(); // // no attributes // map.put(IFaceletTagConstants.TAG_PARAM, nodeMap); // repeat // nodeMap = new InternalNamedNodeMap(); // nodeMap.add(createAttribute(VALUE, CMAttributeDeclaration.REQUIRED, // REPEAT_VALUE_DESCRIPTION)); // nodeMap.add(createAttribute(VAR, CMAttributeDeclaration.REQUIRED, // REPEAT_VAR_DESCRIPTION)); // map.put(IFaceletTagConstants.TAG_REPEAT, nodeMap); _faceletData = Collections.unmodifiableMap(map); } private static CMAttributeDeclaration createAttribute( final AttributeData attributeData) { final AttributeCMAdapter attribute = new AttributeCMAdapter( attributeData.getName(), convertUsageEnum(attributeData .getUsage())); final ComposedAdapterFactory factory = new ComposedAdapterFactory( ComposedAdapterFactory.Descriptor.Registry.INSTANCE); final Object provider = factory.adapt(attributeData, IResourceProvider.class); // get the description from meta-data and feed through the provider // for possible translation String description = attributeData.getDescription(); if (provider instanceof IResourceProvider) { final IResourceProvider resProvider = (IResourceProvider) provider; final String translated = resProvider.getTranslatedString( attributeData, AddTagMDPackage.eINSTANCE .getAttributeData_Description()); description = translated != null ? translated : description; } attribute.setDescription(description); return attribute; } private static int convertUsageEnum(final AttributeUsage usage) { switch (usage) { case OPTIONAL: return CMAttributeDeclaration.OPTIONAL; case REQUIRED: return CMAttributeDeclaration.REQUIRED; case FIXED: return CMAttributeDeclaration.FIXED; case PROHIBITED: return CMAttributeDeclaration.PROHIBITED; default: return CMAttributeDeclaration.OPTIONAL; } } private static class MySingletonManager extends ResourceSingletonObjectManager<MDExternalMetadataStrategy, IProject> { protected MySingletonManager() { super(ResourcesPlugin.getWorkspace()); } @Override protected MDExternalMetadataStrategy createNewInstance( final IProject resource) { return new MDExternalMetadataStrategy(resource); } } public boolean isDisposed() { return _isDisposed.get(); } }