001/*
002 * (c) 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 19-03-2010.
010 */
011package com.thoughtworks.proxy.toys.privilege;
012
013import com.thoughtworks.proxy.ProxyFactory;
014import com.thoughtworks.proxy.factory.StandardProxyFactory;
015import com.thoughtworks.proxy.kit.SimpleReference;
016
017/**
018 * Toy factory to create proxies executing the method calls as privileged actions.
019 *
020 * @author Jörg Schaible
021 * @see com.thoughtworks.proxy.toys.privilege
022 * @since 1.0
023 */
024public class Privileging<T>
025{
026    private Class<T> type;
027    private Object delegate;
028    private ActionExecutor executor;
029
030    /**
031     * Creates a factory for proxy instances that allow a privileged execution of the methods of an object.
032     *
033     * @param type     the type of the proxy when it is finally created.
034     * @return a factory that will proxy instances of the supplied type.
035     * @since 1.0
036     */
037    public static <T> PrivilegingWith<T> proxy(Class<T> type) {
038        return new PrivilegingWith<T>(new Privileging<T>(type));
039    }
040
041    /**
042     * Creates a factory for proxy instances that allow a privileged execution of the methods of an object.
043     *
044     * @param target     the target object that is proxied.
045     * @return a factory that will proxy instances of the supplied type.
046     * @since 1.0
047     */
048    public static <T> PrivilegingExecutedByOrBuild<T> proxy(T target) {
049        @SuppressWarnings("unchecked")
050        Class<T> type = (Class<T>)target.getClass();
051        Privileging<T> privileging = new Privileging<T>(type);
052        privileging.delegate = target;
053        return new PrivilegingExecutedByOrBuild<T>(privileging);
054    }
055
056    private Privileging(Class<T> type) {
057        this.type = type;
058    }
059    
060    public static class PrivilegingWith<T> {
061        private Privileging<T> delegating;
062
063        private PrivilegingWith(Privileging<T> delegating) {
064            this.delegating = delegating;
065        }
066
067        /**
068         * With this delegate.
069         *
070         * @param delegate the object the proxy delegates to.
071         * @return the factory that will route calls to the supplied delegate.
072         * @since 1.0
073         */
074        public PrivilegingExecutedByOrBuild<T> with(Object delegate) {
075            delegating.delegate = delegate;
076            return new PrivilegingExecutedByOrBuild<T>(delegating);
077        }
078    }
079    
080    public static class PrivilegingExecutedByOrBuild<T> extends PrivilegingBuild<T>{
081        private PrivilegingExecutedByOrBuild(Privileging<T> privileging) {
082            super(privileging);
083        }
084
085        /**
086         * Executed with this action executor.
087         *
088         * @param executor the executor that runs the privileged actions.
089         * @return the factory that will route calls to the supplied delegate.
090         * @since 1.0
091         */
092        public PrivilegingBuild<T> executedBy(ActionExecutor executor) {
093            privileging.executor = executor;
094            return new PrivilegingBuild<T>(privileging);
095        }
096    }
097    
098    public static class PrivilegingBuild<T> {
099        protected Privileging<T> privileging;
100
101        private PrivilegingBuild(Privileging<T> privileging) {
102            this.privileging = privileging;
103        }
104
105        /**
106         * Creating a privileging proxy for an object using the {@link StandardProxyFactory}.
107         *
108         * @return the created proxy implementing the <tt>type</tt>
109         * @since 1.0
110         */
111        public T build() {
112            return build(new StandardProxyFactory());
113        }
114
115        /**
116         * Creating a privileging proxy for an object using a special {@link ProxyFactory}.
117         *
118         * @param factory the {@link ProxyFactory} to use.
119         * @return the created proxy implementing the <tt>type</tt>
120         * @since 1.0
121         */
122        public T build(ProxyFactory factory) {
123            return factory.<T>createProxy(new PrivilegingInvoker<Object>(factory,
124                    new SimpleReference<Object>(privileging.delegate), privileging.executor), privileging.type);
125        }
126    }
127}