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 }