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.ldap.handlers;
021    
022    
023    import java.util.concurrent.TimeUnit;
024    
025    import org.apache.directory.shared.ldap.cursor.ClosureMonitor;
026    import org.apache.directory.shared.ldap.cursor.CursorClosedException;
027    import org.apache.directory.shared.ldap.exception.LdapTimeLimitExceededException;
028    
029    
030    /**
031     * A ClosureMonitor implementation which takes into account a time limit.
032     *
033     * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
034     * @version $Rev$, $Date$
035     */
036    public class SearchTimeLimitingMonitor implements ClosureMonitor
037    {
038        private final long startTime = System.currentTimeMillis();
039        private final long millisToLive;
040        
041        private boolean closed;
042        private Exception cause;
043        
044        
045        /**
046         * Creates a new instance of SearchTimeLimitingMonitor.
047         *
048         * @param timeToLive the time before changing state to closed.
049         * @param unit the time units for the timeToLive parameter
050         * @see {@link TimeUnit}
051         */
052        public SearchTimeLimitingMonitor( long timeToLive, TimeUnit unit )
053        {
054            switch ( unit )
055            {
056                case MICROSECONDS:
057                    this.millisToLive = timeToLive / 1000;
058                    break;
059                case MILLISECONDS:
060                    this.millisToLive = timeToLive;
061                    break;
062                case SECONDS:
063                    this.millisToLive = timeToLive * 1000;
064                    break;
065                default:
066                    throw new IllegalStateException( "TimeUnit not supported: " + unit );
067            }
068        }
069    
070        
071        /*
072         * (non-Javadoc)
073         * @see org.apache.directory.server.core.cursor.ClosureMonitor#checkNotClosed()
074         */
075        public void checkNotClosed() throws Exception
076        {
077            if ( System.currentTimeMillis() > startTime + millisToLive )
078            {
079                // state check needed to "try" not to overwrite exception (lack of 
080                // synchronization may still allow overwriting but who cares that 
081                // much
082                if ( ! closed )
083                {
084                    // not going to sync because who cares if it takes a little 
085                    // longer to stop but we need to set cause before toggling 
086                    // closed state or else check for closure can throw null cause 
087                    cause = new LdapTimeLimitExceededException();
088                    closed = true;
089                }
090            }
091            
092            if ( closed )
093            {
094                throw cause;
095            }
096        }
097    
098        
099        /*
100         * (non-Javadoc)
101         * @see org.apache.directory.server.core.cursor.ClosureMonitor#close()
102         */
103        public void close()
104        {
105            if ( ! closed )
106            {
107                // not going to sync because who cares if it takes a little longer 
108                // to stop but we need to set cause before toggling closed state 
109                // or else check for closure can throw null cause 
110                cause = new CursorClosedException();
111                closed = true;
112            }
113        }
114    
115        
116        /*
117         * (non-Javadoc)
118         * @see org.apache.directory.server.core.cursor.ClosureMonitor#close(java.lang.String)
119         */
120        public void close( String cause )
121        {
122            if ( ! closed )
123            {
124                // not going to sync because who cares if it takes a little longer 
125                // to stop but we need to set cause before toggling closed state 
126                // or else check for closure can throw null cause 
127                this.cause = new CursorClosedException( cause );
128                closed = true;
129            }
130        }
131    
132    
133        /*
134         * (non-Javadoc)
135         * @see org.apache.directory.server.core.cursor.ClosureMonitor#close(java.lang.Exception)
136         */
137        public void close( Exception cause )
138        {
139            if ( ! closed )
140            {
141                // not going to sync because who cares if it takes a little longer 
142                // to stop but we need to set cause before toggling closed state 
143                // or else check for closure can throw null cause 
144                this.cause = cause;
145                closed = true;
146            }
147        }
148    
149        
150        /*
151         * (non-Javadoc)
152         * @see org.apache.directory.server.core.cursor.ClosureMonitor#getCause()
153         */
154        public Exception getCause()
155        {
156            return cause;
157        }
158    
159        
160        /*
161         * (non-Javadoc)
162         * @see org.apache.directory.server.core.cursor.ClosureMonitor#isClosed()
163         */
164        public boolean isClosed()
165        {
166            if ( System.currentTimeMillis() > startTime + millisToLive )
167            {
168                // set cause first always
169                cause = new LdapTimeLimitExceededException();
170                closed = true;
171            }
172            
173            return closed;
174        }
175    }
176    
177