KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jahia > services > acl > AclDBUtils


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   * 06-AUG-2003, Jahia Solutions Sarl: Fulco Houkes
37  *
38  * ----- END LICENSE BLOCK -----
39  */

40
41 package org.jahia.services.acl;
42
43 import java.sql.Connection JavaDoc;
44 import java.sql.PreparedStatement JavaDoc;
45 import java.sql.ResultSet JavaDoc;
46 import java.sql.SQLException JavaDoc;
47 import java.sql.Statement JavaDoc;
48 import java.util.ArrayList JavaDoc;
49 import java.util.Enumeration JavaDoc;
50 import java.util.Hashtable JavaDoc;
51 import java.util.Vector JavaDoc;
52
53 import org.apache.log4j.Logger;
54 import org.jahia.data.JahiaDBDOMObject;
55 import org.jahia.data.JahiaDOMObject;
56 import org.jahia.data.fields.FieldTypes;
57 import org.jahia.exceptions.JahiaException;
58 import org.jahia.exceptions.JahiaInitializationException;
59 import org.jahia.exceptions.database.JahiaDatabaseException;
60 import org.jahia.registries.ServicesRegistry;
61 import org.jahia.services.cache.Cache;
62 import org.jahia.services.cache.CacheFactory;
63 import org.jahia.services.cache.CacheListener;
64 import org.jahia.utils.DBRowDataFilter;
65
66 /**
67  * This is a static class providing the necessary database utilities used by
68  * the ACL Manager Service. This class is a singelton and only one instance
69  * can be obtained throught the <code>getInstance()</code> method.
70  *
71  * @author Fulco Houkes
72  * @author MAP
73  * @version 1.1
74  */

