blob: bb7727c91074d4eca13e634c5bda575ae5d33b4f [file] [log] [blame]
/******************************************************************************
* Copyright (c) 2008 BEA Systems, Inc.
* 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:
* Konstantin Komissarchik - initial implementation and ongoing maintenance
******************************************************************************/
package org.eclipse.wst.common.project.facet.core.internal;
import static org.eclipse.wst.common.project.facet.core.internal.FacetCorePlugin.PLUGIN_ID;
import static org.eclipse.wst.common.project.facet.core.internal.FacetCorePlugin.createErrorStatus;
import static org.eclipse.wst.common.project.facet.core.internal.FacetCorePlugin.log;
import static org.eclipse.wst.common.project.facet.core.internal.FacetCorePlugin.logError;
import static org.eclipse.wst.common.project.facet.core.util.internal.PluginUtil.findExtensions;
import static org.eclipse.wst.common.project.facet.core.util.internal.PluginUtil.findOptionalElement;
import static org.eclipse.wst.common.project.facet.core.util.internal.PluginUtil.findRequiredAttribute;
import static org.eclipse.wst.common.project.facet.core.util.internal.PluginUtil.findRequiredElement;
import static org.eclipse.wst.common.project.facet.core.util.internal.PluginUtil.getElementValue;
import static org.eclipse.wst.common.project.facet.core.util.internal.PluginUtil.getTopLevelElements;
import static org.eclipse.wst.common.project.facet.core.util.internal.PluginUtil.instantiate;
import java.util.Collections;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IConfigurationElement;
import org.eclipse.osgi.util.NLS;
import org.eclipse.wst.common.project.facet.core.IDynamicPreset;
import org.eclipse.wst.common.project.facet.core.IPreset;
import org.eclipse.wst.common.project.facet.core.IPresetFactory;
import org.eclipse.wst.common.project.facet.core.IProjectFacet;
import org.eclipse.wst.common.project.facet.core.IProjectFacetVersion;
import org.eclipse.wst.common.project.facet.core.PresetDefinition;
import org.eclipse.wst.common.project.facet.core.ProjectFacetsManager;
import org.eclipse.wst.common.project.facet.core.util.internal.IndexedSet;
import org.eclipse.wst.common.project.facet.core.util.internal.PluginUtil.InvalidExtensionException;
/**
* Contains the logic for processing the <code>presets</code> extension point.
*
* @author <a href="mailto:kosta@bea.com">Konstantin Komissarchik</a>
*/
public final class PresetsExtensionPoint
{
public static final String EXTENSION_POINT_ID = "presets"; //$NON-NLS-1$
private static final String OLD_EXTENSION_POINT_ID = "facets"; //$NON-NLS-1$
private static final String EL_DESCRIPTION = "description"; //$NON-NLS-1$
private static final String EL_DYNAMIC_PRESET = "dynamic-preset"; //$NON-NLS-1$
private static final String EL_FACET = "facet"; //$NON-NLS-1$
private static final String EL_FACTORY = "factory"; //$NON-NLS-1$
private static final String EL_LABEL = "label"; //$NON-NLS-1$
private static final String EL_PRESET = "preset"; //$NON-NLS-1$
private static final String EL_STATIC_PRESET = "static-preset"; //$NON-NLS-1$
private static final String ATTR_CLASS = "class"; //$NON-NLS-1$
private static final String ATTR_EXTENDS = "extends"; //$NON-NLS-1$
private static final String ATTR_ID = "id"; //$NON-NLS-1$
private static final String ATTR_VERSION = "version"; //$NON-NLS-1$
private static final String DEFAULT_DESCRIPTION = ""; //$NON-NLS-1$
private static IndexedSet<String,IPreset> presets = null;
public static Set<IPreset> getPresets()
{
readExtensions();
return presets.getItemSet();
}
public static IPreset getPreset( final String id )
{
readExtensions();
return presets.getItemByKey( id );
}
private static synchronized void readExtensions()
{
if( presets != null )
{
return;
}
presets = new IndexedSet<String,IPreset>();
for( IConfigurationElement element
: getTopLevelElements( findExtensions( PLUGIN_ID, EXTENSION_POINT_ID ) ) )
{
final String elName = element.getName();
if( elName.equals( EL_STATIC_PRESET ) )
{
try
{
readStaticPreset( element );
}
catch( InvalidExtensionException e )
{
// Continue. The problem has been reported to the user via the log.
}
}
else if( elName.equals( EL_DYNAMIC_PRESET ) )
{
try
{
readDynamicPreset( element );
}
catch( InvalidExtensionException e )
{
// Continue. The problem has been reported to the user via the log.
}
}
}
for( IConfigurationElement element
: getTopLevelElements( findExtensions( PLUGIN_ID, OLD_EXTENSION_POINT_ID ) ) )
{
if( element.getName().equals( EL_PRESET ) )
{
try
{
readStaticPreset( element );
}
catch( InvalidExtensionException e )
{
// Continue. The problem has been reported to the user via the log.
}
}
}
// Resolve the base presets. Make sure that no presets are extending presets that do not
// exist, check for circular references, etc.
Set<IPreset> copy = new HashSet<IPreset>( presets.getItemSet() );
for( IPreset preset : copy )
{
if( presets.containsItem( preset ) )
{
resolveBasePreset( preset, new HashSet<IPreset>() );
}
}
// Find static presets that are extending dynamic presets and make them into dynamic
// presets (StaticExtendingDynamicPreset class).
boolean doAnotherPass = true;
while( doAnotherPass )
{
doAnotherPass = false;
for( IPreset preset : presets.getItemSet() )
{
if( preset.getType() == IPreset.Type.STATIC )
{
final StaticPreset stPreset = (StaticPreset) preset;
final String basePresetId = stPreset.getBasePresetId();
if( basePresetId != null )
{
final IPreset basePreset = getPreset( basePresetId );
if( basePreset.getType() == IPreset.Type.DYNAMIC )
{
final StaticExtendingDynamicPreset stPresetNew
= new StaticExtendingDynamicPreset( stPreset.getId(),
stPreset.getPluginId(),
stPreset.getLabel(),
stPreset.getDescription(),
stPreset.getBasePresetId(),
stPreset.getProjectFacets() );
presets.removeItem( stPreset );
presets.addItemWithKey( stPresetNew.getId(), stPresetNew );
doAnotherPass = true;
break;
}
}
}
}
}
}
private static void readStaticPreset( final IConfigurationElement el )
throws InvalidExtensionException
{
final String pluginId = el.getContributor().getName();
final String id = findRequiredAttribute( el, ATTR_ID );
final IConfigurationElement elLabel = findOptionalElement( el, EL_LABEL );
final String label = getElementValue( elLabel, id );
final IConfigurationElement elDesc = findOptionalElement( el, EL_DESCRIPTION );
final String description = getElementValue( elDesc, DEFAULT_DESCRIPTION );
String basePreset = el.getAttribute( ATTR_EXTENDS );
if( basePreset != null )
{
basePreset = basePreset.trim();
if( basePreset.length() == 0 )
{
basePreset = null;
}
}
final Set<IProjectFacetVersion> facets = new HashSet<IProjectFacetVersion>();
for( IConfigurationElement child : el.getChildren() )
{
final String childName = child.getName();
if( childName.equals( EL_FACET ) )
{
final String fid = findRequiredAttribute( child, ATTR_ID );
final String fver = findRequiredAttribute( child, ATTR_VERSION );
if( ! ProjectFacetsManager.isProjectFacetDefined( fid ) )
{
final String msg
= Resources.bind( Resources.presetUsesUnknownFacet, id, pluginId, fid );
logError( msg );
return;
}
final IProjectFacet f = ProjectFacetsManager.getProjectFacet( fid );
if( ! f.hasVersion( fver ) )
{
final String msg
= Resources.bind( Resources.presetUsesUnknownFacetVersion, id, pluginId,
fid, fver );
logError( msg );
return;
}
final IProjectFacetVersion fv = f.getVersion( fver );
facets.add( fv );
}
}
final StaticPreset preset
= new StaticPreset( id, pluginId, label, description, basePreset, facets );
presets.addItemWithKey( id, preset );
}
private static void readDynamicPreset( final IConfigurationElement el )
throws InvalidExtensionException
{
final String pluginId = el.getContributor().getName();
final String id = findRequiredAttribute( el, ATTR_ID );
final IConfigurationElement elFactory = findRequiredElement( el, EL_FACTORY );
final String factoryClassName = findRequiredAttribute( elFactory, ATTR_CLASS );
final DynamicPreset preset = new DynamicPreset( id, pluginId, factoryClassName );
presets.addItemWithKey( id, preset );
}
private static boolean resolveBasePreset( final IPreset preset,
final Set<IPreset> visitedPresets )
{
if( preset.getType() == IPreset.Type.STATIC )
{
final StaticPreset stPreset = (StaticPreset) preset;
final String basePresetId = stPreset.getBasePresetId();
if( basePresetId != null )
{
final IPreset basePreset = getPreset( basePresetId );
boolean problem = false;
visitedPresets.add( preset );
if( basePreset == null )
{
final String msg
= Resources.bind( Resources.basePresetNotFound, stPreset.getId(),
stPreset.getPluginId(), basePresetId );
logError( msg );
problem = true;
}
else if( visitedPresets.contains( basePreset ) )
{
final StringBuilder cycle = new StringBuilder();
final int cycleSize = visitedPresets.size();
int count = 0;
for( IPreset vp : visitedPresets )
{
count++;
if( count > 1 )
{
if( count == cycleSize )
{
cycle.append( " and " ); //$NON-NLS-1$
}
else
{
cycle.append( ", " ); //$NON-NLS-1$
}
}
cycle.append( '"' );
cycle.append( vp.getId() );
cycle.append( '"' );
}
final String msg = Resources.bind( Resources.cycleDetected, cycle.toString() );
logError( msg );
problem = true;
}
else if( ! resolveBasePreset( basePreset, visitedPresets ) )
{
problem = true;
}
if( problem )
{
PresetsExtensionPoint.presets.removeItemByKey( preset.getId() );
return false;
}
}
}
return true;
}
private static class StaticPreset
implements IPreset
{
private final String id;
private final String pluginId;
private final String label;
private final String description;
private final String basePresetId;
private final Set<IProjectFacet> facets;
private final Set<IProjectFacetVersion> facetVersions;
private final Set<IProjectFacetVersion> facetVersionsReadOnly;
public StaticPreset( final String id,
final String pluginId,
final String label,
final String description,
final String basePreset,
final Set<IProjectFacetVersion> facets )
{
this.id = id;
this.pluginId = pluginId;
this.label = label;
this.description = description;
this.basePresetId = basePreset;
this.facetVersions = facets;
this.facetVersionsReadOnly = Collections.unmodifiableSet( this.facetVersions );
this.facets = new HashSet<IProjectFacet>( this.facetVersions.size() );
for( IProjectFacetVersion fv : this.facetVersions )
{
this.facets.add( fv.getProjectFacet() );
}
}
public final String getId()
{
return this.id;
}
public final String getPluginId()
{
return this.pluginId;
}
public Type getType()
{
return Type.STATIC;
}
public final String getLabel()
{
return this.label;
}
public final String getDescription()
{
return this.description;
}
public final String getBasePresetId()
{
return this.basePresetId;
}
public Set<IProjectFacetVersion> getProjectFacets()
{
if( this.basePresetId == null )
{
return this.facetVersionsReadOnly;
}
else
{
final IPreset basePreset = getPreset( this.basePresetId );
return createCombinedFacetSet( basePreset );
}
}
public final boolean isUserDefined()
{
return false;
}
public final String toString()
{
return this.id;
}
public boolean equals( final Object obj )
{
if( ! ( obj instanceof StaticPreset ) )
{
return false;
}
final StaticPreset p = (StaticPreset) obj;
return this.id.equals( p.id ) &&
this.pluginId.equals( p.pluginId ) &&
this.label.equals( p.label ) &&
this.description.equals( p.description ) &&
this.facetVersions.equals( p.facetVersions );
}
protected final Set<IProjectFacetVersion> createCombinedFacetSet( final IPreset basePreset )
{
final Set<IProjectFacetVersion> result
= new HashSet<IProjectFacetVersion>( this.facetVersions );
for( IProjectFacetVersion fv : basePreset.getProjectFacets() )
{
if( ! this.facets.contains( fv.getProjectFacet() ) )
{
result.add( fv );
}
}
return Collections.unmodifiableSet( result );
}
}
private static final class StaticExtendingDynamicPreset
extends StaticPreset
implements IDynamicPreset
{
public StaticExtendingDynamicPreset( final String id,
final String pluginId,
final String label,
final String description,
final String basePresetId,
final Set<IProjectFacetVersion> facets )
{
super( id, pluginId, label, description, basePresetId, facets );
}
@Override
public Type getType()
{
return Type.DYNAMIC;
}
@Override
public Set<IProjectFacetVersion> getProjectFacets()
{
return Collections.emptySet();
}
public IPreset resolve( final Map<String,Object> context )
{
final IDynamicPreset basePreset = (IDynamicPreset) getPreset( getBasePresetId() );
final IPreset resBasePreset = basePreset.resolve( context );
if( resBasePreset == null )
{
return null;
}
else
{
final Set<IProjectFacetVersion> facets = createCombinedFacetSet( resBasePreset );
return new StaticPreset( getId(), getPluginId(), getLabel(), getDescription(),
getBasePresetId(), facets );
}
}
}
private static final class DynamicPreset
implements IDynamicPreset
{
private final String id;
private final String pluginId;
private final String factoryClassName;
public DynamicPreset( final String id,
final String pluginId,
final String factoryClassName )
{
this.id = id;
this.pluginId = pluginId;
this.factoryClassName = factoryClassName;
}
public String getId()
{
return this.id;
}
public Type getType()
{
return Type.DYNAMIC;
}
public String getLabel()
{
return this.id;
}
public String getDescription()
{
return ""; //$NON-NLS-1$
}
public Set<IProjectFacetVersion> getProjectFacets()
{
return Collections.emptySet();
}
public boolean isUserDefined()
{
return false;
}
public IPreset resolve( final Map<String,Object> context )
{
IPresetFactory factory = null;
try
{
factory = instantiate( this.pluginId, this.factoryClassName, IPresetFactory.class );
}
catch( CoreException e )
{
log( e.getStatus() );
}
if( factory != null )
{
PresetDefinition def = null;
try
{
def = factory.createPreset( this.id, context );
}
catch( Exception e )
{
final String msg
= Resources.bind( Resources.failedWhileInvokingPresetFactory,
this.pluginId );
log( createErrorStatus( msg, e ) );
}
if( def != null )
{
final StaticPreset staticPreset
= new StaticPreset( this.id, this.pluginId, def.getLabel(),
def.getDescription(), null, def.getProjectFacets() );
return staticPreset;
}
}
return null;
}
public String toString()
{
return this.id;
}
}
private static final class Resources
extends NLS
{
public static String presetUsesUnknownFacet;
public static String presetUsesUnknownFacetVersion;
public static String basePresetNotFound;
public static String cycleDetected;
public static String failedWhileInvokingPresetFactory;
static
{
initializeMessages( PresetsExtensionPoint.class.getName(), Resources.class );
}
public static String bind( final String template,
final Object arg1,
final Object arg2,
final Object arg3 )
{
return NLS.bind( template, new Object[] { arg1, arg2, arg3 } );
}
public static String bind( final String template,
final Object arg1,
final Object arg2,
final Object arg3,
final Object arg4 )
{
return NLS.bind( template, new Object[] { arg1, arg2, arg3, arg4 } );
}
}
}