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.expressions.IPropertyTester;
import org.eclipse.core.runtime.Assert;
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;
public class TypeExtensionManager implements IRegistryChangeListener {
private String fExtensionPoint;
private static boolean DEBUG= "true".equalsIgnoreCase(Platform.getDebugOption("org.eclipse.core.expressions/debug/TypeExtensionManager"));
private static final String TYPE= "type";
private static final IPropertyTester[] EMPTY_PROPERTY_TESTER_ARRAY= new IPropertyTester[0];
private static final IPropertyTester NULL_PROPERTY_TESTER= new IPropertyTester() {
@Override
public boolean handles(String namespace, String property) {
return false;
}
@Override
public boolean isInstantiated() {
return true;
}
@Override
public boolean isDeclaringPluginActive() {
return true;
}
@Override
public IPropertyTester instantiate() throws CoreException {
return this;
}
@Override
public boolean test(Object receiver, String property, Object[] args, Object expectedValue) {
return false;
}
};
private Map<Class<?>, TypeExtension> fTypeExtensionMap;
private Map<String, List<IConfigurationElement>> fConfigurationElementMap;
private PropertyCache fPropertyCache;
public TypeExtensionManager(String extensionPoint) {
Assert.isNotNull(extensionPoint);
fExtensionPoint= extensionPoint;
Platform.getExtensionRegistry().addRegistryChangeListener(this);
initializeCaches();
}
public Property getProperty(Object receiver, String namespace, String method) throws CoreException {
return getProperty(receiver, namespace, method, false);
}
public synchronized Property getProperty(Object receiver, String namespace, String method, boolean forcePluginActivation) throws CoreException {
long start= 0;
if (Expressions.TRACING)
start= System.currentTimeMillis();
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(forcePluginActivation)) {
if (Expressions.TRACING) {
System.out.println("[Type Extension] - method " +
clazz.getName() + "#" + method +
" found in cache: " +
(System.currentTimeMillis() - start) + " ms.");
}
return cached;
}
fPropertyCache.remove(cached);
}
TypeExtension extension= get(clazz);
IPropertyTester extender= extension.findTypeExtender(this, namespace, method, receiver instanceof Class, forcePluginActivation);
if (extender == TypeExtension.CONTINUE || extender == null) {
Throwable t= null;
if (DEBUG) {
t= new Throwable("forcePluginActivation: " + forcePluginActivation + ", receiver: " + receiver).fillInStackTrace();
}
throw new CoreException(new ExpressionStatus(
ExpressionStatus.TYPE_EXTENDER_UNKOWN_METHOD,
Messages.format(
ExpressionMessages.TypeExtender_unknownMethod,
new String[] {namespace + '.' + method, clazz.toString()}),
t));
}
result.setPropertyTester(extender);
fPropertyCache.put(result);
if (Expressions.TRACING) {
System.out.println("[Type Extension] - method " +
clazz.getName() + "#" + method +
" not found in cache: " +
(System.currentTimeMillis() - start) + " ms.");
}
return result;
}
TypeExtension get(Class<?> clazz) {
TypeExtension result= fTypeExtensionMap.get(clazz);
if (result == null) {
result= new TypeExtension(clazz);
fTypeExtensionMap.put(clazz, result);
}
return result;
}
IPropertyTester[] loadTesters(Class<?> type) {
if (fConfigurationElementMap == null) {
fConfigurationElementMap= new HashMap<>();
IExtensionRegistry registry= Platform.getExtensionRegistry();
IConfigurationElement[] ces= registry.getConfigurationElementsFor(
ExpressionPlugin.getPluginId(),
fExtensionPoint);
for (IConfigurationElement config : ces) {
String typeAttr= config.getAttribute(TYPE);
List<IConfigurationElement> typeConfigs= fConfigurationElementMap.get(typeAttr);
if (typeConfigs == null) {
typeConfigs= new ArrayList<>();
fConfigurationElementMap.put(typeAttr, typeConfigs);
}
typeConfigs.add(config);
}
}
String typeName= type.getName();
List<IConfigurationElement> typeConfigs= 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= 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;
}
}
@Override
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);
}
}