001/*****************************************************************************
002 * Copyright (C) PicoContainer Organization. All rights reserved.            *
003 * ------------------------------------------------------------------------- *
004 * The software in this package is published under the terms of the BSD      *
005 * style license a copy of which has been included with this distribution in *
006 * the LICENSE.txt file.                                                     *
007 *                                                                           *
008 * Original code by Paul Hammant                                             *
009 *****************************************************************************/
010
011package org.picocontainer.gems.monitors;
012
013import java.lang.reflect.Constructor;
014import java.util.ArrayList;
015import java.util.Collections;
016import java.util.HashSet;
017import java.util.List;
018import java.util.Set;
019
020import org.picocontainer.ComponentAdapter;
021import org.picocontainer.ComponentMonitor;
022import org.picocontainer.PicoContainer;
023import org.picocontainer.monitors.AbstractComponentMonitor;
024
025@SuppressWarnings("serial")
026public final class DotDependencyGraphComponentMonitor extends AbstractComponentMonitor implements ComponentMonitor {
027
028        
029        final List<Instantiation> allInstantiated = new ArrayList<Instantiation>();
030
031    public DotDependencyGraphComponentMonitor(final ComponentMonitor delegate) {
032        super(delegate);
033    }
034
035    public DotDependencyGraphComponentMonitor() {
036    }
037
038    @Override
039        public <T> void instantiated(final PicoContainer container, final ComponentAdapter<T> componentAdapter,
040                             final Constructor<T> constructor,
041                             final Object instantiated,
042                             final Object[] injected,
043                             final long duration) {
044
045        this.allInstantiated.add(new Instantiation(constructor, instantiated, injected, duration));
046
047        super.instantiated(container, componentAdapter, constructor, instantiated, injected, duration);
048    }
049
050
051    public String getClassDependencyGraph() {
052
053        Set<String> lines = new HashSet<String>();
054
055        for (Object anAllInstantiated : allInstantiated) {
056            Instantiation instantiation = (Instantiation)anAllInstantiated;
057            for (int j = 0; j < instantiation.getInjected().length; j++) {
058                Object instantiated = instantiation.getInstantiated();
059                Object injected = instantiation.getInjected()[j];
060                lines.add(
061                    "  '" + instantiated.getClass().getName() + "' -> '" + injected.getClass().getName() + "';\n");
062            }
063        }
064
065        return sortLines(lines);
066    }
067
068    private String sortLines(final Set<String> lines) {
069        List<String> list = new ArrayList<String>(lines);
070        Collections.sort(list);
071
072        String dependencies = "";
073        for (Object aList : list) {
074            String dep = (String)aList;
075            dependencies = dependencies + dep;
076        }
077        return dependencies.replaceAll("'","\"");
078    }
079
080    public String getInterfaceDependencyGraph() {
081        Set<String> lines = new HashSet<String>();
082
083        for (Object anAllInstantiated : allInstantiated) {
084            Instantiation instantiation = (Instantiation)anAllInstantiated;
085            for (int j = 0; j < instantiation.getInjected().length; j++) {
086                Object injected = instantiation.getInjected()[j];
087                Class<?> injectedType = instantiation.getConstructor().getParameterTypes()[j];
088                Object instantiated = instantiation.getInstantiated();
089                if (injected.getClass() != injectedType) {
090                    lines.add("  '" + instantiated.getClass().getName() + "' -> '" + injectedType.getName() +
091                              "' [style=dotted,label='needs'];\n");
092                    lines.add("  '" + injected.getClass().getName() + "' -> '" + injectedType.getName() +
093                              "' [style=dotted, color=red,label='isA'];\n");
094                    lines.add("  '" + injectedType.getName() + "' [shape=box, label=" + printClassName(injectedType) +
095                              "];\n");
096                } else {
097                    lines.add("  '" + instantiated.getClass().getName() + "' -> '" + injected.getClass().getName() +
098                              "' [label='needs'];\n");
099                }
100                lines.add("  '" + instantiated.getClass().getName() + "' [label=" +
101                          printClassName(instantiated.getClass()) + "];\n");
102
103            }
104        }
105
106        return sortLines(lines);
107    }
108
109    private String printClassName(final Class<?> clazz) {
110        String className = clazz.getName();
111        return "'" + className.substring(className.lastIndexOf(".")+1) + "\\n" + clazz.getPackage().getName() + "'";
112
113    }
114
115    private static final class Instantiation {
116        final Constructor<?> constructor;
117        final Object instantiated;
118        final Object[] injected;
119        final long duration;
120        
121        public Instantiation(final Constructor<?> constructor, final Object instantiated, final Object[] injected, final long duration) {
122            this.constructor = constructor;
123            this.instantiated = instantiated;
124            this.injected = injected;
125            this.duration = duration;
126        }
127
128        public Constructor<?> getConstructor() {
129            return constructor;
130        }
131
132        public Object getInstantiated() {
133            return instantiated;
134        }
135        public Object[] getInjected() {
136            return injected;
137        }
138    }
139}