75 class AclDBUtils implements ACLInfo, CacheListener {
76     protected static Logger logger = Logger.getLogger (AclDBUtils.class);
77
78     /** Jahia acl database table name */
79     private static String JavaDoc JAHIA_ACL = "jahia_acl";
80
81     /** acl ID field name */
82     private static String JavaDoc FIELD_ACL_ID = "id_jahia_acl";
83
84     /** acl parent ID field name */
85     private static String JavaDoc FIELD_PARENT_ID = "parent_id_jahia_acl";
86
87     /** ACL inheritance field name */
88     private static String JavaDoc FIELD_INHERITANCE = "inheritance_jahia_acl";
89
90     /** Jahia acl entry database table name */
91     private static String JavaDoc JAHIA_ACL_ENTRIES = "jahia_acl_entries";
92
93     /** ACL ID column name of the jahia acl entries table */
94     private static String JavaDoc FIELD_ENTRY_ACL_ID = "id_jahia_acl";
95
96     /** entry target type column name of the jahia acl entries table */
97     private static String JavaDoc FIELD_ENTRY_TYPE = "type_jahia_acl_entries";
98
99     /** entry target key column name of the jahia acl entries table */
100     private static String JavaDoc FIELD_ENTRY_TARGET = "target_jahia_acl_entries";
101
102     /** entry state column name of the jahia acl entries table */
103     private static String JavaDoc FIELD_ENTRY_STATE = "entry_state_jahia_acl_entries";
104
105     /** entry tristate column name of the jahia acl entries table */
106     private static String JavaDoc FIELD_ENTRY_TRISTATE = "entry_trist_jahia_acl_entries";
107
108     private static final int CHUNK_SIZE = 500;
109
110     /** Reference of the unique instance of this object */
111     static private AclDBUtils instance = null;
112
113     // the ACL Entries cache name.
114
public static final String JavaDoc ACL_ENTRIES_CACHE = "ACLEntriesCache";
115
116     Cache cacheACLEntries = null;
117
118     /**
119      * Default constructor
120      *
121      * @throws JahiaDatabaseException
122      */

123     private AclDBUtils ()
124             throws JahiaDatabaseException, JahiaInitializationException {
125
126         // THE CACHE _MUST_ CACHE AN _UNLIMITED_ NUMBER OF ENTRIES!!!
127
// This is set in the JCS configuration file
128
cacheACLEntries = CacheFactory.createCache (ACL_ENTRIES_CACHE);
129         cacheACLEntries.registerListener(this);
130         cacheAllACLEntries ();
131     }
132
133
134     /**
135      * Return the unique instance of this class.
136      *
137      * @return Return the unique instance of this class.
138      */

139     public static synchronized AclDBUtils getInstance () {
140         try {
141             if (instance == null) {
142                 instance = new AclDBUtils ();
143             }
144
145         } catch (JahiaDatabaseException ex) {
146             logger.warn ("!!!!!!! Problem reading ACL entries from database!", ex);
147             return null;
148
149         } catch (JahiaInitializationException ex) {
150             logger.warn ("An initialization occured while dating the ACL Cache Babe! :-/", ex);
151             return null;
152         }
153
154         return instance;
155     }
156
157     public JahiaACL getACL (int aclID) throws JahiaException {
158
159         JahiaACL result = null;
160         // Get a database connection
161
Connection JavaDoc dbConn = org.jahia.services.database.ConnectionDispenser.getConnection ();
162         if (dbConn == null) {
163             return null;
164         }
165         Statement JavaDoc statement = null;
166         StringBuffer JavaDoc query = new StringBuffer JavaDoc ();
167         try {
168             // get aclentriesID
169
statement = dbConn.createStatement ();
170             query.append ("SELECT * ");
171             query.append ("FROM ");
172             query.append (JAHIA_ACL);
173             query.append (" WHERE ");
174             query.append (FIELD_ACL_ID);
175             query.append ("=");
176             query.append (aclID);
177             ResultSet JavaDoc rs = statement.executeQuery (query.toString ());
178             if (rs != null) {
179                 if (rs.next ()) {
180                     int parentID = rs.getInt (FIELD_PARENT_ID);
181                     JahiaACL acl = new JahiaACL (aclID, parentID,
182                             rs.getInt (FIELD_INHERITANCE));
183                     acl.setUserEntries (getACLEntries (aclID, USER_TYPE_ENTRY));
184                     acl.setGroupEntries (getACLEntries (aclID, GROUP_TYPE_ENTRY));
185                     result = acl;
186                 } else {
187                     logger.debug ("ACL " + aclID + " not found in database !");
188                     throw new JahiaException ("ACL " + aclID + " not found in database !", "ACL " + aclID + " not found in database !", JahiaException.ACL_ERROR
189                             , JahiaException.ERROR_SEVERITY);
190                 }
191             }
192         } catch (SQLException JavaDoc ex) {
193             // no exception, the acls are simply not cached...
194
logger.warn ("!!! DB error, can't cache acls : " + ex + ". Query=[" + query + "]",
195                     ex);
196
197         } finally {
198             query = null;
199             closeStatement (statement);
200         }
201         return result;
202     }
203
204     //-------------------------------------------------------------------------
205
// DJ 06/05/02
206
/**
207      * Read all ACLs from the database and construct the JahiaACL tree structure.
208      *
209      * @throws JahiaException when a general failure occured
210      */

211     public void readAllACLs (Cache allACLs) throws JahiaException {
212
213         // Get a database connection
214
Connection JavaDoc dbConn = org.jahia.services.database.ConnectionDispenser.getConnection ();
215         if (dbConn == null) {
216             return;
217         }
218
219         PreparedStatement JavaDoc statement = null;
220         StringBuffer JavaDoc query = new StringBuffer JavaDoc ();
221         try {
222             // get aclentriesID
223
query.append ("SELECT * ");
224             query.append ("FROM ");
225             query.append (JAHIA_ACL);
226             query.append (" ORDER BY ");
227             query.append (FIELD_PARENT_ID);
228             query.append (", ");
229             query.append (FIELD_ACL_ID);
230             statement = dbConn.prepareStatement (query.toString ());
231             ResultSet JavaDoc rs = statement.executeQuery ();
232             // Cache all ACL if possible, otherwise construct relicat
233
Hashtable JavaDoc relicatACL = new Hashtable JavaDoc ();
234             if (rs != null) {
235                 while (rs.next ()) {
236                     int aclID = rs.getInt (FIELD_ACL_ID);
237                     int parentID = rs.getInt (FIELD_PARENT_ID);
238
239                     // Find the parent if exists.
240
JahiaACL parentACL = (JahiaACL) allACLs.get (new Integer JavaDoc (parentID));
241                     if ((parentACL == null) && (parentID > 0)) {
242                         relicatACL.put (new Integer JavaDoc (aclID), new Integer JavaDoc (parentID));
243                     }
244
245                     JahiaACL acl = new JahiaACL (aclID, parentID,
246                             rs.getInt (FIELD_INHERITANCE));
247                     acl.setUserEntries (getACLEntries (aclID, USER_TYPE_ENTRY));
248                     acl.setGroupEntries (getACLEntries (aclID, GROUP_TYPE_ENTRY));
249                     allACLs.put (new Integer JavaDoc (aclID), acl);
250                 }
251             }
252             // Let look about relicat
253
while (!relicatACL.isEmpty ()) {
254                 Enumeration JavaDoc enumeration = relicatACL.keys ();
255                 int rest = relicatACL.size ();
256                 while (enumeration.hasMoreElements ()) {
257                     Integer JavaDoc aclID = (Integer JavaDoc) enumeration.nextElement ();
258                     Integer JavaDoc parentID = (Integer JavaDoc) relicatACL.get (aclID);
259
260                     JahiaACL parentACL = (JahiaACL) allACLs.get (parentID);
261                     // The parent exists now
262
if (parentACL != null) {
263                         JahiaACL acl = (JahiaACL) allACLs.get (aclID);
264                         if (acl != null) {
265                             acl.setParentACL (parentACL, false);
266                         }
267                         relicatACL.remove (aclID);
268                     }
269                     // Test if some ACL are orpheans
270
if (!enumeration.hasMoreElements () && rest == relicatACL.size ()) {
271                         relicatACL.remove (aclID);
272                         logger.debug ("WARNING !!! Parent ACL #" + parentID.toString () +
273                                 " does not exist for ACL #" + aclID.toString ());
274                     }
275                 }
276             }
277             relicatACL = null;
278         } catch (SQLException JavaDoc ex) {
279             logger.warn ("!!! DB error, can't cache acls : " + ex.getMessage () + ". Query=[" +
280                     query + "]", ex);
281             // no exception, the acls are simply not cached...
282
} finally {
283             query = null;
284             closeStatement (statement);
285         }
286     }
287
288     /**
289      * Preloads a certain amount of ACL from the database, using ordered IDs
290      *
291      * @param preloadCount the count of ACLs to preload
292      * @param aclCache the cache in which to preload the ACLs. We will be read
293      * AND writing into this cache.
294      *
295      * @throws JahiaException thrown if there was an error while loading ACLs
296      * from the database.
297      */

298     public void preloadACLs (int preloadCount, Cache aclCache)
299             throws JahiaException {
300
301         // Get a database connection
302
Connection JavaDoc dbConn = org.jahia.services.database.ConnectionDispenser.getConnection ();
303         if (dbConn == null) {
304             return;
305         }
306         PreparedStatement JavaDoc statement = null;
307         StringBuffer JavaDoc query = new StringBuffer JavaDoc ();
308         try {
309             // get aclentriesID
310
query.append ("SELECT * ");
311             query.append ("FROM ");
312             query.append (JAHIA_ACL);
313             query.append (" ORDER BY ");
314             query.append (FIELD_PARENT_ID);
315             query.append (", ");
316             query.append (FIELD_ACL_ID);
317             statement = dbConn.prepareStatement (query.toString ());
318             ResultSet JavaDoc rs = statement.executeQuery ();
319             int resultCount = 0;
320             if (rs != null) {
321                 while (rs.next () && (resultCount < preloadCount)) {
322                     int aclID = rs.getInt (FIELD_ACL_ID);
323                     int parentID = rs.getInt (FIELD_PARENT_ID);
324                     JahiaACL acl = new JahiaACL (aclID, parentID,
325                             rs.getInt (FIELD_INHERITANCE));
326                     acl.setUserEntries (getACLEntries (aclID, USER_TYPE_ENTRY));
327                     acl.setGroupEntries (getACLEntries (aclID, GROUP_TYPE_ENTRY));
328                     aclCache.put (new Integer JavaDoc(aclID), acl);
329                     resultCount++;
330                 }
331             }
332         } catch (SQLException JavaDoc ex) {
333             // no exception, the acls are simply not cached...
334
logger.warn ("!!! DB error, can't cache acls : " + ex + ". Query=[" + query + "]", ex);
335
336         } finally {
337             query = null;
338             closeStatement (statement);
339         }
340     }
341
342     /**
343      * Preloads all page ACL from the database, using ordered IDs
344      *
345      * @param aclCache the cache in which to preload the ACLs. We will be read
346      * AND writing into this cache.
347      *
348      * @throws JahiaException thrown if there was an error while loading ACLs
349      * from the database.
350      */

351     public void preloadPageACLs (Cache aclCache)
352             throws JahiaException {
353
354         logger.debug("Preloading Page ACL");
355
356         // Get a database connection
357
Connection JavaDoc dbConn = org.jahia.services.database.ConnectionDispenser.getConnection ();
358         if (dbConn == null) {
359             return;
360         }
361         int count = 0;
362         PreparedStatement JavaDoc statement = null;
363         StringBuffer JavaDoc query = new StringBuffer JavaDoc ();
364         try {
365             query.append ("SELECT DISTINCT b.id_jahia_acl, b.parent_id_jahia_acl, b.inheritance_jahia_acl ");
366             query.append ("FROM jahia_pages_data a, jahia_acl b ");
367             query.append ("WHERE (a.rights_jahia_pages_data=b.id_jahia_acl)");
368             statement = dbConn.prepareStatement (query.toString ());
369             ResultSet JavaDoc rs = statement.executeQuery ();
370
371             if (rs != null) {
372                 while (rs.next()) {
373                     int aclID = rs.getInt(1);
374                     int parentID = rs.getInt (2);
375                     if ( !aclCache.containsKey(new Integer JavaDoc(aclID)) ){
376                         JahiaACL acl = new JahiaACL(aclID, parentID,
377                             rs.getInt(3));
378                         acl.setUserEntries(getACLEntries(aclID, USER_TYPE_ENTRY));
379                         acl.setGroupEntries(getACLEntries(aclID,
380                             GROUP_TYPE_ENTRY));
381                         aclCache.put(new Integer JavaDoc(aclID), acl);
382                         count++;
383                     }
384                 }
385             }
386         } catch (SQLException JavaDoc ex) {
387             // no exception, the acls are simply not cached...
388
logger.warn ("!!! DB error, can't cache acls : " + ex + ". Query=[" + query + "]", ex);
389
390         } finally {
391             logger.debug("preloading Page ACL, has loaded " + count + " ACLs in cache");
392             query = null;
393             closeStatement (statement);
394         }
395     }
396
397     /**
398      * Preloads all page fields ACL from the database, using ordered IDs
399      *
400      * @param aclCache the cache in which to preload the ACLs. We will be read
401      * AND writing into this cache.
402      *
403      * @throws JahiaException thrown if there was an error while loading ACLs
404      * from the database.
405      */

406     public void preloadPageFieldACLs (Cache aclCache)
407             throws JahiaException {
408
409         logger.debug("Preloading Page Field ACL");
410
411         // Get a database connection
412
Connection JavaDoc dbConn = org.jahia.services.database.ConnectionDispenser.getConnection ();
413         if (dbConn == null) {
414             return;
415         }
416         int count = 0;
417         PreparedStatement JavaDoc statement = null;
418         StringBuffer JavaDoc query = new StringBuffer JavaDoc ();
419         try {
420             query.append ("SELECT DISTINCT b.id_jahia_acl, b.parent_id_jahia_acl, b.inheritance_jahia_acl ");
421             query.append ("FROM jahia_fields_data a, jahia_acl b ");
422             query.append ("WHERE (a.type_jahia_fields_data=");
423             query.append (FieldTypes.PAGE);
424             query.append(" AND a.rights_jahia_fields_data=b.id_jahia_acl)");
425             statement = dbConn.prepareStatement (query.toString ());
426             ResultSet JavaDoc rs = statement.executeQuery ();
427
428             if (rs != null) {
429                 while (rs.next()) {
430                     int aclID = rs.getInt (1);
431                     int parentID = rs.getInt (2);
432                     if ( !aclCache.containsKey(new Integer JavaDoc(aclID)) ){
433                         JahiaACL acl = new JahiaACL(aclID, parentID,
434                             rs.getInt(3));
435                         acl.setUserEntries(getACLEntries(aclID, USER_TYPE_ENTRY));
436                         acl.setGroupEntries(getACLEntries(aclID,
437                             GROUP_TYPE_ENTRY));
438                         aclCache.put(new Integer JavaDoc(aclID), acl);
439                         count++;
440                     }
441                 }
442             }
443         } catch (SQLException JavaDoc ex) {
444             // no exception, the acls are simply not cached...
445
logger.warn ("!!! DB error, can't cache acls : " + ex + ". Query=[" + query + "]", ex);
446
447         } finally {
448             logger.debug("preloading Page Field ACL, has loaded " + count + " ACLs in cache");
449             query = null;
450             closeStatement (statement);
451         }
452     }
453
454     /**
455      * Preloads all container list ACL from the database, using ordered IDs
456      *
457      * @param aclCache the cache in which to preload the ACLs. We will be read
458      * AND writing into this cache.
459      *
460      * @throws JahiaException thrown if there was an error while loading ACLs
461      * from the database.
462      */

463     public void preloadContainerListACLs (Cache aclCache)
464             throws JahiaException {
465
466         logger.debug("Preloading Container List ACL");
467
468         // Get a database connection
469
Connection JavaDoc dbConn = org.jahia.services.database.ConnectionDispenser.getConnection ();
470         if (dbConn == null) {
471             return;
472         }
473         int count = 0;
474         PreparedStatement JavaDoc statement = null;
475         StringBuffer JavaDoc query = new StringBuffer JavaDoc ();
476         try {
477             query.append ("SELECT DISTINCT b.id_jahia_acl, b.parent_id_jahia_acl, b.inheritance_jahia_acl ");
478             query.append ("FROM jahia_ctn_lists a, jahia_acl b ");
479             query.append ("WHERE (a.rights_jahia_ctn_lists=b.id_jahia_acl)");
480             statement = dbConn.prepareStatement (query.toString ());
481             ResultSet JavaDoc rs = statement.executeQuery ();
482
483             if (rs != null) {
484                 while (rs.next()) {
485                     int aclID = rs.getInt (1);
486                     int parentID = rs.getInt (2);
487                     if ( !aclCache.containsKey(new Integer JavaDoc(aclID)) ){
488                         JahiaACL acl = new JahiaACL(aclID, parentID,
489                             rs.getInt(3));
490                         acl.setUserEntries(getACLEntries(aclID, USER_TYPE_ENTRY));
491                         acl.setGroupEntries(getACLEntries(aclID,
492                             GROUP_TYPE_ENTRY));
493                         aclCache.put(new Integer JavaDoc(aclID), acl);
494                         count++;
495                     }
496                 }
497             }
498         } catch (SQLException JavaDoc ex) {
499             // no exception, the acls are simply not cached...
500
logger.warn ("!!! DB error, can't cache acls : " + ex + ". Query=[" + query + "]", ex);
501
502         } finally {
503             logger.debug("preloading Container List ACL, has loaded " + count + " ACLs in cache");
504             query = null;
505             closeStatement (statement);
506         }
507     }
508
509     /**
510      * Preloads Container ACLs from database for a given page
511      *
512      * @param pageID, the pageID
513      * @param aclCache the cache in which to preload the ACLs. We will be read
514      * AND writing into this cache.
515      *
516      * @throws JahiaException thrown if there was an error while loading ACLs
517      * from the database.
518      */

519     public synchronized void preloadContainerACLsByPage (int pageID,
520         Cache aclCache) throws JahiaException {
521         logger.debug("Preloading Container ACL of page " + pageID);
522         // Get a database connection
523
Connection JavaDoc dbConn = org.jahia.services.database.ConnectionDispenser.getConnection ();
524         if (dbConn == null || pageID<1) {
525             return;
526         }
527         int count = 0;
528         PreparedStatement JavaDoc statement = null;
529         StringBuffer JavaDoc query = new StringBuffer JavaDoc ();
530         try {
531             // get aclentriesID
532
query.append ("SELECT DISTINCT b.id_jahia_acl, b.parent_id_jahia_acl, b.inheritance_jahia_acl ");
533             query.append ("FROM jahia_ctn_entries a, jahia_acl b ");
534             query.append ("WHERE (a.pageid_jahia_ctn_entries=?");
535             query.append(" AND a.rights_jahia_ctn_entries=b.id_jahia_acl)");
536             statement = dbConn.prepareStatement (query.toString ());
537             statement.setInt(1, pageID);
538             ResultSet JavaDoc rs = statement.executeQuery ();
539
540             if (rs != null) {
541                 while (rs.next()) {
542                     int aclID = rs.getInt (1);
543                     int parentID = rs.getInt (2);
544                     if ( !aclCache.containsKey(new Integer JavaDoc(aclID)) ){
545                         JahiaACL acl = new JahiaACL(aclID, parentID,
546                             rs.getInt(3));
547                         acl.setUserEntries(getACLEntries(aclID, USER_TYPE_ENTRY));
548                         acl.setGroupEntries(getACLEntries(aclID,
549                             GROUP_TYPE_ENTRY));
550                         aclCache.put( new Integer JavaDoc(aclID), acl);
551                         count++;
552                     }
553                 }
554             }
555         } catch (SQLException JavaDoc ex) {
556             // no exception, the acls are simply not cached...
557
logger.warn ("!!! DB error, can't cache acls : " + ex + ". Query=[" + query + "]", ex);
558
559         } finally {
560             logger.debug("preloading Container ACL for page " + pageID + " has loaded " + count + " ACLs in cache");
561             query = null;
562             closeStatement (statement);
563         }
564     }
565
566     /**
567      * Preloads field ACLs from database for a given page
568      *
569      * @param pageID, the page ID
570      * @param aclCache the cache in which to preload the ACLs. We will be read
571      * AND writing into this cache.
572      *
573      * @throws JahiaException thrown if there was an error while loading ACLs
574      * from the database.
575      */

576     public synchronized void preloadFieldACLsByPage (int pageID,
577         Cache aclCache) throws JahiaException {
578
579         logger.debug("Preloading Field ACL of page " + pageID);
580
581         // Get a database connection
582
Connection JavaDoc dbConn = org.jahia.services.database.ConnectionDispenser.getConnection ();
583         if (dbConn == null && pageID<1) {
584             return;
585         }
586         int count = 0;
587         PreparedStatement JavaDoc statement = null;
588         StringBuffer JavaDoc query = new StringBuffer JavaDoc ();
589         try {
590             // get aclentriesID
591
query.append ("SELECT DISTINCT b.id_jahia_acl, b.parent_id_jahia_acl, b.inheritance_jahia_acl ");
592             query.append ("FROM jahia_fields_data a, jahia_acl b ");
593             query.append ("WHERE (a.pageid_jahia_fields_data=?");
594             query.append(" AND a.rights_jahia_fields_data=b.id_jahia_acl)");
595             statement = dbConn.prepareStatement (query.toString ());
596             statement.setInt(1, pageID);
597             ResultSet JavaDoc rs = statement.executeQuery ();
598             if (rs != null) {
599                 while (rs.next()) {
600                     int aclID = rs.getInt (1);
601                     int parentID = rs.getInt (2);
602                     if ( !aclCache.containsKey(new Integer JavaDoc(aclID)) ){
603                         JahiaACL acl = new JahiaACL(aclID, parentID,
604                             rs.getInt(3));
605                         acl.setUserEntries(getACLEntries(aclID, USER_TYPE_ENTRY));
606                         acl.setGroupEntries(getACLEntries(aclID,
607                             GROUP_TYPE_ENTRY));
608                         aclCache.put(new Integer JavaDoc(aclID), acl);
609                     }
610                 }
611             }
612         } catch (SQLException JavaDoc ex) {
613             // no exception, the acls are simply not cached...
614
logger.warn ("!!! DB error, can't cache acls : " + ex + ". Query=[" + query + "]", ex);
615
616         } finally {
617             logger.debug("preloading Field ACL for page " + pageID + " has loaded " + count + " ACLs in cache");
618             query = null;
619             closeStatement (statement);
620         }
621     }
622
623     //-------------------------------------------------------------------------
624
// FH 4 Apr. 2001
625
/**
626      * Add an ACL entry in the database.
627      *
628      * @param aclID ACL's indentification number.
629      * @param typeID Entry type. See constants defined int <code>ACLInfo</code>.
630      * @param targetID Identification of the target to which the entry has to be applied.
631      * Basically this is the user or group identification key or the IP
632      * number.
633      * @param state ACL entry permissions state.
634      * @param tristate ACL entry permissions tristate.
635      *
636      * @return Return <code>true</code> on success.
637      *
638      * @throws JahiaDatabaseException Throws this error on any database failure.
639      */

640     public boolean addACLEntry (int aclID, int typeID, String JavaDoc targetID,
641                                 int state, int tristate)
642             throws JahiaDatabaseException {
643
644
645         StringBuffer JavaDoc query = new StringBuffer JavaDoc ();
646         query.append ("INSERT INTO ");
647         query.append (JAHIA_ACL_ENTRIES);
648         query.append (" (");
649         query.append (FIELD_ENTRY_ACL_ID);
650         query.append (",");
651         query.append (FIELD_ENTRY_TYPE);
652         query.append (",");
653         query.append (FIELD_ENTRY_TARGET);
654         query.append ("," + FIELD_ENTRY_STATE);
655         query.append (",");
656         query.append (FIELD_ENTRY_TRISTATE);
657         query.append (")");
658         query.append (" VALUES (");
659         query.append (aclID);
660         query.append (",");
661         query.append (typeID);
662         query.append (",'");
663         query.append (targetID);
664         query.append ("',");
665         query.append (state);
666         query.append (",");
667         query.append (tristate);
668         query.append (")");
669
670         boolean result = makeQuery (query.toString ());
671         if (result) {
672             JahiaACLEntry entry = new JahiaACLEntry (state, tristate);
673             Hashtable JavaDoc cachedType = null;
674             Hashtable JavaDoc cachedACL = (Hashtable JavaDoc) cacheACLEntries.get (new Integer JavaDoc (aclID));
675             if (cachedACL == null) {
676                 cachedACL = new Hashtable JavaDoc ();
677                 cacheACLEntries.put (new Integer JavaDoc(aclID), cachedACL);
678             }
679             cachedType = (Hashtable JavaDoc) cachedACL.get (new Integer JavaDoc (typeID));
680             if (cachedType == null) {
681                 cachedType = new Hashtable JavaDoc ();
682                 cachedACL.put (new Integer JavaDoc (typeID), cachedType);
683             }
684             cachedType.put (targetID, entry);
685         }
686         query = null;
687         return result;
688     }
689
690
691     //-------------------------------------------------------------------------
692
// FH 4 Apr. 2001
693
/**
694      * Add an ACL entry into the database.
695      *
696      * @param aclID ACL's indentification number.
697      * @param typeID Entry type. See constants defined int <code>ACLInfo</code>.
698      * @param targetID Identification of the target to which the entry has to be applied.
699      * Basically this is the user or group identification key or the IP
700      * number.
701      * @param state ACL entry permissions state.
702      * @param tristate ACL entry permissions tristate.
703      *
704      * @return Return <code>true</code> on success.
705      *
706      * @throws JahiaDatabaseException Throws this error on any database failure.
707      */

708     public boolean updateACLEntry (int aclID, int typeID, String JavaDoc targetID,
709                                    int state, int tristate)
710             throws JahiaDatabaseException {
711         StringBuffer JavaDoc query = new StringBuffer JavaDoc ("UPDATE ");
712         query.append (JAHIA_ACL_ENTRIES);
713         query.append (" SET ");
714         query.append (FIELD_ENTRY_STATE);
715         query.append ("=");
716         query.append (state);
717         query.append (",");
718         query.append (FIELD_ENTRY_TRISTATE);
719         query.append ("=");
720         query.append (tristate);
721         query.append (" WHERE ((");
722         query.append (FIELD_ENTRY_ACL_ID);
723         query.append ("=");
724         query.append (aclID);
725         query.append (")");
726         query.append (" AND (");
727         query.append (FIELD_ENTRY_TYPE);
728         query.append ("=");
729         query.append (typeID);
730         query.append (")");
731         query.append (" AND (");
732         query.append (FIELD_ENTRY_TARGET);
733         query.append ("='");
734         query.append (targetID);
735         query.append ("'))");
736
737         boolean result = makeQuery (query.toString ());
738         if (result) {
739             JahiaACLEntry entry = new JahiaACLEntry (state, tristate);
740             Hashtable JavaDoc cachedType = null;
741             Hashtable JavaDoc cachedACL = (Hashtable JavaDoc) cacheACLEntries.get (new Integer JavaDoc (aclID));
742             if (cachedACL == null) {
743                 cachedACL = new Hashtable JavaDoc ();
744                 cacheACLEntries.put (new Integer JavaDoc(aclID), cachedACL);
745             }
746             cachedType = (Hashtable JavaDoc) cachedACL.get (new Integer JavaDoc (typeID));
747             if (cachedType == null) {
748                 cachedType = new Hashtable JavaDoc ();
749                 cachedACL.put (new Integer JavaDoc (typeID), cachedType);
750             }
751             cachedType.put (targetID, entry);
752         }
753         query = null;
754         return result;
755     }
756
757
758     //-------------------------------------------------------------------------
759
// FH 4 Apr. 2001
760
/**
761      * Remove the specified ACL entry associated with the specified ACL and
762      * target IDs from the database.
763      *
764      * @param aclID ACL's indentification number.
765      * @param typeID Entry type. See constants defined int <code>ACLInfo</code>.
766      * @param targetID Identification of the target to which the entry has to be applied.
767      * Basically this is the user or group identification key or the IP
768      * number.
769      *
770      * @return Return <code>true</code> on success.
771      *
772      * @throws JahiaDatabaseException Throws this error on any database failure.
773      */

774     public boolean removeACLEntry (int aclID, int typeID, String JavaDoc targetID)
775             throws JahiaDatabaseException {
776         // only do database access if the acl exists in cache, else it shouldn't
777
// exist in the database anyway!
778
Hashtable JavaDoc cachedType = null;
779         Hashtable JavaDoc cachedACL = (Hashtable JavaDoc) cacheACLEntries.get (new Integer JavaDoc (aclID));
780         boolean result = true;
781         if (cachedACL != null) {
782             cachedType = (Hashtable JavaDoc) cachedACL.get (new Integer JavaDoc (typeID));
783             if (cachedType != null) {
784                 StringBuffer JavaDoc query = new StringBuffer JavaDoc ("DELETE FROM ");
785                 query.append (JAHIA_ACL_ENTRIES);
786                 query.append (" WHERE ");
787                 query.append (FIELD_ENTRY_ACL_ID);
788                 query.append ("=");
789                 query.append (aclID);
790                 query.append (" AND ");
791                 query.append (FIELD_ENTRY_TYPE);
792                 query.append ("=");
793                 query.append (typeID);
794                 query.append (" AND ");
795                 query.append (FIELD_ENTRY_TARGET);
796                 query.append ("='");
797                 query.append (targetID);
798                 query.append ("'");
799                 result = makeQuery (query.toString ());
800
801                 if (result) {
802                     cachedType.remove (targetID);
803                 }
804             }
805         }
806         return result;
807     }
808
809
810     //-------------------------------------------------------------------------
811
// FH 4 Apr. 2001
812
/**
813      * Remove all the ACL entries associated with the specified ACL ID and
814      * type.
815      *
816      * @param aclID ACL's indentification number.
817      * @param typeID Entry type. See constants defined int <code>ACLInfo</code>.
818      *
819      * @return Return <code>true</code> on success.
820      *
821      * @throws JahiaDatabaseException Throws this error on any database failure.
822      */

823     public boolean removeACLEntries (int aclID, int typeID)
824             throws JahiaDatabaseException {
825         StringBuffer JavaDoc query = new StringBuffer JavaDoc ("DELETE FROM ");
826         query.append (JAHIA_ACL_ENTRIES);
827         query.append (" WHERE ");
828         query.append (FIELD_ENTRY_ACL_ID);
829         query.append ("=");
830         query.append (aclID);
831         query.append (" AND ");
832         query.append (FIELD_ENTRY_TYPE);
833         query.append ("=");
834         query.append (typeID);
835
836         boolean result = makeQuery (query.toString ());
837         if (result) {
838             Hashtable JavaDoc cachedACL = (Hashtable JavaDoc) cacheACLEntries.get (new Integer JavaDoc (aclID));
839             if (cachedACL != null) {
840                 cachedACL.remove (new Integer JavaDoc (typeID));
841             }
842         }
843         query = null;
844         return result;
845     }
846
847
848     //------------------------------------------------------------------------
849
// FH 4 Apr. 2001
850
/**
851      * Return all the ACL entries associated to the specified ACL ID and having
852      * the specified type.
853      *
854      * @param aclID ACL's indentification number.
855      * @param typeID Entry type. See constants defined int <code>ACLInfo</code>.
856      *
857      * @return Return <code>true</code> on success.
858      */

859     public Hashtable JavaDoc getACLEntries (int aclID, int typeID) {
860         try {
861             // cache might have been flushed, if it's the case let's reload
862
// all the entries.
863
if (cacheACLEntries.isEmpty()) {
864                 cacheAllACLEntries ();
865             }
866         } catch (JahiaDatabaseException jde) {
867             logger.debug ("Error while loading ACL entries for ACL " + aclID,
868                     jde);
869         }
870
871         // it's in cache -> return it!
872
Hashtable JavaDoc aclEntries = (Hashtable JavaDoc) cacheACLEntries.get (new Integer JavaDoc (aclID));
873         if (aclEntries != null) {
874             Hashtable JavaDoc typeEntries = (Hashtable JavaDoc) aclEntries.get (new Integer JavaDoc (typeID));
875             if (typeEntries != null) {
876                 return typeEntries;
877             }
878         } else {
879             /*
880             // not found in cache, let's try to load them from the database.
881             try {
882                 loadACLEntries(aclID);
883                 aclEntries = (Hashtable) cacheACLEntries.get(new Integer(aclID));
884                 if (aclEntries != null) {
885                     Hashtable typeEntries =
886                         (Hashtable) aclEntries.get(new Integer(typeID));
887                     if (typeEntries != null)
888                     {
889                         return typeEntries;
890                     }
891                 }
892             } catch (JahiaDatabaseException jde) {
893                 logger.debug("Error while loading ACL entries for ACL " + aclID, jde);
894             }
895             */

896         }
897         // else it means there is no entry for this aclid/type!
898
return new Hashtable JavaDoc ();
899     }
900
901     private void loadACLEntries (int aclID)
902             throws JahiaDatabaseException {
903
904         // Get a database connection
905
Connection JavaDoc dbConn = org.jahia.services.database.ConnectionDispenser.getConnection ();
906         if (dbConn == null) {
907             throw new JahiaDatabaseException (
908                     "ACL entry loading process could not get a database connection.",
909                     JahiaDatabaseException.CRITICAL_SEVERITY);
910         }
911
912         PreparedStatement JavaDoc statement = null;
913         StringBuffer JavaDoc query = new StringBuffer JavaDoc ();
914         try {
915
916             query = new StringBuffer JavaDoc ();
917             query.append ("SELECT * FROM ");
918             query.append (JAHIA_ACL_ENTRIES);
919             query.append (" WHERE ");
920             query.append (FIELD_ENTRY_ACL_ID);
921             query.append ("=?");
922
923             // get aclentriesID
924
statement = dbConn.prepareStatement (query.toString ());
925             statement.setInt (1, aclID);
926
927             ResultSet JavaDoc rs = statement.executeQuery ();
928             if (rs != null) {
929                 while (rs.next ()) {
930                     String JavaDoc target = rs.getString (FIELD_ENTRY_TARGET);
931                     int state = rs.getInt (FIELD_ENTRY_STATE);
932                     int tristate = rs.getInt (FIELD_ENTRY_TRISTATE);
933                     int id = rs.getInt (FIELD_ENTRY_ACL_ID);
934                     int type = rs.getInt (FIELD_ENTRY_TYPE);
935
936                     JahiaACLEntry entry = new JahiaACLEntry (state, tristate);
937                     Hashtable JavaDoc cachedType = null;
938                     Hashtable JavaDoc cachedACL = (Hashtable JavaDoc) cacheACLEntries.get (new Integer JavaDoc (id));
939                     if (cachedACL == null) {
940                         cachedACL = new Hashtable JavaDoc ();
941                         cacheACLEntries.put (new Integer JavaDoc (id), cachedACL);
942                     }
943
944                     cachedType = (Hashtable JavaDoc) cachedACL.get (new Integer JavaDoc (type));
945                     if (cachedType == null) {
946                         cachedType = new Hashtable JavaDoc ();
947                         cachedACL.put (new Integer JavaDoc (type), cachedType);
948                     }
949
950                     cachedType.put (target, entry);
951                 }
952             }
953
954         } catch (SQLException JavaDoc ex) {
955             throw new JahiaDatabaseException (
956                     "An SQL exception occrued while accessing an ACL entry.",
957                     query.toString (), ex, JahiaDatabaseException.ERROR_SEVERITY);
958         } finally {
959             query = null;
960             closeStatement (statement);
961         }
962     }
963
964     // DJ 05/05/02
965
/**
966      * Cache all the ACL entries from the database. All of them. this is only
967      * possible as there shouldn't be millions of entries in the database
968      * (there is an entry only at points where inheritence is disabled)
969      * If this ever happens (!?) we have to think of a better cache system.
970      *
971      * @throws JahiaDatabaseException Throws this error on any database failure.
972      */

973     private void cacheAllACLEntries ()
974             throws JahiaDatabaseException {
975
976         // Get a database connection
977
Connection JavaDoc dbConn = org.jahia.services.database.ConnectionDispenser.getConnection ();
978         if (dbConn == null) {
979             throw new JahiaDatabaseException (
980                     "ACL entry loading process could not get a database connection.",
981                     JahiaDatabaseException.CRITICAL_SEVERITY);
982         }
983
984         Statement JavaDoc statement = null;
985         StringBuffer JavaDoc query = new StringBuffer JavaDoc ();
986         try {
987             // get aclentriesID
988
statement = dbConn.createStatement ();
989             query.append ("SELECT ");
990             query.append (FIELD_ENTRY_ACL_ID);
991             query.append (" FROM ");
992             query.append (JAHIA_ACL_ENTRIES);
993             query.append (" ORDER BY ");
994             query.append (FIELD_ACL_ID);
995             query.append (" ASC");
996
997             ResultSet JavaDoc rs = statement.executeQuery (query.toString ());
998
999             Vector JavaDoc entries = new Vector JavaDoc ();
1000            if (rs != null) {
1001                while (rs.next ()) {
1002                    entries.add (new Integer JavaDoc (rs.getInt (FIELD_ACL_ID)));
1003                }
1004            }
1005
1006            // cache them, approx. 500 by 500
1007

1008            // why don't we load the whole thing at once ?
1009
int ptr = 0;
1010            while (ptr < entries.size ()) {
1011                query = new StringBuffer JavaDoc ();
1012                query.append ("SELECT * FROM ");
1013                query.append (JAHIA_ACL_ENTRIES);
1014                query.append (" WHERE ");
1015                query.append (FIELD_ENTRY_ACL_ID);
1016                query.append (">=");
1017                query.append ((entries.elementAt (ptr)).toString ());
1018                query.append (" AND ");
1019                query.append (FIELD_ENTRY_ACL_ID);
1020                query.append ("<=");
1021                int max = (ptr + CHUNK_SIZE < entries.size () ?
1022                        ptr + CHUNK_SIZE : entries.size () - 1);
1023                query.append ((entries.elementAt (max)).toString ());
1024
1025                rs = statement.executeQuery (query.toString ());
1026                if (rs != null) {
1027                    while (rs.next ()) {
1028                        String JavaDoc target = rs.getString (FIELD_ENTRY_TARGET);
1029                        int state = rs.getInt (FIELD_ENTRY_STATE);
1030                        int tristate = rs.getInt (FIELD_ENTRY_TRISTATE);
1031                        int id = rs.getInt (FIELD_ENTRY_ACL_ID);
1032                        int type = rs.getInt (FIELD_ENTRY_TYPE);
1033
1034                        JahiaACLEntry entry = new JahiaACLEntry (state, tristate);
1035                        Hashtable JavaDoc cachedType = null;
1036                        Hashtable JavaDoc cachedACL = (Hashtable JavaDoc) cacheACLEntries.get (
1037                                new Integer JavaDoc (id));
1038                        if (cachedACL == null) {
1039                            cachedACL = new Hashtable JavaDoc ();
1040                            cacheACLEntries.put (new Integer JavaDoc (id), cachedACL);
1041                        }
1042
1043                        cachedType = (Hashtable JavaDoc) cachedACL.get (new Integer JavaDoc (type));
1044                        if (cachedType == null) {
1045                            cachedType = new Hashtable JavaDoc ();
1046                            cachedACL.put (new Integer JavaDoc (type), cachedType);
1047                        }
1048
1049                        cachedType.put (target, entry);
1050                    }
1051                }
1052
1053                ptr += CHUNK_SIZE;
1054            }
1055        } catch (SQLException JavaDoc ex) {
1056            throw new JahiaDatabaseException (
1057                    "An SQL exception occrued while accessing an ACL entry.",
1058                    query.toString (), ex, JahiaDatabaseException.ERROR_SEVERITY);
1059        } finally {
1060            query = null;
1061            closeStatement (statement);
1062        }
1063    }
1064
1065    //-------------------------------------------------------------------------
1066
// FH 12 Apr. 2001
1067
/**
1068     * Add all the ACL entries stored in the specified Hashtable into the
1069     * database.
1070     *
1071     * @param aclID Unique identification number of the related ACL object.
1072     * @param typeID Entry type. See constants defined int <code>ACLInfo</code>.
1073     * @param entries Hashtable containing all the entries to store.
1074     *
1075     * @return Return <code>true</code> if the entries could be inserted into the
1076     * database, or <code>false</code> on any error.
1077     *
1078     * @throws JahiaDatabaseException Throw this exception when any error occured while accessing the
1079     * database.
1080     */

1081
1082    public boolean addACLEntries (int aclID, int typeID, Hashtable JavaDoc entries)
1083            throws JahiaDatabaseException {
1084        if (entries == null) {
1085            return false;
1086        }
1087
1088        Enumeration JavaDoc keys = entries.keys ();
1089        while (keys.hasMoreElements ()) {
1090            String JavaDoc key = (String JavaDoc) keys.nextElement ();
1091            JahiaACLEntry entry = (JahiaACLEntry) entries.get (key);
1092
1093            addACLEntry (aclID, typeID, key,
1094                    entry.getState (), entry.getTriState ());
1095        } // while
1096

1097        return true;
1098    }
1099
1100    /**
1101     * Get the direct child (one level down) from a given parent ACL.
1102     *
1103     * @param parentACL_ID The root parent ACL ID.
1104     *
1105     * @return An array list of the direct childs from the given parent ACL.
1106     *
1107     * @throws JahiaDatabaseException
1108     */

1109    public ArrayList JavaDoc getACLDirectChilds (int parentACL_ID)
1110            throws JahiaDatabaseException {
1111        ArrayList JavaDoc aclChilds = new ArrayList JavaDoc ();
1112        Connection JavaDoc dbConn = org.jahia.services.database.ConnectionDispenser.getConnection ();
1113        if (dbConn == null) {
1114            throw new JahiaDatabaseException (
1115                    "ACL entry loading process could not get a database connection.",
1116                    JahiaDatabaseException.CRITICAL_SEVERITY);
1117        }
1118        Statement JavaDoc statement = null;
1119        StringBuffer JavaDoc query = new StringBuffer JavaDoc ();
1120        try {
1121            statement = dbConn.createStatement ();
1122            query.append ("SELECT ");
1123            query.append (FIELD_ACL_ID);
1124            query.append (" FROM ");
1125            query.append (JAHIA_ACL);
1126            query.append (" WHERE ");
1127            query.append (FIELD_PARENT_ID);
1128            query.append ("=");
1129            query.append (parentACL_ID);
1130            ResultSet JavaDoc rs = statement.executeQuery (query.toString ());
1131            while (rs.next ()) {
1132                int child = rs.getInt (FIELD_ACL_ID);
1133                aclChilds.add (new Integer JavaDoc (child));
1134            }
1135        } catch (SQLException JavaDoc ex) {
1136            throw new JahiaDatabaseException (
1137                    "An SQL exception occured while accessing an ACL.",
1138                    query.toString (), ex, JahiaDatabaseException.ERROR_SEVERITY);
1139        } finally {
1140            query = null;
1141            closeStatement (statement);
1142        }
1143        return aclChilds;
1144    }
1145
1146    /**
1147     * Get all childs from a root parent ACL ID.
1148     *
1149     * @param parentACL_ID The root parent ACL ID.
1150     *
1151     * @return an array list OF array list of the direct childs from root parent ID.
1152     *
1153     * @throws JahiaDatabaseException
1154     */

1155    public ArrayList JavaDoc getACLAllChilds (int parentACL_ID)
1156            throws JahiaDatabaseException {
1157
1158        ArrayList JavaDoc aclAllChilds = getACLDirectChilds (parentACL_ID);
1159        int childNb = aclAllChilds.size ();
1160        for (int i = 0; i < childNb; i++) {
1161            aclAllChilds.add (getACLAllChilds (((Integer JavaDoc) aclAllChilds.get (i)).intValue ()));
1162        }
1163        return aclAllChilds;
1164    }
1165
1166    //------------------------------------------------------------------------
1167
// FH 4 Apr. 2001
1168
/**
1169     * Insert the specified ACL into the database.
1170     *
1171     * @param acl Reference to the ACL to be inserted.
1172     *
1173     * @return Return <code>true</code> if the entries could be inserted into the
1174     * database, or <code>false</code> on any error.
1175     *
1176     * @throws JahiaDatabaseException Throw this exception when any error occured while accessing the
1177     * database.
1178     */

1179    public boolean addACLInDB (JahiaACL acl)
1180            throws JahiaDatabaseException {
1181        String JavaDoc parentIDStr = Integer.toString (acl.getParentID ());
1182        StringBuffer JavaDoc query = new StringBuffer JavaDoc ("INSERT INTO ");
1183        query.append (JAHIA_ACL);
1184        query.append (" (");
1185        query.append (FIELD_ACL_ID);
1186        query.append (",");
1187        query.append (FIELD_PARENT_ID);
1188        query.append (",");
1189        query.append (FIELD_INHERITANCE);
1190        query.append (") VALUES (");
1191        query.append (acl.getID ());
1192        query.append (",");
1193        query.append (parentIDStr);
1194        query.append (",");
1195        query.append (Integer.toString (acl.getInheritance ()));
1196        query.append (")");
1197
1198        boolean result = makeQuery (query.toString ());
1199
1200        // Add the user and group entries in the database.
1201
if (result) {
1202            // Add the user entries
1203
result = addACLEntries (acl.getID (), USER_TYPE_ENTRY,
1204                    acl.getAllUserEntries ());
1205            if (result) {
1206                result = addACLEntries (acl.getID (), GROUP_TYPE_ENTRY,
1207                        acl.getAllGroupEntries ());
1208            }
1209
1210            //if (result) {
1211
// result = AddACLEntries (acl.getID(), IP_TYPE_ENTRY,
1212
// acl.getAllIPEntries());
1213
//}
1214
}
1215        query = null;
1216        return result;
1217    }
1218
1219
1220    //------------------------------------------------------------------------
1221
// FH 4 Apr. 2001
1222
/**
1223     * Delete the specified ACL from the database.
1224     *
1225     * @param acl Reference to the ACL to be inserted.
1226     *
1227     * @return Return <code>true</code> if the entries could be inserted into the
1228     * database, or <code>false</code> on any error.
1229     *
1230     * @throws JahiaDatabaseException Throw this exception when any error occured while accessing the
1231     * database.
1232     */

1233    public synchronized boolean deleteACLFromDB (JahiaACL acl)
1234            throws JahiaDatabaseException {
1235        // Get a database connection
1236
Connection JavaDoc dbConn = org.jahia.services.database.ConnectionDispenser.getConnection ();
1237        if (dbConn == null) {
1238            throw new JahiaDatabaseException (
1239                    "ACL deletion process could not get a database connection.",
1240                    JahiaDatabaseException.CRITICAL_SEVERITY);
1241        }
1242
1243        boolean result = false;
1244        Statement JavaDoc statement = null;
1245        StringBuffer JavaDoc query = new StringBuffer JavaDoc ();
1246        try {
1247            statement = dbConn.createStatement ();
1248
1249            // first remove the entries
1250
query.append ("DELETE FROM ");
1251            query.append (JAHIA_ACL_ENTRIES);
1252            query.append (" WHERE ");
1253            query.append (FIELD_ENTRY_ACL_ID);
1254            query.append ("=");
1255            query.append (acl.getID ());
1256
1257            cacheACLEntries.remove (new Integer JavaDoc (acl.getID ()));
1258
1259            statement.executeUpdate (query.toString ());
1260
1261            // clean the string buffer for the next query.
1262
query.delete (0, query.length ());
1263
1264            // then remove the acl itself
1265
query.append ("DELETE FROM ");
1266            query.append (JAHIA_ACL);
1267            query.append (" WHERE ");
1268            query.append (FIELD_ACL_ID);
1269            query.append ("=");
1270            query.append (acl.getID ());
1271
1272            statement.executeUpdate (query.toString ());
1273            acl = null;
1274            result = true;
1275        } catch (SQLException JavaDoc ex) {
1276            throw new JahiaDatabaseException (
1277                    "An SQL exception occured while deleting an ACL.",
1278                    query.toString (), ex, JahiaDatabaseException.ERROR_SEVERITY);
1279        } finally {
1280            query = null;
1281            closeStatement (statement);
1282        }
1283
1284        return result;
1285    }
1286
1287    //-------------------------------------------------------------------------
1288
/**
1289     * Update the ACL parent ID into the database.
1290     *
1291     * @param acl ACL reference to be updated.
1292     *
1293     * @return Return <code>true</code> on success.
1294     *
1295     * @throws JahiaDatabaseException Thows this exception on any database failure.
1296     */

1297    public synchronized boolean updateACL (JahiaACL acl)
1298            throws JahiaDatabaseException {
1299        if (acl == null) {
1300            return false;
1301        }
1302
1303        StringBuffer JavaDoc query = new StringBuffer JavaDoc ("UPDATE ");
1304        query.append (JAHIA_ACL);
1305        query.append (" SET ");
1306        query.append (FIELD_PARENT_ID);
1307        query.append ("=");
1308        query.append (acl.getParentID ());
1309        query.append (",");
1310        query.append (FIELD_INHERITANCE);
1311        query.append ("=");
1312        query.append (acl.getInheritance ());
1313        query.append (" WHERE ");
1314        query.append (FIELD_ACL_ID);
1315        query.append ("=");
1316        query.append (acl.getID ());
1317
1318        boolean result = makeQuery (query.toString ());
1319        query = null;
1320        return result;
1321    }
1322
1323
1324    //-------------------------------------------------------------------------
1325
// FH 4 Apr. 2001
1326
/**
1327     * Remove all the ACL entries associated to the specified user.
1328     *
1329     * @param user_key User unique identification key.
1330     *
1331     * @return Return <code>true</code> on success.
1332     *
1333     * @throws JahiaDatabaseException Thows this exception on any database failure.
1334     */

1335    public synchronized boolean removeACLUserEntries (String JavaDoc user_key)
1336            throws JahiaDatabaseException {
1337        return removeACLEntriesByTarget (user_key, JahiaACL.USER_TYPE_ENTRY);
1338    }
1339
1340
1341    //-------------------------------------------------------------------------
1342
// FH 4 Apr. 2001
1343
/**
1344     * Remove all the ACL entries associated to the specified group.
1345     *
1346     * @param group_key Group unique identification key.
1347     *
1348     * @return Return <code>true</code> on success.
1349     *
1350     * @throws JahiaDatabaseException Thows this exception on any database failure.
1351     */

1352    public synchronized boolean removeACLGroupEntries (String JavaDoc group_key)
1353            throws JahiaDatabaseException {
1354        return removeACLEntriesByTarget (group_key, JahiaACL.GROUP_TYPE_ENTRY);
1355    }
1356
1357
1358    //-------------------------------------------------------------------------
1359
// FH 4 Apr. 2001
1360
/**
1361     * Remove all the ACL entries associated to the specified target name and
1362     * target type. ONLY TO BE CALLED WHEN REMOVING USERS OR GROUPS, BECAUSE
1363     * THE CACHE IS NOT UPDATED.
1364     *
1365     * @param targetName Target name (key)
1366     * @param targetType Target type. See constants defined int <code>ACLInfo</code>.
1367     *
1368     * @return Return <code>true</code> on success.
1369     *
1370     * @throws JahiaDatabaseException Thows this exception on any database failure.
1371     */

1372    private boolean removeACLEntriesByTarget (
1373            String JavaDoc targetName, int targetType)
1374            throws JahiaDatabaseException {
1375
1376        StringBuffer JavaDoc query = new StringBuffer JavaDoc ("DELETE FROM ");
1377        query.append (JAHIA_ACL_ENTRIES);
1378        query.append (" WHERE ");
1379        query.append (FIELD_ENTRY_TYPE);
1380        query.append ("=");
1381        query.append (targetType);
1382        query.append (" AND ");
1383        query.append (FIELD_ENTRY_TARGET);
1384        query.append ("='");
1385        query.append (targetName);
1386        query.append ("'");
1387
1388        boolean result = makeQuery (query.toString ());
1389        query = null;
1390        return result;
1391    }
1392
1393    // NK
1394
/**
1395     * Return a vector containing the acl parents of a list of acl. There is
1396     * no guarantee that the list of ids are unique
1397     *
1398     * @param ids the list of acl ids
1399     *
1400     * @return a vector of acl ids
1401     *
1402     * @throws JahiaException when an general failure occured
1403     */

1404    private Vector JavaDoc getAclParents (Vector JavaDoc ids)
1405            throws JahiaException {
1406
1407
1408        Vector JavaDoc v = new Vector JavaDoc ();
1409
1410        if ((ids == null) || (ids.size () == 0)) {
1411            return v;
1412        }
1413
1414        Connection JavaDoc dbConn = null;
1415        Statement JavaDoc statement = null;
1416
1417        int aclIDMax = getBiggestAclID ();
1418        if (aclIDMax == -1) {
1419            return v;
1420        }
1421
1422        int low = 0;
1423        int high = 0;
1424        Integer JavaDoc I = null;
1425        while (high <= aclIDMax) {
1426            low = high;
1427            high += 5000;
1428
1429            StringBuffer JavaDoc buff = new StringBuffer JavaDoc
1430                    (
1431                            "SELECT DISTINCT id_jahia_acl,parent_id_jahia_acl, inheritance_jahia_acl FROM jahia_acl WHERE id_jahia_acl ");
1432            buff.append (" > ");
1433            buff.append (low);
1434            buff.append (" AND id_jahia_acl <= ");
1435            buff.append (high);
1436
1437            try {
1438                dbConn = org.jahia.services.database.ConnectionDispenser.getConnection ();
1439                statement = dbConn.createStatement ();
1440                if (statement != null) {
1441                    ResultSet JavaDoc rs = statement.executeQuery (buff.toString ());
1442                    if (rs != null) {
1443                        while (rs.next ()) {
1444                            try {
1445                                int aclID = rs.getInt ("id_jahia_acl");
1446                                int parentID = rs.getInt ("parent_id_jahia_acl");
1447
1448                                if (parentID > 0) {
1449                                    if (ids.contains (new Integer JavaDoc (aclID))) {
1450
1451                                        I = new Integer JavaDoc (parentID);
1452                                        if (!v.contains (I)) {
1453                                            v.add (I);
1454                                        }
1455                                    }
1456                                }
1457                            } catch (Throwable JavaDoc t) {
1458                                t.printStackTrace ();
1459                            }
1460                        }
1461                    }
1462                }
1463            } catch (SQLException JavaDoc se) {
1464                String JavaDoc msg = "Cannot load acl from the database.";
1465                logger.warn (msg, se);
1466                throw new JahiaException (msg, se.getMessage (),
1467                        JahiaException.DATABASE_ERROR,
1468                        JahiaException.CRITICAL_SEVERITY, se);
1469            } finally {
1470                closeStatement (statement);
1471            }
1472        }
1473        return v;
1474    }
1475
1476
1477    // NK
1478
/**
1479     * return a DOM document of requested acl.Ensure the ACL list contains unique ids
1480     *
1481     * @param ids the list of acl ids
1482     * @param withParents it true search for alc parent too
1483     *
1484     * @return JahiaDOMObject a DOM representation of this object
1485     *
1486     * @throws JahiaException
1487     */

1488    public JahiaDOMObject getAclsAsDOM (Vector JavaDoc ids, boolean withParents)
1489            throws JahiaException {
1490
1491
1492        JahiaDBDOMObject dom = null;
1493
1494        Connection JavaDoc dbConn = null;
1495        Statement JavaDoc statement = null;
1496
1497        try {
1498
1499
1500            if ((ids == null) || (ids.size () == 0)) {
1501                dom = new JahiaDBDOMObject ();
1502                dom.addTable ("jahia_acl", null);
1503                return dom;
1504            }
1505
1506            // GET ALL PARENTS
1507
Vector JavaDoc v = new Vector JavaDoc ();
1508
1509            if (withParents) {
1510                v.addAll (ids);
1511                Vector JavaDoc aclParents = getAclParents (v);
1512                Vector JavaDoc newAcls = new Vector JavaDoc ();
1513                while (aclParents.size () > 0) {
1514                    newAcls = new Vector JavaDoc ();
1515                    int size = v.size ();
1516                    int size2 = aclParents.size ();
1517                    Integer JavaDoc I = null;
1518                    Integer JavaDoc J = null;
1519                    for (int i = 0; i < size2; i++) {
1520                        boolean isNew = true;
1521                        I = (Integer JavaDoc) aclParents.get (i);
1522                        for (int j = 0; j < size; j++) {
1523                            J = (Integer JavaDoc) v.get (j);
1524                            if (I.intValue () == J.intValue ()) {
1525                                isNew = false;
1526                                break;
1527                            }
1528                        }
1529                        if (isNew) {
1530                            newAcls.add (I);
1531                            v.add (I);
1532                        }
1533                        size = v.size ();
1534                    }
1535                    //v.addAll(newAcls);
1536
aclParents = new Vector JavaDoc ();
1537                    aclParents = getAclParents (newAcls);
1538                }
1539            } else {
1540                v = ids;
1541            }
1542
1543            int aclIDMax = getBiggestAclID ();
1544            if (aclIDMax == -1) {
1545                dom = new JahiaDBDOMObject ();
1546                dom.addTable ("jahia_acl", null);
1547                return dom;
1548            }
1549
1550            AclFilter filter = new AclFilter (v);
1551
1552            dom = new JahiaDBDOMObject ();
1553            int low = 0;
1554            int high = 0;
1555            while (high <= aclIDMax) {
1556                low = high;
1557                high += 5000;
1558                StringBuffer JavaDoc buff = new StringBuffer JavaDoc
1559                        (
1560                                "SELECT DISTINCT id_jahia_acl,parent_id_jahia_acl, inheritance_jahia_acl FROM jahia_acl WHERE id_jahia_acl");
1561                buff.append (" > ");
1562                buff.append (low);
1563                buff.append (" AND id_jahia_acl <= ");
1564                buff.append (high);
1565
1566                try {
1567                    dbConn = org.jahia.services.database.ConnectionDispenser.getConnection ();
1568                    statement = dbConn.createStatement ();
1569                    if (statement != null) {
1570                        ResultSet JavaDoc rs = statement.executeQuery (buff.toString ());
1571                        if (rs != null) {
1572                            dom.addTable ("jahia_acl", rs, filter);
1573                        }
1574                    }
1575                } catch (SQLException JavaDoc se) {
1576                    String JavaDoc msg = "Cannot load acl from the database";
1577                    logger.warn (msg, se);
1578
1579                    throw new JahiaException (msg, se.getMessage (),
1580                            JahiaException.DATABASE_ERROR,
1581                            JahiaException.CRITICAL_SEVERITY, se);
1582                } finally {
1583                    closeStatement (statement);
1584                }
1585            }
1586
1587        } catch (SQLException JavaDoc se) {
1588            String JavaDoc msg = "Cannot load acl from the database";
1589            logger.warn (msg, se);
1590
1591            throw new JahiaException (msg, se.getMessage (),
1592                    JahiaException.DATABASE_ERROR,
1593                    JahiaException.CRITICAL_SEVERITY, se);
1594        }
1595
1596        return dom;
1597    }
1598
1599
1600    // NK
1601
/**
1602     * return a DOM document of requested acl entries
1603     *
1604     * @param ids the list of acl ids
1605     *
1606     * @return JahiaDOMObject a DOM representation of this object
1607     *
1608     * @throws JahiaException
1609     */

1610    public JahiaDOMObject getAclEntriesAsDOM (Vector JavaDoc ids)
1611            throws JahiaException {
1612
1613
1614        JahiaDBDOMObject dom = new JahiaDBDOMObject ();
1615
1616
1617        try {
1618
1619            if (ids == null) {
1620                dom.addTable ("jahia_acl_entries", null);
1621                return dom;
1622            }
1623
1624            Connection JavaDoc dbConn = null;
1625            Statement JavaDoc statement = null;
1626
1627            int aclIDMax = getBiggestAclEntryID ();
1628            if (aclIDMax == -1) {
1629                dom = new JahiaDBDOMObject ();
1630                dom.addTable ("jahia_acl_entries", null);
1631                return dom;
1632            }
1633
1634            AclFilter filter = new AclFilter (ids);
1635
1636            dom = new JahiaDBDOMObject ();
1637            int low = 0;
1638            int high = 0;
1639            while (high <= aclIDMax) {
1640                low = high;
1641                high += 5000;
1642
1643                StringBuffer JavaDoc buff = new StringBuffer JavaDoc (
1644                        "SELECT DISTINCT id_jahia_acl,type_jahia_acl_entries,target_jahia_acl_entries,entry_state_jahia_acl_entries,entry_trist_jahia_acl_entries FROM jahia_acl_entries WHERE id_jahia_acl");
1645                buff.append (" > ");
1646                buff.append (low);
1647                buff.append (" AND id_jahia_acl <= ");
1648                buff.append (high);
1649
1650                try {
1651                    dbConn = org.jahia.services.database.ConnectionDispenser.getConnection ();
1652                    statement = dbConn.createStatement ();
1653                    if (statement != null) {
1654                        ResultSet JavaDoc rs = statement.executeQuery (buff.toString ());
1655                        if (rs != null) {
1656                            dom.addTable ("jahia_acl_entries", rs, filter);
1657                        }
1658                    }
1659                } catch (SQLException JavaDoc se) {
1660                    String JavaDoc msg = "Cannot load acl from the database";
1661                    logger.warn (msg, se);
1662
1663                    throw new JahiaException (msg, se.getMessage (),
1664                            JahiaException.DATABASE_ERROR,
1665                            JahiaException.CRITICAL_SEVERITY, se);
1666
1667                } finally {
1668                    closeStatement (statement);
1669                }
1670            }
1671
1672        } catch (SQLException JavaDoc se) {
1673            String JavaDoc msg = "Cannot load acl from the database";
1674            logger.warn (msg, se);
1675
1676            throw new JahiaException (msg, se.getMessage (),
1677                    JahiaException.DATABASE_ERROR,
1678                    JahiaException.CRITICAL_SEVERITY, se);
1679
1680
1681        }
1682
1683        return dom;
1684
1685    }
1686
1687
1688    // FH 4 Apr. 2001
1689
/**
1690     * Execues and INSERT, UPDATE or DELETE SQL operation. This method should not
1691     * be used with and SELECT operation. This method lock the object on database
1692     * write access.
1693     *
1694     * @param query the SQL operation in qestion.
1695     *
1696     * @return Return <code>true</code> on success.
1697     *
1698     * @throws JahiaDatabaseException Throws this exception on any database failure.
1699     */

1700    public boolean makeQuery (String JavaDoc query)
1701            throws JahiaDatabaseException {
1702        // Get a database connection
1703
Connection JavaDoc dbConn = org.jahia.services.database.ConnectionDispenser.getConnection ();
1704        if (dbConn == null) {
1705            throw new JahiaDatabaseException (
1706                    "ACL SQL query execution process could not get a database connection.",
1707                    JahiaDatabaseException.CRITICAL_SEVERITY);
1708        }
1709
1710        boolean result = false;
1711        Statement JavaDoc statement = null;
1712
1713        try {
1714            statement = dbConn.createStatement ();
1715            if (statement != null) {
1716                synchronized (this) {
1717                    statement.executeUpdate (query);
1718                    result = true;
1719                }
1720            }
1721        } catch (SQLException JavaDoc ex) {
1722            throw new JahiaDatabaseException (
1723                    "An SQL exception occrued while executing an SQL query in the ACL DB Utilities.",
1724                    query, ex, JahiaDatabaseException.ERROR_SEVERITY);
1725        } finally {
1726            closeStatement (statement);
1727        }
1728
1729        return result;
1730    }
1731
1732
1733    /**
1734     * Return the biggest acl id number.
1735     *
1736     * @return int , the biggest acl id number or -1 on error
1737     *
1738     * @throws JahiaDatabaseException Thows this exception on any database failure.
1739     */

1740    public synchronized int getBiggestAclID ()
1741            throws JahiaDatabaseException {
1742        final String JavaDoc MAX_ID = "MaxID";
1743        int val = -1;
1744
1745        Connection JavaDoc connection = org.jahia.services.database.ConnectionDispenser.getConnection ();
1746        if (connection != null) {
1747            Statement JavaDoc statement = null;
1748            StringBuffer JavaDoc query = new StringBuffer JavaDoc ();
1749
1750            try {
1751                query.append ("SELECT MAX(");
1752                query.append (FIELD_ACL_ID);
1753                query.append (") as ");
1754                query.append (MAX_ID);
1755                query.append (" FROM ");
1756                query.append (JAHIA_ACL);
1757
1758                statement = connection.createStatement ();
1759                if (statement != null) {
1760                    ResultSet JavaDoc rs = statement.executeQuery (query.toString ());
1761                    if (rs != null) {
1762                        if (rs.next ()) {
1763                            // get the highest used acl ID
1764
val = rs.getInt (MAX_ID);
1765                        }
1766                    }
1767                }
1768            } catch (SQLException JavaDoc ex) {
1769                throw new JahiaDatabaseException (
1770                        "Could not get the max acl ID",
1771                        query.toString (), ex, JahiaDatabaseException.ERROR_SEVERITY);
1772            } finally {
1773                closeStatement (statement);
1774            }
1775        } else {
1776            throw new JahiaDatabaseException (
1777                    "Could not get a database connection while getting the max acl ID",
1778                    JahiaDatabaseException.CRITICAL_SEVERITY);
1779        }
1780
1781        return val;
1782    }
1783
1784    //-------------------------------------------------------------------------
1785
/**
1786     * Return the biggest acl entry id number.
1787     *
1788     * @return int , the biggest acl entry id number or -1 on error
1789     *
1790     * @throws JahiaDatabaseException Thows this exception on any database failure.
1791     */

1792    public synchronized int getBiggestAclEntryID ()
1793            throws JahiaDatabaseException {
1794        final String JavaDoc MAX_ID = "MaxID";
1795        int val = -1;
1796
1797        Connection JavaDoc connection = org.jahia.services.database.ConnectionDispenser.getConnection ();
1798        if (connection != null) {
1799            Statement JavaDoc statement = null;
1800            StringBuffer JavaDoc query = new StringBuffer JavaDoc ();
1801
1802            try {
1803                query.append ("SELECT MAX(");
1804                query.append (FIELD_ACL_ID);
1805                query.append (") as ");
1806                query.append (MAX_ID);
1807                query.append (" FROM ");
1808                query.append (JAHIA_ACL_ENTRIES);
1809
1810                statement = connection.createStatement ();
1811                if (statement != null) {
1812                    ResultSet JavaDoc rs = statement.executeQuery (query.toString ());
1813                    if (rs != null) {
1814                        if (rs.next ()) {
1815                            // get the highest used acl ID
1816
val = rs.getInt (MAX_ID);
1817                        }
1818                    }
1819                }
1820            } catch (SQLException JavaDoc ex) {
1821                throw new JahiaDatabaseException (
1822                        "Could not get the max acl entry ID",
1823                        query.toString (), ex, JahiaDatabaseException.ERROR_SEVERITY);
1824            } finally {
1825                closeStatement (statement);
1826            }
1827        } else {
1828            throw new JahiaDatabaseException (
1829                    "Could not get a database connection while getting the max acl entry ID",
1830                    JahiaDatabaseException.CRITICAL_SEVERITY);
1831        }
1832
1833        return val;
1834    }
1835
1836    /**
1837     * Return the next available page info ID.
1838     *
1839     * @return Return the next available ACL ID.
1840     *
1841     * @throws JahiaDatabaseException Thows this exception on any database failure.
1842     */

1843    public synchronized int getNextID ()
1844            throws JahiaDatabaseException {
1845        final String JavaDoc MAX_ID = "MaxID";
1846
1847        int counter = -1;
1848
1849        Connection JavaDoc connection = org.jahia.services.database.ConnectionDispenser.getConnection ();
1850        if (connection != null) {
1851            Statement JavaDoc statement = null;
1852            StringBuffer JavaDoc query = new StringBuffer JavaDoc ();
1853
1854            try {
1855                query.append ("SELECT MAX(");
1856                query.append (FIELD_ACL_ID);
1857                query.append (") as ");
1858                query.append (MAX_ID);
1859                query.append (" FROM ");
1860                query.append (JAHIA_ACL);
1861
1862                statement = connection.createStatement ();
1863                if (statement != null) {
1864                    ResultSet JavaDoc rs = statement.executeQuery (query.toString ());
1865                    if (rs != null) {
1866                        if (rs.next ()) {
1867                            // get the highest used page ID
1868
counter = rs.getInt (MAX_ID);
1869
1870                            // increment by one to get the next counter
1871
counter++;
1872                        }
1873                    }
1874                }
1875            } catch (SQLException JavaDoc ex) {
1876                throw new JahiaDatabaseException (
1877                        "Could not get the next ID in the account table",
1878                        query.toString (), ex, JahiaDatabaseException.ERROR_SEVERITY);
1879            } finally {
1880                closeStatement (statement);
1881            }
1882        } else {
1883            throw new JahiaDatabaseException (
1884                    "Could not get a database connection while getting the next available account ID",
1885                    JahiaDatabaseException.CRITICAL_SEVERITY);
1886        }
1887
1888        return counter;
1889    }
1890
1891
1892    // FH 4 Apr. 2001
1893
/**
1894     * Close he specified SQL statement.
1895     *
1896     * @param statement Reference to the statement to close.
1897     */

1898    private void closeStatement (Statement JavaDoc statement) {
1899        // Close the opened statement
1900
try {
1901            if (statement != null) {
1902                statement.close ();
1903            }
1904
1905        } catch (SQLException JavaDoc sqlEx) {
1906            logger.warn("Cannot close a statement", sqlEx);
1907        }
1908    }
1909
1910    /**
1911     * This method is called each time the cache flushes its items.
1912     *
1913     * @param cacheName the name of the cache which flushed its items.
1914     */

1915    public void onCacheFlush(String JavaDoc cacheName) {
1916        if (ACL_ENTRIES_CACHE.equals(cacheName)) {
1917            try {
1918                cacheACLEntries.flush(false);
1919                cacheAllACLEntries();
1920
1921            } catch (JahiaDatabaseException e) {
1922                logger.warn("Could not reload all ACL Entries after cache flush!", e);
1923            }
1924        }
1925    }
1926
1927    public void onCachePut(String JavaDoc cacheName, Object JavaDoc entryKey) {
1928        // do nothing;
1929
}
1930
1931    class AclFilter implements DBRowDataFilter {
1932
1933        private Vector JavaDoc acls;
1934
1935        public AclFilter (Vector JavaDoc aclList) {
1936            this.acls = aclList;
1937        }
1938
1939        public boolean inValue (Hashtable JavaDoc vals) {
1940            if (vals == null) {
1941                return false;
1942            }
1943
1944            if (acls == null) {
1945                return true;
1946            }
1947            String JavaDoc val = null;
1948            try {
1949                val = (String JavaDoc) vals.get ("id_jahia_acl");
1950                Integer JavaDoc aclID = new Integer JavaDoc (val);
1951                return (acls.contains (aclID));
1952
1953            } catch (Throwable JavaDoc t) {
1954                logger.warn ("Error parsing " + val, t);
1955            }
1956            return false;
1957        }
1958    }
1959
1960}
1961
Popular Tags