/*
* Copyright 2008 Lockheed Martin Corporation, except as stated in the file
* entitled Licensing-Information. All modifications copyright 2009 Data Access Technologies, Inc. Licensed under the Academic Free License
* version 3.0 (http://www.opensource.org/licenses/afl-3.0.php), except as stated
* in the file entitled Licensing-Information.
*
* Contributors:
* MDS - initial API and implementation
*
*/
package org.modeldriven.fuml.config;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.JAXBException;
import javax.xml.bind.UnmarshalException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.modeldriven.fuml.FumlException;
import org.modeldriven.fuml.FumlSystemProperty;
import org.modeldriven.fuml.bind.DefaultValidationEventHandler;
import org.xml.sax.SAXException;
import org.modeldriven.fuml.repository.Classifier;
import org.modeldriven.fuml.repository.Property;
public class FumlConfiguration {
private static Log log = LogFactory.getLog(FumlConfiguration.class);
private static FumlConfiguration instance = null;
private static String defaultConfigFileName = "DefaultFumlConfig.xml";
private Map<String, BehaviorExecutionMapping> executions =
new HashMap<String, BehaviorExecutionMapping>();
/** maps import exemptions to XML element local names */
private Map<String, ImportExemption> importExemptions = new HashMap<String, ImportExemption>();
private Map<String, ImportAdapter> importAdapters = new HashMap<String, ImportAdapter>();
private Map<String, NamespaceMapping> pathmaps = new HashMap<String, NamespaceMapping>();
/** maps validation exemptions to classifier names */
private Map<String, List<ValidationExemption>> validationExemptions = new HashMap<String, List<ValidationExemption>>();
private String activeConfigFileName;
private Configuration config;
private FumlConfiguration()
{
log.info("initializing...");
try {
FumlConfigDataBinding configBinding = new FumlConfigDataBinding(
new DefaultValidationEventHandler());
activeConfigFileName = System.getProperty(FumlSystemProperty.CONFIG.getProperty(),
defaultConfigFileName);
log.info("loading configuration, " + activeConfigFileName);
config = unmarshalConfig(activeConfigFileName, configBinding);
if (config.getMappingConfiguration().getBehaviorExecutionMapping() != null)
for (BehaviorExecutionMapping mapping : config.getMappingConfiguration().getBehaviorExecutionMapping())
{
executions.put(mapping.getClassName(), mapping);
Class.forName(mapping.getExecutionClassName()); // execution classes must exist on the classpath
}
if (config.getImportConfiguration().getNamespaceMapping() != null)
for (NamespaceMapping mapping : config.getImportConfiguration().getNamespaceMapping()) {
NamespaceDomain pathmapDomain = mapping.getDomain();
NamespaceDomain targetDomain = this.getNamespaceDomain(mapping.getUri());
if (pathmapDomain.ordinal() != targetDomain.ordinal())
throw new FumlConfigurationException("namespace domain '" + pathmapDomain.name() + "' for namespace mapping '"
+ mapping.getPathmap() + "' does not match namspace domain ("+targetDomain.name()+") of target URI");
if (!mapping.getTarget().startsWith(mapping.getUri())) {
throw new FumlConfigurationException("target for namespace mapping '"
+ mapping.getPathmap() + "' for namspace domain ("+targetDomain.name()+") expected to contain (start with) domain uri '"
+ mapping.getUri() + "'");
}
pathmaps.put(mapping.getPathmap(), mapping);
}
if (config.getImportConfiguration().getExemption() != null)
for (ImportExemption e : config.getImportConfiguration().getExemption())
importExemptions.put(e.getLocalName(), e);
if (config.getImportConfiguration().getAdapter() != null)
for (ImportAdapter adapter : config.getImportConfiguration().getAdapter())
importAdapters.put(adapter.getClassName(), adapter);
if (config.getValidationConfiguration().getExemption() != null)
for (ValidationExemption exemption : config.getValidationConfiguration().getExemption())
{
List<ValidationExemption> list = validationExemptions.get(exemption.getClassifierName());
if (list == null) {
list = new ArrayList<ValidationExemption>();
validationExemptions.put(exemption.getClassifierName(), list);
}
list.add(exemption);
}
}
catch (SAXException e) {
throw new FumlException(e);
}
catch (JAXBException e) {
throw new FumlException(e);
}
catch (ClassNotFoundException e) {
throw new FumlException(e);
}
}
@SuppressWarnings("unchecked")
private Configuration unmarshalConfig(String configFileName, FumlConfigDataBinding binding)
{
try {
InputStream stream = FumlConfiguration.class.getClassLoader().getResourceAsStream(configFileName);
if (stream == null)
stream = FumlConfiguration.class.getResourceAsStream(configFileName);
if (stream == null)
throw new FumlException("cannot find resource '" + configFileName + "' on current classpath");
JAXBElement root = (JAXBElement)binding.validate(stream);
Configuration result = (Configuration)root.getValue();
return result;
}
catch (UnmarshalException e) {
throw new FumlException(e);
}
catch (JAXBException e) {
throw new FumlException(e);
}
}
public static FumlConfiguration getInstance()
throws FumlException
{
if (instance == null)
initializeInstance();
return instance;
}
private static synchronized void initializeInstance()
throws FumlException
{
if (instance == null)
instance = new FumlConfiguration();
}
public Configuration getConfig() {
return config;
}
//FIXME: map this - inefficient
public String[] getSupportedNamespaceURIsForDomain(NamespaceDomain domain)
{
List<String> list = new ArrayList<String>();
Iterator<SupportedNamespace> namespaces =
getConfig().getImportConfiguration().getSupportedNamespace().iterator();
while (namespaces.hasNext())
{
SupportedNamespace namespace = namespaces.next();
if (namespace.getDomain().value().equals(domain.value()))
list.add(namespace.getUri());
}
String[] results = new String[list.size()];
list.toArray(results);
return results;
}
//FIXME: map this - inefficient
public NamespaceDomain getNamespaceDomain(String namespaceUri)
{
NamespaceDomain result = findNamespaceDomain(namespaceUri);
if (result == null)
throw new FumlException("no namespace domain found for URI '"
+ namespaceUri + "' - please add this URI to the set of supported namespaces for the appropriate domain");
return result;
}
//FIXME: map this - inefficient
public NamespaceDomain findNamespaceDomain(String namespaceUri)
{
Iterator<SupportedNamespace> namespaces =
getConfig().getImportConfiguration().getSupportedNamespace().iterator();
while (namespaces.hasNext())
{
SupportedNamespace namespace = namespaces.next();
if (namespace.getUri().equals(namespaceUri))
return namespace.getDomain();
}
return null;
}
public NamespaceMapping findPathmap(String path) {
return this.pathmaps.get(path);
}
public boolean hasReferenceMapping(Classifier classifier, Property property)
{
Iterator<ReferenceMapping> mappings =
getConfig().getMappingConfiguration().getReferenceMapping().iterator();
while (mappings.hasNext())
{
ReferenceMapping mapping = mappings.next();
if (mapping.getClassName().equals(classifier.getName()) &&
mapping.getPropertyName().equals(property.getName()))
return true;
}
return false;
}
public ReferenceMappingType getReferenceMappingType(Classifier classifier, Property property)
{
Iterator<ReferenceMapping> mappings =
getConfig().getMappingConfiguration().getReferenceMapping().iterator();
while (mappings.hasNext())
{
ReferenceMapping mapping = mappings.next();
if (mapping.getClassName().equals(classifier.getName()) &&
mapping.getPropertyName().equals(property.getName()))
return mapping.getType();
}
throw new FumlException("no mapping found for, "
+ classifier.getName() + "." + property.getName());
}
public String findExecutionClassName(String name)
{
BehaviorExecutionMapping mapping = this.executions.get(name);
if (mapping != null)
return mapping.getExecutionClassName();
return null;
}
public String getActiveConfigFileName() {
return activeConfigFileName;
}
/**
* Return the import exception for the goven element local name, if exists
* @param localName the element local name
* @return the import exception or null if not exists
*/
public ImportExemption findImportExemptionByElement(String localName) {
return this.importExemptions.get(localName);
}
public ImportAdapter findImportAdapter(String name) {
return this.importAdapters.get(name);
}
/**
* Returns the list of validation exemptions for the given classifier name.
* @param classifierName the unqualified classifier name
* @return the validation exemptions or
*/
public List<ValidationExemption> findValidationExemptionByClassifierName(String classifierName) {
return this.validationExemptions.get(classifierName);
}
public ValidationExemption findValidationExemptionByProperty(ValidationExemptionType type,
Classifier classifier, String propertyName, String namespaceURI, NamespaceDomain domain) {
ValidationExemption result = null;
if (domain != null) {
List<ValidationExemption> exemptions = findValidationExemptionByClassifierName(classifier.getName());
if (exemptions != null)
for (ValidationExemption exemption : exemptions)
if (exemption.getPropertyName() != null &&
exemption.getPropertyName().equals(propertyName) &&
exemption.getDomain().ordinal() == domain.ordinal() &&
exemption.getType().ordinal() == type.ordinal()) {
result = exemption;
break;
}
}
else
if (log.isDebugEnabled())
log.debug("could not lookup validation exemption for namespace URI '"
+ "namespaceURI");
return result;
}
public ValidationExemption findValidationExemptionByReference(ValidationExemptionType type,
Classifier classifier, String reference, String namespaceURI, NamespaceDomain domain) {
ValidationExemption result = null;
if (domain != null) {
List<ValidationExemption> exemptions = findValidationExemptionByClassifierName(classifier.getName());
if (exemptions != null)
for (ValidationExemption exemption : exemptions)
if (exemption.getHref().equals(reference) &&
exemption.getDomain().ordinal() == domain.ordinal() &&
exemption.getType().ordinal() == type.ordinal()) {
result = exemption;
break;
}
}
else
if (log.isDebugEnabled())
log.debug("could not lookup validation exemption for namespace URI '"
+ "namespaceURI");
return result;
}
}