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