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 *****************************************************************************/
008package org.picocontainer.visitors;
009
010import java.util.ArrayList;
011import java.util.HashSet;
012import java.util.List;
013import java.util.Set;
014
015import org.picocontainer.ComponentAdapter;
016import org.picocontainer.ComponentFactory;
017import org.picocontainer.Parameter;
018import org.picocontainer.PicoContainer;
019import org.picocontainer.PicoVerificationException;
020import 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 */
028public 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}