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