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 java.util.Collection;
024    import java.util.Collections;
025    import java.util.HashMap;
026    import java.util.List;
027    import java.util.Map;
028    
029    import org.apache.directory.server.core.CoreSession;
030    import org.apache.directory.server.core.LdapPrincipal;
031    import org.apache.directory.server.core.entry.ClonedServerEntry;
032    import org.apache.directory.server.i18n.I18n;
033    import org.apache.directory.shared.ldap.entry.Modification;
034    import org.apache.directory.shared.ldap.entry.ServerEntry;
035    import org.apache.directory.shared.ldap.message.control.Control;
036    import org.apache.directory.shared.ldap.name.DN;
037    
038    
039    /**
040     * This abstract class stores common context elements, like the DN, which is used
041     * in all the contexts.
042     *
043     * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
044     * @version $Rev$, $Date$
045     */
046    public abstract class AbstractOperationContext implements OperationContext
047    {
048        protected static final Control[] EMPTY_CONTROLS = new Control[0];
049    
050        /** The DN associated with the context */
051        protected DN dn;
052        
053        /** The entry associated with the target entry of this OperationContext */
054        protected ClonedServerEntry entry;
055        
056        /** The associated request's controls */
057        protected Map<String, Control> requestControls = new HashMap<String, Control>(4);
058    
059        /** The associated response's controls */
060        protected Map<String, Control> responseControls = new HashMap<String, Control>(4);
061    
062        /** the Interceptors bypassed by this operation */
063        protected Collection<String> byPassed;
064        
065        protected LdapPrincipal authorizedPrincipal;
066        
067        /** The core session */
068        protected CoreSession session;
069        
070        protected OperationContext next;
071        
072        protected OperationContext previous;
073    
074        /** A flag used to tell if we should consider referrals as standard entries */
075        protected boolean throwReferral;
076        
077        
078        /**
079         * Creates a new instance of AbstractOperationContext.
080         */
081        public AbstractOperationContext( CoreSession session )
082        {
083            this.session = session;
084        }
085        
086        
087        /**
088         * Creates a new instance of AbstractOperationContext.
089         *
090         * @param dn The associated DN
091         */
092        public AbstractOperationContext( CoreSession session, DN dn )
093        {
094            this.dn = dn;
095            this.session = session;
096            
097            // The flag is set to ignore, so that the revert operation can act on 
098            // the entries, even if they are referrals.
099            ignoreReferral();
100        }
101    
102    
103        public CoreSession getSession()
104        {
105            return session;
106        }
107        
108        
109        protected void setSession( CoreSession session )
110        {
111            this.session = session;
112        }
113        
114        
115        protected void setAuthorizedPrincipal( LdapPrincipal authorizedPrincipal )
116        {
117            this.authorizedPrincipal = authorizedPrincipal;
118        }
119    
120    
121        /**
122         * @return The associated DN
123         */
124        public DN getDn()
125        {
126            return dn;
127        }
128    
129        
130        /**
131         * Set the context DN
132         *
133         * @param dn The DN to set
134         */
135        public void setDn( DN dn )
136        {
137            this.dn = dn;
138        }
139    
140        
141        public void addRequestControl( Control requestControl )
142        {
143            requestControls.put( requestControl.getOid(), requestControl );
144        }
145    
146        
147        public Control getRequestControl( String numericOid )
148        {
149            return requestControls.get( numericOid );
150        }
151    
152        
153        public boolean hasRequestControl( String numericOid )
154        {
155            return requestControls.containsKey( numericOid );
156        }
157    
158        
159        public boolean hasRequestControls()
160        {
161            return ! requestControls.isEmpty();
162        }
163    
164    
165        public void addResponseControl( Control responseControl )
166        {
167            responseControls.put( responseControl.getOid(), responseControl );
168        }
169    
170    
171        public Control getResponseControl( String numericOid )
172        {
173            return responseControls.get( numericOid );
174        }
175    
176    
177        public boolean hasResponseControl( String numericOid )
178        {
179            return responseControls.containsKey( numericOid );
180        }
181    
182    
183        public Control[] getResponseControls()
184        {
185            if ( responseControls.isEmpty() )
186            {
187                return EMPTY_CONTROLS;
188            }
189            
190            return responseControls.values().toArray( EMPTY_CONTROLS );
191        }
192    
193    
194        public boolean hasResponseControls()
195        {
196            return ! responseControls.isEmpty();
197        }
198    
199    
200        public int getResponseControlCount()
201        {
202            return responseControls.size();
203        }
204    
205    
206        public void addRequestControls( Control[] requestControls )
207        {
208            for ( Control c : requestControls )
209            {
210                this.requestControls.put( c.getOid(), c );
211            }
212        }
213    
214        
215        public void setRequestControls( Map<String, Control> requestControls )
216        {
217            this.requestControls = requestControls;
218        }
219    
220        
221        /**
222         * @return the operation name
223         */
224        public abstract String getName();
225    
226    
227        /**
228         * Gets the set of bypassed Interceptors.
229         *
230         * @return the set of bypassed Interceptors
231         */
232        public Collection<String> getByPassed()
233        {
234            if ( byPassed == null )
235            {
236                return Collections.emptyList();
237            }
238            
239            return Collections.unmodifiableCollection( byPassed );
240        }
241        
242        
243        /**
244         * Sets the set of bypassed Interceptors.
245         * 
246         * @param byPassed the set of bypassed Interceptors
247         */
248        public void setByPassed( Collection<String> byPassed )
249        {
250            this.byPassed = byPassed;
251        }
252    
253        
254        /**
255         * Checks to see if an Interceptor is bypassed for this operation.
256         *
257         * @param interceptorName the interceptorName of the Interceptor to check for bypass
258         * @return true if the Interceptor should be bypassed, false otherwise
259         */
260        public boolean isBypassed( String interceptorName )
261        {
262            return byPassed != null && byPassed.contains( interceptorName );
263        }
264    
265    
266        /**
267         * Checks to see if any Interceptors are bypassed by this operation.
268         *
269         * @return true if at least one bypass exists
270         */
271        public boolean hasBypass()
272        {
273            return byPassed != null && !byPassed.isEmpty();
274        }
275    
276        
277        private void setup( AbstractOperationContext opContext )
278        {
279            opContext.setPreviousOperation( this );
280            next = opContext;
281            opContext.setByPassed( byPassed );
282            opContext.setAuthorizedPrincipal( authorizedPrincipal );
283        }
284        
285        
286        public boolean hasEntry( DN dn, Collection<String> byPassed ) throws Exception
287        {
288            EntryOperationContext opContext = new EntryOperationContext( session, dn );
289            setup( opContext );
290            opContext.setByPassed( byPassed );
291            return session.getDirectoryService().getOperationManager().hasEntry( opContext );
292        }
293        
294        
295        public void add( ServerEntry entry, Collection<String> byPassed ) throws Exception
296        {
297            AddOperationContext opContext = new AddOperationContext( session, entry );
298            setup( opContext );
299            opContext.setByPassed( byPassed );
300            session.getDirectoryService().getOperationManager().add( opContext );
301        }
302        
303        
304        public void delete( DN dn, Collection<String> byPassed ) throws Exception
305        {
306            DeleteOperationContext opContext = new DeleteOperationContext( session, dn );
307            setup( opContext );
308            opContext.setByPassed( byPassed );
309            session.getDirectoryService().getOperationManager().delete( opContext );
310        }
311        
312        
313        public void modify( DN dn, List<Modification> mods, Collection<String> byPassed ) throws Exception
314        {
315            ModifyOperationContext opContext = new ModifyOperationContext( session, dn, mods );
316            setup( opContext );
317            opContext.setByPassed( byPassed );
318            session.getDirectoryService().getOperationManager().modify( opContext );
319        }
320        
321        
322        // TODO - need synchronization here and where we update links
323        public LookupOperationContext newLookupContext( DN dn )
324        {
325            LookupOperationContext opContext = new LookupOperationContext( session, dn );
326            setup( opContext );
327            return opContext;
328        }
329    
330    
331        public ClonedServerEntry lookup( LookupOperationContext opContext ) throws Exception
332        {
333            if ( opContext != next )
334            {
335                throw new IllegalStateException( I18n.err( I18n.ERR_319 ) );
336            }
337            return session.getDirectoryService().getOperationManager().lookup( opContext );
338        }
339    
340    
341        public ClonedServerEntry lookup( DN dn, Collection<String> byPassed ) throws Exception
342        {
343            LookupOperationContext opContext = newLookupContext( dn );
344            opContext.setByPassed( byPassed );
345            return session.getDirectoryService().getOperationManager().lookup( opContext );
346        }
347        
348    
349        public LdapPrincipal getEffectivePrincipal()
350        {
351            if ( authorizedPrincipal != null )
352            {
353                return authorizedPrincipal;
354            }
355            
356            return session.getEffectivePrincipal();
357        }
358        
359        
360        // -----------------------------------------------------------------------
361        // OperationContext Linked List Methods
362        // -----------------------------------------------------------------------
363        
364        
365        public boolean isFirstOperation()
366        {
367            return previous == null;
368        }
369        
370        
371        public OperationContext getFirstOperation()
372        {
373            if ( previous == null )
374            {
375                return this;
376            }
377            
378            return previous.getFirstOperation();
379        }
380        
381        
382        public OperationContext getLastOperation()
383        {
384            if ( next == null )
385            {
386                return this;
387            }
388            
389            return next.getLastOperation();
390        }
391        
392        
393        public OperationContext getNextOperation()
394        {
395            return next;
396        }
397        
398        
399        protected void setNextOperation( OperationContext next )
400        {
401            this.next = next;
402        }
403        
404        
405        public OperationContext getPreviousOperation()
406        {
407            return previous;
408        }
409        
410        
411        protected void setPreviousOperation( OperationContext previous )
412        {
413            this.previous = previous;
414        }
415    
416    
417        /**
418         * @param entry the entry to set
419         */
420        public void setEntry( ClonedServerEntry entry )
421        {
422            this.entry = entry;
423        }
424    
425    
426        /**
427         * @return the entry
428         */
429        public ClonedServerEntry getEntry()
430        {
431            return entry;
432        }
433        
434        
435        /**
436         * Set the throwReferral flag to true
437         */
438        public void throwReferral()
439        {
440            throwReferral = true;
441        }
442        
443        
444        /**
445         * @return <code>true</code> if the referrals are thrown
446         */
447        public boolean isReferralThrown()
448        {
449            return throwReferral;
450        }
451    
452    
453        /**
454         * Set the throwReferral flag to false
455         */
456        public void ignoreReferral()
457        {
458            throwReferral = false;
459        }
460    
461    
462        /**
463         * @return <code>true</code> if the referrals are ignored
464         */
465        public boolean isReferralIgnored()
466        {
467            return !throwReferral;
468        }
469    }