001    //$HeadURL: https://svn.wald.intevation.org/svn/deegree/base/branches/2.3_testing/src/org/deegree/portal/standard/security/control/StoreRightsListener.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.portal.standard.security.control;
037    
038    import java.io.StringReader;
039    import java.util.ArrayList;
040    import java.util.HashMap;
041    import java.util.List;
042    import java.util.Map;
043    
044    import org.deegree.enterprise.control.AbstractListener;
045    import org.deegree.enterprise.control.FormEvent;
046    import org.deegree.enterprise.control.RPCException;
047    import org.deegree.enterprise.control.RPCMember;
048    import org.deegree.enterprise.control.RPCMethodCall;
049    import org.deegree.enterprise.control.RPCParameter;
050    import org.deegree.enterprise.control.RPCStruct;
051    import org.deegree.enterprise.control.RPCUtils;
052    import org.deegree.enterprise.control.RPCWebEvent;
053    import org.deegree.framework.log.ILogger;
054    import org.deegree.framework.log.LoggerFactory;
055    import org.deegree.framework.xml.XMLTools;
056    import org.deegree.i18n.Messages;
057    import org.deegree.model.filterencoding.AbstractFilter;
058    import org.deegree.model.filterencoding.Filter;
059    import org.deegree.security.GeneralSecurityException;
060    import org.deegree.security.UnauthorizedException;
061    import org.deegree.security.drm.SecurityAccessManager;
062    import org.deegree.security.drm.SecurityTransaction;
063    import org.deegree.security.drm.model.Right;
064    import org.deegree.security.drm.model.RightType;
065    import org.deegree.security.drm.model.Role;
066    import org.deegree.security.drm.model.SecuredObject;
067    import org.deegree.security.drm.model.User;
068    import org.w3c.dom.Document;
069    
070    /**
071     * This <code>Listener</code> reacts on RPC-StoreRights events.
072     *
073     * Access constraints:
074     * <ul>
075     * <li>only users that have the 'SEC_ADMIN'-role are allowed</li>
076     * </ul>
077     *
078     * @author <a href="mschneider@lat-lon.de">Markus Schneider </a>
079     * @author last edited by: $Author: mschneider $
080     *
081     * @version $Revision: 18195 $, $Date: 2009-06-18 17:55:39 +0200 (Do, 18. Jun 2009) $
082     */
083    public class StoreRightsListener extends AbstractListener {
084    
085        private static final ILogger LOG = LoggerFactory.getLogger( StoreRightsListener.class );
086    
087        private static final String MINX = "-180.0";
088    
089        private static final String MINY = "-90.0";
090    
091        private static final String MAXX = "180.0";
092    
093        private static final String MAXY = "90.0";
094    
095        @Override
096        public void actionPerformed( FormEvent event ) {
097    
098            // the Role for which the rights are to be set
099            int roleId = -1;
100            // array of ints, ids of Layers (SecuredObjects) for which
101            // the Role has access rights
102            int[] layers = null;
103            // corresponding maps of key (PropertyName) / value-pairs that
104            // constitute access constraints
105            Map<String, Object>[] layerConstraints = null;
106    
107            SecurityAccessManager manager = null;
108            SecurityTransaction transaction = null;
109    
110            try {
111                RPCWebEvent ev = (RPCWebEvent) event;
112                RPCMethodCall rpcCall = ev.getRPCMethodCall();
113                RPCParameter[] params = rpcCall.getParameters();
114    
115                // validates the incomming method call and extracts the roleID
116                roleId = validate( params );
117    
118                RPCParameter[] layerParams = (RPCParameter[]) params[1].getValue();
119                layers = new int[layerParams.length];
120                layerConstraints = new Map[layerParams.length];
121                extractLayerValues( layers, layerConstraints, layerParams );
122    
123                // extract FeatureType rights
124                if ( !( params[2].getValue() instanceof RPCParameter[] ) ) {
125                    throw new RPCException( Messages.getMessage( "IGEO_STD_STORERIGHTS_THIRD_PARAM" ) );
126                }
127    
128                // array of ints, ids of FeatureTypes (SecuredObjects) for which
129                // the Role has access rights
130                FeatureTypeRight[] featureTypes = extractFeatureTypeValues( params );
131    
132                transaction = SecurityHelper.acquireTransaction( this );
133                SecurityHelper.checkForAdminRole( transaction );
134    
135                manager = SecurityAccessManager.getInstance();
136                User user = transaction.getUser();
137                Role role = transaction.getRoleById( roleId );
138    
139                // perform access check
140                if ( !user.hasRight( transaction, "update", role ) ) {
141                    getRequest().setAttribute( "SOURCE", this.getClass().getName() );
142                    String s = Messages.getMessage( "IGEO_STD_STORERIGHTS_MISSING_RIGHTS", role.getName() );
143                    getRequest().setAttribute( "MESSAGE", s );
144                    setNextPage( "error.jsp" );
145                    return;
146                }
147    
148                // set/delete access rights for Layers
149                SecuredObject[] presentLayers = transaction.getAllSecuredObjects( ClientHelper.TYPE_LAYER );
150                setAccessRightsForLayers( layers, layerConstraints, transaction, role, presentLayers );
151    
152                // set/delete access rights for FeatureTypes
153                SecuredObject[] presentFeatureTypes = transaction.getAllSecuredObjects( ClientHelper.TYPE_FEATURETYPE );
154                setAccessRightsForFeatureTypes( featureTypes, transaction, role, presentFeatureTypes );
155    
156                manager.commitTransaction( transaction );
157                transaction = null;
158                String s = Messages.getMessage( "IGEO_STD_STORERIGHTS_SUCCESS", role.getID() );
159                getRequest().setAttribute( "MESSAGE", s );
160            } catch ( RPCException e ) {
161                getRequest().setAttribute( "SOURCE", this.getClass().getName() );
162                String s = Messages.getMessage( "IGEO_STD_STORERIGHTS_INVALID_REQ", e.getMessage() );
163                getRequest().setAttribute( "MESSAGE", s );
164                setNextPage( "error.jsp" );
165                LOG.logDebug( e.getMessage(), e );
166            } catch ( GeneralSecurityException e ) {
167                getRequest().setAttribute( "SOURCE", this.getClass().getName() );
168                String s = Messages.getMessage( "IGEO_STD_STORERIGHTS_ERROR", e.getMessage() );
169                getRequest().setAttribute( "MESSAGE", s );
170                setNextPage( "error.jsp" );
171                LOG.logDebug( e.getMessage(), e );
172            } finally {
173                if ( manager != null && transaction != null ) {
174                    try {
175                        manager.abortTransaction( transaction );
176                    } catch ( GeneralSecurityException e ) {
177                        LOG.logDebug( e.getMessage(), e );
178                    }
179                }
180            }
181    
182        }
183    
184        private void setAccessRightsForFeatureTypes( FeatureTypeRight[] featureTypes, SecurityTransaction transaction,
185                                                     Role role, SecuredObject[] presentFeatureTypes )
186                                throws GeneralSecurityException, UnauthorizedException {
187            for ( int i = 0; i < presentFeatureTypes.length; i++ ) {
188                boolean selected = false;
189                SecuredObject featureType = presentFeatureTypes[i];
190                FeatureTypeRight ftr = null;
191                for ( int j = 0; j < featureTypes.length; j++ ) {
192                    ftr = featureTypes[j];
193                    if ( featureType.getID() == ftr.id && ftr.access ) {
194                        selected = true;
195                        break;
196                    }
197                }
198                if ( selected ) {
199                    List<RightType> setRights = new ArrayList<RightType>();
200                    List<RightType> removedRights = new ArrayList<RightType>();
201                    setRights.add( RightType.GETFEATURE );
202                    setRights.add( RightType.DESCRIBEFEATURETYPE );
203    
204                    if ( ftr.insert ) {
205                        setRights.add( RightType.INSERT );
206                    } else {
207                        removedRights.add( RightType.INSERT );
208                    }
209                    if ( ftr.update ) {
210                        setRights.add( RightType.UPDATE );
211                    } else {
212                        removedRights.add( RightType.UPDATE );
213                    }
214                    if ( ftr.delete ) {
215                        setRights.add( RightType.DELETE );
216                    } else {
217                        removedRights.add( RightType.DELETE );
218                    }
219                    RightType[] rights = removedRights.toArray( new RightType[removedRights.size()] );
220                    transaction.removeRights( featureType, role, rights );
221                    rights = setRights.toArray( new RightType[setRights.size()] );
222                    transaction.addRights( featureType, role, rights );
223                } else {
224                    RightType[] rights = new RightType[] { RightType.GETFEATURE, RightType.DESCRIBEFEATURETYPE,
225                                                          RightType.INSERT, RightType.DELETE, RightType.UPDATE };
226                    transaction.removeRights( featureType, role, rights );
227                }
228            }
229        }
230    
231        private void setAccessRightsForLayers( int[] layers, Map[] layerConstraints, SecurityTransaction transaction,
232                                               Role role, SecuredObject[] presentLayers )
233                                throws RPCException, GeneralSecurityException, UnauthorizedException {
234            for ( int i = 0; i < presentLayers.length; i++ ) {
235                boolean isAccessible = false;
236                Map constraintMap = null;
237                SecuredObject layer = presentLayers[i];
238                for ( int j = 0; j < layers.length; j++ ) {
239                    if ( layer.getID() == layers[j] ) {
240                        isAccessible = true;
241                        constraintMap = layerConstraints[j];
242                        break;
243                    }
244                }
245                if ( isAccessible ) {
246                    Filter filter = null;
247                    if ( constraintMap != null ) {
248                        String xml = buildGetMapFilter( constraintMap );
249                        if ( xml != null ) {
250                            try {
251                                Document doc = XMLTools.parse( new StringReader( xml ) );
252                                filter = AbstractFilter.buildFromDOM( doc.getDocumentElement() );
253                            } catch ( Exception e ) {
254                                String s = Messages.getMessage( "IGEO_STD_STORERIGHTS_FILTER_PARSING_ERROR", e.getMessage() );
255                                throw new GeneralSecurityException( s );
256                            }
257                        }
258                        if ( filter != null ) {
259                            LOG.logInfo( "Back to XML: " + filter.toXML() );
260                        }
261                    }
262                    Right[] rights = new Right[] { new Right( layer, RightType.GETMAP, filter ),
263                                                  new Right( layer, RightType.GETFEATUREINFO ),
264                                                  new Right( layer, RightType.GETLEGENDGRAPHIC ) };
265                    transaction.setRights( layer, role, rights );
266                } else {
267                    transaction.removeRights( layer, role, new RightType[] { RightType.GETMAP, RightType.GETFEATUREINFO,
268                                                                            RightType.GETLEGENDGRAPHIC } );
269                }
270            }
271        }
272    
273        private FeatureTypeRight[] extractFeatureTypeValues( RPCParameter[] params )
274                                throws RPCException {
275            FeatureTypeRight[] ftr;
276            RPCParameter[] featureTypeParams = (RPCParameter[]) params[2].getValue();
277            ftr = new FeatureTypeRight[featureTypeParams.length];
278            for ( int i = 0; i < featureTypeParams.length; i++ ) {
279                if ( featureTypeParams[i].getValue() instanceof String ) {
280                    // to be compliant to former versions
281                    int id = 0;
282                    try {
283                        id = Integer.parseInt( (String) featureTypeParams[i].getValue() );
284                    } catch ( NumberFormatException e ) {
285                        String s = Messages.getMessage( "IGEO_STD_STORERIGHTS_INT_EXPECTED" );
286                        throw new RPCException( s );
287                    }
288    
289                    ftr[i] = new FeatureTypeRight( id, true, false, false, false );
290    
291                } else if ( featureTypeParams[i].getValue().getClass() == RPCParameter[].class ) {
292                    RPCParameter[] pm = (RPCParameter[]) featureTypeParams[i].getValue();
293    
294                    int id = 0;
295                    try {
296                        id = Integer.parseInt( (String) pm[0].getValue() );
297                    } catch ( NumberFormatException e ) {
298                        String s = Messages.getMessage( "IGEO_STD_STORERIGHTS_INT_EXPECTED" );
299                        throw new RPCException( s );
300                    }
301    
302                    boolean access = false;
303                    boolean delete = false;
304                    boolean insert = false;
305                    boolean update = false;
306                    RPCStruct struct = (RPCStruct) pm[1].getValue();
307                    String s = RPCUtils.getRpcPropertyAsString( struct, "ACCESS" );
308                    access = "true".equals( s );
309                    s = RPCUtils.getRpcPropertyAsString( struct, "INSERT" );
310                    insert = "true".equals( s );
311                    s = RPCUtils.getRpcPropertyAsString( struct, "UPDATE" );
312                    update = "true".equals( s );
313                    s = RPCUtils.getRpcPropertyAsString( struct, "DELETE" );
314                    delete = "true".equals( s );
315                    ftr[i] = new FeatureTypeRight( id, access, insert, update, delete );
316                } else {
317                    throw new RPCException( Messages.getMessage( "IGEO_STD_STORERIGHTS_WRONGTYPE" ) );
318                }
319            }
320            return ftr;
321        }
322    
323        private void extractLayerValues( int[] layers, Map<String, Object>[] layerConstraints, RPCParameter[] layerParams )
324                                throws RPCException {
325            for ( int i = 0; i < layerParams.length; i++ ) {
326    
327                // is the layer access constrained?
328                if ( layerParams[i].getValue() instanceof RPCParameter[] ) {
329                    layerConstraints[i] = new HashMap<String, Object>();
330                    RPCParameter[] constrainParams = (RPCParameter[]) layerParams[i].getValue();
331                    try {
332                        layers[i] = Integer.parseInt( (String) constrainParams[0].getValue() );
333                    } catch ( NumberFormatException e ) {
334                        String s = Messages.getMessage( "IGEO_STD_STORERIGHTS_INT_EXPECTED" );
335                        throw new RPCException( s );
336                    }
337                    RPCParameter param = constrainParams[1];
338                    RPCStruct constraints = (RPCStruct) param.getValue();
339                    RPCMember[] members = constraints.getMembers();
340                    for ( int j = 0; j < members.length; j++ ) {
341                        String propertyName = members[j].getName();
342                        Object value = members[j].getValue();
343                        if ( value instanceof RPCParameter[] ) {
344                            String[] values = new String[( (RPCParameter[]) value ).length];
345                            for ( int k = 0; k < values.length; k++ ) {
346                                values[k] = (String) ( (RPCParameter[]) value )[k].getValue();
347                            }
348                            layerConstraints[i].put( propertyName, values );
349                        } else if ( value instanceof String ) {
350                            layerConstraints[i].put( propertyName, value );
351                        } else {
352                            String s = Messages.getMessage( "IGEO_STD_STORERIGHTS_LAYER_ACCESSCONSTRAINTS" );
353                            throw new RPCException( s );
354                        }
355                    }
356                } else if ( layerParams[i].getValue() instanceof String ) {
357                    try {
358                        layers[i] = Integer.parseInt( (String) layerParams[i].getValue() );
359                    } catch ( NumberFormatException e ) {
360                        String s = Messages.getMessage( "IGEO_STD_STORERIGHTS_INT_EXPECTED" );
361                        throw new RPCException( s );
362                    }
363                } else {
364                    String s = Messages.getMessage( "IGEO_STD_STORERIGHTS_LAYER_ACCESSCONSTRAINTS" );
365                    throw new RPCException( s );
366                }
367            }
368        }
369    
370        private int validate( RPCParameter[] params )
371                                throws RPCException {
372    
373            // FIXME this is a workaround !!!
374            // originaly, params.length needed to be exactly 3. (thus the error message)
375            // now, pdfplot client uses an RPC with a params.length of 4.
376            if ( params.length != 3 && params.length != 4 ) {
377                throw new RPCException( Messages.getMessage( "IGEO_STD_SEC_WRONG_PARAMS_NUM", "3" ) );
378            }
379    //        if ( params.length != 3 ) {
380    //            throw new RPCException( Messages.getMessage( "IGEO_STD_SEC_WRONG_PARAMS_NUM", "3" ) );
381    //        }
382            if ( !( params[0].getValue() instanceof String ) ) {
383                throw new RPCException( Messages.getMessage( "IGEO_STD_STORERIGHTS_FIRST_PARAM" ) );
384            }
385    
386            // extract role-id
387            int roleId = -1;
388            try {
389                roleId = Integer.parseInt( (String) params[0].getValue() );
390            } catch ( NumberFormatException e ) {
391                throw new RPCException( Messages.getMessage( "IGEO_STD_STORERIGHTS_ROLE_PARAM" ) );
392            }
393    
394            // extract Layer rights
395            if ( !( params[1].getValue() instanceof RPCParameter[] ) ) {
396                throw new RPCException( Messages.getMessage( "IGEO_STD_STORERIGHTS_SECOND_PARAM" ) );
397            }
398            return roleId;
399        }
400    
401        /**
402         * Builds a filter encoding-expression as a constraint for GetMap-operations from the values
403         * stored in the given <code>Map</code>.
404         *
405         * @param constraintMap
406         * @return String
407         * @throws RPCException
408         */
409        String buildGetMapFilter( Map constraintMap )
410                                throws RPCException {
411    
412            int operands = 0;
413            StringBuffer sb = new StringBuffer( 1000 );
414    
415            // bbox
416            if ( constraintMap.get( "bbox" ) != null ) {
417                operands++;
418                String minx = MINX;
419                String miny = MINY;
420                String maxx = MAXX;
421                String maxy = MAXY;
422    
423                String[] bbox = (String[]) constraintMap.get( "bbox" );
424                if ( bbox.length != 4 ) {
425                    throw new RPCException( Messages.getMessage( "IGEO_STD_STORERIGHTS_BBOX_ERROR" ) );
426                }
427                minx = bbox[0];
428                miny = bbox[1];
429                maxx = bbox[2];
430                maxy = bbox[3];
431    
432                sb.append( "<ogc:Within>" );
433                sb.append( "<ogc:PropertyName>GEOM</ogc:PropertyName>" );
434                sb.append( "<gml:Box>" );
435                sb.append( "<gml:coordinates>" );
436                sb.append( minx ).append( ',' ).append( miny ).append( ' ' );
437                sb.append( maxx ).append( ',' ).append( maxy );
438                sb.append( "</gml:coordinates>" );
439                sb.append( "</gml:Box></ogc:Within>" );
440            }
441    
442            // bgcolor
443            String[] bgcolors = (String[]) constraintMap.get( "bgcolor" );
444            if ( bgcolors != null && bgcolors.length > 0 ) {
445                operands++;
446                if ( bgcolors.length > 1 ) {
447                    sb.append( "<ogc:Or>" );
448                }
449                for ( int i = 0; i < bgcolors.length; i++ ) {
450                    sb.append( "<ogc:PropertyIsEqualTo>" );
451                    sb.append( "<ogc:PropertyName>bgcolor</ogc:PropertyName>" );
452                    sb.append( "<ogc:Literal><![CDATA[" + bgcolors[i] + "]]></ogc:Literal>" );
453                    sb.append( "</ogc:PropertyIsEqualTo>" );
454                }
455                if ( bgcolors.length > 1 ) {
456                    sb.append( "</ogc:Or>" );
457                }
458            }
459    
460            // transparent
461            String transparent = (String) constraintMap.get( "transparent" );
462            if ( transparent != null ) {
463                operands++;
464                sb.append( "<ogc:PropertyIsEqualTo>" );
465                sb.append( "<ogc:PropertyName>transparent</ogc:PropertyName>" );
466                sb.append( "<ogc:Literal><![CDATA[" + transparent + "]]></ogc:Literal>" );
467                sb.append( "</ogc:PropertyIsEqualTo>" );
468            }
469    
470            // format
471            String[] formats = (String[]) constraintMap.get( "format" );
472            if ( formats != null && formats.length > 0 ) {
473                operands++;
474                if ( formats.length > 1 ) {
475                    sb.append( "<ogc:Or>" );
476                }
477                for ( int i = 0; i < formats.length; i++ ) {
478                    sb.append( "<ogc:PropertyIsEqualTo>" );
479                    sb.append( "<ogc:PropertyName>format</ogc:PropertyName>" );
480                    sb.append( "<ogc:Literal><![CDATA[" + formats[i] + "]]></ogc:Literal>" );
481                    sb.append( "</ogc:PropertyIsEqualTo>" );
482                }
483                if ( formats.length > 1 ) {
484                    sb.append( "</ogc:Or>" );
485                }
486            }
487    
488            // resolution
489            String resolution = (String) constraintMap.get( "resolution" );
490            if ( resolution != null ) {
491                operands++;
492                sb.append( "<ogc:PropertyIsGreaterThanOrEqualTo>" );
493                sb.append( "<ogc:PropertyName>resolution</ogc:PropertyName>" );
494                sb.append( "<ogc:Literal>" ).append( resolution ).append( "</ogc:Literal>" );
495                sb.append( "</ogc:PropertyIsGreaterThanOrEqualTo>" );
496            }
497    
498            // width
499            String width = (String) constraintMap.get( "width" );
500            if ( width != null ) {
501                operands++;
502                sb.append( "<ogc:PropertyIsLessThanOrEqualTo>" );
503                sb.append( "<ogc:PropertyName>width</ogc:PropertyName>" );
504                sb.append( "<ogc:Literal>" ).append( width ).append( "</ogc:Literal>" );
505                sb.append( "</ogc:PropertyIsLessThanOrEqualTo>" );
506            }
507    
508            // height
509            String height = (String) constraintMap.get( "height" );
510            if ( height != null ) {
511                operands++;
512                sb.append( "<ogc:PropertyIsLessThanOrEqualTo>" );
513                sb.append( "<ogc:PropertyName>height</ogc:PropertyName>" );
514                sb.append( "<ogc:Literal>" ).append( height ).append( "</ogc:Literal>" );
515                sb.append( "</ogc:PropertyIsLessThanOrEqualTo>" );
516            }
517    
518            // exceptions
519            String[] exceptions = (String[]) constraintMap.get( "exceptions" );
520            if ( exceptions != null && exceptions.length > 0 ) {
521                operands++;
522                if ( exceptions.length > 1 ) {
523                    sb.append( "<ogc:Or>" );
524                }
525                for ( int i = 0; i < exceptions.length; i++ ) {
526                    sb.append( "<ogc:PropertyIsEqualTo>" );
527                    sb.append( "<ogc:PropertyName>exceptions</ogc:PropertyName>" );
528                    sb.append( "<ogc:Literal><![CDATA[" ).append( exceptions[i] );
529                    sb.append( "]]></ogc:Literal>" );
530                    sb.append( "</ogc:PropertyIsEqualTo>" );
531                }
532                if ( exceptions.length > 1 ) {
533                    sb.append( "</ogc:Or>" );
534                }
535            }
536    
537            if ( operands == 0 ) {
538                return null;
539            } else if ( operands >= 2 ) {
540                StringBuffer tmp = new StringBuffer( 500 );
541                tmp.append( "<ogc:Filter xmlns:ogc=\"http://www.opengis.net/ogc\" " );
542                tmp.append( "xmlns:gml=\"http://www.opengis.net/gml\">" );
543                tmp.append( "<ogc:And>" ).append( sb ).append( "</ogc:And></ogc:Filter>" );
544                sb = tmp;
545            } else {
546                StringBuffer tmp = new StringBuffer();
547                tmp.append( "<ogc:Filter xmlns:ogc=\"http://www.opengis.net/ogc\" " );
548                tmp.append( "xmlns:gml=\"http://www.opengis.net/gml\">" );
549                tmp.append( sb ).append( "</ogc:Filter>" );
550                sb = tmp;
551            }
552            return sb.toString();
553        }
554    
555        /**
556         * private class for temporary storing rights enabled on a featureType
557         *
558         *
559         * @version $Revision: 18195 $
560         * @author <a href="mailto:poth@lat-lon.de">Andreas Poth</a>
561         * @author last edited by: $Author: mschneider $
562         *
563         * @version 1.0. $Revision: 18195 $, $Date: 2009-06-18 17:55:39 +0200 (Do, 18. Jun 2009) $
564         *
565         * @since 2.0
566         */
567        private class FeatureTypeRight {
568    
569            /**
570             *
571             */
572            public int id = 0;
573    
574            /**
575             *
576             */
577            public boolean access = true;
578    
579            /**
580             *
581             */
582            public boolean delete = true;
583    
584            /**
585             *
586             */
587            public boolean insert = true;
588    
589            /**
590             *
591             */
592            public boolean update = true;
593    
594            /**
595             *
596             * @param id
597             * @param access
598             * @param insert
599             * @param update
600             * @param delete
601             */
602            FeatureTypeRight( int id, boolean access, boolean insert, boolean update, boolean delete ) {
603                this.id = id;
604                this.access = access;
605                this.insert = insert;
606                this.update = update;
607                this.delete = delete;
608            }
609    
610        }
611    
612    }