View Javadoc
1   /*
2    *   Licensed to the Apache Software Foundation (ASF) under one
3    *   or more contributor license agreements.  See the NOTICE file
4    *   distributed with this work for additional information
5    *   regarding copyright ownership.  The ASF licenses this file
6    *   to you under the Apache License, Version 2.0 (the
7    *   "License"); you may not use this file except in compliance
8    *   with the License.  You may obtain a copy of the License at
9    *
10   *     https://www.apache.org/licenses/LICENSE-2.0
11   *
12   *   Unless required by applicable law or agreed to in writing,
13   *   software distributed under the License is distributed on an
14   *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   *   KIND, either express or implied.  See the License for the
16   *   specific language governing permissions and limitations
17   *   under the License.
18   *
19   */
20  package org.apache.directory.ldap.client.api.future;
21  
22  import java.util.concurrent.TimeUnit;
23  
24  import org.apache.directory.api.ldap.model.message.Response;
25  import org.apache.directory.ldap.client.api.LdapConnection;
26  
27  /**
28   * A Future implementation used in LdapConnection operations for operations
29   * that only get one single response.
30   *
31   * @param <R> The result type returned by this Future's <tt>get</tt> method
32   * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
33   */
34  public abstract class UniqueResponseFuture<R extends Response> implements ResponseFuture<R>
35  {
36      /** The response */
37      private R response;
38  
39      /** flag to determine if this future is cancelled */
40      protected boolean cancelled = false;
41  
42      /** If the request has been cancelled because of an exception  it will be stored here */
43      protected Throwable cause;
44  
45      /** The messageID for this future */
46      protected int messageId;
47  
48      /** The connection used by the request */
49      protected LdapConnection connection;
50      
51      /** A flag set to TRUE when the response has been received */
52      private volatile boolean done = false;
53  
54      /**
55       * Creates a new instance of UniqueResponseFuture.
56       *
57       * @param connection The LdapConnection used by the request
58       * @param messageId The associated message ID
59       */
60      public UniqueResponseFuture( LdapConnection connection, int messageId )
61      {
62          this.messageId = messageId;
63          this.connection = connection;
64      }
65  
66  
67      /**
68       * {@inheritDoc}
69       * @throws InterruptedException if the operation has been cancelled by client
70       */
71      @Override
72      public synchronized R get() throws InterruptedException
73      {
74          while ( !done && !cancelled )
75          {
76              wait();
77          }
78  
79          return response;
80      }
81  
82  
83      /**
84       * {@inheritDoc}
85       * @throws InterruptedException if the operation has been cancelled by client
86       */
87      @Override
88      public synchronized R get( long timeout, TimeUnit unit ) throws InterruptedException
89      {
90          // no need to wait if already done or cancelled
91          if ( !done && !cancelled )
92          {
93              wait( unit.toMillis( timeout ) );
94          }
95  
96          return response;
97      }
98  
99  
100     /**
101      * Set the associated Response in this Future
102      * 
103      * @param response The response to add into the Future
104      * @throws InterruptedException if the operation has been cancelled by client
105      */
106     public synchronized void set( R response ) throws InterruptedException
107     {
108         this.response = response;
109 
110         done = response != null;
111 
112         notifyAll();
113     }
114 
115 
116     /**
117      * {@inheritDoc}
118      */
119     @Override
120     public boolean cancel( boolean mayInterruptIfRunning )
121     {
122         if ( cancelled )
123         {
124             return cancelled;
125         }
126 
127         // set the cancel flag first
128         cancelled = true;
129 
130         // Send an abandonRequest only if this future exists
131         if ( !connection.isRequestCompleted( messageId ) )
132         {
133             connection.abandon( messageId );
134         }
135         
136         // Notify the future
137         try
138         { 
139             set( null );
140         }
141         catch ( InterruptedException ie )
142         {
143             // Nothing we can do
144         }
145 
146         return cancelled;
147     }
148 
149 
150     /**
151      * {@inheritDoc}
152      */
153     @Override
154     public boolean isCancelled()
155     {
156         return cancelled;
157     }
158 
159 
160     /**
161      * This operation is not supported in this implementation of Future.
162      * 
163      * {@inheritDoc}
164      */
165     @Override
166     public boolean isDone()
167     {
168         return done;
169     }
170 
171 
172     /**
173      * @return the cause
174      */
175     public Throwable getCause()
176     {
177         return cause;
178     }
179 
180 
181     /**
182      * Associate a cause to the ResponseFuture
183      * @param cause the cause to set
184      */
185     public void setCause( Throwable cause )
186     {
187         this.cause = cause;
188     }
189 
190 
191     /**
192      * Cancel the Future
193      *
194      */
195     public void cancel()
196     {
197         // set the cancel flag first
198         cancelled = true;
199         
200         // Notify the future
201         try
202         { 
203             set( null );
204         }
205         catch ( InterruptedException ie )
206         {
207             // Nothing we can do
208         }
209     }
210 
211 
212     /**
213      * {@inheritDoc}
214      */
215     @Override
216     public String toString()
217     {
218         StringBuilder sb = new StringBuilder();
219 
220         sb.append( "[msgId : " ).append( messageId ).append( ", " );
221         sb.append( "Canceled :" ).append( cancelled ).append( "]" );
222 
223         return sb.toString();
224     }
225 }