001    /*
002     *  Licensed to the Apache Software Foundation (ASF) under one
003     *  or more contributor license agreements.  See the NOTICE file
004     *  distributed with this work for additional information
005     *  regarding copyright ownership.  The ASF licenses this file
006     *  to you under the Apache License, Version 2.0 (the
007     *  "License"); you may not use this file except in compliance
008     *  with the License.  You may obtain a copy of the License at
009     *  
010     *    http://www.apache.org/licenses/LICENSE-2.0
011     *  
012     *  Unless required by applicable law or agreed to in writing,
013     *  software distributed under the License is distributed on an
014     *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015     *  KIND, either express or implied.  See the License for the
016     *  specific language governing permissions and limitations
017     *  under the License. 
018     *  
019     */
020    package org.apache.directory.server.core.interceptor.context;
021    
022    
023    import static org.apache.directory.shared.ldap.filter.SearchScope.ONELEVEL;
024    
025    import java.util.Collection;
026    import java.util.HashSet;
027    import java.util.Set;
028    
029    import javax.naming.NamingException;
030    import javax.naming.directory.SearchControls;
031    
032    import org.apache.directory.server.core.CoreSession;
033    import org.apache.directory.shared.ldap.constants.SchemaConstants;
034    import org.apache.directory.shared.ldap.exception.LdapNoSuchAttributeException;
035    import org.apache.directory.shared.ldap.filter.SearchScope;
036    import org.apache.directory.shared.ldap.message.AliasDerefMode;
037    import org.apache.directory.shared.ldap.name.DN;
038    import org.apache.directory.shared.ldap.schema.AttributeType;
039    import org.apache.directory.shared.ldap.schema.AttributeTypeOptions;
040    import org.apache.directory.shared.ldap.schema.SchemaUtils;
041    import org.apache.directory.shared.ldap.util.ArrayUtils;
042    import org.apache.directory.shared.ldap.util.StringTools;
043    import org.slf4j.Logger;
044    import org.slf4j.LoggerFactory;
045    
046    
047    /**
048     * A context used for search related operations and used by all 
049     * the Interceptors.
050     *
051     * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
052     * @version $Rev$, $Date$
053     */
054    public abstract class SearchingOperationContext extends AbstractOperationContext
055    {
056        /** The LoggerFactory used by this Interceptor */
057        private static Logger LOG = LoggerFactory.getLogger( SearchingOperationContext.class );
058        
059        /** A flag describing the way alias should be handled */
060        protected AliasDerefMode aliasDerefMode = AliasDerefMode.DEREF_ALWAYS;
061    
062        /** The sizeLimit for this search operation */
063        protected long sizeLimit = 0;
064        
065        /** The timeLimit for this search operation */
066        protected int timeLimit = 0;
067        
068        /** The scope for this search : default to One Level */
069        protected SearchScope scope = ONELEVEL;
070    
071        /** A flag set if the returned attributes set contains '+' */
072        protected boolean allOperationalAttributes = false;
073        
074        /** A flag set if the returned attributes set contains '*' */
075        protected boolean allUserAttributes = false;
076        
077        /** A flag set if the returned attributes set contains '1.1' */
078        protected boolean noAttributes = false;
079        
080        /** A set containing the returning attributeTypesOptions */
081        protected Set<AttributeTypeOptions> returningAttributes; 
082        
083        /** A flag if the search operation is abandoned */
084        protected boolean abandoned = false;
085        
086        /** A flag to tell if only the attribute names to be returned */
087        protected boolean typesOnly = false;
088        
089        /**
090         * Creates a new instance of SearchingOperationContext.
091         */
092        public SearchingOperationContext( CoreSession session )
093        {
094            super( session );
095        }
096    
097    
098        /**
099         * Creates a new instance of SearchingOperationContext.
100         *
101         * @param dn The DN to get the suffix from
102         */
103        public SearchingOperationContext( CoreSession session, DN dn )
104        {
105            super( session, dn );
106        }
107    
108    
109        /**
110         * Creates a new instance of a SearchingOperationContext using one level 
111         * scope, with attributes to return.
112         *
113         * @param dn The DN to get the suffix from
114         * @param aliasDerefMode the alias dereferencing mode to use
115         * @throws NamingException 
116         */
117        public SearchingOperationContext( CoreSession session, DN dn, Set<AttributeTypeOptions> returningAttributes )
118        {
119            super( session, dn );
120            this.returningAttributes = returningAttributes;
121        }
122    
123    
124        protected void setReturningAttributes( Collection<String> attributesIds ) 
125            throws Exception
126        {
127            setReturningAttributes( attributesIds.toArray( StringTools.EMPTY_STRINGS ) );
128        }
129        
130        
131        protected void setReturningAttributes( String[] attributesIds ) throws Exception
132        {
133            if ( attributesIds != null && attributesIds.length != 0 )
134            {
135                returningAttributes = new HashSet<AttributeTypeOptions>();
136                
137                for ( String returnAttribute : attributesIds )
138                {
139                    if ( returnAttribute.equals( SchemaConstants.NO_ATTRIBUTE ) )
140                    {
141                        noAttributes = true;
142                        continue;
143                    }
144                    
145                    if ( returnAttribute.equals( SchemaConstants.ALL_OPERATIONAL_ATTRIBUTES ) )
146                    {
147                        allOperationalAttributes = true;
148                        continue;
149                    }
150                    
151                    if ( returnAttribute.equals( SchemaConstants.ALL_USER_ATTRIBUTES ) )
152                    {
153                        allUserAttributes = true;
154                        continue;
155                    }
156                    
157                    try
158                    {
159                        String id = SchemaUtils.stripOptions( returnAttribute );
160                        Set<String> options = SchemaUtils.getOptions( returnAttribute );
161                        
162                        AttributeType attributeType = session.getDirectoryService()
163                            .getSchemaManager().lookupAttributeTypeRegistry( id );
164                        AttributeTypeOptions attrOptions = new AttributeTypeOptions( attributeType, options );
165                       
166                        returningAttributes.add( attrOptions );
167                    }
168                    catch ( LdapNoSuchAttributeException nsae )
169                    {
170                        LOG.warn( "Requested attribute {} does not exist in the schema, it will be ignored", returnAttribute );
171                        // Unknown attributes should be silently ignored, as RFC 2251 states
172                    }
173                }
174                
175                // reset the noAttrubte flag if it is already set cause that will be ignored if any other AT is requested
176                if( noAttributes && ( allUserAttributes || allOperationalAttributes || ( ! returningAttributes.isEmpty() ) ) )
177                {
178                    noAttributes = false;
179                }   
180            }
181        }
182        
183        
184        /**
185         * @see Object#toString()
186         */
187        public String toString()
188        {
189            return "ListOperationContext with DN '" + getDn().getName() + "'";
190        }
191    
192        
193        public AliasDerefMode getAliasDerefMode()
194        {
195            return aliasDerefMode;
196        }
197    
198    
199        public void setAliasDerefMode( AliasDerefMode aliasDerefMode )
200        {
201            this.aliasDerefMode = aliasDerefMode;
202        }
203    
204    
205        /**
206         * @param sizeLimit the sizeLimit to set
207         */
208        public void setSizeLimit( long sizeLimit )
209        {
210            this.sizeLimit = sizeLimit;
211        }
212    
213    
214        /**
215         * @return the sizeLimit
216         */
217        public long getSizeLimit()
218        {
219            return sizeLimit;
220        }
221    
222    
223        /**
224         * @param timeLimit the timeLimit to set
225         */
226        public void setTimeLimit( int timeLimit )
227        {
228            this.timeLimit = timeLimit;
229        }
230    
231    
232        /**
233         * @return the timeLimit
234         */
235        public int getTimeLimit()
236        {
237            return timeLimit;
238        }
239    
240    
241        /**
242         * @param scope the scope to set
243         */
244        public void setScope( SearchScope scope )
245        {
246            this.scope = scope;
247        }
248    
249    
250        /**
251         * @return the scope
252         */
253        public SearchScope getScope()
254        {
255            return scope;
256        }
257    
258    
259        /**
260         * @param allOperationalAttributes the allOperationalAttributes to set
261         */
262        public void setAllOperationalAttributes( boolean allOperationalAttribute )
263        {
264            this.allOperationalAttributes = allOperationalAttribute;
265        }
266    
267    
268        /**
269         * @return the allOperationalAttributes
270         */
271        public boolean isAllOperationalAttributes()
272        {
273            return allOperationalAttributes;
274        }
275    
276    
277        /**
278         * @param allUserAttributes the allUserAttributes to set
279         */
280        public void setAllUserAttributes( boolean allUserAttributes )
281        {
282            this.allUserAttributes = allUserAttributes;
283        }
284    
285    
286        /**
287         * @return the allUserAttributes
288         */
289        public boolean isAllUserAttributes()
290        {
291            return allUserAttributes;
292        }
293    
294    
295        /**
296         * @param noAttributes the noAttributes to set
297         */
298        public void setNoAttributes( boolean noAttributes )
299        {
300            this.noAttributes = noAttributes;
301        }
302    
303    
304        /**
305         * @return the noAttributes
306         */
307        public boolean isNoAttributes()
308        {
309            return noAttributes;
310        }
311    
312    
313        /**
314         * @return true, if attribute descriptions alone need to be returned
315         */
316        public boolean isTypesOnly()
317        {
318            return typesOnly;
319        }
320    
321    
322        public void setTypesOnly( boolean typesOnly )
323        {
324            this.typesOnly = typesOnly;
325        }
326    
327    
328        /**
329         * @param returningAttributes the returningAttributes to set
330         */
331        public void setReturningAttributes( Set<AttributeTypeOptions> returningAttributes )
332        {
333            this.returningAttributes = returningAttributes;
334        }
335    
336    
337        /**
338         * @return the returningAttributes
339         */
340        public Set<AttributeTypeOptions> getReturningAttributes()
341        {
342            return returningAttributes;
343        }
344    
345        
346        /**
347         * Creates a new SearchControls object populated with the parameters 
348         * contained in this SearchOperationContext in normalized form.
349         *
350         * @return a new SearchControls object
351         */
352        public SearchControls getSearchControls()
353        {
354            return getSearchControls( false );
355        }
356        
357        
358        /**
359         * Creates a new SearchControls object populated with the parameters 
360         * contained in this SearchOperationContext.
361         *
362         * @param denormalized true if attribute values are <b>not</b> normalized
363         * @return a new SearchControls object
364         */
365        public SearchControls getSearchControls( boolean denormalized )
366        {
367            SearchControls controls = new SearchControls();
368            controls.setCountLimit( sizeLimit );
369            controls.setSearchScope( scope.getScope() );
370            controls.setTimeLimit( timeLimit );
371    
372            Set<String> allReturningAttributes = new HashSet<String>();
373            
374            if ( noAttributes )
375            {
376                allReturningAttributes.add( SchemaConstants.NO_ATTRIBUTE );
377            }
378            
379            if ( allUserAttributes )
380            {
381                allReturningAttributes.add( SchemaConstants.ALL_USER_ATTRIBUTES );
382            }
383            
384            if ( allOperationalAttributes )
385            {
386                allReturningAttributes.add( SchemaConstants.ALL_OPERATIONAL_ATTRIBUTES );
387            }
388            
389            if ( returningAttributes != null )
390            {
391                for ( AttributeTypeOptions at : returningAttributes )
392                {
393                    if ( denormalized )
394                    {
395                        allReturningAttributes.add( at.getAttributeType().getName() );
396                    }
397                    else
398                    {
399                        allReturningAttributes.add( at.getAttributeType().getOid() );
400                    }
401                }
402            }
403            
404            if ( allReturningAttributes.size() > 0 )
405            {
406                controls.setReturningAttributes( allReturningAttributes.toArray( ArrayUtils.EMPTY_STRING_ARRAY ) );
407            }
408            
409            return controls;
410        }
411    
412    
413        /**
414         * @param abandoned the abandoned to set
415         */
416        public void setAbandoned( boolean abandoned )
417        {
418            this.abandoned = abandoned;
419        }
420    
421    
422        /**
423         * @return the abandoned
424         */
425        public boolean isAbandoned()
426        {
427            return abandoned;
428        }
429    }