001 package com.hammurapi.reasoning.impl;
002
003 import java.util.Collection;
004 import java.util.List;
005 import java.util.Map;
006 import java.util.Set;
007
008 import org.apache.commons.pool.KeyedObjectPool;
009 import org.apache.commons.pool.KeyedPoolableObjectFactory;
010
011 import com.hammurapi.config.bootstrap.ConfigurationException;
012 import com.hammurapi.config.bootstrap.Destroyable;
013 import com.hammurapi.reasoning.Derivation;
014 import com.hammurapi.reasoning.ExceptionHandler;
015 import com.hammurapi.reasoning.ForwardReasoningSession;
016 import com.hammurapi.reasoning.ForwardReasoningSessionFactory;
017 import com.hammurapi.reasoning.Handle;
018 import com.hammurapi.reasoning.InferenceListener;
019 import com.hammurapi.reasoning.ReasoningException;
020
021 /**
022 * Implements session pooling, uses properties as the key.
023 * @author Pavel Vlasov
024 *
025 * @param <F>
026 */
027 public class PoolingForwardReasoningSessionFactory<F> implements ForwardReasoningSessionFactory<F>, Destroyable {
028
029 private ForwardReasoningSessionFactory<F> master;
030
031 protected KeyedObjectPool pool;
032
033 private class PoolableForwardReasoningSession implements ForwardReasoningSession<F> {
034
035 private ForwardReasoningSession<F> master;
036 private Object key;
037
038 PoolableForwardReasoningSession(ForwardReasoningSession<F> master, Object key) {
039 this.master = master;
040 this.key = key;
041 }
042
043 public void close() throws ReasoningException {
044 master.reset();
045 master.setInferenceListener(null);
046 master.setExceptionHandler(null);
047 try {
048 pool.returnObject(key, this);
049 } catch (Exception e) {
050 throw new ReasoningException("Failed to return session to pool: "+e, e);
051 }
052 }
053
054 public boolean contains(Handle<F> handle) throws ReasoningException {
055 return master.contains(handle);
056 }
057
058 public boolean contains(Object fact) throws ReasoningException {
059 return master.contains(fact);
060 }
061
062 public void executeRules() throws ReasoningException {
063 master.executeRules();
064 }
065
066 public F get(Handle<F> handle) throws ReasoningException {
067 return master.get(handle);
068 }
069
070 public Map<Class<F>, Set<Class<F>>> getConclusionMap() {
071 return master.getConclusionMap();
072 }
073
074 public Collection<Derivation<F>> getDerivations(F obj) throws ReasoningException {
075 return master.getDerivations(obj);
076 }
077
078 public Collection<Derivation<F>> getDerivations(Handle<F> handle) throws ReasoningException {
079 return master.getDerivations(handle);
080 }
081
082 public String getDescription() {
083 return master.getDescription();
084 }
085
086 public ExceptionHandler getExceptionHandler() throws ReasoningException {
087 return master.getExceptionHandler();
088 }
089
090 public Handle<F> getHandle(Object fact) {
091 return master.getHandle(fact);
092 }
093
094 public Collection<Handle<F>> getHandles() throws ReasoningException {
095 return master.getHandles();
096 }
097
098 public InferenceListener<F> getInferenceListener() throws ReasoningException {
099 return master.getInferenceListener();
100 }
101
102 public String getName() {
103 return master.getName();
104 }
105
106 public Collection<? extends F> getObjects() throws ReasoningException {
107 return master.getObjects();
108 }
109
110 public Handle<F> put(F fact) throws ReasoningException {
111 return master.put(fact);
112 }
113
114 public Handle<F>[] putAll(F... facts) throws ReasoningException {
115 return master.putAll(facts);
116 }
117
118 public List<Handle<F>> putAll(List<? extends F> facts)
119 throws ReasoningException {
120 return master.putAll(facts);
121 }
122
123 public void remove(F fact, boolean strict) throws ReasoningException {
124 master.remove(fact, strict);
125 }
126
127 public void remove(Handle<F> handle, boolean strict) throws ReasoningException {
128 master.remove(handle, strict);
129 }
130
131 public void reset() throws ReasoningException {
132 master.reset();
133 }
134
135 public void setExceptionHandler(ExceptionHandler handler) throws ReasoningException {
136 master.setExceptionHandler(handler);
137 }
138
139 public void setInferenceListener(InferenceListener<F> listener) throws ReasoningException {
140 master.setInferenceListener(listener);
141 }
142
143 public void updateObject(Handle<F> handle, F obj) throws ReasoningException {
144 master.updateObject(handle, obj);
145 }
146
147 }
148
149 private KeyedPoolableObjectFactory poolFactory = new KeyedPoolableObjectFactory() {
150
151 @Override
152 public boolean validateObject(Object key, Object obj) {
153 return true; // No way to validate, assume always valid.
154 }
155
156 @Override
157 public void passivateObject(Object key, Object obj) throws Exception {
158 // Nothing to do here, passivation handled by the session wrapper.
159
160 }
161
162 @Override
163 public Object makeObject(Object key) throws Exception {
164 return new PoolableForwardReasoningSession(master.createSession((Map<?, ?>) (key==NULL_KEY ? null : key)), key);
165 }
166
167 @Override
168 public void destroyObject(Object key, Object obj) throws Exception {
169 ((PoolableForwardReasoningSession) obj).master.close();
170 }
171
172 @Override
173 public void activateObject(Object key, Object obj) throws Exception {
174 // Nothing to do here.
175 }
176 };
177
178 public PoolingForwardReasoningSessionFactory(ForwardReasoningSessionFactory<F> master, KeyedObjectPool pool) {
179 this.master = master;
180 this.pool = pool;
181 pool.setFactory(poolFactory);
182 }
183
184 private static final Object NULL_KEY = new Object();
185
186 private static Object toKey(Map<?, ?> keyCandidate) {
187 return keyCandidate==null ? NULL_KEY : keyCandidate;
188 }
189
190 @SuppressWarnings("unchecked")
191 @Override
192 public ForwardReasoningSession<F> createSession(Map<?, ?> properties) throws ReasoningException {
193 try {
194 return (ForwardReasoningSession<F>) pool.borrowObject(toKey(properties));
195 } catch (Exception e) {
196 throw new ReasoningException(e);
197 }
198 }
199
200 /**
201 * Closes the pool.
202 */
203 @Override
204 public void destroy() throws ConfigurationException {
205 if (pool!=null) {
206 try {
207 pool.close();
208 } catch (ConfigurationException e) {
209 throw e;
210 } catch (Exception e) {
211 throw new ConfigurationException(e);
212 }
213 }
214 }
215
216 }