/****************************************************************************** * 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 interface.
* Example usage: *
 * 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 { /** * Create wrapper of type cl for po * @param iDempiere model interface type * @param po * @param cl iDempiere model interface class * @return wrapped instance */ @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)); } /** * Get wrapped PO instance * @param * @param model * @return the wrapped PO */ @SuppressWarnings("unchecked") public static T getPO(Object model) { POWrapper wrapper = (POWrapper)Proxy.getInvocationHandler(model); return (T)wrapper.getPO(); } private static final CLogger log = CLogger.getCLogger(POWrapper.class); private final PO po; /** * Private constructor. Use the static create method to create a new instance of POWrapper. * @param po */ private POWrapper(PO po) { super(); this.po = po; } @Override 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); } } /** * @return wrapped PO instance */ 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; } /** * @param cl * @return true if cl is a model interface (for e.g I_C_Order) type */ private boolean isModelInterface(Class cl) { try { String tableName = (String)cl.getField("Table_Name").get(null); return tableName != null; } catch (Exception e) { return false; } } }