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     */
011    package com.thoughtworks.proxy.toys.privilege;
012    
013    import com.thoughtworks.proxy.ProxyFactory;
014    import com.thoughtworks.proxy.factory.StandardProxyFactory;
015    import 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     */
024    public 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    }