mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-03-22 15:19:59 +07:00
Extensions framework.
This commit is contained in:
21
extensions/extensions.iml
Normal file
21
extensions/extensions.iml
Normal file
@@ -0,0 +1,21 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module version="4" relativePaths="true" type="JAVA_MODULE">
|
||||
<component name="ModuleRootManager" />
|
||||
<component name="NewModuleRootManager">
|
||||
<output url="file://$MODULE_DIR$/classes/main" />
|
||||
<exclude-output />
|
||||
<output-test url="file://$MODULE_DIR$/classes/test" />
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<sourceFolder url="file://$MODULE_DIR$/source" isTestSource="false" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/testSource" />
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
<orderEntry type="library" exported="" name="XStream" level="project" />
|
||||
<orderEntry type="library" exported="" name="JDOM" level="project" />
|
||||
<orderEntry type="library" name="commons-collections" level="project" />
|
||||
<orderEntry type="library" name="picocontainer" level="project" />
|
||||
<orderEntryProperties />
|
||||
</component>
|
||||
</module>
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
/*
|
||||
* Copyright (c) 2000-2004 by JetBrains s.r.o. All Rights Reserved.
|
||||
* Use is subject to license terms.
|
||||
*/
|
||||
package com.intellij.openapi.extensions;
|
||||
|
||||
/**
|
||||
* @author akireyev
|
||||
*/
|
||||
public interface AreaInstance {
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
/*
|
||||
* Copyright (c) 2000-2004 by JetBrains s.r.o. All Rights Reserved.
|
||||
* Use is subject to license terms.
|
||||
*/
|
||||
package com.intellij.openapi.extensions;
|
||||
|
||||
/**
|
||||
* @author akireyev
|
||||
*/
|
||||
public interface AreaListener {
|
||||
void areaCreated(String areaClass, AreaInstance areaInstance);
|
||||
void areaDisposing(String areaClass, AreaInstance areaInstance);
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright (c) 2000-2004 by JetBrains s.r.o. All Rights Reserved.
|
||||
* Use is subject to license terms.
|
||||
*/
|
||||
package com.intellij.openapi.extensions;
|
||||
|
||||
/**
|
||||
* @author AKireyev
|
||||
*/
|
||||
public class EPAvailabilityListenerExtension {
|
||||
public static final String EXTENSION_POINT_NAME = "jetbrains.fabrique.framework.epAvailabilityListener";
|
||||
|
||||
private String myExtensionPointName;
|
||||
private String myListenerClass;
|
||||
|
||||
public EPAvailabilityListenerExtension() {
|
||||
}
|
||||
|
||||
public EPAvailabilityListenerExtension(String extensionPointName, String listenerClass) {
|
||||
myExtensionPointName = extensionPointName;
|
||||
myListenerClass = listenerClass;
|
||||
}
|
||||
|
||||
public String getExtensionPointName() {
|
||||
return myExtensionPointName;
|
||||
}
|
||||
|
||||
public void setExtensionPointName(String extensionPointName) {
|
||||
myExtensionPointName = extensionPointName;
|
||||
}
|
||||
|
||||
public String getListenerClass() {
|
||||
return myListenerClass;
|
||||
}
|
||||
|
||||
public void setListenerClass(String listenerClass) {
|
||||
myListenerClass = listenerClass;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
/*
|
||||
* Copyright (c) 2000-2004 by JetBrains s.r.o. All Rights Reserved.
|
||||
* Use is subject to license terms.
|
||||
*/
|
||||
package com.intellij.openapi.extensions;
|
||||
|
||||
/**
|
||||
* @author kir
|
||||
*
|
||||
* An extension can implement this interface to get notifications when it is added/removed to {@link ExtensionPoint}
|
||||
*/
|
||||
public interface Extension {
|
||||
void extensionAdded(ExtensionPoint extensionPoint);
|
||||
void extensionRemoved(ExtensionPoint extensionPoint);
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright (c) 2000-2004 by JetBrains s.r.o. All Rights Reserved.
|
||||
* Use is subject to license terms.
|
||||
*/
|
||||
package com.intellij.openapi.extensions;
|
||||
|
||||
/**
|
||||
* @author AKireyev
|
||||
*/
|
||||
public interface ExtensionPoint {
|
||||
String getName();
|
||||
AreaInstance getArea();
|
||||
|
||||
String getBeanClassName();
|
||||
|
||||
void registerExtension(Object extension);
|
||||
void registerExtension(Object extension, LoadingOrder order);
|
||||
|
||||
Object[] getExtensions();
|
||||
Object getExtension();
|
||||
boolean hasExtension(Object extension);
|
||||
|
||||
void unregisterExtension(Object extension);
|
||||
|
||||
void addExtensionPointListener(ExtensionPointListener listener);
|
||||
void removeExtensionPointListener(ExtensionPointListener extensionPointListener);
|
||||
|
||||
void reset();
|
||||
|
||||
Class getExtensionClass();
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
/*
|
||||
* Copyright (c) 2000-2004 by JetBrains s.r.o. All Rights Reserved.
|
||||
* Use is subject to license terms.
|
||||
*/
|
||||
package com.intellij.openapi.extensions;
|
||||
|
||||
/**
|
||||
* @author AKireyev
|
||||
*/
|
||||
public interface ExtensionPointAvailabilityListener {
|
||||
void extensionPointRegistered(ExtensionPoint extensionPoint);
|
||||
void extensionPointRemoved(ExtensionPoint extensionPoint);
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
/*
|
||||
* Copyright (c) 2000-2004 by JetBrains s.r.o. All Rights Reserved.
|
||||
* Use is subject to license terms.
|
||||
*/
|
||||
package com.intellij.openapi.extensions;
|
||||
|
||||
public interface ExtensionPointListener {
|
||||
void extensionAdded(Object extension);
|
||||
void extensionRemoved(Object extension);
|
||||
}
|
||||
@@ -0,0 +1,235 @@
|
||||
/*
|
||||
* Copyright (c) 2000-2004 by JetBrains s.r.o. All Rights Reserved.
|
||||
* Use is subject to license terms.
|
||||
*/
|
||||
package com.intellij.openapi.extensions;
|
||||
|
||||
import com.intellij.openapi.extensions.impl.ExtensionsAreaImpl;
|
||||
import org.apache.commons.collections.MultiHashMap;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
// todo: make default area instance a non-null object
|
||||
|
||||
public abstract class Extensions {
|
||||
private static LogProvider ourLogger = new SimpleLogProvider();
|
||||
|
||||
public static final String AREA_LISTENER_EXTENSION_POINT = "jetbrains.fabrique.platform.areaListeners";
|
||||
|
||||
private static Map ourAreaClass2prototypeArea;
|
||||
private static Map ourAreaInstance2area;
|
||||
private static MultiHashMap ourAreaClass2instances;
|
||||
private static Map ourAreaInstance2class;
|
||||
private static Map ourAreaClass2Configuration;
|
||||
|
||||
public static ExtensionsArea getRootArea() {
|
||||
return getArea(null);
|
||||
}
|
||||
|
||||
public static ExtensionsArea getArea(AreaInstance areaInstance) {
|
||||
init();
|
||||
if (!ourAreaInstance2area.containsKey(areaInstance)) {
|
||||
throw new IllegalArgumentException("No area instantiated for: " + areaInstance);
|
||||
}
|
||||
return (ExtensionsArea) ourAreaInstance2area.get(areaInstance);
|
||||
}
|
||||
|
||||
public static Object[] getExtensions(String extensionPointName) {
|
||||
return getExtensions(extensionPointName, null);
|
||||
}
|
||||
|
||||
public static Object[] getExtensions(String extensionPointName, AreaInstance areaInstance) {
|
||||
ExtensionsArea area = getArea(areaInstance);
|
||||
assert area != null: "Unable to get area for " + areaInstance;
|
||||
ExtensionPoint extensionPoint = area.getExtensionPoint(extensionPointName);
|
||||
assert extensionPoint != null: "Unable to get extension point " + extensionPoint + " for " + areaInstance;
|
||||
return extensionPoint.getExtensions();
|
||||
}
|
||||
|
||||
private static void init() {
|
||||
if (ourAreaInstance2area == null) {
|
||||
ourAreaInstance2area = new HashMap();
|
||||
ourAreaClass2prototypeArea = new HashMap();
|
||||
ourAreaClass2instances = new MultiHashMap();
|
||||
ourAreaInstance2class = new HashMap();
|
||||
ourAreaClass2Configuration = new HashMap();
|
||||
ExtensionsAreaImpl rootArea = new ExtensionsAreaImpl(null, null, null, ourLogger);
|
||||
ourAreaInstance2area.put(null, rootArea);
|
||||
ourAreaClass2prototypeArea.put(null, rootArea);
|
||||
rootArea.registerExtensionPoint(AREA_LISTENER_EXTENSION_POINT, AreaListener.class.getName());
|
||||
}
|
||||
}
|
||||
|
||||
static void reset() {
|
||||
ourAreaInstance2area = null;
|
||||
ourAreaClass2instances = null;
|
||||
ourAreaClass2prototypeArea = null;
|
||||
ourAreaInstance2class = null;
|
||||
}
|
||||
|
||||
public static void instantiateArea(String areaClass, AreaInstance areaInstance, AreaInstance parentAreaInstance) {
|
||||
if (areaClass == null) {
|
||||
throw new IllegalArgumentException("Should not try to instantiate the root area");
|
||||
}
|
||||
init();
|
||||
if (!ourAreaClass2Configuration.containsKey(areaClass)) {
|
||||
throw new IllegalArgumentException("Area class is not registered: " + areaClass);
|
||||
}
|
||||
if (ourAreaInstance2area.containsKey(areaInstance)) {
|
||||
throw new IllegalArgumentException("Area already instantiated for: " + areaInstance);
|
||||
}
|
||||
ExtensionsArea parentArea = getArea(parentAreaInstance);
|
||||
AreaClassConfiguration configuration = (AreaClassConfiguration)ourAreaClass2Configuration.get(areaClass);
|
||||
if (!equals(parentArea.getAreaClass(), configuration.getParentClassName())) {
|
||||
throw new IllegalArgumentException("Wrong parent area. Expected class: " + configuration.getParentClassName() + " actual class: " + parentArea.getAreaClass());
|
||||
}
|
||||
ExtensionsAreaImpl area = new ExtensionsAreaImpl(areaClass, areaInstance, parentArea.getPicoContainer(), ourLogger);
|
||||
ourAreaInstance2area.put(areaInstance, area);
|
||||
ourAreaClass2instances.put(areaClass, areaInstance);
|
||||
ourAreaInstance2class.put(areaInstance, areaClass);
|
||||
AreaListener[] listeners = getAreaListeners();
|
||||
for (int i = 0; i < listeners.length; i++) {
|
||||
AreaListener listener = listeners[i];
|
||||
listener.areaCreated(areaClass, areaInstance);
|
||||
}
|
||||
}
|
||||
|
||||
private static AreaListener[] getAreaListeners() {
|
||||
AreaListener[] listeners = (AreaListener[]) getRootArea().getExtensionPoint(AREA_LISTENER_EXTENSION_POINT).getExtensions();
|
||||
return listeners;
|
||||
}
|
||||
|
||||
public static void registerAreaClass(String areaClass, String parentAreaClass) {
|
||||
init();
|
||||
if (ourAreaClass2Configuration.containsKey(areaClass)) {
|
||||
// allow duplicate area class registrations if they are the same - fixing duplicate registration in tests is much more trouble
|
||||
AreaClassConfiguration configuration = (AreaClassConfiguration)ourAreaClass2Configuration.get(areaClass);
|
||||
if (!equals(configuration.getParentClassName(), parentAreaClass)) {
|
||||
throw new RuntimeException("Area class already registered: " + areaClass, ((AreaClassConfiguration)ourAreaClass2Configuration.get(areaClass)).getCreationPoint());
|
||||
}
|
||||
else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
AreaClassConfiguration configuration = new AreaClassConfiguration(areaClass, parentAreaClass);
|
||||
ourAreaClass2Configuration.put(areaClass, configuration);
|
||||
}
|
||||
|
||||
public static void disposeArea(AreaInstance areaInstance) {
|
||||
assert ourAreaInstance2area.containsKey(areaInstance);
|
||||
if (areaInstance == null) {
|
||||
throw new IllegalArgumentException("Cannot dispose root area");
|
||||
}
|
||||
|
||||
AreaListener[] listeners = getAreaListeners();
|
||||
String areaClass = (String) ourAreaInstance2class.get(areaInstance);
|
||||
if (areaClass == null) {
|
||||
throw new IllegalArgumentException("Area class is null (area never instantiated?). Instance: " + areaInstance);
|
||||
}
|
||||
try {
|
||||
for (int i = 0; i < listeners.length; i++) {
|
||||
listeners[i].areaDisposing(areaClass, areaInstance);
|
||||
}
|
||||
} finally {
|
||||
ourAreaInstance2area.remove(areaInstance);
|
||||
ourAreaClass2instances.remove(ourAreaInstance2class.remove(areaInstance), areaInstance);
|
||||
ourAreaInstance2class.remove(areaInstance);
|
||||
}
|
||||
}
|
||||
|
||||
public static AreaInstance[] getAllAreas() {
|
||||
init();
|
||||
final Set keys = ourAreaInstance2area.keySet();
|
||||
return (AreaInstance[]) keys.toArray(new AreaInstance[keys.size()]);
|
||||
}
|
||||
|
||||
public static AreaInstance[] getAllAreas(String areaClass) {
|
||||
Collection instances = (Collection) ourAreaClass2instances.get(areaClass);
|
||||
if (instances != null) {
|
||||
return (AreaInstance[]) instances.toArray(new AreaInstance[instances.size()]);
|
||||
}
|
||||
return new AreaInstance[0];
|
||||
}
|
||||
|
||||
public static Object getAreaClass(AreaInstance areaInstance) {
|
||||
if (areaInstance == null) return null;
|
||||
|
||||
assert ourAreaInstance2class.containsKey(areaInstance);
|
||||
return ourAreaInstance2class.get(areaInstance);
|
||||
}
|
||||
|
||||
public static void unregisterAreaClass(String areaClass) {
|
||||
init();
|
||||
assert ourAreaClass2Configuration.containsKey(areaClass) : "Area class is not registered: " + areaClass;
|
||||
ourAreaClass2Configuration.remove(areaClass);
|
||||
}
|
||||
|
||||
private static boolean equals(Object object1, Object object2) {
|
||||
if (object1 == object2) {
|
||||
return true;
|
||||
}
|
||||
if ((object1 == null) || (object2 == null)) {
|
||||
return false;
|
||||
}
|
||||
return object1.equals(object2);
|
||||
}
|
||||
|
||||
public static void setLogProvider(LogProvider logProvider) {
|
||||
ourLogger = logProvider;
|
||||
}
|
||||
|
||||
private static class AreaClassConfiguration {
|
||||
private String myClassName;
|
||||
private String myParentClassName;
|
||||
private Throwable myCreationPoint;
|
||||
|
||||
AreaClassConfiguration(String className, String parentClassName) {
|
||||
myCreationPoint = new Throwable();
|
||||
myClassName = className;
|
||||
myParentClassName = parentClassName;
|
||||
}
|
||||
|
||||
public Throwable getCreationPoint() {
|
||||
return myCreationPoint;
|
||||
}
|
||||
|
||||
public String getClassName() {
|
||||
return myClassName;
|
||||
}
|
||||
|
||||
public String getParentClassName() {
|
||||
return myParentClassName;
|
||||
}
|
||||
}
|
||||
|
||||
public static class SimpleLogProvider implements LogProvider {
|
||||
public void error(String message) {
|
||||
new Throwable(message).printStackTrace();
|
||||
}
|
||||
|
||||
public void error(String message, Throwable t) {
|
||||
System.err.println(message);
|
||||
t.printStackTrace();
|
||||
}
|
||||
|
||||
public void error(Throwable t) {
|
||||
t.printStackTrace();
|
||||
}
|
||||
|
||||
public void warn(String message) {
|
||||
System.err.println(message);
|
||||
}
|
||||
|
||||
public void warn(String message, Throwable t) {
|
||||
System.err.println(message);
|
||||
t.printStackTrace();
|
||||
}
|
||||
|
||||
public void warn(Throwable t) {
|
||||
t.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright (c) 2000-2004 by JetBrains s.r.o. All Rights Reserved.
|
||||
* Use is subject to license terms.
|
||||
*/
|
||||
package com.intellij.openapi.extensions;
|
||||
|
||||
import org.jdom.Element;
|
||||
import org.picocontainer.MutablePicoContainer;
|
||||
import org.picocontainer.PicoContainer;
|
||||
|
||||
/**
|
||||
* @author AKireyev
|
||||
*/
|
||||
public interface ExtensionsArea {
|
||||
|
||||
void registerExtensionPoint(String extensionPointName, String extensionPointBeanClass);
|
||||
void unregisterExtensionPoint(String extensionPointName);
|
||||
|
||||
boolean hasExtensionPoint(String extensionPointName);
|
||||
ExtensionPoint getExtensionPoint(String extensionPointName);
|
||||
|
||||
ExtensionPoint[] getExtensionPoints();
|
||||
|
||||
void suspendInteractions();
|
||||
void resumeInteractions();
|
||||
void killPendingInteractions();
|
||||
|
||||
void addAvailabilityListener(String epName, ExtensionPointAvailabilityListener listener);
|
||||
|
||||
MutablePicoContainer getPicoContainer();
|
||||
|
||||
void registerExtensionPoint(String pluginName, Element extensionPointElement);
|
||||
void registerExtension(String pluginName, Element extensionElement);
|
||||
|
||||
void unregisterExtensionPoint(String pluginName, Element extensionPointElement);
|
||||
|
||||
void unregisterExtension(String pluginName, Element extensionElement);
|
||||
|
||||
PicoContainer getPluginContainer(String pluginName);
|
||||
|
||||
String getAreaClass();
|
||||
}
|
||||
@@ -0,0 +1,244 @@
|
||||
/*
|
||||
* Copyright (c) 2000-2004 by JetBrains s.r.o. All Rights Reserved.
|
||||
* Use is subject to license terms.
|
||||
*/
|
||||
package com.intellij.openapi.extensions;
|
||||
|
||||
import org.jdom.Element;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Alexander Kireyev
|
||||
*/
|
||||
public abstract class LoadingOrder {
|
||||
public static final LoadingOrder ANY = new LoadingOrder("ANY") {
|
||||
int findPlace(Orderable[] orderables, int current) {
|
||||
return DONT_CARE;
|
||||
}
|
||||
};
|
||||
public static final LoadingOrder FIRST = new LoadingOrder("FIRST") {
|
||||
int findPlace(Orderable[] orderables, int current) {
|
||||
return SPECIAL;
|
||||
}
|
||||
};
|
||||
public static final LoadingOrder LAST = new LoadingOrder("LAST") {
|
||||
int findPlace(Orderable[] orderables, int current) {
|
||||
return SPECIAL;
|
||||
}
|
||||
};
|
||||
|
||||
static final int DONT_CARE = -1;
|
||||
static final int ACCEPTABLE = -2;
|
||||
static final int SPECIAL = -3;
|
||||
|
||||
private final String myName; // for debug only
|
||||
private static final String BEFORE_STR = "BEFORE:";
|
||||
private static final String AFTER_STR = "AFTER:";
|
||||
|
||||
private LoadingOrder(String name) {
|
||||
myName = name;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return myName;
|
||||
}
|
||||
|
||||
public static LoadingOrder before(final String id) {
|
||||
return new BeforeLoadingOrder(id);
|
||||
}
|
||||
|
||||
public static LoadingOrder after(final String id) {
|
||||
return new AfterLoadingOrder(id);
|
||||
}
|
||||
|
||||
abstract int findPlace(Orderable[] orderables, int current);
|
||||
|
||||
public static void sort(Orderable[] orderables) {
|
||||
Orderable first = null;
|
||||
Orderable last = null;
|
||||
List other = new ArrayList();
|
||||
for (int i = 0; i < orderables.length; i++) {
|
||||
Orderable orderable = orderables[i];
|
||||
if (orderable.getOrder() == FIRST) {
|
||||
if (first != null) {
|
||||
throw new SortingException("More than one 'first' element", new Element[] {first.getDescribingElement(), orderable.getDescribingElement()});
|
||||
}
|
||||
first = orderable;
|
||||
}
|
||||
else if (orderable.getOrder() == LAST) {
|
||||
if (last != null) {
|
||||
throw new SortingException("More than one 'last' element", new Element[] {last.getDescribingElement(), orderable.getDescribingElement()});
|
||||
}
|
||||
last = orderable;
|
||||
}
|
||||
else {
|
||||
other.add(orderable);
|
||||
}
|
||||
}
|
||||
List result = new ArrayList();
|
||||
if (first != null) {
|
||||
result.add(first);
|
||||
}
|
||||
result.addAll(other);
|
||||
if (last != null) {
|
||||
result.add(last);
|
||||
}
|
||||
|
||||
assert result.size() == orderables.length;
|
||||
|
||||
Orderable[] presorted = (Orderable[]) result.toArray(new Orderable[result.size()]);
|
||||
|
||||
int swapCount = 0;
|
||||
int maxSwaps = presorted.length * presorted.length;
|
||||
for (int i = 0; i < presorted.length; i++) {
|
||||
Orderable orderable = presorted[i];
|
||||
LoadingOrder order = orderable.getOrder();
|
||||
int place = order.findPlace(presorted, i);
|
||||
if (place == DONT_CARE || place == ACCEPTABLE || place == SPECIAL) {
|
||||
continue;
|
||||
}
|
||||
if (place == 0 && presorted[0].getOrder() == FIRST) {
|
||||
throw new SortingException("Element attempts to go before the specified first", new Element[] {orderable.getDescribingElement(), presorted[0].getDescribingElement()});
|
||||
}
|
||||
if (place == presorted.length - 1 && presorted[presorted.length - 1].getOrder() == LAST) {
|
||||
throw new SortingException("Element attempts to go after the specified last", new Element[] {orderable.getDescribingElement(), presorted[presorted.length - 1].getDescribingElement()});
|
||||
}
|
||||
moveTo(presorted, i, place);
|
||||
if (i > place) {
|
||||
i = place;
|
||||
}
|
||||
else {
|
||||
i--;
|
||||
}
|
||||
swapCount++;
|
||||
if (swapCount > maxSwaps) {
|
||||
List allElements = new ArrayList();
|
||||
for (int j = 0; j < presorted.length; j++) {
|
||||
allElements.add(presorted[j].getDescribingElement());
|
||||
}
|
||||
throw new SortingException("Could not satisfy sorting requirements", (Element[]) allElements.toArray(new Element[allElements.size()]));
|
||||
}
|
||||
}
|
||||
|
||||
System.arraycopy(presorted, 0, orderables, 0, presorted.length);
|
||||
}
|
||||
|
||||
private static void moveTo(Orderable[] orderables, int from, int to) {
|
||||
if (to == from) return;
|
||||
Orderable movedOrderable = orderables[from];
|
||||
if (to > from) {
|
||||
for (int i = from; i < to; i++) {
|
||||
orderables[i] = orderables[i + 1];
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (int i = from; i > to; i--) {
|
||||
orderables[i] = orderables[i - 1];
|
||||
}
|
||||
}
|
||||
orderables[to] = movedOrderable;
|
||||
}
|
||||
|
||||
public static LoadingOrder readOrder(String orderAttr) {
|
||||
if (orderAttr != null) {
|
||||
if ("FIRST".equalsIgnoreCase(orderAttr)) return FIRST;
|
||||
if ("LAST".equalsIgnoreCase(orderAttr)) return LAST;
|
||||
if ("ANY".equalsIgnoreCase(orderAttr)) return ANY;
|
||||
if (orderAttr.toUpperCase().startsWith(BEFORE_STR)) {
|
||||
return before(orderAttr.substring(BEFORE_STR.length()));
|
||||
}
|
||||
if (orderAttr.toUpperCase().startsWith(AFTER_STR)) {
|
||||
return after(orderAttr.substring(AFTER_STR.length()));
|
||||
}
|
||||
}
|
||||
return ANY;
|
||||
}
|
||||
|
||||
private static class BeforeLoadingOrder extends LoadingOrder {
|
||||
private final String myId;
|
||||
|
||||
public BeforeLoadingOrder(String id) {
|
||||
super(LoadingOrder.BEFORE_STR + id);
|
||||
myId = id;
|
||||
}
|
||||
|
||||
int findPlace(Orderable[] orderables, int current) {
|
||||
for (int i = 0; i < orderables.length; i++) {
|
||||
Orderable orderable = orderables[i];
|
||||
String orderId = orderable.getOrderId();
|
||||
if (myId.equals(orderId)) {
|
||||
if (current < i) {
|
||||
return ACCEPTABLE;
|
||||
}
|
||||
else {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
}
|
||||
return DONT_CARE;
|
||||
}
|
||||
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (!(o instanceof BeforeLoadingOrder)) return false;
|
||||
|
||||
final BeforeLoadingOrder beforeLoadingOrder = (BeforeLoadingOrder) o;
|
||||
|
||||
if (!myId.equals(beforeLoadingOrder.myId)) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return myId.hashCode();
|
||||
}
|
||||
}
|
||||
|
||||
private static class AfterLoadingOrder extends LoadingOrder {
|
||||
private final String myId;
|
||||
|
||||
public AfterLoadingOrder(String id) {
|
||||
super(LoadingOrder.AFTER_STR + id);
|
||||
myId = id;
|
||||
}
|
||||
|
||||
int findPlace(Orderable[] orderables, int current) {
|
||||
for (int i = 0; i < orderables.length; i++) {
|
||||
Orderable orderable = orderables[i];
|
||||
String orderId = orderable.getOrderId();
|
||||
if (myId.equals(orderId)) {
|
||||
if (current > i) {
|
||||
return ACCEPTABLE;
|
||||
}
|
||||
else {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
}
|
||||
return DONT_CARE;
|
||||
}
|
||||
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (!(o instanceof AfterLoadingOrder)) return false;
|
||||
|
||||
final AfterLoadingOrder afterLoadingOrder = (AfterLoadingOrder) o;
|
||||
|
||||
if (!myId.equals(afterLoadingOrder.myId)) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return myId.hashCode();
|
||||
}
|
||||
}
|
||||
|
||||
public interface Orderable {
|
||||
String getOrderId();
|
||||
LoadingOrder getOrder();
|
||||
Element getDescribingElement();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
/*
|
||||
* Copyright (c) 2000-2004 by JetBrains s.r.o. All Rights Reserved.
|
||||
* Use is subject to license terms.
|
||||
*/
|
||||
package com.intellij.openapi.extensions;
|
||||
|
||||
/**
|
||||
* @author Alexander Kireyev
|
||||
*/
|
||||
public interface LogProvider {
|
||||
void error(String message);
|
||||
void error(String message, Throwable t);
|
||||
void error(Throwable t);
|
||||
|
||||
void warn(String message);
|
||||
void warn(String message, Throwable t);
|
||||
void warn(Throwable t);
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
/*
|
||||
* Copyright (c) 2000-2004 by JetBrains s.r.o. All Rights Reserved.
|
||||
* Use is subject to license terms.
|
||||
*/
|
||||
package com.intellij.openapi.extensions;
|
||||
|
||||
/**
|
||||
* @author akireyev
|
||||
*/
|
||||
public interface PluginAware {
|
||||
void setPluginName(String pluginName);
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
/*
|
||||
* Copyright (c) 2000-2004 by JetBrains s.r.o. All Rights Reserved.
|
||||
* Use is subject to license terms.
|
||||
*/
|
||||
package com.intellij.openapi.extensions;
|
||||
|
||||
import com.thoughtworks.xstream.XStream;
|
||||
|
||||
/**
|
||||
* @author AKireyev
|
||||
*/
|
||||
public interface ReaderConfigurator {
|
||||
void configureReader(XStream xstream);
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* Copyright (c) 2000-2004 by JetBrains s.r.o. All Rights Reserved.
|
||||
* Use is subject to license terms.
|
||||
*/
|
||||
package com.intellij.openapi.extensions;
|
||||
|
||||
import org.jdom.Element;
|
||||
|
||||
/**
|
||||
* @author Alexander Kireyev
|
||||
*/
|
||||
public class SortingException extends RuntimeException {
|
||||
private Element[] myConflictingElements;
|
||||
|
||||
public SortingException(String message, Element[] conflictingElements) {
|
||||
super(message);
|
||||
myConflictingElements = conflictingElements;
|
||||
}
|
||||
|
||||
public Element[] getConflictingElements() {
|
||||
return myConflictingElements;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright (c) 2000-2004 by JetBrains s.r.o. All Rights Reserved.
|
||||
* Use is subject to license terms.
|
||||
*/
|
||||
package com.intellij.openapi.extensions.impl;
|
||||
|
||||
import com.intellij.openapi.extensions.AreaInstance;
|
||||
|
||||
/**
|
||||
* @author akireyev
|
||||
*/
|
||||
class AreaDescriptor {
|
||||
private String myAreaClass;
|
||||
private AreaInstance myInstance;
|
||||
|
||||
public AreaDescriptor(String aClass, AreaInstance instance) {
|
||||
myAreaClass = aClass;
|
||||
myInstance = instance;
|
||||
}
|
||||
|
||||
public String getAreaClass() {
|
||||
return myAreaClass;
|
||||
}
|
||||
|
||||
public AreaInstance getAreaInstance() {
|
||||
return myInstance;
|
||||
}
|
||||
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (!(o instanceof AreaDescriptor)) return false;
|
||||
|
||||
final AreaDescriptor areaDescriptor = (AreaDescriptor) o;
|
||||
|
||||
if (myAreaClass != null ? !myAreaClass.equals(areaDescriptor.myAreaClass) : areaDescriptor.myAreaClass != null) return false;
|
||||
if (myInstance != null ? !myInstance.equals(areaDescriptor.myInstance) : areaDescriptor.myInstance != null) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
int result;
|
||||
result = (myAreaClass != null ? myAreaClass.hashCode() : 0);
|
||||
result = 29 * result + (myInstance != null ? myInstance.hashCode() : 0);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,175 @@
|
||||
/*
|
||||
* Copyright (c) 2000-2004 by JetBrains s.r.o. All Rights Reserved.
|
||||
* Use is subject to license terms.
|
||||
*/
|
||||
package com.intellij.openapi.extensions.impl;
|
||||
|
||||
import org.picocontainer.MutablePicoContainer;
|
||||
import org.picocontainer.PicoContainer;
|
||||
import org.picocontainer.ComponentAdapter;
|
||||
import org.picocontainer.Parameter;
|
||||
import org.picocontainer.defaults.DefaultPicoContainer;
|
||||
import org.picocontainer.defaults.AmbiguousComponentResolutionException;
|
||||
import org.picocontainer.defaults.AbstractPicoVisitor;
|
||||
import org.picocontainer.alternatives.AbstractDelegatingMutablePicoContainer;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* @author Alexander Kireyev
|
||||
*/
|
||||
public class AreaPicoContainer extends AbstractDelegatingMutablePicoContainer implements MutablePicoContainer {
|
||||
private ExtensionsAreaImpl myArea;
|
||||
|
||||
public AreaPicoContainer(PicoContainer parentPicoContainer, ExtensionsAreaImpl area) {
|
||||
super(new DefaultPicoContainer(parentPicoContainer));
|
||||
myArea = area;
|
||||
}
|
||||
|
||||
public ComponentAdapter getComponentAdapter(final Object componentKey) {
|
||||
final ComponentAdapter[] result = new ComponentAdapter[] { null };
|
||||
accept(new EmptyPicoVisitor() {
|
||||
public void visitComponentAdapter(ComponentAdapter componentAdapter) {
|
||||
if (componentKey.equals(componentAdapter.getComponentKey())) {
|
||||
result[0] = componentAdapter;
|
||||
}
|
||||
}
|
||||
});
|
||||
if (result[0] != null) {
|
||||
return result[0];
|
||||
}
|
||||
else {
|
||||
if (getParent() != null) {
|
||||
return getParent().getComponentAdapter(componentKey);
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public List getComponentInstances() {
|
||||
final List result = new ArrayList();
|
||||
accept(new EmptyPicoVisitor() {
|
||||
public void visitContainer(PicoContainer pico) {
|
||||
result.addAll(pico.getComponentInstances());
|
||||
}
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
public List getComponentInstancesOfType(final Class type) {
|
||||
final List result = new ArrayList();
|
||||
accept(new EmptyPicoVisitor() {
|
||||
public void visitContainer(PicoContainer pico) {
|
||||
result.addAll(pico.getComponentInstancesOfType(type));
|
||||
}
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
public Object getComponentInstanceOfType(Class componentType) {
|
||||
List instances = getComponentInstancesOfType(componentType);
|
||||
if (instances.size() == 0) {
|
||||
return null;
|
||||
}
|
||||
else if (instances.size() == 1) {
|
||||
return instances.get(0);
|
||||
}
|
||||
else {
|
||||
throw new AmbiguousComponentResolutionException(componentType, instances.toArray(new Object[instances.size()]));
|
||||
}
|
||||
}
|
||||
|
||||
public Object getComponentInstance(final Object componentKey) {
|
||||
if (getParent() != null) {
|
||||
Object parentInstance = getParent().getComponentInstance(componentKey);
|
||||
if (parentInstance != null) {
|
||||
return parentInstance;
|
||||
}
|
||||
}
|
||||
|
||||
final Object[] result = new Object[] { null };
|
||||
accept(new EmptyPicoVisitor() {
|
||||
public void visitContainer(PicoContainer pico) {
|
||||
final boolean[] found = new boolean[] { false };
|
||||
pico.accept(new EmptyPicoVisitor() {
|
||||
public void visitComponentAdapter(ComponentAdapter componentAdapter) {
|
||||
if (componentKey.equals(componentAdapter.getComponentKey())) {
|
||||
found[0] = true;
|
||||
}
|
||||
}
|
||||
});
|
||||
if (!found[0]) {
|
||||
return;
|
||||
}
|
||||
Object componentInstance = pico.getComponentInstance(componentKey);
|
||||
if (componentInstance != null) {
|
||||
result[0] = componentInstance;
|
||||
}
|
||||
}
|
||||
});
|
||||
return result[0];
|
||||
}
|
||||
|
||||
public ComponentAdapter getComponentAdapterOfType(Class componentType) {
|
||||
List adapters = getComponentAdaptersOfType(componentType);
|
||||
if (adapters.size() == 0) {
|
||||
return null;
|
||||
}
|
||||
else if (adapters.size() == 1) {
|
||||
return (ComponentAdapter) adapters.get(0);
|
||||
}
|
||||
else {
|
||||
Class[] foundClasses = new Class[adapters.size()];
|
||||
for (int i = 0; i < foundClasses.length; i++) {
|
||||
ComponentAdapter componentAdapter = (ComponentAdapter) adapters.get(i);
|
||||
foundClasses[i] = componentAdapter.getComponentImplementation();
|
||||
}
|
||||
throw new AmbiguousComponentResolutionException(componentType, foundClasses);
|
||||
}
|
||||
}
|
||||
|
||||
public Collection getComponentAdapters() {
|
||||
final List result = new ArrayList();
|
||||
if (getParent() != null) {
|
||||
result.addAll(getParent().getComponentAdapters());
|
||||
}
|
||||
accept(new EmptyPicoVisitor() {
|
||||
public void visitComponentAdapter(ComponentAdapter componentAdapter) {
|
||||
result.add(componentAdapter);
|
||||
}
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
public List getComponentAdaptersOfType(final Class componentType) {
|
||||
final List result = new ArrayList();
|
||||
if (getParent() != null) {
|
||||
result.addAll(getParent().getComponentAdaptersOfType(componentType));
|
||||
}
|
||||
accept(new EmptyPicoVisitor() {
|
||||
public void visitComponentAdapter(ComponentAdapter componentAdapter) {
|
||||
if (componentType.isAssignableFrom(componentAdapter.getComponentImplementation())) {
|
||||
result.add(componentAdapter);
|
||||
}
|
||||
}
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
public MutablePicoContainer makeChildContainer() {
|
||||
throw new UnsupportedOperationException("Method makeChildContainer() is not implemented");
|
||||
}
|
||||
|
||||
private abstract class EmptyPicoVisitor extends AbstractPicoVisitor {
|
||||
public void visitContainer(PicoContainer pico) {
|
||||
}
|
||||
|
||||
public void visitComponentAdapter(ComponentAdapter componentAdapter) {
|
||||
}
|
||||
|
||||
public void visitParameter(Parameter parameter) {
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright (c) 2000-2004 by JetBrains s.r.o. All Rights Reserved.
|
||||
* Use is subject to license terms.
|
||||
*/
|
||||
package com.intellij.openapi.extensions.impl;
|
||||
|
||||
import com.thoughtworks.xstream.converters.Converter;
|
||||
import com.thoughtworks.xstream.converters.MarshallingContext;
|
||||
import com.thoughtworks.xstream.converters.UnmarshallingContext;
|
||||
import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
|
||||
import com.thoughtworks.xstream.io.HierarchicalStreamReader;
|
||||
import org.jdom.Element;
|
||||
|
||||
/**
|
||||
* @author Alexander Kireyev
|
||||
*/
|
||||
public class ElementConverter implements Converter {
|
||||
public boolean canConvert(Class aClass) {
|
||||
return Element.class.isAssignableFrom(aClass);
|
||||
}
|
||||
|
||||
public void marshal(Object object, HierarchicalStreamWriter hierarchicalStreamWriter, MarshallingContext marshallingContext) {
|
||||
throw new UnsupportedOperationException("This method is not yet implemented");
|
||||
}
|
||||
|
||||
public Object unmarshal(HierarchicalStreamReader hierarchicalStreamReader, UnmarshallingContext unmarshallingContext) {
|
||||
return hierarchicalStreamReader.peekUnderlyingNode();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright (c) 2000-2004 by JetBrains s.r.o. All Rights Reserved.
|
||||
* Use is subject to license terms.
|
||||
*/
|
||||
package com.intellij.openapi.extensions.impl;
|
||||
|
||||
public class ExtensionClassAndAreaInstance {
|
||||
private final Class myExtensionClass;
|
||||
private final Object myAreaInstance;
|
||||
|
||||
public ExtensionClassAndAreaInstance(Class extensionClass, Object areaInstance) {
|
||||
myExtensionClass = extensionClass;
|
||||
myAreaInstance = areaInstance;
|
||||
}
|
||||
|
||||
public Class getExtensionClass() {
|
||||
return myExtensionClass;
|
||||
}
|
||||
|
||||
public Object getAreaInstance() {
|
||||
return myAreaInstance;
|
||||
}
|
||||
|
||||
public boolean equals(Object areaInstance) {
|
||||
if (this == areaInstance) return true;
|
||||
if (!(areaInstance instanceof ExtensionClassAndAreaInstance)) return false;
|
||||
|
||||
final ExtensionClassAndAreaInstance extensionClassAndAreaInstance = (ExtensionClassAndAreaInstance) areaInstance;
|
||||
|
||||
if (myAreaInstance != null ? !myAreaInstance.equals(extensionClassAndAreaInstance.myAreaInstance) : extensionClassAndAreaInstance.myAreaInstance != null) return false;
|
||||
if (!myExtensionClass.equals(extensionClassAndAreaInstance.myExtensionClass)) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
int result;
|
||||
result = myExtensionClass.hashCode();
|
||||
result = 29 * result + (myAreaInstance != null ? myAreaInstance.hashCode() : 0);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* Copyright (c) 2000-2004 by JetBrains s.r.o. All Rights Reserved.
|
||||
* Use is subject to license terms.
|
||||
*/
|
||||
package com.intellij.openapi.extensions.impl;
|
||||
|
||||
import com.intellij.openapi.extensions.LoadingOrder;
|
||||
import com.intellij.openapi.extensions.PluginAware;
|
||||
import com.intellij.openapi.extensions.ReaderConfigurator;
|
||||
import com.thoughtworks.xstream.XStream;
|
||||
import org.jdom.Element;
|
||||
import org.picocontainer.PicoContainer;
|
||||
import org.picocontainer.PicoInitializationException;
|
||||
import org.picocontainer.PicoIntrospectionException;
|
||||
import org.picocontainer.defaults.AssignabilityRegistrationException;
|
||||
import org.picocontainer.defaults.ConstructorInjectionComponentAdapter;
|
||||
import org.picocontainer.defaults.NotConcreteRegistrationException;
|
||||
|
||||
/**
|
||||
* @author Alexander Kireyev
|
||||
*/
|
||||
public class ExtensionComponentAdapter extends ConstructorInjectionComponentAdapter implements LoadingOrder.Orderable {
|
||||
private Object myComponentInstance;
|
||||
private Element myExtensionElement;
|
||||
private PicoContainer myContainer;
|
||||
private String myPluginName;
|
||||
|
||||
public ExtensionComponentAdapter(Class implementationClass, Element extensionElement, PicoContainer container, String pluginName) {
|
||||
super(new Object(), implementationClass);
|
||||
myExtensionElement = extensionElement;
|
||||
myContainer = container;
|
||||
myPluginName = pluginName;
|
||||
}
|
||||
|
||||
public Object getComponentInstance(final PicoContainer container) throws PicoInitializationException, PicoIntrospectionException, AssignabilityRegistrationException, NotConcreteRegistrationException {
|
||||
assert myContainer == container;
|
||||
|
||||
if (myComponentInstance == null) {
|
||||
if (!Element.class.equals(getComponentImplementation())) {
|
||||
XStream xStream = new XStream(new PropertyReflectionProvider());
|
||||
xStream.registerConverter(new ElementConverter());
|
||||
Object componentInstance = super.getComponentInstance(container);
|
||||
if (componentInstance instanceof ReaderConfigurator) {
|
||||
ReaderConfigurator readerConfigurator = (ReaderConfigurator) componentInstance;
|
||||
readerConfigurator.configureReader(xStream);
|
||||
}
|
||||
xStream.alias(myExtensionElement.getName(), componentInstance.getClass());
|
||||
myComponentInstance = xStream.unmarshal(new JDomReader(myExtensionElement), componentInstance);
|
||||
}
|
||||
else {
|
||||
myComponentInstance = myExtensionElement;
|
||||
}
|
||||
if (myComponentInstance instanceof PluginAware) {
|
||||
PluginAware pluginAware = (PluginAware) myComponentInstance;
|
||||
pluginAware.setPluginName(myPluginName);
|
||||
}
|
||||
}
|
||||
|
||||
return myComponentInstance;
|
||||
}
|
||||
|
||||
public Object getExtension() {
|
||||
return getComponentInstance(myContainer);
|
||||
}
|
||||
|
||||
public LoadingOrder getOrder() {
|
||||
String orderAttr = myExtensionElement.getAttributeValue("order");
|
||||
return LoadingOrder.readOrder(orderAttr);
|
||||
}
|
||||
|
||||
public String getOrderId() {
|
||||
return myExtensionElement.getAttributeValue("id");
|
||||
}
|
||||
|
||||
public Element getExtensionElement() {
|
||||
return myExtensionElement;
|
||||
}
|
||||
|
||||
public Element getDescribingElement() {
|
||||
return getExtensionElement();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,286 @@
|
||||
/*
|
||||
* Copyright (c) 2000-2004 by JetBrains s.r.o. All Rights Reserved.
|
||||
* Use is subject to license terms.
|
||||
*/
|
||||
package com.intellij.openapi.extensions.impl;
|
||||
|
||||
import com.intellij.openapi.extensions.*;
|
||||
|
||||
import java.lang.ref.SoftReference;
|
||||
import java.lang.reflect.Array;
|
||||
import java.util.*;
|
||||
|
||||
import org.jdom.Element;
|
||||
|
||||
/**
|
||||
* @author AKireyev
|
||||
*/
|
||||
public class ExtensionPointImpl implements ExtensionPoint {
|
||||
private final LogProvider myLogger;
|
||||
|
||||
private String myName;
|
||||
private String myBeanClassName;
|
||||
private List myExtensions = new ArrayList();
|
||||
private List myLoadedAdapters = new ArrayList();
|
||||
private Set myExtensionAdapters = new LinkedHashSet();
|
||||
private Set myEPListeners = new LinkedHashSet();
|
||||
private SoftReference myExtensionsCache;
|
||||
private ExtensionsAreaImpl myOwner;
|
||||
private final AreaInstance myArea;
|
||||
private Class myExtensionClass;
|
||||
|
||||
public ExtensionPointImpl(String name, String beanClassName, ExtensionsAreaImpl owner, AreaInstance area, LogProvider logger) {
|
||||
myName = name;
|
||||
myBeanClassName = beanClassName;
|
||||
myOwner = owner;
|
||||
myArea = area;
|
||||
myLogger = logger;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return myName;
|
||||
}
|
||||
|
||||
public AreaInstance getArea() {
|
||||
return myArea;
|
||||
}
|
||||
|
||||
public String getBeanClassName() {
|
||||
return myBeanClassName;
|
||||
}
|
||||
|
||||
public void registerExtension(Object extension) {
|
||||
registerExtension(extension, LoadingOrder.ANY);
|
||||
}
|
||||
|
||||
public void registerExtension(Object extension, LoadingOrder order) {
|
||||
assert (extension != null) : "Extension cannot be null";
|
||||
|
||||
myOwner.getMutablePicoContainer().registerComponentInstance(new Object(), extension);
|
||||
|
||||
assert myExtensions.size() == myLoadedAdapters.size();
|
||||
|
||||
if (LoadingOrder.ANY == order) {
|
||||
int index = myLoadedAdapters.size();
|
||||
if (myLoadedAdapters.size() > 0) {
|
||||
ExtensionComponentAdapter lastAdapter = (ExtensionComponentAdapter) myLoadedAdapters.get(myLoadedAdapters.size() - 1);
|
||||
if (lastAdapter.getOrder() == LoadingOrder.LAST) {
|
||||
index--;
|
||||
}
|
||||
}
|
||||
internalRegisterExtension(extension, new ObjectComponentAdapter(extension, order), index, true);
|
||||
}
|
||||
else {
|
||||
myExtensionAdapters.add(new ObjectComponentAdapter(extension, order));
|
||||
processAdapters();
|
||||
}
|
||||
}
|
||||
|
||||
private void internalRegisterExtension(Object extension, ExtensionComponentAdapter adapter, int index, boolean runNotifications) {
|
||||
myExtensionsCache = null;
|
||||
|
||||
if (myExtensions.contains(extension)) {
|
||||
myLogger.error("Extension was already added: " + extension);
|
||||
}
|
||||
else {
|
||||
myExtensions.add(index, extension);
|
||||
myLoadedAdapters.add(index, adapter);
|
||||
if (runNotifications) {
|
||||
if (extension instanceof Extension) {
|
||||
Extension o = (Extension) extension;
|
||||
try {
|
||||
o.extensionAdded(this);
|
||||
} catch (Throwable e) {
|
||||
myLogger.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
notifyListenersOnAdd(extension);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void notifyListenersOnAdd(Object extension) {
|
||||
ExtensionPointListener[] listeners = (ExtensionPointListener[]) myEPListeners.toArray(new ExtensionPointListener[myEPListeners.size()]);
|
||||
for (int i = 0; i < listeners.length; i++) {
|
||||
ExtensionPointListener listener = listeners[i];
|
||||
try {
|
||||
listener.extensionAdded(extension);
|
||||
} catch (Throwable e) {
|
||||
myLogger.error(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Object[] getExtensions() {
|
||||
Object[] result = null;
|
||||
|
||||
processAdapters();
|
||||
|
||||
if (myExtensionsCache != null) {
|
||||
result = (Object[]) myExtensionsCache.get();
|
||||
}
|
||||
if (result == null) {
|
||||
result = myExtensions.toArray((Object[])Array.newInstance(getExtensionClass(), myExtensions.size()));
|
||||
myExtensionsCache = new SoftReference(result);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private void processAdapters() {
|
||||
if (myExtensionAdapters.size() > 0) {
|
||||
List allAdapters = new ArrayList(myExtensionAdapters.size() + myLoadedAdapters.size());
|
||||
allAdapters.addAll(myExtensionAdapters);
|
||||
allAdapters.addAll(myLoadedAdapters);
|
||||
myExtensions.clear();
|
||||
List loadedAdapters = myLoadedAdapters;
|
||||
myLoadedAdapters = new ArrayList();
|
||||
ExtensionComponentAdapter[] adapters = (ExtensionComponentAdapter[]) allAdapters.toArray(new ExtensionComponentAdapter[myExtensionAdapters.size()]);
|
||||
LoadingOrder.sort(adapters);
|
||||
for (int i = 0; i < adapters.length; i++) {
|
||||
ExtensionComponentAdapter adapter = adapters[i];
|
||||
Object extension = adapter.getExtension();
|
||||
internalRegisterExtension(extension, adapter, i, !loadedAdapters.contains(adapter));
|
||||
}
|
||||
myExtensionAdapters.clear();
|
||||
}
|
||||
}
|
||||
|
||||
public Object getExtension() {
|
||||
Object[] extensions = getExtensions();
|
||||
if (extensions.length == 0) return null;
|
||||
|
||||
return extensions[0];
|
||||
}
|
||||
|
||||
public boolean hasExtension(Object extension) {
|
||||
processAdapters();
|
||||
|
||||
return myExtensions.contains(extension);
|
||||
}
|
||||
|
||||
public void unregisterExtension(Object extension) {
|
||||
assert (extension != null) : "Extension cannot be null";
|
||||
|
||||
myOwner.getMutablePicoContainer().unregisterComponentByInstance(extension);
|
||||
|
||||
processAdapters();
|
||||
|
||||
internalUnregisterExtension(extension);
|
||||
}
|
||||
|
||||
private void internalUnregisterExtension(Object extension) {
|
||||
myExtensionsCache = null;
|
||||
|
||||
if (!myExtensions.contains(extension)) {
|
||||
throw new IllegalArgumentException("Extension to be removed not found: " + extension);
|
||||
}
|
||||
int index = myExtensions.indexOf(extension);
|
||||
myExtensions.remove(index);
|
||||
myLoadedAdapters.remove(index);
|
||||
|
||||
notifyListenersOnRemove(extension);
|
||||
|
||||
if (extension instanceof Extension) {
|
||||
Extension o = (Extension) extension;
|
||||
try {
|
||||
o.extensionRemoved(this);
|
||||
} catch (Throwable e) {
|
||||
myLogger.error(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void notifyListenersOnRemove(Object extensionObject) {
|
||||
for (Iterator iterator = myEPListeners.iterator(); iterator.hasNext();) {
|
||||
ExtensionPointListener listener = (ExtensionPointListener)iterator.next();
|
||||
try {
|
||||
listener.extensionRemoved(extensionObject);
|
||||
} catch (Throwable e) {
|
||||
myLogger.error(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void addExtensionPointListener(ExtensionPointListener listener) {
|
||||
if (myEPListeners.add(listener)) {
|
||||
for (Iterator iterator = myExtensions.iterator(); iterator.hasNext();) {
|
||||
try {
|
||||
listener.extensionAdded(iterator.next());
|
||||
} catch (Throwable e) {
|
||||
myLogger.error(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void removeExtensionPointListener(ExtensionPointListener listener) {
|
||||
if (myEPListeners.contains(listener)) {
|
||||
for (Iterator iterator = myExtensions.iterator(); iterator.hasNext();) {
|
||||
try {
|
||||
listener.extensionRemoved(iterator.next());
|
||||
} catch (Throwable e) {
|
||||
myLogger.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
myEPListeners.remove(listener);
|
||||
}
|
||||
}
|
||||
|
||||
public void reset() {
|
||||
Object[] extensions = getExtensions();
|
||||
for (int i = 0; i < extensions.length; i++) {
|
||||
Object extension = extensions[i];
|
||||
unregisterExtension(extension);
|
||||
}
|
||||
}
|
||||
|
||||
public Class getExtensionClass() {
|
||||
if (myExtensionClass == null) {
|
||||
try {
|
||||
myExtensionClass = Class.forName(myBeanClassName);
|
||||
}
|
||||
catch (ClassNotFoundException e) {
|
||||
myExtensionClass = Object.class;
|
||||
}
|
||||
}
|
||||
return myExtensionClass;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return getName();
|
||||
}
|
||||
|
||||
void registerExtensionAdapter(ExtensionComponentAdapter adapter) {
|
||||
myExtensionAdapters.add(adapter);
|
||||
}
|
||||
|
||||
private static class ObjectComponentAdapter extends ExtensionComponentAdapter {
|
||||
private Object myExtension;
|
||||
private LoadingOrder myLoadingOrder;
|
||||
|
||||
public ObjectComponentAdapter(Object extension, LoadingOrder loadingOrder) {
|
||||
super(Object.class, null, null, null);
|
||||
myExtension = extension;
|
||||
myLoadingOrder = loadingOrder;
|
||||
}
|
||||
|
||||
public Object getExtension() {
|
||||
return myExtension;
|
||||
}
|
||||
|
||||
public LoadingOrder getOrder() {
|
||||
return myLoadingOrder;
|
||||
}
|
||||
|
||||
public String getOrderId() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public Element getDescribingElement() {
|
||||
return new Element("RuntimeExtension: " + myExtension);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,379 @@
|
||||
/*
|
||||
* Copyright (c) 2000-2004 by JetBrains s.r.o. All Rights Reserved.
|
||||
* Use is subject to license terms.
|
||||
*/
|
||||
package com.intellij.openapi.extensions.impl;
|
||||
|
||||
import com.intellij.openapi.extensions.*;
|
||||
import org.apache.commons.collections.MultiHashMap;
|
||||
import org.apache.commons.collections.MultiMap;
|
||||
import org.jdom.Element;
|
||||
import org.jdom.Namespace;
|
||||
import org.jdom.output.XMLOutputter;
|
||||
import org.picocontainer.MutablePicoContainer;
|
||||
import org.picocontainer.PicoContainer;
|
||||
import org.picocontainer.defaults.ConstructorInjectionComponentAdapter;
|
||||
import org.picocontainer.defaults.DefaultPicoContainer;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.StringWriter;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.*;
|
||||
|
||||
public class ExtensionsAreaImpl implements ExtensionsArea {
|
||||
private final LogProvider myLogger;
|
||||
|
||||
static Map ourDefaultEPs = new HashMap();
|
||||
|
||||
static {
|
||||
ourDefaultEPs.put(EPAvailabilityListenerExtension.EXTENSION_POINT_NAME, EPAvailabilityListenerExtension.class.getName());
|
||||
}
|
||||
|
||||
private static boolean DEBUG_REGISTRATION = true;
|
||||
|
||||
private MutablePicoContainer myPicoContainer;
|
||||
// private Map myPluginName2picoContainer = new HashMap();
|
||||
private Throwable myCreationTrace = null;
|
||||
private Map myExtensionPoints = new HashMap();
|
||||
private Map myEPTraces = new HashMap();
|
||||
private MultiMap myAvailabilityListeners = new MultiHashMap();
|
||||
private List mySuspendedListenerActions = new ArrayList();
|
||||
private boolean myAvailabilityNotificationsActive = true;
|
||||
|
||||
private final AreaInstance myAreaInstance;
|
||||
private MultiMap myServiceRegistry = new MultiHashMap();
|
||||
private final String myAreaClass;
|
||||
private Map myServiceClass2ServicesCache = new HashMap();
|
||||
private Map myExtensionElement2extension = new HashMap();
|
||||
private Map myPluginName2picoContainer = new HashMap();
|
||||
|
||||
public ExtensionsAreaImpl(String areaClass, AreaInstance areaInstance, PicoContainer parentPicoContainer, LogProvider logger) {
|
||||
if (DEBUG_REGISTRATION) {
|
||||
myCreationTrace = new Throwable("Area creation trace");
|
||||
}
|
||||
myAreaClass = areaClass;
|
||||
myAreaInstance = areaInstance;
|
||||
myPicoContainer = new AreaPicoContainer(parentPicoContainer, this);
|
||||
if (areaInstance != null) {
|
||||
myPicoContainer.registerComponentInstance(areaInstance);
|
||||
}
|
||||
initialize();
|
||||
myLogger = logger;
|
||||
}
|
||||
|
||||
public ExtensionsAreaImpl(MutablePicoContainer picoContainer, LogProvider logger) {
|
||||
this(null, null, picoContainer, logger);
|
||||
}
|
||||
|
||||
public MutablePicoContainer getPicoContainer() {
|
||||
return myPicoContainer;
|
||||
}
|
||||
|
||||
MutablePicoContainer getMutablePicoContainer() {
|
||||
return myPicoContainer;
|
||||
}
|
||||
|
||||
public String getAreaClass() {
|
||||
return myAreaClass;
|
||||
}
|
||||
|
||||
public void registerExtensionPoint(String pluginName, Element extensionPointElement) {
|
||||
assert pluginName != null;
|
||||
String epName = pluginName + '.' + extensionPointElement.getAttributeValue("name");
|
||||
String className = extensionPointElement.getAttributeValue("beanClass");
|
||||
if (className == null) {
|
||||
className = extensionPointElement.getAttributeValue("interface");
|
||||
}
|
||||
if (className == null) {
|
||||
throw new RuntimeException("No class specified for extension point: " + epName);
|
||||
}
|
||||
registerExtensionPoint(epName, className);
|
||||
}
|
||||
|
||||
public void registerExtension(final String pluginName, final Element extensionElement) {
|
||||
String epName = extractEPName(extensionElement);
|
||||
ExtensionComponentAdapter adapter;
|
||||
String implClass = null;
|
||||
Class extensionClass = getExtensionPoint(epName).getExtensionClass();
|
||||
implClass = extensionElement.getAttributeValue("implementation");
|
||||
if (extensionClass.isInterface() || Modifier.isAbstract(extensionClass.getModifiers())) {
|
||||
if (implClass == null) {
|
||||
throw new RuntimeException("Expected implementation for extension declaration (ep = " + epName + ")");
|
||||
}
|
||||
}
|
||||
if (implClass != null) {
|
||||
try {
|
||||
Class implementationClass = Class.forName(implClass);
|
||||
adapter = new ExtensionComponentAdapter(implementationClass, extensionElement, getPluginContainer(pluginName), pluginName);
|
||||
}
|
||||
catch (ClassNotFoundException e) {
|
||||
myLogger.warn("Extension implementation class not found: " + implClass);
|
||||
myExtensionElement2extension.put(extensionElement, null);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else {
|
||||
final ExtensionPoint extensionPoint = getExtensionPoint(epName);
|
||||
adapter = new ExtensionComponentAdapter(extensionPoint.getExtensionClass(), extensionElement, getPluginContainer(pluginName), pluginName);
|
||||
}
|
||||
myExtensionElement2extension.put(extensionElement, adapter);
|
||||
internalGetPluginContainer(pluginName).registerComponent(adapter);
|
||||
getExtensionPointImpl(epName).registerExtensionAdapter(adapter);
|
||||
}
|
||||
|
||||
private String extractEPName(final Element extensionElement) {
|
||||
String epName = extensionElement.getAttributeValue("point");
|
||||
if (epName == null) {
|
||||
Namespace namespace = extensionElement.getNamespace();
|
||||
epName = namespace.getURI() + '.' + extensionElement.getName();
|
||||
}
|
||||
return epName;
|
||||
}
|
||||
|
||||
public PicoContainer getPluginContainer(String pluginName) {
|
||||
return internalGetPluginContainer(pluginName);
|
||||
}
|
||||
|
||||
private MutablePicoContainer internalGetPluginContainer(String pluginName) {
|
||||
// return myPicoContainer;
|
||||
DefaultPicoContainer pluginContainer = (DefaultPicoContainer) myPluginName2picoContainer.get(pluginName);
|
||||
if (pluginContainer == null) {
|
||||
pluginContainer = new DefaultPicoContainer(myPicoContainer);
|
||||
myPicoContainer.addChildContainer(pluginContainer);
|
||||
myPluginName2picoContainer.put(pluginName, pluginContainer);
|
||||
}
|
||||
return pluginContainer;
|
||||
}
|
||||
|
||||
private void disposePluginContainer(String pluginName) {
|
||||
DefaultPicoContainer pluginContainer = (DefaultPicoContainer) myPluginName2picoContainer.remove(pluginName);
|
||||
if (pluginContainer != null) {
|
||||
myPicoContainer.removeChildContainer(pluginContainer);
|
||||
}
|
||||
}
|
||||
|
||||
public void unregisterExtensionPoint(String pluginName, Element extensionPointElement) {
|
||||
assert pluginName != null;
|
||||
String epName = pluginName + '.' + extensionPointElement.getAttributeValue("name");
|
||||
unregisterExtensionPoint(epName);
|
||||
}
|
||||
|
||||
public void unregisterExtension(String pluginName, Element extensionElement) {
|
||||
String epName = extractEPName(extensionElement);
|
||||
if (!myExtensionElement2extension.containsKey(extensionElement)) {
|
||||
XMLOutputter xmlOutputter = new XMLOutputter();
|
||||
xmlOutputter.setIndent(" ");
|
||||
xmlOutputter.setTextNormalize(true);
|
||||
xmlOutputter.setNewlines(true);
|
||||
StringWriter stringWriter = new StringWriter();
|
||||
try {
|
||||
xmlOutputter.output(extensionElement, stringWriter);
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
myLogger.warn(stringWriter.toString());
|
||||
throw new IllegalArgumentException("Trying to unregister extension element that was never registered");
|
||||
}
|
||||
ExtensionComponentAdapter adapter = (ExtensionComponentAdapter) myExtensionElement2extension.remove(extensionElement);
|
||||
if (adapter == null) return;
|
||||
if (getExtensionPoint(epName).hasExtension(adapter.getExtension())) {
|
||||
getExtensionPoint(epName).unregisterExtension(adapter.getExtension());
|
||||
MutablePicoContainer pluginContainer = internalGetPluginContainer(pluginName);
|
||||
pluginContainer.unregisterComponent(adapter.getComponentKey());
|
||||
if (pluginContainer.getComponentAdapters().size() == 0) {
|
||||
disposePluginContainer(pluginName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void initialize() {
|
||||
for (Iterator iterator = ourDefaultEPs.keySet().iterator(); iterator.hasNext();) {
|
||||
String epName = (String) iterator.next();
|
||||
registerExtensionPoint(epName, (String) ourDefaultEPs.get(epName));
|
||||
}
|
||||
getExtensionPoint(EPAvailabilityListenerExtension.EXTENSION_POINT_NAME).addExtensionPointListener(new ExtensionPointListener() {
|
||||
public void extensionRemoved(Object extension) {
|
||||
EPAvailabilityListenerExtension epListenerExtension = (EPAvailabilityListenerExtension) extension;
|
||||
List listeners = (List) myAvailabilityListeners.get(epListenerExtension.getExtensionPointName());
|
||||
for (Iterator iterator = listeners.iterator(); iterator.hasNext();) {
|
||||
Object listener = iterator.next();
|
||||
if (listener.getClass().getName().equals(epListenerExtension.getListenerClass())) {
|
||||
iterator.remove();
|
||||
return;
|
||||
}
|
||||
}
|
||||
myLogger.warn("Failed to find EP availability listener: " + epListenerExtension.getListenerClass());
|
||||
}
|
||||
|
||||
public void extensionAdded(Object extension) {
|
||||
EPAvailabilityListenerExtension epListenerExtension = (EPAvailabilityListenerExtension) extension;
|
||||
try {
|
||||
String epName = epListenerExtension.getExtensionPointName();
|
||||
|
||||
ExtensionPointAvailabilityListener listener = (ExtensionPointAvailabilityListener) instantiate(Class.forName(epListenerExtension.getListenerClass()));
|
||||
addAvailabilityListener(epName, listener);
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public Object instantiate(Class clazz) {
|
||||
ConstructorInjectionComponentAdapter adapter = new ConstructorInjectionComponentAdapter(System.identityHashCode(new Object()) + "", clazz);
|
||||
return adapter.getComponentInstance(getPicoContainer());
|
||||
}
|
||||
|
||||
public Throwable getCreationTrace() {
|
||||
return myCreationTrace;
|
||||
}
|
||||
|
||||
public void addAvailabilityListener(String epName, ExtensionPointAvailabilityListener listener) {
|
||||
myAvailabilityListeners.put(epName, listener);
|
||||
if (hasExtensionPoint(epName)) {
|
||||
notifyAvailableListener(listener, (ExtensionPoint) myExtensionPoints.get(epName));
|
||||
}
|
||||
}
|
||||
|
||||
public void registerExtensionPoint(final String extensionPointName, String extensionPointBeanClass) {
|
||||
if (hasExtensionPoint(extensionPointName)) {
|
||||
if (DEBUG_REGISTRATION) {
|
||||
myLogger.error((Throwable) myEPTraces.get(extensionPointName));
|
||||
}
|
||||
throw new RuntimeException("Duplicate registration for EP: " + extensionPointName);
|
||||
}
|
||||
|
||||
ExtensionPointImpl extensionPoint = new ExtensionPointImpl(extensionPointName, extensionPointBeanClass, this, myAreaInstance, myLogger);
|
||||
myExtensionPoints.put(extensionPointName, extensionPoint);
|
||||
notifyEPRegistered(extensionPoint);
|
||||
if (DEBUG_REGISTRATION) {
|
||||
myEPTraces.put(extensionPointName, new Throwable("Original registration for " + extensionPointName));
|
||||
}
|
||||
}
|
||||
|
||||
private void notifyEPRegistered(final ExtensionPoint extensionPoint) {
|
||||
List listeners = (List) myAvailabilityListeners.get(extensionPoint.getName());
|
||||
if (listeners != null) {
|
||||
for (Iterator i = listeners.iterator(); i.hasNext();) {
|
||||
final ExtensionPointAvailabilityListener listener = (ExtensionPointAvailabilityListener) i.next();
|
||||
notifyAvailableListener(listener, extensionPoint);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void notifyAvailableListener(final ExtensionPointAvailabilityListener listener, final ExtensionPoint extensionPoint) {
|
||||
Runnable action = new Runnable() {
|
||||
public void run() {
|
||||
listener.extensionPointRegistered(extensionPoint);
|
||||
}
|
||||
};
|
||||
if (myAvailabilityNotificationsActive) {
|
||||
action.run();
|
||||
}
|
||||
else {
|
||||
mySuspendedListenerActions.add(action);
|
||||
}
|
||||
}
|
||||
|
||||
public ExtensionPoint getExtensionPoint(String extensionPointName) {
|
||||
return getExtensionPointImpl(extensionPointName);
|
||||
}
|
||||
|
||||
private ExtensionPointImpl getExtensionPointImpl(String extensionPointName) {
|
||||
if (!hasExtensionPoint(extensionPointName)) {
|
||||
throw new IllegalArgumentException("Missing extension point: " + extensionPointName +
|
||||
" in area " + myAreaInstance );
|
||||
}
|
||||
return (ExtensionPointImpl) myExtensionPoints.get(extensionPointName);
|
||||
}
|
||||
|
||||
public ExtensionPoint[] getExtensionPoints() {
|
||||
return (ExtensionPoint[]) myExtensionPoints.values().toArray(new ExtensionPoint[myExtensionPoints.size()]);
|
||||
}
|
||||
|
||||
public void unregisterExtensionPoint(final String extensionPointName) {
|
||||
ExtensionPoint extensionPoint = (ExtensionPoint) myExtensionPoints.get(extensionPointName);
|
||||
if (extensionPoint != null) {
|
||||
extensionPoint.reset();
|
||||
myExtensionPoints.remove(extensionPointName);
|
||||
notifyEPRemoved(extensionPoint);
|
||||
}
|
||||
}
|
||||
|
||||
private void notifyEPRemoved(final ExtensionPoint extensionPoint) {
|
||||
List listeners = (List) myAvailabilityListeners.get(extensionPoint.getName());
|
||||
if (listeners != null) {
|
||||
for (Iterator i = listeners.iterator(); i.hasNext();) {
|
||||
final ExtensionPointAvailabilityListener listener = (ExtensionPointAvailabilityListener) i.next();
|
||||
Runnable action = new Runnable() {
|
||||
public void run() {
|
||||
listener.extensionPointRemoved(extensionPoint);
|
||||
}
|
||||
};
|
||||
if (myAvailabilityNotificationsActive) {
|
||||
action.run();
|
||||
}
|
||||
else {
|
||||
mySuspendedListenerActions.add(action);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean hasExtensionPoint(String extensionPointName) {
|
||||
return myExtensionPoints.containsKey(extensionPointName);
|
||||
}
|
||||
|
||||
public void suspendInteractions() {
|
||||
myAvailabilityNotificationsActive = false;
|
||||
}
|
||||
|
||||
public void resumeInteractions() {
|
||||
myAvailabilityNotificationsActive = true;
|
||||
ExtensionPoint[] extensionPoints = getExtensionPoints();
|
||||
for (int i = 0; i < extensionPoints.length; i++) {
|
||||
ExtensionPoint extensionPoint = extensionPoints[i];
|
||||
extensionPoint.getExtensions(); // creates extensions from ComponentAdapters
|
||||
}
|
||||
for (Iterator i = mySuspendedListenerActions.iterator(); i.hasNext();) {
|
||||
Runnable action = (Runnable) i.next();
|
||||
try {
|
||||
action.run();
|
||||
}
|
||||
catch (Exception e) {
|
||||
myLogger.error(e);
|
||||
}
|
||||
}
|
||||
mySuspendedListenerActions.clear();
|
||||
}
|
||||
|
||||
public void killPendingInteractions() {
|
||||
mySuspendedListenerActions.clear();
|
||||
}
|
||||
|
||||
private Set collectInterfaces(String className) {
|
||||
try {
|
||||
Class serviceClass = Class.forName(className);
|
||||
Set classes = new HashSet();
|
||||
classes.add(serviceClass.getName());
|
||||
collectInterfaces(serviceClass, classes);
|
||||
return classes;
|
||||
}
|
||||
catch (ClassNotFoundException e) {
|
||||
return Collections.EMPTY_SET;
|
||||
}
|
||||
}
|
||||
|
||||
private void collectInterfaces(Class serviceClass, Set classes) {
|
||||
Class[] interfaces = serviceClass.getInterfaces();
|
||||
for (int i = 0; i < interfaces.length; i++) {
|
||||
Class anInterface = interfaces[i];
|
||||
if (!classes.contains(anInterface.getName())) {
|
||||
classes.add(anInterface.getName());
|
||||
collectInterfaces(anInterface, classes);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright (c) 2000-2004 by JetBrains s.r.o. All Rights Reserved.
|
||||
* Use is subject to license terms.
|
||||
*/
|
||||
package com.intellij.openapi.extensions.impl;
|
||||
|
||||
import org.jdom.Element;
|
||||
import org.jdom.JDOMException;
|
||||
import org.jdom.input.SAXBuilder;
|
||||
import org.jmock.cglib.MockObjectTestCase;
|
||||
import org.picocontainer.defaults.DefaultPicoContainer;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.StringReader;
|
||||
|
||||
import com.intellij.openapi.extensions.LoadingOrder;
|
||||
|
||||
/**
|
||||
* @author Alexander Kireyev
|
||||
*/
|
||||
public class ExtensionComponentAdapterTest extends MockObjectTestCase {
|
||||
public void testLoadingOrderReading() {
|
||||
assertEquals(LoadingOrder.ANY, createAdapter("<extension/>").getOrder());
|
||||
assertEquals(LoadingOrder.FIRST, createAdapter("<extension order=\"FIRST\"/>").getOrder());
|
||||
assertEquals(LoadingOrder.LAST, createAdapter("<extension order=\"LAST\"/>").getOrder());
|
||||
assertEquals(LoadingOrder.before("test"), createAdapter("<extension order=\"BEFORE:test\"/>").getOrder());
|
||||
assertEquals(LoadingOrder.after("test"), createAdapter("<extension order=\"AFTER:test\"/>").getOrder());
|
||||
}
|
||||
|
||||
private ExtensionComponentAdapter createAdapter(String text) {
|
||||
Element extensionElement = readElement(text);
|
||||
|
||||
ExtensionComponentAdapter adapter = new ExtensionComponentAdapter(Object.class, extensionElement, new DefaultPicoContainer(), "");
|
||||
return adapter;
|
||||
}
|
||||
|
||||
static Element readElement(String text) {
|
||||
Element extensionElement1 = null;
|
||||
try {
|
||||
extensionElement1 = new SAXBuilder().build(new StringReader(text)).getRootElement();
|
||||
}
|
||||
catch (JDOMException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
Element extensionElement = extensionElement1;
|
||||
return extensionElement;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,124 @@
|
||||
/*
|
||||
* Copyright (c) 2000-2004 by JetBrains s.r.o. All Rights Reserved.
|
||||
* Use is subject to license terms.
|
||||
*/
|
||||
package com.intellij.openapi.extensions.impl;
|
||||
|
||||
import com.intellij.openapi.extensions.*;
|
||||
import junit.framework.TestCase;
|
||||
import org.picocontainer.defaults.DefaultPicoContainer;
|
||||
|
||||
/**
|
||||
* @author AKireyev
|
||||
*/
|
||||
public class ExtensionPointImplTest extends TestCase {
|
||||
public void testCreate() {
|
||||
ExtensionPointImpl extensionPoint = buildExtensionPoint();
|
||||
assertEquals(ExtensionsImplTest.EXTENSION_POINT_NAME_1, extensionPoint.getName());
|
||||
assertEquals(Integer.class.getName(), extensionPoint.getBeanClassName());
|
||||
}
|
||||
|
||||
private ExtensionPointImpl buildExtensionPoint() {
|
||||
return new ExtensionPointImpl(ExtensionsImplTest.EXTENSION_POINT_NAME_1, Integer.class.getName(), buildExtensionArea(), null, new Extensions.SimpleLogProvider());
|
||||
}
|
||||
|
||||
private ExtensionsAreaImpl buildExtensionArea() {
|
||||
return new ExtensionsAreaImpl(new DefaultPicoContainer(), new Extensions.SimpleLogProvider());
|
||||
}
|
||||
|
||||
public void testUnregisterObject() {
|
||||
ExtensionPointImpl extensionPoint = buildExtensionPoint();
|
||||
extensionPoint.registerExtension(new Integer(123));
|
||||
Object[] extensions = extensionPoint.getExtensions();
|
||||
assertEquals(1, extensions.length);
|
||||
extensionPoint.unregisterExtension(new Integer(123));
|
||||
extensions = extensionPoint.getExtensions();
|
||||
assertEquals(0, extensions.length);
|
||||
}
|
||||
|
||||
public void testRegisterUnregister_Extension() {
|
||||
|
||||
final AreaInstance area = new AreaInstance() {};
|
||||
final ExtensionPointImpl extensionPoint = new ExtensionPointImpl("an.extension.point", Object.class.getName(), buildExtensionArea(), area, new Extensions.SimpleLogProvider());
|
||||
|
||||
final boolean[] flags = new boolean[2];
|
||||
Extension extension = new Extension() {
|
||||
public void extensionAdded(ExtensionPoint extensionPoint1) {
|
||||
assertSame(extensionPoint, extensionPoint1);
|
||||
assertSame(area, extensionPoint1.getArea());
|
||||
flags[0] = true;
|
||||
}
|
||||
|
||||
public void extensionRemoved(ExtensionPoint extensionPoint1) {
|
||||
assertSame(extensionPoint, extensionPoint1);
|
||||
assertSame(area, extensionPoint1.getArea());
|
||||
flags[1] = true;
|
||||
}
|
||||
};
|
||||
|
||||
extensionPoint.registerExtension(extension);
|
||||
assertTrue("Registratioon call is missed", flags[0]);
|
||||
assertFalse(flags[1]);
|
||||
|
||||
extensionPoint.unregisterExtension(extension);
|
||||
assertTrue("UnRegistratioon call is missed", flags[1]);
|
||||
}
|
||||
|
||||
public void testRegisterObject() {
|
||||
ExtensionPointImpl extensionPoint = buildExtensionPoint();
|
||||
extensionPoint.registerExtension(new Integer(123));
|
||||
Object[] extensions = extensionPoint.getExtensions();
|
||||
assertEquals("One extension", 1, extensions.length);
|
||||
assertEquals("Correct type", Integer[].class, extensions.getClass());
|
||||
assertEquals("Correct object", new Integer(123), extensions[0]);
|
||||
}
|
||||
|
||||
public void testRegistrationOrder() {
|
||||
ExtensionPointImpl extensionPoint = buildExtensionPoint();
|
||||
extensionPoint.registerExtension(new Integer(123));
|
||||
extensionPoint.registerExtension(new Integer(321), LoadingOrder.FIRST);
|
||||
Object[] extensions = extensionPoint.getExtensions();
|
||||
assertEquals("One extension", 2, extensions.length);
|
||||
assertEquals("Correct object", new Integer(321), extensions[0]);
|
||||
}
|
||||
|
||||
public void testListener() {
|
||||
ExtensionPointImpl extensionPoint = buildExtensionPoint();
|
||||
final boolean added[] = new boolean[1];
|
||||
final boolean removed[] = new boolean[1];
|
||||
extensionPoint.addExtensionPointListener(new ExtensionPointListener() {
|
||||
public void extensionAdded(Object extension) {
|
||||
added[0] = true;
|
||||
}
|
||||
|
||||
public void extensionRemoved(Object extension) {
|
||||
removed[0] = true;
|
||||
}
|
||||
});
|
||||
assertFalse(added[0]);
|
||||
assertFalse(removed[0]);
|
||||
extensionPoint.registerExtension(new Integer(123));
|
||||
assertTrue(added[0]);
|
||||
assertFalse(removed[0]);
|
||||
added[0] = false;
|
||||
extensionPoint.unregisterExtension(new Integer(123));
|
||||
assertFalse(added[0]);
|
||||
assertTrue(removed[0]);
|
||||
}
|
||||
|
||||
public void testLateListener() {
|
||||
ExtensionPointImpl extensionPoint = buildExtensionPoint();
|
||||
final boolean added[] = new boolean[1];
|
||||
extensionPoint.registerExtension(new Integer(123));
|
||||
assertFalse(added[0]);
|
||||
extensionPoint.addExtensionPointListener(new ExtensionPointListener() {
|
||||
public void extensionAdded(Object extension) {
|
||||
added[0] = true;
|
||||
}
|
||||
|
||||
public void extensionRemoved(Object extension) {
|
||||
}
|
||||
});
|
||||
assertTrue(added[0]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,352 @@
|
||||
/*
|
||||
* Copyright (c) 2000-2004 by JetBrains s.r.o. All Rights Reserved.
|
||||
* Use is subject to license terms.
|
||||
*/
|
||||
package com.intellij.openapi.extensions.impl;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
import com.intellij.openapi.extensions.*;
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.picocontainer.defaults.DefaultPicoContainer;
|
||||
import org.picocontainer.MutablePicoContainer;
|
||||
|
||||
/**
|
||||
* @author AKireyev
|
||||
*/
|
||||
public class ExtensionsImplTest extends TestCase {
|
||||
public static final String EXTENSION_POINT_NAME_1 = "ext.point.one";
|
||||
public static final String AREA_1 = "the.area.one";
|
||||
|
||||
protected void tearDown() throws Exception {
|
||||
ExtensionsTestUtils.hardReset();
|
||||
super.tearDown(); //To change body of overriden methods use Options | File Templates.
|
||||
}
|
||||
|
||||
public void testCreateAndAccess() {
|
||||
ExtensionsAreaImpl extensionsArea = new ExtensionsAreaImpl(null, new Extensions.SimpleLogProvider());
|
||||
int numEP = extensionsArea.getExtensionPoints().length;
|
||||
extensionsArea.registerExtensionPoint(EXTENSION_POINT_NAME_1, Integer.class.getName());
|
||||
assertEquals("Additional EP available", numEP + 1, extensionsArea.getExtensionPoints().length);
|
||||
assertNotNull("EP by name available", extensionsArea.getExtensionPoint(EXTENSION_POINT_NAME_1));
|
||||
}
|
||||
|
||||
public void testInvalidActions() {
|
||||
ExtensionsAreaImpl extensionsArea = new ExtensionsAreaImpl(null, new Extensions.SimpleLogProvider());
|
||||
extensionsArea.registerExtensionPoint(EXTENSION_POINT_NAME_1, Integer.class.getName());
|
||||
try {
|
||||
extensionsArea.registerExtensionPoint(EXTENSION_POINT_NAME_1, Boolean.class.getName());
|
||||
fail("Should not allow duplicate registration");
|
||||
} catch (RuntimeException e) {
|
||||
}
|
||||
}
|
||||
|
||||
public void testUnregisterEP() {
|
||||
ExtensionsAreaImpl extensionsArea = new ExtensionsAreaImpl(null, new Extensions.SimpleLogProvider());
|
||||
int numEP = extensionsArea.getExtensionPoints().length;
|
||||
extensionsArea.registerExtensionPoint(EXTENSION_POINT_NAME_1, Integer.class.getName());
|
||||
final boolean removed[] = new boolean[1];
|
||||
removed[0] = false;
|
||||
extensionsArea.getExtensionPoint(EXTENSION_POINT_NAME_1).addExtensionPointListener(new ExtensionPointListener() {
|
||||
public void extensionAdded(Object extension) {
|
||||
}
|
||||
|
||||
public void extensionRemoved(Object extension) {
|
||||
removed[0] = true;
|
||||
}
|
||||
});
|
||||
extensionsArea.getExtensionPoint(EXTENSION_POINT_NAME_1).registerExtension(new Integer(123));
|
||||
extensionsArea.unregisterExtensionPoint(EXTENSION_POINT_NAME_1);
|
||||
assertTrue("Extension point should be removed", extensionsArea.getExtensionPoints().length == numEP);
|
||||
assertTrue("Extension point disposed", removed[0]);
|
||||
}
|
||||
|
||||
public void testAvailabilityListener() {
|
||||
ExtensionsAreaImpl extensionsArea = new ExtensionsAreaImpl(null, new Extensions.SimpleLogProvider());
|
||||
MyListener.reset();
|
||||
extensionsArea.getExtensionPoint(EPAvailabilityListenerExtension.EXTENSION_POINT_NAME).registerExtension(
|
||||
new EPAvailabilityListenerExtension(EXTENSION_POINT_NAME_1, MyListener.class.getName()));
|
||||
assertEquals(0, MyListener.regcount);
|
||||
assertEquals(0, MyListener.remcount);
|
||||
extensionsArea.registerExtensionPoint(EXTENSION_POINT_NAME_1, Integer.class.getName());
|
||||
assertEquals(1, MyListener.regcount);
|
||||
assertEquals(0, MyListener.remcount);
|
||||
MyListener.reset();
|
||||
extensionsArea.unregisterExtensionPoint(EXTENSION_POINT_NAME_1);
|
||||
assertEquals(1, MyListener.remcount);
|
||||
assertEquals(0, MyListener.regcount);
|
||||
}
|
||||
|
||||
public void testAvailability2Listeners() {
|
||||
ExtensionsAreaImpl extensionsArea = new ExtensionsAreaImpl(null, new Extensions.SimpleLogProvider());
|
||||
MyListener.reset();
|
||||
extensionsArea.registerExtensionPoint(EXTENSION_POINT_NAME_1, Integer.class.getName());
|
||||
extensionsArea.getExtensionPoint(EPAvailabilityListenerExtension.EXTENSION_POINT_NAME).registerExtension(
|
||||
new EPAvailabilityListenerExtension(EXTENSION_POINT_NAME_1, MyListener.class.getName()));
|
||||
extensionsArea.getExtensionPoint(EPAvailabilityListenerExtension.EXTENSION_POINT_NAME).registerExtension(
|
||||
new EPAvailabilityListenerExtension(EXTENSION_POINT_NAME_1, MyListener.class.getName()));
|
||||
assertEquals(2, MyListener.regcount);
|
||||
assertEquals(0, MyListener.remcount);
|
||||
MyListener.reset();
|
||||
extensionsArea.unregisterExtensionPoint(EXTENSION_POINT_NAME_1);
|
||||
assertEquals(2, MyListener.remcount);
|
||||
assertEquals(0, MyListener.regcount);
|
||||
}
|
||||
|
||||
public void testAvailabilityListenerAfter() {
|
||||
ExtensionsAreaImpl extensionsArea = new ExtensionsAreaImpl(null, new Extensions.SimpleLogProvider());
|
||||
extensionsArea.registerExtensionPoint(EXTENSION_POINT_NAME_1, Integer.class.getName());
|
||||
MyListener.reset();
|
||||
extensionsArea.getExtensionPoint(EPAvailabilityListenerExtension.EXTENSION_POINT_NAME).registerExtension(
|
||||
new EPAvailabilityListenerExtension(EXTENSION_POINT_NAME_1, MyListener.class.getName()));
|
||||
assertEquals(1, MyListener.regcount);
|
||||
assertEquals(0, MyListener.remcount);
|
||||
}
|
||||
|
||||
public void testAvailabilityListenerDelay() {
|
||||
ExtensionsAreaImpl extensionsArea = new ExtensionsAreaImpl(null, new Extensions.SimpleLogProvider());
|
||||
MyListener.reset();
|
||||
extensionsArea.suspendInteractions();
|
||||
extensionsArea.getExtensionPoint(EPAvailabilityListenerExtension.EXTENSION_POINT_NAME).registerExtension(
|
||||
new EPAvailabilityListenerExtension(EXTENSION_POINT_NAME_1, MyListener.class.getName()));
|
||||
assertEquals(0, MyListener.regcount);
|
||||
assertEquals(0, MyListener.remcount);
|
||||
extensionsArea.registerExtensionPoint(EXTENSION_POINT_NAME_1, Integer.class.getName());
|
||||
assertEquals(0, MyListener.regcount);
|
||||
assertEquals(0, MyListener.remcount);
|
||||
extensionsArea.resumeInteractions();
|
||||
assertEquals(1, MyListener.regcount);
|
||||
assertEquals(0, MyListener.remcount);
|
||||
MyListener.reset();
|
||||
extensionsArea.suspendInteractions();
|
||||
assertEquals(0, MyListener.regcount);
|
||||
assertEquals(0, MyListener.remcount);
|
||||
extensionsArea.unregisterExtensionPoint(EXTENSION_POINT_NAME_1);
|
||||
assertEquals(0, MyListener.regcount);
|
||||
assertEquals(0, MyListener.remcount);
|
||||
extensionsArea.resumeInteractions();
|
||||
assertEquals(1, MyListener.remcount);
|
||||
assertEquals(0, MyListener.regcount);
|
||||
}
|
||||
|
||||
public void testKillAvailabilityNotifications() {
|
||||
ExtensionsAreaImpl extensionsArea = new ExtensionsAreaImpl(null, new Extensions.SimpleLogProvider());
|
||||
MyListener.reset();
|
||||
extensionsArea.suspendInteractions();
|
||||
extensionsArea.getExtensionPoint(EPAvailabilityListenerExtension.EXTENSION_POINT_NAME).registerExtension(
|
||||
new EPAvailabilityListenerExtension(EXTENSION_POINT_NAME_1, MyListener.class.getName()));
|
||||
assertEquals(0, MyListener.regcount);
|
||||
assertEquals(0, MyListener.remcount);
|
||||
extensionsArea.registerExtensionPoint(EXTENSION_POINT_NAME_1, Integer.class.getName());
|
||||
assertEquals(0, MyListener.regcount);
|
||||
assertEquals(0, MyListener.remcount);
|
||||
extensionsArea.killPendingInteractions();
|
||||
extensionsArea.resumeInteractions();
|
||||
assertEquals(0, MyListener.regcount);
|
||||
assertEquals(0, MyListener.remcount);
|
||||
}
|
||||
|
||||
public void testListenerAfterResume() {
|
||||
ExtensionsAreaImpl extensionsArea = new ExtensionsAreaImpl(null, new Extensions.SimpleLogProvider());
|
||||
extensionsArea.suspendInteractions();
|
||||
extensionsArea.resumeInteractions();
|
||||
MyListener.reset();
|
||||
extensionsArea.getExtensionPoint(EPAvailabilityListenerExtension.EXTENSION_POINT_NAME).registerExtension(
|
||||
new EPAvailabilityListenerExtension(EXTENSION_POINT_NAME_1, MyListener.class.getName()));
|
||||
assertEquals(0, MyListener.regcount);
|
||||
assertEquals(0, MyListener.remcount);
|
||||
extensionsArea.registerExtensionPoint(EXTENSION_POINT_NAME_1, Integer.class.getName());
|
||||
assertEquals(1, MyListener.regcount);
|
||||
assertEquals(0, MyListener.remcount);
|
||||
MyListener.reset();
|
||||
extensionsArea.unregisterExtensionPoint(EXTENSION_POINT_NAME_1);
|
||||
assertEquals(1, MyListener.remcount);
|
||||
assertEquals(0, MyListener.regcount);
|
||||
}
|
||||
|
||||
public void testTryPicoContainer() {
|
||||
DefaultPicoContainer rootContainer = new DefaultPicoContainer();
|
||||
rootContainer.registerComponentInstance("plugin1", new DefaultPicoContainer(rootContainer));
|
||||
rootContainer.registerComponentInstance("plugin2", new DefaultPicoContainer(rootContainer));
|
||||
// rootContainer.registerComponentImplementation("plugin2", DefaultPicoContainer.class);
|
||||
MutablePicoContainer container1 = (MutablePicoContainer)rootContainer.getComponentInstance("plugin1");
|
||||
MutablePicoContainer container2 = (MutablePicoContainer)rootContainer.getComponentInstance("plugin2");
|
||||
container1.registerComponentImplementation("component1", MyComponent1.class);
|
||||
container1.registerComponentImplementation("component1.1", MyComponent1.class);
|
||||
container2.registerComponentImplementation("component2", MyComponent2.class);
|
||||
MyInterface1 testInstance = new MyInterface1() {
|
||||
public void run() {
|
||||
}
|
||||
};
|
||||
rootContainer.registerComponentInstance(testInstance);
|
||||
MyComponent1 component1 = (MyComponent1)container1.getComponentInstance("component1");
|
||||
assertEquals(testInstance, component1.testObject);
|
||||
rootContainer.registerComponentInstance("component1", component1);
|
||||
MyComponent1 component11 = (MyComponent1)container1.getComponentInstance("component1.1");
|
||||
rootContainer.registerComponentInstance("component11", component11);
|
||||
MyComponent2 component2 = (MyComponent2)container2.getComponentInstance("component2");
|
||||
assertEquals(testInstance, component2.testObject);
|
||||
assertTrue(Arrays.asList(component2.comp1).contains(component1));
|
||||
assertTrue(Arrays.asList(component2.comp1).contains(component11));
|
||||
rootContainer.registerComponentInstance("component2", component2);
|
||||
rootContainer.registerComponentImplementation(MyTestComponent.class);
|
||||
MyTestComponent testComponent = (MyTestComponent)rootContainer.getComponentInstance(MyTestComponent.class);
|
||||
assertTrue(Arrays.asList(testComponent.comp1).contains(component1));
|
||||
assertTrue(Arrays.asList(testComponent.comp1).contains(component11));
|
||||
assertEquals(component2, testComponent.comp2);
|
||||
}
|
||||
|
||||
public void testTryPicoContainer2() {
|
||||
DefaultPicoContainer rootContainer = new DefaultPicoContainer();
|
||||
rootContainer.registerComponentImplementation("component1", MyComponent1.class);
|
||||
rootContainer.registerComponentImplementation("component1.1", MyComponent1.class);
|
||||
rootContainer.registerComponentImplementation("component2", MyComponent2.class);
|
||||
rootContainer.registerComponentImplementation(MyTestComponent.class);
|
||||
MyInterface1 testInstance = new MyInterface1() {
|
||||
public void run() {
|
||||
}
|
||||
};
|
||||
rootContainer.registerComponentInstance(testInstance);
|
||||
MyTestComponent testComponent = (MyTestComponent)rootContainer.getComponentInstance(MyTestComponent.class);
|
||||
MyComponent2 component2 = (MyComponent2)rootContainer.getComponentInstance("component2");
|
||||
MyComponent1 component11 = (MyComponent1)rootContainer.getComponentInstance("component1.1");
|
||||
MyComponent1 component1 = (MyComponent1)rootContainer.getComponentInstance("component1");
|
||||
assertEquals(testInstance, component1.testObject);
|
||||
assertEquals(testInstance, component2.testObject);
|
||||
assertTrue(Arrays.asList(component2.comp1).contains(component1));
|
||||
assertTrue(Arrays.asList(component2.comp1).contains(component11));
|
||||
assertTrue(Arrays.asList(testComponent.comp1).contains(component1));
|
||||
assertTrue(Arrays.asList(testComponent.comp1).contains(component11));
|
||||
assertEquals(component2, testComponent.comp2);
|
||||
}
|
||||
|
||||
public void testExtensionsNamespaces() {
|
||||
ExtensionsAreaImpl extensionsArea = new ExtensionsAreaImpl(new DefaultPicoContainer(), new Extensions.SimpleLogProvider());
|
||||
extensionsArea.registerExtensionPoint("plugin.ep1", TestExtensionClassOne.class.getName());
|
||||
extensionsArea.registerExtension("plugin", ExtensionComponentAdapterTest.readElement(
|
||||
"<plugin:ep1 xmlns:plugin=\"plugin\" order=\"LAST\"><text>3</text></plugin:ep1>"));
|
||||
extensionsArea.registerExtension("plugin", ExtensionComponentAdapterTest.readElement(
|
||||
"<ep1 xmlns=\"plugin\" order=\"FIRST\"><text>1</text></ep1>"));
|
||||
extensionsArea.registerExtension("plugin", ExtensionComponentAdapterTest.readElement(
|
||||
"<extension point=\"plugin.ep1\"><text>2</text></extension>"));
|
||||
ExtensionPoint extensionPoint = extensionsArea.getExtensionPoint("plugin.ep1");
|
||||
TestExtensionClassOne[] extensions = (TestExtensionClassOne[]) extensionPoint.getExtensions();
|
||||
assertEquals(3, extensions.length);
|
||||
assertEquals("1", extensions[0].getText());
|
||||
assertEquals("2", extensions[1].getText());
|
||||
assertEquals("3", extensions[2].getText());
|
||||
}
|
||||
|
||||
public void testExtensionsWithOrdering() {
|
||||
ExtensionsAreaImpl extensionsArea = new ExtensionsAreaImpl(new DefaultPicoContainer(), new Extensions.SimpleLogProvider());
|
||||
extensionsArea.registerExtensionPoint("ep1", TestExtensionClassOne.class.getName());
|
||||
extensionsArea.registerExtension("", ExtensionComponentAdapterTest.readElement(
|
||||
"<extension point=\"ep1\" order=\"LAST\"><text>3</text></extension>"));
|
||||
extensionsArea.registerExtension("", ExtensionComponentAdapterTest.readElement(
|
||||
"<extension point=\"ep1\" order=\"FIRST\"><text>1</text></extension>"));
|
||||
extensionsArea.registerExtension("", ExtensionComponentAdapterTest.readElement(
|
||||
"<extension point=\"ep1\"><text>2</text></extension>"));
|
||||
ExtensionPoint extensionPoint = extensionsArea.getExtensionPoint("ep1");
|
||||
TestExtensionClassOne[] extensions = (TestExtensionClassOne[]) extensionPoint.getExtensions();
|
||||
assertEquals(3, extensions.length);
|
||||
assertEquals("1", extensions[0].getText());
|
||||
assertEquals("2", extensions[1].getText());
|
||||
assertEquals("3", extensions[2].getText());
|
||||
}
|
||||
|
||||
public void testExtensionsWithOrderingUpdate() {
|
||||
ExtensionsAreaImpl extensionsArea = new ExtensionsAreaImpl(new DefaultPicoContainer(), new Extensions.SimpleLogProvider());
|
||||
extensionsArea.registerExtensionPoint("ep1", TestExtensionClassOne.class.getName());
|
||||
extensionsArea.registerExtension("", ExtensionComponentAdapterTest.readElement(
|
||||
"<extension point=\"ep1\" order=\"LAST\"><text>6</text></extension>"));
|
||||
extensionsArea.registerExtension("", ExtensionComponentAdapterTest.readElement(
|
||||
"<extension point=\"ep1\" order=\"FIRST\"><text>1</text></extension>"));
|
||||
extensionsArea.registerExtension("", ExtensionComponentAdapterTest.readElement(
|
||||
"<extension point=\"ep1\" id=\"id\"><text>3</text></extension>"));
|
||||
ExtensionPoint extensionPoint = extensionsArea.getExtensionPoint("ep1");
|
||||
TestExtensionClassOne[] extensions = (TestExtensionClassOne[]) extensionPoint.getExtensions();
|
||||
assertEquals(3, extensions.length);
|
||||
assertEquals("1", extensions[0].getText());
|
||||
assertEquals("3", extensions[1].getText());
|
||||
assertEquals("6", extensions[2].getText());
|
||||
TestExtensionClassOne extension = new TestExtensionClassOne("xxx");
|
||||
extensionPoint.registerExtension(extension);
|
||||
extensionPoint.unregisterExtension(extension);
|
||||
extensionsArea.registerExtension("", ExtensionComponentAdapterTest.readElement(
|
||||
"<extension point=\"ep1\" order=\"BEFORE:id\"><text>2</text></extension>"));
|
||||
extensionsArea.registerExtension("", ExtensionComponentAdapterTest.readElement(
|
||||
"<extension point=\"ep1\" order=\"AFTER:id\"><text>4</text></extension>"));
|
||||
extensionPoint.registerExtension(new TestExtensionClassOne("5"));
|
||||
extensions = (TestExtensionClassOne[]) extensionPoint.getExtensions();
|
||||
assertEquals(6, extensions.length);
|
||||
assertEquals("1", extensions[0].getText());
|
||||
assertEquals("2", extensions[1].getText());
|
||||
assertEquals("3", extensions[2].getText());
|
||||
assertEquals("4", extensions[3].getText());
|
||||
assertEquals("5", extensions[4].getText());
|
||||
assertEquals("6", extensions[5].getText());
|
||||
}
|
||||
|
||||
public interface MyInterface1 extends Runnable {
|
||||
}
|
||||
|
||||
public interface MyInterface2 {
|
||||
}
|
||||
|
||||
public interface MyInterface3 extends Runnable {
|
||||
}
|
||||
|
||||
public interface MyInterface4 extends MyInterface1, MyInterface2, MyInterface3 {
|
||||
}
|
||||
|
||||
public static class MyClass implements MyInterface4 {
|
||||
public void run() {
|
||||
}
|
||||
}
|
||||
|
||||
public static class MyComponent1 {
|
||||
public MyInterface1 testObject;
|
||||
|
||||
public MyComponent1(MyInterface1 testObject) {
|
||||
this.testObject = testObject;
|
||||
}
|
||||
}
|
||||
|
||||
public static class MyComponent2 {
|
||||
public MyInterface1 testObject;
|
||||
public MyComponent1[] comp1;
|
||||
|
||||
public MyComponent2(MyComponent1[] comp1, MyInterface1 testObject) {
|
||||
this.comp1 = comp1;
|
||||
this.testObject = testObject;
|
||||
}
|
||||
}
|
||||
|
||||
public static class MyTestComponent {
|
||||
public MyComponent1[] comp1;
|
||||
public MyComponent2 comp2;
|
||||
|
||||
public MyTestComponent(MyComponent1[] comp1, MyComponent2 comp2) {
|
||||
this.comp1 = comp1;
|
||||
this.comp2 = comp2;
|
||||
}
|
||||
}
|
||||
|
||||
public static class MyListener implements ExtensionPointAvailabilityListener {
|
||||
public static int regcount = 0;
|
||||
public static int remcount = 0;
|
||||
|
||||
public void extensionPointRegistered(ExtensionPoint extensionPoint) {
|
||||
regcount++;
|
||||
}
|
||||
|
||||
public void extensionPointRemoved(ExtensionPoint extensionPoint) {
|
||||
remcount++;
|
||||
}
|
||||
|
||||
public static void reset() {
|
||||
regcount = 0;
|
||||
remcount = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,158 @@
|
||||
/*
|
||||
* Copyright (c) 2000-2004 by JetBrains s.r.o. All Rights Reserved.
|
||||
* Use is subject to license terms.
|
||||
*/
|
||||
package com.intellij.openapi.extensions.impl;
|
||||
|
||||
import org.jmock.cglib.MockObjectTestCase;
|
||||
import org.jmock.cglib.Mock;
|
||||
import org.jmock.core.stub.ReturnStub;
|
||||
import org.jdom.Element;
|
||||
import org.picocontainer.PicoContainer;
|
||||
import org.picocontainer.defaults.AssignabilityRegistrationException;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import com.intellij.openapi.extensions.LoadingOrder;
|
||||
import com.intellij.openapi.extensions.SortingException;
|
||||
|
||||
/**
|
||||
* @author Alexander Kireyev
|
||||
*/
|
||||
public class LoadingOrderTest extends MockObjectTestCase {
|
||||
public void testSimpleSorting() {
|
||||
ArrayList target = new ArrayList();
|
||||
target.add(createElement(LoadingOrder.ANY, null, "any"));
|
||||
target.add(createElement(LoadingOrder.FIRST, null, "1"));
|
||||
target.add(createElement(LoadingOrder.LAST, null, "2"));
|
||||
target.add(createElement(LoadingOrder.ANY, null, "any"));
|
||||
LoadingOrder.Orderable[] array = (LoadingOrder.Orderable[]) target.toArray(new LoadingOrder.Orderable[target.size()]);
|
||||
assertSequence(array, "1anyany2");
|
||||
}
|
||||
|
||||
public void testComplexSorting() {
|
||||
ArrayList target = new ArrayList();
|
||||
String idOne = "idone";
|
||||
String idTwo = "idTwo";
|
||||
target.add(createElement(LoadingOrder.before(idTwo), idOne, "2"));
|
||||
target.add(createElement(LoadingOrder.FIRST, null, "0"));
|
||||
target.add(createElement(LoadingOrder.LAST, null, "5"));
|
||||
target.add(createElement(LoadingOrder.after(idTwo), null, "4"));
|
||||
target.add(createElement(LoadingOrder.ANY, idTwo, "3"));
|
||||
target.add(createElement(LoadingOrder.before(idOne), null, "1"));
|
||||
LoadingOrder.Orderable[] array = (LoadingOrder.Orderable[]) target.toArray(new LoadingOrder.Orderable[target.size()]);
|
||||
assertSequence(array, "012345");
|
||||
}
|
||||
|
||||
public void testComplexSorting2() {
|
||||
ArrayList target = new ArrayList();
|
||||
String idOne = "idone";
|
||||
target.add(createElement(LoadingOrder.before(idOne), null, "2"));
|
||||
target.add(createElement(LoadingOrder.after(idOne), null, "4"));
|
||||
target.add(createElement(LoadingOrder.FIRST, null, "1"));
|
||||
target.add(createElement(LoadingOrder.ANY, idOne, "3"));
|
||||
target.add(createElement(LoadingOrder.ANY, null, "5"));
|
||||
target.add(createElement(LoadingOrder.LAST, null, "6"));
|
||||
LoadingOrder.Orderable[] array = (LoadingOrder.Orderable[]) target.toArray(new LoadingOrder.Orderable[target.size()]);
|
||||
assertSequence(array, "123456");
|
||||
}
|
||||
|
||||
private void assertSequence(LoadingOrder.Orderable[] array, String expected) {
|
||||
LoadingOrder.sort(array);
|
||||
StringBuffer sequence = buildSequence(array);
|
||||
assertEquals(expected, sequence.toString());
|
||||
}
|
||||
|
||||
private StringBuffer buildSequence(LoadingOrder.Orderable[] array) {
|
||||
StringBuffer sequence = new StringBuffer();
|
||||
for (int i = 0; i < array.length; i++) {
|
||||
LoadingOrder.Orderable adapter = array[i];
|
||||
sequence.append(((MyElement)adapter.getDescribingElement()).getID());
|
||||
}
|
||||
return sequence;
|
||||
}
|
||||
|
||||
public void testFailingSortingBeforeFirst() {
|
||||
ArrayList target = new ArrayList();
|
||||
target.add(createElement(LoadingOrder.ANY, null, "good"));
|
||||
target.add(createElement(LoadingOrder.FIRST, "first", "bad"));
|
||||
target.add(createElement(LoadingOrder.LAST, null, "good"));
|
||||
target.add(createElement(LoadingOrder.before("first"), null, "bad"));
|
||||
LoadingOrder.Orderable[] array = (LoadingOrder.Orderable[]) target.toArray(new LoadingOrder.Orderable[target.size()]);
|
||||
checkSortingFailure(array, 2);
|
||||
}
|
||||
|
||||
public void testFailingSortingFirst() {
|
||||
ArrayList target = new ArrayList();
|
||||
target.add(createElement(LoadingOrder.ANY, null, "good"));
|
||||
target.add(createElement(LoadingOrder.FIRST, "first", "bad"));
|
||||
target.add(createElement(LoadingOrder.LAST, null, "good"));
|
||||
target.add(createElement(LoadingOrder.FIRST, null, "bad"));
|
||||
LoadingOrder.Orderable[] array = (LoadingOrder.Orderable[]) target.toArray(new LoadingOrder.Orderable[target.size()]);
|
||||
checkSortingFailure(array, 2);
|
||||
}
|
||||
|
||||
private void checkSortingFailure(LoadingOrder.Orderable[] array, int expectedCount) {
|
||||
try {
|
||||
LoadingOrder.sort(array);
|
||||
fail("Should have failed");
|
||||
}
|
||||
catch (SortingException e) {
|
||||
Element[] conflictingElements = e.getConflictingElements();
|
||||
assertEquals(expectedCount, conflictingElements.length);
|
||||
for (int i = 0; i < conflictingElements.length; i++) {
|
||||
MyElement conflictingElement = (MyElement) conflictingElements[i];
|
||||
assertEquals("bad", conflictingElement.getID());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void testFailingSortingAfterLast() {
|
||||
ArrayList target = new ArrayList();
|
||||
target.add(createElement(LoadingOrder.after("last"), null, "bad"));
|
||||
target.add(createElement(LoadingOrder.FIRST, null, "good"));
|
||||
target.add(createElement(LoadingOrder.LAST, "last", "bad"));
|
||||
target.add(createElement(LoadingOrder.ANY, null, "good"));
|
||||
LoadingOrder.Orderable[] array = (LoadingOrder.Orderable[]) target.toArray(new LoadingOrder.Orderable[target.size()]);
|
||||
checkSortingFailure(array, 2);
|
||||
}
|
||||
|
||||
public void testFailingSortingLast() {
|
||||
ArrayList target = new ArrayList();
|
||||
target.add(createElement(LoadingOrder.LAST, null, "bad"));
|
||||
target.add(createElement(LoadingOrder.FIRST, null, "good"));
|
||||
target.add(createElement(LoadingOrder.LAST, "last", "bad"));
|
||||
target.add(createElement(LoadingOrder.ANY, null, "good"));
|
||||
LoadingOrder.Orderable[] array = (LoadingOrder.Orderable[]) target.toArray(new LoadingOrder.Orderable[target.size()]);
|
||||
checkSortingFailure(array, 2);
|
||||
}
|
||||
|
||||
public void testFailingSortingComplex() {
|
||||
ArrayList target = new ArrayList();
|
||||
target.add(createElement(LoadingOrder.after("2"), "1", "bad"));
|
||||
target.add(createElement(LoadingOrder.after("3"), "2", "bad"));
|
||||
target.add(createElement(LoadingOrder.after("1"), "3", "bad"));
|
||||
LoadingOrder.Orderable[] array = (LoadingOrder.Orderable[]) target.toArray(new LoadingOrder.Orderable[target.size()]);
|
||||
checkSortingFailure(array, 3);
|
||||
}
|
||||
|
||||
private LoadingOrder.Orderable createElement(LoadingOrder order, String idString, String elementId) {
|
||||
Mock mock = new Mock(LoadingOrder.Orderable.class);
|
||||
mock.stubs().method("getOrder").withNoArguments().will(new ReturnStub(order));
|
||||
mock.stubs().method("getOrderId").withNoArguments().will(returnValue(idString));
|
||||
mock.stubs().method("getDescribingElement").withNoArguments().will(new ReturnStub(new MyElement(elementId)));
|
||||
return (LoadingOrder.Orderable) mock.proxy();
|
||||
}
|
||||
|
||||
private static class MyElement extends Element {
|
||||
private String myID;
|
||||
|
||||
public MyElement(String ID) {
|
||||
myID = ID;
|
||||
}
|
||||
|
||||
public String getID() {
|
||||
return myID;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright (c) 2000-2004 by JetBrains s.r.o. All Rights Reserved.
|
||||
* Use is subject to license terms.
|
||||
*/
|
||||
package com.intellij.openapi.extensions.impl;
|
||||
|
||||
/**
|
||||
* @author Alexander Kireyev
|
||||
*/
|
||||
public class TestExtensionClassOne {
|
||||
private String myText;
|
||||
|
||||
public TestExtensionClassOne() {
|
||||
}
|
||||
|
||||
public TestExtensionClassOne(String text) {
|
||||
myText = text;
|
||||
}
|
||||
|
||||
public String getText() {
|
||||
return myText;
|
||||
}
|
||||
|
||||
public void setText(String text) {
|
||||
myText = text;
|
||||
}
|
||||
}
|
||||
BIN
lib/dev/jmock-1.0.1.jar
Normal file
BIN
lib/dev/jmock-1.0.1.jar
Normal file
Binary file not shown.
BIN
lib/dev/jmock-cglib-1.0.1.jar
Normal file
BIN
lib/dev/jmock-cglib-1.0.1.jar
Normal file
Binary file not shown.
BIN
lib/xstream.jar
Normal file
BIN
lib/xstream.jar
Normal file
Binary file not shown.
Reference in New Issue
Block a user