iDempiere is built on a sophisticated OSGi (Open Services Gateway initiative) framework that enables true modularity, extensibility, and runtime dynamics. The architecture follows enterprise patterns designed for scalability and maintainability.
package org.adempiere.base;import org.adempiere.base.ds.DynamicServiceLocator;/** * Factory for service locators providing access to OSGi services */public class Service { private static IServiceLocator theLocator = new DynamicServiceLocator(); /** * @return IServiceLocator instance for service discovery */ public static IServiceLocator locator() { return theLocator; }}
// Query for all implementations of a service interfaceList<IModelFactory> factories = Service.locator() .list(IModelFactory.class) .getServices();// Get a specific serviceITaxProvider taxProvider = Service.locator() .locate(ITaxProvider.class) .getService();
The service locator pattern enables loose coupling between bundles and supports runtime service registration/unregistration.
public interface IEventTopics { // Persistent Object Events public static final String MODEL_EVENT_PREFIX = "adempiere/po/"; public static final String PO_BEFORE_NEW = MODEL_EVENT_PREFIX + "beforeNew"; public static final String PO_AFTER_NEW = MODEL_EVENT_PREFIX + "afterNew"; public static final String PO_BEFORE_CHANGE = MODEL_EVENT_PREFIX + "beforeChange"; public static final String PO_AFTER_CHANGE = MODEL_EVENT_PREFIX + "afterChange"; public static final String PO_BEFORE_DELETE = MODEL_EVENT_PREFIX + "beforeDelete"; public static final String PO_AFTER_DELETE = MODEL_EVENT_PREFIX + "afterDelete"; // Document Events public static final String DOC_EVENT_PREFIX = "adempiere/doc/"; public static final String DOC_BEFORE_COMPLETE = DOC_EVENT_PREFIX + "beforeComplete"; public static final String DOC_AFTER_COMPLETE = DOC_EVENT_PREFIX + "afterComplete"; public static final String DOC_BEFORE_POST = DOC_EVENT_PREFIX + "beforePost"; public static final String DOC_AFTER_POST = DOC_EVENT_PREFIX + "afterPost"; // System Events public static final String AFTER_LOGIN = "adempiere/afterLogin"; public static final String ACCT_FACTS_VALIDATE = "adempiere/acct/factsValidate";}
import org.adempiere.base.event.EventManager;import org.osgi.service.event.Event;// Publish an event when a model changesProperties ctx = Env.getCtx();Event event = EventManager.newEvent( IEventTopics.PO_AFTER_CHANGE, new EventProperty("tableName", "C_Order"), new EventProperty("record", order));EventManager.getInstance().sendEvent(event);
package org.adempiere.base;import org.compiere.model.PO;import java.sql.ResultSet;/** * Model factory interface for dynamic PO instantiation */public interface IModelFactory { /** * Get Persistence Class for Table * @param tableName table name * @return class or null */ public Class<?> getClass(String tableName); /** * Get PO Class Instance by ID * @param tableName table name * @param Record_ID record ID * @param trxName transaction name * @return PO for Record or null */ public PO getPO(String tableName, int Record_ID, String trxName); /** * Get PO Class Instance by UUID * @param tableName table name * @param Record_UU record UUID * @param trxName transaction name * @return PO for Record or null */ public PO getPO(String tableName, String Record_UU, String trxName); /** * Get PO Class Instance from ResultSet * @param tableName table name * @param rs result set * @param trxName transaction * @return PO for Record or null */ public PO getPO(String tableName, ResultSet rs, String trxName);}
public class CustomModelFactory implements IModelFactory { @Override public Class<?> getClass(String tableName) { if ("XX_CustomTable".equals(tableName)) { return MCustomTable.class; } return null; } @Override public PO getPO(String tableName, int Record_ID, String trxName) { if ("XX_CustomTable".equals(tableName)) { return new MCustomTable(Env.getCtx(), Record_ID, trxName); } return null; } // Implement other methods...}