blob: 83bd05731f96afc3a9ffe2eb63d2d9c944d1f254 [file] [log] [blame]
/*
* 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;
}
}