diff --git a/base/src/org/compiere/model/CalloutEngine.java b/base/src/org/compiere/model/CalloutEngine.java index 83bc9df5ac..761370ff43 100644 --- a/base/src/org/compiere/model/CalloutEngine.java +++ b/base/src/org/compiere/model/CalloutEngine.java @@ -1,5 +1,5 @@ /****************************************************************************** - * Product: Adempiere ERP & CRM Smart Business Solution * + * 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 * @@ -24,7 +24,7 @@ import java.util.logging.*; import org.compiere.util.*; /** - * Callout Emgine. + * Callout Engine. * * @author Jorg Janke * @version $Id: CalloutEngine.java,v 1.3 2006/07/30 00:51:05 jjanke Exp $ diff --git a/base/src/org/compiere/model/CalloutProductCategory.java b/base/src/org/compiere/model/CalloutProductCategory.java index ca5530c3ee..1a54bbebbd 100644 --- a/base/src/org/compiere/model/CalloutProductCategory.java +++ b/base/src/org/compiere/model/CalloutProductCategory.java @@ -1,5 +1,5 @@ /****************************************************************************** - * Product: Adempiere ERP & CRM Smart Business Solution * + * 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 * @@ -16,17 +16,7 @@ *****************************************************************************/ package org.compiere.model; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.sql.Statement; -import java.util.Iterator; import java.util.Properties; -import java.util.Vector; -import java.util.logging.Level; - -import org.compiere.util.DB; -import org.compiere.util.Env; - /** * Product Category Callouts @@ -51,97 +41,18 @@ public class CalloutProductCategory extends CalloutEngine if (isCalloutActive() || value == null) return ""; - // get values - Integer newParentCategoryId = (Integer) mTab.getValue(MProductCategory.COLUMNNAME_M_Product_Category_Parent_ID); Integer productCategoryId = (Integer) mTab.getValue(MProductCategory.COLUMNNAME_M_Product_Category_ID); if (productCategoryId == null) productCategoryId = new Integer(0); - ResultSet rs = null; - Statement stmt = null; - String sql = " SELECT M_Product_Category_ID, M_Product_Category_Parent_ID FROM M_Product_Category"; - final Vector categories = new Vector(100); - try { - stmt = DB.createStatement(); - rs = stmt.executeQuery(sql); - while (rs.next()) { - if(rs.getInt(1)==productCategoryId.intValue()) { - categories.add(new SimpleTreeNode(rs.getInt(1), newParentCategoryId)); - } - categories.add(new SimpleTreeNode(rs.getInt(1), rs.getInt(2))); - } - if (hasLoop(newParentCategoryId, categories, productCategoryId.intValue())) { - mTab.setValue(MProductCategory.COLUMNNAME_M_Product_Category_Parent_ID, oldValue); + + if (productCategoryId.intValue() > 0) { + MProductCategory pc = new MProductCategory(ctx, productCategoryId.intValue(), null); + pc.setM_Product_Category_Parent_ID(((Integer) value).intValue()); + if (pc.hasLoopInTree()) return "ProductCategoryLoopDetected"; - } - } catch (SQLException e) { - log.log(Level.SEVERE, sql, e); - return e.getMessage(); - } - finally - { - DB.close(rs, stmt); - rs = null; stmt = null; } + return ""; } // testForLoop - - /** - * Recursive search for parent nodes - climbes the to the root. - * If there is a circle there is no root but it comes back to the start node. - * @param parentCategoryId - * @param categories - * @param loopIndicatorId - * @return - */ - private boolean hasLoop(int parentCategoryId, Vector categories, int loopIndicatorId) { - final Iterator iter = categories.iterator(); - boolean ret = false; - while (iter.hasNext()) { - SimpleTreeNode node = (SimpleTreeNode) iter.next(); - if(node.getNodeId()==parentCategoryId){ - if (node.getParentId()==0) { - //root node, all fine - return false; - } - if(node.getNodeId()==loopIndicatorId){ - //loop found - return true; - } - ret = hasLoop(node.getParentId(), categories, loopIndicatorId); - } - } - return ret; - } //hasLoop - - /** - * Simple class for tree nodes. - * @author Karsten Thiemann, kthiemann@adempiere.org - * - */ - private class SimpleTreeNode { - /** id of the node */ - private int nodeId; - /** id of the nodes parent */ - private int parentId; - - /** - * Constructor. - * @param nodeId - * @param parentId - */ - public SimpleTreeNode(int nodeId, int parentId) { - this.nodeId = nodeId; - this.parentId = parentId; - } - - public int getNodeId() { - return nodeId; - } - - public int getParentId() { - return parentId; - } - } - -} // CalloutProductCategory +} // CalloutProductCategory \ No newline at end of file diff --git a/base/src/org/compiere/model/MProductCategory.java b/base/src/org/compiere/model/MProductCategory.java index 1cc69c5212..9cf70e9b13 100644 --- a/base/src/org/compiere/model/MProductCategory.java +++ b/base/src/org/compiere/model/MProductCategory.java @@ -1,5 +1,5 @@ /****************************************************************************** - * Product: Adempiere ERP & CRM Smart Business Solution * + * 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 * @@ -19,6 +19,7 @@ package org.compiere.model; import java.sql.*; import java.util.*; import java.util.logging.*; + import org.compiere.util.*; /** @@ -29,6 +30,12 @@ import org.compiere.util.*; */ public class MProductCategory extends X_M_Product_Category { + /** + * + */ + private static final long serialVersionUID = -1290361229726779892L; + + /** * Get from Cache * @param ctx context @@ -140,6 +147,21 @@ public class MProductCategory extends X_M_Product_Category super(ctx, rs, trxName); } // MProductCategory + /** + * Before Save + * @param newRecord new + * @return true + */ + protected boolean beforeSave (boolean newRecord) + { + if (hasLoopInTree()) { + log.saveError("Error", Msg.getMsg(getCtx(), "ProductCategoryLoopDetected")); + return false; + } + + return true; + } // beforeSave + /** * After Save * @param newRecord new @@ -172,4 +194,103 @@ public class MProductCategory extends X_M_Product_Category return MMPOLICY_FiFo.equals(getMMPolicy()); } // isFiFo -} // MProductCategory + + /** + * Loop detection of product category tree. + * @param productCategoryId + * @param newParentCategoryId + * + * @param newParentCategoryId New Parent Category + * @return "" or error message + */ + public boolean hasLoopInTree () + { + int productCategoryId = getM_Product_Category_ID(); + int newParentCategoryId = getM_Product_Category_Parent_ID(); + // get values + ResultSet rs = null; + PreparedStatement pstmt = null; + String sql = " SELECT M_Product_Category_ID, M_Product_Category_Parent_ID FROM M_Product_Category"; + final Vector categories = new Vector(100); + try { + pstmt = DB.prepareStatement(sql, null); + rs = pstmt.executeQuery(); + while (rs.next()) { + if (rs.getInt(1) == productCategoryId) + categories.add(new SimpleTreeNode(rs.getInt(1), newParentCategoryId)); + categories.add(new SimpleTreeNode(rs.getInt(1), rs.getInt(2))); + } + if (hasLoop(newParentCategoryId, categories, productCategoryId)) + return true; + } catch (SQLException e) { + s_log.log(Level.SEVERE, sql, e); + return true; + } + finally + { + DB.close(rs, pstmt); + rs = null; pstmt = null; + } + return false; + } // hasLoopInTree + + + /** + * Recursive search for parent nodes - climbs the to the root. + * If there is a circle there is no root but it comes back to the start node. + * @param parentCategoryId + * @param categories + * @param loopIndicatorId + * @return + */ + private boolean hasLoop(int parentCategoryId, Vector categories, int loopIndicatorId) { + final Iterator iter = categories.iterator(); + boolean ret = false; + while (iter.hasNext()) { + SimpleTreeNode node = (SimpleTreeNode) iter.next(); + if(node.getNodeId()==parentCategoryId){ + if (node.getParentId()==0) { + //root node, all fine + return false; + } + if(node.getNodeId()==loopIndicatorId){ + //loop found + return true; + } + ret = hasLoop(node.getParentId(), categories, loopIndicatorId); + } + } + return ret; + } //hasLoop + + /** + * Simple class for tree nodes. + * @author Karsten Thiemann, kthiemann@adempiere.org + * + */ + private class SimpleTreeNode { + /** id of the node */ + private int nodeId; + /** id of the nodes parent */ + private int parentId; + + /** + * Constructor. + * @param nodeId + * @param parentId + */ + public SimpleTreeNode(int nodeId, int parentId) { + this.nodeId = nodeId; + this.parentId = parentId; + } + + public int getNodeId() { + return nodeId; + } + + public int getParentId() { + return parentId; + } + } + +} // MProductCategory \ No newline at end of file