All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.sun.enterprise.config.modularity.ConfigModularityUtils Maven / Gradle / Ivy

There is a newer version: 7.2024.1.Alpha1
Show newest version
/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 *
 * Copyright (c) 2012-2013 Oracle and/or its affiliates. All rights reserved.
 *
 * The contents of this file are subject to the terms of either the GNU
 * General Public License Version 2 only ("GPL") or the Common Development
 * and Distribution License("CDDL") (collectively, the "License").  You
 * may not use this file except in compliance with the License.  You can
 * obtain a copy of the License at
 * https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html
 * or packager/legal/LICENSE.txt.  See the License for the specific
 * language governing permissions and limitations under the License.
 *
 * When distributing the software, include this License Header Notice in each
 * file and include the License file at packager/legal/LICENSE.txt.
 *
 * GPL Classpath Exception:
 * Oracle designates this particular file as subject to the "Classpath"
 * exception as provided by Oracle in the GPL Version 2 section of the License
 * file that accompanied this code.
 *
 * Modifications:
 * If applicable, add the following below the License Header, with the fields
 * enclosed by brackets [] replaced by your own identifying information:
 * "Portions Copyright [year] [name of copyright owner]"
 *
 * Contributor(s):
 * If you wish your version of this file to be governed by only the CDDL or
 * only the GPL Version 2, indicate your decision by adding "[Contributor]
 * elects to include this software in this distribution under the [CDDL or GPL
 * Version 2] license."  If you don't indicate a single choice of license, a
 * recipient has the option to distribute your version of this file under
 * either the CDDL, the GPL Version 2 or to extend the choice of license to
 * its licensees as provided above.  However, if you add GPL Version 2 code
 * and therefore, elected the GPL Version 2 license, then the option applies
 * only if the new code is made subject to such option by the copyright
 * holder.
 */
//Portions Copyright [2021] [Payara Foundation and/or affiliates]

package com.sun.enterprise.config.modularity;

import static com.sun.enterprise.config.util.ConfigApiLoggerInfo.*;

import com.sun.enterprise.config.modularity.annotation.CustomConfiguration;
import com.sun.enterprise.config.modularity.annotation.HasCustomizationTokens;
import com.sun.enterprise.config.modularity.customization.ConfigBeanDefaultValue;
import com.sun.enterprise.config.modularity.customization.ConfigCustomizationToken;
import com.sun.enterprise.config.modularity.parser.ConfigurationPopulator;
import com.sun.enterprise.config.modularity.parser.ModuleXMLConfigurationFileParser;
import com.sun.enterprise.config.serverbeans.Application;
import com.sun.enterprise.config.serverbeans.Applications;
import com.sun.enterprise.config.serverbeans.Config;
import com.sun.enterprise.config.serverbeans.Domain;
import com.sun.enterprise.config.serverbeans.Module;
import com.sun.enterprise.config.serverbeans.Resource;
import com.sun.enterprise.config.serverbeans.Server;
import com.sun.enterprise.config.serverbeans.SystemProperty;
import com.sun.enterprise.config.serverbeans.SystemPropertyBag;
import com.sun.enterprise.module.bootstrap.StartupContext;
import com.sun.enterprise.util.LocalStringManager;
import com.sun.enterprise.util.LocalStringManagerImpl;

import org.glassfish.api.admin.RuntimeType;
import org.glassfish.api.admin.ServerEnvironment;
import org.glassfish.api.admin.config.Named;
import org.glassfish.api.logging.LogHelper;
import org.glassfish.config.support.GlassFishConfigBean;
import org.glassfish.config.support.Singleton;
import org.glassfish.hk2.api.ActiveDescriptor;
import org.glassfish.hk2.api.ServiceLocator;
import org.glassfish.hk2.utilities.BuilderHelper;
import org.jvnet.hk2.annotations.Service;
import org.jvnet.hk2.config.Attribute;
import org.jvnet.hk2.config.ConfigBeanProxy;
import org.jvnet.hk2.config.ConfigInjector;
import org.jvnet.hk2.config.ConfigModel;
import org.jvnet.hk2.config.ConfigParser;
import org.jvnet.hk2.config.ConfigSupport;
import org.jvnet.hk2.config.ConfigView;
import org.jvnet.hk2.config.Configured;
import org.jvnet.hk2.config.Dom;
import org.jvnet.hk2.config.DomDocument;
import org.jvnet.hk2.config.DuckTyped;
import org.jvnet.hk2.config.IndentingXMLStreamWriter;
import org.jvnet.hk2.config.SingleConfigCode;
import org.jvnet.hk2.config.TransactionFailure;

import jakarta.inject.Inject;
import javax.xml.stream.XMLOutputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
import javax.xml.stream.XMLStreamWriter;

