KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jahia > content > CrossReferenceManager


1 /*
2  * ____.
3  * __/\ ______| |__/\. _______
4  * __ .____| | \ | +----+ \
5  * _______| /--| | | - \ _ | : - \_________
6  * \\______: :---| : : | : | \________>
7  * |__\---\_____________:______: :____|____:_____\
8  * /_____|
9  *
10  * . . . i n j a h i a w e t r u s t . . .
11  *
12  *
13  *
14  * ----- BEGIN LICENSE BLOCK -----
15  * Version: JCSL 1.0
16  *
17  * The contents of this file are subject to the Jahia Community Source License
18  * 1.0 or later (the "License"); you may not use this file except in
19  * compliance with the License. You may obtain a copy of the License at
20  * http://www.jahia.org/license
21  *
22  * Software distributed under the License is distributed on an "AS IS" basis,
23  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
24  * for the rights, obligations and limitations governing use of the contents
25  * of the file. The Original and Upgraded Code is the Jahia CMS and Portal
26  * Server. The developer of the Original and Upgraded Code is JAHIA Ltd. JAHIA
27  * Ltd. owns the copyrights in the portions it created. All Rights Reserved.
28  *
29  * The Shared Modifications are Jahia View Helper.
30  *
31  * The Developer of the Shared Modifications is Jahia Solution S�rl.
32  * Portions created by the Initial Developer are Copyright (C) 2002 by the
33  * Initial Developer. All Rights Reserved.
34  *
35  * Contributor(s):
36  * 19-Aug-2003, Jahia Solutions Sarl: Fulco Houkes
37  *
38  * ----- END LICENSE BLOCK -----
39  */

40
41
42 package org.jahia.content;
43
44 import java.sql.Connection JavaDoc;
45 import java.sql.PreparedStatement JavaDoc;
46 import java.sql.ResultSet JavaDoc;
47 import java.sql.SQLException JavaDoc;
48 import java.sql.Timestamp JavaDoc;
49 import java.util.ArrayList JavaDoc;
50 import java.util.Date JavaDoc;
51 import java.util.HashMap JavaDoc;
52 import java.util.HashSet JavaDoc;
53 import java.util.Iterator JavaDoc;
54 import java.util.ListIterator JavaDoc;
55 import java.util.Set JavaDoc;
56 import java.util.TreeSet JavaDoc;
57
58 import org.apache.log4j.Logger;
59 import org.jahia.bin.Jahia;
60 import org.jahia.exceptions.JahiaException;
61 import org.jahia.exceptions.JahiaInitializationException;
62 import org.jahia.services.cache.Cache;
63 import org.jahia.services.cache.CacheFactory;
64
65
66 /**
67  * This class is the main object cross reference class. Basically it uses a
68  * hashtable to group object reference this way :
69  *
70  * objectref -> set of objectrefs
71  *
72  * This way we can easily determine for a given object where it is referenced.
73  * ObjectRefs may be of any kind that's a subclass of the ObjectKey class.
74  * @author Serge Huber
75  */

