/*
 * This software is distributed under following license based on modified BSD
 * style license.
 * ----------------------------------------------------------------------
 * 
 * Copyright 2009 The Nimbus2 Project. All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 * 
 * 1. Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer. 
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE NIMBUS PROJECT ``AS IS'' AND ANY EXPRESS
 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
 * NO EVENT SHALL THE NIMBUS PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 * 
 * The views and conclusions contained in the software and documentation are
 * those of the authors and should not be interpreted as representing official
 * policies, either expressed or implied, of the Nimbus2 Project.
 */
package jp.ossc.nimbus.core;

import java.util.*;
import java.lang.reflect.*;
import java.beans.*;
import java.io.*;

import jp.ossc.nimbus.beans.*;
import jp.ossc.nimbus.service.log.Logger;
import jp.ossc.nimbus.service.message.MessageRecordFactory;
import jp.ossc.nimbus.service.repository.*;

/**
 * デフォルトサービスマネージャサービス。<p>
 * サービスを管理する{@link ServiceManager}のデフォルト実装です。<br>
 *
 * @author M.Takata
 */
public class DefaultServiceManagerService extends ServiceBase
 implements ServiceManager, RegistrationListenable,
            DefaultServiceManagerServiceMBean{
    
    private static final long serialVersionUID = 4663655905756505766L;
    
    // メッセージID定義
    private static final String SVCM_ = "SVCM_";
    private static final String SVCM_0 = SVCM_ + 0;
    private static final String SVCM_00 = SVCM_0 + 0;
    private static final String SVCM_000 = SVCM_00 + 0;
    private static final String SVCM_0000 = SVCM_000 + 0;
    private static final String SVCM_00001 = SVCM_0000 + 1;
    private static final String SVCM_00002 = SVCM_0000 + 2;
    private static final String SVCM_00003 = SVCM_0000 + 3;
    private static final String SVCM_00004 = SVCM_0000 + 4;
    private static final String SVCM_00005 = SVCM_0000 + 5;
    private static final String SVCM_00006 = SVCM_0000 + 6;
    private static final String SVCM_00007 = SVCM_0000 + 7;
    private static final String SVCM_00008 = SVCM_0000 + 8;
    private static final String SVCM_00009 = SVCM_0000 + 9;
    private static final String SVCM_00010 = SVCM_000 + 10;
    private static final String SVCM_00011 = SVCM_000 + 11;
    private static final String SVCM_00012 = SVCM_000 + 12;
    private static final String SVCM_00013 = SVCM_000 + 13;
    private static final String SVCM_00014 = SVCM_000 + 14;
    private static final String SVCM_00015 = SVCM_000 + 15;
    private static final String SVCM_00016 = SVCM_000 + 16;
    private static final String SVCM_00017 = SVCM_000 + 17;
    private static final String SVCM_00018 = SVCM_000 + 18;
    private static final String SVCM_00019 = SVCM_000 + 19;
    private static final String SVCM_00020 = SVCM_000 + 20;
    private static final String SVCM_00021 = SVCM_000 + 21;
    private static final String SVCM_00022 = SVCM_000 + 22;
    private static final String SVCM_00023 = SVCM_000 + 23;
    private static final String SVCM_00024 = SVCM_000 + 24;
    private static final String SVCM_00025 = SVCM_000 + 25;
    private static final String SVCM_00026 = SVCM_000 + 26;
    private static final String SVCM_00027 = SVCM_000 + 27;
    private static final String SVCM_00028 = SVCM_000 + 28;
    private static final String SVCM_00029 = SVCM_000 + 29;
    private static final String SVCM_00030 = SVCM_000 + 30;
    private static final String SVCM_00031 = SVCM_000 + 31;
    private static final String SVCM_00032 = SVCM_000 + 32;
    private static final String SVCM_00033 = SVCM_000 + 33;
    private static final String SVCM_00034 = SVCM_000 + 34;
    private static final String SVCM_00035 = SVCM_000 + 35;
    private static final String SVCM_00036 = SVCM_000 + 36;
    private static final String SVCM_00037 = SVCM_000 + 37;
    private static final String SVCM_00038 = SVCM_000 + 38;
    private static final String SVCM_00039 = SVCM_000 + 39;
    private static final String SVCM_00040 = SVCM_000 + 40;
    private static final String SVCM_00041 = SVCM_000 + 41;
    private static final String SVCM_00042 = SVCM_000 + 42;
    private static final String SVCM_00043 = SVCM_000 + 43;
    private static final String SVCM_00044 = SVCM_000 + 44;
    private static final String SVCM_00045 = SVCM_000 + 45;
    private static final String SVCM_00046 = SVCM_000 + 46;
    private static final String SVCM_00047 = SVCM_000 + 47;
    private static final String SVCM_00048 = SVCM_000 + 48;
    
    /**
     * マネージャメタデータ集合。<p>
     */
    private Set<ManagerMetaData> managerMetaDataSet = Collections.<ManagerMetaData>synchronizedSet(new HashSet<ManagerMetaData>());
    
    /**
     * サービスメタデータマップ。<p>
     */
    private Map<String, ServiceMetaData> serviceMetaDataMap = Collections.<String, ServiceMetaData>synchronizedMap(new HashMap<String, ServiceMetaData>());
    
    /**
     * マネージャプロパティ。<p>
     */
    private final Properties managerProperties = new Properties();
    
    /**
     * デプロイ待機中のサービスのマップ。<p>
     * <table border="1">
     *   <tr bgcolor="#CCCCFF"><th colspan="2">キー</th><th colspan="3">値</th></tr>
     *   <tr bgcolor="#CCCCFF"><th>型</th><th>内容</th><th>型</th><th colspan="2">内容</th></tr>
     *   <tr rowspan="3"><td rowspan="3">String</td><td rowspan="3">デプロイ待機中のサービス名</td><td rowspan="3">java.util.Set</td><td colspan="2">デプロイ待機中のサービスが、待っているサービスの集合</td></tr>
     *   <tr bgcolor="#CCCCFF"><th>型</th><th>内容</th></tr>
     *   <tr><td>ServiceName</td><td>サービス名</td></tr>
     * </table>
     */
    private final Map<String, Set<ServiceName>> waitingServices = Collections.<String, Set<ServiceName>>synchronizedMap(new HashMap<String, Set<ServiceName>>());
    
    /**
     * デプロイに失敗したサービスのマップ。<p>
     * <table border="1">
     *   <tr bgcolor="#CCCCFF"><th colspan="2">キー</th><th colspan="2">値</th></tr>
     *   <tr bgcolor="#CCCCFF"><th>型</th><th>内容</th><th>型</th><th>内容</th></tr>
     *   <tr><td>String</td><td>デプロイに失敗したサービス名</td><td>Throwable</td><td colspan="2">デプロイに失敗した原因</td></tr>
     * </table>
     */
    private final Map<String, Throwable> failedServices = Collections.<String, Throwable>synchronizedMap(new HashMap<String, Throwable>());
    
    /**
     * ここで管理されているサービスを登録する{@link Repository}
     */
    private Repository repository = new DefaultRepository();
    
    /**
     * サービスの登録先{@link Repository}のデフォルト実装クラス。<p>
     *
     * @author M.Takata
     */
    private class DefaultRepository implements Repository, Serializable{
        
        private static final long serialVersionUID = 1719730608499127551L;
        
        private final Map<String, Object> serviceMap = Collections.synchronizedMap(new HashMap<String, Object>());
        
        @SuppressWarnings("unchecked")
        @Override
        public <T> T get(String name){
            return (T)serviceMap.get(name);
        }
        
        @Override
        public boolean register(String name, Object service){
            if(serviceMap.containsKey(name)){
                return false;
            }
            synchronized(serviceMap){
                serviceMap.put(name, service);
            }
            return true;
        }
        
        @Override
        public boolean unregister(String name){
            synchronized(serviceMap){
                serviceMap.remove(name);
            }
            return true;
        }
        
        @Override
        public boolean isRegistered(String name){
            return serviceMap.containsKey(name);
        }
        
        @Override
        public Set<String> nameSet(){
            return new HashSet<String>(serviceMap.keySet());
        }
        
        @SuppressWarnings("unchecked")
        @Override
        public <T> Set<T> registeredSet(){
            return new HashSet<T>((Collection<T>)serviceMap.values());
        }
    };
    
    /**
     * このServiceManagerに登録された登録状態リスナのリスト。<p>
     */
    private List<RegistrationListener> registrationListeners = Collections.<RegistrationListener>synchronizedList(new ArrayList<RegistrationListener>());
    
    private Map<AttributeMetaData, Property> attributePropCache = Collections.<AttributeMetaData, Property>synchronizedMap(new HashMap<AttributeMetaData, Property>());
    
    // ServiceManagerのJavaDoc
    @Override
    public void deploy(ManagerMetaData metaData) throws DeploymentException{
        
        managerMetaDataSet.add(metaData);
        
        // ServiceManagerのLoggerの設定
        final ServiceNameMetaData logData = metaData.getLog();
        if(logData != null){
            final String managerName = logData.getManagerName();
            final String logName = logData.getServiceName();
            if(managerName != null && logName != null){
                setSystemLoggerServiceName(new ServiceName(managerName, logName));
            }
        }
        
        // ServiceManagerのMessageRecordFactoryの設定
        final ServiceNameMetaData messageData = metaData.getMessage();
        if(messageData != null){
            final String managerName = messageData.getManagerName();
            final String messageName = messageData.getServiceName();
            if(managerName != null && messageName != null){
                setSystemMessageRecordFactoryServiceName(
                    new ServiceName(managerName, messageName)
                );
            }
        }
        
        // ServiceManagerのRepositoryの設定
        final ServiceNameMetaData repositoryData = metaData.getRepository();
        if(repositoryData != null){
            final String managerName = repositoryData.getManagerName();
            final String repositoryName = repositoryData.getServiceName();
            if(managerName != null && repositoryName != null){
                setServiceRepository(managerName, repositoryName);
            }
        }
        
        final Map<String, ServiceMetaData> serviceDataMap = metaData.getServices();
        for(ServiceMetaData serviceData : serviceDataMap.values()){
            deploy(serviceData);
        }
    }
    
    // ServiceManagerのJavaDoc
    @Override
    public void undeploy(ManagerMetaData metaData){
        final Map<String, ServiceMetaData> serviceDataMap = metaData.getServices();
        for(ServiceMetaData serviceData : serviceDataMap.values()){
            undeploy(serviceData);
        }
        managerMetaDataSet.remove(metaData);
    }
    
    // ServiceManagerのJavaDoc
    @Override
    public void deploy(ServiceMetaData metaData) throws DeploymentException{
        String serviceName = metaData.getName();
        if(isRegisteredService(serviceName) || serviceMetaDataMap.containsKey(serviceName)){
            final Logger logger = getLogger();
            logger.write(SVCM_00048, metaData.getName(), serviceName);
            return;
        }
        if(metaData.isTemplate()){
            serviceMetaDataMap.put(serviceName, metaData);
        }else{
            try{
                metaData = metaData.applyTemplate(this);
                registerService(metaData);
            }catch(DeploymentException e){
                throw e;
            }catch(Throwable e){
                throw new DeploymentException(e);
            }
        }
    }
    
    // ServiceManagerのJavaDoc
    @Override
    public void undeploy(ServiceMetaData metaData){
        unregisterService(metaData.getName());
    }
    
    // ServiceManagerのJavaDoc
    @Override
    public Set<ManagerMetaData> getManagerMetaDataSet(){
        return managerMetaDataSet;
    }
    
    // ServiceManagerのJavaDoc
    @Override
    public ServiceMetaData getServiceMetaData(String name){
        return serviceMetaDataMap.get(name);
    }
    
    // ServiceManagerのJavaDoc
    @Override
    public List<ServiceMetaData.DependsMetaData> getDepends(String serviceName){
        ServiceMetaData serviceData = serviceMetaDataMap.get(serviceName);
        return serviceData == null ? null : serviceData.getDepends();
    }
    
    // ServiceManagerのJavaDoc
    @Override
    public List<ServiceMetaData> getDependedServices(
        String managerName,
        String serviceName
    ){
        final List<ServiceMetaData> result = new ArrayList<ServiceMetaData>();
        for(Map.Entry<String, ServiceMetaData> entry : serviceMetaDataMap.entrySet()){
            final String name = entry.getKey();
            if(name.equals(serviceName)
                && getServiceName().equals(managerName)){
                continue;
            }
            for(ServiceMetaData.DependsMetaData dependsData : entry.getValue().getDepends()){
                if(dependsData.getServiceName().equals(serviceName)
                    && dependsData.getManagerName().equals(managerName)){
                    result.add(entry.getValue());
                    break;
                }
            }
        }
        return result;
    }
    
    // ServiceManagerのJavaDoc
    @Override
    public Service getService(String name) throws ServiceNotFoundException{
        final Object obj = repository.get(name);
        if(obj == null){
            throw new ServiceNotFoundException(getServiceName(), name);
        }
        Service service = null;
        if(obj instanceof Service){
            service = (Service)obj;
        }else{
            service = convertObjectToService(name, obj);
        }
        return service;
    }
    
    // ServiceManagerのJavaDoc
    @SuppressWarnings("unchecked")
    @Override
    public Object getServiceObject(String name) throws ServiceNotFoundException{
        Object target = convertServiceToObject(getService(name));
        if(target != null && target instanceof FactoryService){
            target = ((FactoryService<Object>)target).newInstance();
            if(target instanceof Service){
                target = convertServiceToObject((Service)target);
            }
        }
        return target;
    }
    
    // ServiceManagerのJavaDoc
    @Override
    public ServiceStateListenable getServiceStateListenable(String name)
     throws ServiceNotFoundException{
        final Service obj = repository.get(name);
        if(obj == null){
            throw new ServiceNotFoundException(getServiceName(), name);
        }
        ServiceStateListenable broadcaster = null;
        if(obj instanceof ServiceStateListenable){
            broadcaster = (ServiceStateListenable)obj;
        }
        return broadcaster;
    }
    
    // ServiceManagerのJavaDoc
    @Override
    public boolean registerService(String name, Object obj) throws Exception{
        return registerService(name, convertObjectToService(name, obj));
    }
    
    // ServiceManagerのJavaDoc
    @Override
    public boolean registerService(String name, Service service) throws Exception{
        final Logger logger = getLogger();
        
        logger.write(SVCM_00001, name, service);
        
        final boolean result = repository.register(name, service); 
        if(result){
            service.setServiceManagerName(getServiceName());
            service.setServiceName(name);
            processRegisterd(service);
            logger.write(SVCM_00002, getServiceName(), name);
            if(getState() == State.STARTED){
                createService(name);
            }
        }else{
            logger.write(SVCM_00003, getServiceName(), name);
        }
        return result;
    }
    
    // ServiceManagerのJavaDoc
    @Override
    public boolean registerService(ServiceMetaData serviceData)
     throws Exception{
        serviceMetaDataMap.put(serviceData.getName(), serviceData);
        serviceData.setManagerName(getServiceName());
        Service service = instanciateService(serviceData);
        return registerService(serviceData.getName(), service);
    }
    
    // ServiceManagerのJavaDoc
    @Override
    public boolean unregisterService(String name){
        final Logger logger = getLogger();
        
        logger.write(SVCM_00004, name);
        
        Service service = null;
        try{
            service = getService(name);
        }catch(ServiceNotFoundException e){
            return true;
        }
        final boolean result = repository.unregister(name); 
        if(result){
            processUnregisterd(service);
            logger.write(SVCM_00005, getServiceName(), name);
        }else{
            logger.write(SVCM_00006, getServiceName(), name);
        }
        serviceMetaDataMap.remove(name);
        return result;
    }
    
    // ServiceManagerのJavaDoc
    @Override
    public boolean isRegisteredService(String name){
        return repository.isRegistered(name); 
    }
    
    // ServiceManagerのJavaDoc
    @Override
    public Set<String> serviceNameSet(){
        return repository.nameSet();
    }
    
    // ServiceManagerのJavaDoc
    @Override
    public Set<Service> serviceSet(){
        return repository.registeredSet();
    }
    
    // ServiceManagerのJavaDoc
    @Override
    public Set<Object> serviceObjectSet(){
        final Set<Object> result = new HashSet<Object>();
        for(String serviceName : serviceNameSet()){
            Object obj = null;
            try{
                obj = getServiceObject(serviceName);
            }catch(ServiceNotFoundException e){
                continue;
            }
            result.add(obj);
        }
        return result;
    }
    
    // ServiceManagerのJavaDoc
    @Override
    public boolean setServiceRepository(
        final String manager,
        final String service
    ){
        if(ServiceManagerFactory.isRegisteredService(manager, service)
             && ServiceManagerFactory.getService(manager, service).getState()
                 == State.STARTED
        ){
            return setServiceRepository(
                ServiceManagerFactory.getService(manager, service)
            );
        }else{
            ServiceManagerFactory.addServiceStateListener(
                manager,
                service,
                new SetServiceRepositoryServiceStateListener(
                    getServiceName(),
                    manager,
                    service,
                    null
                )
            );
            return false;
        }
    }
    
    /**
     * サービスを登録する{@link Repository}サービスを設定する。<p>
     *
     * @param repositoryService Repositoryサービス
     * @return Repositoryサービスの設定に成功した場合true
     */
    private boolean setServiceRepository(Service repositoryService){
        Repository newRep = null;
        final String managerName = repositoryService.getServiceManagerName();
        final String serviceName = repositoryService.getServiceName();
        try{
            newRep = ServiceManagerFactory.getServiceObject(
                managerName,
                serviceName
            );
        }catch(ServiceNotFoundException e){
            return false;
        }
        final boolean isReplaced = setServiceRepository(newRep);
        if(isReplaced){
            ServiceManagerFactory.addServiceStateListener(
                managerName,
                serviceName,
                new SetServiceRepositoryServiceStateListener(
                    getServiceName(),
                    managerName,
                    serviceName,
                    new DefaultRepository()
                )
            );
        }
        return isReplaced;
    }
    
    private static class SetServiceRepositoryServiceStateListener
     implements ServiceStateListener, Serializable{
        private static final long serialVersionUID = 2107809742131214956L;
        private String targetManagerName;
        private String manager;
        private String service;
        private Repository defaultRep;
        public SetServiceRepositoryServiceStateListener(
            String targetManagerName,
            String manager,
            String service,
            Repository defaultRep
        ){
            this.targetManagerName = targetManagerName;
            this.manager = manager;
            this.service = service;
            this.defaultRep = defaultRep;
        }
        @Override
        public void stateChanged(ServiceStateChangeEvent e)
         throws Exception{
            ServiceManager mng = ServiceManagerFactory.findManager(targetManagerName);
            if(mng == null){
                switch(e.getService().getState()){
                case STARTED:
                    if(defaultRep == null){
                        ServiceManagerFactory
                            .removeServiceStateListener(manager, service, SetServiceRepositoryServiceStateListener.this);
                    }
                    ServiceManagerFactory.addServiceStateListener(
                        targetManagerName,
                        targetManagerName,
                        this
                    );
                    break;
                case STOPPED:
                default:
                }
            }else{
                switch(e.getService().getState()){
                case STARTED:
                    if(defaultRep == null){
                        ServiceManagerFactory
                            .removeServiceStateListener(manager, service, SetServiceRepositoryServiceStateListener.this);
                    }
                    mng.setServiceRepository(manager, service);
                    break;
                case STOPPED:
                    if(defaultRep != null){
                        mng.setServiceRepository(defaultRep);
                    }
                    break;
                default:
                }
            }
        }
        @Override
        public boolean isEnabledState(State st){
            if(defaultRep == null){
                return st == State.STARTED;
            }else{
                return st == State.STARTED || st == State.STOPPED;
            }
        }
        @Override
        public int hashCode(){
            return (targetManagerName == null ? 0 : targetManagerName.hashCode())
                + (manager == null ? 0 : manager.hashCode())
                + (service == null ? 0 : service.hashCode())
                + (defaultRep == null ? 0 : 1);
        }
        @Override
        public boolean equals(Object obj){
            if(obj == null
                || !(obj instanceof SetServiceRepositoryServiceStateListener)){
                return false;
            }
            SetServiceRepositoryServiceStateListener comp
                = (SetServiceRepositoryServiceStateListener)obj;
            if((targetManagerName != null || comp.targetManagerName != null)
                && (targetManagerName == null || comp.targetManagerName == null
                    || !targetManagerName.equals(comp.targetManagerName))){
                return false;
            }
            if((manager != null || comp.manager != null)
                && (manager == null || comp.manager == null
                    || !manager.equals(comp.manager))){
                return false;
            }
            if((service != null || comp.service != null)
                && (service == null || comp.service == null
                    || !service.equals(comp.service))){
                return false;
            }
            if(!(defaultRep == null && comp.defaultRep == null)
                || !(defaultRep != null && comp.defaultRep != null)){
                return false;
            }
            return true;
        }
    }
    
    // ServiceManagerのJavaDoc
    @Override
    public boolean setServiceRepository(Repository newRep){
        final Logger logger = getLogger();
        synchronized(repository){
            if(newRep == null || repository.equals(newRep)){
                return false;
            }
            boolean success = true;
            final Set<String> registered = new HashSet<String>();
            for(String name : repository.nameSet()){
                final Service service = repository.get(name);
                if(service != null){
                    if(!newRep.register(name, service)){
                        success = false;
                    }else{
                        registered.add(name);
                    }
                }
            }
            if(!success){
                for(String name : registered){
                    newRep.unregister(name);
                }
                logger.write(SVCM_00007, newRep);
                return false;
            }
            for(String name : newRep.nameSet()){
                repository.unregister(name);
            }
            repository = newRep;
            logger.write(SVCM_00008, newRep);
        }
        return true;
    }
    
    /**
     * {@link Service}インタフェースを実装するオブジェクトを各サービスを提供するサービスオブジェクトに変換する。<p>
     *
     * @param service {@link Service}インタフェースを実装するオブジェクト
     * @return 各サービスを提供するサービスオブジェクト
     */
    private Object convertServiceToObject(Service service){
        Object target = service;
        while(target instanceof ServiceProxy){
            Object child = ((ServiceProxy)target).getTarget();
            if(child == target){
                break;
            }
            target = child;
        }
        return target;
    }
    
    // ServiceManagerのJavaDoc
    public Service convertObjectToService(String name, Object obj){
        if(obj == null){
            return null;
        }
        Service service = null;
        if(obj instanceof Service){
            service = (Service)obj;
        }else if(obj instanceof ServiceBaseSupport){
            final ServiceBaseSupport support = (ServiceBaseSupport)obj;
            try{
                service = ServiceProxyFactory.createServiceBaseProxy(support);
            }catch(Exception e){
                return null;
            }
        }else{
            try{
                service = ServiceProxyFactory.createServiceBaseProxy(obj);
            }catch(Exception e){
                return null;
            }
        }
        service.setServiceManagerName(getServiceName());
        service.setServiceName(name);
        return service;
    }
    
    // ServiceManagerのJavaDoc
    @Override
    public String getProperty(String name){
        return managerProperties.getProperty(name);
    }
    
    // ServiceManagerのJavaDoc
    @Override
    public void setProperty(String name, String value){
        managerProperties.setProperty(name, value);
    }
    
    /**
     * サービスを生成する必要があるか調べる。<p>
     * 必ずtrueを返す。<br>
     *
     * @return サービスを生成する必要がある場合true、そうでない場合false
     */
    @Override
    protected boolean isNecessaryToCreate(){
        return true;
    }
    
    /**
     * このサービスの生成前処理を行う。<p>
     *
     * @exception Exception 生成前処理に失敗した場合
     */
    @Override
    protected void preCreateService() throws Exception{
        final Logger logger = getLogger();
        
        state = State.CREATING;
        processStateChanged(State.CREATING);
        
        if(getServiceName() != null){
            if(isRegisteredService(getServiceName())){
                final Service registeredService = getService(getServiceName());
                if(registeredService != this){
                    logger.write(
                        SVCM_00013,
                        getServiceName(), getServiceName()
                    );
                    stopService(getServiceName());
                    destroyService(getServiceName());
                    if(isRegisteredService(getServiceName())){
                        unregisterService(getServiceName());
                    }
                    registerService(getServiceName(), this);
                }
            }else{
                registerService(getServiceName(), this);
            }
            
            if(ServiceManagerFactory.isRegisteredManager(getServiceName())){
                final ServiceManager registeredManager
                     = ServiceManagerFactory.findManager(getServiceName());
                if(registeredManager != this){
                    logger.write(SVCM_00014, getServiceName());
                    registeredManager.destroy();
                    if(ServiceManagerFactory
                        .isRegisteredManager(getServiceName())){
                        ServiceManagerFactory
                            .unregisterManager(getServiceName());
                    }
                    ServiceManagerFactory.registerManager(
                        getServiceName(),
                        this
                    );
                }
            }else{
                ServiceManagerFactory.registerManager(getServiceName(), this);
            }
        }
    }
    
    /**
     * サービスを開始する必要があるか調べる。<p>
     * サービス状態が{@link #DESTROYED}または、{@link #FAILED}で、サービスを開始しようとした場合、例外をthrowする。それ以外は、trueを返す。<br>
     *
     * @return サービスを開始する必要がある場合true、そうでない場合false
     * @exception Exception サービス状態が{@link #DESTROYED}または、{@link #FAILED}で、サービスを開始しようとした場合
     */
    @Override
    protected boolean isNecessaryToStart() throws Exception{
        if(state == State.DESTROYED || state == State.FAILED){
            final MessageRecordFactory message = getMessageRecordFactory();
            throw new IllegalStateException(
                message.findMessage(
                    SVCM_00009,
                    getServiceName(), state
                )
            );
        }
        return true;
    }
    
    /**
     * このサービスの破棄前処理を行う。<p>
     *
     * @exception Exception 破棄前処理に失敗した場合
     */
    @Override
    protected void preDestroyService() throws Exception{
        if(state != State.STOPPED){
            stop();
        }
        
        state = State.DESTROYING;
        processStateChanged(State.DESTROYING);
        
        if(getServiceName() != null){
            unregisterService(getServiceName());
        }
    }
    
    /**
     * このサービスの破棄後処理を行う。<p>
     *
     * @exception Exception 破棄後処理に失敗した場合
     */
    @Override
    protected void postDestroyService() throws Exception{
        if(getServiceName() != null){
            if(ServiceManagerFactory.findManager(getServiceName()) == this){
                ServiceManagerFactory.unregisterManager(getServiceName());
            }
        }
        
        state = State.DESTROYED;
        processStateChanged(State.DESTROYED);
    }
    
    /**
     * このサービスの生成処理を行う。<p>
     * このマネージャに登録されている全てのサービスに対して以下の処理を順次行う。<br>
     * <ol>
     *   <li>サービスの生成処理（{@link Service#create()}）を行う。</li>
     *   <li>サービスの属性の設定を行う。</li>
     * </ol>
     *
     * @exception Exception 生成処理に失敗した場合
     */
    @Override
    public void createService() throws Exception{
       createAllService();
    }
    
    /**
     * このサービスの開始処理を行う。<p>
     * このマネージャに登録されている全てのサービスの開始処理({@link Service#start()})を行う。<br>
     * サービスの開始時には、開始しようとしているサービスが依存しているサービスの開始が優先されて行われる。<br>
     * 依存関係のあるサービスのロードが完了していない場合には、そのサービスがロードされ開始されるまで、依存されているサービスの開始は待機される。<br>
     * <p>
     * また、このマネージャが定義されているサービス定義ファイルのserver要素の子要素に、manager-repository要素、log要素、message要素が定義されている場合、ServiceManagerFactoryにLogger、MessageRecordFactory、Repositoryの設定を行う。<br>
     * 同様に、このマネージャが定義されているmanager要素の子要素に、repository要素、log要素、message要素が定義されている場合、このマネージャにLogger、MessageRecordFactory、Repositoryの設定を行う。<br>
     *
     * @exception Exception 開始処理に失敗した場合
     */
    @Override
    public void startService() throws Exception{
        final Logger logger = getLogger();
        
        startAllService();
        
        if(existWaitingService()){
            for(String waitingServiceName : getWaitingServices()){
                final Set<ServiceName> causes = getWaitingCauses(waitingServiceName);
                logger.write(
                    SVCM_00024,
                    getServiceName(), waitingServiceName, causes
                );
            }
        }
    }
    
    /**
     * このサービスの停止処理を行う。<p>
     * このマネージャに登録されている全てのサービスの停止処理（{@link Service#stop()}）を行う。<p>
     * サービスの停止時には、停止しようとしているサービスが依存されているサービスの停止が優先されて行われる。<br>
     *
     * @exception Exception 停止処理に失敗した場合
     */
    @Override
    public void stopService() throws Exception{
        stopAllService();
        clearWaitingServices();
        if(existFailedService()){
            for(String failedServiceName : getFailedServices()){
                try{
                    createService(failedServiceName);
                }catch(Exception e){
                }
            }
            clearFailedServices();
        }
        attributePropCache.clear();
    }
    
    /**
     * このサービスの破棄処理を行う。<p>
     * このマネージャに登録されている全てのサービスの破棄処理を行う。<p>
     *
     * @exception Exception 破棄処理に失敗した場合
     */
    @Override
    public void destroyService() throws Exception{
        destroyAllService();
    }
    
    // ServiceManagerのJavaDoc
    @Override
    public void createService(String name) throws Exception{
        createService(name, new HashSet<String>());
    }
    
    // ServiceManagerのJavaDoc
    @Override
    public void createService(String name, Set<String> completed)
     throws Exception{
        changeServiceState(name, State.CREATING, completed);
    }
    
    // ServiceManagerのJavaDoc
    @Override
    public void createService(Set<String> names){
        changeServiceState(names, State.CREATING);
    }
    
    // ServiceManagerのJavaDoc
    @Override
    public void createService(Service service, ServiceMetaData serviceData)
     throws Exception{
        changeServiceState(service, serviceData, State.CREATING);
    }
    
    // ServiceManagerのJavaDoc
    @Override
    public void createAllService(){
        changeAllServiceState(State.CREATING);
    }
    
    // ServiceManagerのJavaDoc
    @Override
    public void startService(String name) throws Exception{
        startService(name, new HashSet<String>());
    }
    
    // ServiceManagerのJavaDoc
    @Override
    public void startService(String name, Set<String> completed) throws Exception{
        changeServiceState(name, State.STARTING, completed);
    }
    
    // ServiceManagerのJavaDoc
    @Override
    public void startService(Set<String> names){
        changeServiceState(names, State.STARTING);
    }
    
    // ServiceManagerのJavaDoc
    @Override
    public void startService(Service service, ServiceMetaData serviceData)
     throws Exception{
        changeServiceState(service, serviceData, State.STARTING);
    }
    
    // ServiceManagerのJavaDoc
    @Override
    public void startAllService(){
        changeAllServiceState(State.STARTING);
    }
    
    // ServiceManagerのJavaDoc
    @Override
    public void restartService(String name) throws Exception{
        restartService(name, new HashSet<String>());
    }
    
    // ServiceManagerのJavaDoc
    @Override
    public void restartService(String name, Set<String> completed) throws Exception{
        stopService(name, completed);
        completed.clear();
        startService(name, completed);
    }
    
    // ServiceManagerのJavaDoc
    @Override
    public void restartService(Set<String> names){
        stopService(names);
        startService(names);
    }
    
    // ServiceManagerのJavaDoc
    @Override
    public void restartService(Service service, ServiceMetaData serviceData)
     throws Exception{
        stopService(service, serviceData);
        startService(service, serviceData);
    }
    
    // ServiceManagerのJavaDoc
    @Override
    public void restartAllService(){
        stopAllService();
        startAllService();
    }
    
    // ServiceManagerのJavaDoc
    @Override
    public void stopService(String name){
        stopService(name, new HashSet<String>());
    }
    
    // ServiceManagerのJavaDoc
    @Override
    public void stopService(String name, Set<String> completed){
        final Logger logger = getLogger();
        try{
            changeServiceState(name, State.STOPPING, completed);
        }catch(Exception e){
            //  起こり得ない
            logger.write(SVCM_00035, e);
        }
    }
    
    // ServiceManagerのJavaDoc
    @Override
    public void stopService(Set<String> names){
        changeServiceState(names, State.STOPPING);
    }
    
    // ServiceManagerのJavaDoc
    @Override
    public void stopService(Service service, ServiceMetaData serviceData){
        try{
            changeServiceState(service, serviceData, State.STOPPING);
        }catch(Exception e){
            //  起こり得ない
            logger.write(SVCM_00035, e);
        }
    }
    
    // ServiceManagerのJavaDoc
    @Override
    public void stopAllService(){
        changeAllServiceState(State.STOPPING);
    }
    
    // ServiceManagerのJavaDoc
    @Override
    public void destroyService(String name){
        destroyService(name, new HashSet<String>());
    }
    
    // ServiceManagerのJavaDoc
    @Override
    public void destroyService(String name, Set<String> completed){
        changeServiceState(name, State.DESTROYING, completed);
    }
    
    // ServiceManagerのJavaDoc
    @Override
    public void destroyService(Set<String> names){
        changeServiceState(names, State.DESTROYING);
    }
    
    // ServiceManagerのJavaDoc
    @Override
    public void destroyService(Service service, ServiceMetaData serviceData){
        try{
            changeServiceState(service, serviceData, State.DESTROYING);
        }catch(Exception e){
            //  起こり得ない
            logger.write(SVCM_00035, e);
        }
    }
    
    // ServiceManagerのJavaDoc
    @Override
    public void destroyAllService(){
        changeAllServiceState(State.DESTROYING);
    }
    
    /**
     * このマネージャに登録されている全てのサービスの状態を、指定された状態の完了形の状態へと遷移させる。<p>
     *
     * @param state 移行したい遷移状態
     * @see #changeServiceState(String, int, Set)
     */
    protected void changeAllServiceState(State state){
        changeServiceState(serviceNameSet(), state);
    }
    
    /**
     * 指定されたサービス集合の状態を、指定された状態の完了形の状態へと遷移させる。<p>
     *
     * @param serviceNames サービス名文字列の集合
     * @param state 移行したい遷移状態
     * @see #changeServiceState(String, int, Set)
     */
    protected void changeServiceState(Set<String> serviceNames, State state){
        final Set<String> completed = new HashSet<String>();
        final String myName = getServiceName();
        for(String name : serviceNames){
            if(name.equals(myName) || completed.contains(name)){
                continue;
            }
            changeServiceState(name, state, completed);
        }
    }
    
    /**
     * 指定されたサービスの状態を、指定された状態の完了形の状態へと遷移させる。<p>
     * stateに指定可能な状態は、{@link Service#CREATING}、{@link Service#STARTING}、{@link Service#STOPPING}、{@link Service#DESTROYING}の４つである。それぞれを指定して状態変更を行った結果は、それぞれ{@link Service#CREATED}、{@link Service#STARTED}、{@link Service#STOPPED}、{@link Service#DESTROYED}となる。<br>
     *
     * @param name サービス名
     * @param state 移行したい遷移状態
     * @param completed 状態遷移されたサービス名の集合。依存関係により状態遷移されたサービスを含む。
     */
    protected void changeServiceState(
        String name,
        State state,
        Set<String> completed
    ){
        if(getServiceName().equals(name)){
            return;
        }
        Service service = null;
        try{
            service = getService(name);
        }catch(ServiceNotFoundException e){
            return;
        }
        if(getServiceName().equals(service.getServiceManagerName())){
            boolean changeState = false;
            synchronized(service){
                switch(state){
                case CREATING:
                    if(completed == null || !completed.contains(name)){
                        changeState = changeServiceState(service, state);
                        if(completed != null){
                            completed.add(name);
                        }
                    }
                    break;
                case STARTING:
                    ServiceMetaData serviceData = getServiceMetaData(name);
                    if(serviceData != null
                         && serviceData.getServiceLoader() != null
                         && serviceData.getServiceLoader().getState() != State.STARTED
                         && serviceData.getInitStateValue().ordinal() < State.STARTING.ordinal()){
                        break;
                    }
                    if(processDepends(this, name, state, completed)){
                        changeState = changeServiceState(service, state);
                        if(completed != null){
                            completed.add(name);
                        }
                        if(!changeState){
                            return;
                        }
                        processDepended(this, name, state, completed);
                    }
                    break;
                case STOPPING:
                    if(processDepended(this, name, state, completed)){
                        if(completed == null || !completed.contains(name)){
                            changeState = changeServiceState(service, state);
                            if(completed != null){
                                completed.add(name);
                            }
                        }
                    }
                    break;
                case DESTROYING:
                    if(service.getState() != State.STOPPED){
                        changeServiceState(name, State.STOPPING, new HashSet<String>());
                    }
                    if(completed == null || !completed.contains(name)){
                        changeState = changeServiceState(service, state);
                        if(completed != null){
                            completed.add(name);
                        }
                    }
                    break;
                default:
                    final MessageRecordFactory message
                         = getMessageRecordFactory();
                    throw new IllegalArgumentException(
                        message.findMessage(
                            SVCM_00010,
                            getServiceName(), name, state, getState()
                        )
                    );
                }
            }
        }
    }
    
    /**
     * 指定したサービスを待機中のサービスとして追加する。<p>
     *
     * @param causeService 待機の原因となっているサービスのサービス名
     * @param waitService 待機中のサービスのサービス名
     */
    private void addWaitingServiceCause(
        ServiceName causeService,
        String waitService
    ){
        Set<ServiceName> causes = getWaitingCauses(waitService);
        if(causes == null){
            causes = new HashSet<ServiceName>();
            waitingServices.put(waitService, causes);
        }
        if(!causes.contains(causeService)){
            causes.add(causeService);
        }
    }
    
    /**
     * 指定したサービスを待機中のサービスから削除する。<p>
     *
     * @param causeService 待機の原因となっているサービスのサービス名
     * @param waitService 待機中のサービスのサービス名
     */
    private void removeWaitingServiceCause(
        ServiceName causeService,
        String waitService
    ){
        Set<ServiceName> causes = getWaitingCauses(waitService);
        if(causes == null){
            return;
        }
        if(causes.contains(causeService)){
            causes.remove(causeService);
            if(causes.size() == 0){
                waitingServices.remove(waitService);
            }
        }
    }
    
    // ServiceManagerのJavaDoc
    @Override
    public Set<ServiceName> getWaitingCauses(String waitService){
        Set<ServiceName> causes = null;
        if(waitingServices.containsKey(waitService)){
            causes = waitingServices.get(waitService);
        }
        return causes;
    }
    
    // ServiceManagerのJavaDoc
    @Override
    public void clearWaitingServices(){
        waitingServices.clear();
    }
    
    // ServiceManagerのJavaDoc
    @Override
    public boolean existWaitingService(){
        return waitingServices.size() != 0;
    }
    
    // ServiceManagerのJavaDoc
    @Override
    public Set<String> getWaitingServices(){
        return waitingServices.keySet();
    }
    
    /**
     * 指定したサービスを起動失敗による待機中のサービスとして追加する。<p>
     *
     * @param causeService 待機の原因となっているサービスのサービス名
     * @param waitService 待機中のサービスのサービス名
     */
    private void addFailedServiceCause(
        String failedService,
        Throwable cause
    ){
        failedServices.put(failedService, cause);
    }
    
    /**
     * 指定したサービスを起動失敗による待機中のサービスから削除する。<p>
     *
     * @param causeService 待機の原因となっているサービスのサービス名
     * @param waitService 待機中のサービスのサービス名
     */
    private void removeFailedServiceCause(
        String failedService
    ){
        if(failedService == null){
            return;
        }
        failedServices.remove(failedService);
    }
    
    // ServiceManagerのJavaDoc
    @Override
    public Throwable getFailedCause(String failedService){
        Throwable cause = null;
        if(failedServices.containsKey(failedService)){
            cause = failedServices.get(failedService);
        }
        return cause;
    }
    
    // ServiceManagerのJavaDoc
    @Override
    public void clearFailedServices(){
        failedServices.clear();
    }
    
    // ServiceManagerのJavaDoc
    @Override
    public boolean existFailedService(){
        return failedServices.size() != 0;
    }
    
    // ServiceManagerのJavaDoc
    @Override
    public Set<String> getFailedServices(){
        return failedServices.keySet();
    }
    
    /**
     * 依存するサービスの状態変更を待機して、状態変更されたタイミングで対象のサービスの状態変更が行われるように登録する。<p>
     *
     * @param target 状態変更を監視したいサービス
     * @param manager 状態変更を待機するサービスが登録されているServiceManager
     * @param waitService 状態変更を待機するサービス
     * @param state 状態変更を待機するサービスが遷移したい状態
     * @param completed 状態遷移されたサービス名の集合。依存関係により状態遷移されたサービスを含む。
     */
    private void waitServiceStateProcess(
        Service target,
        final ServiceManager manager,
        final String waitService,
        final State state,
        final Set<String> completed
    ){
        final Logger logger = getLogger();
        
        Service targetService = null;
        if(!(target instanceof ServiceStateListenable)){
            final String managerName = target.getServiceManagerName();
            final ServiceManager mng = ServiceManagerFactory.findManager(
                managerName
            );
            targetService = mng;
        }else{
            targetService = target;
        }
        
        final ServiceStateListenable broad
             = (ServiceStateListenable)targetService;
        final ServiceName cause = new ServiceName(
            target.getServiceManagerName(),
            target.getServiceName()
        );
        addWaitingServiceCause(cause, waitService);
        class ServiceWaitServiceStateListener implements ServiceStateListener{
            private String managerName;
            private String serviceName;
            public ServiceWaitServiceStateListener(
                String managerName,
                String serviceName
            ){
                this.managerName = managerName;
                this.serviceName = serviceName;
            }
            @Override
            public void stateChanged(ServiceStateChangeEvent e){
                removeWaitingServiceCause(cause, waitService);
                broad.removeServiceStateListener(this);
                if(!completed.contains(waitService)){
                    try{
                        switch(state){
                        case CREATING:
                            manager.createService(waitService, completed);
                            break;
                        case STARTING:
                            manager.startService(waitService, completed);
                            break;
                        case STOPPING:
                            manager.stopService(waitService, completed);
                            break;
                        case DESTROYING:
                            manager.destroyService(waitService, completed);
                            break;
                        default:
                            // 起こり得ない
                        }
                    }catch(Exception ex){
                        String messageId = null;
                        switch(getState()){
                        case CREATING:
                            messageId = SVCM_00033;
                            break;
                        case STARTING:
                            messageId = SVCM_00034;
                            break;
                        case STOPPING:
                        case DESTROYING:
                        default:
                            // 起こり得ない
                            logger.write(SVCM_00035, ex);
                            return;
                        }
                        logger.write(
                            messageId,
                            ex,
                            manager.getServiceName(), waitService
                        );
                    }
                }
            }
            @Override
            public boolean isEnabledState(State st){
                if(state == State.CREATING){
                    return st == State.CREATED;
                }else if(state == State.STARTING){
                    return st == State.STARTED;
                }else{
                    return false;
                }
            }
            @Override
            public int hashCode(){
                return (managerName == null ? 0 : managerName.hashCode())
                    + (serviceName == null ? 0 : serviceName.hashCode());
            }
            @Override
            public boolean equals(Object obj){
                if(obj == null
                    || !(obj instanceof ServiceWaitServiceStateListener)){
                    return false;
                }
                ServiceWaitServiceStateListener comp
                    = (ServiceWaitServiceStateListener)obj;
                if((managerName != null || comp.managerName != null)
                    && (managerName == null || comp.managerName == null
                        || !managerName.equals(comp.managerName))){
                    return false;
                }
                if((serviceName != null || comp.serviceName != null)
                    && (serviceName == null || comp.serviceName == null
                        || !serviceName.equals(comp.serviceName))){
                    return false;
                }
                return true;
            }
        }
        broad.addServiceStateListener(
            new ServiceWaitServiceStateListener(
                getServiceName(),
                waitService
            )
        );
        
        String messageId = null;
        switch(state){
        case CREATING:
            messageId = SVCM_00025;
            break;
        case STARTING:
            messageId = SVCM_00026;
            break;
        case STOPPING:
            messageId = SVCM_00027;
            break;
        case DESTROYING:
            messageId = SVCM_00028;
            break;
        default:
            break;
        }
        logger.write(
            messageId,
            targetService.getServiceManagerName(),
            targetService.getServiceName(),
            getServiceName(),
            waitService
        );
    }
    
    /**
     * 依存するサービスマネージャの登録を待機して、登録されたタイミングで状態変更監視対象のサービスの状態をチェックして、対象のサービスの状態変更が行われるように登録する。<p>
     *
     * @param targetMng ServiceManagerFactoryへの登録を監視したいServiceManagerの名前
     * @param targetService 状態変更を監視したいサービスの名前
     * @param waitService 状態変更を待機するサービス
     * @param completed 状態遷移されたサービス名の集合。依存関係により状態遷移されたサービスを含む。
     */
    private void waitRegistrationManagerProcess(
        final String targetMng,
        final String targetService,
        final String waitService,
        final Set<String> completed
    ){
        final Logger logger = getLogger();
        
        final ServiceName cause = new ServiceName(
            targetMng,
            targetMng
        );
        addWaitingServiceCause(cause, waitService);
        ServiceManagerFactory.addRegistrationListener(
            new RegistrationListener(){
                private final State state = getState();
                @Override
                public void registered(RegistrationEvent e){
                    final ServiceManager manager
                         = (ServiceManager)e.getRegistration();
                    if(!manager.getServiceName().equals(targetMng)){
                        return;
                    }
                    ServiceManagerFactory.removeRegistrationListener(this);
                    removeWaitingServiceCause(cause, waitService);
                    Service service = null;
                    try{
                        service = manager.getService(targetService);
                    }catch(ServiceNotFoundException ex){
                        waitRegistrationServiceProcess(
                            manager,
                            targetService,
                            waitService,
                            state,
                            completed
                        );
                        return;
                    }
                    if(!isMatchingState(service, state)){
                        waitServiceStateProcess(
                            service,
                            DefaultServiceManagerService.this,
                            waitService,
                            state,
                            completed
                        );
                    }else if(!completed.contains(waitService)){
                        DefaultServiceManagerService.this.changeServiceState(
                            waitService,
                            state,
                            completed
                        );
                    }
                }
                @Override
                public void unregistered(RegistrationEvent e){
                }
            }
        );
        
        String messageId = null;
        switch(getState()){
        case CREATING:
            messageId = SVCM_00031;
            break;
        case STARTING:
            messageId = SVCM_00032;
            break;
        default:
            break;
        }
        logger.write(
            messageId,
            targetMng, getServiceName(), waitService
        );
    }
    
    private void waitRegistrationServiceProcess(
        final ServiceManager targetMng,
        final String targetService,
        final String waitService,
        final State state,
        final Set<String> completed
    ){
        final Logger logger = getLogger();
        
        final ServiceName cause = new ServiceName(
            targetMng.getServiceName(),
            targetService
        );
        addWaitingServiceCause(cause, waitService);
        
        targetMng.addRegistrationListener(
            new RegistrationListener(){
                @Override
                public void registered(RegistrationEvent e){
                    final Service service
                         = (Service)e.getRegistration();
                    if(!service.getServiceName().equals(targetService)){
                        return;
                    }
                    removeWaitingServiceCause(cause, waitService);
                    targetMng.removeRegistrationListener(this);
                    if(!isMatchingState(service, state)){
                        waitServiceStateProcess(
                            service,
                            DefaultServiceManagerService.this,
                            waitService,
                            state,
                            completed
                        );
                    }else if(!completed.contains(waitService)){
                        DefaultServiceManagerService.this.changeServiceState(
                            waitService,
                            state,
                            completed
                        );
                    }
                }
                @Override
                public void unregistered(RegistrationEvent e){
                }
            }
        );
        
        String messageId = null;
        switch(state){
        case CREATING:
            messageId = SVCM_00029;
            break;
        case STARTING:
            messageId = SVCM_00030;
            break;
        default:
            break;
        }
        logger.write(
            messageId,
            targetMng.getServiceName(),
            targetService,
            getServiceName(),
            waitService
        );
    }
    
    private boolean processDepends(
        ServiceManager manager,
        final String serviceName,
        State state,
        Set<String> completed
    ){
        final Logger logger = getLogger();
        
        final List<ServiceMetaData.DependsMetaData> dependsList
            = manager.getDepends(serviceName);
        if(dependsList == null){
            return true;
        }
        for(ServiceMetaData.DependsMetaData dependsData : dependsList){
            final String managerName = dependsData.getManagerName();
            final String dependsServiceName = dependsData.getServiceName();
            
            ServiceManager mng = null;
            Service dependsService = null;
            final boolean isMyService
                 = managerName.equals(getServiceName());
            if(isMyService){
                mng = manager;
                try{
                    dependsService = getService(dependsServiceName);
                }catch(ServiceNotFoundException e){
                    dependsService = null;
                }
            }else{
                mng = ServiceManagerFactory.findManager(managerName);
                if(mng == null){
                    waitRegistrationManagerProcess(
                        managerName,
                        dependsServiceName,
                        serviceName,
                        new HashSet<String>()
                    );
                    return false;
                }
                try{
                    dependsService = mng.getService(dependsServiceName);
                }catch(ServiceNotFoundException e){
                    dependsService = null;
                }
            }
            
            if(dependsService == null){
                waitRegistrationServiceProcess(
                    mng,
                    dependsServiceName,
                    serviceName,
                    state,
                    completed
                );
                return false;
            }
            
            // 相互依存チェック
            if(isDepends(mng, dependsServiceName, manager, serviceName)){
                logger.write(
                    SVCM_00036,
                    manager.getServiceName(),
                    serviceName,
                    mng.getServiceName(),
                    dependsServiceName
                );
                waitServiceStateProcess(
                    dependsService,
                    manager,
                    serviceName,
                    state,
                    isMyService ? completed : new HashSet<String>()
                );
                return false;
            }
            
            if(!isMatchingState(dependsService, state)){
                if(!isMyService){
                    waitServiceStateProcess(
                        dependsService,
                        manager,
                        serviceName,
                        state,
                        new HashSet<String>()
                    );
                    return false;
                }else if(!completed.contains(dependsServiceName)){
                    changeServiceState(
                        dependsServiceName,
                        state,
                        completed
                    );
                    if(!completed.contains(dependsServiceName)){
                        waitServiceStateProcess(
                            dependsService,
                            manager,
                            serviceName,
                            state,
                            completed
                        );
                        return false;
                    }
                }
            }
        }
        return true;
    }
    
    private boolean processDepended(
        ServiceManager manager,
        String serviceName,
        State state,
        Set<String> completed
    ){
        final Logger logger = getLogger();
        boolean result = true;
        for(ServiceManager mng : ServiceManagerFactory.findManagers()){
            if(mng.getState() != State.STARTING
                 && mng.getState() != State.STARTED
                 && mng.getState() != State.STOPPING){
                continue;
            }
            final List<ServiceMetaData> dependedList = mng.getDependedServices(
                manager.getServiceName(),
                serviceName
            );
            for(ServiceMetaData serviceData : dependedList){
                final String dependsServiceName = serviceData.getName();
                Service dependsService = null;
                try{
                    dependsService = mng.getService(dependsServiceName);
                }catch(ServiceNotFoundException e){
                    if(state != State.CREATING){
                        continue;
                    }
                    try{
                        mng.deploy(serviceData);
                    }catch(DeploymentException ee){
                        continue;
                    }
                    dependsService = mng.getService(dependsServiceName);
                }
                
                if(isDepends(manager, serviceName, mng, dependsServiceName)){
                    logger.write(
                        SVCM_00036,
                        manager.getServiceName(),
                        serviceName,
                        mng.getServiceName(),
                        dependsServiceName
                    );
                    result = false;
                    continue;
                }
                
                if(!isMatchingState(dependsService, state)){
                   if(!completed.contains(dependsServiceName)){
                        switch(state){
                        case STARTING:
                            if(mng.getState() == State.STARTED){
                                try{
                                    mng.startService(
                                        dependsServiceName,
                                        completed
                                    );
                                }catch(Exception e){
                                    continue;
                                }
                            }
                            break;
                        case STOPPING:
                            mng.stopService(dependsServiceName, completed);
                            break;
                        case DESTROYING:
                        case CREATING:
                        default:
                            //  起こり得ない
                        }
                    }
                }
            }
        }
        return result;
    }
    
    private boolean isDepends(
        ServiceManager manager1,
        String service1,
        ServiceManager manager2,
        String service2
    ){
        final Set<ServiceMetaData.DependsMetaData> depends = getAllDepends(
            manager1,
            service1,
            new HashSet<ServiceMetaData.DependsMetaData>()
        );
        if(depends == null){
            return false;
        }
        for(ServiceMetaData.DependsMetaData dependsData : depends){
            if(dependsData.getServiceName().equals(service2)
                && dependsData.getManagerName()
                    .equals(manager2.getServiceName())
            ){
                return true;
            }
        }
        return false;
    }
    
    private Set<ServiceMetaData.DependsMetaData> getAllDepends(
        ServiceManager manager,
        String service,
        Set<ServiceMetaData.DependsMetaData> depends
    ){
        final List<ServiceMetaData.DependsMetaData> dependsList
            = manager.getDepends(service);
        if(dependsList == null){
            return depends;
        }
        for(ServiceMetaData.DependsMetaData dependsData : dependsList){
            if(depends.contains(dependsData)){
                continue;
            }
            final ServiceManager mng = ServiceManagerFactory.findManager(
                dependsData.getManagerName()
            );
            if(mng == null){
                continue;
            }
            depends.add(dependsData);
            depends = getAllDepends(
                mng,
                dependsData.getServiceName(),
                depends
            );
        }
        return depends;
    }
    
    private boolean isMatchingState(Service service, State state)
     throws IllegalStateException{
        final State serviceState = service.getState();
        ServiceMetaData serviceData = ServiceManagerFactory.getServiceMetaData(
            service.getServiceManagerName(),
            service.getServiceName()
        );
        if(state.ordinal() < State.STARTED.ordinal()
             && serviceData != null
             && serviceData.getServiceLoader() != null
             && serviceData.getServiceLoader().getState() != State.STARTED
             && serviceData.getInitStateValue() == serviceState
             
        ){
            return true;
        }
        switch(state){
        case CREATING:
        case CREATED:
            return serviceState == State.CREATED
                 || serviceState == State.STARTING
                 || serviceState == State.STARTED;
        case STARTING:
        case STARTED:
            return serviceState == State.STARTED;
        case STOPPING:
        case STOPPED:
            return serviceState == State.STOPPED
                 || serviceState == State.DESTROYING
                 || serviceState == State.DESTROYED;
        case DESTROYING:
        case DESTROYED:
            return serviceState == State.DESTROYED;
        default:
            final MessageRecordFactory message
                 = getMessageRecordFactory();
            throw new IllegalStateException(
                message.findMessage(
                    SVCM_00011,
                    getServiceName(),
                    name,
                    state,
                    serviceState
                )
            );
        }
    }
    
    private boolean changeServiceState(Service service, State state){
        final Logger logger = getLogger();
        final String managerName = service.getServiceManagerName();
        final String serviceName = service.getServiceName();
        if(getServiceName().equals(serviceName)){
            return false;
        }
        ServiceManager manager = null;
        if(managerName.equals(getServiceName())){
            manager = this;
        }else{
            manager = ServiceManagerFactory.findManager(managerName);
        }
        ServiceMetaData serviceData = manager.getServiceMetaData(serviceName);
        try{
            return changeServiceState(service, serviceData, state);
        }catch(Throwable e){
            switch(state){
            case CREATING:
                logger.write(
                    SVCM_00033,
                    e,
                    managerName, serviceName
                );
                if(managerName.equals(getServiceName())){
                    addFailedServiceCause(serviceName, e);
                }
                return false;
            case STARTING:
                logger.write(
                    SVCM_00034,
                    e,
                    managerName, serviceName
                );
                if(managerName.equals(getServiceName())){
                    addFailedServiceCause(serviceName, e);
                }
                return false;
            case STOPPING:
            case DESTROYING:
            default:
                return true;
            }
        }
    }
    
    private boolean changeServiceState(
        Object obj,
        ServiceMetaData serviceData,
        State state
    ) throws Exception{
        
        String managerName = null;
        String serviceName = null;
        Service service = null;
        Object serviceObj = obj;
        if(obj instanceof Service){
            service = (Service)obj;
            managerName = service.getServiceManagerName();
            serviceName = service.getServiceName();
            if(getServiceName().equals(serviceName)){
                return true;
            }
            serviceObj = convertServiceToObject(service);
        }
        switch(state){
        case CREATING:
            if(service instanceof ServiceBase
                    && !((ServiceBase)service).isNecessaryToCreate()){
                return false;
            }
            if(serviceData != null && !serviceData.isFactory()){
                callInvokes(serviceObj, serviceData, State.CREATING);
            }
            if(service != null){
                service.create();
            }
            if(serviceData != null && !serviceData.isFactory()){
                setFields(serviceObj, serviceData, State.CREATED);
                setAttributes(serviceObj, serviceData, State.CREATED);
                callInvokes(serviceObj, serviceData, State.CREATED);
            }
            removeFailedServiceCause(serviceName);
            break;
        case STARTING:
            if(service instanceof ServiceBase
                    && !((ServiceBase)service).isNecessaryToStart()){
                return false;
            }
            if(serviceData != null && !serviceData.isFactory()){
                setFields(serviceObj, serviceData, State.STARTING);
                setAttributes(serviceObj, serviceData, State.STARTING);
                callInvokes(serviceObj, serviceData, State.STARTING);
            }
            if(service != null){
                service.start();
            }
            if(serviceData != null && !serviceData.isFactory()){
                callInvokes(serviceObj, serviceData, State.STARTED);
            }
            break;
        case STOPPING:
            if(service instanceof ServiceBase
                    && !((ServiceBase)service).isNecessaryToStop()){
                return false;
            }
            if(serviceData != null && !serviceData.isFactory()){
                callInvokes(serviceObj, serviceData, State.STOPPING);
            }
            if(service != null){
                service.stop();
            }
            if(serviceData != null && !serviceData.isFactory()){
                callInvokes(serviceObj, serviceData, State.STOPPED);
            }
            break;
        case DESTROYING:
            if(service instanceof ServiceBase
                    && !((ServiceBase)service).isNecessaryToDestroy()){
                return false;
            }
            if(serviceData != null && !serviceData.isFactory()){
                callInvokes(serviceObj, serviceData, State.DESTROYING);
            }
            if(service != null){
                service.destroy();
            }
            if(serviceData != null && !serviceData.isFactory()){
                callInvokes(serviceObj, serviceData, State.DESTROYED);
            }
            break;
        default:
            final MessageRecordFactory message
                 = getMessageRecordFactory();
            throw new IllegalStateException(
                message.findMessage(
                    SVCM_00012,
                    managerName, serviceName, state
                )
            );
        }
        return true;
    }
    
    @Override
    public Service instanciateService(ServiceMetaData data) throws Exception{
        Object obj = instanciateObject(data);
        final Service service = convertObjectToService(
            data.getName(),
            obj
        );
        return service;
    }
    
    @Override
    public Object createObject(ServiceMetaData data) throws Exception{
        Object obj = instanciateObject(data);
        
        if(!(obj instanceof ServiceBase) && obj instanceof ServiceBaseSupport){
            final ServiceBaseSupport support = (ServiceBaseSupport)obj;
            try{
                obj = ServiceProxyFactory.createServiceBaseProxy(support);
            }catch(Exception e){
                return null;
            }
        }
        
        if(obj != null){
            changeServiceState(obj, data, State.CREATING);
            changeServiceState(obj, data, State.STARTING);
        }
        return obj;
    }
    
    private Object getValueOfServiceRef(ServiceRefMetaData serviceRefData)
     throws ServiceNotFoundException{
        return ServiceManagerFactory.getServiceObject(
            serviceRefData.getManagerName(),
            serviceRefData.getServiceName()
        );
    }
    
    private Object getValueOfArgument(ArgumentMetaData argData)
     throws Exception{
        if(argData.isNullValue()){
            return null;
        }
        Object value = argData.getValue();
        if(value instanceof ServiceRefMetaData){
            return getValueOfServiceRef((ServiceRefMetaData)value);
        }else if(value instanceof ObjectMetaData){
            return getValueOfObject((ObjectMetaData)value);
        }else if(value instanceof StaticInvokeMetaData){
            return callInvoke(null, null, (StaticInvokeMetaData)value);
        }else if(value instanceof StaticFieldRefMetaData){
            return getStaticFieldValue((StaticFieldRefMetaData)value);
        }else{
            Class<?> type = null;
            if(argData.getValueType() != null){
                type = Utility.convertStringToClass(argData.getValueType());
            }else if(argData.getType() != null){
                type = Utility.convertStringToClass(argData.getType());
            }else{
                type = String.class;
            }
            return getValueOfText(
                argData.getParentObjectMetaData(),
                type,
                (String)value
            );
        }
    }
    
    private Object getValueOfTarget(InvokeMetaData invokeData)
     throws Exception{
        MetaData targetData = invokeData.getTarget();
        if(targetData == null){
            return null;
        }
        if(targetData instanceof ServiceRefMetaData){
            return getValueOfServiceRef((ServiceRefMetaData)targetData);
        }else if(targetData instanceof ObjectMetaData){
            return getValueOfObject((ObjectMetaData)targetData);
        }else if(targetData instanceof StaticInvokeMetaData){
            return callInvoke(null, null, (StaticInvokeMetaData)targetData);
        }else if(targetData instanceof StaticFieldRefMetaData){
            return getStaticFieldValue((StaticFieldRefMetaData)targetData);
        }else if(targetData instanceof InvokeMetaData){
            return callInvoke(
                getValueOfTarget((InvokeMetaData)targetData),
                null,
                (InvokeMetaData)targetData
            );
        }
        return null;
    }
    
    private Object instanciateObject(ObjectMetaData objData) throws Exception{
        Object value = null;
        final Class<Object> clazz = (Class<Object>)Utility.convertStringToClass(objData.getCode());
        if((objData instanceof ServiceMetaData)
            && ((ServiceMetaData)objData).isFactory()){
            final ServiceMetaData serviceData = (ServiceMetaData)objData;
            final GenericsFactoryServiceProxy<Object> proxy
                 = new GenericsFactoryServiceProxy<Object>(
                    clazz,
                    serviceData.isManagement()
                 );
            if(ServiceMetaData.INSTANCE_TYPE_THREADLOCAL
                .equals(serviceData.getInstance())){
                proxy.setThreadLocal(true);
            }
            proxy.setCreateTemplateOnStart(serviceData.isCreateTemplate());
            value = proxy;
        }else{
            
            final ConstructorMetaData constData = objData.getConstructor();
            if(constData == null){
                if(clazz.isArray()){
                    final Class<?> elementType = clazz.getComponentType();
                    value = Array.newInstance(elementType, 0);
                }else{
                    value = clazz.newInstance();
                }
            }else{
                if(constData.getInvoke() != null){
                    InvokeMetaData invoke = constData.getInvoke();
                    Object target = getValueOfTarget(invoke);
                    value = callInvoke(target, null, invoke);
                    if(value == null){
                        final MessageRecordFactory message
                             = getMessageRecordFactory();
                        throw new InstantiationException(
                            message.findMessage(
                                SVCM_00015,
                                target == null
                                     ? null : target.getClass().getName(),
                                invoke.getName()
                            )
                        );
                    }
                }else if(constData.getStaticInvoke() != null){
                    StaticInvokeMetaData invoke = constData.getStaticInvoke();
                    value = callInvoke(null, null, invoke);
                    if(value == null){
                        final MessageRecordFactory message
                             = getMessageRecordFactory();
                        throw new InstantiationException(
                            message.findMessage(
                                SVCM_00015,
                                invoke.getCode(), invoke.getName()
                            )
                        );
                    }
                }else if(constData.getStaticFieldRef() != null){
                    StaticFieldRefMetaData field
                         = constData.getStaticFieldRef();
                    value = getStaticFieldValue(field);
                    if(value == null){
                        final MessageRecordFactory message
                             = getMessageRecordFactory();
                        throw new InstantiationException(
                            message.findMessage(
                                SVCM_00016,
                                field.getCode(), field.getName()
                            )
                        );
                    }
                }else if(clazz.isArray()){
                    final Class<?> elementType = clazz.getComponentType();
                    final Collection<ArgumentMetaData> argCollection = constData.getArguments();
                    Object argVals = Array.newInstance(
                        elementType,
                        argCollection.size()
                    );
                    int i = 0;
                    for(ArgumentMetaData argData : argCollection){
                        Array.set(argVals, i, getValueOfArgument(argData));
                        i++;
                    }
                    value = argVals;
                }else{
                    final Collection<ArgumentMetaData> argCollection = constData.getArguments();
                    final Class<?>[] argTypes = new Class[argCollection.size()];
                    final Object[] argVals = new Object[argCollection.size()];
                    int i = 0;
                    for(ArgumentMetaData argData : argCollection){
                        argVals[i] = getValueOfArgument(argData);
                        if(argData.getType() != null){
                            argTypes[i] = Utility.convertStringToClass(
                                argData.getType()
                            );
                        }else if(argVals[i] != null){
                            argTypes[i] = argVals[i].getClass();
                        }else{
                            argTypes[i] = String.class;
                        }
                        i++;
                    }
                    final Constructor<Object> constructor
                         = clazz.getConstructor(argTypes);
                    value = constructor.newInstance(argVals);
                }
            }
        }
        return value;
    }
    
    private Object getValueOfObject(ObjectMetaData objData) throws Exception{
        Object value = instanciateObject(objData);
        setFields(value, objData, State.CREATED);
        setAttributes(value, objData, State.CREATED);
        callInvokes(value, objData);
        return value;
    }
    
    private Object getStaticFieldValue(StaticFieldRefMetaData refData) throws Exception{
        final Class<?> clazz = Utility.convertStringToClass(refData.getCode());
        final Field field = clazz.getField(refData.getName());
        return field.get(null);
    }
    
    private Object getValueOfText(
        ObjectMetaData objData,
        Type type,
        String textValue
    ) throws Exception{
        final Logger logger = getLogger();
        
        // システムプロパティの置換
        textValue = Utility.replaceSystemProperty(textValue, false);
        // サービスローダ構成プロパティの置換
        textValue = Utility.replaceServiceLoderConfig(
            objData.getServiceLoader().getConfig(),
            textValue,
            false
        );
        // マネージャプロパティの置換
        textValue = Utility.replaceManagerProperty(
            this,
            textValue,
            false
        );
        // サーバプロパティの置換
        textValue = Utility.replaceServerProperty(textValue, true);
        Class<?> typeClass = null;
        if(type instanceof Class){
            typeClass = (Class<?>)type;
        }else if(type instanceof ParameterizedType){
            typeClass = (Class<?>)((ParameterizedType)type).getRawType();
        }else{
            return textValue;
        }
        
        final PropertyEditor editor
             = objData.getServiceLoader().findEditor(typeClass);
        if(editor == null){
            logger.write(SVCM_00040, typeClass);
            return null;
        }
        if(editor instanceof ServiceNameEditor){
            ((ServiceNameEditor)editor).setServiceManagerName(
                objData.getManagerName()
            );
        }else if(editor instanceof ServiceNameArrayEditor){
            ((ServiceNameArrayEditor)editor).setServiceManagerName(
                objData.getManagerName()
            );
        }else if(editor instanceof ParameterizedTypePropertyEditor
            && type instanceof ParameterizedType){
            ((ParameterizedTypePropertyEditor)editor).setServiceLoader(
                objData.getServiceLoader()
            );
            ((ParameterizedTypePropertyEditor)editor).setServiceManager(
                this
            );
            ((ParameterizedTypePropertyEditor)editor).setParameterizedType(
                (ParameterizedType)type
            );
        }
        editor.setAsText(textValue);
        return editor.getValue();
    }
    
    private void setFields(
        Object target,
        ObjectMetaData objData,
        State state
    ){
        if(objData == null){
            return;
        }
        for(FieldMetaData field : objData.getFields()){
            Object value = field.getValue();
            if(value != null){
                if(objData instanceof ServiceMetaData){
                    if(state == State.STARTING){
                        if(value instanceof ServiceRefMetaData){
                            setField(target, objData, field);
                        }
                    }else{
                        if(!(value instanceof ServiceRefMetaData)){
                            setField(target, objData, field);
                        }
                    }
                }else{
                    setField(target, objData, field);
                }
            }
        }
    }
    
    private void setField(
        Object target,
        ObjectMetaData objData,
        FieldMetaData field
    ){
        final Logger logger = getLogger();
        
        final String name = field.getName();
        
        final Class<?> targetClazz = target.getClass();
        Field f = null;
        try{
            f = targetClazz.getField(name);
        }catch(NoSuchFieldException e){
            if(name.length() != 0 && Character.isUpperCase(name.charAt(0))){
                StringBuilder tmpName = new StringBuilder();
                tmpName.append(Character.toLowerCase(name.charAt(0)));
                if(name.length() > 1){
                    tmpName.append(name.substring(1));
                }
                try{
                    f = targetClazz.getField(tmpName.toString());
                }catch(NoSuchFieldException e2){
                }
            }
            if(f == null){
                if(objData instanceof ServiceMetaData){
                    ServiceMetaData serviceData = (ServiceMetaData)objData;
                    logger.write(
                        SVCM_00038,
                        serviceData.getManager().getName(),
                        serviceData.getName(),
                        name
                    );
                }else{
                    logger.write(
                        SVCM_00037,
                        objData.getCode(),
                        name
                    );
                }
                return;
            }
        }
        
        Object value = field.getValue();
        try{
            if(value instanceof ServiceRefMetaData){
                value = getValueOfServiceRef((ServiceRefMetaData)value);
            }else if(value instanceof ObjectMetaData){
                value = getValueOfObject((ObjectMetaData)value);
            }else if(value instanceof StaticInvokeMetaData){
                value = callInvoke(null, null, (StaticInvokeMetaData)value);
            }else if(value instanceof StaticFieldRefMetaData){
                value = getStaticFieldValue((StaticFieldRefMetaData)value);
            }else{
                Type type = null;
                if(field.getType() != null){
                    type = Utility.convertStringToClass(field.getType());
                }else{
                    type = f.getGenericType();
                }
                if(type == null || Object.class.equals(type)){
                    type = String.class;
                }
                value = getValueOfText(objData, type, (String)value);
            }
        }catch(Throwable e){
            if(objData instanceof ServiceMetaData){
                ServiceMetaData serviceData = (ServiceMetaData)objData;
                logger.write(
                    SVCM_00042,
                    e,
                    serviceData.getManager().getName(),
                    serviceData.getName(),
                    name,
                    value
                );
            }else{
                logger.write(
                    SVCM_00041,
                    e,
                    objData.getCode(),
                    name,
                    value
                );
            }
            return;
        }
        
        try{
            f.set(target, value);
            if(objData instanceof ServiceMetaData){
                ServiceMetaData serviceData = (ServiceMetaData)objData;
                logger.write(
                    SVCM_00045,
                    serviceData.getManager().getName(),
                    serviceData.getName(),
                    name,
                    value
                );
            }else{
                logger.write(
                    SVCM_00044,
                    objData.getCode(),
                    name,
                    value
                );
            }
        }catch(Throwable e){
            if(objData instanceof ServiceMetaData){
                ServiceMetaData serviceData = (ServiceMetaData)objData;
                logger.write(
                    SVCM_00043,
                    e,
                    serviceData.getManager().getName(),
                    serviceData.getName(),
                    name,
                    value
                );
            }else{
                logger.write(
                    SVCM_00039,
                    e,
                    objData.getCode(),
                    name,
                    value
                );
            }
        }
    }
    
    private void callInvokes(
        Object target,
        ObjectMetaData objData,
        State state
    ){
        if(objData == null){
            return;
        }
        for(InvokeMetaData invokeData : objData.getInvokes()){
            if(state == invokeData.getCallStateValue()){
                try{
                    callInvoke(target, objData, invokeData);
                }catch(Exception e){
                    // 無視する
                }
            }
        }
    }
    
    private void callInvokes(
        Object target,
        ObjectMetaData objData
    ){
        if(objData == null){
            return;
        }
        for(InvokeMetaData invokeData : objData.getInvokes()){
            try{
                callInvoke(target, objData, invokeData);
            }catch(Exception e){
                // 無視する
            }
        }
    }
    
    private boolean isAccessableClass(Class<?> clazz){
        final int modifier = clazz.getModifiers();
        return Modifier.isPublic(modifier)
            || ((Modifier.isProtected(modifier)
                || (!Modifier.isPublic(modifier)
                    && !Modifier.isProtected(modifier)
                    && !Modifier.isPrivate(modifier)))
                && DefaultServiceManagerService.class.getPackage().equals(clazz.getPackage()));
    }
    
    private Object callInvoke(
        Object target,
        ObjectMetaData objData,
        InvokeMetaData invoke
    ) throws Exception{
        final Logger logger = getLogger();
        
        final String methodName = invoke.getName();
        
        Class<?> clazz = null;
        Method method = null;
        Object[] argVals = null;
        try{
            if(invoke instanceof StaticInvokeMetaData){
                clazz = Utility.convertStringToClass(
                    ((StaticInvokeMetaData)invoke).getCode()
                );
            }else{
                if(target == null){
                    logger.write(
                        SVCM_00017,
                        invoke
                    );
                    return null;
                }
                clazz = target.getClass();
            }
            final Collection<ArgumentMetaData> argCollection = invoke.getArguments();
            Class<?>[] argTypes = null;
            if(argCollection.size() == 0){
            }else{
                argTypes = new Class[argCollection.size()];
                argVals = new Object[argCollection.size()];
                int i = 0;
                for(ArgumentMetaData argData : argCollection){
                    argVals[i] = getValueOfArgument(argData);
                    if(argData.getType() != null){
                        argTypes[i] = Utility.convertStringToClass(
                            argData.getType()
                        );
                    }else if(argVals[i] != null){
                        argTypes[i] = argVals[i].getClass();
                    }else{
                        argTypes[i] = String.class;
                    }
                    i++;
                }
            }
            if(!isAccessableClass(clazz)){
                final Class<?>[] interfaces = clazz.getInterfaces();
                for(Class<?> itf : interfaces){
                    if(isAccessableClass(itf)){
                        try{
                            method = itf.getMethod(
                                methodName,
                                argTypes
                            );
                            clazz = itf;
                            break;
                        }catch(NoSuchMethodException e){
                        }
                    }
                }
            }
            if(method == null){
                method = clazz.getMethod(methodName, argTypes);
            }
        }catch(Throwable th){
            if(objData == null){
                logger.write(
                    SVCM_00019,
                    th,
                    clazz.getName(),
                    invoke
                );
            }else if(objData instanceof ServiceMetaData){
                ServiceMetaData serviceData = (ServiceMetaData)objData;
                logger.write(
                    SVCM_00020,
                    th,
                    serviceData.getManager().getName(),
                    serviceData.getName(),
                    invoke
                );
            }else{
                logger.write(
                    SVCM_00021,
                    th,
                    objData.getCode(),
                    invoke
                );
            }
            if(th instanceof Exception){
                throw (Exception)th;
            }else if(th instanceof Error){
                throw (Error)th;
            }else{
                throw new InvocationTargetException(th);
            }
        }
        try{
            return method.invoke(target, argVals);
        }catch(Throwable th){
            if(objData == null){
                logger.write(
                    SVCM_00018,
                    th,
                    clazz.getName(),
                    method
                );
            }else if(objData instanceof ServiceMetaData){
                ServiceMetaData serviceData = (ServiceMetaData)objData;
                logger.write(
                    SVCM_00022,
                    th,
                    serviceData.getManager().getName(),
                    serviceData.getName(),
                    method
                );
            }else{
                logger.write(
                    SVCM_00023,
                    th,
                    objData.getCode(),
                    method
                );
            }
            if(th instanceof Exception){
                throw (Exception)th;
            }else if(th instanceof Error){
                throw (Error)th;
            }else{
                throw new InvocationTargetException(th);
            }
        }
    }
    
    private void setAttributes(
        Object target,
        ObjectMetaData objData,
        State state
    ){
        if(objData == null){
            return;
        }
        for(AttributeMetaData attr : objData.getAttributes()){
            Object value = attr.getValue();
            if(value != null){
                if(objData instanceof ServiceMetaData){
                    if(state == State.STARTING){
                        if(value instanceof ServiceRefMetaData){
                            setAttribute(target, objData, attr);
                        }
                    }else{
                        if(!(value instanceof ServiceRefMetaData)){
                            setAttribute(target, objData, attr);
                        }
                    }
                }else{
                    setAttribute(target, objData, attr);
                }
            }
        }
    }
    
    private void setAttribute(
        Object target,
        ObjectMetaData objData,
        AttributeMetaData attr
    ){
        final String name = attr.getName();
        Object value = attr.getValue();
        Property prop = attributePropCache.get(attr);
        if(prop == null){
            try{
                prop = PropertyFactory.createProperty(name);
                attributePropCache.put(attr, prop);
            }catch(IllegalArgumentException e){
                if(objData instanceof ServiceMetaData){
                    ServiceMetaData serviceData = (ServiceMetaData)objData;
                    logger.write(
                        SVCM_00046,
                        e,
                        serviceData.getManager().getName(),
                        serviceData.getName(),
                        name
                    );
                }else{
                    logger.write(
                        SVCM_00047,
                        e,
                        objData.getCode(),
                        name
                    );
                }
                return;
            }
        }
        try{
            if(value instanceof ServiceRefMetaData){
                value = getValueOfServiceRef((ServiceRefMetaData)value);
            }else if(value instanceof ObjectMetaData){
                value = getValueOfObject((ObjectMetaData)value);
            }else if(value instanceof StaticInvokeMetaData){
                value = callInvoke(null, null, (StaticInvokeMetaData)value);
            }else if(value instanceof StaticFieldRefMetaData){
                value = getStaticFieldValue((StaticFieldRefMetaData)value);
            }else if(!(value instanceof org.w3c.dom.Element)){
                Type type = null;
                if(attr.getType() != null){
                    type = Utility.convertStringToClass(attr.getType());
                }else{
                    try{
                        type = prop.getPropertyGenericType(target);
                    }catch(NoSuchPropertyException e){
                    }
                }
                if(type == null || Object.class.equals(type)){
                    type = String.class;
                }
                value = getValueOfText(objData, type, (String)value);
            }
        }catch(Throwable e){
            if(objData instanceof ServiceMetaData){
                ServiceMetaData serviceData = (ServiceMetaData)objData;
                logger.write(
                    SVCM_00042,
                    e,
                    serviceData.getManager().getName(),
                    serviceData.getName(),
                    name,
                    value
                );
            }else{
                logger.write(
                    SVCM_00041,
                    e,
                    objData.getCode(),
                    name,
                    value
                );
            }
            return;
        }
        
        if(value == null){
            return;
        }
        
        try{
            prop.setProperty(target, value);
            if(objData instanceof ServiceMetaData){
                ServiceMetaData serviceData = (ServiceMetaData)objData;
                logger.write(
                    SVCM_00045,
                    serviceData.getManager().getName(),
                    serviceData.getName(),
                    name,
                    value
                );
            }else{
                logger.write(
                    SVCM_00044,
                    objData.getCode(),
                    name,
                    value
                );
            }
        }catch(NoSuchPropertyException e){
            if(objData instanceof ServiceMetaData){
                ServiceMetaData serviceData = (ServiceMetaData)objData;
                logger.write(
                    SVCM_00038,
                    serviceData.getManager().getName(),
                    serviceData.getName(),
                    name
                );
            }else{
                logger.write(
                    SVCM_00037,
                    objData.getCode(),
                    name
                );
            }
        }catch(InvocationTargetException e){
            if(objData instanceof ServiceMetaData){
                ServiceMetaData serviceData = (ServiceMetaData)objData;
                logger.write(
                    SVCM_00043,
                    e.getTargetException(),
                    serviceData.getManager().getName(),
                    serviceData.getName(),
                    name,
                    value
                );
            }else{
                logger.write(
                    SVCM_00039,
                    e.getTargetException(),
                    objData.getCode(),
                    name,
                    value
                );
            }
        }
    }
    
    /**
     * 登録状態が変更された事を監視するRegistrationListenerを追加する。<p>
     *
     * @param listener RegistrationListenerオブジェクト
     */
    @Override
    public void addRegistrationListener(RegistrationListener listener){
        if(!registrationListeners.contains(listener)){
            registrationListeners.add(listener);
        }
    }
    
    /**
     * 登録状態が変更された事を監視するRegistrationListenerを削除する。<p>
     *
     * @param listener RegistrationListenerオブジェクト
     */
    @Override
    public void removeRegistrationListener(
        RegistrationListener listener
    ){
        registrationListeners.remove(listener);
    }
    
    /**
     * Serviceが登録された事をRegistrationListenerに通知する。<p>
     * 
     * @param service 登録されたService
     * @see RegistrationListener
     * @see RegistrationEvent
     */
    protected void processRegisterd(Service service){
        final List<RegistrationListener> listeners
             = new ArrayList<RegistrationListener>(registrationListeners);
        for(RegistrationListener listener : listeners){
            listener.registered(new RegistrationEvent(service));
        }
    }
    
    /**
     * Serviceが削除された事をRegistrationListenerに通知する。<p>
     * 
     * @param service 削除されたService
     * @see RegistrationListener
     * @see RegistrationEvent
     */
    protected void processUnregisterd(Service service){
        final List<RegistrationListener> listeners
             = new ArrayList<RegistrationListener>(registrationListeners);
        for(RegistrationListener listener : listeners){
            listener.unregistered(new RegistrationEvent(service));
        }
    }
    
    // ServiceManagerのJavaDoc
    @Override
    public void addServiceStateListener(
        final String name,
        final ServiceStateListener listener
    ){
        if(isRegisteredService(name)){
            final ServiceStateListenable broadcaster
                 = getServiceStateListenable(name);
            if(broadcaster != null){
                broadcaster.addServiceStateListener(listener);
                return;
            }
        }
        addRegistrationListener(
            new RegistrationListener(){
                public void registered(RegistrationEvent e){
                    final Service service
                         = (Service)e.getRegistration();
                    if(!service.getServiceName().equals(name)){
                        return;
                    }
                    removeRegistrationListener(this);
                    addServiceStateListener(name, listener);
                }
                public void unregistered(RegistrationEvent e){
                }
            }
        );
    }
    
    // ServiceManagerのJavaDoc
    @Override
    public void removeServiceStateListener(
        String name,
        ServiceStateListener listener
    ){
        if(isRegisteredService(name)){
            final ServiceStateListenable broadcaster
                 = getServiceStateListenable(name);
            if(broadcaster != null){
                broadcaster.removeServiceStateListener(listener);
            }
        }
    }
}