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