001: /*
002: * This file is part of PFIXCORE.
003: *
004: * PFIXCORE is free software; you can redistribute it and/or modify
005: * it under the terms of the GNU Lesser General Public License as published by
006: * the Free Software Foundation; either version 2 of the License, or
007: * (at your option) any later version.
008: *
009: * PFIXCORE is distributed in the hope that it will be useful,
010: * but WITHOUT ANY WARRANTY; without even the implied warranty of
011: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
012: * GNU Lesser General Public License for more details.
013: *
014: * You should have received a copy of the GNU Lesser General Public License
015: * along with PFIXCORE; if not, write to the Free Software
016: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
017: *
018: */
019:
020: package de.schlund.pfixxml.targets;
021:
022: import java.util.Collection;
023: import java.util.HashMap;
024: import java.util.HashSet;
025: import java.util.Iterator;
026: import java.util.TreeSet;
027:
028: import org.apache.log4j.Logger;
029:
030: import de.schlund.pfixxml.util.RefCountingCollection;
031:
032: /**
033: * TargetDependencyRelation This is a helper singleton class that holds all the "interesting"
034: * relations between targets and AuxDependencies. These relations are build up during the generation
035: * of a target via the addRelation(parent, child, target) method, and reset before gneration of the
036: * target via the resetRelation(target) method.
037: *
038: * The relations currently handled are:
039: *
040: * Target -> Set(AuxDependency)
041: * AuxDependency -> Set(Target)
042: * TargetGenerator -> RefCountingCollection(AuxDependency)
043: * AuxDependency -> RefCountingCollection(TargetGenerator)
044: * Target -> Map("parent"-AuxDependency->Set("child"-AuxDependency))
045: * AuxDependency -> RefCountingCollection("child"-AuxDependency)
046: * Target -> Map("child"-AuxDependency->Set("parent"-AuxDependency)) // Commented out currently!
047: * AuxDependency -> RefCountingCollection("parent"-AuxDependency) // Commented out currently!
048: *
049: * The last two mappings are not use anywhere and are thus commented out in the code to save memory.
050: *
051: * Created: Thu Nov 24 13:00:00 2005
052: *
053: * @author <a href="mailto:jtl@schlund.de">Jens Lautenbacher</a>
054: *
055: */
056:
057: public class TargetDependencyRelation {
058: private static final Logger LOG = Logger
059: .getLogger(TargetDependencyRelation.class);
060: private static final TargetDependencyRelation instance = new TargetDependencyRelation();
061:
062: private HashMap<AuxDependency, TreeSet<Target>> allauxs;
063: private HashMap<Target, TreeSet<AuxDependency>> alltargets;
064: private HashMap<AuxDependency, RefCountingCollection<TargetGenerator>> auxtotgen;
065: private HashMap<TargetGenerator, RefCountingCollection<AuxDependency>> tgentoaux;
066: private HashMap<Target, HashMap<AuxDependency, HashSet<AuxDependency>>> targettoparentchild;
067: private HashMap<AuxDependency, RefCountingCollection<AuxDependency>> auxtochildaux;
068:
069: // private HashMap<Target, HashMap<AuxDependency, HashSet<AuxDependency>>> targettochildparent;
070: // private HashMap<AuxDependency, RefCountingCollection<AuxDependency>> auxtoparentaux;
071:
072: private TargetDependencyRelation() {
073: reset();
074: }
075:
076: public void reset() {
077: allauxs = new HashMap<AuxDependency, TreeSet<Target>>();
078: alltargets = new HashMap<Target, TreeSet<AuxDependency>>();
079: auxtotgen = new HashMap<AuxDependency, RefCountingCollection<TargetGenerator>>();
080: tgentoaux = new HashMap<TargetGenerator, RefCountingCollection<AuxDependency>>();
081: targettoparentchild = new HashMap<Target, HashMap<AuxDependency, HashSet<AuxDependency>>>();
082: auxtochildaux = new HashMap<AuxDependency, RefCountingCollection<AuxDependency>>();
083: // targettochildparent = new HashMap<Target, HashMap<AuxDependency, HashSet<AuxDependency>>>();
084: // auxtoparentaux = new HashMap<AuxDependency, RefCountingCollection<AuxDependency>>();
085: }
086:
087: public static final TargetDependencyRelation getInstance() {
088: return instance;
089: }
090:
091: public synchronized TreeSet<AuxDependency> getAllDependencies() {
092: if (allauxs.isEmpty()) {
093: return null;
094: } else {
095: return new TreeSet<AuxDependency>(allauxs.keySet());
096: }
097: }
098:
099: public synchronized TreeSet<AuxDependency> getProjectDependencies(
100: TargetGenerator tgen) {
101: RefCountingCollection<AuxDependency> auxsForTgen = tgentoaux
102: .get(tgen);
103: if (auxsForTgen == null) {
104: return null;
105: } else {
106: return new TreeSet<AuxDependency>(auxsForTgen);
107: }
108: }
109:
110: public synchronized TreeSet<AuxDependency> getAllDependenciesForType(
111: DependencyType type) {
112: if (allauxs.isEmpty()) {
113: return null;
114: } else {
115: TreeSet<AuxDependency> tmp = new TreeSet<AuxDependency>();
116: for (Iterator<AuxDependency> i = allauxs.keySet()
117: .iterator(); i.hasNext();) {
118: AuxDependency aux = i.next();
119: if (aux.getType().equals(type)) {
120: tmp.add(aux);
121: }
122: }
123: return tmp;
124: }
125: }
126:
127: public synchronized TreeSet<AuxDependency> getProjectDependenciesForType(
128: TargetGenerator tgen, DependencyType type) {
129: RefCountingCollection<AuxDependency> auxsForTgen = tgentoaux
130: .get(tgen);
131: if (auxsForTgen == null) {
132: return null;
133: } else {
134: TreeSet<AuxDependency> tmp = new TreeSet<AuxDependency>();
135: for (Iterator<AuxDependency> i = auxsForTgen.iterator(); i
136: .hasNext();) {
137: AuxDependency aux = i.next();
138: if (aux.getType().equals(type)) {
139: tmp.add(aux);
140: }
141: }
142: return tmp;
143: }
144: }
145:
146: public synchronized TreeSet<AuxDependency> getDependenciesForTarget(
147: Target target) {
148: TreeSet<AuxDependency> auxsForTarget = alltargets.get(target);
149: if (auxsForTarget == null) {
150: return null;
151: } else {
152: return new TreeSet<AuxDependency>(auxsForTarget);
153: }
154: }
155:
156: public synchronized TreeSet<Target> getAffectedTargets(
157: AuxDependency aux) {
158: TreeSet<Target> targetsForAux = allauxs.get(aux);
159: if (targetsForAux == null) {
160: return null;
161: } else {
162: return new TreeSet<Target>(targetsForAux);
163: }
164: }
165:
166: public synchronized TreeSet<TargetGenerator> getAffectedTargetGenerators(
167: AuxDependency aux) {
168: RefCountingCollection<TargetGenerator> tgensForAux = auxtotgen
169: .get(aux);
170: if (tgensForAux == null) {
171: return null;
172: } else {
173: return new TreeSet<TargetGenerator>(tgensForAux);
174: }
175: }
176:
177: synchronized HashMap<AuxDependency, HashSet<AuxDependency>> getParentChildMapForTarget(
178: Target target) {
179: HashMap<AuxDependency, HashSet<AuxDependency>> parentchildForTarget = targettoparentchild
180: .get(target);
181: if (parentchildForTarget == null) {
182: return null;
183: } else {
184: HashMap<AuxDependency, HashSet<AuxDependency>> retval = new HashMap<AuxDependency, HashSet<AuxDependency>>();
185: for (Iterator<AuxDependency> i = parentchildForTarget
186: .keySet().iterator(); i.hasNext();) {
187: AuxDependency parent = i.next();
188: if (parentchildForTarget.get(parent) != null) {
189: HashSet<AuxDependency> children = new HashSet<AuxDependency>(
190: parentchildForTarget.get(parent));
191: retval.put(parent, children);
192: }
193: }
194: return retval;
195: }
196: }
197:
198: public synchronized TreeSet<AuxDependency> getChildrenOverallForAuxDependency(
199: AuxDependency parent) {
200: RefCountingCollection<AuxDependency> children = auxtochildaux
201: .get(parent);
202: if (children == null) {
203: return null;
204: } else {
205: return new TreeSet<AuxDependency>(children);
206: }
207: }
208:
209: public synchronized TreeSet<AuxDependency> getChildrenForTargetForAuxDependency(
210: Target target, AuxDependency parent) {
211: HashMap<AuxDependency, HashSet<AuxDependency>> parentchildForTarget = targettoparentchild
212: .get(target);
213: if (parentchildForTarget == null) {
214: return null;
215: } else {
216: HashSet<AuxDependency> children = parentchildForTarget
217: .get(parent);
218: if (children == null) {
219: return null;
220: } else {
221: return new TreeSet<AuxDependency>(children);
222: }
223: }
224: }
225:
226: // public synchronized HashMap<AuxDependency, HashSet<AuxDependency>> getChildParentMapForTarget(Target target) {
227: // HashMap<AuxDependency, HashSet<AuxDependency>> childparentForTarget = targettochildparent.get(target);
228: // if (childparentForTarget == null) {
229: // return null;
230: // } else {
231: // HashMap<AuxDependency, HashSet<AuxDependency>> retval = new HashMap<AuxDependency, HashSet<AuxDependency>>();
232: // for (Iterator<AuxDependency> i = childparentForTarget.keySet().iterator(); i.hasNext();) {
233: // AuxDependency child = i.next();
234: // if (childparentForTarget.get(child) != null) {
235: // HashSet<AuxDependency> parents = (HashSet<AuxDependency>) childparentForTarget.get(child).clone();
236: // retval.put(child, parents);
237: // }
238: // }
239: // return retval;
240: // }
241: // }
242:
243: // public synchronized TreeSet<AuxDependency> getParentsOverallForAuxDependency(AuxDependency child) {
244: // RefCountingCollection<AuxDependency> parents = auxtoparentaux.get(child);
245: // if (parents == null) {
246: // return null;
247: // } else {
248: // return new TreeSet<AuxDependency>(parents);
249: // }
250: // }
251:
252: // public synchronized TreeSet<AuxDependency> getParentsForTargetForAuxDependency(Target target, AuxDependency child) {
253: // HashMap<AuxDependency, HashSet<AuxDependency>> childparentForTarget = targettochildparent.get(target);
254: // if (childparentForTarget == null) {
255: // return null;
256: // } else {
257: // HashSet<AuxDependency> parents = childparentForTarget.get(child);
258: // if (parents == null) {
259: // return null;
260: // } else {
261: // return new TreeSet<AuxDependency>(parents);
262: // }
263: // }
264: // }
265:
266: public synchronized void addRelation(AuxDependency parent,
267: AuxDependency aux, Target target) {
268:
269: if (parent != AuxDependencyManager.root
270: && !checkLoopFree(parent, aux, target)) {
271: throw new RuntimeException("*** FATAL *** Adding " + aux
272: + " to Parent " + parent + " for target "
273: + target.getFullName() + " would result in a LOOP!");
274: }
275:
276: LOG.debug("+++ Adding relations " + target.getFullName()
277: + " <-> " + aux.toString() + " / " + parent.toString());
278:
279: TargetGenerator tgen = target.getTargetGenerator();
280: if (allauxs.get(aux) == null) {
281: allauxs.put(aux, new TreeSet<Target>());
282: }
283: if (alltargets.get(target) == null) {
284: alltargets.put(target, new TreeSet<AuxDependency>());
285: }
286: if (auxtotgen.get(aux) == null) {
287: auxtotgen.put(aux,
288: new RefCountingCollection<TargetGenerator>());
289: }
290: if (tgentoaux.get(tgen) == null) {
291: tgentoaux.put(tgen,
292: new RefCountingCollection<AuxDependency>());
293: }
294: if (targettoparentchild.get(target) == null) {
295: targettoparentchild
296: .put(
297: target,
298: new HashMap<AuxDependency, HashSet<AuxDependency>>());
299: }
300: if (auxtochildaux.get(parent) == null) {
301: auxtochildaux.put(parent,
302: new RefCountingCollection<AuxDependency>());
303: }
304: // if (targettochildparent.get(target) == null) {
305: // targettochildparent.put(target, new HashMap<AuxDependency, HashSet<AuxDependency>>());
306: // }
307: // if (auxtoparentaux.get(aux) == null) {
308: // auxtoparentaux.put(aux, new RefCountingCollection<AuxDependency>());
309: // }
310:
311: TreeSet<Target> targetsForAux = allauxs.get(aux);
312: TreeSet<AuxDependency> auxsForTarget = alltargets.get(target);
313: RefCountingCollection<TargetGenerator> tgensForAux = auxtotgen
314: .get(aux);
315: RefCountingCollection<AuxDependency> auxsForTgen = tgentoaux
316: .get(tgen);
317: HashMap<AuxDependency, HashSet<AuxDependency>> parentchildForTarget = targettoparentchild
318: .get(target);
319: RefCountingCollection<AuxDependency> auxsForParent = auxtochildaux
320: .get(parent);
321: // HashMap<AuxDependency, HashSet<AuxDependency>> childparentForTarget = targettochildparent.get(target);
322: // RefCountingCollection<AuxDependency> auxsForChild = auxtoparentaux.get(aux);
323:
324: if (targetsForAux.add(target)) { // Make sure to ignore multiple target<->aux relations
325: auxsForTarget.add(aux);
326: tgensForAux.add(tgen);
327: auxsForTgen.add(aux);
328: }
329:
330: HashSet<AuxDependency> children = parentchildForTarget
331: .get(parent);
332: if (children == null) {
333: children = new HashSet<AuxDependency>();
334: parentchildForTarget.put(parent, children);
335: }
336: // HashSet<AuxDependency> parents = childparentForTarget.get(aux);
337: // if (parents == null) {
338: // parents = new HashSet<AuxDependency>();
339: // childparentForTarget.put(aux, parents);
340: // }
341:
342: if (children.add(aux)) { // Make sure to ignore multiple parent<->child relations
343: // Note: we must allow here multiple entries for the same
344: // child per target, but not per parent!
345: auxsForParent.add(aux);
346: // parents.add(parent);
347: // auxsForChild.add(parent);
348: }
349: }
350:
351: public synchronized void resetRelation(Target target) {
352: LOG.debug("--- Removing all relations for "
353: + target.getFullName());
354:
355: TargetGenerator tgen = target.getTargetGenerator();
356:
357: TreeSet<AuxDependency> auxsForTarget = alltargets.get(target);
358:
359: if (auxsForTarget == null) {
360: // CAT.debug("*** Trying to reset relations for unknown target " + target.getFullName() + " ***");
361: return;
362: }
363: if (auxsForTarget.isEmpty()) {
364: LOG.error("*** Known target " + target.getFullName()
365: + " has empty relation set! ***");
366: return;
367: }
368:
369: RefCountingCollection<AuxDependency> auxsForTgen = tgentoaux
370: .get(tgen);
371:
372: for (Iterator<AuxDependency> i = auxsForTarget.iterator(); i
373: .hasNext();) {
374: AuxDependency aux = i.next();
375: if (aux.getType().isDynamic()) {
376: TreeSet<Target> targetsForAux = allauxs.get(aux);
377: RefCountingCollection<TargetGenerator> tgensForAux = auxtotgen
378: .get(aux);
379:
380: targetsForAux.remove(target);
381: if (targetsForAux.isEmpty()) {
382: allauxs.remove(aux);
383: }
384: tgensForAux.remove(tgen);
385: if (tgensForAux.isEmpty()) {
386: auxtotgen.remove(aux);
387: }
388:
389: auxsForTgen.remove(aux);
390: i.remove();
391: }
392: }
393: if (auxsForTgen.isEmpty()) {
394: tgentoaux.remove(tgen);
395: }
396: if (auxsForTarget.isEmpty()) {
397: alltargets.remove(target);
398: }
399:
400: HashMap<AuxDependency, HashSet<AuxDependency>> parentchildForTarget = targettoparentchild
401: .get(target);
402: for (Iterator<AuxDependency> i = parentchildForTarget.keySet()
403: .iterator(); i.hasNext();) {
404: AuxDependency parent = i.next();
405: // System.out.println("---> parent: " + parent);
406: HashSet<AuxDependency> children = parentchildForTarget
407: .get(parent);
408: RefCountingCollection<AuxDependency> allchildren = auxtochildaux
409: .get(parent);
410: // System.out.println(" allc: " + allchildren);
411: for (Iterator<AuxDependency> j = children.iterator(); j
412: .hasNext();) {
413: AuxDependency child = j.next();
414: // System.out.println(" child: " + child);
415: if (child.getType().isDynamic()) {
416: allchildren.remove(child);
417: j.remove();
418: }
419: }
420: if (children.isEmpty()) {
421: i.remove();
422: }
423: if (allchildren.isEmpty()) {
424: auxtochildaux.remove(parent);
425: }
426: }
427: if (parentchildForTarget.isEmpty()) {
428: targettoparentchild.remove(target);
429: }
430:
431: // HashMap<AuxDependency, HashSet<AuxDependency>> childparentForTarget = targettochildparent.get(target);
432: // for (Iterator<AuxDependency> i = childparentForTarget.keySet().iterator(); i.hasNext(); ) {
433: // AuxDependency child = i.next();
434: // if (!child.getType().isDynamic()) { // YES! child.getType() here, not parent.getType() in the inner loop is correct!
435: // continue;
436: // }
437: // HashSet<AuxDependency> parents = childparentForTarget.get(child);
438: // RefCountingCollection<AuxDependency> allparents = auxtoparentaux.get(child);
439: // for (Iterator<AuxDependency> j = parents.iterator(); j.hasNext();) {
440: // AuxDependency parent = j.next();
441: // allparents.remove(parent);
442: // j.remove();
443: // }
444: // if (parents.isEmpty()) {
445: // i.remove();
446: // }
447: // if (allparents.isEmpty()) {
448: // auxtoparentaux.remove(child);
449: // }
450: // }
451: // if (childparentForTarget.isEmpty()) {
452: // targettochildparent.remove(target);
453: // }
454: }
455:
456: public synchronized void resetAllRelations(
457: Collection<Target> targets) {
458: for (Iterator<Target> i = targets.iterator(); i.hasNext();) {
459: Target target = i.next();
460: resetRelation(target);
461: }
462: }
463:
464: private synchronized boolean checkLoopFree(AuxDependency parent,
465: AuxDependency aux, Target target) {
466: // The simple loop
467: if (parent == aux) {
468: return false;
469: }
470:
471: HashMap<AuxDependency, HashSet<AuxDependency>> parentchild = targettoparentchild
472: .get(target);
473:
474: if (parentchild != null) {
475: // Now iterate over all children of aux recursively and check if any of them is parent.
476: HashSet<AuxDependency> children = parentchild.get(aux);
477: if (children != null) {
478: for (Iterator<AuxDependency> i = children.iterator(); i
479: .hasNext();) {
480: AuxDependency child = i.next();
481: if (child.getType() == DependencyType.TEXT) {
482: if (!checkLoopFree(parent, child, target)) {
483: return false;
484: }
485: }
486: }
487: }
488: }
489: return true;
490: }
491:
492: }// DependencyRefCounter
|