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    package org.picocontainer.visitors;
009    
010    import java.util.ArrayList;
011    import java.util.HashSet;
012    import java.util.List;
013    import java.util.Set;
014    
015    import org.picocontainer.ComponentAdapter;
016    import org.picocontainer.ComponentFactory;
017    import org.picocontainer.Parameter;
018    import org.picocontainer.PicoContainer;
019    import org.picocontainer.PicoVerificationException;
020    import org.picocontainer.PicoVisitor;
021    
022    
023    /**
024     * Visitor to verify {@link PicoContainer} instances. The visitor walks down the logical container hierarchy.
025     * 
026     * @author Jörg Schaible
027     */
028    public class VerifyingVisitor extends TraversalCheckingVisitor {
029    
030        private final List<RuntimeException> nestedVerificationExceptions;
031        private final Set<ComponentAdapter> verifiedComponentAdapters;
032        private final Set<ComponentFactory> verifiedComponentFactories;
033        private final PicoVisitor componentAdapterCollector;
034        private PicoContainer currentPico;
035    
036        /**
037         * Construct a VerifyingVisitor.
038         */
039        public VerifyingVisitor() {
040            nestedVerificationExceptions = new ArrayList<RuntimeException>();
041            verifiedComponentAdapters = new HashSet<ComponentAdapter>();
042            verifiedComponentFactories = new HashSet<ComponentFactory>();
043            componentAdapterCollector = new ComponentAdapterCollector();
044        }
045    
046        /**
047         * Traverse through all components of the {@link PicoContainer} hierarchy and verify the components.
048         * 
049         * @throws PicoVerificationException if some components could not be verified.
050         * @see org.picocontainer.PicoVisitor#traverse(java.lang.Object)
051         */
052        public Object traverse(Object node) throws PicoVerificationException {
053            nestedVerificationExceptions.clear();
054            verifiedComponentAdapters.clear();
055            try {
056                super.traverse(node);
057                if (!nestedVerificationExceptions.isEmpty()) {
058                    throw new PicoVerificationException(new ArrayList<RuntimeException>(nestedVerificationExceptions));
059                }
060            } finally {
061                nestedVerificationExceptions.clear();
062                verifiedComponentAdapters.clear();
063            }
064            return Void.TYPE;
065        }
066    
067        public boolean visitContainer(PicoContainer pico) {
068            super.visitContainer(pico);
069            currentPico = pico;
070            return CONTINUE_TRAVERSAL;
071        }
072    
073        public void visitComponentAdapter(ComponentAdapter<?> componentAdapter) {
074            super.visitComponentAdapter(componentAdapter);
075            if (!verifiedComponentAdapters.contains(componentAdapter)) {
076                try {
077                    componentAdapter.verify(currentPico);
078                } catch (RuntimeException e) {
079                    nestedVerificationExceptions.add(e);
080                }
081                componentAdapter.accept(componentAdapterCollector);
082            }
083    
084        }
085    
086        public void visitComponentFactory(ComponentFactory componentFactory) {
087            super.visitComponentFactory(componentFactory);
088    
089            if (!verifiedComponentFactories.contains(componentFactory)) {
090                try {
091                    componentFactory.verify(currentPico);
092                } catch (RuntimeException e) {
093                    nestedVerificationExceptions.add(e);
094                }
095                componentFactory.accept(componentAdapterCollector);
096            }
097    
098        }
099    
100    
101    
102        private class ComponentAdapterCollector implements PicoVisitor {
103            // /CLOVER:OFF
104            public Object traverse(Object node) {
105                return null;
106            }
107    
108            public boolean visitContainer(PicoContainer pico) {
109                return CONTINUE_TRAVERSAL;
110            }
111    
112            // /CLOVER:ON
113    
114            public void visitComponentAdapter(ComponentAdapter componentAdapter) {
115                verifiedComponentAdapters.add(componentAdapter);
116            }
117    
118            public void visitComponentFactory(ComponentFactory componentFactory) {
119                verifiedComponentFactories.add(componentFactory);
120            }
121    
122            public void visitParameter(Parameter parameter) {
123    
124            }
125        }
126    }