76
77 public class CrossReferenceManager {
78
79     /** logging */
80     private static Logger logger = Logger.getLogger (CrossReferenceManager.class);
81
82     // the Object Link cache name.
83
public static final String JavaDoc OBJECT_LINK_CACHE = "ObjectLinkCache";
84     // the preloaded object link by reference object.
85
public static final String JavaDoc PRELOADED_OBJECT_LINKS_BY_REF_OBJECT_CACHE = "PreloadedObjectLinksByRefObjectCache";
86
87     /** the cross reference cache */
88     private Cache crossRefTable;
89
90     /** the preloaded object link by ref object */
91     private Cache preloadedObjectLinkByRefObjectCache;
92
93     /** the unique instance of this class */
94     private static CrossReferenceManager instance;
95
96     public static final String JavaDoc REFERENCE_TYPE = "reference";
97
98     /** Default constructor, creates a new <code>CrossReferenceManager</code> instance.
99      */

100     protected CrossReferenceManager () {
101
102         logger.debug ("Initializing...");
103         try {
104             crossRefTable = CacheFactory.createCache (OBJECT_LINK_CACHE);
105
106             preloadedObjectLinkByRefObjectCache =
107                 CacheFactory.createCache (PRELOADED_OBJECT_LINKS_BY_REF_OBJECT_CACHE);
108
109             //preloadObjectXRefs();
110
} catch (JahiaInitializationException e) {
111             logger.warn ("Could not initialize the Cross-Reference Manager cache!! Strange things are going to happen! ;)", e);
112         }
113     }
114
115
116     /**
117      * <p>Returns the unique instance of this service.</p>
118      * <p><strong>Note</strong>: this is a synchronized access method so it might affect performance
119      * if a lot of threads must access it simultaneously.</p>
120      *
121      * @return the class instance.
122      */

123     public static synchronized CrossReferenceManager getInstance () {
124         if (instance == null) {
125             instance = new CrossReferenceManager ();
126         }
127         return instance;
128     }
129
130
131     /**
132      * Retrieve a set of object references, basically all the objects that
133      * reference the object passed in parameter
134      * @param objectKey an ObjectKey type object that identifies the object for
135      * which to retrieve the set of references
136      * @return a set of ObjectKey objects that are the objects that reference
137      * the object passed in parameter
138      * @throws JahiaException in case there was a problem retrieving the
139      * references from the database
140      */

141     public Set JavaDoc getObjectXRefs (ObjectKey objectKey)
142             throws JahiaException {
143         logger.debug ("Retrieving xrefs for object " + objectKey);
144
145         Set JavaDoc set = (Set JavaDoc)crossRefTable.get (objectKey);
146         if (set != null)
147             return set;
148
149         // let's try to load it from the database
150
ArrayList JavaDoc leftLinks = ObjectLinkDB.getInstance ().
151                 findByRightObjectKey (objectKey);
152         set = new TreeSet JavaDoc (new ObjectKeyComparator());
153         Iterator JavaDoc leftLinksIter = leftLinks.listIterator ();
154         while (leftLinksIter.hasNext ()) {
155             ObjectLink curLink = (ObjectLink)leftLinksIter.next ();
156             set.add (curLink.getLeftObjectKey ());
157         }
158         crossRefTable.put (objectKey, set);
159         return set;
160     }
161
162     /**
163      * Performs a reverse lookup of objects, by specifying the reference
164      * destination and returning all the sources that are in pointed to from
165      * that destination.
166      *
167      * Note : This method iterates through all the sources to find the
168      * destination target so it is NOT optimal and has some overhead. Maybe a
169      * further optimization would be to build bidirectional references, but
170      * this would complicate handling of "dirty" references.
171      *
172      * @param objectXRef the destination reference object key that specifies
173      * for which object we want to lookup source object.
174      * @return a set of ObjectKey objects that are the objects that are
175      * references by the passed reference object key.
176      * @throws JahiaException in case there was a problem retrieving the
177      * references from the database
178      */

179     public Set JavaDoc getReverseObjectXRefs (ObjectKey objectXRef)
180             throws JahiaException
181     {
182         Set JavaDoc objectSourceKeys = new HashSet JavaDoc ();
183
184         Object JavaDoc[] keys = crossRefTable.keys();
185         for (int i=0; i<keys.length;i++) {
186             if (keys[i] instanceof ObjectKey) {
187                 Set JavaDoc curXRefSet = (Set JavaDoc)crossRefTable.get (keys[i]);
188                 if (curXRefSet != null) {
189                     if (curXRefSet.contains (objectXRef)) {
190                         // we found a reference that corresponds to the one we want
191
// to lookup source object for, let's add the source object
192
// key to the result set.
193
objectSourceKeys.add (keys[i]);
194                     }
195                 }
196             }
197         }
198
199         // TODO: The cache does not hold always all the object references, therefore
200
// the previous for loop might not find all the keys pointing to the
201
// desired ObjectKey. Some might not have been loaded yet from the DB
202
// and will not be considered by the next if statment!
203

204         if (objectSourceKeys.size () == 0) {
205             // this could be because the keys were not yet loaded from the
206
// database, let's make sure we do so if necessary.
207
ArrayList JavaDoc rightLinks = ObjectLinkDB.getInstance ().
208                     findByLeftObjectKey (objectXRef);
209             Set JavaDoc resultSet = new HashSet JavaDoc ();
210             Iterator JavaDoc rightLinksIter = rightLinks.listIterator ();
211             while (rightLinksIter.hasNext ()) {
212                 ObjectLink curLink = (ObjectLink)rightLinksIter.next ();
213                 resultSet.add (curLink.getRightObjectKey ());
214                 getObjectXRefs (curLink.getRightObjectKey ());
215             }
216             objectSourceKeys = resultSet;
217         }
218
219         return objectSourceKeys;
220     }
221
222     /**
223      * Adds a cross reference between the two objects passed in parameter. The
224      * first object key is used as the key in the lookup table.
225      * @param objectKey the key for the object to add a cross reference to
226      * @param objectXRef another key for the object that references the first
227      * object
228      * @throws JahiaException in case there were problems storing the references
229      * in the database
230      */

231     public void setObjectXRef (ObjectKey objectKey, ObjectKey objectXRef)
232             throws JahiaException
233     {
234         logger.debug ("Setting xref from object " + objectXRef +
235                 " to " + objectKey + " ...");
236         if ( objectKey != null && objectXRef != null
237              && objectKey.equals(objectXRef) ){
238             // cannot reference an object to itself
239
logger.debug ("Setting xref cannot set reference for the object " + objectXRef +
240                     " to itself !!!");
241             return;
242         }
243
244         // loads from database if necessary
245
getObjectXRefs (objectKey);
246
247         // get the object
248
Set JavaDoc curXRefSet = (Set JavaDoc)crossRefTable.get (objectKey);
249         if (curXRefSet == null) {
250             curXRefSet = new TreeSet JavaDoc (new ObjectKeyComparator ());
251         }
252
253         if (!curXRefSet.contains (objectXRef)) {
254             ObjectLink.createLink (objectXRef, objectKey, REFERENCE_TYPE, 1,
255                     new Date JavaDoc (),
256                     "root:0", new Date JavaDoc (), "root:0", new HashMap JavaDoc (),
257                     new HashMap JavaDoc (), new HashMap JavaDoc ());
258             Set JavaDoc newXRefSet = new TreeSet JavaDoc (new ObjectKeyComparator ());
259             newXRefSet.addAll(curXRefSet);
260             newXRefSet.add (objectXRef);
261             
262             // add the modified curXRefSet
263
crossRefTable.put (objectKey, newXRefSet);
264         }
265    }
266
267
268     /**
269      * Removes all cross references for an object.
270      * @param objectKey the key for the object whose references are to be
271      * deleted.
272      */

273     public void removeObjectXRefs (ObjectKey objectKey)
274             throws JahiaException {
275         logger.debug ("Removing xrefs for object " + objectKey.getKey ());
276         // first let's remove it from memory cache
277
crossRefTable.remove (objectKey);
278
279         // now let's remove it from the database, making sure we only use the
280
// links that existed for the cross reference manager and no other
281
// type of link.
282
Set JavaDoc objectXRefKeys = getObjectXRefs (objectKey);
283         Iterator JavaDoc objectXRefKeyIter = objectXRefKeys.iterator ();
284         while (objectXRefKeyIter.hasNext ()) {
285             ObjectKey curXRefKey = (ObjectKey)objectXRefKeyIter.next ();
286             ArrayList JavaDoc objectLinks = ObjectLinkDB.getInstance ().findByTypeAndLeftAndRightObjectKeys (REFERENCE_TYPE, curXRefKey, objectKey);
287             ListIterator JavaDoc objectLinkIter = objectLinks.listIterator ();
288             while (objectLinkIter.hasNext ()) {
289                 ObjectLink curLink = (ObjectLink)objectLinkIter.next ();
290                 curLink.remove ();
291             }
292
293         }
294     }
295
296     /**
297      * Remove an xref for a given object, leaving all the other xrefs intact
298      * @param objectKey the destination object that is the target of the
299      * reference
300      * @param objectXRef the object source of the reference
301      * @throws JahiaException thrown in case there was a problem communicating
302      * with the database
303      */

304     public void removeObjectXRef (ObjectKey objectKey, ObjectKey objectXRef)
305             throws JahiaException {
306         logger.debug ("Removing xref " + objectXRef.getKey () + " for object " +
307                 objectKey.getKey ());
308
309         getObjectXRefs (objectKey); // loads from database if necessary
310

311         Set JavaDoc curXRefSet = (Set JavaDoc)crossRefTable.get (objectKey);
312         if (curXRefSet != null) {
313             if (curXRefSet.contains (objectXRef)) {
314                 Set JavaDoc newXRefSet = new TreeSet JavaDoc(new ObjectKeyComparator());
315                 newXRefSet.addAll(curXRefSet);
316                 // ok we found the xref, let's remove it from memory
317
newXRefSet.remove (objectXRef);
318                 crossRefTable.put (objectKey, newXRefSet);
319                 
320                 // now let's remove it from the database.
321
ArrayList JavaDoc objectLinks = ObjectLinkDB.getInstance ().
322                         findByTypeAndLeftAndRightObjectKeys (
323                                 REFERENCE_TYPE, objectXRef, objectKey);
324
325                 ListIterator JavaDoc objectLinkIter = objectLinks.listIterator ();
326                 while (objectLinkIter.hasNext ()) {
327                     ObjectLink curLink = (ObjectLink)objectLinkIter.next ();
328                     curLink.remove ();
329                 }
330             }
331         }
332
333     }
334
335     public String JavaDoc toString () {
336         StringBuffer JavaDoc refTableBuffer = new StringBuffer JavaDoc ();
337
338         refTableBuffer.append ("CrossReferenceManager internal state\n");
339
340
341         Object JavaDoc[] objectKeys = crossRefTable.keys ();
342
343         for (int k=0; k<objectKeys.length; k++) {
344
345             // get the next ObjectKey
346
ObjectKey curObjectKey = (ObjectKey)objectKeys[k];
347             if (curObjectKey != null) {
348
349                 refTableBuffer.append (curObjectKey.getKey ());
350                 refTableBuffer.append (" <-- ");
351                 StringBuffer JavaDoc leftPad = new StringBuffer JavaDoc (curObjectKey.getKey ().
352                         length () + 5);
353
354                 for (int i = 0; i < curObjectKey.getKey ().length (); i++) {
355                     leftPad.append (" ");
356                 }
357                 leftPad.append (" <-- ");
358
359                 Set JavaDoc curXRefSet = (Set JavaDoc)crossRefTable.get (curObjectKey);
360                 if (curXRefSet != null) {
361                     Iterator JavaDoc xRefKeys = curXRefSet.iterator ();
362                     int count = 0;
363                     while (xRefKeys.hasNext ()) {
364                         ObjectKey curXRefObjectKey = (ObjectKey)xRefKeys.next ();
365                         if (count > 0) {
366                             refTableBuffer.append (leftPad.toString ());
367                         }
368                         refTableBuffer.append (curXRefObjectKey.getKey ());
369                         refTableBuffer.append ("\n");
370                         count++;
371                     }
372                 } else {
373                     refTableBuffer.append ("No XRefs !\n");
374                 }
375             }
376         }
377         return refTableBuffer.toString ();
378     }
379
380     protected void preloadObjectXRefs ()
381         throws JahiaException {
382
383         logger.info("Preloading Object links in cache");
384
385         int count = 0;
386         Connection JavaDoc dbConn = null;
387         PreparedStatement JavaDoc stmt = null;
388         ResultSet JavaDoc rs = null;
389
390         final String JavaDoc selectFields = "id," +
391                                     "left_oid," +
392                                     "right_oid," +
393                                     "type," +
394                                     "status," +
395                                     "creation_date," +
396                                     "creation_user," +
397                                     "lastmodif_date," +
398                                     "lastmodif_user";
399
400         try {
401             String JavaDoc sqlQuery = "SELECT " +
402                               selectFields +
403                               " FROM jahia_link ORDER BY right_oid ";
404
405             dbConn = org.jahia.services.database.ConnectionDispenser.getConnection();
406             stmt = dbConn.prepareStatement(sqlQuery);
407             // rs can't be null (cf. api)
408
rs = stmt.executeQuery();
409
410             while (rs.next()) {
411                 int id = rs.getInt("id");
412                 String JavaDoc leftOID = rs.getString("left_oid");
413                 String JavaDoc rightOID = rs.getString("right_oid");
414                 String JavaDoc type = rs.getString("type");
415                 int status = rs.getInt("status");
416                 Timestamp JavaDoc creationDate = rs.getTimestamp("creation_date");
417                 String JavaDoc creationUserKey = rs.getString("creation_user");
418                 Timestamp JavaDoc lastModificationDate = rs.getTimestamp(
419                     "lastmodif_date");
420                 String JavaDoc lastModificationUserKey = rs.getString("lastmodif_user");
421                 try {
422                     ObjectKey objKey = ObjectKey.getInstance(rightOID);
423                     ObjectLink objLink = new ObjectLink(id,
424                                              ObjectKey.getInstance(leftOID),
425                                              objKey,
426                                              type,
427                                              status,
428                                              creationDate, creationUserKey,
429                                              lastModificationDate,
430                                              lastModificationUserKey,
431                                              new HashMap JavaDoc(),
432                                              new HashMap JavaDoc(), new HashMap JavaDoc());
433                     if (objKey != null && objLink != null) {
434                         synchronized(crossRefTable){
435                             Set JavaDoc set = new TreeSet JavaDoc(new ObjectKeyComparator());
436                             set.addAll((Set JavaDoc)crossRefTable.get(objKey));
437                             set.add(objLink.getLeftObjectKey());
438                             crossRefTable.put(objKey, set);
439                             count++;
440                         }
441                     }
442                 } catch (ClassNotFoundException JavaDoc cnfe) {
443                     logger.error("Couldn't create instance of an ObjectKey", cnfe);
444                 }
445             }
446
447         } catch (SQLException JavaDoc se) {
448             throw new JahiaException(
449                 "Error preloading object cross reference from the database",
450                 se.getMessage(),
451                 JahiaException.DATABASE_ERROR,
452                 JahiaException.ERROR_SEVERITY, se);
453         } finally {
454             try {
455                 logger.info("Preloding Object Links, has loaded " + count + " entries in cache");
456                 if (stmt != null)
457                     stmt.close();
458             } catch (SQLException JavaDoc ex) {
459                 throw new JahiaException("Cannot free resources",
460                                          "Cannot free resources",
461                                          JahiaException.DATABASE_ERROR,
462                                          JahiaException.WARNING_SEVERITY, ex);
463             }
464         }
465     }
466
467     public void preloadObjectXRefsByRefObjectKey(ObjectKey refObjectKey)
468         throws JahiaException {
469
470         if ( Jahia.getSettings().isDb_support_embedded_select_statement() ){
471             synchronized (crossRefTable) {
472                 if (refObjectKey == null ||
473                     preloadedObjectLinkByRefObjectCache.containsKey(
474                     refObjectKey)) {
475                     return;
476                 }
477
478                 logger.info("Preloading Object links for ref object " +
479                             refObjectKey
480                             + " in cache");
481
482                 int count = 0;
483                 Connection JavaDoc dbConn = null;
484                 PreparedStatement JavaDoc stmt = null;
485                 ResultSet JavaDoc rs = null;
486
487                 final String JavaDoc selectFields = "id," +
488                     "left_oid," +
489                     "right_oid," +
490                     "type," +
491                     "status," +
492                     "creation_date," +
493                     "creation_user," +
494                     "lastmodif_date," +
495                     "lastmodif_user";
496
497                 try {
498                     String JavaDoc sqlQuery = "SELECT " + selectFields + " FROM jahia_link WHERE right_oid IN (SELECT DISTINCT right_oid FROM jahia_link WHERE left_oid=?) ORDER BY right_oid ";
499
500                     dbConn = org.jahia.services.database.ConnectionDispenser.
501                         getConnection();
502                     stmt = dbConn.prepareStatement(sqlQuery);
503                     stmt.setString(1, refObjectKey.toString());
504                     // rs can't be null (cf. api)
505
rs = stmt.executeQuery();
506                     Set JavaDoc set = null;
507                     ObjectKey currKey = null;
508                     while (rs.next()) {
509                         int id = rs.getInt("id");
510                         String JavaDoc leftOID = rs.getString("left_oid");
511                         String JavaDoc rightOID = rs.getString("right_oid");
512                         String JavaDoc type = rs.getString("type");
513                         int status = rs.getInt("status");
514                         Timestamp JavaDoc creationDate = rs.getTimestamp(
515                             "creation_date");
516                         String JavaDoc creationUserKey = rs.getString("creation_user");
517                         Timestamp JavaDoc lastModificationDate = rs.getTimestamp(
518                             "lastmodif_date");
519                         String JavaDoc lastModificationUserKey = rs.getString(
520                             "lastmodif_user");
521                         try {
522                             ObjectKey objKey = ObjectKey.getInstance(rightOID);
523                             ObjectLink objLink = new ObjectLink(id,
524                                 ObjectKey.getInstance(leftOID),
525                                 objKey,
526                                 type,
527                                 status,
528                                 creationDate, creationUserKey,
529                                 lastModificationDate,
530                                 lastModificationUserKey,
531                                 new HashMap JavaDoc(),
532                                 new HashMap JavaDoc(), new HashMap JavaDoc());
533                             if (objKey != null) {
534                                 if (objKey.equals(currKey)) {
535                                     if (objLink != null) {
536                                         set.add(objLink.getLeftObjectKey());
537                                     }
538                                 }
539                                 else {
540                                     if (currKey != null) {
541                                         crossRefTable.put(currKey, set);
542                                         count++;
543                                         if (!crossRefTable.containsKey(objKey)) {
544                                             currKey = objKey;
545                                             set = new TreeSet JavaDoc(new
546                                                 ObjectKeyComparator());
547                                             if (objLink != null) {
548                                                 set.add(objLink.
549                                                     getLeftObjectKey());
550                                             }
551                                         }
552                                         else {
553                                             currKey = null;
554                                         }
555                                     }
556                                     else if (!crossRefTable.containsKey(objKey)) {
557                                         set = new TreeSet JavaDoc(new
558                                             ObjectKeyComparator());
559                                         if (objLink != null) {
560                                             set.add(objLink.getLeftObjectKey());
561                                         }
562                                         currKey = objKey;
563                                     }
564                                     else {
565                                         currKey = null;
566                                     }
567                                 }
568                             }
569                         }
570                         catch (ClassNotFoundException JavaDoc cnfe) {
571                             logger.error(
572                                 "Couldn't create instance of an ObjectKey",
573                                 cnfe);
574                         }
575                     }
576
577                 }
578                 catch (SQLException JavaDoc se) {
579                     /*
580                                      throw new JahiaException(
581                          "Error preloading object cross reference from the database",
582                         se.getMessage(),
583                         JahiaException.DATABASE_ERROR,
584                         JahiaException.ERROR_SEVERITY, se);*/

585                     logger.warn("exception ", se);
586                 }
587                 finally {
588                     try {
589                         if (refObjectKey != null) {
590                             preloadedObjectLinkByRefObjectCache.put(
591                                 refObjectKey,
592                                 refObjectKey);
593                         }
594                         logger.info("Preloding Object Links, has loaded " +
595                                     count +
596                                     " entries in cache");
597                         if (stmt != null)
598                             stmt.close();
599                     }
600                     catch (SQLException JavaDoc ex) {
601                         throw new JahiaException("Cannot free resources",
602                                                  "Cannot free resources",
603                                                  JahiaException.DATABASE_ERROR,
604                                                  JahiaException.
605                                                  WARNING_SEVERITY,
606                                                  ex);
607                     }
608                 }
609             }
610         }
611     }
612
613 }
614
Popular Tags