Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: com/RuntimeCollective/webapps/bean/TreeExtension.java


1   /* $Header: /home/CVS/rjp/src/com/RuntimeCollective/webapps/bean/TreeExtension.java,v 1.7 2003/09/30 15:13:10 joe Exp $
2    * $Revision: 1.7 $
3    * $Date: 2003/09/30 15:13:10 $
4    *
5    * ====================================================================
6    *
7    * Josephine : http://www.runtime-collective.com/josephine/index.html
8    *
9    * Copyright (C) 2003 Runtime Collective
10   * 
11   * This product includes software developed by the
12   * Apache Software Foundation (http://www.apache.org/).
13   *
14   * This library is free software; you can redistribute it and/or
15   * modify it under the terms of the GNU Lesser General Public
16   * License as published by the Free Software Foundation; either
17   * version 2.1 of the License, or (at your option) any later version.
18   *
19   * This library is distributed in the hope that it will be useful,
20   * but WITHOUT ANY WARRANTY; without even the implied warranty of
21   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
22   * Lesser General Public License for more details.
23   *
24   * You should have received a copy of the GNU Lesser General Public
25   * License along with this library; if not, write to the Free Software
26   * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
27   *
28   */
29  
30  package com.RuntimeCollective.webapps.bean;
31  
32  import com.RuntimeCollective.permission.bean.PermissibleExtension;
33  import com.RuntimeCollective.webapps.BeanUtils;
34  import com.RuntimeCollective.webapps.EntityBeanStore;
35  import com.RuntimeCollective.webapps.RuntimeDataSource;
36  import com.RuntimeCollective.webapps.RuntimeParameters;
37  import com.RuntimeCollective.webapps.bean.EntityBean;
38  import com.RuntimeCollective.webapps.bean.User;
39  
40  import java.net.MalformedURLException;
41  import java.sql.SQLException;
42  import java.util.ArrayList;
43  import java.util.List;
44  import javax.servlet.jsp.PageContext;
45  
46  import org.apache.commons.beanutils.PropertyUtils;
47  import org.apache.struts.util.RequestUtils;
48  
49  /**
50   * This is an extension which places the extended EntityBean into a tree,
51   * thus having 0/1 parent and 0/n children. The type of parents and children
52   * is unconstrained (EntityBeans, that is).
53   * <p>
54   * A given EntityBean can belong to any number of trees, it will have
55   * 1/n TreeExtension(s) for each tree it belongs to.
56   *
57   * @version $Id: TreeExtension.java,v 1.7 2003/09/30 15:13:10 joe Exp $
58   */
59  public class TreeExtension implements EntityBean {
60  
61      private static final String SELECT_ID = "select id from "; 
62      private static final String SELECT_TREE_NAME = "select tree_name from "; 
63      private static final String WHERE_BEAN_ID = " where bean_id = ";
64      private static final String AND_TREE_NAME = " and tree_name = '";
65      private static final String DELETE_FROM = "delete from ";
66      private static final String WHERE_ID = " where id = ";
67      private static final String SELECT_DATA = "select bean_id, tree_name, parent_id from "; 
68      private static final String UPDATE = "update "; 
69      private static final String SET_POSITION = " set pos_no = "; 
70      private static final String AND_PARENT = ", parent_id = "; 
71      private static final String NULL_PARENT_WHERE = " set parent_id = null where parent_id = "; 
72      private static final String WHERE_PARENT = " where parent_id = ";
73      private static final String ORDER_POSITION = " order by pos_no";
74      private static final String ORDER_BY_TREE_NAME = " order by tree_name";
75  
76      private static final String ESC = "'";
77      private static final String EMPTY_STRING = "";
78      private static final String SPACE = " ";
79  
80      public static final String DATABASE_TABLE = "webapps_treeext";
81      private static final String FIELD_TREE_NAME = "tree_name";
82      private static final String FIELD_BEAN_ID = "bean_id";
83      private static final String FIELD_PARENT_ID = "parent_id";
84      private static final String FIELD_POSITION = "pos_no";
85  
86      public static final String START_HREF = "<a href=\"";
87      public static final String START_SPAN = "<span class=\"";
88      public static final String END_QUOTE_TAG = "\">";
89      public static final String END_HREF = "</a>";
90      public static final String END_SPAN = "</span>";
91      public static final String UNKNOWN = "unknown";
92      public static final String SEPARATOR = " : ";
93  
94  
95      // -------------------- EntityBean implementation -------------------------
96      
97      /** This bean's id */
98      protected int id;    
99  
100     /**
101      * Set the unique id of this bean instance.
102      */
103     public void setId(int id) {
104         this.id = id;
105     }
106 
107     /**
108      * Get the unique id of this bean instance.
109      */
110     public int getId() {
111         return id;
112     }
113 
114     /**
115      * Save this bean in the database.
116      */
117     public void save() {
118 
119         // parent_id and pos_no are really owned by the parent
120 
121         try {
122 
123             // beanId shouldn't be null, really
124             Integer beanInt = (beanId == EntityBean.NULL_ID) ? null : new Integer(beanId);
125             Integer parentInt = (parentId == EntityBean.NULL_ID) ? null : new Integer(parentId);
126             RuntimeDataSource.save(id, DATABASE_TABLE,
127                                    new String[] { FIELD_BEAN_ID, FIELD_TREE_NAME, FIELD_PARENT_ID },
128                                    new Object[] { beanInt,
129                                                   treeName,
130                                                   parentInt }
131                                    );
132             
133             // save the parent-child mappings (parent_id and pos_no)
134             int childId;
135             ArrayList updates = new ArrayList(childrenIds.size());
136             for (int i=0; i<childrenIds.size(); i++) {
137                 childId = ((Integer) childrenIds.get(i)).intValue();
138                 updates.add((new StringBuffer(90)).append(UPDATE).append(DATABASE_TABLE).append(SET_POSITION).append(i).append(AND_PARENT).append(id).append(WHERE_ID).append(childId).toString());
139             }
140             if (!updates.isEmpty()) {
141                 String[] updates_array = new String[updates.size()];
142                 updates_array = (String[]) updates.toArray(updates_array);
143                 RuntimeDataSource.update(updates_array);
144             }
145         } catch (SQLException e) {
146             RuntimeParameters.logError(this, "Could not save.", e);
147             e.printStackTrace();
148         }
149     }
150 
151     /**
152      * Delete this bean from the database.
153      */
154     public void delete() {
155         try {
156             RuntimeDataSource.update(new String[] {
157                 UPDATE+DATABASE_TABLE+NULL_PARENT_WHERE+id,
158                 DELETE_FROM+DATABASE_TABLE+WHERE_ID+id
159             } );
160         } catch (SQLException e) {
161             RuntimeParameters.logError(this, "Could not delete.", e);
162             e.printStackTrace();
163         }
164     }
165 
166 
167     // -------------------- TreeExtension specific -------------------------
168 
169     /**
170      * Constructs a new blank bean with a unique id.
171      */
172     public TreeExtension() throws SQLException {
173         setId(RuntimeDataSource.nextId());
174     }
175 
176     /**
177      * Gets a bean from the RuntimeDataSource, given an id.
178      *
179      * @param id id of the Moderated bean
180      * @exception SQLException thrown if no bean with such an id exits
181      */    
182     public TreeExtension(int id) throws SQLException {
183         Object[] results = RuntimeDataSource.queryRow(SELECT_DATA+DATABASE_TABLE+WHERE_ID+id);
184         if (results.length != 3) {
185             throw new SQLException("Cannot load TreeExtension with id="+id+" : "
186                                    +results.length+" fields found in "+DATABASE_TABLE+".");
187         }
188 
189         this.id = id;
190 
191         if (results[0] != null)
192             beanId = Integer.parseInt(results[0].toString());
193         else
194             beanId = EntityBean.NULL_ID;
195 
196         treeName = (String) results[1];
197 
198         if (results[2] != null)
199             parentId = Integer.parseInt(results[2].toString());
200         else
201             parentId = EntityBean.NULL_ID;
202 
203         // load the children mappings
204         int[] children = RuntimeDataSource.queryInts(SELECT_ID+DATABASE_TABLE+WHERE_PARENT+id+ORDER_POSITION);
205         for (int i=0; i<children.length; i++) {
206             childrenIds.add(new Integer(children[i]));
207         }
208     }
209 
210 
211     /** The id of the EntityBean this TreeExtension is for. */
212     protected int beanId = EntityBean.NULL_ID;
213 
214     /** Gets the bean. */
215     public EntityBean getEntityBean() {
216         return (EntityBean) RuntimeParameters.getStore().get(EntityBean.class.getName(), beanId);
217     }
218 
219     /** Sets the bean. */
220     public void setEntityBean(EntityBean bean) {
221         if (bean == null)
222             this.beanId = EntityBean.NULL_ID;
223         else
224             this.beanId = bean.getId();
225     }
226     
227     /** The name of the tree we are in. */
228     protected String treeName = null;
229 
230     /** Gets the tree name. */
231     public String getTreeName() {
232   return treeName;
233     }
234 
235     /** Sets the tree name. */
236     public void setTreeName(String approve) {
237   treeName = approve;
238     }
239 
240 
241     /** The Parent */
242     protected int parentId = EntityBean.NULL_ID;
243 
244     /** Set the Parent - don't use this unless you really mean to; use parent.addChild() instead. */
245     public void setParent(TreeExtension parent) {
246         if (parent != null)
247             parentId = parent.getId();
248         else
249             parentId = EntityBean.NULL_ID;
250     }
251 
252     /** Get the Parent */
253     public TreeExtension getParent() {
254         if (parentId != EntityBean.NULL_ID) {
255             return (TreeExtension) RuntimeParameters.getStore().get(TreeExtension.class.getName(), parentId);
256         } else {
257             return null;
258         }
259     }
260 
261     /** Get the Parent at the top of the tree, recursively. */
262     public TreeExtension getTopParent() {
263         TreeExtension parent = getParent();
264         if (parent != null) {
265             return parent.getTopParent();
266         } else {
267             return this;
268         }
269     }
270 
271 
272     /** The Children */
273     protected List childrenIds = new ArrayList();
274     
275     /** Remove a Child at a given position. */
276     public void removeChild(int position) {
277         if ((position >= 0) && (position < childrenIds.size())) {
278             childrenIds.remove(position);
279         }
280     }
281 
282     /** Remove a Child from this TreeExtension (all its positions, if more than one). */
283     public void removeChild(TreeExtension child) {
284         if (child != null) {
285             Integer childId = new Integer(child.getId());
286             while (childrenIds.contains(childId)) {
287                 childrenIds.remove(childId);
288             }
289             child.setParent(null);
290         }
291     }
292 
293     /** Add a Child to this TreeExtension. */
294     public void addChild(TreeExtension child) {
295         if (child != null) {
296             Integer childId = new Integer(child.getId());
297             childrenIds.add(childId);
298             child.setParent(this);
299         }
300     }
301 
302 
303     /** Get the position-nth child from this TreeExtension. */
304     public TreeExtension getChild(int position) {
305         if ((position >= 0) && (position < childrenIds.size())) {
306             return (TreeExtension) RuntimeParameters.getStore().get(TreeExtension.class.getName(), ((Integer) childrenIds.get(position)).intValue());
307         } else {
308             return null;
309         }
310     }
311 
312     /** Get the list of children (a List of TreeExtension). */
313     public List getChildren() {
314         return BeanUtils.beansFromIds(childrenIds);
315     }
316 
317     /** Get the position, by calling the Parent's getChildPosition. Returns -1 by default (ie no parent). */
318     public int getPosition() {
319         TreeExtension parent = getParent();
320         if (parent != null) {
321             return parent.getChildPosition(this);
322         } else {
323             return -1;
324         }
325     }
326 
327     /** Get the position of a child. Returns -1 by default (ie not there). */
328     public int getChildPosition(TreeExtension child) {
329         List children = getChildren();
330         return children.indexOf(child);
331     }
332 
333 
334     public String toString() {
335         return TreeExtension.class.getName() + " " + id + " ( " + super.toString() + " )";
336     }
337 
338     /** Construct a breadcrumb for this TreeExtension. */
339     public String getBreadcrumb(PageContext pageContext, String displayProperty, String displayPath, boolean asLinks, String styleClass) {
340 
341         // build a list of all parents
342         List parents = new ArrayList();
343         TreeExtension current = this;
344         while ((current = current.getParent()) != null) {
345             parents.add(current);
346         }
347 
348         // go through the list of parents, starting from the root
349         StringBuffer result = new StringBuffer(parents.size()*80);
350         for (int i=parents.size()-1; i>=0; i--) {
351             current = (TreeExtension) parents.get(i);
352             result.append(current.displayInBreadCrumb(pageContext, displayProperty, displayPath, asLinks, styleClass, false));
353         }
354 
355         // append the current object
356         result.append(displayInBreadCrumb(pageContext, displayProperty, displayPath, false, styleClass, true));
357 
358         return result.toString();
359     }
360 
361     /** Render the TreeExtension as one element in a Breadcrumb. */
362     public String displayInBreadCrumb(PageContext pageContext, String displayProperty, String displayPath, boolean asLinks, String styleClass, boolean isLast) {
363 
364         StringBuffer result = new StringBuffer(80);
365         EntityBean bean = getEntityBean();
366 
367         if (asLinks) {
368             result.append(START_HREF);
369             try {
370                 result.append(RequestUtils.computeURL(pageContext, null, null, displayPath+getId(), null, null, false));
371             } catch (MalformedURLException e) {
372                 RuntimeParameters.logError(this, "Couldn't compute link URL.", e);
373             }
374             result.append(END_QUOTE_TAG);
375         }
376         
377         if (styleClass != null) {
378             result.append(START_SPAN)
379                 .append(styleClass)
380                 .append(END_QUOTE_TAG);
381         }
382         
383         Object displayValue = null;
384         try {
385             displayValue = PropertyUtils.getProperty(bean, displayProperty);
386         } catch (Exception e) {
387             RuntimeParameters.logError(this, "Couldn't get display value.", e);
388         }
389         if (displayValue == null) {
390             result.append(UNKNOWN);
391         } else {
392             result.append(displayValue.toString());
393         }
394         
395         if (styleClass != null) {
396             result.append(END_SPAN);
397         }
398         
399         if (asLinks) {
400             result.append(END_HREF);
401         }
402 
403         if (!isLast) {
404             result.append(SEPARATOR);
405         }
406 
407         return result.toString();
408     }
409 
410     /**
411      * Recursive Permission test, which will check the PermissibleExtension
412      * of the EntityBean of this TreeExtension, and then (if necessary)
413      * do the same on the parent(s).
414      *
415      * @param action, the action to be performed
416      * @param user, the user who is trying to perform the action
417      * @return a boolean, yes the user can perform the action, or no
418      */
419     public boolean canPerformAction(String action, User user) {
420 
421         RuntimeParameters.logDebug(this, "Checking permissions on tree extension "+getId()+" for action "+action+" for user "+(user != null ? ""+user.getId() : "null"));
422 
423         // try to check this bean
424         EntityBean bean = getEntityBean();
425         if (bean != null) {
426             PermissibleExtension permissible = PermissibleExtension.getFor(bean);
427             if (permissible != null) {
428                 if (!permissible.canPerformAction(action, user)) {
429                     return false;
430                 }
431             }
432         }
433 
434         // call the parent, if any
435         TreeExtension parent = getParent();
436         if (parent != null) {
437             return parent.canPerformAction(action, user);
438         }
439 
440         // all fine, no more checks to do
441         return true;
442     }
443 
444 
445     // -------------------- TreeExtension statics -------------------------        
446     
447     /**
448      * Gets the TreeExtension for a particular bean and a particular treeName, if one exists.
449      * If more than one exists, the firstly created on (ie smallest id) will be returned.
450      */
451     public static TreeExtension getFor(EntityBean bean, String treeName) {
452         List all = getAllFor(bean, treeName);
453         if ((all != null) && (!all.isEmpty())) {
454             return (TreeExtension) all.get(0);
455         } else {
456             return null;
457         }
458     }
459 
460     /**
461      * Gets all the TreeExtensions for a particular bean and a particular treeName, ordered by id.
462      */
463     public static List getAllFor(EntityBean bean, String treeName) {
464 
465         if ((bean == null) || (treeName == null)) {
466             return null;
467         }
468 
469         List result = null;
470 
471         try {
472             int[] ids = RuntimeDataSource.queryInts(SELECT_ID+DATABASE_TABLE+WHERE_BEAN_ID+bean.getId()+AND_TREE_NAME+RuntimeDataSource.escape(treeName)+ESC);
473             result = new ArrayList(ids.length);
474             for (int i=0; i<ids.length; i++) {
475                 result.add((TreeExtension) RuntimeParameters.getStore().get(TreeExtension.class.getName(), ids[i]));
476             }
477         } catch (SQLException e) {
478             RuntimeParameters.logError("TreeExtension", "Could not getAllFor.", e);
479             e.printStackTrace();
480         }
481 
482         return result;
483     }
484 
485     /**
486      * Gets all the TreeExtensions for a particular bean, ordered by treeName then by id.
487      */
488     public static List getAllFor(EntityBean bean) {
489 
490         List result = new ArrayList();
491 
492         List treeNames = TreeExtension.getTreeNamesFor(bean);
493         for (int i=0; i<treeNames.size(); i++) {
494             result.addAll(getAllFor(bean, (String) treeNames.get(i)));
495         }
496 
497         return result;
498     }
499 
500 
501 
502     /**
503      * Get a list of TreeNames to which an EntityBean belongs, order alphabetically.
504      */
505     public static List getTreeNamesFor(EntityBean bean) {
506 
507         if (bean == null) {
508             return null;
509         }
510 
511         List result = null;
512 
513         try {
514             Object[][] names = RuntimeDataSource.queryRows(SELECT_TREE_NAME+DATABASE_TABLE+WHERE_BEAN_ID+bean.getId()+ORDER_BY_TREE_NAME);
515             String aName;
516             result = new ArrayList(names.length);
517             for (int i=0; i<names.length; i++) {
518                 aName = (String) names[i][0];
519                 if (!result.contains(aName)) {
520                     result.add(aName);
521                 }
522             }
523         } catch (SQLException e) {
524             RuntimeParameters.logError("TreeExtension", "Could not getTreeNamesFor.", e);
525             e.printStackTrace();
526         }
527 
528         return result;
529     }
530 
531     /**
532      * Check if the EntityBean belongs, and *only* belongs, to the TreeName provided.
533      */
534     public static boolean onlyBelongsTo(EntityBean bean, String treeName) {
535 
536         if ((bean == null) || (treeName == null)) {
537             return false;
538         }
539 
540         List names = getTreeNamesFor(bean);
541 
542         RuntimeParameters.logDebug("TreeExtension", "Tree name : "+treeName+", size : "+names);
543         //RuntimeParameters.logDebug("TreeExtension", "Tree name : "+treeName+", size : "+names.size()+", first : "+names.get(0));
544 
545         return ((names != null) && (names.size() == 1) && (treeName.equals((String) names.get(0))));
546     }
547 }
548 
549 
550