import java.beans.PropertyVetoException;
import java.io.BufferedOutputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Proxy;
import java.lang.reflect.Type;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import java.util.Properties;
import java.util.StringTokenizer;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * Contains utility methods for zero-config
 *
 * @author Masoud Kalali
 */
@Service
@Singleton
public final class ConfigModularityUtils {
    
    private static final Logger LOG = getLogger();

    @Inject
    private ServiceLocator serviceLocator;
    @Inject
    private StartupContext context;

    private boolean ignorePersisting = false;
    private boolean isCommandInvocation = false;

    public  URL getConfigurationFileUrl(Class configBeanClass, String baseFileName, String runtimeType) {
        //TODO can be optimized a little by checking the default file...
        String fileName = runtimeType + "-" + baseFileName;
        URL fileUrl = configBeanClass.getClassLoader().getResource("META-INF/configuration/" + fileName);
        if (fileUrl == null) {
            fileUrl = configBeanClass.getClassLoader().getResource("META-INF/configuration/" + baseFileName);
        }
        return fileUrl;
    }

    /**
     * If exists, locate and return a URL to the configuration snippet for the given config bean class.
     *
     * @param configBeanClass the config bean type we want to check for its configuration snippet
     * @return A url to the file or null of not exists
     */
    public List getDefaultConfigurations(Class configBeanClass, String runtimeType) {

        //Determine if it is DAS or instance
        CustomConfiguration c = (CustomConfiguration) configBeanClass.getAnnotation(CustomConfiguration.class);
        List defaults = Collections.emptyList();
        if (c.usesOnTheFlyConfigGeneration()) {
            Method m = getGetDefaultValuesMethod(configBeanClass);
            if (m != null) {
                try {
                    defaults = (List) m.invoke(null, runtimeType);
                } catch (Exception e) {
                    LogHelper.log(LOG, Level.INFO, cannotGetDefaultConfig, e,configBeanClass.getName());
                }
            }
        } else {
            //TODO properly handle the exceptions
            LocalStringManager localStrings =
                    new LocalStringManagerImpl(configBeanClass);
            ModuleXMLConfigurationFileParser parser = new ModuleXMLConfigurationFileParser(localStrings);
            try {
                defaults = parser.parseServiceConfiguration(getConfigurationFileUrl(configBeanClass, c.baseConfigurationFileName(), runtimeType).openStream());
            } catch (XMLStreamException e) {
                LOG.log(Level.SEVERE, cannotParseDefaultDefaultConfig, e);
            } catch (IOException e) {
                LOG.log(Level.SEVERE, cannotParseDefaultDefaultConfig, e);
            }
        }
        return defaults;
    }

    public boolean hasCustomConfig(Class configBeanClass) {
        return configBeanClass.getAnnotation(CustomConfiguration.class) != null;
    }

