package org.kefirsf.bb;
import org.kefirsf.bb.conf.Configuration;
import org.kefirsf.bb.util.Exceptions;
import org.kefirsf.bb.util.Utils;
import org.w3c.dom.Document;
import org.xml.sax.SAXException;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import java.io.*;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
/**
* Create the text processor configuration
*
* @author Vitaliy Samolovskih aka Kefir
*/
public class ConfigurationFactory {
// Helper constants
private static final String DEFAULT_CONFIGURATION = "org/kefirsf/bb/default";
private static final String SAFE_HTML_CONFIGURATION = "org/kefirsf/bb/safehtml";
private static final String TEXTILE_CONFIGURATION = "org/kefirsf/bb/textile";
private static final String MARKDOWN_CONFIGURATION = "org/kefirsf/bb/markdown";
private static final String DEFAULT_USER_CONFIGURATION = "kefirbb";
private static final String CONFIGURATION_EXTENSION = ".xml";
// Configuration paths
public static final String DEFAULT_USER_CONFIGURATION_FILE = DEFAULT_USER_CONFIGURATION + CONFIGURATION_EXTENSION;
public static final String DEFAULT_CONFIGURATION_FILE = DEFAULT_CONFIGURATION + CONFIGURATION_EXTENSION;
public static final String SAFE_HTML_CONFIGURATION_FILE = SAFE_HTML_CONFIGURATION + CONFIGURATION_EXTENSION;
public static final String TEXTILE_CONFIGURATION_FILE = TEXTILE_CONFIGURATION + CONFIGURATION_EXTENSION;
public static final String MARKDOWN_CONFIGURATION_FILE = MARKDOWN_CONFIGURATION + CONFIGURATION_EXTENSION;
public static final String DEFAULT_PROPERTIES_FILE = "kefirbb.properties";
public static final String DEFAULT_PROPERTIES_XML_FILE = "kefirbb.properties.xml";
private final DomConfigurationFactory domConfigurationFactory = DomConfigurationFactory.getInstance();
/**
* Singletone class instance
*/
private static final ConfigurationFactory instance = new ConfigurationFactory();
/**
* private constructor
*/
private ConfigurationFactory() {
}
/**
* Return instance of class ConfigurationFactory
*
* @return configuration factory
*/
public static ConfigurationFactory getInstance() {
return instance;
}
/**
* Create the default bb-code processor.
*
* @return Default bb-code processor
* @throws TextProcessorFactoryException when can't read the default code set resource
*/
public Configuration create() {
Configuration configuration;
try {
InputStream stream = null;
try {
// Search the user configuration
stream = Utils.openResourceStream(DEFAULT_USER_CONFIGURATION_FILE);
// If user configuration not found then use default
if (stream == null) {
stream = Utils.openResourceStream(DEFAULT_CONFIGURATION_FILE);
}
if (stream != null) {
configuration = create(stream);
} else {
throw new TextProcessorFactoryException("Can't find or open default configuration resource.");
}
} finally {
if (stream != null) {
stream.close();
}
}
Properties properties = new Properties();
// Load properties from .property file
InputStream propertiesStream = null;
try {
propertiesStream = Utils.openResourceStream(DEFAULT_PROPERTIES_FILE);
if (propertiesStream != null) {
properties.load(propertiesStream);
}
} finally {
if (propertiesStream != null) {
propertiesStream.close();
}
}
// Load properties from xml file
InputStream xmlPropertiesStream = null;
try {
xmlPropertiesStream = Utils.openResourceStream(DEFAULT_PROPERTIES_XML_FILE);
if (xmlPropertiesStream != null) {
properties.loadFromXML(xmlPropertiesStream);
}
} finally {
if (xmlPropertiesStream != null) {
xmlPropertiesStream.close();
}
}
if (!properties.isEmpty()) {
Map<String, CharSequence> params = new HashMap<String, CharSequence>();
params.putAll(configuration.getParams());
for (Map.Entry<Object, Object> entry : properties.entrySet()) {
Object key = entry.getKey();
if (key != null) {
params.put(key.toString(), entry.getValue().toString());
}
}
configuration.setParams(params);
}
} catch (IOException e) {
throw new TextProcessorFactoryException(e);
}
return configuration;
}
/**
* Create the bb-processor using xml-configuration resource
*
* @param resourceName name of resource file
* @return bb-code processor
* @throws TextProcessorFactoryException when can't find or read the resource or illegal config file
*/
public Configuration createFromResource(String resourceName) {
Exceptions.nullArgument("resourceName", resourceName);
Configuration configuration;
try {
InputStream stream = null;
try {
stream = Utils.openResourceStream(resourceName);
if (stream != null) {
configuration = create(stream);
} else {
throw new TextProcessorFactoryException("Can't find or open resource \"" + resourceName + "\".");
}
} finally {
if (stream != null) {
stream.close();
}
}
} catch (IOException e) {
throw new TextProcessorFactoryException(e);
}
return configuration;
}
/**
* Create the bb-code processor from file with XML-configuration.
*
* @param fileName name of file with configuration
* @return bb-code processor
* @throws TextProcessorFactoryException any problems
*/
public Configuration create(String fileName) {
return create(new File(fileName));
}
/**
* Create the bb-code processor from file with XML-configuration.
*
* @param file file with configuration
* @return bb-code processor
* @throws TextProcessorFactoryException any problems
*/
public Configuration create(File file) {
try {
Configuration configuration;
InputStream stream = new BufferedInputStream(new FileInputStream(file));
try {
configuration = create(stream);
} finally {
stream.close();
}
return configuration;
} catch (IOException e) {
throw new TextProcessorFactoryException(e);
}
}
/**
* Create the bb-processor from XML InputStream
*
* @param stream the input stream with XML
* @return bb-code processor
* @throws TextProcessorFactoryException when can't build Document
*/
public Configuration create(InputStream stream) {
try {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setValidating(false);
factory.setIgnoringElementContentWhitespace(true);
factory.setNamespaceAware(true);
DocumentBuilder documentBuilder = factory.newDocumentBuilder();
Document document = documentBuilder.parse(stream);
return domConfigurationFactory.create(document);
} catch (ParserConfigurationException e) {
throw new TextProcessorFactoryException(e);
} catch (IOException e) {
throw new TextProcessorFactoryException(e);
} catch (SAXException e) {
throw new TextProcessorFactoryException(e);
}
}
}