From e18ee7d5b66c8cc6964b3e951f82ad04b4f308bc Mon Sep 17 00:00:00 2001 From: teo_sarca Date: Tue, 4 May 2010 14:59:42 +0000 Subject: [PATCH] FR [ 2996361 ] Add POWrapper class Link to SF Tracker: http://sourceforge.net/support/tracker.php?aid=2996361 --- base/src/org/adempiere/model/POWrapper.java | 195 ++++++++++++++++++++ 1 file changed, 195 insertions(+) create mode 100644 base/src/org/adempiere/model/POWrapper.java diff --git a/base/src/org/adempiere/model/POWrapper.java b/base/src/org/adempiere/model/POWrapper.java new file mode 100644 index 0000000000..6adf556ef8 --- /dev/null +++ b/base/src/org/adempiere/model/POWrapper.java @@ -0,0 +1,195 @@ +/****************************************************************************** + * Product: Adempiere ERP & CRM Smart Business Solution * + * Copyright (C) 2010 Teo Sarca, teo.sarca@gmail.com * + * 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. * + *****************************************************************************/ +package org.adempiere.model; + +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Method; +import java.lang.reflect.Proxy; +import java.math.BigDecimal; +import java.util.logging.Level; + +import org.adempiere.exceptions.AdempiereException; +import org.compiere.model.MTable; +import org.compiere.model.PO; +import org.compiere.util.CLogger; + +/** + * Wrap a PO object to a given bean interface. + * Example + *
+ * public interface I_C_Invoice_Customized
+ * {
+ *	public int getCustomValue1();
+ *	public void setCustomValue1(int customValue1);
+ *	public String getCustomString1();
+ *	public void setCustomString1(String customString1);
+ * }
+ * ....
+ * MInvoice invoice = ......;
+ * I_C_Invoice_Customized invoiceCustomized = POWrapper.create(invoice, I_C_Invoice_Customized.class);
+ * invoiceCustomized.setCustomValue1(12345);
+ * invoiceCustomized.setCustomString1("my test string");
+ * invoice.saveEx();
+ * 
+ * @author Teo Sarca, teo.sarca@gmail.com + */ +public class POWrapper implements InvocationHandler +{ + @SuppressWarnings("unchecked") + public static T create(Object po, Class cl) + { + if (!(po instanceof PO)) + { + throw new AdempiereException("Not a PO object - "+po); + } + if (cl.isInstance(po)) + { + return (T)po; + } + return (T)Proxy.newProxyInstance(cl.getClassLoader(), new Class[]{cl}, new POWrapper((PO)po)); + } + + @SuppressWarnings("unchecked") + public static T getPO(Object model) + { + POWrapper wrapper = (POWrapper)Proxy.getInvocationHandler(model); + return (T)wrapper.getPO(); + } + + private final CLogger log = CLogger.getCLogger(getClass()); + private final PO po; + + private POWrapper(PO po) + { + super(); + this.po = po; + } + + public Object invoke(Object proxy, Method method, Object[] args) throws Throwable + { + String methodName = method.getName(); + if (methodName.startsWith("set") && args.length == 1) + { + String propertyName = methodName.substring(3); + po.set_ValueOfColumn(propertyName, args[0]); + return null; + } + else if (methodName.startsWith("get") && (args == null || args.length == 0)) + { + String propertyName = methodName.substring(3); + Object value = null; + final int idx = po.get_ColumnIndex(propertyName); + if (idx >= 0) + value = po.get_Value(propertyName); + if (value != null) + { + return value; + } + // + if (method.getReturnType() == int.class) + { + value = Integer.valueOf(0); + } + else if (method.getReturnType() == BigDecimal.class) + { + value = BigDecimal.ZERO; + } + else if (isModelInterface(method.getReturnType())) + { + value = getReferencedObject(propertyName, method); + } + else if (PO.class.isAssignableFrom(method.getReturnType())) + { + throw new IllegalArgumentException("Method not supported - "+methodName); + } + return value; + } + else if (methodName.startsWith("is") && (args == null || args.length == 0)) + { + String propertyName = methodName.substring(2); + int ii = po.get_ColumnIndex(propertyName); + if (ii >= 0) + { + return po.get_Value(ii); + } + ii = po.get_ColumnIndex("Is"+propertyName); + if (ii >= 0) + { + return po.get_Value(ii); + } + // + throw new IllegalArgumentException("Method not supported - "+methodName); + } + else + { + return method.invoke(po, args); + } + } + + public PO getPO() + { + return po; + } + + /** + * Load object that is referenced by given property. + * Example: getReferencedObject("M_Product", method) should load the M_Product record + * with ID given by M_Product_ID property name; + * @param propertyName + * @param method + * @return + */ + private final Object getReferencedObject(String propertyName, Method method) + { + int i = po.get_ColumnIndex(propertyName+"_ID"); + if (i < 0) + return null; + + // Fetch Record_ID + final Integer record_id = po.get_ValueAsInt(i); + if (record_id == null || record_id <= 0) + return null; + + + // Fetch TableName from returning class + Class cl = method.getReturnType(); + String tableName; + try + { + tableName = (String)cl.getField("Table_Name").get(null); + } + catch (Exception e) + { + log.log(Level.SEVERE, e.getLocalizedMessage(), e); + return null; + } + + // Load Persistent Object + PO child = MTable.get(po.getCtx(), tableName).getPO(record_id, po.get_TrxName()); + return child; + } + + private boolean isModelInterface(Class cl) + { + try + { + String tableName = (String)cl.getField("Table_Name").get(null); + return tableName != null; + } + catch (Exception e) + { + return false; + } + } +}