001    /**
002     * hammurapi-rules @mesopotamia.version@
003     * Hammurapi rules engine. 
004     * Copyright (C) 2005  Hammurapi Group
005     *
006     * This program is free software; you can redistribute it and/or
007     * modify it under the terms of the GNU Lesser General Public
008     * License as published by the Free Software Foundation; either
009     * version 2 of the License, or (at your option) any later version.
010     *
011     * This program is distributed in the hope that it will be useful,
012     * but WITHOUT ANY WARRANTY; without even the implied warranty of
013     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
014     * Lesser General Public License for more details.
015     *
016     * You should have received a copy of the GNU Lesser General Public
017     * License along with this library; if not, write to the Free Software
018     * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
019     *
020     * URL: http://http://www.hammurapi.biz
021     * e-Mail: support@hammurapi.biz 
022     */
023    package biz.hammurapi.rules;
024    
025    import java.util.Collection;
026    import java.util.HashMap;
027    import java.util.HashSet;
028    import java.util.Iterator;
029    import java.util.Map;
030    
031    import biz.hammurapi.config.Component;
032    import biz.hammurapi.config.ComponentBase;
033    import biz.hammurapi.config.ConfigurationException;
034    import biz.hammurapi.config.RuntimeConfigurationException;
035    
036    /**
037     * Collection manager which holds collections in memory and 
038     * can use storage to persist state. 
039     * @author Pavel Vlasov
040     * @version ${Revision}
041     */
042    public class PojoCollectionManager extends ComponentBase implements Component, CollectionManager {
043    
044            private Map collectionMap;
045            private Class collectionType = HashSet.class;
046            private String storageReference;
047            
048            /**
049             * Path to object storage.
050             * @param storageReference
051             */
052            public void setStorageReference(String storageReference) {
053                    this.storageReference = storageReference;
054            }
055            
056            /**
057             * Starts collection manager. Loads collections from storage if storage reference is not null.
058             */
059            synchronized public void start() throws ConfigurationException {                
060                    if (storageReference==null) {
061                            collectionMap=new HashMap();
062                    } else {
063                            collectionMap = (Map) ((ObjectStorage) get(storageReference)).get("collection-manager");
064                            if (collectionMap==null) {
065                                    collectionMap=new HashMap();
066                                    ((ObjectStorage) get(storageReference)).put("collection-manager", collectionMap);
067                            }
068                    }
069            }
070    
071            /**
072             * Empty method. Storage of collections is performed by object storage if storage reference is set.
073             */
074            synchronized public void stop() throws ConfigurationException {
075                    // Nothing.
076            }
077                    
078            private class CollectionEntry {
079                    String ruleName;
080                    String collectionName;
081                    Object monitor;
082    
083                    CollectionEntry(String ruleName, String collectionName, Object monitor) {
084                            this.ruleName = ruleName;
085                            this.collectionName = collectionName;
086                            this.monitor = monitor;
087                    }
088                    
089                    public String toString() {
090                            return "[Collection entry] Rule="+ruleName+", Collection="+collectionName;
091                    }
092                    
093                    public boolean equals(Object obj) {
094                            if (obj==this) {
095                                    return true;
096                            }
097                            
098                            if (obj instanceof CollectionEntry) {
099                                    CollectionEntry ce = (CollectionEntry) obj;
100                                    
101                                    return ruleName.equals(ce.ruleName) && collectionName.equals(ce.collectionName);
102                            }
103                            
104                            return false;
105                    }
106                    
107                    public int hashCode() {
108                            return ruleName.hashCode() ^ collectionName.hashCode();
109                    }
110            }
111            
112            /**
113             * @see biz.hammurapi.rules.CollectionManager#getList(java.lang.String, java.lang.String)
114             */
115            synchronized public Collection get(String ruleName, String listName, Object monitor) {
116                    CollectionEntry ce=new CollectionEntry(ruleName, listName, monitor);
117                    Collection ret=(Collection) collectionMap.get(ce);
118                    if (ret==null) {
119                            try {
120                                    ret=(Collection) collectionType.newInstance();
121                                    collectionMap.put(ce, ret);
122                            } catch (InstantiationException e) {
123                                    throw new RuntimeConfigurationException("Cannot instantiate "+collectionType+": "+e, e);
124                            } catch (IllegalAccessException e) {
125                                    throw new RuntimeConfigurationException("Cannot instantiate "+collectionType+": "+e, e);
126                            }  
127                    }
128                    return ret;
129            }
130    
131            /* (non-Javadoc)
132             * @see biz.hammurapi.rules.CollectionManager#clear()
133             */
134            public synchronized void clear() {
135                    Iterator it=collectionMap.values().iterator();
136                    while (it.hasNext()) {
137                            ((Collection) it.next()).clear();
138                    }               
139            }
140    
141            /**
142             * Iterates over all collections and removes negated facts.
143             * Collection operations are synchronized using monitor object passed in get() method for a given collection
144             * or collection itself if monitor is null.
145             */
146            public synchronized boolean isNegatedBy(Negator negator) {
147                    Iterator it=collectionMap.entrySet().iterator();
148                    while (it.hasNext()) {
149                            Map.Entry entry = (Map.Entry) it.next();
150                            CollectionEntry ce = (CollectionEntry) entry.getKey();
151                            Collection col = (Collection) entry.getValue();
152                            synchronized (ce.monitor==null ? col : ce.monitor) {
153                                    Iterator cit=col.iterator();
154                                    while (cit.hasNext()) {
155                                            Object o=cit.next();
156                                            if (o instanceof Conclusion) {
157                                                    if (((Conclusion) o).isNegatedBy(negator)) {
158                                                            cit.remove();
159                                                    }
160                                            } else {
161                                                    if (negator.negates(o)) {
162                                                            cit.remove();
163                                                    }
164                                            }
165                                    }
166                            }
167                    }
168                    return false; // Return value has no meaning for collection manager.
169            }
170            
171            public void setCollectionType(String collectionType) {
172                    try {
173                            this.collectionType = Class.forName(collectionType);
174                    } catch (ClassNotFoundException e) {
175                            throw new RuntimeConfigurationException("Cannot load collection class: "+e, e);
176                    }
177            }
178    
179            public void setCollectionType(Class collectionType) {
180                    this.collectionType = collectionType;
181            }
182    }