mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-07-31 17:39:05 +00:00
MOB-864: Propagation of installation / dev environment settings to subsystems plus subsystem framework extensions for composite properties
- Set of overridable properties now centralized to new global-properties bean and referenced by repository-properties, hibernateConfigProperties and subsystems - Installer defaults can now be specified in classpath:alfresco-global.properties - A special BeanFactoryPostProcessor ensures backward compatibility with existing alfresco/extension/*-context.xml files overriding repository-properties or hibernateConfigProperties. - Subsystems pick up initial property values from global-properties. Placeholders expanded. - Messages now output when subsystems stopped and started - Object names lists to allow better hierarchical organisation - Composite properties now supported by child application contexts - Materialized in context.xml as ListFactoryBeans - lists of beans - Configured values injected before application context started - Configurable via alfresco-global.properties or JMX git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@14351 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
@@ -24,37 +24,76 @@
|
||||
*/
|
||||
package org.alfresco.repo.management.subsystems;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.BeanNameAware;
|
||||
import org.springframework.beans.factory.DisposableBean;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextAware;
|
||||
import org.springframework.context.ApplicationEvent;
|
||||
import org.springframework.context.ApplicationListener;
|
||||
import org.springframework.context.event.ContextRefreshedEvent;
|
||||
|
||||
/**
|
||||
* A base class for {@link PropertyBackedBean}s. Gets its category from its Spring bean name and automatically destroys
|
||||
* itself on server shutdown. Communicates its creation and destruction to a {@link PropertyBackedBeanRegistry}.
|
||||
* A base class for {@link PropertyBackedBean}s. Gets its category from its Spring bean name and automatically
|
||||
* propagates and resolves property defaults on initialization. Automatically destroys itself on server shutdown.
|
||||
* Communicates its creation and destruction to a {@link PropertyBackedBeanRegistry}.
|
||||
*
|
||||
* @author dward
|
||||
*/
|
||||
public abstract class AbstractPropertyBackedBean implements PropertyBackedBean, InitializingBean, DisposableBean,
|
||||
BeanNameAware
|
||||
public abstract class AbstractPropertyBackedBean implements PropertyBackedBean, ApplicationContextAware,
|
||||
ApplicationListener, InitializingBean, DisposableBean, BeanNameAware
|
||||
{
|
||||
|
||||
/** The default ID. */
|
||||
protected static final String DEFAULT_ID = "default";
|
||||
/** The root component of the default ID. */
|
||||
protected static final String DEFAULT_ID_ROOT = "default";
|
||||
|
||||
/** The registry. */
|
||||
/** The default ID (when we do not expect there to be more than one instance within a category). */
|
||||
protected static final List<String> DEFAULT_ID = Collections
|
||||
.singletonList(AbstractPropertyBackedBean.DEFAULT_ID_ROOT);
|
||||
|
||||
/** The parent application context. */
|
||||
private ApplicationContext parent;
|
||||
|
||||
/** The registry of all property backed beans. */
|
||||
private PropertyBackedBeanRegistry registry;
|
||||
|
||||
/** The id. */
|
||||
private String id = DEFAULT_ID;
|
||||
/** The hierarchical id. Must be unique within the category. */
|
||||
private List<String> id = AbstractPropertyBackedBean.DEFAULT_ID;
|
||||
|
||||
/** The category. */
|
||||
private String category;
|
||||
|
||||
/** Should the application context be started on startup of the parent application?. */
|
||||
private boolean autoStart;
|
||||
|
||||
/** Property defaults provided by the installer or System properties. */
|
||||
private Properties propertyDefaults;
|
||||
|
||||
/** Resolves placeholders in the property defaults. */
|
||||
private DefaultResolver defaultResolver = new DefaultResolver();
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.context.ApplicationContextAware#setApplicationContext(org.springframework.context.
|
||||
* ApplicationContext)
|
||||
*/
|
||||
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException
|
||||
{
|
||||
this.parent = applicationContext;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the registry.
|
||||
* Sets the registry of all property backed beans.
|
||||
*
|
||||
* @param registry
|
||||
* the registry to set
|
||||
* the registry of all property backed beans
|
||||
*/
|
||||
public void setRegistry(PropertyBackedBeanRegistry registry)
|
||||
{
|
||||
@@ -62,13 +101,13 @@ public abstract class AbstractPropertyBackedBean implements PropertyBackedBean,
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the registry.
|
||||
* Gets the registry of all property backed beans.
|
||||
*
|
||||
* @return the registry
|
||||
* @return the registry of all property backed beans
|
||||
*/
|
||||
public PropertyBackedBeanRegistry getRegistry()
|
||||
protected PropertyBackedBeanRegistry getRegistry()
|
||||
{
|
||||
return registry;
|
||||
return this.registry;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -86,17 +125,87 @@ public abstract class AbstractPropertyBackedBean implements PropertyBackedBean,
|
||||
* @param id
|
||||
* the id to set
|
||||
*/
|
||||
public void setId(String id)
|
||||
public void setId(List<String> id)
|
||||
{
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates whether the bean should be started on startup of the parent application context.
|
||||
*
|
||||
* @param autoStart
|
||||
* <code>true</code> if the bean should be started on startup of the parent application context
|
||||
*/
|
||||
public void setAutoStart(boolean autoStart)
|
||||
{
|
||||
this.autoStart = autoStart;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the property defaults provided by the installer or System properties.
|
||||
*
|
||||
* @param propertyDefaults
|
||||
* the property defaults
|
||||
*/
|
||||
public void setPropertyDefaults(Properties propertyDefaults)
|
||||
{
|
||||
this.propertyDefaults = propertyDefaults;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the property defaults provided by the installer or System properties.
|
||||
*
|
||||
* @return the property defaults
|
||||
*/
|
||||
protected Properties getPropertyDefaults()
|
||||
{
|
||||
return this.propertyDefaults;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves the default value of a property, if there is one, expanding placholders as necessary.
|
||||
*
|
||||
* @param name
|
||||
* the property name
|
||||
* @return the resolved default value or <code>null</code> if there isn't one
|
||||
*/
|
||||
protected String resolveDefault(String name)
|
||||
{
|
||||
String value = this.propertyDefaults.getProperty(name);
|
||||
if (value != null)
|
||||
{
|
||||
value = this.defaultResolver.resolveValue(value);
|
||||
}
|
||||
return value == null || value.length() == 0 ? null : value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the parent application context.
|
||||
*
|
||||
* @return the parent application context
|
||||
*/
|
||||
protected ApplicationContext getParent()
|
||||
{
|
||||
return this.parent;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
|
||||
*/
|
||||
public void afterPropertiesSet() throws Exception
|
||||
{
|
||||
// Override default settings using corresponding global defaults (this allows installer settings
|
||||
// to propagate through)
|
||||
for (String property : getPropertyNames())
|
||||
{
|
||||
String value = resolveDefault(property);
|
||||
if (value != null)
|
||||
{
|
||||
setProperty(property, value);
|
||||
}
|
||||
}
|
||||
|
||||
this.registry.register(this);
|
||||
}
|
||||
|
||||
@@ -104,7 +213,7 @@ public abstract class AbstractPropertyBackedBean implements PropertyBackedBean,
|
||||
* (non-Javadoc)
|
||||
* @see org.alfresco.repo.management.SelfDescribingBean#getId()
|
||||
*/
|
||||
public String getId()
|
||||
public List<String> getId()
|
||||
{
|
||||
return this.id;
|
||||
}
|
||||
@@ -145,4 +254,56 @@ public abstract class AbstractPropertyBackedBean implements PropertyBackedBean,
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.alfresco.repo.management.subsystems.PropertyBackedBean#getDescription(java.lang.String)
|
||||
*/
|
||||
public String getDescription(String name)
|
||||
{
|
||||
return isUpdateable(name) ? "Editable Property " + name : "Read-only Property " + name;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see
|
||||
* org.springframework.context.ApplicationListener#onApplicationEvent(org.springframework.context.ApplicationEvent)
|
||||
*/
|
||||
public void onApplicationEvent(ApplicationEvent event)
|
||||
{
|
||||
if (this.autoStart && event instanceof ContextRefreshedEvent && event.getSource() == this.parent)
|
||||
{
|
||||
start();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Uses a Spring {@link PropertyPlaceholderConfigurer} to resolve placeholders in the property defaults. This means
|
||||
* that placeholders need not be displayed in the configuration UI or JMX console.
|
||||
*/
|
||||
public class DefaultResolver extends PropertyPlaceholderConfigurer
|
||||
{
|
||||
|
||||
/**
|
||||
* Instantiates a new default resolver.
|
||||
*/
|
||||
public DefaultResolver()
|
||||
{
|
||||
setIgnoreUnresolvablePlaceholders(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Expands the given value, resolving any ${} placeholders using the property defaults
|
||||
*
|
||||
* @param val
|
||||
* the value to expand
|
||||
* @return the expanded value
|
||||
*/
|
||||
public String resolveValue(String val)
|
||||
{
|
||||
return AbstractPropertyBackedBean.this.propertyDefaults == null ? null : parseStringValue(val,
|
||||
AbstractPropertyBackedBean.this.propertyDefaults, new HashSet<Object>());
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@@ -25,25 +25,32 @@
|
||||
package org.alfresco.repo.management.subsystems;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.Set;
|
||||
import java.util.StringTokenizer;
|
||||
import java.util.TreeMap;
|
||||
import java.util.TreeSet;
|
||||
|
||||
import org.alfresco.config.JBossEnabledResourcePatternResolver;
|
||||
import org.alfresco.config.JndiPropertiesFactoryBean;
|
||||
import org.alfresco.repo.imap.config.ImapConfigBean;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.BeanNameAware;
|
||||
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
|
||||
import org.springframework.beans.factory.config.BeanPostProcessor;
|
||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||
import org.springframework.beans.factory.config.ListFactoryBean;
|
||||
import org.springframework.beans.factory.config.PropertiesFactoryBean;
|
||||
import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextAware;
|
||||
import org.springframework.context.ApplicationEvent;
|
||||
import org.springframework.context.ApplicationListener;
|
||||
import org.springframework.context.event.ContextRefreshedEvent;
|
||||
import org.springframework.context.support.ClassPathXmlApplicationContext;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.core.io.support.ResourcePatternResolver;
|
||||
|
||||
/**
|
||||
@@ -56,56 +63,102 @@ import org.springframework.core.io.support.ResourcePatternResolver;
|
||||
* The factory will search for a Spring application context in the classpath using the following patterns in order:
|
||||
* <ul>
|
||||
* <li>alfresco/subsystems/<category>/<typeName>/*-context.xml</li>
|
||||
* <li>alfresco/extension/subsystems/<category>/<typeName>/<id/*-context.xml</li>
|
||||
* <li>alfresco/extension/subsystems/<category>/<typeName>/<id>/*-context.xml</li>
|
||||
* </ul>
|
||||
* The child application context may use <code>${}</code> placeholders, and will be configured with a
|
||||
* {@link PropertyPlaceholderConfigurer} initialised with properties files found in classpath matching the following
|
||||
* {@link PropertyPlaceholderConfigurer} initialized with properties files found in classpath matching the following
|
||||
* patterns in order:
|
||||
* <ul>
|
||||
* <li>alfresco/subsystems/<category>/<typeName>/*.properties</li>
|
||||
* <li>alfresco/extension/subsystems/<category>/<typeName>/<id/*.properties</li>
|
||||
* <li>alfresco/extension/subsystems/<category>/<typeName>/<id>/*.properties</li>
|
||||
* </ul>
|
||||
* This means that the extension classpath can be used to provide instance-specific overrides to product default
|
||||
* settings. Of course, if you are using the Enterprise edition, you might want to use a JMX client such as JConsole to
|
||||
* edit the settings instead!
|
||||
* <p>
|
||||
* For advanced purposes, the class also allows management of 'composite' properties, that is properties that can be
|
||||
* populated with a sequence of zero or more objects, themselves registered as property-backed beans. Using the
|
||||
* <code>compositePropertyTypes</code> property you can register a Map of property names to Java Bean classes. Each
|
||||
* property named in this map will then be materialized as a 'composite' property.
|
||||
* <p>
|
||||
* Composite property settings are best controlled either through a JMX console (Enterprise edition only) or
|
||||
* /alfresco-global.properties in the classpath (the replacement to /alfresco/extension/custom-repository.properties).
|
||||
* For example, suppose "imap.server.mountPoints" was registered as a composite property of type {@link ImapConfigBean}.
|
||||
* You can then use the property to configure a list of {@link ImapConfigBean}s. First you specify in the property's
|
||||
* value a list of zero or more 'instance names'. Each name must be unique within the property.
|
||||
* <p>
|
||||
* <code>imap.server.mountPoints=Repository_virtual,Repository_archive</code>
|
||||
* <p>
|
||||
* Then, by magic you have two separate instances of {@link ImapConfigBean} whose properties you can address through an
|
||||
* extended set of properties prefixed by "imap.server.mountPoints".
|
||||
* <p>
|
||||
* To set a property on one of the instances, you append ".value.<instance name>.<bean property name>" to the
|
||||
* parent property name. For example:
|
||||
* <p>
|
||||
* <code>imap.server.mountPoints.value.Repository_virtual.mode=virtual</code>
|
||||
* <p>
|
||||
* To specify a default value for a property on all instances of the bean, you append ".default.<bean property name>"
|
||||
* to the parent property name. For example:
|
||||
* <p>
|
||||
* <code>imap.server.mountPoints.default.store=${spaces.store}</code>
|
||||
* <p>
|
||||
* Note that it's perfectly valid to use placeholders in property values that will be resolved from other global
|
||||
* properties.
|
||||
* <p>
|
||||
* In order to actually utilize this configurable list of beans in your child application context, you simply need to
|
||||
* declare a {@link ListFactoryBean} whose ID is the same name as the property. For example:
|
||||
*
|
||||
* <pre>
|
||||
* <bean id="imap.server.mountPoints" class="org.springframework.beans.factory.config.ListFactoryBean">
|
||||
* <property name="sourceList">
|
||||
* <!-- Whatever you declare in here will get replaced by the property value list -->
|
||||
* </property>
|
||||
* </bean>
|
||||
* </pre>
|
||||
*
|
||||
* Then, when the application context is started and before that bean is initialized, it will be given the current
|
||||
* configured list of values for the composite property. Magic! This all sounds like a complex, yet primitive
|
||||
* replacement for Spring, but it means you can do powerful things to reconfigure the system through an admin UI rather
|
||||
* than editing XML.
|
||||
*
|
||||
* @author dward
|
||||
*/
|
||||
public class ChildApplicationContextFactory extends AbstractPropertyBackedBean implements ApplicationContextAware,
|
||||
ApplicationListener, ApplicationContextFactory
|
||||
public class ChildApplicationContextFactory extends AbstractPropertyBackedBean implements ApplicationContextFactory
|
||||
{
|
||||
|
||||
/** The name of the special read-only property containing the type name. */
|
||||
private static final String TYPE_NAME_PROPERTY = "$type";
|
||||
|
||||
/** The Constant PROPERTIES_SUFFIX. */
|
||||
/** The suffix to the property file search path. */
|
||||
private static final String PROPERTIES_SUFFIX = "/*.properties";
|
||||
|
||||
/** The Constant CONTEXT_SUFFIX. */
|
||||
/** The suffix to the context file search path. */
|
||||
private static final String CONTEXT_SUFFIX = "/*-context.xml";
|
||||
|
||||
/** The Constant CLASSPATH_PREFIX. */
|
||||
/** The prefix to default file search paths. */
|
||||
private static final String CLASSPATH_PREFIX = "classpath*:alfresco/subsystems/";
|
||||
|
||||
/** The Constant EXTENSION_CLASSPATH_PREFIX. */
|
||||
/** The prefix to extension file search paths. */
|
||||
private static final String EXTENSION_CLASSPATH_PREFIX = "classpath*:alfresco/extension/subsystems/";
|
||||
|
||||
/** The logger. */
|
||||
private static Log logger = LogFactory.getLog(ChildApplicationContextFactory.class);
|
||||
|
||||
/** The parent. */
|
||||
private ApplicationContext parent;
|
||||
|
||||
/** The properties. */
|
||||
/** The properties to be used in placeholder expansion. */
|
||||
private Properties properties;
|
||||
|
||||
/** The application context. */
|
||||
/** The child application context. */
|
||||
private ClassPathXmlApplicationContext applicationContext;
|
||||
|
||||
/** The auto start. */
|
||||
private boolean autoStart;
|
||||
|
||||
/** The type name. */
|
||||
private String typeName;
|
||||
|
||||
/** The registered composite propertes and their types. */
|
||||
private Map<String, Class<?>> compositePropertyTypes = Collections.emptyMap();
|
||||
|
||||
/** The composite property values. */
|
||||
private Map<String, Map<String, CompositeDataBean>> compositeProperties = new TreeMap<String, Map<String, CompositeDataBean>>();
|
||||
|
||||
/**
|
||||
* Default constructor for container construction.
|
||||
*/
|
||||
@@ -120,6 +173,8 @@ public class ChildApplicationContextFactory extends AbstractPropertyBackedBean i
|
||||
* the parent application context
|
||||
* @param registry
|
||||
* the registry of property backed beans
|
||||
* @param propertyDefaults
|
||||
* property defaults provided by the installer or System properties
|
||||
* @param category
|
||||
* the category
|
||||
* @param typeName
|
||||
@@ -130,10 +185,11 @@ public class ChildApplicationContextFactory extends AbstractPropertyBackedBean i
|
||||
* Signals that an I/O exception has occurred.
|
||||
*/
|
||||
public ChildApplicationContextFactory(ApplicationContext parent, PropertyBackedBeanRegistry registry,
|
||||
String category, String typeName, String id) throws IOException
|
||||
Properties propertyDefaults, String category, String typeName, List<String> id) throws IOException
|
||||
{
|
||||
setApplicationContext(parent);
|
||||
setRegistry(registry);
|
||||
setPropertyDefaults(propertyDefaults);
|
||||
setBeanName(category);
|
||||
setTypeName(typeName);
|
||||
setId(id);
|
||||
@@ -152,28 +208,6 @@ public class ChildApplicationContextFactory extends AbstractPropertyBackedBean i
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.context.ApplicationContextAware#setApplicationContext(org.springframework.context.
|
||||
* ApplicationContext)
|
||||
*/
|
||||
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException
|
||||
{
|
||||
this.parent = applicationContext;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates whether the application context be started on startup of the parent application context.
|
||||
*
|
||||
* @param autoStart
|
||||
* <code>true</code> if the application context should be started on startup of the parent application
|
||||
* context
|
||||
*/
|
||||
public void setAutoStart(boolean autoStart)
|
||||
{
|
||||
this.autoStart = autoStart;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the type name.
|
||||
*
|
||||
@@ -195,6 +229,19 @@ public class ChildApplicationContextFactory extends AbstractPropertyBackedBean i
|
||||
return this.typeName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a set of composite propertes and their types.
|
||||
*
|
||||
* @param compositePropertyTypes
|
||||
* a map of property names to Java classes. The classes should follow standard Java Bean conventions. If
|
||||
* the class implements {@link BeanNameAware} the instance name will be propagated to the
|
||||
* <code>beanName</code> property automatically.
|
||||
*/
|
||||
public void setCompositePropertyTypes(Map<String, Class<?>> compositePropertyTypes)
|
||||
{
|
||||
this.compositePropertyTypes = compositePropertyTypes;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
|
||||
@@ -204,38 +251,31 @@ public class ChildApplicationContextFactory extends AbstractPropertyBackedBean i
|
||||
{
|
||||
if (getTypeName() == null)
|
||||
{
|
||||
setTypeName(getId());
|
||||
setTypeName(getId().get(0));
|
||||
}
|
||||
|
||||
// Load the property defaults
|
||||
PropertiesFactoryBean factory = new PropertiesFactoryBean();
|
||||
|
||||
Resource[] baseResources = this.parent.getResources(ChildApplicationContextFactory.CLASSPATH_PREFIX
|
||||
+ getCategory() + '/' + getTypeName() + ChildApplicationContextFactory.PROPERTIES_SUFFIX);
|
||||
// Allow overrides from the extension classpath
|
||||
Resource[] extensionResources = this.parent
|
||||
.getResources(ChildApplicationContextFactory.EXTENSION_CLASSPATH_PREFIX + getCategory() + '/'
|
||||
+ getTypeName() + '/' + getId() + '/' + ChildApplicationContextFactory.PROPERTIES_SUFFIX);
|
||||
Resource[] combinedResources;
|
||||
if (baseResources.length == 0)
|
||||
{
|
||||
combinedResources = extensionResources;
|
||||
}
|
||||
else if (extensionResources.length == 0)
|
||||
{
|
||||
combinedResources = baseResources;
|
||||
}
|
||||
else
|
||||
{
|
||||
combinedResources = new Resource[baseResources.length + extensionResources.length];
|
||||
System.arraycopy(baseResources, 0, combinedResources, 0, baseResources.length);
|
||||
System.arraycopy(extensionResources, 0, combinedResources, baseResources.length, extensionResources.length);
|
||||
}
|
||||
factory.setLocations(combinedResources);
|
||||
factory.setLocations(getParent().getResources(
|
||||
ChildApplicationContextFactory.CLASSPATH_PREFIX + getCategory() + '/' + getTypeName()
|
||||
+ ChildApplicationContextFactory.PROPERTIES_SUFFIX));
|
||||
factory.afterPropertiesSet();
|
||||
this.properties = (Properties) factory.getObject();
|
||||
|
||||
// Now let the superclass propagate default settings from the global properties and register us
|
||||
super.afterPropertiesSet();
|
||||
|
||||
// Apply any property overrides from the extension classpath and also allow system properties and JNDI to
|
||||
// override
|
||||
JndiPropertiesFactoryBean overrideFactory = new JndiPropertiesFactoryBean();
|
||||
overrideFactory.setSystemPropertiesMode(PropertyPlaceholderConfigurer.SYSTEM_PROPERTIES_MODE_OVERRIDE);
|
||||
overrideFactory.setLocations(getParent().getResources(
|
||||
ChildApplicationContextFactory.EXTENSION_CLASSPATH_PREFIX + getCategory() + '/' + getTypeName() + '/'
|
||||
+ getId() + '/' + ChildApplicationContextFactory.PROPERTIES_SUFFIX));
|
||||
overrideFactory.setProperties(this.properties);
|
||||
overrideFactory.afterPropertiesSet();
|
||||
this.properties = (Properties) overrideFactory.getObject();
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -247,6 +287,7 @@ public class ChildApplicationContextFactory extends AbstractPropertyBackedBean i
|
||||
{
|
||||
Set<String> result = new TreeSet<String>(((Map) this.properties).keySet());
|
||||
result.add(ChildApplicationContextFactory.TYPE_NAME_PROPERTY);
|
||||
result.addAll(this.compositePropertyTypes.keySet());
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -260,6 +301,24 @@ public class ChildApplicationContextFactory extends AbstractPropertyBackedBean i
|
||||
{
|
||||
return getTypeName();
|
||||
}
|
||||
else if (this.compositePropertyTypes.containsKey(name))
|
||||
{
|
||||
Map<String, CompositeDataBean> beans = this.compositeProperties.get(name);
|
||||
if (beans != null)
|
||||
{
|
||||
StringBuilder list = new StringBuilder(100);
|
||||
for (String id : beans.keySet())
|
||||
{
|
||||
if (list.length() > 0)
|
||||
{
|
||||
list.append(',');
|
||||
}
|
||||
list.append(id);
|
||||
}
|
||||
return list.toString();
|
||||
}
|
||||
return "";
|
||||
}
|
||||
else
|
||||
{
|
||||
return this.properties.getProperty(name);
|
||||
@@ -278,7 +337,12 @@ public class ChildApplicationContextFactory extends AbstractPropertyBackedBean i
|
||||
throw new IllegalStateException("Illegal write to property \""
|
||||
+ ChildApplicationContextFactory.TYPE_NAME_PROPERTY + "\"");
|
||||
}
|
||||
if (value == null)
|
||||
Class<?> type = this.compositePropertyTypes.get(name);
|
||||
if (type != null)
|
||||
{
|
||||
updateCompositeProperty(name, value, type);
|
||||
}
|
||||
else if (value == null)
|
||||
{
|
||||
this.properties.remove(name);
|
||||
}
|
||||
@@ -288,6 +352,79 @@ public class ChildApplicationContextFactory extends AbstractPropertyBackedBean i
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates a composite property with a new list of instance names. Properties of those instances that existed
|
||||
* previously will be preserved. Instances that no longer exist will be destroyed. New instances will be brought
|
||||
* into life with default values, as described in the class description.
|
||||
*
|
||||
* @param name
|
||||
* the composite property name
|
||||
* @param value
|
||||
* a list of bean instance IDs
|
||||
* @param type
|
||||
* the bean class
|
||||
*/
|
||||
private void updateCompositeProperty(String name, String value, Class<?> type)
|
||||
{
|
||||
// Retrieve the map of existing values of this property
|
||||
Map<String, CompositeDataBean> propertyValues = this.compositeProperties.get(name);
|
||||
if (propertyValues == null)
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
propertyValues = Collections.emptyMap();
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
Map<String, CompositeDataBean> newPropertyValues = new LinkedHashMap<String, CompositeDataBean>(11);
|
||||
if (value != null)
|
||||
{
|
||||
StringTokenizer tkn = new StringTokenizer(value, ", \t\n\r\f");
|
||||
while (tkn.hasMoreTokens())
|
||||
{
|
||||
String id = tkn.nextToken();
|
||||
|
||||
// Generate a unique ID within the category
|
||||
List<String> childId = new ArrayList<String>(3);
|
||||
childId.addAll(getId());
|
||||
childId.add(name);
|
||||
childId.add(id);
|
||||
|
||||
// Look out for new or updated children
|
||||
CompositeDataBean child = propertyValues.get(id);
|
||||
|
||||
if (child == null)
|
||||
{
|
||||
child = new CompositeDataBean(getParent(), this, getRegistry(), getPropertyDefaults(),
|
||||
getCategory(), type, childId);
|
||||
}
|
||||
newPropertyValues.put(id, child);
|
||||
}
|
||||
}
|
||||
|
||||
// Destroy any children that have been removed
|
||||
Set<String> idsToRemove = new TreeSet<String>(propertyValues.keySet());
|
||||
idsToRemove.removeAll(newPropertyValues.keySet());
|
||||
for (String id : idsToRemove)
|
||||
{
|
||||
CompositeDataBean child = propertyValues.get(id);
|
||||
child.destroy(true);
|
||||
}
|
||||
this.compositeProperties.put(name, newPropertyValues);
|
||||
}
|
||||
catch (RuntimeException e)
|
||||
{
|
||||
throw e;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.alfresco.repo.management.subsystems.AbstractPropertyBackedBean#isUpdateable(java.lang.String)
|
||||
@@ -299,47 +436,33 @@ public class ChildApplicationContextFactory extends AbstractPropertyBackedBean i
|
||||
return !name.equals(ChildApplicationContextFactory.TYPE_NAME_PROPERTY);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.alfresco.repo.management.subsystems.AbstractPropertyBackedBean#getDescription(java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public String getDescription(String name)
|
||||
{
|
||||
return name.equals(ChildApplicationContextFactory.TYPE_NAME_PROPERTY) ? "Read-only subsystem type name"
|
||||
: this.compositePropertyTypes.containsKey(name) ? "Comma separated list of child object names" : super
|
||||
.getDescription(name);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.alfresco.repo.management.subsystems.PropertyBackedBean#start()
|
||||
*/
|
||||
public synchronized void start()
|
||||
{
|
||||
this.applicationContext = new ClassPathXmlApplicationContext(new String[]
|
||||
// This is where we actually create and start a child application context based on the configured properties.
|
||||
if (this.applicationContext == null)
|
||||
{
|
||||
ChildApplicationContextFactory.CLASSPATH_PREFIX + getCategory() + '/' + getTypeName()
|
||||
+ ChildApplicationContextFactory.CONTEXT_SUFFIX,
|
||||
ChildApplicationContextFactory.EXTENSION_CLASSPATH_PREFIX + getCategory() + '/' + getTypeName() + '/'
|
||||
+ getId() + '/' + ChildApplicationContextFactory.CONTEXT_SUFFIX
|
||||
}, false, this.parent)
|
||||
{
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.context.support.AbstractApplicationContext#getResourcePatternResolver()
|
||||
*/
|
||||
@Override
|
||||
protected ResourcePatternResolver getResourcePatternResolver()
|
||||
{
|
||||
return new JBossEnabledResourcePatternResolver(this);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
// Add a property placeholder configurer, with the subsystem-scoped default properties
|
||||
PropertyPlaceholderConfigurer configurer = new PropertyPlaceholderConfigurer();
|
||||
configurer.setProperties(this.properties);
|
||||
configurer.setIgnoreUnresolvablePlaceholders(true);
|
||||
this.applicationContext.addBeanFactoryPostProcessor(configurer);
|
||||
|
||||
// Add all the post processors of the parent, e.g. to make sure system placeholders get expanded properly
|
||||
for (Object postProcessor : this.parent.getBeansOfType(BeanFactoryPostProcessor.class).values())
|
||||
{
|
||||
this.applicationContext.addBeanFactoryPostProcessor((BeanFactoryPostProcessor) postProcessor);
|
||||
ChildApplicationContextFactory.logger.info("Starting '" + getCategory() + "' subsystem, ID: " + getId());
|
||||
this.applicationContext = new ChildApplicationContext();
|
||||
this.applicationContext.refresh();
|
||||
ChildApplicationContextFactory.logger.info("Startup of '" + getCategory() + "' subsystem, ID: " + getId()
|
||||
+ " complete");
|
||||
}
|
||||
|
||||
this.applicationContext.setClassLoader(this.parent.getClassLoader());
|
||||
this.applicationContext.refresh();
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -350,8 +473,29 @@ public class ChildApplicationContextFactory extends AbstractPropertyBackedBean i
|
||||
{
|
||||
if (this.applicationContext != null)
|
||||
{
|
||||
ChildApplicationContextFactory.logger.info("Stopping '" + getCategory() + "' subsystem, ID: " + getId());
|
||||
this.applicationContext.close();
|
||||
this.applicationContext = null;
|
||||
ChildApplicationContextFactory.logger.info("Stopped '" + getCategory() + "' subsystem, ID: " + getId());
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.alfresco.repo.management.subsystems.AbstractPropertyBackedBean#destroy(boolean)
|
||||
*/
|
||||
@Override
|
||||
public void destroy(boolean permanent)
|
||||
{
|
||||
super.destroy(permanent);
|
||||
|
||||
// Cascade the destroy / shutdown
|
||||
for (Map<String, CompositeDataBean> beans : this.compositeProperties.values())
|
||||
{
|
||||
for (CompositeDataBean bean : beans.values())
|
||||
{
|
||||
bean.destroy(permanent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -361,24 +505,104 @@ public class ChildApplicationContextFactory extends AbstractPropertyBackedBean i
|
||||
*/
|
||||
public synchronized ApplicationContext getApplicationContext()
|
||||
{
|
||||
if (this.applicationContext == null)
|
||||
{
|
||||
start();
|
||||
}
|
||||
start();
|
||||
return this.applicationContext;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see
|
||||
* org.springframework.context.ApplicationListener#onApplicationEvent(org.springframework.context.ApplicationEvent)
|
||||
/**
|
||||
* A specialized application context class with the power to propagate simple and composite property values into
|
||||
* beans before they are initialized.
|
||||
*
|
||||
* @author dward
|
||||
*/
|
||||
public void onApplicationEvent(ApplicationEvent event)
|
||||
private class ChildApplicationContext extends ClassPathXmlApplicationContext
|
||||
{
|
||||
// Automatically refresh the application context on boot up, if required
|
||||
if (this.autoStart && event instanceof ContextRefreshedEvent && event.getSource() == this.parent)
|
||||
|
||||
/**
|
||||
* The Constructor.
|
||||
*
|
||||
* @throws BeansException
|
||||
* the beans exception
|
||||
*/
|
||||
private ChildApplicationContext() throws BeansException
|
||||
{
|
||||
getApplicationContext();
|
||||
super(new String[]
|
||||
{
|
||||
ChildApplicationContextFactory.CLASSPATH_PREFIX + getCategory() + '/' + getTypeName()
|
||||
+ ChildApplicationContextFactory.CONTEXT_SUFFIX,
|
||||
ChildApplicationContextFactory.EXTENSION_CLASSPATH_PREFIX + getCategory() + '/' + getTypeName() + '/'
|
||||
+ getId() + '/' + ChildApplicationContextFactory.CONTEXT_SUFFIX
|
||||
}, false, ChildApplicationContextFactory.this.getParent());
|
||||
|
||||
// Add a property placeholder configurer, with the subsystem-scoped default properties
|
||||
PropertyPlaceholderConfigurer configurer = new PropertyPlaceholderConfigurer();
|
||||
configurer.setProperties(ChildApplicationContextFactory.this.properties);
|
||||
configurer.setIgnoreUnresolvablePlaceholders(true);
|
||||
addBeanFactoryPostProcessor(configurer);
|
||||
|
||||
// Add all the post processors of the parent, e.g. to make sure system placeholders get expanded properly
|
||||
for (Object postProcessor : getParent().getBeansOfType(BeanFactoryPostProcessor.class).values())
|
||||
{
|
||||
addBeanFactoryPostProcessor((BeanFactoryPostProcessor) postProcessor);
|
||||
}
|
||||
|
||||
setClassLoader(ChildApplicationContextFactory.this.getParent().getClassLoader());
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.context.support.AbstractApplicationContext#getResourcePatternResolver()
|
||||
*/
|
||||
@Override
|
||||
protected ResourcePatternResolver getResourcePatternResolver()
|
||||
{
|
||||
// Ensure we can resolve resourced on JBoss 5
|
||||
return new JBossEnabledResourcePatternResolver(this);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see
|
||||
* org.springframework.context.support.AbstractApplicationContext#postProcessBeanFactory(org.springframework
|
||||
* .beans.factory.config.ConfigurableListableBeanFactory)
|
||||
*/
|
||||
@Override
|
||||
protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)
|
||||
{
|
||||
// Propagate composite properties to list factories of the corresponding name
|
||||
beanFactory.addBeanPostProcessor(new BeanPostProcessor()
|
||||
{
|
||||
|
||||
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException
|
||||
{
|
||||
return bean;
|
||||
}
|
||||
|
||||
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException
|
||||
{
|
||||
if (bean instanceof ListFactoryBean
|
||||
&& ChildApplicationContextFactory.this.compositePropertyTypes.containsKey(beanName))
|
||||
{
|
||||
Map<String, CompositeDataBean> beans = ChildApplicationContextFactory.this.compositeProperties
|
||||
.get(beanName);
|
||||
List<Object> beanList;
|
||||
if (beans != null)
|
||||
{
|
||||
beanList = new ArrayList<Object>(beans.size());
|
||||
for (CompositeDataBean wrapped : beans.values())
|
||||
{
|
||||
beanList.add(wrapped.getBean());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
beanList = Collections.emptyList();
|
||||
}
|
||||
((ListFactoryBean) bean).setSourceList(beanList);
|
||||
}
|
||||
return bean;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1,247 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2009 Alfresco Software Limited.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
* As a special exception to the terms and conditions of version 2.0 of
|
||||
* the GPL, you may redistribute this Program in connection with Free/Libre
|
||||
* and Open Source Software ("FLOSS") applications as described in Alfresco's
|
||||
* FLOSS exception. You should have received a copy of the text describing
|
||||
* the FLOSS exception, and it is also available here:
|
||||
* http://www.alfresco.com/legal/licensing"
|
||||
*/
|
||||
package org.alfresco.repo.management.subsystems;
|
||||
|
||||
import java.beans.PropertyDescriptor;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
import java.util.Set;
|
||||
import java.util.TreeSet;
|
||||
|
||||
import org.springframework.beans.BeanWrapper;
|
||||
import org.springframework.beans.BeanWrapperImpl;
|
||||
import org.springframework.beans.factory.BeanNameAware;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
|
||||
/**
|
||||
* A class that wraps an instance of a Java Bean class declared as a composite property type on
|
||||
* {@link ChildApplicationContextFactory} making it configurable, either through alfresco-global.properties or a JMX
|
||||
* console.
|
||||
*
|
||||
* @see ChildApplicationContextFactory
|
||||
* @author dward
|
||||
*/
|
||||
public class CompositeDataBean extends AbstractPropertyBackedBean
|
||||
{
|
||||
/** The owning bean */
|
||||
private final PropertyBackedBean owner;
|
||||
|
||||
/** The Java bean instance. */
|
||||
private final Object bean;
|
||||
|
||||
/** A Spring wrapper around the Java bean, allowing easy configuration of properties. */
|
||||
private final BeanWrapper wrappedBean;
|
||||
|
||||
/** The property names. */
|
||||
private final Set<String> propertyNames;
|
||||
|
||||
/** The writeable properties. */
|
||||
private final Set<String> writeableProperties;
|
||||
|
||||
/** The prefix used to look up default values for this bean's properties */
|
||||
private String defaultKeyPrefix;
|
||||
|
||||
/** The prefix used to look up instance-specific default values for this bean's properties */
|
||||
private String instanceKeyPrefix;
|
||||
|
||||
/**
|
||||
* Constructor for dynamically created instances, e.g. through {@link ChildApplicationContextFactory}.
|
||||
*
|
||||
* @param parent
|
||||
* the parent application context
|
||||
* @param registry
|
||||
* the registry of property backed beans
|
||||
* @param propertyDefaults
|
||||
* property defaults provided by the installer or System properties
|
||||
* @param category
|
||||
* the category
|
||||
* @param id
|
||||
* the instance id
|
||||
* @param owner
|
||||
* the owning bean
|
||||
* @param type
|
||||
* the class of Java bean to be wrapped
|
||||
* @throws IOException
|
||||
* Signals that an I/O exception has occurred.
|
||||
*/
|
||||
public CompositeDataBean(ApplicationContext parent, PropertyBackedBean owner, PropertyBackedBeanRegistry registry,
|
||||
Properties propertyDefaults, String category, Class<?> type, List<String> id) throws IOException
|
||||
{
|
||||
setApplicationContext(parent);
|
||||
setRegistry(registry);
|
||||
setPropertyDefaults(propertyDefaults);
|
||||
setBeanName(category);
|
||||
setId(id);
|
||||
this.owner = owner;
|
||||
|
||||
try
|
||||
{
|
||||
this.bean = type.newInstance();
|
||||
// Tell the bean its name if it cares
|
||||
if (this.bean instanceof BeanNameAware)
|
||||
{
|
||||
((BeanNameAware) this.bean).setBeanName(id.get(id.size() - 1));
|
||||
}
|
||||
this.wrappedBean = new BeanWrapperImpl(this.bean);
|
||||
PropertyDescriptor[] descriptors = this.wrappedBean.getPropertyDescriptors();
|
||||
this.propertyNames = new TreeSet<String>();
|
||||
this.writeableProperties = new TreeSet<String>();
|
||||
for (PropertyDescriptor descriptor : descriptors)
|
||||
{
|
||||
Method readMethod = descriptor.getReadMethod();
|
||||
if (readMethod != null)
|
||||
{
|
||||
if (readMethod.getDeclaringClass().isAssignableFrom(Object.class))
|
||||
{
|
||||
// Ignore Object properties such as class
|
||||
continue;
|
||||
}
|
||||
this.propertyNames.add(descriptor.getName());
|
||||
if (descriptor.getWriteMethod() != null)
|
||||
{
|
||||
this.writeableProperties.add(descriptor.getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
afterPropertiesSet();
|
||||
}
|
||||
catch (RuntimeException e)
|
||||
{
|
||||
throw e;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.alfresco.repo.management.subsystems.AbstractPropertyBackedBean#afterPropertiesSet()
|
||||
*/
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception
|
||||
{
|
||||
// Derive a default and instance key prefix of the form "<parent>.default." and "<parent>.value.<this>."
|
||||
StringBuilder defaultKeyPrefixBuff = new StringBuilder(200);
|
||||
StringBuilder instanceKeyPrefixBuff = new StringBuilder(200);
|
||||
List<String> id = getId();
|
||||
int size = id.size();
|
||||
if (size > 1)
|
||||
{
|
||||
defaultKeyPrefixBuff.append(id.get(size - 2)).append('.');
|
||||
instanceKeyPrefixBuff.append(defaultKeyPrefixBuff);
|
||||
}
|
||||
defaultKeyPrefixBuff.append("default.");
|
||||
instanceKeyPrefixBuff.append("value.").append(id.get(size - 1)).append('.');
|
||||
|
||||
this.defaultKeyPrefix = defaultKeyPrefixBuff.toString();
|
||||
this.instanceKeyPrefix = instanceKeyPrefixBuff.toString();
|
||||
|
||||
// Set initial values according to property defaults.
|
||||
super.afterPropertiesSet();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.alfresco.repo.management.subsystems.AbstractPropertyBackedBean#resolveDefault(java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
protected String resolveDefault(String name)
|
||||
{
|
||||
// Because we may have multiple instances, we try an instance-specific default before falling back to a general
|
||||
// property level default
|
||||
String value = super.resolveDefault(this.instanceKeyPrefix + name);
|
||||
return value == null ? super.resolveDefault(this.defaultKeyPrefix + name) : value;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.alfresco.repo.management.subsystems.PropertyBackedBean#getProperty(java.lang.String)
|
||||
*/
|
||||
public String getProperty(String name)
|
||||
{
|
||||
Object value = this.wrappedBean.getPropertyValue(name);
|
||||
return value == null ? null : value.toString();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.alfresco.repo.management.subsystems.PropertyBackedBean#getPropertyNames()
|
||||
*/
|
||||
public Set<String> getPropertyNames()
|
||||
{
|
||||
return this.propertyNames;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.alfresco.repo.management.subsystems.PropertyBackedBean#setProperty(java.lang.String, java.lang.String)
|
||||
*/
|
||||
public void setProperty(String name, String value)
|
||||
{
|
||||
this.wrappedBean.setPropertyValue(name, value);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.alfresco.repo.management.subsystems.AbstractPropertyBackedBean#isUpdateable(java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public boolean isUpdateable(String name)
|
||||
{
|
||||
return this.writeableProperties.contains(name);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.alfresco.repo.management.subsystems.PropertyBackedBean#start()
|
||||
*/
|
||||
public void start()
|
||||
{
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.alfresco.repo.management.subsystems.PropertyBackedBean#stop()
|
||||
*/
|
||||
public void stop()
|
||||
{
|
||||
// Ensure any edits to child composites cause the parent to be shut down and subsequently re-initialized
|
||||
this.owner.stop();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the wrapped Java bean.
|
||||
*
|
||||
* @return the Java bean
|
||||
*/
|
||||
protected Object getBean()
|
||||
{
|
||||
return this.bean;
|
||||
}
|
||||
}
|
@@ -34,12 +34,7 @@ import java.util.StringTokenizer;
|
||||
import java.util.TreeMap;
|
||||
import java.util.TreeSet;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextAware;
|
||||
import org.springframework.context.ApplicationEvent;
|
||||
import org.springframework.context.ApplicationListener;
|
||||
import org.springframework.context.event.ContextRefreshedEvent;
|
||||
|
||||
/**
|
||||
* A default {@link ChildApplicationContextManager} implementation that manages a 'chain' of
|
||||
@@ -54,20 +49,17 @@ import org.springframework.context.event.ContextRefreshedEvent;
|
||||
* this property is editable at runtime via JMX. If a new <id> is included in the list then a new
|
||||
* {@link ChildApplicationContextFactory} will be brought into existence. Similarly, if one is removed from the list,
|
||||
* then the corresponding instance will be destroyed. For Alfresco community edition, the chain is best configured
|
||||
* through the {@link #setDefaultChain(String)} method via Spring configuration.
|
||||
* through the {@link #setChain(String)} method via Spring configuration.
|
||||
*
|
||||
* @author dward
|
||||
*/
|
||||
public class DefaultChildApplicationContextManager extends AbstractPropertyBackedBean implements
|
||||
ApplicationContextAware, ApplicationListener, ChildApplicationContextManager
|
||||
ChildApplicationContextManager
|
||||
{
|
||||
|
||||
/** The name of the special property that holds the ordering of child instance names. */
|
||||
private static final String ORDER_PROPERTY = "chain";
|
||||
|
||||
/** The parent. */
|
||||
private ApplicationContext parent;
|
||||
|
||||
/** The default type name. */
|
||||
private String defaultTypeName;
|
||||
|
||||
@@ -80,25 +72,12 @@ public class DefaultChildApplicationContextManager extends AbstractPropertyBacke
|
||||
/** The child application contexts. */
|
||||
private Map<String, ChildApplicationContextFactory> childApplicationContexts = new TreeMap<String, ChildApplicationContextFactory>();
|
||||
|
||||
/** The auto start. */
|
||||
private boolean autoStart;
|
||||
|
||||
/**
|
||||
* Instantiates a new default child application context manager.
|
||||
*/
|
||||
public DefaultChildApplicationContextManager()
|
||||
{
|
||||
setId("manager");
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.context.ApplicationContextAware#setApplicationContext(org.springframework.context.
|
||||
* ApplicationContext)
|
||||
*/
|
||||
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException
|
||||
{
|
||||
this.parent = applicationContext;
|
||||
setId(Collections.singletonList("manager"));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -127,18 +106,6 @@ public class DefaultChildApplicationContextManager extends AbstractPropertyBacke
|
||||
this.defaultChain = defaultChain;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates whether all child application contexts should be started on startup of the parent application context.
|
||||
*
|
||||
* @param autoStart
|
||||
* <code>true</code> if all child application contexts should be started on startup of the parent
|
||||
* application context
|
||||
*/
|
||||
public void setAutoStart(boolean autoStart)
|
||||
{
|
||||
this.autoStart = autoStart;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.alfresco.repo.management.subsystems.AbstractPropertyBackedBean#afterPropertiesSet()
|
||||
@@ -151,7 +118,7 @@ public class DefaultChildApplicationContextManager extends AbstractPropertyBacke
|
||||
// Use the first type as the default, unless one is specified explicitly
|
||||
if (this.defaultTypeName == null)
|
||||
{
|
||||
updateOrder(this.defaultChain, AbstractPropertyBackedBean.DEFAULT_ID);
|
||||
updateOrder(this.defaultChain, AbstractPropertyBackedBean.DEFAULT_ID_ROOT);
|
||||
this.defaultTypeName = this.childApplicationContexts.get(this.instanceIds.get(0)).getTypeName();
|
||||
}
|
||||
else
|
||||
@@ -161,7 +128,7 @@ public class DefaultChildApplicationContextManager extends AbstractPropertyBacke
|
||||
}
|
||||
else if (this.defaultTypeName == null)
|
||||
{
|
||||
setDefaultTypeName(AbstractPropertyBackedBean.DEFAULT_ID);
|
||||
setDefaultTypeName(AbstractPropertyBackedBean.DEFAULT_ID_ROOT);
|
||||
}
|
||||
|
||||
super.afterPropertiesSet();
|
||||
@@ -173,7 +140,10 @@ public class DefaultChildApplicationContextManager extends AbstractPropertyBacke
|
||||
*/
|
||||
public void start()
|
||||
{
|
||||
// Nothing to do
|
||||
for (String instance : getInstanceIds())
|
||||
{
|
||||
getApplicationContext(instance);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -224,6 +194,16 @@ public class DefaultChildApplicationContextManager extends AbstractPropertyBacke
|
||||
return Collections.singleton(DefaultChildApplicationContextManager.ORDER_PROPERTY);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.alfresco.repo.management.subsystems.AbstractPropertyBackedBean#getDescription(java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public String getDescription(String name)
|
||||
{
|
||||
return "Comma separated list of name:type pairs";
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.alfresco.repo.management.subsystems.PropertyBackedBean#setProperty(java.lang.String, java.lang.String)
|
||||
@@ -256,22 +236,6 @@ public class DefaultChildApplicationContextManager extends AbstractPropertyBacke
|
||||
return child == null ? null : child.getApplicationContext();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see
|
||||
* org.springframework.context.ApplicationListener#onApplicationEvent(org.springframework.context.ApplicationEvent)
|
||||
*/
|
||||
public void onApplicationEvent(ApplicationEvent event)
|
||||
{
|
||||
if (this.autoStart && event instanceof ContextRefreshedEvent && event.getSource() == this.parent)
|
||||
{
|
||||
for (String instance : getInstanceIds())
|
||||
{
|
||||
getApplicationContext(instance);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the order string.
|
||||
*
|
||||
@@ -325,8 +289,12 @@ public class DefaultChildApplicationContextManager extends AbstractPropertyBacke
|
||||
}
|
||||
if (factory == null)
|
||||
{
|
||||
this.childApplicationContexts.put(id, new ChildApplicationContextFactory(this.parent,
|
||||
getRegistry(), getCategory(), typeName, "managed$" + id));
|
||||
// Generate a unique ID within the category
|
||||
List<String> childId = new ArrayList<String>(2);
|
||||
childId.add("managed");
|
||||
childId.add(id);
|
||||
this.childApplicationContexts.put(id, new ChildApplicationContextFactory(getParent(),
|
||||
getRegistry(), getPropertyDefaults(), getCategory(), typeName, childId));
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -0,0 +1,208 @@
|
||||
/*
|
||||
* Copyright (C) 2005-2009 Alfresco Software Limited.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
* As a special exception to the terms and conditions of version 2.0 of
|
||||
* the GPL, you may redistribute this Program in connection with Free/Libre
|
||||
* and Open Source Software ("FLOSS") applications as described in Alfresco's
|
||||
* FLOSS exception. You should have received a copy of the text describing
|
||||
* the FLOSS exception, and it is also available here:
|
||||
* http://www.alfresco.com/legal/licensing"
|
||||
*/
|
||||
package org.alfresco.repo.management.subsystems;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.MutablePropertyValues;
|
||||
import org.springframework.beans.PropertyValue;
|
||||
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
|
||||
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
|
||||
import org.springframework.beans.factory.config.BeanReference;
|
||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||
import org.springframework.beans.factory.config.RuntimeBeanReference;
|
||||
import org.springframework.beans.factory.config.TypedStringValue;
|
||||
import org.springframework.beans.factory.support.ManagedList;
|
||||
|
||||
/**
|
||||
* A {@link BeanFactoryPostProcessor} that upgrades old-style Spring overrides that add location paths to the
|
||||
* <code>repository-properties</code> or <code>hibernateConfigProperties</code> beans to instead add these paths to the
|
||||
* <code>global-properties</code> bean. To avoid the warning messages output by this class, new property overrides
|
||||
* should be added to alfresco-global.properties without overriding any bean definitions.
|
||||
*
|
||||
* @author dward
|
||||
*/
|
||||
public class LegacyConfigPostProcessor implements BeanFactoryPostProcessor
|
||||
{
|
||||
/** The name of the bean that, in new configurations, holds all properties */
|
||||
private static final String BEAN_NAME_GLOBAL_PROPERTIES = "global-properties";
|
||||
|
||||
/** The name of the bean that expands repository properties. These should now be defaulted from global-properties. */
|
||||
private static final String BEAN_NAME_REPOSITORY_PROPERTIES = "repository-properties";
|
||||
|
||||
/** The name of the bean that holds hibernate properties. These should now be overriden by global-properties. */
|
||||
private static final String BEAN_NAME_HIBERNATE_PROPERTIES = "hibernateConfigProperties";
|
||||
|
||||
/** The name of the property on a Spring property loader that holds a list of property file location paths. */
|
||||
private static final String PROPERTY_LOCATIONS = "locations";
|
||||
|
||||
/** The name of the property on a Spring property loader that holds a local property map. */
|
||||
private static final String PROPERTY_PROPERTIES = "properties";
|
||||
|
||||
/** The logger. */
|
||||
private static Log logger = LogFactory.getLog(LegacyConfigPostProcessor.class);
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see
|
||||
* org.springframework.beans.factory.config.BeanFactoryPostProcessor#postProcessBeanFactory(org.springframework.
|
||||
* beans.factory.config.ConfigurableListableBeanFactory)
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException
|
||||
{
|
||||
try
|
||||
{
|
||||
// Look up the global-properties bean and its locations list
|
||||
MutablePropertyValues globalProperties = beanFactory.getBeanDefinition(
|
||||
LegacyConfigPostProcessor.BEAN_NAME_GLOBAL_PROPERTIES).getPropertyValues();
|
||||
PropertyValue pv = globalProperties.getPropertyValue(LegacyConfigPostProcessor.PROPERTY_LOCATIONS);
|
||||
Collection<Object> globalPropertyLocations;
|
||||
Object value;
|
||||
|
||||
// Use the locations list if there is one, otherwise associate a new empty list
|
||||
if (pv != null && (value = pv.getValue()) != null && value instanceof Collection)
|
||||
{
|
||||
globalPropertyLocations = (Collection<Object>) value;
|
||||
}
|
||||
else
|
||||
{
|
||||
globalPropertyLocations = new ManagedList(10);
|
||||
globalProperties
|
||||
.addPropertyValue(LegacyConfigPostProcessor.PROPERTY_LOCATIONS, globalPropertyLocations);
|
||||
}
|
||||
|
||||
// Move location paths added to repository-properties
|
||||
MutablePropertyValues repositoryProperties = processLocations(beanFactory, globalPropertyLocations,
|
||||
LegacyConfigPostProcessor.BEAN_NAME_REPOSITORY_PROPERTIES, new String[]
|
||||
{
|
||||
"classpath:alfresco/version.properties"
|
||||
});
|
||||
// Fix up additional properties to enforce correct order of precedence
|
||||
repositoryProperties.addPropertyValue("ignoreUnresolvablePlaceholders", Boolean.TRUE);
|
||||
repositoryProperties.addPropertyValue("localOverride", Boolean.FALSE);
|
||||
repositoryProperties.addPropertyValue("systemPropertiesModeName", "SYSTEM_PROPERTIES_MODE_NEVER");
|
||||
|
||||
// Move location paths added to hibernateConfigProperties
|
||||
MutablePropertyValues hibernateProperties = processLocations(beanFactory, globalPropertyLocations,
|
||||
LegacyConfigPostProcessor.BEAN_NAME_HIBERNATE_PROPERTIES, new String[]
|
||||
{
|
||||
"classpath:alfresco/domain/hibernate-cfg.properties"
|
||||
});
|
||||
// Fix up additional properties to enforce correct order of precedence
|
||||
hibernateProperties.addPropertyValue("localOverride", Boolean.TRUE);
|
||||
}
|
||||
catch (NoSuchBeanDefinitionException e)
|
||||
{
|
||||
// Ignore and continue
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a bean name (assumed to implement {@link org.springframework.core.io.support.PropertiesLoaderSupport})
|
||||
* checks whether it already references the <code>global-properties</code> bean. If not, 'upgrades' the bean by
|
||||
* appending all additional resources it mentions in its <code>locations</code> property to
|
||||
* <code>globalPropertyLocations</code>, except for those resources mentioned in <code>newLocations</code>. A
|
||||
* reference to <code>global-properties</code> will then be added and the resource list in
|
||||
* <code>newLocations<code> will then become the new <code>locations</code> list for the bean.
|
||||
*
|
||||
* @param beanFactory
|
||||
* the bean factory
|
||||
* @param globalPropertyLocations
|
||||
* the list of global property locations to be appended to
|
||||
* @param beanName
|
||||
* the bean name
|
||||
* @param newLocations
|
||||
* the new locations to be set on the bean
|
||||
* @return the mutable property values
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
private MutablePropertyValues processLocations(ConfigurableListableBeanFactory beanFactory,
|
||||
Collection<Object> globalPropertyLocations, String beanName, String[] newLocations)
|
||||
{
|
||||
// Get the bean an check its existing properties value
|
||||
MutablePropertyValues beanProperties = beanFactory.getBeanDefinition(beanName).getPropertyValues();
|
||||
PropertyValue pv = beanProperties.getPropertyValue(LegacyConfigPostProcessor.PROPERTY_PROPERTIES);
|
||||
Object value;
|
||||
|
||||
// If the properties value already references the global-properties bean, we have nothing else to do. Otherwise,
|
||||
// we have to 'upgrade' the bean definition.
|
||||
if (pv == null || (value = pv.getValue()) == null || !(value instanceof BeanReference)
|
||||
|| ((BeanReference) value).getBeanName().equals(LegacyConfigPostProcessor.BEAN_NAME_GLOBAL_PROPERTIES))
|
||||
{
|
||||
// Convert the array of new locations to a managed list of type string values, so that it is
|
||||
// compatible with a bean definition
|
||||
Collection<Object> newLocationList = new ManagedList(newLocations.length);
|
||||
if (newLocations != null && newLocations.length > 0)
|
||||
{
|
||||
for (String preserveLocation : newLocations)
|
||||
{
|
||||
newLocationList.add(new TypedStringValue(preserveLocation));
|
||||
}
|
||||
}
|
||||
|
||||
// If there is currently a locations list, process it
|
||||
pv = beanProperties.getPropertyValue(LegacyConfigPostProcessor.PROPERTY_LOCATIONS);
|
||||
if (pv != null && (value = pv.getValue()) != null && value instanceof Collection)
|
||||
{
|
||||
Collection<Object> locations = (Collection<Object>) value;
|
||||
|
||||
// Compute the set of locations that need to be added to globalPropertyLocations (preserving order) and
|
||||
// warn about each
|
||||
Set<Object> addedLocations = new LinkedHashSet<Object>(locations);
|
||||
addedLocations.removeAll(globalPropertyLocations);
|
||||
addedLocations.removeAll(newLocationList);
|
||||
|
||||
for (Object location : addedLocations)
|
||||
{
|
||||
LegacyConfigPostProcessor.logger.warn("Legacy configuration detected: adding "
|
||||
+ (location instanceof TypedStringValue ? ((TypedStringValue) location).getValue()
|
||||
: location.toString()) + " to global-properties definition");
|
||||
globalPropertyLocations.add(location);
|
||||
}
|
||||
|
||||
}
|
||||
// Ensure the bean now references global-properties
|
||||
beanProperties.addPropertyValue(LegacyConfigPostProcessor.PROPERTY_PROPERTIES, new RuntimeBeanReference(
|
||||
LegacyConfigPostProcessor.BEAN_NAME_GLOBAL_PROPERTIES));
|
||||
|
||||
// Ensure the new location list is now set on the bean
|
||||
if (newLocationList.size() > 0)
|
||||
{
|
||||
beanProperties.addPropertyValue(LegacyConfigPostProcessor.PROPERTY_LOCATIONS, newLocationList);
|
||||
}
|
||||
else
|
||||
{
|
||||
beanProperties.removePropertyValue(LegacyConfigPostProcessor.PROPERTY_LOCATIONS);
|
||||
}
|
||||
}
|
||||
return beanProperties;
|
||||
}
|
||||
}
|
@@ -24,6 +24,7 @@
|
||||
*/
|
||||
package org.alfresco.repo.management.subsystems;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
@@ -38,6 +39,7 @@ import java.util.Set;
|
||||
*/
|
||||
public interface PropertyBackedBean
|
||||
{
|
||||
|
||||
/**
|
||||
* Gets a human readable categorization of this bean, explaining its purpose. This category may be used e.g. in
|
||||
* administration UIs and JMX object names.
|
||||
@@ -47,11 +49,12 @@ public interface PropertyBackedBean
|
||||
public String getCategory();
|
||||
|
||||
/**
|
||||
* Gets an identifier for the bean. Must be unique within the category.
|
||||
* Gets an identifier for the bean. Must be unique within the category. The ID is a List to encourage hierarchical
|
||||
* structuring of IDs, e.g. to aid construction of JMX Object names and presentation in JConsole.
|
||||
*
|
||||
* @return the id
|
||||
*/
|
||||
public String getId();
|
||||
public List<String> getId();
|
||||
|
||||
/**
|
||||
* Gets the names of all properties.
|
||||
@@ -89,6 +92,15 @@ public interface PropertyBackedBean
|
||||
*/
|
||||
public boolean isUpdateable(String name);
|
||||
|
||||
/**
|
||||
* Gets a Human readable description of the property, e.g. to provide via JMX.
|
||||
*
|
||||
* @param name
|
||||
* the name
|
||||
* @return the description
|
||||
*/
|
||||
public String getDescription(String name);
|
||||
|
||||
/**
|
||||
* Starts up the component, using its new property values.
|
||||
*/
|
||||
|
@@ -25,19 +25,16 @@
|
||||
package org.alfresco.repo.management.subsystems;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextAware;
|
||||
|
||||
/**
|
||||
* A configurable proxy for a set of {@link ApplicationContextFactory} beans that allows dynamic selection of one or
|
||||
* more alternative subsystems via a <code>sourceBeanName</code> property. As with other {@link PropertyBackedBean}s,
|
||||
* can be stopped, reconfigured, started and tested.
|
||||
*/
|
||||
public class SwitchableApplicationContextFactory extends AbstractPropertyBackedBean implements ApplicationContextAware,
|
||||
public class SwitchableApplicationContextFactory extends AbstractPropertyBackedBean implements
|
||||
ApplicationContextFactory
|
||||
{
|
||||
/**
|
||||
@@ -45,9 +42,6 @@ public class SwitchableApplicationContextFactory extends AbstractPropertyBackedB
|
||||
*/
|
||||
private static final String SOURCE_BEAN_PROPERTY = "sourceBeanName";
|
||||
|
||||
/** The parent application context. */
|
||||
private ApplicationContext parent;
|
||||
|
||||
/** The bean name of the source {@link ApplicationContextFactory}. */
|
||||
private String sourceBeanName;
|
||||
|
||||
@@ -76,23 +70,17 @@ public class SwitchableApplicationContextFactory extends AbstractPropertyBackedB
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.context.ApplicationContextAware#setApplicationContext(org.springframework.context.
|
||||
* ApplicationContext)
|
||||
*/
|
||||
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException
|
||||
{
|
||||
this.parent = applicationContext;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.alfresco.enterprise.repo.management.ConfigurableBean#onStart()
|
||||
*/
|
||||
public synchronized void start()
|
||||
{
|
||||
this.sourceApplicationContextFactory = (ApplicationContextFactory) this.parent.getBean(this.sourceBeanName);
|
||||
if (this.sourceApplicationContextFactory == null)
|
||||
{
|
||||
this.sourceApplicationContextFactory = (ApplicationContextFactory) getParent().getBean(this.sourceBeanName);
|
||||
this.sourceApplicationContextFactory.start();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -128,7 +116,8 @@ public class SwitchableApplicationContextFactory extends AbstractPropertyBackedB
|
||||
return this.sourceApplicationContextFactory.getApplicationContext();
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.alfresco.repo.management.subsystems.PropertyBackedBean#getProperty(java.lang.String)
|
||||
*/
|
||||
public synchronized String getProperty(String name)
|
||||
@@ -140,7 +129,8 @@ public class SwitchableApplicationContextFactory extends AbstractPropertyBackedB
|
||||
return this.sourceBeanName;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.alfresco.repo.management.subsystems.PropertyBackedBean#getPropertyNames()
|
||||
*/
|
||||
public Set<String> getPropertyNames()
|
||||
@@ -148,7 +138,8 @@ public class SwitchableApplicationContextFactory extends AbstractPropertyBackedB
|
||||
return Collections.singleton(SOURCE_BEAN_PROPERTY);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.alfresco.repo.management.subsystems.PropertyBackedBean#setProperty(java.lang.String, java.lang.String)
|
||||
*/
|
||||
public synchronized void setProperty(String name, String value)
|
||||
@@ -157,9 +148,9 @@ public class SwitchableApplicationContextFactory extends AbstractPropertyBackedB
|
||||
{
|
||||
throw new IllegalStateException("Illegal attempt to write to property \"" + name + "\"");
|
||||
}
|
||||
if (!parent.containsBean(value))
|
||||
if (!getParent().containsBean(value))
|
||||
{
|
||||
throw new IllegalStateException("\"" + value + "\" is not a valid bean name");
|
||||
throw new IllegalStateException("\"" + value + "\" is not a valid bean name");
|
||||
}
|
||||
setSourceBeanName(value);
|
||||
}
|
||||
|
Reference in New Issue
Block a user