    /**
     * Find a getter method that returns a collection of the type we want to put set.
     *
     * @param owner     The class we want to search to find a method that returns a Collection typed with toSetType
     * @param typeToSet The type we want to find a matching collection fo
     * @return The Method that
     */
    public Method findSuitableCollectionGetter(Class owner, Class typeToSet) {
        Method[] methods = owner.getMethods();
        Method tm = returnException(owner, typeToSet);
        if (tm != null) return tm;
        for (Method m : methods) {
            if (m.getName().startsWith("get")) {
                Type t = m.getGenericReturnType();
                if (t instanceof ParameterizedType) {
                    ParameterizedType pt = (ParameterizedType) t;
                    Type actualGenericParameter = pt.getActualTypeArguments()[0];
                    if (pt.getActualTypeArguments().length == 1) {
                        if (Collection.class.isAssignableFrom(m.getReturnType())) {
                            if (actualGenericParameter instanceof Class) {
                                if (typeToSet.isAssignableFrom((Class) actualGenericParameter)) {
                                    if ((m.getAnnotation(DuckTyped.class) != null)) {
                                        return m;
                                    } else {
                                        Method deepM = findDeeperSuitableCollectionGetter(owner, typeToSet);
                                        return deepM != null ? deepM : m;
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
        return findDeeperSuitableCollectionGetter(owner, typeToSet);
    }

    private Method returnException(Class owner, Class typeToSet) {
        if (owner.isAssignableFrom(Applications.class) && (typeToSet.isAssignableFrom(Application.class)) || typeToSet.isAssignableFrom(Module.class)) {
            try {
                Method m = owner.getMethod("getModules");
                return m;
            } catch (NoSuchMethodException e) {
                LogHelper.log(LOG, Level.INFO, noMethodInReturnException, e, 
                        owner.getName(), typeToSet.getName());
            }
        }
        return null;
    }

    public Method findDeeperSuitableCollectionGetter(Class owner, Class typeToSet) {
        Class[] ifs = typeToSet.getInterfaces();
        Method[] methods = owner.getMethods();
        for (Method m : methods) {
            if (m.getName().startsWith("get")) {
                Type t = m.getGenericReturnType();
                if (t instanceof ParameterizedType) {
                    ParameterizedType pt = (ParameterizedType) t;
                    Type actualGenericParameter = pt.getActualTypeArguments()[0];
                    if (pt.getActualTypeArguments().length == 1) {
                        if (Collection.class.isAssignableFrom(m.getReturnType())) {
                            if (actualGenericParameter instanceof Class) {
                                if (checkInterfaces(ifs, actualGenericParameter)) {
                                    return m;
                                }
                            }
                        }
                    }
                }
            }
        }

        return null;
    }

    public boolean checkInterfaces(Class[] ifs, Type actualGenericParameter) {
        for (Class clz : ifs) {
            if (clz.getSimpleName().equals("ConfigBeanProxy") || clz.getSimpleName().equals("Injectable")
                    || clz.getSimpleName().equals("PropertyBag")) {
                continue;
            }
            if (actualGenericParameter instanceof Class && clz.isAssignableFrom((Class) actualGenericParameter)) {
                return true;
            }
        }
        return false;
    }

    public Class getOwningClassForLocation(String location) {
        StringTokenizer tokenizer = new StringTokenizer(location, "/", false);
        if (!tokenizer.hasMoreElements()) return null;
        if (!tokenizer.nextToken().equalsIgnoreCase("domain")) return null;
        String level = "domain";
        if (location.equalsIgnoreCase("domain/configs")) return getClassFor("domain");
        //It is a named config so we shall just return the config class
        if ((tokenizer.countTokens() == 2) && location.startsWith("domain/configs")) {
            return Config.class;
        }
        while (tokenizer.hasMoreElements()) {
            level = tokenizer.nextToken();
        }
        return getClassFor(level);
    }


    public ConfigBeanProxy getOwningObject(String location) {
        if (!location.startsWith("domain/configs")) {
            if (!location.startsWith("domain")) {
                //Sorry only know domain and below :D
                return null;
            }
            StringTokenizer tokenizer = new StringTokenizer(location, "/", false);
            //something directly inside the domain itself as we know one token is domain for sure
            if (tokenizer.countTokens() == 1) {
                return serviceLocator.getService(Domain.class);
            }
            location = location.substring(location.indexOf("/", "domain".length()) + 1);
            tokenizer = new StringTokenizer(location, "/", false);
            ConfigBeanProxy parent = serviceLocator.getService(Domain.class);

            //skipping the domain itself as a token, we know it and took it away.
            String parentElement = "domain";
            String childElement = null;
            while (tokenizer.hasMoreTokens()) {
                try {
                    childElement = tokenizer.nextToken();
                    parent = getOwner(parent, parentElement, childElement);
                    parentElement = childElement;
                } catch (Exception e) {
                    LogHelper.log(LOG, Level.INFO, cannotGetParentConfigBean, e, childElement);
                }
            }
            return parent;
        } else {
            Class typeToFindGetter = getOwningClassForLocation(location);
            if (typeToFindGetter == null) {
                return null;
            }

            //Check if config object is where the location or it goes deeper in the config layers.
            StringTokenizer tokenizer = new StringTokenizer(location, "/", false);
            //something directly inside the config itself
            if (tokenizer.countTokens() == 3) {
                String expression = location.substring(location.lastIndexOf('[') + 1, location.length() - 1);
                String configName = resolveExpression(expression);
                return serviceLocator.getService(Domain.class).getConfigNamed(configName);
            }

            location = location.substring(location.indexOf("/", "domain/configs".length()) + 1);
            tokenizer = new StringTokenizer(location, "/", false);
            String curLevel = tokenizer.nextToken();
            String expression;
            if (curLevel.contains("[")) {
                expression = curLevel.substring(curLevel.lastIndexOf('[') + 1, curLevel.length() - 1);
            } else {
                expression = curLevel;
            }

            String configName = resolveExpression(expression);
            ConfigBeanProxy parent = serviceLocator.getService(Domain.class).getConfigNamed(configName);

            String childElement;
            String parentElement = "Config";
            while (tokenizer.hasMoreTokens()) {
                try {
                    childElement = tokenizer.nextToken();
                    parent = getOwner(parent, parentElement, childElement);
                    parentElement = childElement;
                } catch (Exception e) {
                    LogHelper.log(LOG, Level.INFO, cannotGetParentConfigBean, e, configName);
                }
            }
            return parent;
        }
    }

    public ConfigBeanProxy getOwner(ConfigBeanProxy parent, String parentElement, String childElement) throws InvocationTargetException, IllegalAccessException {

        if (childElement.contains("CURRENT_INSTANCE_CONFIG_NAME")) {
            return serviceLocator.getService(Config.class, ServerEnvironment.DEFAULT_INSTANCE_NAME);
        }
        if (childElement.contains("CURRENT_INSTANCE_SERVER_NAME")) {
            return serviceLocator.getService(Server.class, ServerEnvironment.DEFAULT_INSTANCE_NAME);
        }
        if (childElement.endsWith("]")) {
            String componentName;
            String elementName;
            elementName = childElement.substring(childElement.lastIndexOf('/') + 1, childElement.indexOf('['));
            componentName = childElement.substring(childElement.lastIndexOf('[') + 1, childElement.indexOf(']'));
            Class childClass = getClassFor(elementName);
            Class parentClass = getClassFor(parentElement);
            Method m = findSuitableCollectionGetter(parentClass, childClass);
            if (m != null) {
                try {
                    Collection col = (Collection) m.invoke(parent);
                    componentName = resolveExpression(componentName);
                    return getNamedConfigBeanFromCollection(col, componentName, childClass);
                } catch (Exception e) {
                    LogHelper.log(LOG, Level.INFO, invalidPath, e, childElement,componentName);
                }
            }
            return null;
        } else {
            Class clz = getClassFor(childElement);
            if (parent == null) return null;
            Method m = getMatchingGetterMethod(parent.getClass(), clz);
            if (m != null) {
                return (ConfigBeanProxy) m.invoke(parent);
            } else {

                try {
                    m = parent.getClass().getMethod("getExtensionByType", java.lang.Class.class);
                } catch (NoSuchMethodException e) {
                    if (LOG.isLoggable(Level.FINE)) {
                        LOG.log(Level.FINE, "Cannot find getExtensionByType", e);
                    }
                }
                if (m != null) {
                    return (ConfigBeanProxy) m.invoke(parent, clz);
                }
                return null;
            }
        }
    }

    public  List getExtensions(ConfigBeanProxy parent) {

        Method m = null;
        try {
            if (parent != null) {
                m = parent.getClass().getMethod("getExtensions");
            }
        } catch (NoSuchMethodException e) {
        }
        if (m != null) {
            try {
                return (List) m.invoke(parent);
            } catch (Exception e) {

            }
        }
        return Collections.emptyList();
    }

    public  T setConfigBean(T finalConfigBean, ConfigBeanDefaultValue configBeanDefaultValue, ConfigBeanProxy parent) {
        Class owningClassForLocation = getOwningClassForLocation(configBeanDefaultValue.getLocation());
        Class configBeanClass = getClassForFullName(configBeanDefaultValue.getConfigBeanClassName());

        try {
            ConfigBeanProxy configBeanInstance = null;
            if (getNameForConfigBean(finalConfigBean, configBeanClass) == null) {
                List extensions = getExtensions(parent);
                for (ConfigBeanProxy extension : extensions) {
                    try {
                        configBeanInstance = (ConfigBeanProxy) configBeanClass.cast(extension);
                        break;
                    } catch (Exception e) {
                        // ignore, not the right type.
                    }
                }
                if (!configBeanDefaultValue.replaceCurrentIfExists() || !stackPositionHigher(finalConfigBean, configBeanInstance)) {
                    if (configBeanInstance != null) return (T) configBeanInstance;
                }
                if (configBeanInstance != null) {
                    extensions.remove(configBeanInstance);
                }
            }

        } catch (InvocationTargetException e) {
            LOG.log(Level.INFO, cannotSetConfigBean, e);
        } catch (IllegalAccessException e) {
            LOG.log(Level.INFO, cannotSetConfigBean, e);
        }

        Method m = getMatchingSetterMethod(owningClassForLocation, configBeanClass);
        if (m != null) {
            try {
                if (configBeanClass.getAnnotation(HasCustomizationTokens.class) != null) {
                    applyCustomTokens(configBeanDefaultValue, finalConfigBean, parent);
                }
                m.invoke(parent, finalConfigBean);
            } catch (Exception e) {
                LogHelper.log(LOG, Level.INFO, cannotSetConfigBeanFor, e, finalConfigBean.getClass().getName());
            }
            return finalConfigBean;
        }

        m = findSuitableCollectionGetter(owningClassForLocation, configBeanClass);
        if (m != null) {
            try {
                Collection col = (Collection) m.invoke(parent);
                String name = getNameForConfigBean(finalConfigBean, configBeanClass);
                ConfigBeanProxy itemToRemove = getNamedConfigBeanFromCollection(col, name, configBeanClass);
                if (configBeanDefaultValue.replaceCurrentIfExists()) {
                    try {
                        if (itemToRemove != null) {
                            if (stackPositionHigher(finalConfigBean, itemToRemove)) {
                                col.remove(itemToRemove);
                            }
                        }
                    } catch (Exception ex) {
                        LogHelper.log(LOG, Level.INFO, cannotRemoveConfigBean, ex, finalConfigBean.getClass().getName());
                    }
                }
                if (configBeanClass.getAnnotation(HasCustomizationTokens.class) != null) {
                    applyCustomTokens(configBeanDefaultValue, finalConfigBean, parent);
                }
                if (itemToRemove != null && !configBeanDefaultValue.replaceCurrentIfExists()) {
                    //Check for duplication here.
                    if (((ConfigView) Proxy.getInvocationHandler(itemToRemove)).getProxyType().isAssignableFrom(configBeanClass)) {
                        return finalConfigBean;
                    }
                }
                col.add(finalConfigBean);
                return finalConfigBean;
            } catch (Exception e) {
                LogHelper.log(LOG, Level.INFO, cannotSetConfigBeanFor, e, finalConfigBean.getClass().getName());
            }
        }
        return null;
    }

    public  boolean stackPositionHigher(T finalConfigBean, ConfigBeanProxy itemToRemove) {
        if (itemToRemove == null || finalConfigBean == null) return true;
        if (RankedConfigBeanProxy.class.isAssignableFrom(finalConfigBean.getClass()) && RankedConfigBeanProxy.class.isAssignableFrom(itemToRemove.getClass())) {
            int itemToRemoveRank = Integer.parseInt(((RankedConfigBeanProxy) itemToRemove).getRank());
            int finalConfigBeanRank = Integer.parseInt(((RankedConfigBeanProxy) finalConfigBean).getRank());
            return finalConfigBeanRank > itemToRemoveRank;
        } else {
            return true;
        }

    }

    public synchronized  void applyCustomTokens(final ConfigBeanDefaultValue configBeanDefaultValue,
                                                                           T finalConfigBean, ConfigBeanProxy parent)
            throws TransactionFailure, PropertyVetoException {
        //go up in the parents tree till meet someone ImplementingSystemProperty
        //then that is the freaking parent, get it and set the SystemProperty :D
        if (parent instanceof SystemPropertyBag) {
            addSystemPropertyForToken(configBeanDefaultValue.getCustomizationTokens(), (SystemPropertyBag) parent);
        } else {
            ConfigBeanProxy curParent = finalConfigBean;
            while (!(curParent instanceof SystemPropertyBag)) {
                curParent = curParent.getParent();
            }
            if (configBeanDefaultValue.getCustomizationTokens().size() != 0) {
                final boolean oldIP = isIgnorePersisting();
                try {
                    setIgnorePersisting(true);
                    final SystemPropertyBag bag = (SystemPropertyBag) curParent;
                    final List tokens = configBeanDefaultValue.getCustomizationTokens();
                    ConfigSupport.apply(new SingleConfigCode() {
                        public Object run(SystemPropertyBag param) throws PropertyVetoException, TransactionFailure {
                            addSystemPropertyForToken(tokens, bag);
                            return param;
                        }
                    }, bag);
                } finally {
                    setIgnorePersisting(oldIP);
                }
            }
        }
    }

    public void addSystemPropertyForToken(List tokens, SystemPropertyBag bag)
            throws TransactionFailure, PropertyVetoException {
        for (ConfigCustomizationToken token : tokens) {
            if (!bag.containsProperty(token.getName())) {
                SystemProperty prop = bag.createChild(SystemProperty.class);
                prop.setName(token.getName());
                prop.setDescription(token.getDescription());
                prop.setValue(token.getValue());
                bag.getSystemProperty().add(prop);
            }
        }
    }

    public  T getCurrentConfigBeanForDefaultValue(ConfigBeanDefaultValue defaultValue)
            throws InvocationTargetException, IllegalAccessException {
        //TODO make this method target aware!
        Class parentClass = getOwningClassForLocation(defaultValue.getLocation());
        Class configBeanClass = getClassForFullName(defaultValue.getConfigBeanClassName());
        Method m = findSuitableCollectionGetter(parentClass, configBeanClass);
        if (m != null) {
            ConfigParser configParser = new ConfigParser(serviceLocator);
            // I don't use the GlassFish document here as I don't need persistence
            final DomDocument doc = new DomDocument(serviceLocator) {
                @Override
                public Dom make(final ServiceLocator serviceLocator, XMLStreamReader xmlStreamReader, GlassFishConfigBean dom,
                                ConfigModel configModel) {
                    // by default, people get the translated view.
                    return new GlassFishConfigBean(serviceLocator, this, dom, configModel, xmlStreamReader);
                }
            };

            ConfigBeanProxy parent = getOwningObject(defaultValue.getLocation());
            ConfigurationPopulator populator = new ConfigurationPopulator(defaultValue.getXmlConfiguration(), doc, parent);
            populator.run(configParser);
            ConfigBeanProxy configBean = doc.getRoot().createProxy(configBeanClass);
            Collection col = (Collection) m.invoke(parent);
            return (T) getConfigBeanFromCollection(col, configBean, configBeanClass);

        }
        return null;
    }

    public  T getConfigBeanFromCollection(Collection col, T configBeanObject,
                                                                     Class typeOfObjects)
            throws InvocationTargetException, IllegalAccessException {
        String nameToLookFor = getNameForConfigBean(configBeanObject, typeOfObjects);
        if (nameToLookFor != null) {
            T returnee = getNamedConfigBeanFromCollection(col, nameToLookFor, typeOfObjects);
            if (returnee != null) return returnee;
        } else {
            for (T configBean : col) {
                try {
                    typeOfObjects.cast(configBean);
                    return configBean;
                } catch (Exception ex) {
                    //ignore it
                }
            }
        }
        return null;
    }

    public  T getNamedConfigBeanFromCollection(Collection col,
                                                                          String nameToLookFor,
                                                                          Class typeOfObjects)
            throws InvocationTargetException, IllegalAccessException {
        if (nameToLookFor == null) return null;
        for (Object item : col) {
            if (!((ConfigView) Proxy.getInvocationHandler(item)).getProxyType().isAssignableFrom(typeOfObjects)) {
                continue;
            }
            String name = getNameForConfigBean(item, typeOfObjects);
            if (nameToLookFor.equalsIgnoreCase(name)) {
                return (T) item;
            }
        }
        return null;
    }

    public String getNameForConfigBean(Object configBean, Class configBeanType) throws InvocationTargetException, IllegalAccessException {
        if (configBean instanceof Named) {
            Named nme = (Named) configBean;
            return nme.getName();
        }
        if (configBean instanceof Resource) {
            Resource res = (Resource) configBean;
            return res.getIdentity();
        }
        Method[] methods = configBeanType.getMethods();
        for (Method method : methods) {
            Attribute attributeAnnotation = method.getAnnotation(Attribute.class);
            if ((attributeAnnotation != null) && attributeAnnotation.key()) {
                return (String) method.invoke(configBean);
            }
        }
        return null;
    }

    /**
     * convert a configuration element name to representing class name
     *
     * @param name the configuration element name we want to convert to class name
     * @return the class name which the configuration element represent.
     */
    public String convertConfigElementNameToClassName(String name) {
        // first, trim off the prefix
        StringTokenizer tokenizer = new StringTokenizer(name, "-", false);
        StringBuilder className = new StringBuilder();

        while (tokenizer.hasMoreTokens()) {
            String part = tokenizer.nextToken();
            Locale loc = Locale.getDefault();
            part = part.replaceFirst(part.substring(0, 1), part.substring(0, 1).toUpperCase(loc));
            className.append(part);

        }
        return className.toString();
    }


    public Class getClassFor(String serviceName) {
        serviceName = getServiceTypeNameIfNamedComponent(serviceName);
        ConfigInjector injector = serviceLocator.getService(ConfigInjector.class, serviceName.toLowerCase(Locale.getDefault()));
        return getClassFromInjector(injector);
    }

    public Class getClassFromInjector(ConfigInjector injector) {
        if (injector != null) {
            String clzName = injector.getClass().getName().substring(0, injector.getClass().getName().length() - 8);
            try {
                return injector.getClass().getClassLoader().loadClass(clzName);
            } catch (ClassNotFoundException e) {
                return null;
            }
        }
        return null;
    }

    public String getServiceTypeNameIfNamedComponent(String serviceName) {
        if (serviceName.endsWith("]")) {
            serviceName = serviceName.substring(0, serviceName.indexOf('['));
        }
        return serviceName;
    }

    public String resolveExpression(String expression) {
        if (expression.startsWith("$")) {
            String name = expression.substring(1, expression.length());
            if (name.equalsIgnoreCase("CURRENT_INSTANCE_CONFIG_NAME")) {
                expression = serviceLocator.getService(Config.class, ServerEnvironment.DEFAULT_INSTANCE_NAME).getName();
            }
            if (name.equalsIgnoreCase("CURRENT_INSTANCE_SERVER_NAME")) {
                expression = serviceLocator.getService(Server.class, ServerEnvironment.DEFAULT_INSTANCE_NAME).getName();
            }
        }
        return expression;
    }

    public String serializeConfigBeanByType(Class configBeanType) {
        ConfigBeanProxy configBeanProxy = getConfigBeanInstanceFor(configBeanType);
        return serializeConfigBean(configBeanProxy);
    }

    public ConfigBeanProxy getConfigBeanInstanceFor(Class configBeanType) {
        return (ConfigBeanProxy) serviceLocator.getService(configBeanType);
    }

    public String serializeConfigBean(ConfigBeanProxy configBean) {
        if (configBean == null) return null;
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        XMLOutputFactory xmlFactory = XMLOutputFactory.newInstance();
        XMLStreamWriter writer = null;
        IndentingXMLStreamWriter indentingXMLStreamWriter = null;
        String s = null;
        try {
            writer = xmlFactory.createXMLStreamWriter(new BufferedOutputStream(bos));
            indentingXMLStreamWriter = new IndentingXMLStreamWriter(writer);
            Dom configBeanDom = Dom.unwrap(configBean);
            configBeanDom.writeTo(configBeanDom.model.getTagName(), indentingXMLStreamWriter);
            indentingXMLStreamWriter.flush();
            s = bos.toString();
        } catch (XMLStreamException e) {
            if (LOG.isLoggable(Level.FINE)) {
                LOG.log(Level.FINE, "Cannot serialize the configbean: " + configBean.toString(), e);
            }
            return null;
        } finally {
            try {
                if (bos != null)
                    bos.close();
                if (writer != null)
                    writer.close();
                if (indentingXMLStreamWriter != null)
                    indentingXMLStreamWriter.close();
            } catch (IOException e) {
                if (LOG.isLoggable(Level.FINE)) {
                    LOG.log(Level.FINE, "Cannot serialize the configbean: " + configBean.toString(), e);
                }
            } catch (XMLStreamException e) {
                if (LOG.isLoggable(Level.FINE)) {
                    LOG.log(Level.FINE, "Cannot serialize the configbean: " + configBean.toString(), e);
                }
            }

        }
        return s;
    }

    /**
     * Find a suitable getter method in the given class. the returned method represent a method that will return back a type of  methodReturnType.
     *
     * @param classToQuery     The class we want to find the getter in
     * @param methodReturnType the type we want to find the getter for
     * @return A Method object for a getter method in the classToQuery  which returns the    methodReturnType
     */
    public Method getMatchingGetterMethod(Class classToQuery, Class methodReturnType) {
        Method[] methods = classToQuery.getMethods();
        for (Method method : methods) {
            Class rt = method.getReturnType();
            if (rt != null && methodReturnType != null) {
                if (rt.getSimpleName().equals(methodReturnType.getSimpleName())) {
                    return method;
                }
            }
        }
        return null;
    }

    /**
     * Finds and return the setter method matching the class identified by   typeToSet
     *
     * @param classToQuery The ConfigLoader we want to inspect for presence of a setter method accepting class of type fqcn.
     * @param typeToSet    the type we want to find a setter for
     * @return the matching Method object or null if not present.
     */
    public Method getMatchingSetterMethod(Class classToQuery, Class typeToSet) {
        String className = typeToSet.getName().substring(typeToSet.getName().lastIndexOf(".") + 1, typeToSet.getName().length());
        String setterName = "set" + className;
        Method[] methods = classToQuery.getClass().getMethods();
        for (Method method : methods) {
            if (method.getName().equalsIgnoreCase(setterName)) {
                return method;
            }
        }
        return null;
    }


    public Class getDuckClass(Class configBeanType) {
        Class duck;
        final Class[] clz = configBeanType.getDeclaredClasses();
        for (Class aClz : clz) {
            duck = aClz;
            if (duck.getSimpleName().equals("Duck")) {
                return duck;
            }
        }
        return null;
    }

    public Method getGetDefaultValuesMethod(Class configBeanType) {
        Class duck = getDuckClass(configBeanType);
        if (duck == null) {
            return null;
        }
        Method m;
        try {
            m = duck.getMethod("getDefaultValues", String.class);
        } catch (Exception ex) {
            return null;
        }
        return m;
    }

    public boolean deleteConfigurationForConfigBean(ConfigBeanProxy configBean, Collection col, ConfigBeanDefaultValue defaultValue) {
        String name;
        ConfigBeanProxy itemToRemove;
        try {
            Class configBeanClass = getClassForFullName(defaultValue.getConfigBeanClassName());
            name = getNameForConfigBean(configBean, configBeanClass);
            itemToRemove = getNamedConfigBeanFromCollection(col, name, configBeanClass);
            if (itemToRemove != null) {
                col.remove(itemToRemove);
                return true;
            }
            if (name == null) {
                col.remove(configBean);
                return true;
            }
        } catch (Exception ex) {
            return false;
        }
        return false;
    }

    public Class getClassForFullName(String configBeanClassName) {
        ActiveDescriptor descriptor = serviceLocator.getBestDescriptor(BuilderHelper.createContractFilter(configBeanClassName));
        if (descriptor != null) {
            if (!descriptor.isReified()) {
                descriptor = serviceLocator.reifyDescriptor(descriptor);
            }
            return getClassFromDescriptor(descriptor);
        } else {
            descriptor = serviceLocator.getBestDescriptor(BuilderHelper.createContractFilter(configBeanClassName + "Injector"));
            if (!descriptor.isReified()) {
                descriptor = serviceLocator.reifyDescriptor(descriptor);
            }
            ConfigInjector injector = (ConfigInjector) serviceLocator.getServiceHandle(descriptor).getService();
            return getClassFromInjector(injector);
        }
    }

    public Class getClassFromDescriptor(ActiveDescriptor descriptor) {

        Class defaultReturnValue = descriptor.getImplementationClass();

        String name = descriptor.getName();
        if (name == null) return defaultReturnValue;

        Class foundContract = null;
        for (Type contract : descriptor.getContractTypes()) {
            if (!(contract instanceof Class)) continue;

            Class cc = (Class) contract;
            if (cc.getName().equals(name)) {
                foundContract = cc;
                break;
            }
        }

        if (foundContract == null) return defaultReturnValue;
        return foundContract;
    }

    public String replacePropertiesWithCurrentValue(String xmlConfiguration, ConfigBeanDefaultValue value) throws InvocationTargetException, IllegalAccessException {
        for (ConfigCustomizationToken token : value.getCustomizationTokens()) {
            String toReplace = "${" + token.getName() + "}";
            ConfigBeanProxy current = getCurrentConfigBeanForDefaultValue(value);
            String propertyValue = getPropertyValue(token, current);
            if (propertyValue != null) {
                xmlConfiguration = xmlConfiguration.replace(toReplace, propertyValue);
            }
        }
        return xmlConfiguration;
    }


    public String getPropertyValue(ConfigCustomizationToken token, ConfigBeanProxy finalConfigBean) {
        if (finalConfigBean != null) {
            ConfigBeanProxy parent = finalConfigBean.getParent();
            while (!(parent instanceof SystemPropertyBag)) {
                parent = parent.getParent();
                if (parent == null) return null;
            }
            if (((SystemPropertyBag) parent).getSystemProperty(token.getName()) != null) {
                return ((SystemPropertyBag) parent).getSystemProperty(token.getName()).getValue();
            }
            return null;
        } else return token.getValue();
    }


    public String getRuntimeTypePrefix(StartupContext startupContext) {
        Properties args = startupContext.getArguments();
        RuntimeType serverType = RuntimeType.getDefault();
        String typeString = args.getProperty("-type");
        if (typeString != null)
            serverType = RuntimeType.valueOf(typeString);
        if (LOG.isLoggable(Level.FINE)) {
            LOG.fine("server type is: " + serverType.name());
        }
        if (serverType.isEmbedded()) return "embedded";
        if (serverType.isSingleInstance() || serverType.isDas()) return "admin";
        if (serverType.isInstance()) return "instance";
        return "";
    }


    public List getAnnotatedConfigBeans(Class annotationType) {
        List prox = new ArrayList();
        List> descriptor = serviceLocator.getDescriptors(BuilderHelper.createContractFilter(ConfigInjector.class.getName()));
        Class clz = null;
        for (ActiveDescriptor desc : descriptor) {
            if (desc.getName() == null) {
                continue;
            }
            ConfigInjector injector = serviceLocator.getService(ConfigInjector.class, desc.getName());
            if (injector != null) {
                String clzName = injector.getClass().getName().substring(0, injector.getClass().getName().length() - 8);
                if (clzName == null) {
                    continue;
                }
                try {
                    clz = injector.getClass().getClassLoader().loadClass(clzName);
                    if (clz == null) {
                        if (LOG.isLoggable(Level.FINE)) {
                            LOG.log(Level.FINE, "Cannot find the class mapping to:  " + clzName);
                        }
                        continue;
                    }
                } catch (Throwable e) {
                    if (LOG.isLoggable(Level.FINE)) {
                        LOG.log(Level.FINE, "Cannot load the class", e);
                    }
                    continue;
                }
            }
            if (clz != null) {
                if (clz.isAnnotationPresent(annotationType)) {
                    prox.add(clz);
                }
            }
        }
        return prox;
    }

    public boolean isIgnorePersisting() {
        return ignorePersisting;
    }

    public void setIgnorePersisting(boolean ignorePersisting) {
        this.ignorePersisting = ignorePersisting;
    }

    public boolean isCommandInvocation() {
        return isCommandInvocation;
    }

    public void setCommandInvocation(boolean commandInvocation) {
        isCommandInvocation = commandInvocation;
    }

    public List getInstalledExtensions(Class extensionType) {
        List extensions = new ArrayList();
        List cbeans = getAnnotatedConfigBeans(Configured.class);

        for (Class c : cbeans) {
            try {
                if (c.asSubclass(extensionType) != null && c != extensionType) {
                    extensions.add(c);
                }
            } catch (ClassCastException e) {
                continue;
            }
        }
        return extensions;
    }
}