1 16 package org.directwebremoting.guice; 17 18 import com.google.inject.Key; 19 import com.google.inject.Provider; 20 import com.google.inject.Scope; 21 import com.google.inject.util.ToStringBuilder; 22 23 import java.util.Collection ; 24 import java.util.ArrayList ; 25 import java.util.List ; 26 import static java.util.Collections.synchronizedList ; 27 import static java.util.Collections.unmodifiableList ; 28 29 import java.util.concurrent.Callable ; 30 import java.util.concurrent.ConcurrentHashMap ; 31 import java.util.concurrent.ConcurrentMap ; 32 import java.util.concurrent.ExecutionException ; 33 import java.util.concurrent.Future ; 34 import java.util.concurrent.FutureTask ; 35 36 import org.directwebremoting.util.Logger; 37 import static org.directwebremoting.guice.AbstractContextScope.State.*; 38 39 47 public abstract class AbstractContextScope<C, R> 48 implements ContextScope<C>, ContextRegistry<C, R> 49 { 50 protected AbstractContextScope(Class <C> type, String scopeName) 51 { 52 this.type = type; 53 this.scopeName = scopeName; 54 } 55 56 public String toString() 57 { 58 return scopeName; 59 } 60 61 public List <Key<?>> getKeysInScope() 62 { 63 synchronized (scopedKeys) 64 { 65 return new ArrayList <Key<?>>(scopedKeys); 66 } 67 } 68 69 public <T> Provider<T> scope(final Key<T> key, final Provider<T> creator) 70 { 71 if (log.isDebugEnabled()) 72 { 73 log.debug(String.format( 74 "scope %s: adding key %s with creator %s", 75 scopeName, key, creator 76 )); 77 } 78 79 scopedKeys.add(key); 80 final String name = key.toString(); 81 return new Provider<T>() 82 { 83 public T get() 84 { 85 if (log.isDebugEnabled()) 86 { 87 log.debug(String.format( 88 "scope %s: getting key %s with creator %s", 89 scopeName, key, creator 90 )); 91 } 92 93 C context = getContext(key); 94 R registry = registryFor(context); 95 InstanceProvider<T> future = 96 AbstractContextScope.this.get(registry, key, name); 97 if (future == null) 98 { 99 InstanceProvider<T> futureTask = new FutureTaskProvider<T>(creator); 100 future = putIfAbsent(registry, key, name, futureTask); 101 if (future == null) 102 { 103 future = futureTask; 104 futureTask.run(); 105 if (Thread.currentThread().isInterrupted()) 106 { 107 remove(registry, key, name, futureTask); 108 } 109 } 110 } 111 return future.get(); 112 } 113 114 public String toString() 115 { 116 return new ToStringBuilder(this.getClass()) 117 .add("scopeName", scopeName) 118 .add("type", type) 119 .add("key", key) 120 .add("creator", creator) 121 .toString(); 122 } 123 }; 124 } 125 126 public abstract C get(); 127 128 129 public Class <C> type() 130 { 131 return type; 132 } 133 134 public Collection <C> getOpenContexts() 135 { 136 Collection <C> openContexts = new ArrayList <C>(); 137 for (C context : contexts.keySet()) 138 { 139 if (contexts.get(context) == OPEN) 140 { 141 openContexts.add(context); 142 } 143 } 144 return openContexts; 145 } 146 147 public void close(C context, ContextCloseHandler<?>... closeHandlers) 148 { 149 if (!contexts.replace(context, OPEN, CLOSED)) 150 { 151 return; 153 } 154 155 for (InstanceProvider<?> provider : registeredProviders(registryFor(context))) 156 { 157 Object value = null; 158 try 159 { 160 value = provider.get(); 161 } 162 catch (RuntimeException e) 163 { 164 } 168 169 if (value == null) 170 { 171 continue; 173 } 174 175 for (ContextCloseHandler<?> closeHandler : closeHandlers) 176 { 177 handleClose(closeHandler, value); 178 } 179 } 180 } 181 182 public void closeAll(ContextCloseHandler<?>... closeHandlers) 183 { 184 for (C context : getOpenContexts()) 185 { 186 close(context, closeHandlers); 187 } 188 } 189 190 private <T> void handleClose(ContextCloseHandler<T> closeHandler, Object value) 191 { 192 Class <T> type = closeHandler.type(); 193 if (type.isInstance(value)) 194 { 195 try 196 { 197 closeHandler.close(type.cast(value)); 198 } 199 catch (Exception e) 200 { 201 } 205 } 206 } 207 208 private C getContext(Key<?> key) 209 { 210 C context = null; 211 RuntimeException caught = null; 212 try 213 { 214 context = get(); 215 if (contexts.putIfAbsent(context, OPEN) == CLOSED) 216 { 217 context = null; 219 } 220 } 221 catch (RuntimeException ex) 222 { 223 caught = ex; 224 } 225 if (context == null) 226 { 227 throw new OutOfScopeException(this, key, caught); 228 } 229 230 return context; 231 } 232 233 private Collection <InstanceProvider<?>> registeredProviders(R registry) 234 { 235 List <InstanceProvider<?>> providers = new ArrayList <InstanceProvider<?>>(); 236 for (Key<?> key : getKeysInScope()) 237 { 238 InstanceProvider<?> provider = get(registry, key, key.toString()); 239 if (provider != null) 240 { 241 providers.add(provider); 242 } 243 } 244 return providers; 245 } 246 247 enum State 248 { 249 OPEN, 250 CLOSED 251 } 252 253 private final Class <C> type; 254 255 private final String scopeName; 256 257 258 private final List <Key<?>> scopedKeys = synchronizedList(new ArrayList <Key<?>>()); 259 260 private final ConcurrentMap <C, State> contexts = new ConcurrentHashMap <C, State>(); 261 262 265 private static final Logger log = Logger.getLogger(AbstractContextScope.class); 266 } 267 | Popular Tags |