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   *    http://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.mina.common.support;
21  
22  import java.util.ArrayList;
23  import java.util.Iterator;
24  import java.util.List;
25  
26  import org.apache.mina.common.ExceptionMonitor;
27  import org.apache.mina.common.IoFuture;
28  import org.apache.mina.common.IoFutureListener;
29  import org.apache.mina.common.IoSession;
30  
31  /**
32   * A default implementation of {@link IoFuture}.
33   *  
34   * @author The Apache Directory Project (mina-dev@directory.apache.org)
35   * @version $Rev: 561238 $, $Date: 2007-07-31 15:12:43 +0900 (화, 31  7월 2007) $
36   */
37  public class DefaultIoFuture implements IoFuture {
38      private final IoSession session;
39  
40      private final Object lock;
41  
42      private IoFutureListener firstListener;
43  
44      private List otherListeners;
45  
46      private Object result;
47  
48      private boolean ready;
49  
50      /**
51       * Creates a new instance.
52       * 
53       * @param session an {@link IoSession} which is associated with this future
54       */
55      public DefaultIoFuture(IoSession session) {
56          this.session = session;
57          this.lock = this;
58      }
59  
60      /**
61       * Creates a new instance which uses the specified object as a lock.
62       */
63      public DefaultIoFuture(IoSession session, Object lock) {
64          if (lock == null) {
65              throw new NullPointerException("lock");
66          }
67          this.session = session;
68          this.lock = lock;
69      }
70  
71      public IoSession getSession() {
72          return session;
73      }
74  
75      public Object getLock() {
76          return lock;
77      }
78  
79      public void join() {
80          synchronized (lock) {
81              while (!ready) {
82                  try {
83                      lock.wait();
84                  } catch (InterruptedException e) {
85                  }
86              }
87          }
88      }
89  
90      public boolean join(long timeoutInMillis) {
91          long startTime = (timeoutInMillis <= 0) ? 0 : System
92                  .currentTimeMillis();
93          long waitTime = timeoutInMillis;
94  
95          synchronized (lock) {
96              if (ready) {
97                  return ready;
98              } else if (waitTime <= 0) {
99                  return ready;
100             }
101 
102             for (;;) {
103                 try {
104                     lock.wait(waitTime);
105                 } catch (InterruptedException e) {
106                 }
107 
108                 if (ready)
109                     return true;
110                 else {
111                     waitTime = timeoutInMillis
112                             - (System.currentTimeMillis() - startTime);
113                     if (waitTime <= 0) {
114                         return ready;
115                     }
116                 }
117             }
118         }
119     }
120 
121     public boolean isReady() {
122         synchronized (lock) {
123             return ready;
124         }
125     }
126 
127     /**
128      * Sets the result of the asynchronous operation, and mark it as finished.
129      */
130     protected void setValue(Object newValue) {
131         synchronized (lock) {
132             // Allow only once.
133             if (ready) {
134                 return;
135             }
136 
137             result = newValue;
138             ready = true;
139             lock.notifyAll();
140 
141             notifyListeners();
142         }
143     }
144 
145     /**
146      * Returns the result of the asynchronous operation.
147      */
148     protected Object getValue() {
149         synchronized (lock) {
150             return result;
151         }
152     }
153 
154     public void addListener(IoFutureListener listener) {
155         if (listener == null) {
156             throw new NullPointerException("listener");
157         }
158 
159         synchronized (lock) {
160             if (!ready) {
161                 if (firstListener == null) {
162                     firstListener = listener;
163                 } else {
164                     if (otherListeners == null) {
165                         otherListeners = new ArrayList(1);
166                     }
167                     otherListeners.add(listener);
168                 }
169             } else {
170                 notifyListener(listener);
171             }
172         }
173     }
174 
175     public void removeListener(IoFutureListener listener) {
176         if (listener == null) {
177             throw new NullPointerException("listener");
178         }
179 
180         synchronized (lock) {
181             if (listener == firstListener) {
182                 if (otherListeners != null && !otherListeners.isEmpty()) {
183                     firstListener = (IoFutureListener) otherListeners.remove(0);
184                 } else {
185                     firstListener = null;
186                 }
187             } else if (otherListeners != null) {
188                 otherListeners.remove(listener);
189             }
190         }
191     }
192 
193     private void notifyListeners() {
194         synchronized (lock) {
195             if (firstListener != null) {
196                 notifyListener(firstListener);
197                 if (otherListeners != null) {
198                     for (Iterator i = otherListeners.iterator(); i.hasNext();) {
199                         notifyListener((IoFutureListener) i.next());
200                     }
201                 }
202             }
203         }
204     }
205 
206     private void notifyListener(IoFutureListener l) {
207         try {
208             l.operationComplete(this);
209         } catch (Throwable t) {
210             ExceptionMonitor.getInstance().exceptionCaught(t);
211         }
212     }
213 }