001    /*
002     * (c) 2003-2005, 2009, 2010 ThoughtWorks Ltd
003     * All rights reserved.
004     *
005     * The software in this package is published under the terms of the BSD
006     * style license a copy of which has been included with this distribution in
007     * the LICENSE.txt file.
008     * 
009     * Created on 11-May-2004
010     */
011    package com.thoughtworks.proxy.toys.failover;
012    
013    import java.util.ArrayList;
014    import java.util.List;
015    
016    import com.thoughtworks.proxy.ProxyFactory;
017    import com.thoughtworks.proxy.kit.ReflectionUtils;
018    
019    /**
020     * Factory for proxy instances handling failover. Delegates to one object as long as there is no exception, fails over
021     * to the next when an exception occurs.
022     *
023     * @author Aslak Hellesøy
024     * @author Paul Hammant
025     * @see com.thoughtworks.proxy.toys.failover
026     * @since 0.1
027     */
028    public class Failover<T> {
029        private Class<?>[] types;
030        private T[] delegates;
031        private Class<? extends Throwable> exceptionClass;
032    
033        private Failover(Class<T> primaryType, Class<?>... types) {
034            this.types = ReflectionUtils.makeTypesArray(primaryType, types);
035        }
036    
037        /**
038         * Creates a factory for proxy instances handling failover situations.
039         *
040         * @param type the types of the proxy
041         * @return a factory that will proxy instances of the supplied type.
042         * @since 1.0
043         */
044        public static <T> FailoverWithOrExceptingOrBuild<T> proxy(Class<T> type) {
045            return new FailoverWithOrExceptingOrBuild<T>(new Failover<T>(type));
046        }
047        
048        /**
049         * Creates a factory for proxy instances handling failover situations.
050         *
051         * @param primaryType the primary type implemented by the proxy
052         * @param types other types that are implemented by the proxy
053         * @return a factory that will proxy instances of the supplied type.
054         * @since 1.0
055         */
056        public static <T> FailoverWithOrExceptingOrBuild<T> proxy(final Class<T> primaryType, final Class<?> ... types) {
057            return new FailoverWithOrExceptingOrBuild<T>(new Failover<T>(primaryType, types));
058        }
059        
060        /**
061         * Creates a factory for proxy instances handling failover situations.
062         *
063         * @param delegates the array with the delegates in a failover situation
064         * @return a factory that will proxy instances of the supplied type.
065         * @since 1.0
066         */
067        public static <T> FailoverExceptingOrBuild<T> proxy(final T... delegates) {
068            Failover<T> failover = new Failover<T>(null);
069            failover.delegates = delegates;
070            return new FailoverExceptingOrBuild<T>(failover);
071        }
072    
073        public static class FailoverWithOrExceptingOrBuild<T> extends FailoverExceptingOrBuild<T> {
074    
075            private FailoverWithOrExceptingOrBuild(Failover<T> failover) {
076                super(failover);
077            }
078    
079            /**
080             * With these delegates.
081             *
082             * @param delegates the delegates used for failover
083             * @return a factory that will use the supplied delegates in case of a failure.
084             * @since 1.0
085             */
086            public FailoverExceptingOrBuild<T> with(final T... delegates) {
087                failover.delegates = delegates;
088                return new FailoverExceptingOrBuild<T>(failover);
089            }
090        }
091    
092        public static class FailoverExceptingOrBuild<T> extends FailoverBuild<T> {
093    
094            private FailoverExceptingOrBuild(Failover<T> failover) {
095                super(failover);
096            }
097    
098            /**
099             * Excepting this exception class.
100             *
101             * @param exceptionClass the type of the exceptions triggering failover
102             * @return a factory that will trigger the usage of the next delegate based on the supplied Throwable type.
103             * @since 1.0
104             */
105            public FailoverBuild<T> excepting(Class<? extends Throwable> exceptionClass) {
106                failover.exceptionClass = exceptionClass;
107                return new FailoverBuild<T>(failover);
108            }
109        }
110    
111        public static class FailoverBuild<T> {
112            protected Failover<T> failover;
113    
114            private FailoverBuild(Failover<T> failover) {
115                this.failover = failover;
116            }
117    
118            /**
119             * Create a proxy of a specific types with failover capability using the given objects.  The provided exception type
120             * determines the type of exceptions that trigger the failover.
121             *
122             * @param proxyFactory the {@link ProxyFactory} to use
123             * @return the created proxy
124             * @since 1.0
125             */
126            public T build(final ProxyFactory proxyFactory) {
127                return new FailoverInvoker<T>(failover.types, proxyFactory, failover.delegates, failover.exceptionClass).proxy();
128            }
129        }
130    }