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