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