001    //$HeadURL: svn+ssh://rbezema@svn.wald.intevation.org/deegree/base/branches/2.2_testing/src/org/deegree/security/drm/SQLRegistry.java $
002    /*----------------    FILE HEADER  ------------------------------------------
003    
004     This file is part of deegree.
005     Copyright (C) 2001-2008 by:
006     EXSE, Department of Geography, University of Bonn
007     http://www.giub.uni-bonn.de/deegree/
008     lat/lon GmbH
009     http://www.lat-lon.de
010    
011     This library is free software; you can redistribute it and/or
012     modify it under the terms of the GNU Lesser General Public
013     License as published by the Free Software Foundation; either
014     version 2.1 of the License, or (at your option) any later version.
015    
016     This library is distributed in the hope that it will be useful,
017     but WITHOUT ANY WARRANTY; without even the implied warranty of
018     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
019     Lesser General Public License for more details.
020    
021     You should have received a copy of the GNU Lesser General Public
022     License along with this library; if not, write to the Free Software
023     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
024    
025     Contact:
026    
027     Andreas Poth
028     lat/lon GmbH
029     Aennchenstr. 19
030     53115 Bonn
031     Germany
032     E-Mail: poth@lat-lon.de
033    
034     Prof. Dr. Klaus Greve
035     Department of Geography
036     University of Bonn
037     Meckenheimer Allee 166
038     53115 Bonn
039     Germany
040     E-Mail: greve@giub.uni-bonn.de
041    
042     ---------------------------------------------------------------------------*/
043    package org.deegree.security.drm;
044    
045    import java.io.BufferedReader;
046    import java.io.IOException;
047    import java.io.InputStreamReader;
048    import java.io.OutputStream;
049    import java.io.OutputStreamWriter;
050    import java.io.Reader;
051    import java.io.StringReader;
052    import java.sql.Clob;
053    import java.sql.Connection;
054    import java.sql.PreparedStatement;
055    import java.sql.ResultSet;
056    import java.sql.ResultSetMetaData;
057    import java.sql.SQLException;
058    import java.sql.Statement;
059    import java.sql.Types;
060    import java.util.ArrayList;
061    import java.util.Properties;
062    
063    import oracle.jdbc.OracleConnection;
064    import oracle.sql.CLOB;
065    
066    import org.deegree.framework.log.ILogger;
067    import org.deegree.framework.log.LoggerFactory;
068    import org.deegree.framework.util.DataBaseIDGenerator;
069    import org.deegree.framework.util.StringTools;
070    import org.deegree.framework.xml.XMLTools;
071    import org.deegree.io.DBConnectionPool;
072    import org.deegree.io.IDGeneratorFactory;
073    import org.deegree.model.filterencoding.AbstractFilter;
074    import org.deegree.model.filterencoding.ComplexFilter;
075    import org.deegree.model.filterencoding.Filter;
076    import org.deegree.model.filterencoding.FilterConstructionException;
077    import org.deegree.security.GeneralSecurityException;
078    import org.deegree.security.drm.model.Group;
079    import org.deegree.security.drm.model.Privilege;
080    import org.deegree.security.drm.model.Right;
081    import org.deegree.security.drm.model.RightType;
082    import org.deegree.security.drm.model.Role;
083    import org.deegree.security.drm.model.SecurableObject;
084    import org.deegree.security.drm.model.SecuredObject;
085    import org.deegree.security.drm.model.User;
086    import org.w3c.dom.Document;
087    import org.w3c.dom.Element;
088    
089    /**
090     * This is an implementation of a <code>Registry</code> using an SQL-Database (via JDBC) as
091     * backend.
092     * 
093     * @author <a href="mailto:mschneider@lat-lon.de">Markus Schneider </a>
094     * @version $Revision: 9346 $
095     */
096    public final class SQLRegistry implements SecurityRegistry {
097    
098        private static final ILogger LOG = LoggerFactory.getLogger( SQLRegistry.class );
099    
100        private String dbDriver;
101    
102        private String dbName;
103    
104        private String dbUser;
105    
106        private String dbPassword;
107    
108        /** Exclusive connection for a transaction (only one at a time). */
109        private Connection transactionalConnection = null;
110    
111        public void clean( SecurityTransaction transaction )
112                                throws GeneralSecurityException {
113    
114            PreparedStatement pstmt = null;
115            try {
116                BufferedReader reader = new BufferedReader(
117                                                            new InputStreamReader(
118                                                                                   SQLRegistry.class.getResourceAsStream( "clean.sql" ) ) );
119                StringBuffer sb = new StringBuffer( 5000 );
120                String line = null;
121                while ( ( line = reader.readLine() ) != null ) {
122                    sb.append( line );
123                }
124                String tmp = sb.toString();
125                String[] commands = StringTools.toArray( tmp, ";", false );
126                for ( int i = 0; i < commands.length; i++ ) {
127                    String command = commands[i].trim();
128                    if ( !command.equals( "" ) ) {
129                        pstmt = transactionalConnection.prepareStatement( command );
130                        pstmt.executeUpdate();
131                        closeStatement( pstmt );
132                        pstmt = null;
133                    }
134                }
135            } catch ( SQLException e ) {
136                LOG.logError( e.getMessage(), e );
137                closeStatement( pstmt );
138                abortTransaction( transaction );
139                throw new GeneralSecurityException( "SQLRegistry.clean() failed. Rollback performed. " + "Error message: "
140                                                    + e.getMessage() );
141            } catch ( IOException e ) {
142                LOG.logError( e.getMessage(), e );
143                throw new GeneralSecurityException( "SQLRegistry.clean() failed. Problem reading sql command file. "
144                                                    + "Error message: " + e.getMessage() );
145            }
146        }
147    
148        /**
149         * Adds a new user account to the <code>Registry</code>.
150         * 
151         * @param transaction
152         * @param name
153         * @throws GeneralSecurityException
154         *             this is a <code>DuplicateException</code> if the group already existed
155         */
156        public User registerUser( SecurityTransaction transaction, String name, String password, String lastName,
157                                  String firstName, String emailAddress )
158                                throws GeneralSecurityException {
159            try {
160                getUserByName( transaction, name );
161                throw new DuplicateException( "Registration of user '" + name + "' failed! A user with "
162                                              + "this name already exists." );
163            } catch ( UnknownException e ) {
164            }
165    
166            User user = new User( getID( transaction, "SEC_SECURABLE_OBJECTS" ), name, password, firstName, lastName,
167                                  emailAddress, this );
168            PreparedStatement pstmt = null;
169    
170            try {
171                pstmt = transactionalConnection.prepareStatement( "INSERT INTO SEC_SECURABLE_OBJECTS (ID,NAME,TITLE) VALUES (?,?,?)" );
172                pstmt.setInt( 1, user.getID() );
173                pstmt.setString( 2, user.getName() );
174                pstmt.setString( 3, user.getTitle() );
175                pstmt.executeUpdate();
176                closeStatement( pstmt );
177                pstmt = null;
178    
179                pstmt = transactionalConnection.prepareStatement( "INSERT INTO SEC_USERS (ID,PASSWORD,FIRSTNAME,LASTNAME,EMAIL) VALUES (?,?,?,?,?)" );
180                pstmt.setInt( 1, user.getID() );
181                pstmt.setString( 2, password );
182                pstmt.setString( 3, user.getFirstName() );
183                pstmt.setString( 4, user.getLastName() );
184                pstmt.setString( 5, user.getEmailAddress() );
185                pstmt.executeUpdate();
186                closeStatement( pstmt );
187            } catch ( SQLException e ) {
188                LOG.logError( e.getMessage(), e );
189                closeStatement( pstmt );
190                abortTransaction( transaction );
191                throw new GeneralSecurityException( "SQLRegistry.registerUser() failed. Rollback performed. "
192                                                    + "Error message: " + e.getMessage() );
193            }
194            return user;
195        }
196    
197        /**
198         * Removes an existing <code>User<code> from the <code>Registry</code>
199         * (including its relations).
200         * 
201         * @param transaction
202         * @param user
203         * @throws GeneralSecurityException
204         */
205        public void deregisterUser( SecurityTransaction transaction, User user )
206                                throws GeneralSecurityException {
207            PreparedStatement pstmt = null;
208    
209            try {
210                pstmt = transactionalConnection.prepareStatement( "DELETE FROM SEC_JT_USERS_GROUPS WHERE FK_USERS=?" );
211                pstmt.setInt( 1, user.getID() );
212                pstmt.executeUpdate();
213                pstmt.close();
214                pstmt = null;
215                pstmt = transactionalConnection.prepareStatement( "DELETE FROM SEC_JT_USERS_ROLES WHERE FK_USERS=?" );
216                pstmt.setInt( 1, user.getID() );
217                pstmt.executeUpdate();
218                pstmt.close();
219                pstmt = null;
220                pstmt = transactionalConnection.prepareStatement( "DELETE FROM SEC_USERS WHERE ID=?" );
221                pstmt.setInt( 1, user.getID() );
222                pstmt.executeUpdate();
223                pstmt.close();
224                pstmt = null;
225                pstmt = transactionalConnection.prepareStatement( "DELETE FROM SEC_JT_ROLES_SECOBJECTS WHERE FK_SECURABLE_OBJECTS=?" );
226                pstmt.setInt( 1, user.getID() );
227                pstmt.executeUpdate();
228                pstmt.close();
229                pstmt = null;
230                pstmt = transactionalConnection.prepareStatement( "DELETE FROM SEC_SECURABLE_OBJECTS WHERE ID=?" );
231                pstmt.setInt( 1, user.getID() );
232                pstmt.executeUpdate();
233                pstmt.close();
234            } catch ( SQLException e ) {
235                LOG.logError( e.getMessage(), e );
236                closeStatement( pstmt );
237                abortTransaction( transaction );
238                throw new GeneralSecurityException( "SQLRegistry.deregisterUser() failed. Rollback performed. "
239                                                    + "Error message: " + e.getMessage() );
240            }
241        }
242    
243        /**
244         * Updates the metadata (name, email, etc.) of a <code>User</code> in the
245         * <code>Registry</code>.
246         * 
247         * @throws GeneralSecurityException
248         *             this is a <code>DuplicateException</code> if a user with the new name already
249         *             existed
250         */
251        public void updateUser( SecurityTransaction transaction, User user )
252                                throws GeneralSecurityException {
253    
254            PreparedStatement pstmt = null;
255    
256            try {
257                pstmt = transactionalConnection.prepareStatement( "UPDATE SEC_SECURABLE_OBJECTS SET NAME=?,TITLE=? WHERE ID=?" );
258                pstmt.setString( 1, user.getName() );
259                pstmt.setString( 2, user.getTitle() );
260                pstmt.setInt( 3, user.getID() );
261                pstmt.executeUpdate();
262                closeStatement( pstmt );
263                pstmt = null;
264    
265                pstmt = transactionalConnection.prepareStatement( "UPDATE SEC_USERS SET PASSWORD=?,FIRSTNAME=?,LASTNAME=?,EMAIL=? WHERE ID=?" );
266                pstmt.setString( 1, user.getPassword() );
267                pstmt.setString( 2, user.getFirstName() );
268                pstmt.setString( 3, user.getLastName() );
269                pstmt.setString( 4, user.getEmailAddress() );
270                pstmt.setInt( 5, user.getID() );
271                pstmt.executeUpdate();
272                closeStatement( pstmt );
273            } catch ( SQLException e ) {
274                LOG.logError( e.getMessage(), e );
275                closeStatement( pstmt );
276                abortTransaction( transaction );
277                throw new GeneralSecurityException( "SQLRegistry.registerUser() failed. Rollback performed. "
278                                                    + "Error message: " + e.getMessage() );
279            }
280        }
281    
282        /**
283         * Retrieves a <code>User</code> from the <code>Registry</code>.
284         * 
285         * @param securityAccess
286         * @param name
287         * @throws GeneralSecurityException
288         *             this is an <code>UnknownException</code> if the user is not known to the
289         *             <code>Registry</code>
290         * 
291         */
292        public User getUserByName( SecurityAccess securityAccess, String name )
293                                throws GeneralSecurityException {
294            User user = null;
295            Connection con = acquireLocalConnection( securityAccess );
296            PreparedStatement pstmt = null;
297            ResultSet rs = null;
298    
299            try {
300                pstmt = con.prepareStatement( "SELECT SEC_USERS.ID,SEC_USERS.PASSWORD,SEC_USERS.FIRSTNAME,SEC_USERS.LASTNAME,SEC_USERS.EMAIL "
301                                              + "FROM SEC_USERS,SEC_SECURABLE_OBJECTS "
302                                              + "WHERE SEC_USERS.ID=SEC_SECURABLE_OBJECTS.ID AND "
303                                              + "SEC_SECURABLE_OBJECTS.NAME=?" );
304                pstmt.setString( 1, name );
305                rs = pstmt.executeQuery();
306                if ( rs.next() ) {
307                    user = new User( rs.getInt( 1 ), name, rs.getString( 2 ), rs.getString( 3 ), rs.getString( 4 ),
308                                     rs.getString( 5 ), this );
309                } else {
310                    throw new UnknownException( "Lookup of user '" + name
311                                                + "' failed! A user with this name does not exist." );
312                }
313            } catch ( SQLException e ) {
314                LOG.logError( e.getMessage(), e );
315                throw new GeneralSecurityException( e );
316            } finally {
317                closeResultSet( rs );
318                closeStatement( pstmt );
319                releaseLocalConnection( securityAccess, con );
320            }
321    
322            return user;
323        }
324    
325        /**
326         * Retrieves a <code>User</code> from the <code>Registry</code>.
327         * 
328         * @param securityAccess
329         * @param id
330         * @throws GeneralSecurityException
331         *             this is an <code>UnknownException</code> if the user is not known to the
332         *             <code>Registry</code>
333         */
334        public User getUserById( SecurityAccess securityAccess, int id )
335                                throws GeneralSecurityException {
336            User user = null;
337            Connection con = acquireLocalConnection( securityAccess );
338            PreparedStatement pstmt = null;
339            ResultSet rs = null;
340    
341            try {
342                pstmt = con.prepareStatement( "SELECT SEC_SECURABLE_OBJECTS.NAME,"
343                                              + "SEC_USERS.PASSWORD,SEC_USERS.FIRSTNAME,SEC_USERS.LASTNAME,"
344                                              + "SEC_USERS.EMAIL FROM SEC_USERS,SEC_SECURABLE_OBJECTS "
345                                              + "WHERE SEC_SECURABLE_OBJECTS.ID=? AND SEC_USERS.ID=SEC_SECURABLE_OBJECTS.ID" );
346                pstmt.setInt( 1, id );
347                rs = pstmt.executeQuery();
348                if ( rs.next() ) {
349                    user = new User( id, rs.getString( 1 ), rs.getString( 2 ), rs.getString( 3 ), rs.getString( 4 ),
350                                     rs.getString( 5 ), this );
351                } else {
352                    throw new UnknownException( "Lookup of user with id: " + id
353                                                + " failed! A user with this id does not exist." );
354                }
355            } catch ( SQLException e ) {
356                throw new GeneralSecurityException( e );
357            } finally {
358                closeResultSet( rs );
359                closeStatement( pstmt );
360                releaseLocalConnection( securityAccess, con );
361            }
362            return user;
363        }
364    
365        /**
366         * Retrieves all <code>User</code> s from the <code>Registry</code>.
367         * 
368         * @param securityAccess
369         * @throws GeneralSecurityException
370         */
371        public User[] getAllUsers( SecurityAccess securityAccess )
372                                throws GeneralSecurityException {
373            ArrayList<User> users = new ArrayList<User>( 500 );
374            Connection con = acquireLocalConnection( securityAccess );
375            PreparedStatement pstmt = null;
376            ResultSet rs = null;
377    
378            try {
379                pstmt = con.prepareStatement( "SELECT SEC_USERS.ID,SEC_SECURABLE_OBJECTS.NAME,SEC_USERS.PASSWORD,SEC_USERS.FIRSTNAME,SEC_USERS.LASTNAME,SEC_USERS.EMAIL "
380                                              + "FROM SEC_USERS,SEC_SECURABLE_OBJECTS "
381                                              + "WHERE SEC_USERS.ID=SEC_SECURABLE_OBJECTS.ID" );
382                rs = pstmt.executeQuery();
383                while ( rs.next() ) {
384                    users.add( new User( rs.getInt( 1 ), rs.getString( 2 ), rs.getString( 3 ), rs.getString( 4 ),
385                                         rs.getString( 5 ), rs.getString( 6 ), this ) );
386                }
387            } catch ( SQLException e ) {
388                LOG.logError( e.getMessage(), e );
389                throw new GeneralSecurityException( e );
390            } finally {
391                closeResultSet( rs );
392                closeStatement( pstmt );
393                releaseLocalConnection( securityAccess, con );
394            }
395            return users.toArray( new User[users.size()] );
396        }
397    
398        /**
399         * Retrieves all <code>Users</code> s from the <code>Registry</code> that are associated
400         * DIRECTLY (i.e. not via group memberships) with a given <code>Role</code>.
401         * 
402         * @param securityAccess
403         * @param role
404         * @throws GeneralSecurityException
405         */
406        public User[] getUsersWithRole( SecurityAccess securityAccess, Role role )
407                                throws GeneralSecurityException {
408            ArrayList<User> users = new ArrayList<User>( 500 );
409            Connection con = acquireLocalConnection( securityAccess );
410            PreparedStatement pstmt = null;
411            ResultSet rs = null;
412    
413            try {
414                pstmt = con.prepareStatement( "SELECT SEC_USERS.ID,SEC_SECURABLE_OBJECTS.NAME,SEC_USERS.PASSWORD,SEC_USERS.FIRSTNAME,SEC_USERS.LASTNAME,"
415                                              + "SEC_USERS.EMAIL "
416                                              + "FROM SEC_USERS,SEC_SECURABLE_OBJECTS,SEC_JT_USERS_ROLES "
417                                              + "WHERE SEC_SECURABLE_OBJECTS.ID=SEC_USERS.ID AND SEC_JT_USERS_ROLES.FK_USERS=SEC_USERS.ID"
418                                              + " AND SEC_JT_USERS_ROLES.FK_ROLES=?" );
419                pstmt.setInt( 1, role.getID() );
420                rs = pstmt.executeQuery();
421                while ( rs.next() ) {
422                    users.add( new User( rs.getInt( 1 ), rs.getString( 2 ), rs.getString( 3 ), rs.getString( 4 ),
423                                         rs.getString( 5 ), rs.getString( 6 ), this ) );
424                }
425            } catch ( SQLException e ) {
426                LOG.logError( e.getMessage(), e );
427                throw new GeneralSecurityException( e );
428            } finally {
429                closeResultSet( rs );
430                closeStatement( pstmt );
431                releaseLocalConnection( securityAccess, con );
432            }
433            return users.toArray( new User[users.size()] );
434        }
435    
436        /**
437         * Retrieves all <code>User</code> s from the <code>Registry</code> that belong to the given
438         * <code>Group</code> DIRECTLY (i.e. not via inheritance).
439         * 
440         * @param securityAccess
441         * @param group
442         * @throws GeneralSecurityException
443         */
444        public User[] getUsersInGroup( SecurityAccess securityAccess, Group group )
445                                throws GeneralSecurityException {
446            ArrayList<User> users = new ArrayList<User>( 500 );
447            Connection con = acquireLocalConnection( securityAccess );
448            PreparedStatement pstmt = null;
449            ResultSet rs = null;
450    
451            try {
452                pstmt = con.prepareStatement( "SELECT SEC_USERS.ID,SEC_SECURABLE_OBJECTS.NAME,SEC_USERS.PASSWORD,SEC_USERS.FIRSTNAME,SEC_USERS.LASTNAME,"
453                                              + "SEC_USERS.EMAIL "
454                                              + "FROM SEC_USERS,SEC_SECURABLE_OBJECTS,SEC_JT_USERS_GROUPS "
455                                              + "WHERE SEC_SECURABLE_OBJECTS.ID=SEC_USERS.ID AND SEC_JT_USERS_GROUPS.FK_USERS=SEC_USERS.ID"
456                                              + " AND SEC_JT_USERS_GROUPS.FK_GROUPS=?" );
457                pstmt.setInt( 1, group.getID() );
458                rs = pstmt.executeQuery();
459                while ( rs.next() ) {
460                    users.add( new User( rs.getInt( 1 ), rs.getString( 2 ), rs.getString( 3 ), rs.getString( 4 ),
461                                         rs.getString( 5 ), rs.getString( 6 ), this ) );
462                }
463            } catch ( SQLException e ) {
464                LOG.logError( e.getMessage(), e );
465                throw new GeneralSecurityException( e );
466            } finally {
467                closeResultSet( rs );
468                closeStatement( pstmt );
469                releaseLocalConnection( securityAccess, con );
470            }
471            return users.toArray( new User[users.size()] );
472        }
473    
474        /**
475         * Adds a new group account to the <code>Registry</code>.
476         * 
477         * 
478         * @param transaction
479         * @param name
480         * @throws GeneralSecurityException
481         *             this is a <code>DuplicateException</code> if the group already existed
482         */
483        public Group registerGroup( SecurityTransaction transaction, String name, String title )
484                                throws GeneralSecurityException {
485            try {
486                getGroupByName( transaction, name );
487                throw new DuplicateException( "Registration of group '" + name + "' failed! A group with "
488                                              + "this name already exists." );
489            } catch ( UnknownException e ) {
490            }
491    
492            Group group = new Group( getID( transaction, "SEC_SECURABLE_OBJECTS" ), name, title, this );
493            PreparedStatement pstmt = null;
494    
495            try {
496                pstmt = transactionalConnection.prepareStatement( "INSERT INTO SEC_SECURABLE_OBJECTS (ID,NAME,TITLE) VALUES (?,?,?)" );
497                pstmt.setInt( 1, group.getID() );
498                pstmt.setString( 2, group.getName() );
499                pstmt.setString( 3, group.getTitle() );
500                pstmt.executeUpdate();
501                pstmt.close();
502                pstmt = null;
503    
504                pstmt = transactionalConnection.prepareStatement( "INSERT INTO SEC_GROUPS (ID) VALUES (?)" );
505                pstmt.setInt( 1, group.getID() );
506                pstmt.executeUpdate();
507                pstmt.close();
508            } catch ( SQLException e ) {
509                LOG.logError( e.getMessage(), e );
510                closeStatement( pstmt );
511                abortTransaction( transaction );
512                throw new GeneralSecurityException( "SQLRegistry.registerGroup() failed. Rollback performed. "
513                                                    + "Error message: " + e.getMessage() );
514            }
515            return group;
516        }
517    
518        /**
519         * Removes an existing <code>Group</code> from the <code>Registry</code> (including its
520         * relations).
521         * 
522         * @param transaction
523         * @param group
524         * @throws GeneralSecurityException
525         */
526        public void deregisterGroup( SecurityTransaction transaction, Group group )
527                                throws GeneralSecurityException {
528            PreparedStatement pstmt = null;
529    
530            try {
531                pstmt = transactionalConnection.prepareStatement( "DELETE FROM SEC_JT_USERS_GROUPS WHERE FK_GROUPS=?" );
532                pstmt.setInt( 1, group.getID() );
533                pstmt.executeUpdate();
534                pstmt.close();
535                pstmt = null;
536                pstmt = transactionalConnection.prepareStatement( "DELETE FROM SEC_JT_GROUPS_GROUPS WHERE FK_GROUPS=? OR FK_GROUPS_MEMBER=?" );
537                pstmt.setInt( 1, group.getID() );
538                pstmt.setInt( 2, group.getID() );
539                pstmt.executeUpdate();
540                pstmt.close();
541                pstmt = null;
542                pstmt = transactionalConnection.prepareStatement( "DELETE FROM SEC_JT_GROUPS_ROLES WHERE FK_GROUPS=?" );
543                pstmt.setInt( 1, group.getID() );
544                pstmt.executeUpdate();
545                pstmt.close();
546                pstmt = null;
547                pstmt = transactionalConnection.prepareStatement( "DELETE FROM SEC_GROUPS WHERE ID=?" );
548                pstmt.setInt( 1, group.getID() );
549                pstmt.executeUpdate();
550                pstmt.close();
551                pstmt = null;
552                pstmt = transactionalConnection.prepareStatement( "DELETE FROM SEC_JT_ROLES_SECOBJECTS WHERE FK_SECURABLE_OBJECTS=?" );
553                pstmt.setInt( 1, group.getID() );
554                pstmt.executeUpdate();
555                pstmt.close();
556                pstmt = null;
557                pstmt = transactionalConnection.prepareStatement( "DELETE FROM SEC_SECURABLE_OBJECTS WHERE ID=?" );
558                pstmt.setInt( 1, group.getID() );
559                pstmt.executeUpdate();
560                pstmt.close();
561                pstmt = null;
562            } catch ( SQLException e ) {
563                LOG.logError( e.getMessage(), e );
564                closeStatement( pstmt );
565                abortTransaction( transaction );
566                throw new GeneralSecurityException( "SQLRegistry.deregisterGroup() failed. Rollback performed. "
567                                                    + "Error message: " + e.getMessage() );
568            }
569        }
570    
571        /**
572         * Retrieves a <code>Group</code> from the <code>Registry</code>.
573         * 
574         * @param securityAccess
575         * @param name
576         * @throws GeneralSecurityException
577         *             this is an <code>UnknownException</code> if the group is not known to the
578         *             <code>Registry</code>
579         */
580        public Group getGroupByName( SecurityAccess securityAccess, String name )
581                                throws GeneralSecurityException {
582            Group group = null;
583            Connection con = acquireLocalConnection( securityAccess );
584            PreparedStatement pstmt = null;
585            ResultSet rs = null;
586    
587            try {
588                pstmt = con.prepareStatement( "SELECT SEC_GROUPS.ID,SEC_SECURABLE_OBJECTS.TITLE "
589                                              + "FROM SEC_GROUPS,SEC_SECURABLE_OBJECTS "
590                                              + "WHERE SEC_GROUPS.ID=SEC_SECURABLE_OBJECTS.ID AND "
591                                              + "SEC_SECURABLE_OBJECTS.NAME=?" );
592                pstmt.setString( 1, name );
593                rs = pstmt.executeQuery();
594                if ( rs.next() ) {
595                    group = new Group( rs.getInt( 1 ), name, rs.getString( 2 ), this );
596                } else {
597                    throw new UnknownException( "Lookup of group '" + name
598                                                + "' failed! A group with this name does not exist." );
599                }
600            } catch ( SQLException e ) {
601                LOG.logError( e.getMessage(), e );
602                throw new GeneralSecurityException( e );
603            } finally {
604                closeResultSet( rs );
605                closeStatement( pstmt );
606                releaseLocalConnection( securityAccess, con );
607            }
608            return group;
609        }
610    
611        /**
612         * Retrieves a <code>Group</code> from the <code>Registry</code>.
613         * 
614         * @param securityAccess
615         * @param id
616         * @throws GeneralSecurityException
617         *             this is an <code>UnknownException</code> if the group is not known to the
618         *             <code>Registry</code>
619         */
620        public Group getGroupById( SecurityAccess securityAccess, int id )
621                                throws GeneralSecurityException {
622            Group group = null;
623            Connection con = acquireLocalConnection( securityAccess );
624            PreparedStatement pstmt = null;
625            ResultSet rs = null;
626    
627            try {
628                pstmt = con.prepareStatement( "SELECT SEC_SECURABLE_OBJECTS.NAME,SEC_SECURABLE_OBJECTS.TITLE "
629                                              + "FROM SEC_GROUPS,SEC_SECURABLE_OBJECTS "
630                                              + "WHERE SEC_SECURABLE_OBJECTS.ID=? AND SEC_GROUPS.ID=SEC_SECURABLE_OBJECTS.ID" );
631                pstmt.setInt( 1, id );
632                rs = pstmt.executeQuery();
633                if ( rs.next() ) {
634                    group = new Group( id, rs.getString( 1 ), rs.getString( 2 ), this );
635                } else {
636                    throw new UnknownException( "Lookup of group with id: " + id
637                                                + " failed! A group with this id does not exist." );
638                }
639            } catch ( SQLException e ) {
640                LOG.logError( e.getMessage(), e );
641                throw new GeneralSecurityException( e );
642            } finally {
643                closeResultSet( rs );
644                closeStatement( pstmt );
645                releaseLocalConnection( securityAccess, con );
646            }
647            return group;
648        }
649    
650        /**
651         * Retrieves all <code>Group</code> s from the <code>Registry</code>.
652         * 
653         * @param securityAccess
654         * @throws GeneralSecurityException
655         */
656        public Group[] getAllGroups( SecurityAccess securityAccess )
657                                throws GeneralSecurityException {
658            ArrayList<Group> groups = new ArrayList<Group>( 50 );
659            Connection con = acquireLocalConnection( securityAccess );
660            PreparedStatement pstmt = null;
661            ResultSet rs = null;
662    
663            try {
664                pstmt = con.prepareStatement( "SELECT SEC_GROUPS.ID,SEC_SECURABLE_OBJECTS.NAME,SEC_SECURABLE_OBJECTS.TITLE "
665                                              + "FROM SEC_GROUPS,SEC_SECURABLE_OBJECTS "
666                                              + "WHERE SEC_GROUPS.ID=SEC_SECURABLE_OBJECTS.ID" );
667                rs = pstmt.executeQuery();
668                while ( rs.next() ) {
669                    groups.add( new Group( rs.getInt( 1 ), rs.getString( 2 ), rs.getString( 3 ), this ) );
670                }
671            } catch ( SQLException e ) {
672                LOG.logError( e.getMessage(), e );
673                throw new GeneralSecurityException( e );
674            } finally {
675                closeResultSet( rs );
676                closeStatement( pstmt );
677                releaseLocalConnection( securityAccess, con );
678            }
679            return groups.toArray( new Group[groups.size()] );
680        }
681    
682        /**
683         * Adds a new role to the <code>Registry</code>.
684         * 
685         * @param transaction
686         * @param name
687         * @throws GeneralSecurityException
688         *             this is a <code>DuplicateException</code> if the role already existed
689         */
690        public Role registerRole( SecurityTransaction transaction, String name )
691                                throws GeneralSecurityException {
692            try {
693                getRoleByName( transaction, name );
694                throw new DuplicateException( "Registration of role '" + name + "' failed! A role with "
695                                              + "this name already exists." );
696            } catch ( UnknownException e ) {
697            }
698    
699            Role role = new Role( getID( transaction, "SEC_SECURABLE_OBJECTS" ), name, this );
700            PreparedStatement pstmt = null;
701    
702            try {
703                pstmt = transactionalConnection.prepareStatement( "INSERT INTO SEC_SECURABLE_OBJECTS (ID,NAME,TITLE) VALUES (?,?,?)" );
704                pstmt.setInt( 1, role.getID() );
705                pstmt.setString( 2, role.getName() );
706                pstmt.setString( 3, role.getTitle() );
707                pstmt.executeUpdate();
708                pstmt.close();
709                pstmt = null;
710    
711                pstmt = transactionalConnection.prepareStatement( "INSERT INTO SEC_ROLES (ID) VALUES (?)" );
712                pstmt.setInt( 1, role.getID() );
713                pstmt.executeUpdate();
714                pstmt.close();
715                pstmt = null;
716            } catch ( SQLException e ) {
717                LOG.logError( e.getMessage(), e );
718                closeStatement( pstmt );
719                abortTransaction( transaction );
720                throw new GeneralSecurityException( "SQLRegistry.registerRole() failed. Rollback performed. "
721                                                    + "Error message: " + e.getMessage() );
722            }
723            return role;
724        }
725    
726        /**
727         * Removes an existing <code>Role</code> from the <code>Registry</code> (including its
728         * relations).
729         * 
730         * @param transaction
731         * @param role
732         * @throws GeneralSecurityException
733         */
734        public void deregisterRole( SecurityTransaction transaction, Role role )
735                                throws GeneralSecurityException {
736            PreparedStatement pstmt = null;
737    
738            try {
739                pstmt = transactionalConnection.prepareStatement( "DELETE FROM SEC_JT_USERS_ROLES WHERE FK_ROLES=?" );
740                pstmt.setInt( 1, role.getID() );
741                pstmt.executeUpdate();
742                pstmt.close();
743                pstmt = null;
744                pstmt = transactionalConnection.prepareStatement( "DELETE FROM SEC_JT_GROUPS_ROLES WHERE FK_ROLES=?" );
745                pstmt.setInt( 1, role.getID() );
746                pstmt.executeUpdate();
747                pstmt.close();
748                pstmt = null;
749                pstmt = transactionalConnection.prepareStatement( "DELETE FROM SEC_JT_ROLES_SECOBJECTS WHERE FK_ROLES=? OR FK_SECURABLE_OBJECTS=?" );
750                pstmt.setInt( 1, role.getID() );
751                pstmt.setInt( 2, role.getID() );
752                pstmt.executeUpdate();
753                pstmt.close();
754                pstmt = null;
755                pstmt = transactionalConnection.prepareStatement( "DELETE FROM SEC_ROLES WHERE ID=?" );
756                pstmt.setInt( 1, role.getID() );
757                pstmt.executeUpdate();
758                pstmt.close();
759                pstmt = null;
760                pstmt = transactionalConnection.prepareStatement( "DELETE FROM SEC_SECURABLE_OBJECTS WHERE ID=?" );
761                pstmt.setInt( 1, role.getID() );
762                pstmt.executeUpdate();
763                pstmt.close();
764                pstmt = null;
765            } catch ( SQLException e ) {
766                LOG.logError( e.getMessage(), e );
767                closeStatement( pstmt );
768                abortTransaction( transaction );
769                throw new GeneralSecurityException( "SQLRegistry.deregisterRole() failed. Rollback performed. "
770                                                    + "Error message: " + e.getMessage() );
771            }
772        }
773    
774        /**
775         * Retrieves a <code>Role</code> from the <code>Registry</code>.
776         * 
777         * @param securityAccess
778         * @param name
779         * @throws GeneralSecurityException
780         *             this is an <code>UnknownException</code> if the role is not known to the
781         *             <code>Registry</code>
782         */
783        public Role getRoleByName( SecurityAccess securityAccess, String name )
784                                throws GeneralSecurityException {
785            Role role = null;
786            Connection con = acquireLocalConnection( securityAccess );
787            PreparedStatement pstmt = null;
788            ResultSet rs = null;
789    
790            try {
791                pstmt = con.prepareStatement( "SELECT SEC_ROLES.ID " + "FROM SEC_ROLES,SEC_SECURABLE_OBJECTS "
792                                              + "WHERE SEC_ROLES.ID=SEC_SECURABLE_OBJECTS.ID AND "
793                                              + "SEC_SECURABLE_OBJECTS.NAME=?" );
794                pstmt.setString( 1, name );
795                rs = pstmt.executeQuery();
796                if ( rs.next() ) {
797                    role = new Role( rs.getInt( 1 ), name, this );
798                } else {
799                    throw new UnknownException( "Lookup of role '" + name
800                                                + "' failed! A role with this name does not exist." );
801                }
802            } catch ( SQLException e ) {
803                LOG.logError( e.getMessage(), e );
804                throw new GeneralSecurityException( e );
805            } finally {
806                closeResultSet( rs );
807                closeStatement( pstmt );
808                releaseLocalConnection( securityAccess, con );
809            }
810            return role;
811        }
812    
813        /**
814         * Retrieves all <code>Roles</code> s from the <code>Registry</code> that have a certain
815         * namespace.
816         * 
817         * @param securityAccess
818         * @param ns
819         *            null for default namespace
820         * @throws GeneralSecurityException
821         */
822        public Role[] getRolesByNS( SecurityAccess securityAccess, String ns )
823                                throws GeneralSecurityException {
824            ArrayList<Role> roles = new ArrayList<Role>( 100 );
825            Connection con = acquireLocalConnection( securityAccess );
826            PreparedStatement pstmt = null;
827            ResultSet rs = null;
828            try {
829                if ( ns != null && ( !ns.equals( "" ) ) ) {
830                    pstmt = con.prepareStatement( "SELECT SEC_ROLES.ID,SEC_SECURABLE_OBJECTS.NAME "
831                                                  + "FROM SEC_ROLES,SEC_SECURABLE_OBJECTS "
832                                                  + "WHERE SEC_SECURABLE_OBJECTS.ID=SEC_ROLES.ID AND SEC_SECURABLE_OBJECTS.NAME LIKE ?" );
833                    pstmt.setString( 1, ns + ":%" );
834                } else {
835                    pstmt = con.prepareStatement( "SELECT SEC_ROLES.ID,SEC_SECURABLE_OBJECTS.NAME "
836                                                  + "FROM SEC_ROLES,SEC_SECURABLE_OBJECTS "
837                                                  + "WHERE SEC_SECURABLE_OBJECTS.ID=SEC_ROLES.ID AND "
838                                                  + "SEC_SECURABLE_OBJECTS.NAME NOT LIKE '%:%'" );
839                }
840    
841                rs = pstmt.executeQuery();
842                while ( rs.next() ) {
843                    roles.add( new Role( rs.getInt( 1 ), rs.getString( 2 ), this ) );
844                }
845            } catch ( SQLException e ) {
846                LOG.logError( e.getMessage(), e );
847                throw new GeneralSecurityException( e );
848            } finally {
849                closeResultSet( rs );
850                closeStatement( pstmt );
851                releaseLocalConnection( securityAccess, con );
852            }
853            return roles.toArray( new Role[roles.size()] );
854        }
855    
856        /**
857         * Retrieves a <code>Role</code> from the <code>Registry</code>.
858         * 
859         * @param securityAccess
860         * @param id
861         * @throws GeneralSecurityException
862         *             this is an <code>UnknownException</code> if the role is not known to the
863         *             <code>Registry</code>
864         */
865        public Role getRoleById( SecurityAccess securityAccess, int id )
866                                throws GeneralSecurityException {
867            Role role = null;
868            Connection con = acquireLocalConnection( securityAccess );
869            PreparedStatement pstmt = null;
870            ResultSet rs = null;
871    
872            try {
873                pstmt = con.prepareStatement( "SELECT SEC_SECURABLE_OBJECTS.NAME "
874                                              + "FROM SEC_ROLES,SEC_SECURABLE_OBJECTS "
875                                              + "WHERE SEC_SECURABLE_OBJECTS.ID=? AND SEC_ROLES.ID=SEC_SECURABLE_OBJECTS.ID" );
876                pstmt.setInt( 1, id );
877                rs = pstmt.executeQuery();
878                if ( rs.next() ) {
879                    role = new Role( id, rs.getString( 1 ), this );
880                } else {
881                    throw new UnknownException( "Lookup of role with id: " + id
882                                                + " failed! A role with this id does not exist." );
883                }
884            } catch ( SQLException e ) {
885                LOG.logError( e.getMessage(), e );
886                throw new GeneralSecurityException( e );
887            } finally {
888                closeResultSet( rs );
889                closeStatement( pstmt );
890                releaseLocalConnection( securityAccess, con );
891            }
892            return role;
893        }
894    
895        /**
896         * Retrieves all <code>Role</code> s from the <code>Registry</code>, except those that are
897         * only used internally (these have namespaces that begin with $).
898         * 
899         * @param securityAccess
900         * @throws GeneralSecurityException
901         */
902        public Role[] getAllRoles( SecurityAccess securityAccess )
903                                throws GeneralSecurityException {
904            ArrayList<Role> roles = new ArrayList<Role>( 50 );
905            Connection con = acquireLocalConnection( securityAccess );
906            PreparedStatement pstmt = null;
907            ResultSet rs = null;
908    
909            try {
910                pstmt = con.prepareStatement( "SELECT SEC_ROLES.ID,SEC_SECURABLE_OBJECTS.NAME "
911                                              + "FROM SEC_ROLES,SEC_SECURABLE_OBJECTS "
912                                              + "WHERE SEC_ROLES.ID=SEC_SECURABLE_OBJECTS.ID AND "
913                                              + "SEC_SECURABLE_OBJECTS.NAME NOT LIKE '$%:%'" );
914                rs = pstmt.executeQuery();
915                while ( rs.next() ) {
916                    roles.add( new Role( rs.getInt( 1 ), rs.getString( 2 ), this ) );
917                }
918            } catch ( SQLException e ) {
919                LOG.logError( e.getMessage(), e );
920                throw new GeneralSecurityException( e );
921            } finally {
922                closeResultSet( rs );
923                closeStatement( pstmt );
924                releaseLocalConnection( securityAccess, con );
925            }
926            return roles.toArray( new Role[roles.size()] );
927        }
928    
929        /**
930         * Adds a new <code>SecuredObject</code> to the <code>Registry</code>.
931         * 
932         * @param transaction
933         * @param type
934         * @param name
935         * @param title
936         * @throws GeneralSecurityException
937         *             this is a <code>DuplicateException</code> if the object already existed
938         */
939        public SecuredObject registerSecuredObject( SecurityTransaction transaction, String type, String name, String title )
940                                throws GeneralSecurityException {
941            try {
942                getSecuredObjectByName( transaction, name, type );
943                throw new DuplicateException( "Registration of secured object '" + name + "' with type '" + type
944                                              + "' failed! A secured object with this name and type " + "already exists." );
945            } catch ( UnknownException e ) {
946            }
947    
948            PreparedStatement pstmt = null;
949            SecuredObject object = null;
950            ResultSet rs = null;
951    
952            try {
953                // check for ID of object type (add type if necessary)
954                int typeId = 0;
955                pstmt = transactionalConnection.prepareStatement( "SELECT ID FROM SEC_SECURED_OBJECT_TYPES WHERE NAME=?" );
956                pstmt.setString( 1, type );
957                rs = pstmt.executeQuery();
958                if ( rs.next() ) {
959                    typeId = rs.getInt( 1 );
960                    rs.close();
961                    rs = null;
962                    pstmt.close();
963                    pstmt = null;
964                } else {
965                    typeId = getID( transaction, "SEC_SECURED_OBJECT_TYPES" );
966                    rs.close();
967                    rs = null;
968                    pstmt.close();
969                    pstmt = null;
970                    pstmt = transactionalConnection.prepareStatement( "INSERT INTO SEC_SECURED_OBJECT_TYPES (ID,NAME) VALUES (?,?)" );
971                    pstmt.setInt( 1, typeId );
972                    pstmt.setString( 2, type );
973                    pstmt.executeUpdate();
974                    pstmt.close();
975                    pstmt = null;
976                }
977    
978                // insert securable object part
979                object = new SecuredObject( getID( transaction, "SEC_SECURABLE_OBJECTS" ), typeId, name, title, this );
980                pstmt = transactionalConnection.prepareStatement( "INSERT INTO SEC_SECURABLE_OBJECTS (ID,NAME,TITLE) VALUES (?,?,?)" );
981                pstmt.setInt( 1, object.getID() );
982                pstmt.setString( 2, object.getName() );
983                pstmt.setString( 3, object.getTitle() );
984                pstmt.executeUpdate();
985                pstmt.close();
986                pstmt = null;
987    
988                // insert secured object
989                pstmt = transactionalConnection.prepareStatement( "INSERT INTO SEC_SECURED_OBJECTS (ID, FK_SECURED_OBJECT_TYPES) VALUES (?,?)" );
990                pstmt.setInt( 1, object.getID() );
991                pstmt.setInt( 2, typeId );
992                pstmt.executeUpdate();
993                pstmt.close();
994                pstmt = null;
995            } catch ( SQLException e ) {
996                LOG.logError( e.getMessage(), e );
997                closeResultSet( rs );
998                closeStatement( pstmt );
999                abortTransaction( transaction );
1000                throw new GeneralSecurityException( "SQLRegistry.registerSecuredObject() failed. Rollback performed. "
1001                                                    + "Error message: " + e.getMessage() );
1002            }
1003            return object;
1004        }
1005    
1006        /**
1007         * Removes an existing <code>SecuredObject</code> from the <code>Registry</code> (including
1008         * its associations).
1009         * 
1010         * @param transaction
1011         * @param object
1012         * @throws GeneralSecurityException
1013         */
1014        public void deregisterSecuredObject( SecurityTransaction transaction, SecuredObject object )
1015                                throws GeneralSecurityException {
1016            PreparedStatement pstmt = null;
1017    
1018            try {
1019                pstmt = transactionalConnection.prepareStatement( "DELETE FROM SEC_SECURED_OBJECTS WHERE ID=?" );
1020                pstmt.setInt( 1, object.getID() );
1021                pstmt.executeUpdate();
1022                pstmt.close();
1023                pstmt = null;
1024                pstmt = transactionalConnection.prepareStatement( "DELETE FROM SEC_JT_ROLES_SECOBJECTS WHERE FK_SECURABLE_OBJECTS=?" );
1025                pstmt.setInt( 1, object.getID() );
1026                pstmt.executeUpdate();
1027                pstmt.close();
1028                pstmt = null;
1029                pstmt = transactionalConnection.prepareStatement( "DELETE FROM SEC_SECURABLE_OBJECTS WHERE ID=?" );
1030                pstmt.setInt( 1, object.getID() );
1031                pstmt.executeUpdate();
1032                pstmt = null;
1033            } catch ( SQLException e ) {
1034                LOG.logError( e.getMessage(), e );
1035                closeStatement( pstmt );
1036                abortTransaction( transaction );
1037                throw new GeneralSecurityException( "SQLRegistry.deregisterSecuredObject() failed. Rollback performed. "
1038                                                    + "Error message: " + e.getMessage() );
1039            }
1040        }
1041    
1042        /**
1043         * Retrieves a <code>SecuredObject</code> from the <code>Registry</code>.
1044         * 
1045         * @param securityAccess
1046         * @param name
1047         * @throws GeneralSecurityException
1048         *             this is an <code>UnknownException</code> if the object is not known to the
1049         *             <code>Registry</code>
1050         */
1051        public SecuredObject getSecuredObjectByName( SecurityAccess securityAccess, String name, String type )
1052                                throws GeneralSecurityException {
1053            SecuredObject object = null;
1054            Connection con = acquireLocalConnection( securityAccess );
1055            PreparedStatement pstmt = null;
1056            ResultSet rs = null;
1057    
1058            try {
1059                pstmt = con.prepareStatement( "SELECT SEC_SECURED_OBJECTS.ID,SEC_SECURED_OBJECT_TYPES.ID, "
1060                                              + "SEC_SECURABLE_OBJECTS.TITLE "
1061                                              + "FROM SEC_SECURED_OBJECTS,SEC_SECURED_OBJECT_TYPES,SEC_SECURABLE_OBJECTS "
1062                                              + "WHERE SEC_SECURED_OBJECTS.FK_SECURED_OBJECT_TYPES=SEC_SECURED_OBJECT_TYPES.ID AND "
1063                                              + "SEC_SECURED_OBJECTS.ID=SEC_SECURABLE_OBJECTS.ID AND SEC_SECURABLE_OBJECTS.NAME LIKE ? AND "
1064                                              + "SEC_SECURED_OBJECT_TYPES.NAME=?" );
1065                pstmt.setString( 1, name );
1066                pstmt.setString( 2, type );
1067                rs = pstmt.executeQuery();
1068                if ( rs.next() ) {
1069                    object = new SecuredObject( rs.getInt( 1 ), rs.getInt( 2 ), name, rs.getString( 3 ), this );
1070                } else {
1071                    throw new UnknownException( "Lookup of secured object '" + name + "' with type '" + type
1072                                                + "' failed! A secured object with this " + "name and type does not exist." );
1073                }
1074            } catch ( SQLException e ) {
1075                LOG.logError( e.getMessage(), e );
1076                throw new GeneralSecurityException( e );
1077            } finally {
1078                closeResultSet( rs );
1079                closeStatement( pstmt );
1080                releaseLocalConnection( securityAccess, con );
1081            }
1082            return object;
1083        }
1084    
1085        /**
1086         * Retrieves a <code>SecuredObject</code> from the <code>Registry</code>.
1087         * 
1088         * @param securityAccess
1089         * @param id
1090         * @throws GeneralSecurityException
1091         *             this is an <code>UnknownException</code> if the object is not known to the
1092         *             <code>Registry</code>
1093         */
1094        public SecuredObject getSecuredObjectById( SecurityAccess securityAccess, int id )
1095                                throws GeneralSecurityException {
1096            SecuredObject object = null;
1097            Connection con = acquireLocalConnection( securityAccess );
1098            PreparedStatement pstmt = null;
1099            ResultSet rs = null;
1100    
1101            try {
1102                pstmt = con.prepareStatement( "SELECT SEC_SECURED_OBJECTS.FK_SECURED_OBJECT_TYPES,SEC_SECURABLE_OBJECTS.NAME,"
1103                                              + "SEC_SECURABLE_OBJECTS.TITLE "
1104                                              + "FROM SEC_SECURED_OBJECTS,SEC_SECURABLE_OBJECTS "
1105                                              + "WHERE SEC_SECURED_OBJECTS.ID=SEC_SECURABLE_OBJECTS.ID AND SEC_SECURABLE_OBJECTS.ID=?" );
1106                pstmt.setInt( 1, id );
1107                rs = pstmt.executeQuery();
1108                if ( rs.next() ) {
1109                    object = new SecuredObject( id, rs.getInt( 1 ), rs.getString( 2 ), rs.getString( 3 ), this );
1110                } else {
1111                    throw new UnknownException( "Lookup of secured object with id: " + id
1112                                                + " failed! A secured object with this id does not exist." );
1113                }
1114            } catch ( SQLException e ) {
1115                LOG.logError( e.getMessage(), e );
1116                throw new GeneralSecurityException( e );
1117            } finally {
1118                closeResultSet( rs );
1119                closeStatement( pstmt );
1120                releaseLocalConnection( securityAccess, con );
1121            }
1122            return object;
1123        }
1124    
1125        /**
1126         * Retrieves all <code>SecuredObject</code> s from the <code>Registry</code> that have a
1127         * certain namespace.
1128         * 
1129         * @param securityAccess
1130         * @param ns
1131         *            null for default namespace
1132         * @param type
1133         * @throws GeneralSecurityException
1134         */
1135        public SecuredObject[] getSecuredObjectsByNS( SecurityAccess securityAccess, String ns, String type )
1136                                throws GeneralSecurityException {
1137            ArrayList<SecuredObject> objects = new ArrayList<SecuredObject>( 100 );
1138            Connection con = acquireLocalConnection( securityAccess );
1139            PreparedStatement pstmt = null;
1140            ResultSet rs = null;
1141            try {
1142                if ( ns != null && ( !ns.equals( "" ) ) ) {
1143                    pstmt = con.prepareStatement( "SELECT SEC_SECURED_OBJECTS.ID,SEC_SECURED_OBJECT_TYPES.ID, "
1144                                                  + "SEC_SECURABLE_OBJECTS.NAME,SEC_SECURABLE_OBJECTS.TITLE "
1145                                                  + "FROM SEC_SECURED_OBJECTS,SEC_SECURED_OBJECT_TYPES,SEC_SECURABLE_OBJECTS "
1146                                                  + "WHERE SEC_SECURED_OBJECTS.FK_SECURED_OBJECT_TYPES=SEC_SECURED_OBJECT_TYPES.ID AND "
1147                                                  + "SEC_SECURABLE_OBJECTS.ID=SEC_SECURED_OBJECTS.ID AND SEC_SECURED_OBJECT_TYPES.NAME=? "
1148                                                  + "AND SEC_SECURABLE_OBJECTS.NAME LIKE ?" );
1149                    pstmt.setString( 1, type );
1150                    pstmt.setString( 2, ns + ":%" );
1151                } else {
1152                    pstmt = con.prepareStatement( "SELECT SEC_SECURED_OBJECTS.ID,SEC_SECURED_OBJECT_TYPES.ID, "
1153                                                  + "SEC_SECURABLE_OBJECTS.NAME,SEC_SECURABLE_OBJECTS.TITLE "
1154                                                  + "FROM SEC_SECURED_OBJECTS,SEC_SECURED_OBJECT_TYPES,SEC_SECURABLE_OBJECTS "
1155                                                  + "WHERE SEC_SECURED_OBJECTS.FK_SECURED_OBJECT_TYPES=SEC_SECURED_OBJECT_TYPES.ID AND "
1156                                                  + "SEC_SECURABLE_OBJECTS.ID=SEC_SECURED_OBJECTS.ID AND SEC_SECURED_OBJECT_TYPES.NAME=? "
1157                                                  + "AND SEC_SECURABLE_OBJECTS.NAME NOT LIKE '%:%'" );
1158                    pstmt.setString( 1, type );
1159                }
1160                rs = pstmt.executeQuery();
1161                while ( rs.next() ) {
1162                    objects.add( new SecuredObject( rs.getInt( 1 ), rs.getInt( 2 ), rs.getString( 3 ), rs.getString( 4 ),
1163                                                    this ) );
1164                }
1165            } catch ( SQLException e ) {
1166                LOG.logError( e.getMessage(), e );
1167                throw new GeneralSecurityException( e );
1168            } finally {
1169                closeResultSet( rs );
1170                closeStatement( pstmt );
1171                releaseLocalConnection( securityAccess, con );
1172            }
1173            return objects.toArray( new SecuredObject[objects.size()] );
1174        }
1175    
1176        /**
1177         * Retrieves all <code>SecuredObject</code> s with the given type from the
1178         * <code>Registry</code>.
1179         * 
1180         * @param securityAccess
1181         * @param type
1182         * @throws GeneralSecurityException
1183         */
1184        public SecuredObject[] getAllSecuredObjects( SecurityAccess securityAccess, String type )
1185                                throws GeneralSecurityException {
1186            ArrayList<SecuredObject> objects = new ArrayList<SecuredObject>( 100 );
1187            Connection con = acquireLocalConnection( securityAccess );
1188            PreparedStatement pstmt = null;
1189            ResultSet rs = null;
1190    
1191            try {
1192                pstmt = con.prepareStatement( "SELECT SEC_SECURED_OBJECTS.ID,SEC_SECURED_OBJECT_TYPES.ID, "
1193                                              + "SEC_SECURABLE_OBJECTS.NAME,SEC_SECURABLE_OBJECTS.TITLE "
1194                                              + "FROM SEC_SECURED_OBJECTS,SEC_SECURED_OBJECT_TYPES,SEC_SECURABLE_OBJECTS "
1195                                              + "WHERE SEC_SECURED_OBJECTS.FK_SECURED_OBJECT_TYPES=SEC_SECURED_OBJECT_TYPES.ID AND "
1196                                              + "SEC_SECURABLE_OBJECTS.ID=SEC_SECURED_OBJECTS.ID AND SEC_SECURED_OBJECT_TYPES.NAME=?" );
1197                pstmt.setString( 1, type );
1198                rs = pstmt.executeQuery();
1199                while ( rs.next() ) {
1200                    objects.add( new SecuredObject( rs.getInt( 1 ), rs.getInt( 2 ), rs.getString( 3 ), rs.getString( 4 ),
1201                                                    this ) );
1202                }
1203            } catch ( SQLException e ) {
1204                LOG.logError( e.getMessage(), e );
1205                throw new GeneralSecurityException( e );
1206            } finally {
1207                closeResultSet( rs );
1208                closeStatement( pstmt );
1209                releaseLocalConnection( securityAccess, con );
1210            }
1211            return objects.toArray( new SecuredObject[objects.size()] );
1212        }
1213    
1214        /**
1215         * Adds a new <code>Privilege</code> to the <code>Registry</code>.
1216         * 
1217         * @param transaction
1218         * @param name
1219         * @throws GeneralSecurityException
1220         *             this is a <code>DuplicateException</code> if the <code>Privilege</code>
1221         *             already existed
1222         */
1223        public Privilege registerPrivilege( SecurityTransaction transaction, String name )
1224                                throws GeneralSecurityException {
1225            try {
1226                getPrivilegeByName( transaction, name );
1227                throw new DuplicateException( "Registration of privilege '" + name + "' failed! A privilege with "
1228                                              + "this name already exists." );
1229            } catch ( UnknownException e ) {
1230            }
1231    
1232            int id = getID( transaction, "SEC_PRIVILEGES" );
1233            Privilege privilege = new Privilege( id, name );
1234            PreparedStatement pstmt = null;
1235    
1236            try {
1237                pstmt = transactionalConnection.prepareStatement( "INSERT INTO SEC_PRIVILEGES (ID, NAME) VALUES (?,?)" );
1238                pstmt.setInt( 1, id );
1239                pstmt.setString( 2, name );
1240                pstmt.executeUpdate();
1241                pstmt.close();
1242            } catch ( SQLException e ) {
1243                LOG.logError( e.getMessage(), e );
1244                closeStatement( pstmt );
1245                abortTransaction( transaction );
1246                throw new GeneralSecurityException( "SQLRegistry.registerPrivilege() failed. Rollback performed. "
1247                                                    + "Error message: " + e.getMessage() );
1248            }
1249            return privilege;
1250        }
1251    
1252        /**
1253         * Removes an existing</code> Privilege</code> from the <code>Registry </code> (including its
1254         * relations).
1255         * 
1256         * @param transaction
1257         * @param privilege
1258         * @throws GeneralSecurityException
1259         */
1260        public void deregisterPrivilege( SecurityTransaction transaction, Privilege privilege )
1261                                throws GeneralSecurityException {
1262            PreparedStatement pstmt = null;
1263    
1264            try {
1265                pstmt = transactionalConnection.prepareStatement( "DELETE FROM SEC_JT_ROLES_PRIVILEGES WHERE FK_PRIVILEGES=?" );
1266                pstmt.setInt( 1, privilege.getID() );
1267                pstmt.executeUpdate();
1268                pstmt.close();
1269                pstmt = null;
1270                pstmt = transactionalConnection.prepareStatement( "DELETE FROM SEC_PRIVILEGES WHERE ID=?" );
1271                pstmt.setInt( 1, privilege.getID() );
1272                pstmt.executeUpdate();
1273                pstmt.close();
1274            } catch ( SQLException e ) {
1275                LOG.logError( e.getMessage(), e );
1276                closeStatement( pstmt );
1277                abortTransaction( transaction );
1278                throw new GeneralSecurityException( "SQLRegistry.deregisterPrivilege() failed. Rollback performed. "
1279                                                    + "Error message: " + e.getMessage() );
1280            }
1281        }
1282    
1283        /**
1284         * Retrieves a <code>Privilege</code> from the <code>Registry</code>.
1285         * 
1286         * @param securityAccess
1287         * @param name
1288         * @throws GeneralSecurityException
1289         *             this is an <code>UnknownException</code> if the privilege is not known to the
1290         *             <code>Registry</code>
1291         */
1292        public Privilege getPrivilegeByName( SecurityAccess securityAccess, String name )
1293                                throws GeneralSecurityException {
1294            Privilege privilege = null;
1295            Connection con = acquireLocalConnection( securityAccess );
1296            PreparedStatement pstmt = null;
1297            ResultSet rs = null;
1298    
1299            try {
1300                pstmt = con.prepareStatement( "SELECT ID FROM SEC_PRIVILEGES WHERE NAME=?" );
1301                pstmt.setString( 1, name );
1302                rs = pstmt.executeQuery();
1303                if ( rs.next() ) {
1304                    privilege = new Privilege( rs.getInt( 1 ), name );
1305                } else {
1306                    throw new UnknownException( "Lookup of privilege '" + name
1307                                                + "' failed! A privilege with this name does not exist." );
1308                }
1309            } catch ( SQLException e ) {
1310                LOG.logError( e.getMessage(), e );
1311                throw new GeneralSecurityException( e );
1312            } finally {
1313                closeResultSet( rs );
1314                closeStatement( pstmt );
1315                releaseLocalConnection( securityAccess, con );
1316            }
1317            return privilege;
1318        }
1319    
1320        /**
1321         * Retrieves all <code>Privileges</code> s from the <code>Registry</code> that are
1322         * associated DIRECTLY (i.e. not via group memberships) with a given <code>Role</code>.
1323         * 
1324         * @param securityAccess
1325         * @param role
1326         * @throws GeneralSecurityException
1327         */
1328        public Privilege[] getPrivilegesForRole( SecurityAccess securityAccess, Role role )
1329                                throws GeneralSecurityException {
1330            ArrayList<Privilege> privileges = new ArrayList<Privilege>();
1331            Connection con = acquireLocalConnection( securityAccess );
1332            PreparedStatement pstmt = null;
1333            ResultSet rs = null;
1334    
1335            try {
1336                pstmt = con.prepareStatement( "SELECT SEC_PRIVILEGES.ID,SEC_PRIVILEGES.NAME "
1337                                              + "FROM SEC_JT_ROLES_PRIVILEGES, SEC_PRIVILEGES WHERE "
1338                                              + "SEC_JT_ROLES_PRIVILEGES.FK_ROLES=? AND "
1339                                              + "SEC_JT_ROLES_PRIVILEGES.FK_PRIVILEGES=SEC_PRIVILEGES.ID" );
1340                pstmt.setInt( 1, role.getID() );
1341                rs = pstmt.executeQuery();
1342                while ( rs.next() ) {
1343                    privileges.add( new Privilege( rs.getInt( 1 ), rs.getString( 2 ) ) );
1344                }
1345            } catch ( SQLException e ) {
1346                LOG.logError( e.getMessage(), e );
1347                throw new GeneralSecurityException( e );
1348            } finally {
1349                closeResultSet( rs );
1350                closeStatement( pstmt );
1351                releaseLocalConnection( securityAccess, con );
1352            }
1353            return privileges.toArray( new Privilege[privileges.size()] );
1354        }
1355    
1356        /**
1357         * Sets all <code>Privilege</code> s that are associated with a given <code>Role</code>.
1358         * 
1359         * @param transaction
1360         * @param role
1361         * @param privileges
1362         * @throws GeneralSecurityException
1363         */
1364        public void setPrivilegesForRole( SecurityTransaction transaction, Role role, Privilege[] privileges )
1365                                throws GeneralSecurityException {
1366            PreparedStatement pstmt = null;
1367    
1368            try {
1369                pstmt = transactionalConnection.prepareStatement( "DELETE FROM SEC_JT_ROLES_PRIVILEGES WHERE FK_ROLES=?" );
1370                pstmt.setInt( 1, role.getID() );
1371                pstmt.executeUpdate();
1372                pstmt.close();
1373                pstmt = null;
1374    
1375                for ( int i = 0; i < privileges.length; i++ ) {
1376                    pstmt = transactionalConnection.prepareStatement( "INSERT INTO SEC_JT_ROLES_PRIVILEGES (FK_ROLES, FK_PRIVILEGES) VALUES (?,?)" );
1377                    pstmt.setInt( 1, role.getID() );
1378                    pstmt.setInt( 2, privileges[i].getID() );
1379                    pstmt.executeUpdate();
1380                    pstmt.close();
1381                    pstmt = null;
1382                }
1383            } catch ( SQLException e ) {
1384                LOG.logError( e.getMessage(), e );
1385                closeStatement( pstmt );
1386                abortTransaction( transaction );
1387                throw new GeneralSecurityException( "SQLRegistry.setPrivilegesForRols() failed. Rollback performed. "
1388                                                    + "Error message: " + e.getMessage() );
1389            }
1390        }
1391    
1392        /**
1393         * Adds a new <code>Right</code> to the <code>Registry</code>.
1394         * 
1395         * @param transaction
1396         * @param name
1397         * @throws GeneralSecurityException
1398         *             this is a <code>DuplicateException</code> if the <code>Right</code> already
1399         *             existed
1400         */
1401        public RightType registerRightType( SecurityTransaction transaction, String name )
1402                                throws GeneralSecurityException {
1403            try {
1404                getRightTypeByName( transaction, name );
1405                throw new DuplicateException( "Registration of right '" + name + "' failed! A right with "
1406                                              + "this name already exists." );
1407            } catch ( UnknownException e ) {
1408            }
1409    
1410            int id = getID( transaction, "SEC_RIGHTS" );
1411            RightType right = new RightType( id, name );
1412            PreparedStatement pstmt = null;
1413    
1414            try {
1415                pstmt = transactionalConnection.prepareStatement( "INSERT INTO SEC_RIGHTS (ID, NAME) VALUES (?,?)" );
1416                pstmt.setInt( 1, id );
1417                pstmt.setString( 2, name );
1418                pstmt.executeUpdate();
1419                pstmt.close();
1420            } catch ( SQLException e ) {
1421                LOG.logError( e.getMessage(), e );
1422                closeStatement( pstmt );
1423                abortTransaction( transaction );
1424                throw new GeneralSecurityException( "SQLRegistry.registerRight() failed. Rollback "
1425                                                    + "performed. Error message: " + e.getMessage() );
1426            }
1427            return right;
1428        }
1429    
1430        /**
1431         * Removes an existing <code>RightType</code> from the <code>Registry</code> (including its
1432         * relations).
1433         * 
1434         * @param transaction
1435         * @param type
1436         * @throws GeneralSecurityException
1437         */
1438        public void deregisterRightType( SecurityTransaction transaction, RightType type )
1439                                throws GeneralSecurityException {
1440            PreparedStatement pstmt = null;
1441    
1442            try {
1443                pstmt = transactionalConnection.prepareStatement( "DELETE FROM SEC_JT_ROLES_SECOBJECTS WHERE FK_RIGHTS=?" );
1444                pstmt.setInt( 1, type.getID() );
1445                pstmt.executeUpdate();
1446                pstmt.close();
1447                pstmt = null;
1448                pstmt = transactionalConnection.prepareStatement( "DELETE FROM SEC_RIGHTS WHERE ID=?" );
1449                pstmt.setInt( 1, type.getID() );
1450                pstmt.executeUpdate();
1451                pstmt.close();
1452            } catch ( SQLException e ) {
1453                LOG.logError( e.getMessage(), e );
1454                closeStatement( pstmt );
1455                abortTransaction( transaction );
1456                throw new GeneralSecurityException( "SQLRegistry.deregisterRight() failed. Rollback performed. "
1457                                                    + "Error message: " + e.getMessage() );
1458            }
1459        }
1460    
1461        /**
1462         * Retrieves a <code>Right</code> from the <code>Registry</code>.
1463         * 
1464         * @param securityAccess
1465         * @param name
1466         * @throws GeneralSecurityException
1467         *             this is an <code>UnknownException</code> if the <code>Right</code> is not
1468         *             known to the <code>Registry</code>
1469         */
1470        public RightType getRightTypeByName( SecurityAccess securityAccess, String name )
1471                                throws GeneralSecurityException {
1472            RightType right = null;
1473            Connection con = acquireLocalConnection( securityAccess );
1474            PreparedStatement pstmt = null;
1475            ResultSet rs = null;
1476    
1477            try {
1478                pstmt = con.prepareStatement( "SELECT ID FROM SEC_RIGHTS WHERE NAME=?" );
1479                pstmt.setString( 1, name );
1480                rs = pstmt.executeQuery();
1481                if ( rs.next() ) {
1482                    right = new RightType( rs.getInt( 1 ), name );
1483                } else {
1484                    throw new UnknownException( "Lookup of right '" + name
1485                                                + "' failed! A right with this name does not exist." );
1486                }
1487            } catch ( SQLException e ) {
1488                LOG.logError( e.getMessage(), e );
1489                throw new GeneralSecurityException( e );
1490            } finally {
1491                closeResultSet( rs );
1492                closeStatement( pstmt );
1493                releaseLocalConnection( securityAccess, con );
1494            }
1495            return right;
1496        }
1497    
1498        /**
1499         * Retrieves the <code>Rights</code> from the <code>Registry</code> that are associated with
1500         * a given <code>Role</code> and a <code>SecurableObject</code>.
1501         * 
1502         * @param securityAccess
1503         * @param object
1504         * @param role
1505         * @throws GeneralSecurityException
1506         */
1507        public Right[] getRights( SecurityAccess securityAccess, SecurableObject object, Role role )
1508                                throws GeneralSecurityException {
1509            ArrayList<Right> rights = new ArrayList<Right>();
1510            Connection con = acquireLocalConnection( securityAccess );
1511            PreparedStatement pstmt = null;
1512            ResultSet rs = null;
1513    
1514            try {
1515                pstmt = con.prepareStatement( "SELECT SEC_RIGHTS.ID,SEC_RIGHTS.NAME,"
1516                                              + "SEC_JT_ROLES_SECOBJECTS.CONSTRAINTS FROM SEC_JT_ROLES_SECOBJECTS,"
1517                                              + "SEC_RIGHTS WHERE SEC_JT_ROLES_SECOBJECTS.FK_ROLES=? AND "
1518                                              + "SEC_JT_ROLES_SECOBJECTS.FK_SECURABLE_OBJECTS=? AND "
1519                                              + "SEC_JT_ROLES_SECOBJECTS.FK_RIGHTS=SEC_RIGHTS.ID" );
1520                pstmt.setInt( 1, role.getID() );
1521                pstmt.setInt( 2, object.getID() );
1522                rs = pstmt.executeQuery();
1523                ResultSetMetaData metadata = rs.getMetaData();
1524                int constraintType = metadata.getColumnType( 3 );
1525    
1526                while ( rs.next() ) {
1527                    Right right = null;
1528                    RightType type = new RightType( rs.getInt( 1 ), rs.getString( 2 ) );
1529                    String constraints = null;
1530                    Object o = rs.getObject( 3 );
1531                    if ( o != null ) {
1532                        if ( constraintType == Types.CLOB ) {
1533                            Reader reader = ( (Clob) o ).getCharacterStream();
1534                            StringBuffer sb = new StringBuffer( 2000 );
1535                            int c;
1536                            try {
1537                                while ( ( c = reader.read() ) > -1 ) {
1538                                    sb.append( (char) c );
1539                                }
1540                                reader.close();
1541                            } catch ( IOException e ) {
1542                                throw new GeneralSecurityException( "Error converting CLOB to constraint string: "
1543                                                                    + e.getMessage() );
1544                            }
1545                            constraints = sb.toString();
1546                        } else {
1547                            constraints = o.toString();
1548                        }
1549                    }
1550    
1551                    // check if the right has constraints
1552                    if ( constraints != null && constraints.length() > 3 ) {
1553                        right = new Right( object, type, buildFilter( constraints ) );
1554                    } else {
1555                        right = new Right( object, type, null );
1556                    }
1557    
1558                    rights.add( right );
1559                }
1560            } catch ( SQLException e ) {
1561                LOG.logError( e.getMessage(), e );
1562                throw new GeneralSecurityException( e );
1563            } finally {
1564                closeResultSet( rs );
1565                closeStatement( pstmt );
1566                releaseLocalConnection( securityAccess, con );
1567            }
1568            return rights.toArray( new Right[rights.size()] );
1569        }
1570    
1571        /**
1572         * Sets the <code>Rights</code> to be associated with a given <code>Role</code> and
1573         * <code>SecurableObject</code>.
1574         * 
1575         * @param transaction
1576         * @param object
1577         * @param role
1578         * @param rights
1579         * @throws GeneralSecurityException
1580         */
1581        public void setRights( SecurityTransaction transaction, SecurableObject object, Role role, Right[] rights )
1582                                throws GeneralSecurityException {
1583            PreparedStatement pstmt = null;
1584    
1585            try {
1586                pstmt = transactionalConnection.prepareStatement( "DELETE FROM SEC_JT_ROLES_SECOBJECTS WHERE FK_ROLES=? AND FK_SECURABLE_OBJECTS=?" );
1587                pstmt.setInt( 1, role.getID() );
1588                pstmt.setInt( 2, object.getID() );
1589                pstmt.executeUpdate();
1590                pstmt.close();
1591    
1592                for ( int i = 0; i < rights.length; i++ ) {
1593    
1594                    String constraints = null;
1595                    if ( rights[i].getConstraints() != null ) {
1596                        constraints = rights[i].getConstraints().toXML().toString();
1597                    }
1598                    LOG.logDebug( "constraints to add: ", constraints );
1599                    if ( transactionalConnection instanceof OracleConnection ) {
1600                        handleOracle( object, role, rights[i], constraints );
1601                    } else {
1602                        pstmt = transactionalConnection.prepareStatement( "INSERT INTO SEC_JT_ROLES_SECOBJECTS (FK_ROLES, FK_SECURABLE_OBJECTS, FK_RIGHTS,CONSTRAINTS) VALUES (?,?,?,?)" );
1603                        pstmt.setInt( 1, role.getID() );
1604                        pstmt.setInt( 2, object.getID() );
1605                        pstmt.setInt( 3, rights[i].getType().getID() );
1606                        pstmt.setString( 4, constraints );
1607                        pstmt.executeUpdate();
1608                        pstmt.close();
1609                    }
1610    
1611                }
1612            } catch ( SQLException e ) {
1613                LOG.logError( e.getMessage(), e );
1614                closeStatement( pstmt );
1615                abortTransaction( transaction );
1616                throw new GeneralSecurityException( "SQLRegistry.setRights() failed. Rollback performed. "
1617                                                    + "Error message: " + e.getMessage() );
1618            }
1619        }
1620    
1621        private void handleOracle( SecurableObject object, Role role, Right right, String constraints )
1622                                throws SQLException {
1623    
1624            PreparedStatement pstmt;
1625            pstmt = transactionalConnection.prepareStatement( "INSERT INTO SEC_JT_ROLES_SECOBJECTS (FK_ROLES, FK_SECURABLE_OBJECTS, FK_RIGHTS, CONSTRAINTS) VALUES (?,?,?, EMPTY_CLOB() )" );
1626            pstmt.setInt( 1, role.getID() );
1627            pstmt.setInt( 2, object.getID() );
1628            pstmt.setInt( 3, right.getType().getID() );
1629            pstmt.executeUpdate();
1630            pstmt.close();
1631            transactionalConnection.commit();
1632    
1633            if ( constraints != null ) {
1634                pstmt = transactionalConnection.prepareStatement( "select CONSTRAINTS from SEC_JT_ROLES_SECOBJECTS where FK_ROLES = ? and FK_SECURABLE_OBJECTS = ? and FK_RIGHTS = ? FOR UPDATE" );
1635                pstmt.setInt( 1, role.getID() );
1636                pstmt.setInt( 2, object.getID() );
1637                pstmt.setInt( 3, right.getType().getID() );
1638                ResultSet rs = pstmt.executeQuery();
1639                rs.next();
1640    
1641                CLOB clob = (oracle.sql.CLOB) rs.getClob( 1 );
1642                try {
1643                    // clob.getAsciiOutputStream().write( constraints.getBytes() );
1644                    OutputStream os = clob.getAsciiOutputStream();
1645                    OutputStreamWriter osw = new OutputStreamWriter( os );
1646    
1647                    // use that output stream to write character data to the Oracle data store
1648                    osw.write( constraints.toCharArray() );
1649                    // write data and commit
1650                    osw.flush();
1651                    osw.close();
1652                    os.close();
1653                } catch ( IOException e ) {
1654                    e.printStackTrace();
1655                }
1656            }
1657            pstmt.close();
1658        }
1659    
1660        /**
1661         * Sets one <code>Right</code> to be associated with a given <code>Role</code> and all given
1662         * <code>SecurableObjects</code>.
1663         * 
1664         * @param transaction
1665         * @param objects
1666         * @param role
1667         * @param right
1668         * @throws GeneralSecurityException
1669         */
1670        public void setRights( SecurityTransaction transaction, SecurableObject[] objects, Role role, Right right )
1671                                throws GeneralSecurityException {
1672            PreparedStatement pstmt = null;
1673    
1674            try {
1675                pstmt = transactionalConnection.prepareStatement( "DELETE FROM SEC_JT_ROLES_SECOBJECTS WHERE FK_ROLES=? AND FK_RIGHTS=?" );
1676                pstmt.setInt( 1, role.getID() );
1677                pstmt.setInt( 2, right.getType().getID() );
1678                pstmt.executeUpdate();
1679                pstmt.close();
1680                pstmt = null;
1681    
1682                for ( int i = 0; i < objects.length; i++ ) {
1683                    String constraints = null;
1684                    if ( right.getConstraints() != null ) {
1685                        constraints = right.getConstraints().toXML().toString();
1686                    }
1687                    pstmt = transactionalConnection.prepareStatement( "INSERT INTO SEC_JT_ROLES_SECOBJECTS (FK_ROLES, FK_SECURABLE_OBJECTS, FK_RIGHTS, CONSTRAINTS) VALUES (?,?,?,?)" );
1688                    pstmt.setInt( 1, role.getID() );
1689                    pstmt.setInt( 2, objects[i].getID() );
1690                    pstmt.setInt( 3, right.getType().getID() );
1691                    pstmt.setString( 4, constraints );
1692                    pstmt.executeUpdate();
1693                    pstmt.close();
1694                    pstmt = null;
1695                }
1696            } catch ( SQLException e ) {
1697                closeStatement( pstmt );
1698                abortTransaction( transaction );
1699                throw new GeneralSecurityException( "SQLRegistry.setRights() failed. Rollback performed. "
1700                                                    + "Error message: " + e.getMessage() );
1701            }
1702        }
1703    
1704        /**
1705         * Retrieves all <code>Group</code> s from the <code>Registry</code> that the given
1706         * <code>User</code> is a DIRECT (i.e. not via inheritance) member of.
1707         * 
1708         * @param securityAccess
1709         * @param user
1710         * @throws GeneralSecurityException
1711         */
1712        public Group[] getGroupsForUser( SecurityAccess securityAccess, User user )
1713                                throws GeneralSecurityException {
1714            ArrayList<Group> groups = new ArrayList<Group>( 100 );
1715            Connection con = acquireLocalConnection( securityAccess );
1716            PreparedStatement pstmt = null;
1717            ResultSet rs = null;
1718    
1719            try {
1720                pstmt = con.prepareStatement( "SELECT SEC_GROUPS.ID,SEC_SECURABLE_OBJECTS.NAME,SEC_SECURABLE_OBJECTS.TITLE "
1721                                              + "FROM SEC_SECURABLE_OBJECTS,SEC_GROUPS,SEC_JT_USERS_GROUPS WHERE "
1722                                              + "SEC_SECURABLE_OBJECTS.ID=SEC_GROUPS.ID AND "
1723                                              + "SEC_JT_USERS_GROUPS.FK_GROUPS=SEC_GROUPS.ID AND "
1724                                              + "SEC_JT_USERS_GROUPS.FK_USERS=?" );
1725                pstmt.setInt( 1, user.getID() );
1726                rs = pstmt.executeQuery();
1727                while ( rs.next() ) {
1728                    groups.add( new Group( rs.getInt( 1 ), rs.getString( 2 ), rs.getString( 3 ), this ) );
1729                }
1730            } catch ( SQLException e ) {
1731                throw new GeneralSecurityException( e );
1732            } finally {
1733                closeResultSet( rs );
1734                closeStatement( pstmt );
1735                releaseLocalConnection( securityAccess, con );
1736            }
1737            return groups.toArray( new Group[groups.size()] );
1738        }
1739    
1740        /**
1741         * Retrieves all <code>Groups</code> s from the <code>Registry</code> that are members of
1742         * another <code>Group</code> DIRECTLY (i.e. not via inheritance).
1743         * 
1744         * @param securityAccess
1745         * @param group
1746         * @throws GeneralSecurityException
1747         */
1748        public Group[] getGroupsInGroup( SecurityAccess securityAccess, Group group )
1749                                throws GeneralSecurityException {
1750            ArrayList<Group> groups = new ArrayList<Group>( 100 );
1751            Connection con = acquireLocalConnection( securityAccess );
1752            PreparedStatement pstmt = null;
1753            ResultSet rs = null;
1754    
1755            try {
1756                pstmt = con.prepareStatement( "SELECT SEC_GROUPS.ID,SEC_SECURABLE_OBJECTS.NAME,SEC_SECURABLE_OBJECTS.TITLE "
1757                                              + "FROM SEC_GROUPS,SEC_SECURABLE_OBJECTS,SEC_JT_GROUPS_GROUPS "
1758                                              + "WHERE SEC_SECURABLE_OBJECTS.ID=SEC_GROUPS.ID"
1759                                              + " AND SEC_JT_GROUPS_GROUPS.FK_GROUPS_MEMBER=SEC_GROUPS.ID"
1760                                              + " AND SEC_JT_GROUPS_GROUPS.FK_GROUPS=?" );
1761                pstmt.setInt( 1, group.getID() );
1762                rs = pstmt.executeQuery();
1763                while ( rs.next() ) {
1764                    groups.add( new Group( rs.getInt( 1 ), rs.getString( 2 ), rs.getString( 3 ), this ) );
1765                }
1766            } catch ( SQLException e ) {
1767                throw new GeneralSecurityException( e );
1768            } finally {
1769                closeResultSet( rs );
1770                closeStatement( pstmt );
1771                releaseLocalConnection( securityAccess, con );
1772            }
1773            return groups.toArray( new Group[groups.size()] );
1774        }
1775    
1776        /**
1777         * Retrieves all <code>Group</code> s from the <code>Registry</code> that the given
1778         * <code>Group</code> is a DIRECT member (i.e. not via inheritance) of.
1779         * 
1780         * @param securityAccess
1781         * @param group
1782         * @throws GeneralSecurityException
1783         */
1784        public Group[] getGroupsForGroup( SecurityAccess securityAccess, Group group )
1785                                throws GeneralSecurityException {
1786            ArrayList<Group> groups = new ArrayList<Group>( 100 );
1787            Connection con = acquireLocalConnection( securityAccess );
1788            PreparedStatement pstmt = null;
1789            ResultSet rs = null;
1790    
1791            try {
1792                pstmt = con.prepareStatement( "SELECT SEC_GROUPS.ID,SEC_SECURABLE_OBJECTS.NAME,SEC_SECURABLE_OBJECTS.TITLE "
1793                                              + "FROM SEC_SECURABLE_OBJECTS,SEC_GROUPS,SEC_JT_GROUPS_GROUPS WHERE "
1794                                              + "SEC_SECURABLE_OBJECTS.ID=SEC_GROUPS.ID AND "
1795                                              + "SEC_JT_GROUPS_GROUPS.FK_GROUPS=SEC_GROUPS.ID AND "
1796                                              + "SEC_JT_GROUPS_GROUPS.FK_GROUPS_MEMBER=?" );
1797                pstmt.setInt( 1, group.getID() );
1798                rs = pstmt.executeQuery();
1799                while ( rs.next() ) {
1800                    groups.add( new Group( rs.getInt( 1 ), rs.getString( 2 ), rs.getString( 3 ), this ) );
1801                }
1802            } catch ( SQLException e ) {
1803                throw new GeneralSecurityException( e );
1804            } finally {
1805                closeResultSet( rs );
1806                closeStatement( pstmt );
1807                releaseLocalConnection( securityAccess, con );
1808            }
1809            return groups.toArray( new Group[groups.size()] );
1810        }
1811    
1812        /**
1813         * Retrieves all <code>Group</code> s from the <code>Registry</code> that are associated
1814         * with a given <code>Role</code> DIRECTLY (i.e. not via inheritance).
1815         * 
1816         * @param securityAccess
1817         * @param role
1818         * @throws GeneralSecurityException
1819         */
1820        public Group[] getGroupsWithRole( SecurityAccess securityAccess, Role role )
1821                                throws GeneralSecurityException {
1822            ArrayList<Group> groups = new ArrayList<Group>( 100 );
1823            Connection con = acquireLocalConnection( securityAccess );
1824            PreparedStatement pstmt = null;
1825            ResultSet rs = null;
1826    
1827            try {
1828                pstmt = con.prepareStatement( "SELECT SEC_GROUPS.ID,SEC_SECURABLE_OBJECTS.NAME,SEC_SECURABLE_OBJECTS.TITLE "
1829                                              + "FROM SEC_SECURABLE_OBJECTS,SEC_GROUPS,SEC_JT_GROUPS_ROLES WHERE "
1830                                              + "SEC_SECURABLE_OBJECTS.ID=SEC_GROUPS.ID AND "
1831                                              + "SEC_JT_GROUPS_ROLES.FK_GROUPS=SEC_GROUPS.ID AND "
1832                                              + "SEC_JT_GROUPS_ROLES.FK_ROLES=?" );
1833                pstmt.setInt( 1, role.getID() );
1834                rs = pstmt.executeQuery();
1835                while ( rs.next() ) {
1836                    groups.add( new Group( rs.getInt( 1 ), rs.getString( 2 ), rs.getString( 3 ), this ) );
1837                }
1838            } catch ( SQLException e ) {
1839                throw new GeneralSecurityException( e );
1840            } finally {
1841                closeResultSet( rs );
1842                closeStatement( pstmt );
1843                releaseLocalConnection( securityAccess, con );
1844            }
1845            return groups.toArray( new Group[groups.size()] );
1846        }
1847    
1848        /**
1849         * Retrieves all <code>Role</code> s from the <code>Registry</code> that are associated with
1850         * a given <code>User</code> DIRECTLY (i.e. not via group memberships).
1851         * 
1852         * @param securityAccess
1853         * @param user
1854         * @throws GeneralSecurityException
1855         */
1856        public Role[] getRolesForUser( SecurityAccess securityAccess, User user )
1857                                throws GeneralSecurityException {
1858            ArrayList<Role> roles = new ArrayList<Role>( 100 );
1859            Connection con = acquireLocalConnection( securityAccess );
1860            PreparedStatement pstmt = null;
1861            ResultSet rs = null;
1862    
1863            try {
1864                pstmt = con.prepareStatement( "SELECT SEC_ROLES.ID,SEC_SECURABLE_OBJECTS.NAME "
1865                                              + "FROM SEC_SECURABLE_OBJECTS,SEC_ROLES,SEC_JT_USERS_ROLES WHERE "
1866                                              + "SEC_SECURABLE_OBJECTS.ID=SEC_ROLES.ID AND SEC_JT_USERS_ROLES.FK_ROLES=SEC_ROLES.ID "
1867                                              + "AND SEC_JT_USERS_ROLES.FK_USERS=?" );
1868                pstmt.setInt( 1, user.getID() );
1869                rs = pstmt.executeQuery();
1870                while ( rs.next() ) {
1871                    roles.add( new Role( rs.getInt( 1 ), rs.getString( 2 ), this ) );
1872                }
1873            } catch ( SQLException e ) {
1874                throw new GeneralSecurityException( e );
1875            } finally {
1876                closeResultSet( rs );
1877                closeStatement( pstmt );
1878                releaseLocalConnection( securityAccess, con );
1879            }
1880            return roles.toArray( new Role[roles.size()] );
1881        }
1882    
1883        /**
1884         * Retrieves all <code>Role</code> s from the <code>Registry</code> that are associated with
1885         * a given <code>Group</code> DIRECTLY (i.e. not via inheritance).
1886         * 
1887         * @param securityAccess
1888         * @param group
1889         * @throws GeneralSecurityException
1890         */
1891        public Role[] getRolesForGroup( SecurityAccess securityAccess, Group group )
1892                                throws GeneralSecurityException {
1893            ArrayList<Role> roles = new ArrayList<Role>( 100 );
1894            Connection con = acquireLocalConnection( securityAccess );
1895            PreparedStatement pstmt = null;
1896            ResultSet rs = null;
1897    
1898            try {
1899                pstmt = con.prepareStatement( "SELECT SEC_ROLES.ID,SEC_SECURABLE_OBJECTS.NAME "
1900                                              + "FROM SEC_SECURABLE_OBJECTS,SEC_ROLES,SEC_JT_GROUPS_ROLES WHERE "
1901                                              + "SEC_SECURABLE_OBJECTS.ID=SEC_ROLES.ID AND SEC_JT_GROUPS_ROLES.FK_ROLES=SEC_ROLES.ID "
1902                                              + "AND SEC_JT_GROUPS_ROLES.FK_GROUPS=?" );
1903                pstmt.setInt( 1, group.getID() );
1904                rs = pstmt.executeQuery();
1905                while ( rs.next() ) {
1906                    roles.add( new Role( rs.getInt( 1 ), rs.getString( 2 ), this ) );
1907                }
1908            } catch ( SQLException e ) {
1909                throw new GeneralSecurityException( e );
1910            } finally {
1911                closeResultSet( rs );
1912                closeStatement( pstmt );
1913                releaseLocalConnection( securityAccess, con );
1914            }
1915            return roles.toArray( new Role[roles.size()] );
1916        }
1917    
1918        /**
1919         * Sets the <code>Group</code> s that a given <code>User</code> is member of DIRECTLY (i.e.
1920         * not via inheritance).
1921         * 
1922         * @param transaction
1923         * @param user
1924         * @param groups
1925         * @throws GeneralSecurityException
1926         */
1927        public void setGroupsForUser( SecurityTransaction transaction, User user, Group[] groups )
1928                                throws GeneralSecurityException {
1929            PreparedStatement pstmt = null;
1930    
1931            try {
1932                pstmt = transactionalConnection.prepareStatement( "DELETE FROM SEC_JT_USERS_GROUPS WHERE FK_USERS=?" );
1933                pstmt.setInt( 1, user.getID() );
1934                pstmt.executeUpdate();
1935                pstmt.close();
1936                pstmt = null;
1937    
1938                for ( int i = 0; i < groups.length; i++ ) {
1939                    pstmt = transactionalConnection.prepareStatement( "INSERT INTO SEC_JT_USERS_GROUPS (FK_USERS, FK_GROUPS) VALUES (?,?)" );
1940                    pstmt.setInt( 1, user.getID() );
1941                    pstmt.setInt( 2, groups[i].getID() );
1942                    pstmt.executeUpdate();
1943                    pstmt.close();
1944                    pstmt = null;
1945                }
1946            } catch ( SQLException e ) {
1947                closeStatement( pstmt );
1948                abortTransaction( transaction );
1949                throw new GeneralSecurityException( "SQLRegistry.setGroupsForUser() failed. Rollback performed. "
1950                                                    + "Error message: " + e.getMessage() );
1951            }
1952        }
1953    
1954        /**
1955         * Sets the <code>Group</code> s that a given <code>Group</code> is member of DIRECTLY (i.e.
1956         * not via inheritance).
1957         * 
1958         * @param transaction
1959         * @param group
1960         * @param groups
1961         * @throws GeneralSecurityException
1962         */
1963        public void setGroupsForGroup( SecurityTransaction transaction, Group group, Group[] groups )
1964                                throws GeneralSecurityException {
1965            PreparedStatement pstmt = null;
1966    
1967            try {
1968                pstmt = transactionalConnection.prepareStatement( "DELETE FROM SEC_JT_GROUPS_GROUPS WHERE FK_GROUPS_MEMBER=?" );
1969                pstmt.setInt( 1, group.getID() );
1970                pstmt.executeUpdate();
1971                pstmt.close();
1972                pstmt = null;
1973    
1974                for ( int i = 0; i < groups.length; i++ ) {
1975                    pstmt = transactionalConnection.prepareStatement( "INSERT INTO SEC_JT_GROUPS_GROUPS (FK_GROUPS_MEMBER, FK_GROUPS) VALUES (?,?)" );
1976                    pstmt.setInt( 1, group.getID() );
1977                    pstmt.setInt( 2, groups[i].getID() );
1978                    pstmt.executeUpdate();
1979                    pstmt.close();
1980                    pstmt = null;
1981                }
1982            } catch ( SQLException e ) {
1983                closeStatement( pstmt );
1984                abortTransaction( transaction );
1985                throw new GeneralSecurityException( "SQLRegistry.setGroupsForGroup() failed. Rollback performed. "
1986                                                    + "Error message: " + e.getMessage() );
1987            }
1988        }
1989    
1990        /**
1991         * Sets the <code>Group</code> s that a given <code>Role</code> is associated to DIRECTLY
1992         * (i.e. not via inheritance).
1993         * 
1994         * @param transaction
1995         * @param role
1996         * @param groups
1997         * @throws GeneralSecurityException
1998         */
1999        public void setGroupsWithRole( SecurityTransaction transaction, Role role, Group[] groups )
2000                                throws GeneralSecurityException {
2001            PreparedStatement pstmt = null;
2002    
2003            try {
2004                pstmt = transactionalConnection.prepareStatement( "DELETE FROM SEC_JT_GROUPS_ROLES WHERE FK_ROLES=?" );
2005                pstmt.setInt( 1, role.getID() );
2006                pstmt.executeUpdate();
2007                pstmt.close();
2008                pstmt = null;
2009    
2010                for ( int i = 0; i < groups.length; i++ ) {
2011                    pstmt = transactionalConnection.prepareStatement( "INSERT INTO SEC_JT_GROUPS_ROLES (FK_GROUPS, FK_ROLES) VALUES (?,?)" );
2012                    pstmt.setInt( 1, groups[i].getID() );
2013                    pstmt.setInt( 2, role.getID() );
2014                    pstmt.executeUpdate();
2015                    pstmt.close();
2016                    pstmt = null;
2017                }
2018            } catch ( SQLException e ) {
2019                closeStatement( pstmt );
2020                abortTransaction( transaction );
2021                throw new GeneralSecurityException( "SQLRegistry.setGroupsWithRole() failed. Rollback performed. "
2022                                                    + "Error message: " + e.getMessage() );
2023            }
2024        }
2025    
2026        /**
2027         * Sets the <code>User</code> s that a given <code>Role</code> is associated to DIRECTLY
2028         * (i.e. not via <code>Group</code> membership).
2029         * 
2030         * @param transaction
2031         * @param role
2032         * @param users
2033         * @throws GeneralSecurityException
2034         */
2035        public void setUsersWithRole( SecurityTransaction transaction, Role role, User[] users )
2036                                throws GeneralSecurityException {
2037    
2038            PreparedStatement pstmt = null;
2039    
2040            try {
2041                pstmt = transactionalConnection.prepareStatement( "DELETE FROM SEC_JT_USERS_ROLES WHERE FK_ROLES=?" );
2042                pstmt.setInt( 1, role.getID() );
2043                pstmt.executeUpdate();
2044                pstmt.close();
2045                pstmt = null;
2046    
2047                for ( int i = 0; i < users.length; i++ ) {
2048                    pstmt = transactionalConnection.prepareStatement( "INSERT INTO SEC_JT_USERS_ROLES (FK_USERS, FK_ROLES) VALUES (?,?)" );
2049                    pstmt.setInt( 1, users[i].getID() );
2050                    pstmt.setInt( 2, role.getID() );
2051                    pstmt.executeUpdate();
2052                    pstmt.close();
2053                    pstmt = null;
2054                }
2055            } catch ( SQLException e ) {
2056                closeStatement( pstmt );
2057                abortTransaction( transaction );
2058                throw new GeneralSecurityException( "SQLRegistry.setUsersWithRole() failed. Rollback performed. "
2059                                                    + "Error message: " + e.getMessage() );
2060            }
2061        }
2062    
2063        /**
2064         * Sets the <code>User</code> s that are members of a given <code>Group</code> DIRECTLY
2065         * (i.e. not via inheritance).
2066         * 
2067         * @param transaction
2068         * @param group
2069         * @param users
2070         * @throws GeneralSecurityException
2071         */
2072        public void setUsersInGroup( SecurityTransaction transaction, Group group, User[] users )
2073                                throws GeneralSecurityException {
2074            PreparedStatement pstmt = null;
2075    
2076            try {
2077                pstmt = transactionalConnection.prepareStatement( "DELETE FROM SEC_JT_USERS_GROUPS WHERE FK_GROUPS=?" );
2078                pstmt.setInt( 1, group.getID() );
2079                pstmt.executeUpdate();
2080                pstmt.close();
2081                pstmt = null;
2082    
2083                for ( int i = 0; i < users.length; i++ ) {
2084                    closeStatement( pstmt );
2085                    pstmt = transactionalConnection.prepareStatement( "INSERT INTO SEC_JT_USERS_GROUPS (FK_USERS, FK_GROUPS) VALUES (?,?)" );
2086                    pstmt.setInt( 1, users[i].getID() );
2087                    pstmt.setInt( 2, group.getID() );
2088                    pstmt.executeUpdate();
2089                    pstmt.close();
2090                    pstmt = null;
2091                }
2092            } catch ( SQLException e ) {
2093                closeStatement( pstmt );
2094                abortTransaction( transaction );
2095                throw new GeneralSecurityException( "SQLRegistry.setUsersInGroup() failed. Rollback performed. "
2096                                                    + "Error message: " + e.getMessage() );
2097            }
2098        }
2099    
2100        /**
2101         * Sets the <code>Groups</code> s that are members of a given <code>Group</code> DIRECTLY
2102         * (i.e. not via inheritance).
2103         * 
2104         * @param transaction
2105         * @param group
2106         * @param groups
2107         * @throws GeneralSecurityException
2108         */
2109        public void setGroupsInGroup( SecurityTransaction transaction, Group group, Group[] groups )
2110                                throws GeneralSecurityException {
2111            PreparedStatement pstmt = null;
2112    
2113            try {
2114                pstmt = transactionalConnection.prepareStatement( "DELETE FROM SEC_JT_GROUPS_GROUPS WHERE FK_GROUPS=?" );
2115                pstmt.setInt( 1, group.getID() );
2116                pstmt.executeUpdate();
2117                pstmt.close();
2118                pstmt = null;
2119    
2120                for ( int i = 0; i < groups.length; i++ ) {
2121                    pstmt = transactionalConnection.prepareStatement( "INSERT INTO SEC_JT_GROUPS_GROUPS (FK_GROUPS_MEMBER, FK_GROUPS) VALUES (?,?)" );
2122                    pstmt.setInt( 1, groups[i].getID() );
2123                    pstmt.setInt( 2, group.getID() );
2124                    pstmt.executeUpdate();
2125                    pstmt.close();
2126                    pstmt = null;
2127                }
2128            } catch ( SQLException e ) {
2129                closeStatement( pstmt );
2130                abortTransaction( transaction );
2131                throw new GeneralSecurityException( "SQLRegistry.setGroupsInGroup() failed. Rollback performed. "
2132                                                    + "Error message: " + e.getMessage() );
2133            }
2134        }
2135    
2136        /**
2137         * Sets the <code>Role</code> s that a given <code>User</code> is directly associated to
2138         * (i.e. not via <code>Group</code> membership).
2139         * 
2140         * @param transaction
2141         * @param user
2142         * @param roles
2143         * @throws GeneralSecurityException
2144         */
2145        public void setRolesForUser( SecurityTransaction transaction, User user, Role[] roles )
2146                                throws GeneralSecurityException {
2147            PreparedStatement pstmt = null;
2148    
2149            try {
2150                pstmt = transactionalConnection.prepareStatement( "DELETE FROM SEC_JT_USERS_ROLES WHERE FK_USERS=?" );
2151                pstmt.setInt( 1, user.getID() );
2152                pstmt.executeUpdate();
2153                pstmt.close();
2154                pstmt = null;
2155    
2156                for ( int i = 0; i < roles.length; i++ ) {
2157                    pstmt = transactionalConnection.prepareStatement( "INSERT INTO SEC_JT_USERS_ROLES (FK_USERS, FK_ROLES) VALUES (?,?)" );
2158                    pstmt.setInt( 1, user.getID() );
2159                    pstmt.setInt( 2, roles[i].getID() );
2160                    pstmt.executeUpdate();
2161                    pstmt.close();
2162                    pstmt = null;
2163                }
2164            } catch ( SQLException e ) {
2165                closeStatement( pstmt );
2166                abortTransaction( transaction );
2167                throw new GeneralSecurityException( "SQLRegistry.setRolesForUser() failed. Rollback performed. "
2168                                                    + "Error message: " + e.getMessage() );
2169            }
2170        }
2171    
2172        /**
2173         * Sets the <code>Role</code> s that a given <code>Group</code> is associated to directly
2174         * (i.e. not via inheritance).
2175         * 
2176         * @param transaction
2177         * @param group
2178         * @param roles
2179         * @throws GeneralSecurityException
2180         */
2181        public void setRolesForGroup( SecurityTransaction transaction, Group group, Role[] roles )
2182                                throws GeneralSecurityException {
2183            PreparedStatement pstmt = null;
2184    
2185            try {
2186                pstmt = transactionalConnection.prepareStatement( "DELETE FROM SEC_JT_GROUPS_ROLES WHERE FK_GROUPS=?" );
2187                pstmt.setInt( 1, group.getID() );
2188                pstmt.executeUpdate();
2189                pstmt.close();
2190                pstmt = null;
2191    
2192                for ( int i = 0; i < roles.length; i++ ) {
2193                    pstmt = transactionalConnection.prepareStatement( "INSERT INTO SEC_JT_GROUPS_ROLES (FK_GROUPS, FK_ROLES) VALUES (?,?)" );
2194                    pstmt.setInt( 1, group.getID() );
2195                    pstmt.setInt( 2, roles[i].getID() );
2196                    pstmt.executeUpdate();
2197                    pstmt.close();
2198                    pstmt = null;
2199                }
2200            } catch ( SQLException e ) {
2201                closeStatement( pstmt );
2202                abortTransaction( transaction );
2203                throw new GeneralSecurityException( "SQLRegistry.setRolesForGroup() failed. Rollback performed. "
2204                                                    + "Error message: " + e.getMessage() );
2205            }
2206        }
2207    
2208        /**
2209         * Initializes the <code>SQLRegistry</code> -instance according to the contents of the
2210         * submitted <code>Properties</code>.
2211         * 
2212         * @param properties
2213         * @throws GeneralSecurityException
2214         */
2215        public void initialize( Properties properties )
2216                                throws GeneralSecurityException {
2217            this.dbDriver = properties.getProperty( "driver" );
2218            this.dbName = properties.getProperty( "url" );
2219            this.dbUser = properties.getProperty( "user" );
2220            this.dbPassword = properties.getProperty( "password" );
2221        }
2222    
2223        /**
2224         * Signals the <code>SQLRegistry</code> that a new transaction begins.
2225         * 
2226         * Only one transaction can be active at a time.
2227         * 
2228         * 
2229         * @param transaction
2230         * @throws GeneralSecurityException
2231         */
2232        public synchronized void beginTransaction( SecurityTransaction transaction )
2233                                throws GeneralSecurityException {
2234            try {
2235                transactionalConnection = DBConnectionPool.getInstance().acquireConnection( dbDriver, dbName, dbUser,
2236                                                                                            dbPassword );
2237                // transactionalConnection.setAutoCommit(false);
2238            } catch ( Exception e ) {
2239                throw new GeneralSecurityException( e );
2240            }
2241        }
2242    
2243        /**
2244         * Signals the <code>SQLRegistry</code> that the current transaction ends, i.e. the changes
2245         * made by the transaction are made persistent.
2246         * 
2247         * @param transaction
2248         * @throws GeneralSecurityException
2249         */
2250        public void commitTransaction( SecurityTransaction transaction )
2251                                throws GeneralSecurityException {
2252            try {
2253                transactionalConnection.commit();
2254            } catch ( SQLException e ) {
2255                throw new GeneralSecurityException( "Committing of transaction failed: " + e.getMessage() );
2256            } finally {
2257                try {
2258                    DBConnectionPool.getInstance().releaseConnection( transactionalConnection, dbDriver, dbName, dbUser,
2259                                                                      dbPassword );
2260                } catch ( Exception e ) {
2261                    e.printStackTrace();
2262                }
2263            }
2264        }
2265    
2266        /**
2267         * Signals the <code>SQLRegistry</code> that the current transaction shall be aborted. Changes
2268         * made during the transaction are undone.
2269         * 
2270         * @param transaction
2271         * @throws GeneralSecurityException
2272         */
2273        public void abortTransaction( SecurityTransaction transaction )
2274                                throws GeneralSecurityException {
2275            try {
2276                transactionalConnection.rollback();
2277            } catch ( SQLException e ) {
2278                throw new GeneralSecurityException( "Aborting of transaction failed: " + e.getMessage() );
2279            } finally {
2280                try {
2281                    DBConnectionPool.getInstance().releaseConnection( transactionalConnection, dbDriver, dbName, dbUser,
2282                                                                      dbPassword );
2283                } catch ( Exception e ) {
2284                    e.printStackTrace();
2285                }
2286            }
2287        }
2288    
2289        /**
2290         * Acquires a new <code>Connection</code>. If the given securityAccess is the exclusive
2291         * Read/Write-transaction holder, the transactionalConnection is returned, else a new
2292         * <code>Connection</code> is taken from the pool.
2293         * 
2294         * @param securityAccess
2295         * @return
2296         * @throws GeneralSecurityException
2297         */
2298        private Connection acquireLocalConnection( SecurityAccess securityAccess )
2299                                throws GeneralSecurityException {
2300    
2301            Connection con = null;
2302    
2303            if ( securityAccess instanceof SecurityTransaction ) {
2304                con = transactionalConnection;
2305            } else {
2306                try {
2307                    con = DBConnectionPool.getInstance().acquireConnection( dbDriver, dbName, dbUser, dbPassword );
2308                    // con.setAutoCommit(false);
2309                } catch ( Exception e ) {
2310                    throw new GeneralSecurityException( e );
2311                }
2312            }
2313            return con;
2314        }
2315    
2316        /**
2317         * Releases a <code>Connection</code>. If the given securityAccess is the exclusive
2318         * Read/Write-transaction holder, nothing happens, else it is returned to the pool.
2319         * 
2320         * @param securityAccess
2321         * @param con
2322         * @return
2323         * @throws GeneralSecurityException
2324         */
2325        private void releaseLocalConnection( SecurityAccess securityAccess, Connection con )
2326                                throws GeneralSecurityException {
2327    
2328            if ( !( securityAccess instanceof SecurityTransaction ) ) {
2329                if ( con != null ) {
2330                    try {
2331                        DBConnectionPool.getInstance().releaseConnection( con, dbDriver, dbName, dbUser, dbPassword );
2332                    } catch ( Exception e ) {
2333                        throw new GeneralSecurityException( e );
2334                    }
2335                }
2336            }
2337        }
2338    
2339        /**
2340         * Closes the given <code>Statement</code> if it is not null.
2341         * 
2342         * @param stmt
2343         * @throws GeneralSecurityException
2344         */
2345        private void closeStatement( Statement stmt )
2346                                throws GeneralSecurityException {
2347            if ( stmt != null ) {
2348                try {
2349                    stmt.close();
2350                } catch ( SQLException e ) {
2351                    throw new GeneralSecurityException( e );
2352                }
2353            }
2354        }
2355    
2356        /**
2357         * Closes the given <code>ResultSet</code> if it is not null.
2358         * 
2359         * @param rs
2360         * @throws GeneralSecurityException
2361         */
2362        private void closeResultSet( ResultSet rs )
2363                                throws GeneralSecurityException {
2364            if ( rs != null ) {
2365                try {
2366                    rs.close();
2367                } catch ( SQLException e ) {
2368                    throw new GeneralSecurityException( e );
2369                }
2370            }
2371        }
2372    
2373        /**
2374         * Retrieves an unused PrimaryKey-value for the given table. The table must have its PrimaryKey
2375         * in an Integer-field named 'ID'.
2376         * 
2377         * @param table
2378         * @return
2379         */
2380        private int getID( SecurityTransaction transaction, String table )
2381                                throws GeneralSecurityException {
2382            int id = 0;
2383            Connection con = acquireLocalConnection( transaction );
2384    
2385            try {
2386                DataBaseIDGenerator idGenerator = IDGeneratorFactory.createIDGenerator( con, table, "ID" );
2387                Object o = idGenerator.generateUniqueId();
2388                if ( !( o instanceof Integer ) ) {
2389                    throw new GeneralSecurityException( "Error generating new PrimaryKey for table '" + table + "'." );
2390                }
2391                id = ( (Integer) o ).intValue();
2392            } catch ( SQLException e ) {
2393                throw new GeneralSecurityException( e );
2394            } finally {
2395                releaseLocalConnection( transaction, con );
2396            }
2397            return id;
2398        }
2399    
2400        /**
2401         * Tries to build a <code>ComplexFilter</code> from the given string representation.
2402         * 
2403         * @param constraints
2404         * @return
2405         * @throws GeneralSecurityException
2406         */
2407        private ComplexFilter buildFilter( String constraints )
2408                                throws GeneralSecurityException {
2409            Filter filter = null;
2410            try {
2411                Document document = XMLTools.parse( new StringReader( constraints ) );
2412                Element element = document.getDocumentElement();
2413                filter = AbstractFilter.buildFromDOM( element );
2414            } catch ( FilterConstructionException e ) {
2415                throw new GeneralSecurityException( "The stored constraint is not a valid filter: " + e.getMessage() );
2416            } catch ( Exception e ) {
2417                throw new GeneralSecurityException( "Error parsing the stored constraint: " + e.getMessage() );
2418            }
2419            if ( !( filter instanceof ComplexFilter ) ) {
2420                throw new GeneralSecurityException( "The stored constraint is not of type 'ComplexFilter'." );
2421            }
2422            return (ComplexFilter) filter;
2423        }
2424    }