blob: c07677c22d9a7d623df74561f3993279864edaf1 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2004 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Common Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/cpl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.core.internal.expressions;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IConfigurationElement;
import org.eclipse.core.runtime.IExtensionDelta;
import org.eclipse.core.runtime.IExtensionRegistry;
import org.eclipse.core.runtime.IRegistryChangeEvent;
import org.eclipse.core.runtime.IRegistryChangeListener;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.expressions.IPropertyTester;
public class TypeExtensionManager implements IRegistryChangeListener {
private String fExtensionPoint;
private static final String TYPE= "type"; //$NON-NLS-1$
private static final IPropertyTester[] EMPTY_PROPERTY_TESTER_ARRAY= new IPropertyTester[0];
private static final IPropertyTester NULL_PROPERTY_TESTER= new IPropertyTester() {
public boolean handles(String namespace, String property) {
return false;
}
public boolean isInstantiated() {
return true;
}
public boolean isDeclaringPluginActive() {
return true;
}
public IPropertyTester instantiate() throws CoreException {
return this;
}
public boolean test(Object receiver, String property, Object[] args, Object expectedValue) {
return false;
}
};
/*
* Map containing all already created type extension object.
*/
private Map/*<Class, TypeExtension>*/ fTypeExtensionMap;
/*
* Table containing mapping of class name to configuration element
*/
private Map/*<String, List<IConfigurationElement>>*/ fConfigurationElementMap;
/*
* A cache to give fast access to the last 1000 method invocations.
*/
private PropertyCache fPropertyCache;
public TypeExtensionManager(String extensionPoint) {
Assert.isNotNull(extensionPoint);
fExtensionPoint= extensionPoint;
Platform.getExtensionRegistry().addRegistryChangeListener(this);
initializeCaches();
}
public synchronized Property getProperty(Object receiver, String namespace, String method) throws CoreException {
long start= 0;
if (Expressions.TRACING)
start= System.currentTimeMillis();
// if we call a static method than the receiver is the class object
Class clazz= receiver instanceof Class ? (Class)receiver : receiver.getClass();
Property result= new Property(clazz, namespace, method);
Property cached= fPropertyCache.get(result);
if (cached != null) {
if (cached.isValidCacheEntry()) {
if (Expressions.TRACING) {
System.out.println("[Type Extension] - method " + //$NON-NLS-1$
clazz.getName() + "#" + method + //$NON-NLS-1$
" found in cache: " + //$NON-NLS-1$
(System.currentTimeMillis() - start) + " ms."); //$NON-NLS-1$
}
return cached;
}
// The type extender isn't loaded in the cached method but can be loaded
// now. So remove method from cache and do the normal look up so that the
// implementation class gets loaded.
fPropertyCache.remove(cached);
}
TypeExtension extension= get(clazz);
IPropertyTester extender= extension.findTypeExtender(this, namespace, method, receiver instanceof Class);
if (extender == TypeExtension.CONTINUE || extender == null) {
throw new CoreException(new ExpressionStatus(
ExpressionStatus.TYPE_EXTENDER_UNKOWN_METHOD,
ExpressionMessages.getFormattedString(
"TypeExtender.unknownMethod", //$NON-NLS-1$
new Object[] {method, clazz.toString()})));
}
result.setPropertyTester(extender);
fPropertyCache.put(result);
if (Expressions.TRACING) {
System.out.println("[Type Extension] - method " + //$NON-NLS-1$
clazz.getName() + "#" + method + //$NON-NLS-1$
" not found in cache: " + //$NON-NLS-1$
(System.currentTimeMillis() - start) + " ms."); //$NON-NLS-1$
}
return result;
}
/*
* This method doesn't need to be synchronized since it is called
* from withing the getProperty method which is synchronized
*/
/* package */ TypeExtension get(Class clazz) {
TypeExtension result= (TypeExtension)fTypeExtensionMap.get(clazz);
if (result == null) {
result= new TypeExtension(clazz);
fTypeExtensionMap.put(clazz, result);
}
return result;
}
/*
* This method doesn't need to be synchronized since it is called
* from withing the getProperty method which is synchronized
*/
/* package */ IPropertyTester[] loadTesters(Class type) {
if (fConfigurationElementMap == null) {
fConfigurationElementMap= new HashMap();
IExtensionRegistry registry= Platform.getExtensionRegistry();
IConfigurationElement[] ces= registry.getConfigurationElementsFor(
ExpressionPlugin.getPluginId(),
fExtensionPoint);
for (int i= 0; i < ces.length; i++) {
IConfigurationElement config= ces[i];
String typeAttr= config.getAttribute(TYPE);
List typeConfigs= (List)fConfigurationElementMap.get(typeAttr);
if (typeConfigs == null) {
typeConfigs= new ArrayList();
fConfigurationElementMap.put(typeAttr, typeConfigs);
}
typeConfigs.add(config);
}
}
String typeName= type.getName();
List typeConfigs= (List)fConfigurationElementMap.get(typeName);
if (typeConfigs == null)
return EMPTY_PROPERTY_TESTER_ARRAY;
else {
IPropertyTester[] result= new IPropertyTester[typeConfigs.size()];
for (int i= 0; i < result.length; i++) {
IConfigurationElement config= (IConfigurationElement)typeConfigs.get(i);
try {
result[i]= new PropertyTesterDescriptor(config);
} catch (CoreException e) {
ExpressionPlugin.getDefault().getLog().log(e.getStatus());
result[i]= NULL_PROPERTY_TESTER;
}
}
fConfigurationElementMap.remove(typeName);
return result;
}
}
public void registryChanged(IRegistryChangeEvent event) {
IExtensionDelta[] deltas= event.getExtensionDeltas(ExpressionPlugin.getPluginId(), fExtensionPoint);
if (deltas.length > 0) {
initializeCaches();
}
}
private synchronized void initializeCaches() {
fTypeExtensionMap= new HashMap();
fConfigurationElementMap= null;
fPropertyCache= new PropertyCache(1000);
}
}