| /* |
| * Copyright (c) 2012, 2018 Oracle and/or its affiliates. All rights reserved. |
| * |
| * This program and the accompanying materials are made available under the |
| * terms of the Eclipse Public License v. 2.0, which is available at |
| * http://www.eclipse.org/legal/epl-2.0. |
| * |
| * This Source Code may also be made available under the following Secondary |
| * Licenses when the conditions for such availability set forth in the |
| * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, |
| * version 2 with the GNU Classpath Exception, which is available at |
| * https://www.gnu.org/software/classpath/license.html. |
| * |
| * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 |
| */ |
| |
| 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 <U extends ConfigBeanProxy> URL getConfigurationFileUrl(Class<U> 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<ConfigBeanDefaultValue> getDefaultConfigurations(Class configBeanClass, String runtimeType) { |
| |
| //Determine if it is DAS or instance |
| CustomConfiguration c = (CustomConfiguration) configBeanClass.getAnnotation(CustomConfiguration.class); |
| List<ConfigBeanDefaultValue> defaults = Collections.emptyList(); |
| if (c.usesOnTheFlyConfigGeneration()) { |
| Method m = getGetDefaultValuesMethod(configBeanClass); |
| if (m != null) { |
| try { |
| defaults = (List<ConfigBeanDefaultValue>) 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.<Domain>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.<Domain>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.<Config>getService(Config.class, ServerEnvironment.DEFAULT_INSTANCE_NAME); |
| } |
| if (childElement.contains("CURRENT_INSTANCE_SERVER_NAME")) { |
| return serviceLocator.<Server>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 <U extends ConfigBeanProxy> List<U> getExtensions(ConfigBeanProxy parent) { |
| |
| Method m = null; |
| try { |
| if (parent != null) { |
| m = parent.getClass().getMethod("getExtensions"); |
| } |
| } catch (NoSuchMethodException e) { |
| } |
| if (m != null) { |
| try { |
| return (List<U>) m.invoke(parent); |
| } catch (Exception e) { |
| |
| } |
| } |
| return Collections.emptyList(); |
| } |
| |
| public <T extends ConfigBeanProxy> 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<ConfigBeanProxy> 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 <T extends ConfigBeanProxy> 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 <T extends ConfigBeanProxy> 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<ConfigCustomizationToken> tokens = configBeanDefaultValue.getCustomizationTokens(); |
| ConfigSupport.apply(new SingleConfigCode<SystemPropertyBag>() { |
| public Object run(SystemPropertyBag param) throws PropertyVetoException, TransactionFailure { |
| addSystemPropertyForToken(tokens, bag); |
| return param; |
| } |
| }, bag); |
| } finally { |
| setIgnorePersisting(oldIP); |
| } |
| } |
| } |
| } |
| |
| public void addSystemPropertyForToken(List<ConfigCustomizationToken> 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 extends ConfigBeanProxy> 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<GlassFishConfigBean>(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 extends ConfigBeanProxy> T getConfigBeanFromCollection(Collection<T> 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 extends ConfigBeanProxy> T getNamedConfigBeanFromCollection(Collection<T> 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.<Config>getService(Config.class, ServerEnvironment.DEFAULT_INSTANCE_NAME).getName(); |
| } |
| if (name.equalsIgnoreCase("CURRENT_INSTANCE_SERVER_NAME")) { |
| expression = serviceLocator.<Server>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 { |
| 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<Class> getAnnotatedConfigBeans(Class annotationType) { |
| List<Class> prox = new ArrayList<Class>(); |
| List<ActiveDescriptor<?>> 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); |
| 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<Class> getInstalledExtensions(Class extensionType) { |
| List<Class> extensions = new ArrayList(); |
| List<Class> cbeans = getAnnotatedConfigBeans(Configured.class); |
| |
| for (Class c : cbeans) { |
| try { |
| if (c != extensionType) { |
| extensions.add(c); |
| } |
| } catch (ClassCastException e) { |
| continue; |
| } |
| } |
| return extensions; |
| } |
| } |