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

Quick Search    Search Deep

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


1   /* $Header: /home/CVS/rjp/src/com/RuntimeCollective/webapps/bean/VersionedExtension.java,v 1.5 2003/09/30 15:13:10 joe Exp $
2    * $Revision: 1.5 $
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.webapps.RuntimeDataSource;
33  import com.RuntimeCollective.webapps.RuntimeParameters;
34  import com.RuntimeCollective.webapps.EntityBeanStore;
35  import com.RuntimeCollective.webapps.bean.Duplicable;
36  import com.RuntimeCollective.webapps.bean.EntityBean;
37  import com.RuntimeCollective.webapps.bean.Versioned;
38  
39  import java.util.ArrayList;
40  import java.util.HashMap;
41  import java.util.Iterator;
42  import java.util.List;
43  import java.sql.SQLException;
44  
45  /**
46   * An extension which can be used to stick the Versioned behaviour to any Duplicable bean.
47   * This also adds a VersionNotes property to each version.
48   *
49   * @version $Id: VersionedExtension.java,v 1.5 2003/09/30 15:13:10 joe Exp $
50   */
51  public class VersionedExtension implements Versioned {
52  
53      private static final String SELECT_ID = "select id from "; 
54      private static final String WHERE_DUPLICABLE_ID = " where duplicable_id = ";
55      private static final String DELETE_FROM = "delete from ";
56      private static final String WHERE_ID = " where id = ";
57      private static final String SELECT_DATA = "select duplicable_id, version_tag, version_ref, version_notes from "; 
58      private static final String SELECT_ID_TAG = "select id, version_tag from ";
59      private static final String WHERE_VER_REF = " where version_ref = ";
60  
61      private static final String ESC = "'";
62      private static final String EMPTY_STRING = "";
63      private static final String SPACE = " ";
64  
65      public static final String DATABASE_TABLE = "webapps_versionedext";
66      private static final String FIELD_DUPLICABLE_ID = "duplicable_id";
67      private static final String FIELD_VTAG = "version_tag";
68      private static final String FIELD_VREF = "version_ref";
69      private static final String FIELD_VNOTES = "version_notes";
70  
71  
72  
73      // -------------------- EntityBean stuff -------------------------        
74  
75      protected int id;
76  
77      public void setId(int id) {
78          this.id = id;
79      }
80  
81      public int getId() {
82          return id;
83      }
84  
85      /**
86       * Save this bean in the database.
87       */
88      public void save() {
89  
90          // duplicableId shouldn't be null, really
91          try {
92              Integer duplicableInt = (duplicableId == EntityBean.NULL_ID) ? null : new Integer(duplicableId);
93              Integer versionRef = (versionReference == EntityBean.NULL_ID) ? null : new Integer(versionReference);
94              RuntimeDataSource.save(id, DATABASE_TABLE,
95                                     new String[] { FIELD_DUPLICABLE_ID, FIELD_VTAG, FIELD_VREF, FIELD_VNOTES },
96                                     new Object[] { duplicableInt, versionTag, versionRef, versionNotes }
97                                     );
98          } catch (SQLException e) {
99              RuntimeParameters.logError(this, "Could not save.", e);
100             e.printStackTrace();
101         }
102     }
103 
104     /**
105      * Delete this bean from the database.
106      */
107     public void delete() {
108         try {
109             RuntimeDataSource.update(DELETE_FROM+DATABASE_TABLE+WHERE_ID+id);
110 
111             // refresh the tag list
112             refreshVersionsCache(true);
113         
114         } catch (SQLException e) {
115             RuntimeParameters.logError(this, "Could not delete.", e);
116             e.printStackTrace();
117         }
118     }
119 
120     /**
121      * Constructs a new blank bean with a unique id.
122      */
123     public VersionedExtension() throws SQLException {
124         setId(RuntimeDataSource.nextId());
125         
126         setVersionReference(id);
127         setVersionTag(Versioned.TRUNK_TAG);
128         setVersionNotes("");
129     }
130 
131     /**
132      * Gets a bean from the RuntimeDataSource, given an id.
133      *
134      * @param id id of the VersionedExtension bean
135      * @exception SQLException thrown if no bean with such an id exits
136      */    
137     public VersionedExtension(int id) throws SQLException {
138 
139         Object[] results = RuntimeDataSource.queryRow(SELECT_DATA+DATABASE_TABLE+WHERE_ID+id);
140         if (results.length != 4) {
141             throw new SQLException("Cannot load VersionedExtension with id="+id+" : "
142                                    +results.length+" fields found in "+DATABASE_TABLE+".");
143         }
144 
145         this.id = id;
146 
147         if (results[0] != null)
148             duplicableId = Integer.parseInt(results[0].toString());
149         else
150             duplicableId = EntityBean.NULL_ID;
151 
152         setVersionTag((String) results[1]);
153 
154         if (results[2] != null)
155             setVersionReference(((Integer) results[2]).intValue());
156         else
157             setVersionReference(EntityBean.NULL_ID);
158 
159         setVersionNotes((String) results[3]);
160 
161         // refresh the tag list
162         refreshVersionsCache(false);
163     }
164 
165 
166     // -------------------- Versioned stuff -------------------------        
167     
168     /** This is not implemented - we *could* make VersionedExtension properly Duplicable... */
169     public Duplicable makeDuplicate() {
170         return null;
171     }
172 
173     /** This is not implemented - we *could* make VersionedExtension properly Duplicable... */
174     public Duplicable makeDuplicate(int duplicateId) {
175         return null;
176     }
177 
178     /** This is not implemented - we *could* make VersionedExtension properly Duplicable... */
179     public Duplicable customiseDuplicate(Duplicable duplicate) {
180         return null;
181     }
182 
183 
184     // -------------------- Versioned stuff -------------------------        
185 
186     /**
187      * The Reference of this Version, that is,
188      * the id of the first object in the family of versions.
189      */
190     protected int versionReference;
191 
192     public void setVersionReference(int reference) {
193         versionReference = reference;
194     }
195 
196     public int getVersionReference() {
197         return versionReference;
198     }
199 
200     /* The Tag of this Version */
201     protected String versionTag;
202 
203     public void setVersionTag(String tag) {
204         versionTag = tag;
205     }
206 
207     public String getVersionTag() {
208         return versionTag;
209     }
210 
211     /* The Notes of this Version */
212     protected String versionNotes;
213 
214     public void setVersionNotes(String notes) {
215         versionNotes = notes;
216     }
217 
218     public String getVersionNotes() {
219         return versionNotes;
220     }
221 
222     /**
223      * Get the List of all version tags for this VersionedExtension,
224      * ie for this Duplicable.
225      */
226     public List getVersionTagList() {
227         List result = new ArrayList();
228 
229         Iterator ids = versionsCache.keySet().iterator();
230         Integer anId;
231         String aTag;
232         while (ids.hasNext()) {
233             anId = (Integer) ids.next();
234             aTag = (String) versionsCache.get(anId);
235             if (!result.contains(aTag)) {
236                 result.add(aTag);
237             }
238         }
239         
240         return result;
241     }
242 
243     /**
244      * Get the List of all versions, in unspecified order.
245      * FIXME: this should be trickled up to the Versioned interface.
246      */
247     public List getVersionList() {
248         Iterator ids = versionsCache.keySet().iterator();
249         List versions = new ArrayList();
250 
251         while (ids.hasNext()) {
252             versions.add(RuntimeParameters.getStore().get(VersionedExtension.class.getName(), ((Integer) ids.next()).intValue()));
253         }
254 
255         return versions;
256     }
257 
258 
259     /**
260      * Create and save a new version of this object based on a existing one,
261      * and tag it with the specified tag. If a version with the newVersionTag
262      * already exists, it will be overwritten - ie its id will be reused.
263      * <p>
264      * The reference version should already exist, otherwise this method will do
265      * nothing and return "null".
266      * <br>
267      * A version with the newVersionTag may or may not exist: if it doesn't, it will
268      * be created - if it does, it will be overwritten.
269      * <p>
270      * Note the new/updated Duplicable and VersionedExtension are both saved.
271      *
272      * @param referenceVersionTag, the version which will be duplicated and used as
273      * a base for the new version
274      * @param newVersionTag, the tag given to the new version
275      * @return a new version, or null if either the reference version doesn't exist, or
276      * the new tag is already used.
277      */
278     public Versioned createOrReplaceVersion(String referenceVersionTag, String newVersionTag) {
279 
280         RuntimeParameters.logDebug(this, "Versioning "+getDuplicable().getClass().getName()
281                                    +" "+getDuplicable().getId()+" from "+referenceVersionTag+" to "+newVersionTag);
282 
283         // get the VersionReference
284         // (we need to do this first as we may be overwriting the Live version)
285         int versionRef = getVersion(Versioned.TRUNK_TAG).getId();
286 
287         VersionedExtension edited = (VersionedExtension) getVersion(referenceVersionTag);
288         if (edited == null) {
289             RuntimeParameters.logDebug(this, "Could not find the referenceVersion for Tag "+referenceVersionTag);
290             return null;
291         }
292 
293         Duplicable editedDuplicable = edited.getDuplicable();
294 
295         VersionedExtension newVersion = (VersionedExtension) getVersion(newVersionTag);
296         Duplicable newVersionDuplicable;
297         if (newVersion == null) {
298             // create new Version
299             newVersion = (VersionedExtension) RuntimeParameters.getStore().create(VersionedExtension.class.getName());
300             newVersionDuplicable = editedDuplicable.makeDuplicate();
301 
302         } else {
303             // overwrite that Version
304             newVersionDuplicable = newVersion.getDuplicable();
305             if (newVersionDuplicable != null) {
306                 newVersionDuplicable = editedDuplicable.makeDuplicate(newVersionDuplicable.getId());
307             } else {
308                 RuntimeParameters.logError(this, "Trying to overwrite an existing VersionedExtension with a null Duplicable.");
309                 return null;
310             }
311         }
312 
313         // populate/update the extension of the new/updated duplicable
314         newVersion.setDuplicable(newVersionDuplicable);
315         newVersion.setVersionTag(newVersionTag);
316         newVersion.setVersionReference(versionRef);
317 
318         // save and refresh the new version from the db, to prevent stale data
319         RuntimeParameters.getStore().save(newVersionDuplicable);
320         RuntimeParameters.getStore().save(newVersion);
321         RuntimeParameters.getStore().refresh(newVersion);
322         
323         // refresh the tag list
324         refreshVersionsCache(true);
325         
326         return newVersion;
327     }
328 
329     /**
330      * Get an existing version of this object.
331      * <p>
332      * The version should already exist. It is doesn't, then this method
333      * will do nothing and return "null".
334      *
335      * @param aVersionTag, the version required
336      * @return the required version, or "null" if it doesn't exist
337      */
338     public Versioned getVersion(String aVersionTag) {
339 
340         //System.out.println(" This "+getId()+" ("+VersionTag+"), looking for tag : "+versionTag);
341 
342         // quick optimisation
343         if ((aVersionTag != null) && (aVersionTag.equals(versionTag))) {
344             return this;
345         }
346 
347         Iterator ids = versionsCache.keySet().iterator();
348         Integer anId;
349         String aTag;
350         while (ids.hasNext()) {
351             anId = (Integer) ids.next();
352             aTag = (String) versionsCache.get(anId);
353 
354             //System.out.println(" Versions : id : "+anId+" tag : "+aTag);
355             
356             if (aTag.equals(aVersionTag)) {
357                 try {
358                     return (Versioned) RuntimeParameters.getStore().get(Versioned.class.getName(), anId.intValue());
359                 } catch (RuntimeException e) {
360                     RuntimeParameters.logError(this, "Couldn't get version "+aVersionTag+" for "+getId(), e);
361                     e.printStackTrace();
362                     return null;
363                 }
364             }
365         }
366         
367         return null;
368     }
369 
370     /**
371      * A HashMap of all version ids for this object, and their version tag.
372      */
373     protected HashMap versionsCache = new HashMap();
374 
375     protected void setVersionsCache(HashMap map) {
376         versionsCache = map;
377     }
378 
379     /** Refresh the cache of VersionTags, for this object and all its versions
380      * @param allVersions, whether all versions should be refreshed, or just this one
381      */
382     protected void refreshVersionsCache(boolean allVersions) {
383         HashMap versions = readVersionsCache();
384 
385         //RuntimeParameters.logDebug(this, "Refreshing version tag list "+allVersions);
386         
387         // we need to do that even if we do allVersions, as we are going to use
388         // this object's map to getVersion(aTag)
389         setVersionsCache(versions);
390         
391         if (allVersions) {
392             VersionedExtension version;
393             Iterator ids = versions.keySet().iterator();
394             Integer anId;
395             String aTag;
396             while (ids.hasNext()) {
397                 anId = (Integer) ids.next();
398                 aTag = (String) versions.get(anId);
399                 version = (VersionedExtension) getVersion(aTag);
400                 version.setVersionsCache(versions);
401             }
402         }
403     }
404 
405     /** Read from the database the list of VersionTags which exist
406      * for that VersionedExtension, that is for that Duplicable, really.
407      */
408     protected HashMap readVersionsCache() {
409 
410         HashMap result = new HashMap();
411         
412         try {
413             // load the VersionTags
414             Object[][] rows = RuntimeDataSource.queryRows((new StringBuffer(80)).append(SELECT_ID_TAG).append(DATABASE_TABLE).append(WHERE_VER_REF).append(getVersionReference()).toString());
415             
416             if (rows != null) {
417                 for (int i=0; i<rows.length; i++) {
418                     result.put((Integer) rows[i][0], (String) rows[i][1]);
419                     //System.out.println(" Found version "+rows[i][1]+" for id "+rows[i][0]);
420                 }
421             }
422             
423         } catch (Exception e) {
424             RuntimeParameters.logError(this, "Could not getVersionTagList().", e);
425             e.printStackTrace();
426         }
427         
428         return result;
429     }
430     
431 
432     // -------------------- VersionedExtension stuff -------------------------        
433 
434     /** The id of the Duplicable this VersionedExtension is for. */
435     protected int duplicableId = EntityBean.NULL_ID;
436 
437     /** Gets the duplicable. */
438     public Duplicable getDuplicable() {
439         return (Duplicable) RuntimeParameters.getStore().get(Duplicable.class.getName(), duplicableId);
440     }
441 
442     /** Sets the duplicable. */
443     public void setDuplicable(Duplicable duplicable) {
444         if (duplicable == null)
445             this.duplicableId = Duplicable.NULL_ID;
446         else
447             this.duplicableId = duplicable.getId();
448     }
449     
450     public String toString() {
451         return VersionedExtension.class.getName() + " " + id + " ( " + super.toString() + " )";
452     }
453 
454 
455     // -------------------- VersionedExtension statics -------------------------        
456     
457     /**
458      * Gets the VersionedExtension for a particular duplicable, if one exists.
459      */
460    public static VersionedExtension getFor(Duplicable duplicable) {
461 
462         if (duplicable == null) {
463             return null;
464         }
465 
466         try {
467             int[] ids = RuntimeDataSource.queryInts(SELECT_ID+DATABASE_TABLE+WHERE_DUPLICABLE_ID+duplicable.getId());
468             if (ids.length > 0) {
469                 return (VersionedExtension) RuntimeParameters.getStore().get(VersionedExtension.class.getName(), ids[0]);
470             }
471 
472         } catch (Exception e) {
473             RuntimeParameters.logError("VersionedExtension", "Could not getFor.", e);
474             e.printStackTrace();
475         }
476 
477         return null;
478     }
479 
480     /**
481      * Gets the VersionedExtension for a particular bean,
482      * or create a TRUNK_TAG VersionedExtension if there is none.
483      * <p>
484      * NOTE: newly created VersionedExtension objects are NOT saved -
485      * you'll need to do that.
486      */
487     public static VersionedExtension getOrCreateFor(Duplicable duplicable) {
488 
489         if (duplicable == null)
490             return null;
491   
492         VersionedExtension verExt = VersionedExtension.getFor(duplicable);
493         if (verExt != null) {
494             return verExt;
495         }
496 
497         // ok we'll need to create it
498         verExt = (VersionedExtension) RuntimeParameters.getStore().create(VersionedExtension.class.getName());
499         verExt.populateAsTrunkOf(duplicable);
500         // not saving it - caller is responsible!
501         return verExt;
502     }    
503 
504     /**
505      * This method, not often used, populates the Extension
506      * like it is the TRUNK of the given Duplicable.
507      * This is called by getOrCreateFor when creating.
508      */
509     public void populateAsTrunkOf(Duplicable duplicable) {
510         setDuplicable(duplicable);
511         setVersionTag(Versioned.TRUNK_TAG);
512         setVersionReference(getId());
513         // setup the versionCache without reading the db (we may not be saved)
514         versionsCache = new HashMap();
515         versionsCache.put(new Integer(getId()), getVersionTag());
516     }
517 }
518 
519 
520 
521