blob: 4d257fd16a88214126a88f42ae56ec31bec73ff7 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2007, 2008 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
* yyyymmdd bug Email and other contact information
* -------- -------- -----------------------------------------------------------
* 20071024 196997 pmoogk@ca.ibm.com - Peter Moogk
* 20071113 209701 pmoogk@ca.ibm.com - Peter Moogk
* 20080111 214907 pmoogk@ca.ibm.com - Peter Moogk
* 20080214 218996 pmoogk@ca.ibm.com - Peter Moogk, Concurrent exception fix
* 20080325 222095 pmoogk@ca.ibm.com - Peter Moogk
* 20080625 238482 pmoogk@ca.ibm.com - Peter Moogk, Adding thread safety to the service platform api.
*******************************************************************************/
package org.eclipse.wst.ws.service.internal.policy;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Vector;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.eclipse.core.expressions.EvaluationContext;
import org.eclipse.core.expressions.EvaluationResult;
import org.eclipse.core.expressions.Expression;
import org.eclipse.core.expressions.IEvaluationContext;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.ProjectScope;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.preferences.IEclipsePreferences;
import org.eclipse.wst.ws.service.policy.IFilter;
import org.eclipse.wst.ws.service.policy.IServicePolicy;
import org.eclipse.wst.ws.service.policy.IStateEnumerationItem;
import org.eclipse.wst.ws.service.policy.ServicePolicyActivator;
import org.eclipse.wst.ws.service.policy.ServicePolicyPlatform;
import org.eclipse.wst.ws.service.policy.listeners.IPolicyChildChangeListener;
import org.eclipse.wst.ws.service.policy.listeners.IPolicyPlatformLoadListener;
import org.eclipse.wst.ws.service.policy.listeners.IPolicyPlatformProjectLoadListener;
import org.osgi.service.prefs.BackingStoreException;
public class ServicePolicyPlatformImpl
{
private List<IPolicyPlatformLoadListener> loadListeners;
private Map<String, ServicePolicyImpl> committedPolicyMap;
private Map<String, ServicePolicyImpl> policyMap;
private Map<String, List<IStateEnumerationItem>> enumList;
private Map<String, StateEnumerationItemImpl> enumItemList;
private Map<IProject, ProjectEntry> enabledProjectMap;
private List<Expression> enabledList;
private List<IPolicyChildChangeListener> childChangeListeners;
private List<IPolicyChildChangeListener> childChangeListenersOnCommit;
private List<IServicePolicy> commitChildChangePolicy;
private List<Boolean> commitChildChangeAdded;
private List<IServicePolicy> queuedChildChangePolicy;
private List<Boolean> queuedChildChangeAdded;
private List<IPolicyPlatformProjectLoadListener> projectPlatformListeners;
private ServicePolicyPlatform apiPlatform;
public ServicePolicyPlatformImpl( ServicePolicyPlatform platform )
{
apiPlatform = platform;
}
public void load()
{
ServicePolicyRegistry registry = new ServicePolicyRegistry( this );
List<String> localIds = LocalUtils.getLocalPolicyIds();
loadListeners = new Vector<IPolicyPlatformLoadListener>();
policyMap = new HashMap<String, ServicePolicyImpl>();
enumList = new HashMap<String, List<IStateEnumerationItem>>();
enumItemList = new HashMap<String, StateEnumerationItemImpl>();
enabledProjectMap = new HashMap<IProject, ProjectEntry>();
enabledList = new Vector<Expression>();
childChangeListeners = new Vector<IPolicyChildChangeListener>();
childChangeListenersOnCommit = new Vector<IPolicyChildChangeListener>();
commitChildChangePolicy = new Vector<IServicePolicy>();
commitChildChangeAdded = new Vector<Boolean>();
projectPlatformListeners = new Vector<IPolicyPlatformProjectLoadListener>();
registry.load( loadListeners, policyMap, enumList, enumItemList );
// This first loop through the ids will only create service policy objects
// without populating them with there values.
for( String localPolicyId : localIds )
{
ServicePolicyImpl localPolicy = new ServicePolicyImpl( false, localPolicyId, this );
policyMap.put( localPolicyId, localPolicy );
}
// This second loop will populate the service policy values and
// crossreference parent and child service policies.
for( String localPolicyId : localIds )
{
LocalUtils.loadLocalPolicy( localPolicyId, this );
}
}
public void callLoadListeners()
{
for( IPolicyPlatformLoadListener loadListener : loadListeners )
{
try
{
loadListener.load();
}
catch( Exception exc )
{
ServicePolicyActivator.logError( "Error in load listener:" + loadListener.getClass().getName(), exc ); //$NON-NLS-1$
}
}
commitChanges( false );
// Commit any project level changes that have been made by load listeners.
for( IProject project : enabledProjectMap.keySet() )
{
commitChanges( project );
}
}
public ServicePolicyPlatform getApiPlatform()
{
return apiPlatform;
}
public void addEnabledExpression( Expression expression )
{
if( expression != null )
{
enabledList.add( expression );
}
}
public boolean isEnabled( Object object )
{
boolean result = false;
IEvaluationContext context = new EvaluationContext( null, object );
context.addVariable( "selection", object ); //$NON-NLS-1$
context.setAllowPluginActivation( true );
for( Expression enabledItem : enabledList )
{
try
{
EvaluationResult expResult = enabledItem.evaluate( context );
// If any expression returns TRUE or NOT_LOADED we will return true as
// the result.
if( expResult != EvaluationResult.FALSE )
{
result = true;
break;
}
}
catch( CoreException exc )
{
// Ignore the expression if an exception occurs.
ServicePolicyActivator.logError( "Error evaluating enablement expression.", exc ); //$NON-NLS-1$
}
}
return result;
}
public void commitChanges( boolean saveLocals )
{
List<String> localIds = new Vector<String>();
if( saveLocals ) LocalUtils.removeAllPreferencePolicies( null, null );
// Fire child change events for commit listeners
for( IPolicyChildChangeListener listener : childChangeListenersOnCommit )
{
listener.childChange( commitChildChangePolicy, commitChildChangeAdded );
}
removeDeletedPreferenceData();
commitChildChangePolicy = new Vector<IServicePolicy>();
commitChildChangeAdded = new Vector<Boolean>();
for( ServicePolicyImpl policy : policyMap.values() )
{
policy.commitChanges();
if( saveLocals && !policy.isPredefined() )
{
LocalUtils.saveLocalPolicy( policy );
localIds.add( policy.getId() );
}
}
if( saveLocals ) LocalUtils.saveLocalIds( localIds );
committedPolicyMap = new HashMap<String, ServicePolicyImpl>();
committedPolicyMap.putAll( policyMap );
ServicePolicyActivator.getDefault().savePluginPreferences();
}
private void removeDeletedPreferenceData()
{
for( int index = 0; index < commitChildChangePolicy.size(); index++ )
{
IServicePolicy policy = commitChildChangePolicy.get( index );
boolean added = commitChildChangeAdded.get( index );
if( !added )
{
// Add policy is being deleted. We need to remove any state data
// for this policy at the workspace level and the project level.
LocalUtils.removeAllPreferencePolicies( policy.getId(), null );
for( IProject proj : enabledProjectMap.keySet() )
{
if( proj.exists() && proj.isOpen() )
{
IEclipsePreferences projPrefs = new ProjectScope( proj ).getNode( ServicePolicyActivator.PLUGIN_ID );
LocalUtils.removeAllPreferencePolicies( policy.getId(), projPrefs );
try
{
projPrefs.flush();
}
catch( BackingStoreException exc )
{
ServicePolicyActivator.logError( "Error flushing project properties.", exc ); //$NON-NLS-1$
}
}
}
}
}
}
/**
* This method is called internally to remove a service policy.
*
* @param policy
*/
public void removePolicy( IServicePolicy policy )
{
policyMap.remove( policy.getId() );
fireChildChangeEvent( policy, false );
}
/**
* This method is only called from the platform API
*
* @param policy
*/
public void removePlatformPolicy( IServicePolicy policy )
{
if( policy.isPredefined() ) return;
IServicePolicy parent = policy.getParentPolicy();
if( parent == null )
{
// Remove any children first
List<IServicePolicy> children = new Vector<IServicePolicy>( policy.getChildren() );
for( IServicePolicy child : children )
{
policy.removeChild( child );
}
removePolicy( (ServicePolicyImpl)policy);
}
else
{
parent.removeChild( policy );
}
}
public void addChildChangeListener( IPolicyChildChangeListener listener, boolean onCommit )
{
if( onCommit )
{
childChangeListenersOnCommit.add( listener );
}
else
{
childChangeListeners.add( listener );
}
}
public void removeChildChangeListener( IPolicyChildChangeListener listener, boolean onCommit )
{
if( onCommit )
{
childChangeListenersOnCommit.remove( listener );
}
else
{
childChangeListeners.remove( listener );
}
}
public void queueChildChangeListeners( boolean queue )
{
if( queue && queuedChildChangeAdded == null )
{
queuedChildChangeAdded = new Vector<Boolean>();
queuedChildChangePolicy = new Vector<IServicePolicy>();
}
else if( !queue && queuedChildChangeAdded != null )
{
// Queuing has been turned off so we will fire all the queued events.
for( IPolicyChildChangeListener listener : childChangeListeners )
{
listener.childChange( queuedChildChangePolicy, queuedChildChangeAdded );
}
queuedChildChangeAdded = null;
queuedChildChangePolicy = null;
}
}
public void fireChildChangeEvent( IServicePolicy policy, boolean isAdd )
{
if( queuedChildChangeAdded == null )
{
List<IServicePolicy> policyList = new Vector<IServicePolicy>(1);
List<Boolean> addedList = new Vector<Boolean>(1);
policyList.add( policy );
addedList.add( isAdd );
for( IPolicyChildChangeListener listener : childChangeListeners )
{
listener.childChange( policyList, addedList );
}
}
else
{
queuedChildChangeAdded.add( isAdd );
queuedChildChangePolicy.add( policy );
}
commitChildChangeAdded.add( isAdd );
commitChildChangePolicy.add( policy );
}
public void commitChanges( IProject project )
{
for( ServicePolicyImpl policy : policyMap.values() )
{
((PolicyStateImpl)policy.getPolicyState( project )).commitChanges();
}
ProjectEntry entry = getProjectEntry( project );
entry.isEnabledCommitted = entry.isEnabled;
setProjectEnabled( project, entry.isEnabledCommitted );
try
{
IEclipsePreferences projectPrefs = new ProjectScope( project ).getNode( ServicePolicyActivator.PLUGIN_ID );
projectPrefs.flush();
}
catch( BackingStoreException exc )
{
ServicePolicyActivator.logError( "Error while committing project preferences.", exc ); //$NON-NLS-1$
}
}
public void discardChanges()
{
policyMap = new HashMap<String, ServicePolicyImpl>();
policyMap.putAll( committedPolicyMap );
commitChildChangePolicy = new Vector<IServicePolicy>();
commitChildChangeAdded = new Vector<Boolean>();
for( ServicePolicyImpl policy : committedPolicyMap.values() )
{
policy.discardChanges();
}
}
public void discardChanges( IProject project )
{
for( ServicePolicyImpl policy : policyMap.values() )
{
((PolicyStateImpl)policy.getPolicyState( project )).discardChanges();
}
ProjectEntry entry = getProjectEntry( project );
entry.isEnabled = entry.isEnabledCommitted;
}
public void restoreDefaults()
{
Vector<ServicePolicyImpl> tempPolicyValues
= new Vector<ServicePolicyImpl>( policyMap.values() );
for( ServicePolicyImpl policy : tempPolicyValues )
{
policy.restoreDefaults();
}
}
public void restoreDefaults( IProject project )
{
for( ServicePolicyImpl policy : policyMap.values() )
{
policy.restoreDefaults( project );
}
}
public Set<String> getAllPolicyIds()
{
return policyMap.keySet();
}
public List<IServicePolicy> getRootServicePolicies( IFilter filter )
{
List<IServicePolicy> rootPolicies = new Vector<IServicePolicy>();
for( String policyId : policyMap.keySet() )
{
ServicePolicyImpl policy = policyMap.get( policyId );
if( policy.getParentPolicy() == null )
{
if( filter == null || (filter != null && filter.accept( policy )) )
{
rootPolicies.add( policy );
}
}
}
return rootPolicies;
}
public ServicePolicyImpl createServicePolicy( IServicePolicy parent,
String id,
String enumListId,
String defaultEnumId )
{
if( id == null ) id = "org.eclipse.wst.ws.service.policy.id"; //$NON-NLS-1$
String uniqueId = makeUniqueId( id );
ServicePolicyImpl policy = new ServicePolicyImpl( false, uniqueId, this );
policy.setParent( (ServicePolicyImpl)parent );
policy.setEnumListId( enumListId );
policy.setDefaultEnumId( defaultEnumId );
policyMap.put( uniqueId, policy );
fireChildChangeEvent( policy, true );
return policy;
}
public ServicePolicyImpl getServicePolicy( String id )
{
return id == null ? null : policyMap.get( id );
}
public List<IStateEnumerationItem> getStateEnumeration( String enumId )
{
return enumList.get( enumId );
}
public IStateEnumerationItem getStateItemEnumeration( String stateItemId )
{
return enumItemList.get( stateItemId );
}
public boolean isProjectPreferencesEnabled( IProject project )
{
ProjectEntry entry = getProjectEntry( project );
return entry.isEnabled;
}
private boolean getProjectPreferenceEnabled( IProject project )
{
String pluginId = ServicePolicyActivator.PLUGIN_ID;
IEclipsePreferences projectPreference = new ProjectScope( project ).getNode( pluginId );
String key = pluginId + ".projectEnabled"; //$NON-NLS-1$
return projectPreference.getBoolean( key, false );
}
public void setProjectPreferencesEnabled( IProject project, boolean value )
{
ProjectEntry entry = getProjectEntry( project );
entry.isEnabled = value;
}
/**
* Add a project platform listener. When a particular project is referenced
* by in the service policy platform this listener will be called the first
* time the project is loaded into the system.
*
* @param listener the listener
*/
public void addProjectLoadListener( IPolicyPlatformProjectLoadListener listener )
{
projectPlatformListeners.add( listener );
}
/**
* Removes a project platform listener.
*
* @param listener the listener
*/
public void removeProjectLoadListener( IPolicyPlatformProjectLoadListener listener )
{
projectPlatformListeners.remove( listener );
}
private void setProjectEnabled( IProject project, boolean value )
{
String pluginId = ServicePolicyActivator.PLUGIN_ID;
IEclipsePreferences projectPreference = new ProjectScope( project ).getNode( pluginId );
String key = pluginId + ".projectEnabled"; //$NON-NLS-1$
projectPreference.putBoolean( key, value );
}
private ProjectEntry getProjectEntry( IProject project )
{
ProjectEntry entry = enabledProjectMap.get( project );
if( entry == null )
{
entry = new ProjectEntry();
enabledProjectMap.put( project, entry );
entry.isEnabledCommitted = getProjectPreferenceEnabled( project );
entry.isEnabled = entry.isEnabledCommitted;
fireProjectLoadListener( project );
}
return entry;
}
private void fireProjectLoadListener( IProject project )
{
for( IPolicyPlatformProjectLoadListener listener : projectPlatformListeners )
{
listener.load( project );
}
}
private String makeUniqueId( String id )
{
String result = id;
int idCount = 1;
Pattern pattern = Pattern.compile( "\\d*$" ); // Match any numerical digits at the end //$NON-NLS-1$
// of the string.
while( policyMap.containsKey( result ) )
{
Matcher matcher = pattern.matcher( result );
result = matcher.replaceFirst( "" ) + idCount; //$NON-NLS-1$
idCount++;
}
return result;
}
private class ProjectEntry
{
boolean isEnabledCommitted;
boolean isEnabled;
}
}