/*******************************************************************************
* Copyright (c) 2014 Manumitting Technologies Inc 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:
* Brian de Alwis (MTI) - initial API and implementation
*******************************************************************************/
package org.eclipse.e4.ui.css.core.impl.engine;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.WeakHashMap;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IConfigurationElement;
import org.eclipse.core.runtime.IExtensionRegistry;
import org.eclipse.e4.ui.css.core.dom.IElementProvider;
import org.eclipse.e4.ui.css.core.engine.CSSEngine;
import org.w3c.dom.Element;
/**
* A simple {@link IElementProvider} that is configured by an extension point.
*/
public class RegistryCSSElementProvider implements IElementProvider {
/* the original extension point was misspelled */
private static final String DEPRECATED_ELEMENT_PROVIDER_EXTPOINT = "org.eclipse.e4.u.css.core.elementProvider";
private static final String ELEMENT_PROVIDER_EXTPOINT = "org.eclipse.e4.ui.css.core.elementProvider";
final private IExtensionRegistry registry;;
private String[] extpts = { ELEMENT_PROVIDER_EXTPOINT,
DEPRECATED_ELEMENT_PROVIDER_EXTPOINT };
private Map<Class<?>, IElementProvider> providerCache = Collections
.synchronizedMap(new WeakHashMap<Class<?>, IElementProvider>());
public RegistryCSSElementProvider(IExtensionRegistry registry) {
// FIXME: add a registry listener to refresh caches; but would need to
// add a dispose() to IElementProvider
this.registry = registry;
}
@Override
public Element getElement(Object o, CSSEngine engine) {
if (o instanceof Element) {
return (Element) o;
}
IElementProvider provider = providerCache.get(o.getClass());
if (provider != null) {
return provider.getElement(o, engine);
}
for (Class<?> type : computeElementTypeLookup(o.getClass())) {
String typeName = type.getName();
for (String extpt : extpts) {
for (IConfigurationElement ce : registry.getConfigurationElementsFor(extpt)) {
if ("provider".equals(ce.getName())) {
for (IConfigurationElement ce2 : ce.getChildren()) {
if (typeName.equals(ce2.getAttribute("class"))) {
try {
if (extpt
.equals(DEPRECATED_ELEMENT_PROVIDER_EXTPOINT)) {
System.err
.println("Extension point "
+ DEPRECATED_ELEMENT_PROVIDER_EXTPOINT
+ " is deprecated; use "
+ ELEMENT_PROVIDER_EXTPOINT);
}
provider = (IElementProvider) ce
.createExecutableExtension("class");
providerCache.put(o.getClass(), provider);
return provider.getElement(o, engine);
} catch (CoreException e1) {
e1.printStackTrace();
}
}
}
}
}
}
}
return null;
}
private List<Class<?>> computeElementTypeLookup(Class<?> clazz) {
ArrayList<Class<?>> results = new ArrayList<>();
LinkedList<Class<?>> todo = new LinkedList<>();
Set<Class<?>> seen = new HashSet<>();
todo.add(clazz);
while (!todo.isEmpty()) {
Class<?> candidate = todo.removeFirst();
if (!seen.contains(candidate)) {
seen.add(candidate);
results.add(candidate);
Collections.addAll(todo, candidate.getInterfaces());
if (candidate.getSuperclass() != null) {
todo.add(candidate.getSuperclass());
}
}
}
return results;
}
}