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 */
020package org.apache.directory.api.ldap.model.cursor;
021
022
023/**
024 * A basic ClosureMonitor that simply uses a boolean for state and a cause
025 * exception.
026 *
027 * Note that we consciously chose not to synchronize close() operations with
028 * checks to see if the monitor state is closed because it costs to
029 * synchronize and it's OK for the Cursor not to stop immediately when close()
030 * is called.
031 *
032 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
033 */
034public class DefaultClosureMonitor implements ClosureMonitor
035{
036    /** Tells if the monitor is closed or not */
037    private boolean closed;
038
039    /** If we get an exception, the cause is stored in this variable */
040    private Exception cause;
041
042
043    /**
044     * {@inheritDoc}
045     */
046    @Override
047    public final void close()
048    {
049        // state check needed to "try" not to overwrite exception (lack of
050        // synchronization may still allow overwriting but who cares that much
051        if ( !closed )
052        {
053            // not going to sync because who cares if it takes a little longer
054            // to stop but we need to set cause before toggling closed state
055            // or else check for closure can throw null cause
056            cause = CursorClosedException.INSTANCE;
057            closed = true;
058        }
059    }
060
061
062    /**
063     * {@inheritDoc}
064     */
065    @Override
066    public final void close( final String cause )
067    {
068        // state check needed to "try" not to overwrite exception (lack of
069        // synchronization may still allow overwriting but who cares that much
070        if ( !closed )
071        {
072            // not going to sync because who cares if it takes a little longer
073            // to stop but we need to set cause before toggling closed state
074            // or else check for closure can throw null cause
075            this.cause = new CursorClosedException( cause );
076            closed = true;
077        }
078    }
079
080
081    /**
082     * {@inheritDoc}
083     */
084    @Override
085    public final void close( final Exception cause )
086    {
087        // state check needed to "try" not to overwrite exception (lack of
088        // synchronization may still allow overwriting but who cares that much
089        if ( !closed )
090        {
091            // not going to sync because who cares if it takes a little longer
092            // to stop but we need to set cause before toggling closed state
093            // or else check for closure can throw null cause
094            this.cause = cause;
095            closed = true;
096        }
097    }
098
099
100    /**
101     * {@inheritDoc}
102     */
103    @Override
104    public final Exception getCause()
105    {
106        return cause;
107    }
108
109
110    /**
111     * {@inheritDoc}
112     */
113    @Override
114    public final boolean isClosed()
115    {
116        return closed;
117    }
118
119
120    /**
121     * {@inheritDoc}
122     */
123    @Override
124    public void checkNotClosed() throws CursorClosedException
125    {
126        // lack of synchronization may cause pass but eventually it will work
127        if ( closed )
128        {
129            throw new CursorClosedException( cause.getMessage() );
130        }
131    }
132}