PO Wrapper
From iDempiere en
- Author: - Red1 maintains this page.
- Name: - POWrapper in org.adempiere.model of iDempiere source
- Creator: - Teo Sarca, Romania (teo.sarca@gmail.com)
- Purpose: - To wrap any customised I_ class property to a core model without the X_ class.
- Importance: - Both core and plugin becomes integrated and yet grow without impacting each other.
- Movie Demo: - red1 YouTube
- My Advice: - Use this sparingly. Even though this removes your customization from core, it is best not to entangle core models at all in your design.
Introduction
- This technique was first taught to me by Hengsin but I made a minimalist snip below to demonstrate how it can be used in a more elegant way for any case.
- Plugin still inherit any core model dynamically and POWrapper integrates the new added properties conveniently.
- Nevertheless, I still recommend to use a tab add-on instead (as shown in many of my plugins) to avoid any performance due to locking a single tab model by multiple sources, AD window design conflict and scalability of model issues.
Preparation
- Firstly you have a new property or field lets say in model or table C_Order, which is Vehicle_ID to record trucks that transport your orders (this is part of the new WMS i am repairing as a pure plugin).
- So after creating this field in the AD, you generate model for the X_ and I_ classes.
Plugin Placing
- You place the I_C_Order class in your plugin
- You make a new MOrder extends org.compiere.model.MOrder
Wrapper Method
- Inside the plugin MOrder, you just put in this snippet:
public I_C_Order getWrapper(){ return POWrapper.create(this, I_C_Order.class); }
Calling Class
- In any other class such as an EventValidator, the new field is called for example in this test:
MOrder order = new MOrder(Env.getCtx(),0,null); order.getWrapper().setVehicle_ID(1000000); order.setDescription("POWrapper mumbo - "+order.getWrapper().getVehicle_ID());
Result
- SUCCESS! It works as shown here. The DB also has the new value in it.
Explanation
- Some may wonder what is POWrapper really doing. Two things:
- Allow new plugin Model remain as extension of core Model class.
- Wrap the new model separately in the plugin.
- What about the new X_Class? Well, that is made redundant as POWrapper has the efficiency of doing away with the middle X-man. You need not quote any X_class properties but goes straight to I_ properties. Well this is how Teo's code does it:
- First he uses an invocation handler:
- public Object invoke(Object proxy, Method method, Object[] args)
- In it validates the methods to be 'set' or 'get' or even 'is'.
- It sorts out its data-type, be it Integer, BigDecimal or another Object:
- Example: getReferencedObject("M_Product", method) should load the M_Product record
Note about entanglement
- POWrapper removes any cross entanglement as it inherits both original core model intact and the new plugin properties without overriding the similar core model.
- I still avoid POWrapper as only a stop gap measure in my present Slovakian WMS migration as i wish to loosen further the core coupling via an add-on separate model referencing the parent model approach via a Foreign Key lookup solely.
- This allows more scalability of AD window design, avoiding table overload from multiple code sources and more easier atomic handling of separate table models particularly in case of DB restore over same tables (for example you can drop C_OrderWMS without dropping C_Order giving more agility in database recovery).
- I have examples in my plugins such as Plugin:_Alt_OrderLine where no POWrapper is used and not a single inch of the core data is written to but at most looked up.