001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017
018package org.apache.commons.proxy2.stub;
019
020import java.util.Collections;
021import java.util.HashSet;
022import java.util.Set;
023
024import org.apache.commons.lang3.ArrayUtils;
025import org.apache.commons.lang3.Validate;
026import org.apache.commons.lang3.builder.Builder;
027import org.apache.commons.proxy2.Invoker;
028import org.apache.commons.proxy2.ObjectProvider;
029import org.apache.commons.proxy2.ProxyFactory;
030import org.apache.commons.proxy2.interceptor.SwitchInterceptor;
031import org.apache.commons.proxy2.invoker.NullInvoker;
032import org.apache.commons.proxy2.provider.ConstantProvider;
033
034public class StubBuilder<T> implements Builder<T>
035{
036    //******************************************************************************************************************
037    // Fields
038    //******************************************************************************************************************
039
040    private final ProxyFactory proxyFactory;
041    private final T target;
042    private final SwitchInterceptor switchInterceptor = new SwitchInterceptor();
043    private final Set<Class<?>> proxyTypes = new HashSet<Class<?>>();
044
045    //******************************************************************************************************************
046    // Constructors
047    //******************************************************************************************************************
048
049    public StubBuilder(ProxyFactory proxyFactory, Class<T> type)
050    {
051        this(proxyFactory, type, NullInvoker.INSTANCE);
052    }
053
054    public StubBuilder(ProxyFactory proxyFactory, Class<T> type, Invoker invoker)
055    {
056        this.proxyFactory = proxyFactory;
057        this.target = proxyFactory.createInvokerProxy(invoker, type);
058        this.proxyTypes.add(Validate.notNull(type));
059    }
060
061    public StubBuilder(ProxyFactory proxyFactory, Class<T> type, ObjectProvider<? extends T> provider)
062    {
063        this.proxyFactory = proxyFactory;
064        this.target = proxyFactory.createDelegatorProxy(provider, type);
065        this.proxyTypes.add(Validate.notNull(type));
066    }
067
068    public StubBuilder(ProxyFactory proxyFactory, Class<T> type, T target)
069    {
070        this.proxyFactory = proxyFactory;
071        this.target = proxyFactory.createDelegatorProxy(new ConstantProvider<T>(target), type);
072        this.proxyTypes.add(Validate.notNull(type));
073    }
074
075    //******************************************************************************************************************
076    // Other Methods
077    //******************************************************************************************************************
078
079    @Override
080    public T build()
081    {
082        return proxyFactory.createInterceptorProxy(target, switchInterceptor,
083                proxyTypes.toArray(ArrayUtils.EMPTY_CLASS_ARRAY));
084    }
085
086    public <O> StubBuilder<T> train(BaseTrainer<?, O> trainer)
087    {
088        final TrainingContext trainingContext = TrainingContext.join(proxyFactory);
089        try
090        {
091            final O trainee = trainingContext.push(trainer.traineeType, switchInterceptor);
092            trainer.train(trainee);
093            proxyTypes.add(trainer.traineeType);
094        }
095        finally
096        {
097            trainingContext.part();
098        }
099        return this;
100    }
101
102    public StubBuilder<T> addProxyTypes(Class<?>... proxyTypes)
103    {
104        Collections.addAll(this.proxyTypes, Validate.noNullElements(proxyTypes));
105        return this;
106    }
107}