    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    }