/*
 * $Id: ObjectUtil.java,v 1.3 2005/04/11 16:33:29 sugimotokenichi Exp $
 * Copyright (C) 2005 SUGIMOTO Ken-ichi
 * 作成日: 2005/03/23
 */
package feat.v1;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.List;
import java.util.Map;

import org.apache.commons.beanutils.ConvertUtils;
import org.apache.commons.beanutils.PropertyUtils;
import org.apache.commons.collections.BeanMap;

/**
 * オブジェクトの操作のためのユーティリティクラス。
 * @author SUGIMOTO Ken-ichi
 */
public class ObjectUtil {

    /**
     * クラスをロードする。
     * nameで指定された名前を完全修飾名としてロードを試みて、見つからなければnameの前に
     * パッケージ名を付けてロードを試みる。
     * デフォルトパッケージに同名のクラスがあるとそちらが優先されてしまうため、デフォルトパッケージには
     * クラスを含めないほうが良い。
     * ロードには、このクラスをロードしたクラスローダが使われる。
     * @param name String
     * @param pkg String
     * @throws ClassNotFoundException
     * @return Class
     */
    public static Class loadClass(String name, String pkg) throws
            ClassNotFoundException {
        // 引数のチェック
        if ( pkg == null )
            pkg = "";
        if ( name == null )
            throw new ClassNotFoundException("クラス名がnull");

        ClassLoader loader = ObjectUtil.class.getClassLoader();//Thread.currentThread().getContextClassLoader();
        Class ret = null;
        try {
            ret = loader.loadClass(name);
        }
        catch (ClassNotFoundException ex) {
            // 見つからなかったらパッケージ名を付けて探してみる
            name = pkg + "." + name;
            ret = loader.loadClass(name);
        }

        return ret;
    }

    /**
     * 文字列の配列を適切な型に変換してコンストラクタを呼び出す。
     * @param clazz Class
     * @param args String[]
     * @return Object
     */
    public static Object newInstance(Class clazz, String[] args) throws
            NoSuchMethodException, InvocationTargetException,
            IllegalArgumentException, IllegalAccessException,
            InstantiationException {
        if ( clazz == null || args == null )
            throw new IllegalArgumentException("引数がnull");

        // コンストラクタを探す
        // 引数の数がargsと同じものを探す
        Constructor[] constructors = clazz.getConstructors();
        Constructor cons = null;
        for(int i=0; i<constructors.length; i++) {
            if ( constructors[i].getParameterTypes().length == args.length )
                cons = constructors[i];
        }

        if ( cons != null ) {
            // 渡された文字列をコンストラクタの型に変換
            Class[] types = cons.getParameterTypes();
            Object[] params = new Object[args.length];
            for(int i=0; i<args.length; i++) {
                params[i] = ConvertUtils.convert(args[i], types[i]);
            }
            return cons.newInstance(params);
        }
        throw new NoSuchMethodException(clazz.getName()+"には引数が"+args.length+"個のコンストラクタは定義されていない");
    }

    /**
     * オブジェクトのプロパティの値を取得する。
     * @param bean Object
     * @param name プロパティ名。ネストした名前やインデックス、マップも指定できる。
     * @return Object
     */
    public static Object getProperty(Object bean, String name) throws
            NoSuchMethodException, InvocationTargetException,
            IllegalAccessException {
        return PropertyUtils.getProperty(bean, name);
    }

    public static void setProperty(Object bean, String name, Object value)
    		throws IllegalAccessException, InvocationTargetException, NoSuchMethodException {

        PropertyUtils.setProperty(bean, name, value);
    }

    /**
     * リストのすべてのオブジェクトのnameプロパティにvalueをセットする。
     * @param list
     * @param name
     * @param value
     * @throws NoSuchMethodException
     * @throws InvocationTargetException
     * @throws IllegalAccessException
     */
    public static void setProperty(List list, String name, Object value)
    		throws IllegalAccessException, InvocationTargetException, NoSuchMethodException {

        for(int i=0; i<list.size(); i++) {
            setProperty(list.get(i), name, value);
        }
    }

    /**
     * オブジェクトをMapインタフェースでラップしたオブジェクトを返す。
     * @param bean
     * @return
     */
    public static Map getBeanMap(Object bean) {
        return new BeanMap(bean);
    }

}
