com.bluecloud.ioc.core.KernelComponentDepender.java Source code

Java tutorial

Introduction

Here is the source code for com.bluecloud.ioc.core.KernelComponentDepender.java

Source

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

import java.lang.reflect.Array;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.bluecloud.ioc.classloader.ClassHandler;
import com.bluecloud.ioc.exception.KernelComponentDependerException;
import com.bluecloud.ioc.metadata.ComponentMetadata;
import com.bluecloud.ioc.metadata.ConstructorMetadata;
import com.bluecloud.ioc.metadata.EntryMetadata;
import com.bluecloud.ioc.metadata.PropertyMetadata;
import com.bluecloud.ioc.metadata.ServiceMetadata;
import com.bluecloud.ioc.metadata.ServicesMetadata;

/**
 * @author <a href="mailto:hanlu0808@gmail.com">Hanlu</a>
 * 
 */
public class KernelComponentDepender implements ComponentDepender {

    private Log log = LogFactory.getLog(KernelComponentDepender.class);

    /**
     * 
     */
    public KernelComponentDepender() {
    }

    /**
     * <h3>Component?</h3>
     * 
     * @param service
     *            ComponentService?
     * @param context
     *            ??Component
     * @return
     * @throws KernelComponentDependerException
     */
    private Object getServiceDepend(ServiceMetadata service, ComponentContext context)
            throws KernelComponentDependerException {
        String bind = service.getBind();
        if (bind != null) {
            ComponentObject componentObject = ((KernelComponentContext) context).getReadyComponent(bind);
            if (componentObject == null) {
                componentObject = ((KernelComponentContext) context).getDependComponent(bind);
            }
            if (componentObject != null) {
                if (componentObject.isNew()) {
                    return this.cloneComponent(service, componentObject, context);
                } else {
                    return componentObject.getObject();
                }
            }
            return null;
        } else {
            try {
                int size = service.getProperties().isEmpty() ? 0 : service.getProperties().size();
                if (size > 0) {
                    Class<?>[] parameterTypes = new Class[size];
                    Object[] initargs = new Object[size];
                    for (int i = 0; i < size; i++) {
                        PropertyMetadata property = service.getProperties().get(i);
                        parameterTypes[i] = property.getType();
                        initargs[i] = property.getValue();
                    }
                    return ClassHandler.createObject(service.getClazz(), parameterTypes, initargs);
                } else {
                    return ClassHandler.getClass(service.getClazz(), true);
                }
            } catch (Exception e) {
                throw new KernelComponentDependerException(e);
            }
        }
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * com.css.sword.esb.server.microkernel.core.ComponentDepender#injectConstructor
     * (com.css.sword.esb.server.microkernel.metadata.ComponentMetadata,
     * com.css.sword.esb.server.microkernel.core.ComponentContext)
     */
    public Object injectConstructor(ComponentMetadata componentMetadata, ComponentContext context)
            throws KernelComponentDependerException {
        Object componentObject = null;
        ConstructorMetadata constructor = componentMetadata.getConstructor();
        int size = constructor.getServices().size();
        Object[] constructorObjects = new Object[size];
        try {
            for (int index = 0; index < size; index++) {
                ServiceMetadata service = constructor.getServices().get(index);
                constructorObjects[index] = getServiceDepend(service, context);
            }
            componentObject = ClassHandler.createObject(componentMetadata.getClazz(), constructor.getIndex(),
                    constructorObjects);
        } catch (Exception e) {
            throw new KernelComponentDependerException(e);
        }
        return componentObject;
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * com.css.sword.esb.server.microkernel.core.ComponentDepender#inject(java
     * .lang.Object,
     * com.css.sword.esb.server.microkernel.metadata.ServiceMetadata,
     * com.css.sword.esb.server.microkernel.core.ComponentContext)
     */
    public void inject(Object componentObject, ServiceMetadata service, ComponentContext context)
            throws KernelComponentDependerException {
        Object injectObject = this.getServiceDepend(service, context);
        String bind = service.getBind();
        String methodName = null;
        try {
            if (bind != null && service.getName() == null) {
                methodName = this.getSetMethodName(bind);
            } else {
                methodName = this.getSetMethodName(service.getName());
            }
            ClassHandler.invokeMethod(componentObject, methodName, injectObject);
        } catch (Exception e) {
            throw new KernelComponentDependerException(e);
        }
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * com.css.sword.esb.server.microkernel.core.ComponentDepender#injectList
     * (java.lang.Object,
     * com.css.sword.esb.server.microkernel.metadata.ServicesMetadata,
     * com.css.sword.esb.server.microkernel.core.ComponentContext)
     */
    public void injectList(Object componentObject, ServicesMetadata services, ComponentContext context)
            throws KernelComponentDependerException {
        String limited = services.getLimited();
        String type = services.getType();
        String name = services.getName();
        int size = services.getSize();
        String methodName = getSetMethodName(name);
        Object injectObject = null;
        try {
            if (limited != null) {
                injectObject = haveLimited(limited, type, size, services, context);
            } else {
                injectObject = notLimited(type, services, context, size);
            }
            ClassHandler.invokeMethod(componentObject, methodName, injectObject);
        } catch (Exception e) {
            throw new KernelComponentDependerException(e);
        }
    }

    /**
     * <h3>set??</h3> service[name]setName
     * 
     * @param name
     *            ???servicebindname?servicesname
     * @return set??
     */
    private String getSetMethodName(String name) {
        return "set" + name.substring(0, 1).toUpperCase() + name.substring(1);
    }

    /**
     * <h3>?</h3>
     * 
     * @param type
     *            
     * @param services
     *            ??
     * @param context
     *            ??Component?
     * @param size
     *            Component
     * @return
     * @throws KernelComponentDependerException
     */
    private Object notLimited(String type, ServicesMetadata services, ComponentContext context, int size)
            throws KernelComponentDependerException {
        if (type.equals("List")) {
            return this.collectionType(new ArrayList<Object>(size), services, context);
        }
        if (type.equals("Set")) {
            return this.collectionType(new HashSet<Object>(size), services, context);
        }
        if (type.equals("Map")) {
            Map<Object, Object> map = new HashMap<Object, Object>(size);
            for (ServiceMetadata service : services.getServices()) {
                Object serviceObject = this.getServiceDepend(service, context);
                if (service.getName() != null) {
                    map.put(service.getName(), serviceObject);
                } else if (service.getName() == null && service.getBind() != null) {
                    map.put(service.getBind(), serviceObject);
                }
            }
            return map;
        }
        if (type.equals("Array")) {
            return this.collectionType(new ArrayList<Object>(size), services, context).toArray(new Object[size]);
        }
        return null;
    }

    /**
     * <h3>?</h3>
     * 
     * @param limited
     *            ???
     * @param type
     *            
     * @param size
     *            Component
     * @param services
     *            ??
     * @param context
     *            ??Component?
     * @return
     * @throws KernelComponentDependerException
     * @throws NoSuchMethodException
     * @throws InvocationTargetException
     * @throws ClassNotFoundException
     * @throws IllegalAccessException
     * @throws InstantiationException
     * @throws SecurityException
     * @throws IllegalArgumentException
     */
    private Object haveLimited(String limited, String type, int size, ServicesMetadata services,
            ComponentContext context) throws KernelComponentDependerException, IllegalArgumentException,
            SecurityException, InstantiationException, IllegalAccessException, ClassNotFoundException,
            InvocationTargetException, NoSuchMethodException {
        Class<?> limitedClass = (Class<?>) ClassHandler.getClass(limited, false);
        if (type.equals("List")) {
            return this.collectionType(new ArrayList<Object>(size), services, context, limitedClass, limited);
        }
        if (type.equals("Set")) {
            return this.collectionType(new HashSet<Object>(size), services, context, limitedClass, limited);
        }
        if (type.equals("Map")) {
            Map<Object, Object> map = new HashMap<Object, Object>(size);
            for (ServiceMetadata service : services.getServices()) {
                Object serviceObject = this.getServiceDepend(service, context);
                if (limitedClass.isAssignableFrom(serviceObject.getClass())) {
                    if (service.getName() != null) {
                        map.put(service.getName(), serviceObject);
                    } else if (service.getName() == null && service.getBind() != null) {
                        map.put(service.getBind(), serviceObject);
                    }
                } else {
                    if (log.isErrorEnabled()) {
                        log.error("?" + limited);
                    }
                    throw new ClassCastException(service.getClazz());
                }
            }
            return map;
        }
        if (type.equals("Array")) {
            Object array = Array.newInstance(limitedClass, size);
            int index = 0;
            for (ServiceMetadata service : services.getServices()) {
                Object serviceObject = this.getServiceDepend(service, context);
                if (limitedClass.isAssignableFrom(serviceObject.getClass())) {
                    Array.set(array, index, serviceObject);
                    index++;
                } else {
                    if (log.isErrorEnabled()) {
                        log.error("?" + limited);
                    }
                    throw new ClassCastException(service.getClazz());
                }
            }
            return array;
        }
        return null;
    }

    /**
     * <h3>List?Set</h3>
     * 
     * @param collection
     *            List?Set
     * @param services
     *            ??
     * @param context
     *            ??Component?
     * @return
     * @throws KernelComponentDependerException
     * @throws KernelComponentDependerException
     */
    private Collection<Object> collectionType(Collection<Object> collection, ServicesMetadata services,
            ComponentContext context) throws KernelComponentDependerException {
        for (ServiceMetadata service : services.getServices()) {
            Object serviceObject = this.getServiceDepend(service, context);
            collection.add(serviceObject);
        }
        return collection;
    }

    /**
     * <h3>List?Set</h3>
     * 
     * @param collection
     *            List?Set?
     * @param services
     *            ??
     * @param context
     *            ??Component?
     * @param limitedClass
     *            ?Class
     * @param limited
     *            ???
     * @return
     * @throws KernelComponentDependerException
     */
    private Collection<Object> collectionType(Collection<Object> collection, ServicesMetadata services,
            ComponentContext context, Class<?> limitedClass, String limited)
            throws KernelComponentDependerException {
        for (ServiceMetadata service : services.getServices()) {
            Object serviceObject = this.getServiceDepend(service, context);
            if (limitedClass.isAssignableFrom(serviceObject.getClass())) {
                collection.add(serviceObject);
            } else {
                if (log.isErrorEnabled()) {
                    log.error("?" + limited);
                }
                throw new ClassCastException(service.getClazz());
            }
        }
        return collection;
    }

    /**
     * <h3>Component</h3>
     * 
     * @param component
     *            Component?
     * @param cloneComponent
     *            Component
     * @param context
     *            ??Component?
     * @return
     * @throws KernelComponentDependerException
     */
    private Object cloneComponent(ServiceMetadata component, ComponentObject cloneComponent,
            ComponentContext context) throws KernelComponentDependerException {
        ComponentMetadata cloneComponentMetadata = cloneComponent.getComponentMetadate();
        Object componentObject = null;
        try {
            // ?Constructor?Constructor?
            ConstructorMetadata cloneConstructor = cloneComponentMetadata.getConstructor();
            if (cloneConstructor != null) {
                List<ServiceMetadata> oldConstructorServices = new ArrayList<ServiceMetadata>();
                int cloneServiceSize = cloneConstructor.getServices().size();
                int entrySize = component.getEntries().size();
                // ???Componentconstructorservice????
                if (cloneServiceSize == entrySize) {
                    int serviceIndex = 0;
                    List<ServiceMetadata> cloneConstructorServices = cloneConstructor.getServices();
                    this.copyCloneConstructorService(oldConstructorServices, cloneConstructorServices);// ?constructorservice
                    for (EntryMetadata entry : component.getEntries()) {
                        int eps = entry.getProperties().size();
                        List<PropertyMetadata> cloneServiceProperties = cloneConstructorServices.get(serviceIndex)
                                .getProperties();
                        List<EntryMetadata> cloneServiceEntries = cloneConstructorServices.get(serviceIndex)
                                .getEntries();
                        if (!cloneServiceProperties.isEmpty()) {// ?service?property
                            this.cloneServiceProperties(cloneServiceProperties, eps, entry);
                        } else if (!cloneServiceEntries.isEmpty()) {// ?service?entry
                            this.cloneServiceEntries(cloneServiceEntries, eps, entry);
                        }
                        serviceIndex++;
                    }
                }
                componentObject = injectConstructor(cloneComponentMetadata, context);
                // Component??
                this.restoreCloneComponent(cloneComponentMetadata, oldConstructorServices);
            } else {
                componentObject = ClassHandler.getClass(cloneComponentMetadata.getClazz(), true);
            }
            // ??
            for (ServiceMetadata service : cloneComponentMetadata.getServices()) {
                inject(componentObject, service, context);
            }
            // ??
            for (ServicesMetadata services : cloneComponentMetadata.getListService()) {
                injectList(componentObject, services, context);
            }
        } catch (Exception e) {
            throw new KernelComponentDependerException(e);
        }
        return componentObject;
    }

    /**
     * <h3>?constructorservice</h3> Component?Component??
     * 
     * @param oldConstructorServices
     * @param cloneConstructorServices
     */
    private void copyCloneConstructorService(List<ServiceMetadata> oldConstructorServices,
            List<ServiceMetadata> cloneConstructorServices) {
        for (ServiceMetadata oldServiceMetadata : cloneConstructorServices) {
            oldConstructorServices.add(oldServiceMetadata.cloneServiceMetadata());
        }
    }

    /**
     * <h3>Component?</h3>
     * 
     * @param cloneComponentMetadata
     * @param oldConstructorServices
     */
    private void restoreCloneComponent(ComponentMetadata cloneComponentMetadata,
            List<ServiceMetadata> oldConstructorServices) {
        for (int i = 0; i < oldConstructorServices.size(); i++) {
            cloneComponentMetadata.getConstructor().getServices().set(i, oldConstructorServices.get(i));
        }
    }

    /**
     * <h3>serviceentry??</h3>
     * 
     * @param cloneServiceEntries
     * @param eps
     * @param entry
     */
    private void cloneServiceEntries(List<EntryMetadata> cloneServiceEntries, int eps, EntryMetadata entry) {
        int propertyIndex = 0;
        int sps = 0;
        for (EntryMetadata serviceEntry : cloneServiceEntries) {
            sps += serviceEntry.getProperties().size();
        }
        // ?property?property???
        int nps = sps - eps >= 0 ? eps : sps;
        for (int entryIndex = 0; entryIndex < cloneServiceEntries.size(); entryIndex++) {
            List<PropertyMetadata> cloneEntryProperties = cloneServiceEntries.get(entryIndex).getProperties();
            for (int entryPropertyIndex = 0; entryPropertyIndex < cloneEntryProperties
                    .size(); entryPropertyIndex++) {
                if (propertyIndex < nps) {
                    PropertyMetadata newPM = entry.getProperties().get(propertyIndex);
                    cloneEntryProperties.set(entryPropertyIndex, newPM);
                } else {
                    return;
                }
                propertyIndex++;
            }
        }
    }

    /**
     * <h3>serviceproperty??</h3>
     * 
     * @param cloneServiceProperties
     * @param eps
     * @param entry
     */
    private void cloneServiceProperties(List<PropertyMetadata> cloneServiceProperties, int eps,
            EntryMetadata entry) {
        int propertyIndex = 0;
        int sps = cloneServiceProperties.size();
        // ?property?property???
        int nps = sps - eps >= 0 ? eps : sps;
        while (propertyIndex < nps) {
            cloneServiceProperties.set(propertyIndex, entry.getProperties().get(propertyIndex));
            propertyIndex++;
        }
    }
}