blob: b7b2b21db1ed57a5562d397381c3a710aef891c3 [file] [log] [blame]
/*******************************************************************************
* 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();
}
}