diff --git a/base/plugin.xml b/base/plugin.xml
index cb6b8fe432..a02eda5e25 100644
--- a/base/plugin.xml
+++ b/base/plugin.xml
@@ -1,6 +1,7 @@
-
+
+
diff --git a/base/schema/org.adempiere.base.Callout.exsd b/base/schema/org.adempiere.base.Callout.exsd
new file mode 100644
index 0000000000..a4657b6ea9
--- /dev/null
+++ b/base/schema/org.adempiere.base.Callout.exsd
@@ -0,0 +1,119 @@
+
+
+
+
+
+
+
+
+ This is the ADempiere Call extension point.
+
+Callouts provided by plugins are not entered into the application dictionary.
+Instead, you specify Table and Column in the extension declaration.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ [Enter the first release in which this extension point appears.]
+
+
+
+
+
+
+
+
+ [Enter extension point usage example here.]
+
+
+
+
+
+
+
+
+ [Enter API information here.]
+
+
+
+
+
+
+
+
+ [Enter information about supplied implementation of this extension point.]
+
+
+
+
+
diff --git a/base/src/org/adempiere/base/Core.java b/base/src/org/adempiere/base/Core.java
new file mode 100644
index 0000000000..df6ce32268
--- /dev/null
+++ b/base/src/org/adempiere/base/Core.java
@@ -0,0 +1,41 @@
+package org.adempiere.base;
+
+import java.net.URL;
+import java.util.List;
+
+import org.adempiere.base.equinox.ExtensionList;
+import org.compiere.model.Callout;
+
+/**
+ * This is a facade class for the Service Locator.
+ * It provides simple access to all core services.
+ *
+ * @author viola
+ */
+public class Core {
+
+ public static IResourceFinder getResourceFinder() {
+ return new IResourceFinder() {
+
+ public URL getResource(String name) {
+ List f = Service.list(IResourceFinder.class);
+ for (IResourceFinder finder : f) {
+ URL url = finder.getResource(name);
+ if (url!=null)
+ return url;
+ }
+ return null;
+ }
+ };
+ }
+
+ public static Callout getCallout(String tableName, String columnName) {
+ ServiceQuery query = new ServiceQuery();
+ query.put("tableName", tableName);
+ query.put("columnName", columnName);
+
+ return Service.locate(Callout.class, query);
+ }
+
+
+}
diff --git a/base/src/org/adempiere/base/IResourceFinder.java b/base/src/org/adempiere/base/IResourceFinder.java
index a99ea7b76b..12d751d355 100644
--- a/base/src/org/adempiere/base/IResourceFinder.java
+++ b/base/src/org/adempiere/base/IResourceFinder.java
@@ -18,7 +18,7 @@ package org.adempiere.base;
import java.net.URL;
-public interface IResourceFinder {
+public interface IResourceFinder extends IService {
URL getResource(String name);
diff --git a/base/src/org/adempiere/base/IService.java b/base/src/org/adempiere/base/IService.java
new file mode 100644
index 0000000000..5745fce41f
--- /dev/null
+++ b/base/src/org/adempiere/base/IService.java
@@ -0,0 +1,5 @@
+package org.adempiere.base;
+
+public interface IService {
+
+}
diff --git a/base/src/org/adempiere/base/IServiceLocator.java b/base/src/org/adempiere/base/IServiceLocator.java
index 7b127bfd4d..3d75392dd1 100644
--- a/base/src/org/adempiere/base/IServiceLocator.java
+++ b/base/src/org/adempiere/base/IServiceLocator.java
@@ -16,16 +16,24 @@
*****************************************************************************/
package org.adempiere.base;
+import java.util.List;
+
+import org.compiere.model.Callout;
+
/**
* A service locator looks up services.
* This is the central authority for adempiere service definition,
* because each service defined has to be looked up via this interface.
+ *
+ * A service in adempiere is an interface extended from the tagging interface IService.
+ *
* @author viola
*
*/
public interface IServiceLocator {
-
- IResourceFinder getResourceFinder();
-
+ T locate(Class type);
+ T locate(Class type, ServiceQuery query);
+ List list(Class type);
+ List list(Class type, ServiceQuery query);
}
diff --git a/base/src/org/adempiere/base/Service.java b/base/src/org/adempiere/base/Service.java
index 4ab5206ec8..bc397e5c24 100644
--- a/base/src/org/adempiere/base/Service.java
+++ b/base/src/org/adempiere/base/Service.java
@@ -16,26 +16,46 @@
*****************************************************************************/
package org.adempiere.base;
+import java.util.List;
+
import org.adempiere.base.equinox.EquinoxServiceLocator;
/**
* This is a very simple factory for service locators
+ *
* @author viola
- *
+ *
*/
public class Service {
private static IServiceLocator theLocator;
public static IServiceLocator locator() {
- if (theLocator==null) {
+ if (theLocator == null) {
synchronized (Service.class) {
- if (theLocator==null) {
+ if (theLocator == null) {
theLocator = new EquinoxServiceLocator();
+ System.out
+ .println("Started service locator: " + theLocator);
}
}
}
return theLocator;
}
+ public static T locate(Class type) {
+ return locator().locate(type);
+ }
+
+ public static T locate(Class type, ServiceQuery query) {
+ return locator().locate(type, query);
+ }
+
+ public static List list(Class type) {
+ return locator().list(type);
+ }
+
+ public static List list(Class type, ServiceQuery query) {
+ return locator().list(type, query);
+ }
}
diff --git a/base/src/org/adempiere/base/ServiceQuery.java b/base/src/org/adempiere/base/ServiceQuery.java
new file mode 100644
index 0000000000..3cb1f42a6e
--- /dev/null
+++ b/base/src/org/adempiere/base/ServiceQuery.java
@@ -0,0 +1,9 @@
+package org.adempiere.base;
+
+import java.util.HashMap;
+
+public class ServiceQuery extends HashMap {
+
+ private static final long serialVersionUID = -3624488575106821781L;
+
+}
diff --git a/base/src/org/adempiere/base/equinox/EquinoxResourceFinder.java b/base/src/org/adempiere/base/equinox/EquinoxResourceFinder.java
deleted file mode 100644
index b720e95006..0000000000
--- a/base/src/org/adempiere/base/equinox/EquinoxResourceFinder.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/******************************************************************************
- * Product: Adempiere ERP & CRM Smart Business Solution *
- * Copyright (C) 1999-2006 ComPiere, Inc. All Rights Reserved. *
- * This program is free software; you can redistribute it and/or modify it *
- * under the terms version 2 of the GNU General Public License as published *
- * by the Free Software Foundation. This program is distributed in the hope *
- * that it will be useful, but WITHOUT ANY WARRANTY; without even the implied *
- * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *
- * See the GNU General Public License for more details. *
- * You should have received a copy of the GNU General Public License along *
- * with this program; if not, write to the Free Software Foundation, Inc., *
- * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. *
- * For the text or an alternative of this public license, you may reach us *
- * ComPiere, Inc., 2620 Augustine Dr. #245, Santa Clara, CA 95054, USA *
- * or via info@compiere.org or http://www.compiere.org/license.html *
- *****************************************************************************/
-package org.adempiere.base.equinox;
-
-import java.net.URL;
-
-import org.adempiere.base.IResourceFinder;
-
-public class EquinoxResourceFinder implements IResourceFinder {
-
- public URL getResource(String name) {
- ExtensionList list = new ExtensionList(IResourceFinder.class, "org.adempiere.base.ResourceFinder");
- for (IResourceFinder rf : list) {
- URL url = rf.getResource(name);
- if (url!=null)
- return url;
- }
- return null;
- }
-
-}
\ No newline at end of file
diff --git a/base/src/org/adempiere/base/equinox/EquinoxServiceLocator.java b/base/src/org/adempiere/base/equinox/EquinoxServiceLocator.java
index 907ef8e7ed..fe13648039 100644
--- a/base/src/org/adempiere/base/equinox/EquinoxServiceLocator.java
+++ b/base/src/org/adempiere/base/equinox/EquinoxServiceLocator.java
@@ -16,14 +16,41 @@
*****************************************************************************/
package org.adempiere.base.equinox;
-import org.adempiere.base.IResourceFinder;
+import java.util.List;
+
+import org.adempiere.base.IService;
import org.adempiere.base.IServiceLocator;
+import org.adempiere.base.ServiceQuery;
+/**
+ * This is the Equinox implementation of the ADempiere Service Locator.
+ * It delegates work to the ExtensionList that lookups up services as extensions.
+ * The ids of extension points have to correspond to the interface names of the services.
+ *
+ * @author viola
+ *
+ */
public class EquinoxServiceLocator implements IServiceLocator {
- public IResourceFinder getResourceFinder() {
- return new EquinoxResourceFinder();
+ public List list(Class type) {
+ ExtensionList list = new ExtensionList(type, type.getName());
+ return list.asList();
+ }
+
+ public List list(Class type, ServiceQuery query) {
+ ExtensionList list = new ExtensionList(type, type.getName(), query);
+ return list.asList();
+ }
+
+ public T locate(Class type) {
+ ExtensionList list = new ExtensionList(type, type.getName());
+ return list.first();
+ }
+
+ public T locate(Class type, ServiceQuery query) {
+ ExtensionList list = new ExtensionList(type, type.getName(), query);
+ return list.first();
}
}
diff --git a/base/src/org/adempiere/base/equinox/ExtensionList.java b/base/src/org/adempiere/base/equinox/ExtensionList.java
index 760a36e4f8..02a2bebc7e 100644
--- a/base/src/org/adempiere/base/equinox/ExtensionList.java
+++ b/base/src/org/adempiere/base/equinox/ExtensionList.java
@@ -16,12 +16,28 @@
*****************************************************************************/
package org.adempiere.base.equinox;
+import java.util.ArrayList;
+import java.util.HashMap;
import java.util.Iterator;
+import java.util.List;
+import org.adempiere.base.ServiceQuery;
+import org.compiere.model.Callout;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IConfigurationElement;
import org.eclipse.core.runtime.Platform;
+/**
+ * This List looks up services as extensions in equinox.
+ * The extension point must be the class name of the service interface.
+ * The query attributes are checked against the attributes
+ * of the extension configuration element.
+ *
+ * In order to minimize equinox lookups, a filtering iterator is used.
+ * @author viola
+ *
+ * @param The service this list holds implementations of.
+ */
public class ExtensionList implements Iterable{
public class ExtensionIterator implements Iterator {
@@ -29,11 +45,31 @@ public class ExtensionList implements Iterable{
private int index = 0;
public boolean hasNext() {
+ iterateUntilAccepted();
return index implements Iterable{
}
private IConfigurationElement[] elements;
+ private HashMap filters = new HashMap();
public ExtensionList(Class clazz, String id) {
try {
@@ -58,8 +95,34 @@ public class ExtensionList implements Iterable{
}
}
+ public ExtensionList(Class type, String name, ServiceQuery query) {
+ this(type, name);
+ for (String key : query.keySet()) {
+ addFilter(key, query.get(key));
+ }
+ }
+
public Iterator iterator() {
return new ExtensionIterator();
}
+ public void addFilter(String name, String value) {
+ filters.put(name, value);
+ }
+
+ public T first() {
+ Iterator i = iterator();
+ if (!i.hasNext())
+ return null;
+ return i.next();
+ }
+
+ public List asList() {
+ List result = new ArrayList();
+ for (T t : this) {
+ result.add(t);
+ }
+ return result;
+ }
+
}
diff --git a/base/src/org/compiere/Adempiere.java b/base/src/org/compiere/Adempiere.java
index a306fef357..787ee1fc30 100644
--- a/base/src/org/compiere/Adempiere.java
+++ b/base/src/org/compiere/Adempiere.java
@@ -22,6 +22,7 @@ import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
+import java.util.List;
import java.util.Properties;
import java.util.logging.Level;
@@ -30,6 +31,8 @@ import javax.jnlp.ServiceManager;
import javax.jnlp.UnavailableServiceException;
import javax.swing.ImageIcon;
+import org.adempiere.base.Core;
+import org.adempiere.base.IResourceFinder;
import org.adempiere.base.Service;
import org.compiere.db.CConnection;
import org.compiere.model.MClient;
@@ -337,7 +340,7 @@ public final class Adempiere
if (s_imageLogo == null)
{
Toolkit tk = Toolkit.getDefaultToolkit();
- URL url = Service.locator().getResourceFinder().getResource(s_file100x30);
+ URL url = Core.getResourceFinder().getResource(s_file100x30);
// URL url = org.compiere.Adempiere.class.getResource(s_file100x30);
// System.out.println(url);
if (url == null)
@@ -583,7 +586,7 @@ public final class Adempiere
} // startupEnvironment
public static URL getResource(String name) {
- return Service.locator().getResourceFinder().getResource(name);
+ return Core.getResourceFinder().getResource(name);
}
diff --git a/base/src/org/compiere/model/Callout.java b/base/src/org/compiere/model/Callout.java
index 59501e7024..1709ed74df 100644
--- a/base/src/org/compiere/model/Callout.java
+++ b/base/src/org/compiere/model/Callout.java
@@ -18,6 +18,8 @@ package org.compiere.model;
import java.util.Properties;
+import org.adempiere.base.IService;
+
/**
* Callout Interface for Callout.
* Used in MTab and ImpFormatRow
@@ -25,7 +27,7 @@ import java.util.Properties;
* @author Jorg Janke
* @version $Id: Callout.java,v 1.2 2006/07/30 00:51:05 jjanke Exp $
*/
-public interface Callout
+public interface Callout extends IService
{
/**
* Start Callout.
diff --git a/base/src/org/compiere/model/GridTab.java b/base/src/org/compiere/model/GridTab.java
index bfda81e985..041ede129a 100644
--- a/base/src/org/compiere/model/GridTab.java
+++ b/base/src/org/compiere/model/GridTab.java
@@ -37,6 +37,8 @@ import java.util.logging.Level;
import javax.script.ScriptEngine;
import javax.swing.event.EventListenerList;
+import org.adempiere.base.Core;
+import org.adempiere.base.Service;
import org.compiere.util.CLogMgt;
import org.compiere.util.CLogger;
import org.compiere.util.DB;
@@ -2682,6 +2684,13 @@ public class GridTab implements DataStatusListener, Evaluatee, Serializable
*/
public String processCallout (GridField field)
{
+ Object value = field.getValue();
+ Object oldValue = field.getOldValue();
+ Callout co = Core.getCallout(getTableName(), field.getColumnName());
+ if (co!=null) {
+ return co.start(m_vo.ctx, "", m_vo.WindowNo, this, field, value, oldValue);
+ }
+
String callout = field.getCallout();
if (callout.length() == 0)
return "";
@@ -2689,8 +2698,6 @@ public class GridTab implements DataStatusListener, Evaluatee, Serializable
if (isProcessed() && !field.isAlwaysUpdateable()) // only active records
return ""; // "DocProcessed";
- Object value = field.getValue();
- Object oldValue = field.getOldValue();
log.fine(field.getColumnName() + "=" + value
+ " (" + callout + ") - old=" + oldValue);
diff --git a/base/src/org/compiere/util/Env.java b/base/src/org/compiere/util/Env.java
index 076e681113..aa25b4e9ea 100644
--- a/base/src/org/compiere/util/Env.java
+++ b/base/src/org/compiere/util/Env.java
@@ -46,6 +46,7 @@ import javax.swing.JFrame;
import javax.swing.RepaintManager;
import javax.swing.SwingUtilities;
+import org.adempiere.base.Core;
import org.adempiere.base.IResourceFinder;
import org.adempiere.base.Service;
import org.compiere.Adempiere;
@@ -1485,7 +1486,7 @@ public final class Env
*/
public static Image getImage (String fileNameInImageDir)
{
- IResourceFinder rf = Service.locator().getResourceFinder();
+ IResourceFinder rf = Core.getResourceFinder();
URL url = rf.getResource("images/" + fileNameInImageDir);
// URL url = Adempiere.class.getResource("images/" + fileNameInImageDir);
@@ -1506,7 +1507,7 @@ public final class Env
*/
public static ImageIcon getImageIcon (String fileNameInImageDir)
{
- IResourceFinder rf = Service.locator().getResourceFinder();
+ IResourceFinder rf = Core.getResourceFinder();
URL url = rf.getResource("images/" + fileNameInImageDir);
// URL url = Adempiere.class.getResource("images/" + fileNameInImageDir);
if (url == null)
@@ -1528,7 +1529,7 @@ public final class Env
*/
public static ImageIcon getImageIcon2 (String fileName)
{
- IResourceFinder rf = Service.locator().getResourceFinder();
+ IResourceFinder rf = Core.getResourceFinder();
URL url = rf.getResource("images/" + fileName+".gif");
// URL url = Adempiere.class.getResource("images/" + fileName+".gif");
if (url == null)
diff --git a/client/plugin.xml b/client/plugin.xml
index 41786b2054..071f08d40f 100644
--- a/client/plugin.xml
+++ b/client/plugin.xml
@@ -4,7 +4,7 @@
+ point="org.adempiere.base.IResourceFinder">