/*
 * The Gemma project
 * 
 * Copyright (c) 2006 University of British Columbia
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */
package ubic.gemma.util;

import java.beans.PropertyDescriptor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

import org.apache.commons.beanutils.PropertyUtils;

/**
 * Class to help complete beans based on other beans
 * 
 * @author pavlidis
 * @version $Id$
 */
public class BeanPropertyCompleter {

    /**
     * Given a source Object and a source one of the same type, fill in any missing attributes of the target object with
     * ones from the source object. Any non-null values in the target are NOT overwritten by corresponding values in the
     * source.
     * 
     * @param targetObject
     * @param sourceObject
     */
    public static void complete( Object targetObject, Object sourceObject ) {
        complete( targetObject, sourceObject, false );
    }

    /**
     * Given a source Object and a source one of the same type, fill in any missing attributes of the target object with
     * ones from the source object. If update is true, then any non-null values in the target object will be clobbered
     * with the non-null values from the source object.
     * <p>
     * Associated objects which are in collections or maps are not updated individually. All associations are either
     * assigned to or left alone. Thus collections will be replaced if "update" is selected, but if not, the collection
     * will not be changed, even if the sourceObject contains new members in the collection.
     * 
     * @param targetObject
     * @param sourceObject
     * @param update
     */
    public static void complete( Object targetObject, Object sourceObject, boolean update ) {
        if ( targetObject == null || sourceObject == null )
            throw new IllegalArgumentException( "Args must be non-null" );

        if ( targetObject.getClass() != sourceObject.getClass() )
            throw new IllegalArgumentException( "Args must be of the same type" );

        PropertyDescriptor[] props = PropertyUtils.getPropertyDescriptors( targetObject );
        for ( int i = 0; i < props.length; i++ ) {
            PropertyDescriptor descriptor = props[i];
            Method setter = descriptor.getWriteMethod();
            if ( setter == null ) continue;
            Method getter = descriptor.getReadMethod();

            try {
                Object sourceValue = getter.invoke( sourceObject, new Object[] {} );
                if ( sourceValue == null ) continue;

                Object persistedValue = getter.invoke( targetObject, new Object[] {} );

                if ( persistedValue == null || update ) {
                    setter.invoke( targetObject, new Object[] { sourceValue } );
                }

            } catch ( IllegalArgumentException e ) {
                throw new RuntimeException( e );
            } catch ( IllegalAccessException e ) {
                throw new RuntimeException( e );
            } catch ( InvocationTargetException e ) {
                throw new RuntimeException( e );
            }

        }

    }
}

@@ -2288,32 +2288,62 @@
 date ) %7B%0A       
+ return;%0A        /*%0A         *
  if ( targetObje
@@ -2378,28 +2378,16 @@
 = null )
-%0A           
  throw n
@@ -2428,16 +2428,27 @@
  must be
+%0A         *
  non-nul
@@ -2452,25 +2452,16 @@
 null%22 );
-%0A%0A       
  if ( ta
@@ -2510,28 +2510,16 @@
 lass() )
-%0A           
  throw n
@@ -2538,32 +2538,43 @@
 gumentException(
+%0A         *
  %22Args must be o
@@ -2592,25 +2592,16 @@
 type%22 );
-%0A%0A       
  Propert
@@ -2659,16 +2659,27 @@
 riptors(
+%0A         *
  targetO
@@ -2686,24 +2686,16 @@
 bject );
-%0A       
  for ( i
@@ -2729,28 +2729,16 @@
  i++ ) %7B
-%0A           
  Propert
@@ -2771,16 +2771,23 @@
 rops%5Bi%5D;
+ Method
 %0A       
@@ -2788,25 +2788,17 @@
         
-   Method
+*
  setter 
@@ -2827,28 +2827,16 @@
 ethod();
-%0A           
  if ( se
@@ -2859,28 +2859,16 @@
 ontinue;
-%0A           
  Method 
@@ -2871,24 +2871,35 @@
 hod getter =
+%0A         *
  descriptor.
@@ -2918,43 +2918,14 @@
 d();
-%0A%0A            try %7B%0A               
+ try %7B
  Obj
@@ -2985,24 +2985,29 @@
 ject%5B%5D %7B%7D );
+ if (
 %0A           
@@ -3004,27 +3004,17 @@
         
-       if (
+*
  sourceV
@@ -3037,33 +3037,16 @@
 ontinue;
-%0A%0A               
  Object 
@@ -3109,17 +3109,21 @@
 %5B%5D %7B%7D );
-%0A
+ if (
 %0A       
@@ -3128,19 +3128,9 @@
     
-       if (
+*
  per
@@ -3166,28 +3166,8 @@
  ) %7B
-%0A                   
  set
@@ -3227,49 +3227,31 @@
 %7D );
-%0A                %7D%0A%0A            %7D catch (
+ %7D %7D catch (%0A         *
  Ill
@@ -3277,32 +3277,16 @@
 on e ) %7B
-%0A               
  throw n
@@ -3306,36 +3306,24 @@
 eption( e );
-%0A           
  %7D catch ( I
@@ -3341,32 +3341,38 @@
 sException e ) %7B
+ throw
 %0A               
@@ -3361,36 +3361,25 @@
 ow%0A         
-       throw
+*
  new Runtime
@@ -3393,28 +3393,16 @@
 on( e );
-%0A           
  %7D catch
@@ -3439,24 +3439,8 @@
  ) %7B
-%0A               
  thr
@@ -3472,32 +3472,22 @@
 e );
-%0A          
  
+%7D
  %7D%0A
-%0A
+ 
         
 %7D%0A%0A 
@@ -3478,23 +3478,23 @@
  %7D%0A         
-%7D%0A
+*/
 %0A    %7D%0A%7D%0A

disable this by commenting it out. call to complete will be removed entirely later