/**
* Copyright 2008 - 2009 Pro-Netics S.P.A.
*
* Licensed 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 it.pronetics.madstore.common.configuration.spring;
import it.pronetics.madstore.common.configuration.spring.MadStoreConfigurationBean.AtomPublishingProtocolConfiguration;
import it.pronetics.madstore.common.configuration.spring.MadStoreConfigurationBean.CrawlerConfiguration;
import it.pronetics.madstore.common.configuration.spring.MadStoreConfigurationBean.GridConfiguration;
import it.pronetics.madstore.common.configuration.spring.MadStoreConfigurationBean.HttpCacheConfiguration;
import it.pronetics.madstore.common.configuration.spring.MadStoreConfigurationBean.IndexConfiguration;
import it.pronetics.madstore.common.configuration.spring.MadStoreConfigurationBean.JcrConfiguration;
import it.pronetics.madstore.common.configuration.spring.MadStoreConfigurationBean.OpenSearchConfiguration;
import it.pronetics.madstore.common.configuration.spring.MadStoreConfigurationBean.SimpleTriggerConfiguration;
import it.pronetics.madstore.common.configuration.spring.MadStoreConfigurationBean.IndexConfiguration.Property;
import it.pronetics.madstore.common.configuration.support.MadStoreConfigurationException;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.ManagedList;
import org.springframework.beans.factory.support.ManagedMap;
import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.util.xml.DomUtils;
import org.w3c.dom.DOMException;
import org.w3c.dom.Element;
/**
* Spring-based configuration parser for creating the
* {@link it.pronetics.madstore.common.configuration.spring.MadStoreConfigurationBean}.
* @author Salvatore Incandela
*/
public class MadStoreConfigurationBeanDefinitionParser extends AbstractSingleBeanDefinitionParser {
private static final String SEPARATOR = System.getProperty("file.separator");
private static final String TASK_NAME = "name";
private static final String MADSTORE_HOME_BEAN_PROPERTY = "madStoreHome";
private static final String CRAWLER = "crawler";
private static final String REPOSITORY = "repository";
private static final String SERVER = "server";
private static final String TARGET_SITE = "targetSite";
private static final String HOST_NAME = "hostName";
private static final String START_LINK = "startLink";
private static final String MAX_CONCURRENT_DOWNLOADS = "maxConcurrentDownloads";
private static final String MAX_VISITED_LINKS = "maxVisitedLinks";
private static final String START_DELAY = "startDelay";
private static final String REPEAT_INTERVAL = "repeatInterval";
private static final String WORKSPACE = "workspace";
private static final String SHORT_NAME = "shortName";
private static final String DESCRIPTION = "description";
private static final String INDEXED_PROPERTIES_NAMESPACES = "indexedPropertiesNamespaces";
private static final String NAMESPACE = "namespace";
private static final String NAMESPACE_PREFIX = "prefix";
private static final String NAMESPACE_URL = "url";
private static final String INDEXED_PROPERTIES = "indexedProperties";
private static final String PROPERTY = "property";
private static final String PROPERTY_NAME = TASK_NAME;
private static final String BOOST = "boost";
private static final String XPATH = "xpath";
private static final String DEFAULT_INDEX_FOLDER = "index";
private static final String DEFAULT_JCR_FOLDER = "jcr";
private static final String CRAWLER_CONFIGURATIONS_BEAN_PROPERTY = "crawlerConfigurations";
private static final String SIMPLE_TRIGGER_CONFIGURATION_TAG = "simpleTrigger";
private static final String TASKS_CONFIGURATION_BEAN_PROPERTY = "tasks";
private static final String LOCAL_ADDRESS_ATTRIBUTE = "localAddress";
private static final String GRID_ENABLED_TAG = "grid-enabled";
private static final String GRID_CONFIGURATION_BEAN_PROPERTY = "gridConfiguration";
private static final String GRID_FOLDER = "gridgain";
private static final String JCR_CONFIGURATION_BEAN_PROPERTY = "jcrConfiguration";
private static final String INDEX_CONFIGURATION_TAG = "index";
private static final String INDEX_CONFIGURATION_BEAN_PROPERTY = "indexConfiguration";
private static final String HTTP_CACHE_CONFIGURATION_BEAN_PROPERTY = "httpCacheConfiguration";
private static final String MAX_AGE_ATTRIBUTE = "max-age";
private static final String HTTPCACHE_ENABLED_TAG = "httpCache-enabled";
private static final String OS_CONFIGURATION_TAG = "openSearch";
private static final String OS_CONFIGURATION_BEAN_PROPERTY = "openSearchConfiguration";
private static final String APP_CONFIGURATION_TAG = "atomPub";
private static final String APP_CONFIGURATION_BEAN_PROPERTY = "atomPublishingProtocolConfiguration";
private static final String JCR_MAX_HISTORY = "maxHistory";
private static final String TASKS_TAG = "tasks";
private static final String TASK_TAG = "task";
private static final String CRAWLER_TASK = "crawlerTask";
@SuppressWarnings("unchecked")
protected Class getBeanClass(Element element) {
return MadStoreConfigurationBean.class;
}
protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder beanDefinitionBuilder) {
try {
String madStoreDir = MadStoreConfigurationManager.getInstance().getMadStoreHome();
beanDefinitionBuilder.addPropertyValue(MADSTORE_HOME_BEAN_PROPERTY, madStoreDir);
Element crawlerElement = DomUtils.getChildElementByTagName(element, CRAWLER);
Element repositoryElement = DomUtils.getChildElementByTagName(element, REPOSITORY);
Element serverElement = DomUtils.getChildElementByTagName(element, SERVER);
Element tasksElement = DomUtils.getChildElementByTagName(element, TASKS_TAG);
if (repositoryElement == null) {
throw new IllegalStateException("At least one " + REPOSITORY + " element should be present.");
}
if (crawlerElement != null) {
parseCrawlerConfigurations(crawlerElement, beanDefinitionBuilder);
parseGridConfiguration(crawlerElement, beanDefinitionBuilder);
} else {
dummyCrawlerConfigurations(beanDefinitionBuilder);
}
parseJcrConfiguration(repositoryElement, beanDefinitionBuilder);
parseIndexConfiguration(repositoryElement, beanDefinitionBuilder);
if (serverElement != null) {
Element httpCacheEnabled = DomUtils.getChildElementByTagName(serverElement, HTTPCACHE_ENABLED_TAG);
HttpCacheConfiguration httpCacheConfiguration = new HttpCacheConfiguration();
Integer maxAge = new Integer(0);
if (httpCacheEnabled != null) {
maxAge = new Integer(httpCacheEnabled.getAttribute(MAX_AGE_ATTRIBUTE));
}
httpCacheConfiguration.setMaxAge(maxAge);
beanDefinitionBuilder.addPropertyValue(HTTP_CACHE_CONFIGURATION_BEAN_PROPERTY, httpCacheConfiguration);
parseAppConfiguration(serverElement, beanDefinitionBuilder);
parseOsConfiguration(serverElement, beanDefinitionBuilder);
} else {
dummyAppConfiguration(beanDefinitionBuilder);
dummyOsConfiguration(beanDefinitionBuilder);
}
parseTasksConfiguration(tasksElement, beanDefinitionBuilder);
} catch(Exception ex) {
throw new MadStoreConfigurationException(ex.getMessage(), ex);
}
}
@Override
protected boolean shouldGenerateIdAsFallback() {
return true;
}
@SuppressWarnings("unchecked")
private void dummyCrawlerConfigurations(BeanDefinitionBuilder factory) {
List<CrawlerConfiguration> crawlerConfigurations = new ManagedList();
factory.addPropertyValue(CRAWLER_CONFIGURATIONS_BEAN_PROPERTY, crawlerConfigurations);
}
@SuppressWarnings("unchecked")
private void parseCrawlerConfigurations(Element element, BeanDefinitionBuilder factory) {
List<Element> targetSites = DomUtils.getChildElementsByTagName(element, TARGET_SITE);
List<CrawlerConfiguration> crawlerConfigurations = new ManagedList(targetSites.size());
for (Element targetSiteEle : targetSites) {
String hostName = DomUtils.getChildElementByTagName(targetSiteEle, HOST_NAME).getTextContent();
String startLink = DomUtils.getChildElementByTagName(targetSiteEle, START_LINK).getTextContent();
String maxConcurrentDownloads = DomUtils.getChildElementByTagName(targetSiteEle, MAX_CONCURRENT_DOWNLOADS).getTextContent();
String maxVisitedLinks = DomUtils.getChildElementByTagName(targetSiteEle, MAX_VISITED_LINKS).getTextContent();
CrawlerConfiguration crawlerConfiguration = new CrawlerConfiguration();
crawlerConfiguration.setHostName(hostName);
crawlerConfiguration.setStartLink(startLink);
crawlerConfiguration.setMaxConcurrentDownloads(new Integer(maxConcurrentDownloads).intValue());
crawlerConfiguration.setMaxVisitedLinks(new Integer(maxVisitedLinks).intValue());
crawlerConfigurations.add(crawlerConfiguration);
}
factory.addPropertyValue(CRAWLER_CONFIGURATIONS_BEAN_PROPERTY, crawlerConfigurations);
}
@SuppressWarnings("unchecked")
private void parseTasksConfiguration(Element tasksElement, BeanDefinitionBuilder beanDefinitionBuilder) throws NumberFormatException, MadStoreConfigurationException, DOMException {
List<Element> taskElements = DomUtils.getChildElementsByTagName(tasksElement, TASK_TAG);
Map<String, SimpleTriggerConfiguration> triggerTasks = new ManagedMap();
for (Element task : taskElements) {
String key = task.getAttribute(TASK_NAME);
Element simpleTriggerConfigurationElement = DomUtils.getChildElementByTagName(task, SIMPLE_TRIGGER_CONFIGURATION_TAG);
String startDelaySt = DomUtils.getChildElementByTagName(simpleTriggerConfigurationElement, START_DELAY).getTextContent();
String repeatIntervalSt = DomUtils.getChildElementByTagName(simpleTriggerConfigurationElement, REPEAT_INTERVAL).getTextContent();
if ("".equals(startDelaySt) || "".equals(repeatIntervalSt)) {
throw new MadStoreConfigurationException("Parameters startDelay and repeatInterval in " + SIMPLE_TRIGGER_CONFIGURATION_TAG + " tag cannot be empty.");
}
SimpleTriggerConfiguration simpleTriggerConfiguration = new SimpleTriggerConfiguration();
simpleTriggerConfiguration.setStartDelay(new Integer(startDelaySt).intValue());
simpleTriggerConfiguration.setRepeatInterval(new Integer(repeatIntervalSt).intValue());
triggerTasks.put(key, simpleTriggerConfiguration);
}
beanDefinitionBuilder.addPropertyValue(TASKS_CONFIGURATION_BEAN_PROPERTY, triggerTasks);
List<CrawlerConfiguration> crawlerConfigurations = (List<CrawlerConfiguration>) beanDefinitionBuilder.getBeanDefinition().getPropertyValues().getPropertyValue(
CRAWLER_CONFIGURATIONS_BEAN_PROPERTY).getValue();
if (triggerTasks.keySet().contains(CRAWLER_TASK) && crawlerConfigurations.size() == 0) {
throw new MadStoreConfigurationException("Crawler task cannot exist without crawler tag definition!");
}
}
private void parseGridConfiguration(Element crawlerElement, BeanDefinitionBuilder beanDefinitionBuilder) throws UnknownHostException {
Element gridEnabled = DomUtils.getChildElementByTagName(crawlerElement, GRID_ENABLED_TAG);
if (gridEnabled != null) {
String madStoreDir = MadStoreConfigurationManager.getInstance().getMadStoreHome();
String gridDir = new StringBuilder(madStoreDir).append(SEPARATOR).append(GRID_FOLDER).toString();
String localAddress = gridEnabled.getAttribute(LOCAL_ADDRESS_ATTRIBUTE);
if (localAddress == null || localAddress.equals("")) {
localAddress = InetAddress.getLocalHost().getHostAddress();
}
GridConfiguration gridConfiguration = new GridConfiguration();
gridConfiguration.setHomeDir(gridDir);
gridConfiguration.setLocalAddress(localAddress);
beanDefinitionBuilder.addPropertyValue(GRID_CONFIGURATION_BEAN_PROPERTY, gridConfiguration);
}
}
private void parseJcrConfiguration(Element repositoryElement, BeanDefinitionBuilder beanDefinitionBuilder) throws DOMException {
JcrConfiguration jcrConfiguration = new JcrConfiguration();
String madStoreDir = MadStoreConfigurationManager.getInstance().getMadStoreHome();
String jcrDir = new StringBuilder(madStoreDir).append(SEPARATOR).append(DEFAULT_JCR_FOLDER).toString();
jcrConfiguration.setHomeDir(jcrDir);
jcrConfiguration.setUsername("");
jcrConfiguration.setPassword("".toCharArray());
Integer maxHistory = Integer.valueOf(DomUtils.getChildElementByTagName(repositoryElement, JCR_MAX_HISTORY).getTextContent());
jcrConfiguration.setMaxHistory(maxHistory);
beanDefinitionBuilder.addPropertyValue(JCR_CONFIGURATION_BEAN_PROPERTY, jcrConfiguration);
}
@SuppressWarnings("unchecked")
private void parseIndexConfiguration(Element repositoryElement, BeanDefinitionBuilder beanDefinitionBuilder) {
IndexConfiguration indexConfiguration = new IndexConfiguration();
Element indexConfigurationElement = DomUtils.getChildElementByTagName(repositoryElement, INDEX_CONFIGURATION_TAG);
String madStoreDir = MadStoreConfigurationManager.getInstance().getMadStoreHome();
String indexDir = new StringBuilder(madStoreDir).append(SEPARATOR).append(DEFAULT_INDEX_FOLDER).toString();
indexConfiguration.setIndexDir(indexDir);
List<Element> indexedPropertiesNamespacesElementList = DomUtils.getChildElementsByTagName(DomUtils.getChildElementByTagName(indexConfigurationElement, INDEXED_PROPERTIES_NAMESPACES),
NAMESPACE);
Map<String, String> indexedPropertiesNamespaces = new HashMap<String, String>();
for (Element namespaceElement : indexedPropertiesNamespacesElementList) {
String name = namespaceElement.getAttribute(NAMESPACE_PREFIX);
String xPath = namespaceElement.getAttribute(NAMESPACE_URL);
indexedPropertiesNamespaces.put(name, xPath);
}
indexConfiguration.setIndexedPropertiesNamespaces(indexedPropertiesNamespaces);
List<Element> indexedPropertiesElementList = DomUtils.getChildElementsByTagName(DomUtils.getChildElementByTagName(indexConfigurationElement, INDEXED_PROPERTIES), PROPERTY);
List<Property> indexedProperties = new ManagedList(indexedPropertiesElementList.size());
for (Element propertyElement : indexedPropertiesElementList) {
String name = propertyElement.getAttribute(PROPERTY_NAME);
String xPath = DomUtils.getChildElementByTagName(propertyElement, XPATH).getTextContent();
int boost = Integer.valueOf((DomUtils.getChildElementByTagName(propertyElement, BOOST).getTextContent()));
Property indexedProperty = indexConfiguration.new Property(name, xPath, boost);
indexedProperties.add(indexedProperty);
}
indexConfiguration.setIndexedProperties(indexedProperties);
beanDefinitionBuilder.addPropertyValue(INDEX_CONFIGURATION_BEAN_PROPERTY, indexConfiguration);
}
private void dummyAppConfiguration(BeanDefinitionBuilder beanDefinitionBuilder) {
AtomPublishingProtocolConfiguration atomPublishingProtocolConfiguration = new AtomPublishingProtocolConfiguration();
atomPublishingProtocolConfiguration.setWorkspace(new String());
beanDefinitionBuilder.addPropertyValue(APP_CONFIGURATION_BEAN_PROPERTY, atomPublishingProtocolConfiguration);
}
private void parseAppConfiguration(Element serverElement, BeanDefinitionBuilder beanDefinitionBuilder) throws DOMException {
Element appConfigurationElement = DomUtils.getChildElementByTagName(serverElement, APP_CONFIGURATION_TAG);
AtomPublishingProtocolConfiguration atomPublishingProtocolConfiguration = new AtomPublishingProtocolConfiguration();
atomPublishingProtocolConfiguration.setWorkspace(DomUtils.getChildElementByTagName(appConfigurationElement, WORKSPACE).getTextContent());
beanDefinitionBuilder.addPropertyValue(APP_CONFIGURATION_BEAN_PROPERTY, atomPublishingProtocolConfiguration);
}
private void dummyOsConfiguration(BeanDefinitionBuilder beanDefinitionBuilder) {
OpenSearchConfiguration openSearchConfiguration = new OpenSearchConfiguration();
openSearchConfiguration.setShortName(new String());
openSearchConfiguration.setDescription(new String());
beanDefinitionBuilder.addPropertyValue(OS_CONFIGURATION_BEAN_PROPERTY, openSearchConfiguration);
}
private void parseOsConfiguration(Element serverElement, BeanDefinitionBuilder beanDefinitionBuilder) throws DOMException {
Element osConfigurationElement = DomUtils.getChildElementByTagName(serverElement, OS_CONFIGURATION_TAG);
OpenSearchConfiguration openSearchConfiguration = new OpenSearchConfiguration();
openSearchConfiguration.setShortName(DomUtils.getChildElementByTagName(osConfigurationElement, SHORT_NAME).getTextContent());
openSearchConfiguration.setDescription(DomUtils.getChildElementByTagName(osConfigurationElement, DESCRIPTION).getTextContent());
beanDefinitionBuilder.addPropertyValue(OS_CONFIGURATION_BEAN_PROPERTY, openSearchConfiguration);
}
}