blob: 9a1c4af262f68897bc1dff6d69964e60a6e881db [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.cocoon.spring.configurator.impl;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.Properties;
import org.apache.cocoon.spring.configurator.ResourceFilter;
import org.apache.cocoon.spring.configurator.ResourceUtils;
import org.springframework.beans.factory.BeanDefinitionStoreException;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.w3c.dom.Element;
/**
* Abstract class for the settings element parsers.
*
* @see ChildSettingsElementParser
* @see SettingsElementParser
* @version $Id$
* @since 1.0
*/
public abstract class AbstractSettingsElementParser extends AbstractElementParser {
/**
* Get the current running mode
*/
protected abstract String getRunningMode(Element e);
/**
* Create and register the settings bean factory post processor.
*/
protected abstract void createSettingsBeanFactoryPostProcessor(Element element,
ParserContext parserContext,
String runningMode);
private ResourceFilter resourceFilter;
/**
* Get additional includes of property directories.
*/
protected List getPropertyIncludes(Element childSettingsElement) {
List propertyDirs = null;
if ( childSettingsElement != null ) {
final Element[] propertyDirConfigs = this.getChildElements(childSettingsElement, "include-properties");
if ( propertyDirConfigs != null && propertyDirConfigs.length > 0 ) {
propertyDirs = new ArrayList();
for(int i=0; i < propertyDirConfigs.length; i++) {
propertyDirs.add(this.getAttributeValue(propertyDirConfigs[i], "dir", null));
}
}
}
return propertyDirs;
}
/**
* Get additional properties.
*/
protected Properties getAdditionalProperties(Element childSettingsElement) {
Properties variables = null;
final Element[] properties = this.getChildElements(childSettingsElement, "property");
if ( properties != null && properties.length > 0 ) {
variables = new Properties();
for(int i=0; i<properties.length; i++) {
variables.setProperty(this.getAttributeValue(properties[i], "name", null),
this.getAttributeValue(properties[i], "value", null));
}
}
return variables;
}
/**
* Get additional includes of bean configurations.
*/
protected List getBeanIncludes(Element childSettingsElement) {
final List includes = new ArrayList();
// search for includes
if ( childSettingsElement.hasChildNodes() ) {
final Element[] includeElements = this.getChildElements(childSettingsElement, "include-beans");
if ( includeElements != null ) {
for(int i = 0 ; i < includeElements.length; i++ ) {
final String dir = this.getAttributeValue(includeElements[i], "dir", null);
includes.add(dir);
}
}
}
return includes;
}
/**
* Return the includes for the property override configuration
*/
protected List getBeanPropertyOverrideIncludes(Element settingsElement) {
return this.getBeanIncludes(settingsElement);
}
/**
* @see org.springframework.beans.factory.xml.BeanDefinitionParser#parse(org.w3c.dom.Element, org.springframework.beans.factory.xml.ParserContext)
*/
public BeanDefinition parse(Element element, ParserContext parserContext) {
final String runningMode = this.getRunningMode(element);
try {
this.resourceFilter = getResourceFilter(element);
} catch (Exception e) {
throw new BeanDefinitionStoreException("Unable to read filter configuration", e);
}
// create factory for settings object
this.createSettingsBeanFactoryPostProcessor(element, parserContext, runningMode);
// Get bean includes for property overrides
final List overridePropertyIncludes = this.getBeanPropertyOverrideIncludes(element);
// If there are bean includes for a directory, we register a property placeholder configurer
if ( overridePropertyIncludes.size() > 0 ) {
this.registerPropertyOverrideConfigurer(parserContext, overridePropertyIncludes);
}
// register additonal components
this.registerComponents(element, parserContext);
// Get bean includes
final List beanIncludes = this.getBeanIncludes(element);
// process bean includes!
final Iterator beanIncludeIterator = beanIncludes.iterator();
while ( beanIncludeIterator.hasNext() ) {
final String dir = (String)beanIncludeIterator.next();
try {
this.handleBeanInclude(parserContext, dir, false);
this.handleBeanInclude(parserContext, dir + "/" + runningMode, true);
} catch (Exception e) {
throw new BeanDefinitionStoreException("Unable to read spring configurations from " + dir, e);
}
}
return null;
}
/**
* This method can be used for subclasses to register additional components.
*/
protected void registerComponents(Element settingsElement, ParserContext parserContext) {
// nothing to do here
}
/**
* Handle include for spring bean configurations.
*/
protected void handleBeanInclude(final ParserContext parserContext,
final String path,
final boolean optional)
throws Exception {
final ResourcePatternResolver resolver =
(ResourcePatternResolver) parserContext.getReaderContext().getReader().getResourceLoader();
// check if the directory to read from exists
// we only check if optional is set to true
boolean load = true;
if ( optional
&& !ResourceUtils.isClasspathUri(path) ) {
final Resource rsrc = resolver.getResource(path);
if ( !rsrc.exists()) {
load = false;
}
}
if ( load ) {
try {
Resource[] resources = resolver.getResources(path + "/*.xml");
resources = ResourceUtils.filterResources(resources, getResourceFilter());
Arrays.sort(resources, ResourceUtils.getResourceComparator());
for (int i = 0; i < resources.length; i++) {
this.handleImport(parserContext, resources[i].getURL().toExternalForm());
}
} catch (IOException ioe) {
throw new Exception("Unable to read configurations from " + path, ioe);
}
}
}
protected void handleImport(ParserContext parserContext, String uri) {
final ResourceLoader resourceLoader = parserContext.getReaderContext().getReader().getResourceLoader();
parserContext.getDelegate().getReaderContext().getReader().loadBeanDefinitions(resourceLoader.getResource(uri));
}
/**
* Register a property placeholder configurer. The configurer will read all
* *.properties files from the specified locations.
*
* @param parserContext
* @param locations
*/
protected void registerPropertyOverrideConfigurer(final ParserContext parserContext,
final List locations) {
final RootBeanDefinition beanDef = this.createBeanDefinition(ExtendedPropertyOverrideConfigurer.class.getName(),
null, true);
beanDef.getPropertyValues().addPropertyValue("locations", locations);
beanDef.getPropertyValues().addPropertyValue("resourceLoader",
parserContext.getReaderContext().getReader().getResourceLoader());
beanDef.getPropertyValues().addPropertyValue("resourceFilter", getResourceFilter());
beanDef.getPropertyValues().addPropertyValue("beanNameSeparator", "/");
this.register(beanDef, ExtendedPropertyOverrideConfigurer.class.getName(), parserContext.getRegistry());
}
protected ResourceFilter getResourceFilter(Element e) throws Exception {
Element[] filters = this.getChildElements(e, "filter");
if (filters.length == 0)
return null;
else if (filters.length > 1)
throw new RuntimeException("Only one filter definition is allowed and you configured " + filters.length + " filters.");
String filterClassName = filters[0].getAttribute("class");
if (filterClassName.length() == 0)
throw new RuntimeException("Missing 'class' attribute.");
return (ResourceFilter)java.lang.Class.forName(filterClassName).newInstance();
}
protected final ResourceFilter getResourceFilter() {
return this.resourceFilter;
}
}