001    package nl.cwi.sen1.modulemanager.model;
002    
003    import java.util.HashMap;
004    import java.util.HashSet;
005    import java.util.Iterator;
006    import java.util.LinkedList;
007    import java.util.Map;
008    import java.util.Set;
009    
010    import nl.cwi.sen1.moduleapi.types.AttributeStore;
011    import nl.cwi.sen1.moduleapi.types.ModuleId;
012    import aterm.AFun;
013    import aterm.ATerm;
014    import aterm.ATermAppl;
015    import aterm.pure.PureFactory;
016    
017    public class ModuleDatabase {
018            private int moduleCount;
019    
020            protected Map<ModuleId, Module> modules;
021    
022            protected Map<ModuleId, Set<ModuleId>> descendants;
023    
024            private Map<ModuleId, Set<ModuleId>> transDescendants;
025    
026            private AttributeUpdateRuleMap attributeUpdateRules;
027    
028            private Map<ModuleId, Set<ModuleId>> ascendants;
029    
030            private AttributeSetListener listener;
031    
032            private AFun modalAND, modalOR, modalNOT, modalONE, modalALL, modalSET;
033    
034            public ModuleDatabase(AttributeSetListener l, PureFactory factory) {
035                    moduleCount = 0;
036                    modules = new HashMap<ModuleId, Module>();
037                    descendants = new HashMap<ModuleId, Set<ModuleId>>();
038                    transDescendants = new HashMap<ModuleId, Set<ModuleId>>();
039                    ascendants = new HashMap<ModuleId, Set<ModuleId>>();
040                    listener = l;
041                    attributeUpdateRules = new AttributeUpdateRuleMap();
042    
043                    modalAND = factory.makeAFun("and", 2, false);
044                    modalOR = factory.makeAFun("or", 2, false);
045                    modalNOT = factory.makeAFun("not", 1, false);
046                    modalONE = factory.makeAFun("one", 1, false);
047                    modalALL = factory.makeAFun("all", 1, false);
048                    modalSET = factory.makeAFun("set", 3, false);
049            }
050    
051            public int getNextModuleId() {
052                    return moduleCount++;
053            }
054    
055            public void addModule(Module module, ModuleId moduleId) {
056                    modules.put(moduleId, module);
057                    descendants.put(moduleId, new HashSet<ModuleId>());
058                    ascendants.put(moduleId, new HashSet<ModuleId>());
059            }
060    
061            public void removeModule(ModuleId moduleId) {
062                    deleteAllDependencies(moduleId);
063                    modules.remove(moduleId);
064                    descendants.remove(moduleId);
065                    ascendants.remove(moduleId);
066            }
067    
068            private void triggerAllAttributeUpdateRulesOnAllModules() {
069                    for (Iterator<ModuleId> iter = modules.keySet().iterator(); iter
070                                    .hasNext();) {
071                            triggerAllAttributeUpdateRules(iter.next());
072                    }
073            }
074    
075            private void triggerAllAttributeUpdateRules(ModuleId id) {
076                    for (Iterator<AttributeUpdateRule> iter = attributeUpdateRules
077                                    .iterator(); iter.hasNext();) {
078                            propagate(iter.next(), id);
079                    }
080            }
081    
082            public void setAttribute(ModuleId moduleId, ATerm namespace, ATerm key,
083                            ATerm value) {
084                    Module module = modules.get(moduleId);
085    
086                    if (module == null) {
087                            System.err.println("MM - addAttribute: module [" + moduleId
088                                            + "] doesn't exist");
089                            return;
090                    }
091    
092                    updateAttribute(moduleId, namespace, key, value);
093            }
094    
095            private void updateAttribute(ModuleId moduleId, ATerm namespace, ATerm key,
096                            ATerm value) {
097                    Module module = modules.get(moduleId);
098                    ATerm oldValue = module.getAttribute(namespace, key);
099                    ATerm oldPredicate = module.getPredicate(namespace, key);
100    
101                    module.deletePredicate(namespace, key);
102    
103                    if (oldValue == null || !oldValue.isEqual(value)) {
104                            module.setAttribute(namespace, key, value);
105                            if (oldPredicate != null) {
106                                    fireAttributeSetListener(moduleId, namespace, key,
107                                                    oldPredicate, value);
108                            } else {
109                                    fireAttributeSetListener(moduleId, namespace, key, oldValue,
110                                                    value);
111                            }
112                            propagateToParents(moduleId);
113                            triggerAllAttributeUpdateRules(moduleId);
114                    }
115            }
116    
117            private void updatePredicate(ModuleId moduleId, ATerm namespace, ATerm key,
118                            ATerm predicate) {
119                    Module module = modules.get(moduleId);
120                    ATerm oldValue = module.getPredicate(namespace, key);
121                    // If there was no predicate get the old value. The listener gives the
122                    // new value as well as the old value.
123                    if (oldValue == null) {
124                            oldValue = module.getAttribute(namespace, key);
125                    }
126    
127                    if (oldValue == null || !oldValue.isEqual(predicate)) {
128                            module.setPredicate(namespace, key, predicate);
129                            fireAttributeSetListener(moduleId, namespace, key, oldValue,
130                                            predicate);
131                            propagateToParents(moduleId);
132                    }
133            }
134    
135            private void fireAttributeSetListener(ModuleId id, ATerm namespace,
136                            ATerm key, ATerm oldValue, ATerm newValue) {
137                    listener.attributeSet(id, namespace, key, oldValue, newValue);
138            }
139    
140            private void propagateToParents(ModuleId id) {
141                    Set<ModuleId> parents = getParents(id);
142                    for (Iterator<ModuleId> iter = parents.iterator(); iter.hasNext();) {
143                            triggerAllAttributeUpdateRules(iter.next());
144                    }
145            }
146    
147            private void propagate(AttributeUpdateRule rule, ModuleId id) {
148                    Module module = modules.get(id);
149                    ATerm namespace = rule.getNamespace();
150                    ATerm key = rule.getKey();
151    
152                    ATerm oldPredicate = module.getPredicate(namespace, key);
153                    ATerm newPredicate = rule.getPredicateValue();
154    
155                    ATerm oldValue = module.getAttribute(namespace, key);
156    
157                    ATerm formula = rule.getFormula();
158                    boolean result = innermostRuleEvaluation(formula, id);
159    
160                    if (result) {
161                            updatePredicate(id, namespace, key, newPredicate);
162                    } else {
163                            /* Fall back to attribute value by removing predicate */
164                            if (oldPredicate != null && newPredicate.equals(oldPredicate)) {
165                                    module.deletePredicate(namespace, key);
166                                    fireAttributeSetListener(id, namespace, key, oldPredicate,
167                                                    oldValue);
168                                    propagateToParents(id);
169                            }
170                    }
171            }
172    
173            public ATerm getModuleAttribute(ModuleId moduleId, ATerm namespace,
174                            ATerm key) {
175                    Module module = modules.get(moduleId);
176    
177                    if (module == null) {
178                            System.err.println("MM - getModuleAttribute: module [" + moduleId
179                                            + "] doesn't exist");
180                            return null;
181                    }
182    
183                    ATerm value = module.getPredicate(namespace, key);
184                    if (value == null) {
185                            value = module.getAttribute(namespace, key);
186                    }
187    
188                    return value;
189            }
190    
191            public ModuleId getModuleIdByAttribute(ATerm namespace, ATerm key,
192                            ATerm value) {
193                    for (Iterator<ModuleId> iter = modules.keySet().iterator(); iter
194                                    .hasNext();) {
195                            ModuleId moduleId = iter.next();
196                            Module module = modules.get(moduleId);
197    
198                            if (value.equals(module.getPredicate(namespace, key))) {
199                                    return moduleId;
200                            } else if (value.equals(module.getAttribute(namespace, key))) {
201                                    return moduleId;
202                            }
203                    }
204    
205                    return null;
206            }
207    
208            public Set<ModuleId> getAllModules() {
209                    Set<ModuleId> allModules = new HashSet<ModuleId>();
210    
211                    for (Iterator<ModuleId> iter = modules.keySet().iterator(); iter
212                                    .hasNext();) {
213                            allModules.add(iter.next());
214                    }
215    
216                    return allModules;
217            }
218    
219            public void deleteModuleAttribute(ModuleId moduleId, ATerm namespace,
220                            ATerm key) {
221                    Module module = modules.get(moduleId);
222    
223                    if (module == null) {
224                            System.err.println("MM - deleteModuleAttribute: module ["
225                                            + moduleId + "] doesn't exist");
226                            return;
227                    }
228    
229                    module.deleteAttribute(namespace, key);
230            }
231    
232            public AttributeStore getAllAttributes(ModuleId moduleId) {
233                    Module module = modules.get(moduleId);
234    
235                    if (module == null) {
236                            throw new IllegalArgumentException(
237                                            "MM - getAllAttributes: module [" + moduleId
238                                                            + "] doesn't exist");
239                    }
240    
241                    return module.getAttributes();
242            }
243    
244            public void addDependency(ModuleId moduleFromId, ModuleId moduleToId) {
245                    Set<ModuleId> dependencies;
246                    Module moduleFrom = modules.get(moduleFromId);
247                    Module moduleTo = modules.get(moduleToId);
248    
249                    if (moduleFrom == null) {
250                            System.err.println("MM - addDependency: module [" + moduleFromId
251                                            + "] doesn't exist");
252                            return;
253                    }
254    
255                    if (moduleTo == null) {
256                            System.err.println("MM - addDependency: module [" + moduleToId
257                                            + "] doesn't exist");
258                            return;
259                    }
260    
261                    dependencies = descendants.get(moduleFromId);
262                    dependencies.add(moduleToId);
263    
264                    dependencies = ascendants.get(moduleToId);
265                    dependencies.add(moduleFromId);
266    
267                    transDescendants = new HashMap<ModuleId, Set<ModuleId>>();
268            }
269    
270            public Set<ModuleId> getChildren(ModuleId moduleId) {
271                    return descendants.get(moduleId);
272            }
273    
274            public Set<ModuleId> getAllChildren(ModuleId moduleId) {
275                    Set<ModuleId> dependencies = transDescendants.get(moduleId);
276    
277                    if (dependencies == null) {
278                            dependencies = new HashSet<ModuleId>();
279                            LinkedList<ModuleId> temp = new LinkedList<ModuleId>();
280    
281                            temp.addAll(getChildren(moduleId));
282    
283                            while (!temp.isEmpty()) {
284                                    ModuleId tempId = temp.getFirst();
285                                    if (!dependencies.contains(tempId)) {
286                                            dependencies.add(tempId);
287                                            temp.addAll(getChildren(tempId));
288                                    }
289                                    temp.removeFirst();
290                            }
291    
292                            transDescendants.put(moduleId, dependencies);
293                    }
294    
295                    return dependencies;
296            }
297    
298            public Set<ModuleId> getParents(ModuleId moduleId) {
299                    return ascendants.get(moduleId);
300            }
301    
302            public Set<ModuleId> getAllParents(ModuleId moduleId) {
303                    Set<ModuleId> dependencies = new HashSet<ModuleId>();
304                    LinkedList<ModuleId> temp = new LinkedList<ModuleId>();
305    
306                    temp.addAll(getParents(moduleId));
307    
308                    while (!temp.isEmpty()) {
309                            ModuleId tempId = temp.getFirst();
310                            if (!dependencies.contains(tempId)) {
311                                    dependencies.add(tempId);
312                                    temp.addAll(getParents(tempId));
313                            }
314                            temp.removeFirst();
315                    }
316    
317                    return dependencies;
318            }
319    
320            public Set<ModuleId> getClosableModules(ModuleId moduleId) {
321                    Set<ModuleId> dependencies = getAllChildren(moduleId);
322                    LinkedList<ModuleId> temp = new LinkedList<ModuleId>();
323    
324                    dependencies.add(moduleId);
325                    temp.addAll(dependencies);
326    
327                    while (!temp.isEmpty()) {
328                            ModuleId tempId = temp.getFirst();
329                            Set<ModuleId> parents = getParents(tempId);
330    
331                            if (!dependencies.containsAll(parents)) {
332                                    Set<ModuleId> children = getAllChildren(tempId);
333                                    dependencies.removeAll(children);
334                                    dependencies.remove(tempId);
335                            }
336    
337                            temp.removeFirst();
338                    }
339    
340                    return dependencies;
341            }
342    
343            public void deleteDependency(ModuleId moduleFromId, ModuleId moduleToId) {
344                    LinkedList<ModuleId> deps;
345                    Module moduleFrom = modules.get(moduleFromId);
346    
347                    if (moduleFrom == null) {
348                            System.err.println("MM - deleteDependency: module [" + moduleFromId
349                                            + "] doesn't exist");
350                            return;
351                    }
352    
353                    Module moduleTo = modules.get(moduleToId);
354    
355                    if (moduleTo == null) {
356                            System.err.println("MM - deleteDependency: module [" + moduleToId
357                                            + "] doesn't exist");
358                            return;
359                    }
360    
361                    deps = new LinkedList<ModuleId>(descendants.get(moduleFromId));
362                    deps.remove(moduleToId);
363    
364                    deps = new LinkedList<ModuleId>(ascendants.get(moduleToId));
365                    deps.remove(moduleFromId);
366    
367                    transDescendants = new HashMap<ModuleId, Set<ModuleId>>();
368            }
369    
370            public void deleteDependencies(ModuleId moduleId) {
371                    Set<ModuleId> dependencies;
372    
373                    Module module = modules.get(moduleId);
374    
375                    if (module == null) {
376                            System.err.println("MM - deleteDependencies: module [" + moduleId
377                                            + "] doesn't exist");
378                            return;
379                    }
380    
381                    for (Iterator<ModuleId> iter = modules.keySet().iterator(); iter
382                                    .hasNext();) {
383                            ModuleId tempId = iter.next();
384                            dependencies = getParents(tempId);
385                            if (dependencies.contains(moduleId)) {
386                                    dependencies.remove(moduleId);
387                            }
388                    }
389    
390                    dependencies = descendants.get(moduleId);
391                    dependencies.clear();
392            }
393    
394            private void deleteAllDependencies(ModuleId moduleId) {
395                    deleteDependencies(moduleId);
396    
397                    for (Iterator<ModuleId> iter = modules.keySet().iterator(); iter
398                                    .hasNext();) {
399                            Set<ModuleId> dependencies = getChildren(iter.next());
400                            if (dependencies.contains(moduleId)) {
401                                    dependencies.remove(moduleId);
402                            }
403                    }
404            }
405    
406            public Map<ModuleId, Set<ModuleId>> getDependencies() {
407                    return descendants;
408            }
409    
410            public void printStatistics() {
411                    int sumDeps = 0;
412                    for (Iterator<Set<ModuleId>> iter = descendants.values().iterator(); iter
413                                    .hasNext();) {
414                            sumDeps += iter.next().size();
415                    }
416                    System.err.println(modules.size() + " modules");
417                    System.err.println(sumDeps + " dependencies");
418            }
419    
420            public void registerAttributeUpdateRule(ATerm namespace, ATerm key,
421                            ATerm rule, ATerm value) {
422                    for (Iterator<AttributeUpdateRule> iter = attributeUpdateRules
423                                    .iterator(); iter.hasNext();) {
424                            AttributeUpdateRule check = iter.next();
425                            if (checkRuleViolation(check.getNamespace(), check.getKey(), check
426                                            .getPredicateValue(), rule)) {
427                                    System.err.println("Rule " + rule + " violates " + check);
428                                    return;
429                            }
430                    }
431                    attributeUpdateRules.put(namespace, key, rule, value);
432                    triggerAllAttributeUpdateRulesOnAllModules();
433            }
434    
435            private boolean checkRuleViolation(ATerm namespace, ATerm key,
436                            ATerm predicate, ATerm rule) {
437                    if (((ATermAppl) rule).getAFun().equals(modalSET)) {
438                            return (rule.getChildAt(0).equals(namespace)
439                                            && rule.getChildAt(1).equals(key) && rule.getChildAt(2)
440                                            .equals(predicate));
441                    }
442    
443                    boolean violation = false;
444                    for (int i = 0; i < rule.getChildCount(); i++) {
445                            violation = violation
446                                            || checkRuleViolation(namespace, key, predicate,
447                                                            (ATerm) rule.getChildAt(i));
448                    }
449                    return violation;
450            }
451    
452            private boolean innermostRuleEvaluation(ATerm rule, ModuleId id) {
453                    if (((ATermAppl) rule).getAFun().equals(modalAND)) {
454                            return evaluateAnd((ATerm) rule.getChildAt(0), (ATerm) rule
455                                            .getChildAt(1), id);
456                    }
457                    if (((ATermAppl) rule).getAFun().equals(modalOR)) {
458                            return evaluateOr((ATerm) rule.getChildAt(0), (ATerm) rule
459                                            .getChildAt(1), id);
460                    }
461                    if (((ATermAppl) rule).getAFun().equals(modalNOT)) {
462                            return evaluateNot((ATerm) rule.getChildAt(0), id);
463                    }
464                    if (((ATermAppl) rule).getAFun().equals(modalONE)) {
465                            return evaluateOne((ATerm) rule.getChildAt(0), id);
466                    }
467                    if (((ATermAppl) rule).getAFun().equals(modalALL)) {
468                            return evaluateAll((ATerm) rule.getChildAt(0), id);
469                    }
470                    if (((ATermAppl) rule).getAFun().equals(modalSET)) {
471                            return evaluateSet((ATerm) rule.getChildAt(2), id, (ATerm) rule
472                                            .getChildAt(0), (ATerm) rule.getChildAt(1));
473                    }
474    
475                    System.err.println("Error evaluating attribute update rule [" + rule
476                                    + "]; forgot set?");
477                    return false;
478            }
479    
480            private boolean evaluateAnd(ATerm op1, ATerm op2, ModuleId id) {
481                    return (innermostRuleEvaluation(op1, id) && innermostRuleEvaluation(
482                                    op2, id));
483            }
484    
485            private boolean evaluateOr(ATerm op1, ATerm op2, ModuleId id) {
486                    return (innermostRuleEvaluation(op1, id) || innermostRuleEvaluation(
487                                    op2, id));
488            }
489    
490            private boolean evaluateNot(ATerm op, ModuleId id) {
491                    return !(innermostRuleEvaluation(op, id));
492            }
493    
494            private boolean evaluateOne(ATerm op, ModuleId id) {
495                    boolean result = false;
496                    Set<ModuleId> children = getAllChildren(id);
497                    Iterator<ModuleId> iter = children.iterator();
498    
499                    while (iter.hasNext() && result == false) {
500                            ModuleId childId = iter.next();
501                            result = innermostRuleEvaluation(op, childId);
502                    }
503    
504                    return result;
505            }
506    
507            private boolean evaluateAll(ATerm op, ModuleId id) {
508                    boolean result = true;
509                    Set<ModuleId> children = getAllChildren(id);
510                    Iterator<ModuleId> iter = children.iterator();
511    
512                    while (iter.hasNext() && result == true) {
513                            ModuleId childId = iter.next();
514                            result = innermostRuleEvaluation(op, childId);
515                    }
516    
517                    return result;
518            }
519    
520            private boolean evaluateSet(ATerm op, ModuleId id, ATerm namespace,
521                            ATerm key) {
522                    ATerm value = modules.get(id).getAttribute(namespace, key);
523    
524                    return op.equals(value);
525            }
526    }