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    
018    package org.apache.commons.proxy.provider;
019    
020    import org.apache.commons.proxy.ObjectProvider;
021    import org.apache.commons.proxy.ProxyUtils;
022    import org.apache.commons.proxy.exception.ObjectProviderException;
023    
024    import java.io.Serializable;
025    import java.lang.reflect.InvocationTargetException;
026    import java.lang.reflect.Method;
027    
028    /**
029     * Merely calls <code>clone()</code> (reflectively) on the given {@link Cloneable} object.
030     *
031     * @author James Carman
032     * @since 1.0
033     */
034    public class CloningProvider implements ObjectProvider, Serializable
035    {
036    //**********************************************************************************************************************
037    // Fields
038    //**********************************************************************************************************************
039    
040        private final Cloneable cloneable;
041        private Method cloneMethod;
042    
043    //**********************************************************************************************************************
044    // Constructors
045    //**********************************************************************************************************************
046    
047        /**
048         * Constructs a provider which returns clone copies of the specified {@link Cloneable}
049         * object.
050         *
051         * @param cloneable the object to clone
052         */
053        public CloningProvider( Cloneable cloneable )
054        {
055            this.cloneable = cloneable;
056        }
057    
058    //**********************************************************************************************************************
059    // ObjectProvider Implementation
060    //**********************************************************************************************************************
061    
062    
063        public Object getObject()
064        {
065            try
066            {
067                return getCloneMethod().invoke(cloneable, ProxyUtils.EMPTY_ARGUMENTS);
068            }
069            catch( IllegalAccessException e )
070            {
071                throw new ObjectProviderException(
072                        "Class " + cloneable.getClass().getName() + " does not have a public clone() method.", e);
073            }
074            catch( InvocationTargetException e )
075            {
076                throw new ObjectProviderException(
077                        "Attempt to clone object of type " + cloneable.getClass().getName() + " threw an exception.", e);
078            }
079        }
080    
081    //**********************************************************************************************************************
082    // Getter/Setter Methods
083    //**********************************************************************************************************************
084    
085        private synchronized Method getCloneMethod()
086        {
087            if( cloneMethod == null )
088            {
089                try
090                {
091                    cloneMethod = cloneable.getClass().getMethod("clone", ProxyUtils.EMPTY_ARGUMENT_TYPES);
092                }
093                catch( NoSuchMethodException e )
094                {
095                    throw new ObjectProviderException(
096                            "Class " + cloneable.getClass().getName() + " does not have a public clone() method.");
097                }
098            }
099            return cloneMethod;
100        }
101    }