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.james.jspf.executor;
021
022 import java.util.ArrayList;
023 import java.util.Iterator;
024 import java.util.List;
025
026 import org.apache.james.jspf.core.Logger;
027 import org.apache.james.jspf.core.SPFSession;
028
029
030 /**
031 * A Blocking version of SPFResult which block until the SPFResult is fully set
032 *
033 */
034 public class FutureSPFResult extends SPFResult {
035
036 private boolean isReady;
037 private List<IFutureSPFResultListener> listeners;
038 private int waiters;
039 private final Logger log;
040
041 public FutureSPFResult() {
042 this.log = null;
043 isReady = false;
044 }
045
046 public FutureSPFResult(Logger log) {
047 this.log = log;
048 this.isReady = false;
049 }
050
051 /**
052 * Set SPFResult using the given SPFsession
053 *
054 * @param session
055 *
056 */
057 public void setSPFResult(SPFSession session) {
058 Iterator<IFutureSPFResultListener> listenerIt = null;
059 synchronized (this) {
060 if (!isReady) {
061 setSPFSession(session);
062 isReady = true;
063 if (waiters > 0) {
064 notifyAll();
065 }
066 if (listeners != null) {
067 listenerIt = listeners.iterator();
068 listeners = null;
069 }
070 }
071 }
072 if (listenerIt != null) {
073 while (listenerIt.hasNext()) {
074 IFutureSPFResultListener listener = listenerIt.next();
075 try {
076 listener.onSPFResult(this);
077 } catch (Throwable e) {
078 // catch exception. See JSPF-95
079 if (log != null) {
080 log.warn("An exception was thrown by the listener " + listener, e);
081 }
082 }
083 }
084 listenerIt = null;
085 }
086 }
087
088 /**
089 * Waits until the SPFResult is set
090 *
091 */
092 private synchronized void checkReady() {
093 while (!isReady) {
094 try {
095 waiters++;
096 wait();
097 } catch (InterruptedException e) {
098 Thread.currentThread().interrupt();
099 } finally {
100 waiters--;
101 }
102 }
103 }
104
105 /**
106 * @see org.apache.james.jspf.executor.SPFResult#getExplanation()
107 */
108 public String getExplanation() {
109 checkReady();
110 return super.getExplanation();
111 }
112
113 /**
114 * @see org.apache.james.jspf.executor.SPFResult#getHeader()
115 */
116 public String getHeader() {
117 checkReady();
118 return super.getHeader();
119 }
120
121 /**
122 * @see org.apache.james.jspf.executor.SPFResult#getHeaderName()
123 */
124 public String getHeaderName() {
125 checkReady();
126 return super.getHeaderName();
127 }
128
129 /**
130 * @see org.apache.james.jspf.executor.SPFResult#getHeaderText()
131 */
132 public String getHeaderText() {
133 checkReady();
134 return super.getHeaderText();
135 }
136
137 /**
138 * @see org.apache.james.jspf.executor.SPFResult#getResult()
139 */
140 public String getResult() {
141 checkReady();
142 return super.getResult();
143 }
144
145 /**
146 * Return true if the result was fully builded
147 *
148 * @return true or false
149 */
150 public synchronized boolean isReady() {
151 return isReady;
152 }
153
154 /**
155 * Add a {@link IFutureSPFResultListener} which will get notified once {@link #isReady()} returns <code>true</code>
156 *
157 * @param listener
158 */
159 public synchronized void addListener(IFutureSPFResultListener listener) {
160 if (!isReady) {
161 if (listeners == null) {
162 listeners = new ArrayList<IFutureSPFResultListener>();
163 }
164 listeners.add(listener);
165 } else {
166 listener.onSPFResult(this);
167 }
168 }
169
170 /**
171 * Remove a {@link IFutureSPFResultListener}
172 *
173 * @param listener
174 */
175 public synchronized void removeListener(IFutureSPFResultListener listener) {
176 if (!isReady && listeners != null) {
177 listeners.remove(listener);
178 }
179 }
180
181
182 /**
183 * Listener which will get notified once a {@link FutureSPFResult#isReady()} returns <code>true</code>. So it will not block anymore
184 *
185 *
186 */
187 public interface IFutureSPFResultListener {
188
189 /**
190 * Get called once a {@link FutureSPFResult} is ready
191 *
192 * @param result
193 */
194 void onSPFResult(FutureSPFResult result);
195 }
196 }