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    
011    package org.picocontainer.gems.monitors;
012    
013    import java.lang.reflect.Constructor;
014    import java.util.ArrayList;
015    import java.util.Collections;
016    import java.util.HashSet;
017    import java.util.List;
018    import java.util.Set;
019    
020    import org.picocontainer.ComponentAdapter;
021    import org.picocontainer.ComponentMonitor;
022    import org.picocontainer.PicoContainer;
023    import org.picocontainer.monitors.AbstractComponentMonitor;
024    
025    @SuppressWarnings("serial")
026    public 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    }