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 */
011package com.thoughtworks.proxy.toys.failover;
012
013import java.util.ArrayList;
014import java.util.List;
015
016import com.thoughtworks.proxy.ProxyFactory;
017import 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 */
028public 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}