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    }