blob: e356d4e1bb8afb59278c0cf476c928bd7962d55e [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.openejb.config.sys;
import org.apache.openejb.config.AppModule;
import org.apache.openejb.config.BeanProperties;
import org.apache.openejb.config.DeploymentModule;
import org.apache.openejb.config.EjbModule;
import org.apache.openejb.config.EnvEntriesPropertiesDeployer;
import org.apache.openejb.config.PojoConfiguration;
import org.apache.openejb.config.WebModule;
import org.apache.openejb.loader.SystemInstance;
import org.apache.openejb.util.LogCategory;
import org.apache.openejb.util.Logger;
import org.apache.openejb.util.Saxs;
import org.xml.sax.Attributes;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
import javax.xml.parsers.ParserConfigurationException;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Properties;
public class SaxAppCtxConfig {
private static final Logger LOGGER = Logger.getInstance(LogCategory.OPENEJB_STARTUP_CONFIG, SaxAppContextConfig.class);
public static void parse(final AppModule appModule, final InputSource source,
final EnvEntriesPropertiesDeployer envEntriesDeployer, final BeanProperties beanProperties)
throws SAXException, ParserConfigurationException, IOException {
Saxs.factory()
.newSAXParser()
.parse(source, new SaxAppContextConfig(appModule, envEntriesDeployer, beanProperties));
}
private static class SaxAppContextConfig extends StackHandler {
private static final Collection<String> IMPORT_ALIASES = Arrays.asList("import", "include");
private static final Collection<String> APPLICATION_ALIASES = Arrays.asList("appcontext", "app-context", "application");
private static final Collection<String> POJOS_ALIASES = Arrays.asList("pojocontexts", "pojo-contexts", "pojos");
private static final Collection<String> POJO_ALIASES = Arrays.asList("pojo");
private static final Collection<String> BEAN_CONTEXTS_ALIASES = Arrays.asList("beancontexts", "bean-contexts", "ejbs");
private static final Collection<String> WEBAPP_ALIASES = Arrays.asList("webapps", "webcontexts", "web-contexts", "wars");
private static final Collection<String> MODULE_ALIASES = Arrays.asList("modulecontext", "module");
private static final Collection<String> BEAN_CONTEXT_ALIASES = Arrays.asList("ejb", "beancontext", "bean-context");
private static final Collection<String> CONFIGURATION_ALIASES = Arrays.asList("configuration", "properties", "settings");
private static final Collection<String> RESOURCES_ALIASES = Arrays.asList("resources");
private static final Collection<String> SERVICE_ALIASES = Arrays.asList("service");
private static final Collection<String> RESOURCE_ALIASES = Arrays.asList("resource");
private static final Collection<String> ENV_ENTRIES_ALIASES = Arrays.asList("enventries", "env-entries");
private static final Collection<String> ENV_ENTRY_ALIASES = Arrays.asList("enventry", "env-entry");
private final AppModule module;
private final EnvEntriesPropertiesDeployer envEntriesDeployer;
private final BeanProperties beanPropertiesDeployer;
public SaxAppContextConfig(final AppModule appModule, final EnvEntriesPropertiesDeployer envEntriesDeployer, final BeanProperties beanProperties) {
this.module = appModule;
this.envEntriesDeployer = envEntriesDeployer;
this.beanPropertiesDeployer = beanProperties;
}
@Override
public void startDocument() throws SAXException {
push(new Document());
}
private class Document extends DefaultHandler {
@Override
public void startElement(final String uri, final String localName, final String qName, final Attributes attributes) throws SAXException {
// by default don't care about root tag
if (!APPLICATION_ALIASES.contains(localName.toLowerCase())
&& SystemInstance.get().getOptions().get("openejb.configuration.strict-tags", false)) {
throw new IllegalStateException("Unsupported Element: " + localName);
}
push(new Root());
}
}
private class Root extends DefaultHandler {
@Override
public void startElement(final String uri, final String localName, final String qName, final Attributes attributes) throws SAXException {
final String name = localName.toLowerCase();
if (CONFIGURATION_ALIASES.contains(name)) {
push(new Configuration("", module.getProperties()));
} else if (ENV_ENTRIES_ALIASES.contains(name)) {
push(new EnvEntries());
} else if (BEAN_CONTEXTS_ALIASES.contains(name)) {
push(new BeanContexts(null));
} else if (MODULE_ALIASES.contains(name)) {
push(new ModuleContext(attributes.getValue("id")));
} else if (WEBAPP_ALIASES.contains(name)) {
push(new WebAppContext(attributes.getValue("id")));
} else if (POJOS_ALIASES.contains(name)) {
push(new Pojos());
} else if (RESOURCES_ALIASES.contains(name)) {
push(new ResourcesConfig());
} else if (IMPORT_ALIASES.contains(name)) {
importFile(attributes.getValue("path"));
push(new DefaultHandler()); // just to keep the stack consistent
} else {
throw new IllegalStateException("Unsupported Element: " + localName);
}
}
private void importFile(final String path) throws SAXException {
final File file = new File(path);
if (file.exists()) {
try {
parse(module, new InputSource(new FileInputStream(file)), envEntriesDeployer, beanPropertiesDeployer);
} catch (ParserConfigurationException e) {
throw new SAXException(e);
} catch (IOException e) {
throw new SAXException(e);
}
} else { // try in the classpath
final ClassLoader cl = module.getClassLoader();
if (cl != null) {
final InputStream is = cl.getResourceAsStream(path);
if (is != null) {
try {
parse(module, new InputSource(is), envEntriesDeployer, beanPropertiesDeployer);
} catch (ParserConfigurationException e) {
throw new SAXException(e);
} catch (IOException e) {
throw new SAXException(e);
}
} else {
LOGGER.warning("Can't find " + path);
}
} else {
LOGGER.warning("Can't find " + path + ", no classloader for the module " + module);
}
}
}
}
private class Configuration extends Content {
private final Properties properties;
private final String prefix;
private Configuration(final String prefix, final Properties properties) {
this.properties = properties;
this.prefix = prefix;
}
@Override
public void startElement(final String uri, final String localName, final String qName, final Attributes attributes) {
push(new Configuration(prefix + localName + ".", properties));
}
@Override
public void setValue(final String text) {
if (properties == null) {
return;
}
try {
for (Map.Entry<Object, Object> entry : new PropertiesAdapter().unmarshal(text).entrySet()) {
properties.put(prefix + entry.getKey(), entry.getValue());
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
private class MultipleConfiguration extends Content {
private final Collection<Properties> properties;
private final String prefix;
private MultipleConfiguration(final String prefix, final Collection<Properties> properties) {
this.properties = properties;
this.prefix = prefix;
}
@Override
public void startElement(final String uri, final String localName, final String qName, final Attributes attributes) {
push(new MultipleConfiguration(prefix + localName + ".", properties));
}
@Override
public void setValue(final String text) {
if (properties == null) {
return;
}
try {
for (Properties p : properties) {
for (Map.Entry<Object, Object> entry : new PropertiesAdapter().unmarshal(text).entrySet()) {
p.put(prefix + entry.getKey(), entry.getValue());
}
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
private class Pojos extends DefaultHandler {
protected final List<PojoConfig> genericConfigs = new ArrayList<PojoConfig>();
protected final Collection<String> aliases;
private Pojos() {
this(POJO_ALIASES);
}
protected Pojos(final Collection<String> aliases) {
this.aliases = aliases;
}
@Override
public void startElement(final String uri, final String localName, final String qName, final Attributes attributes) throws SAXException {
if (aliases.contains(localName.toLowerCase())) {
final PojoConfig beanConfig = newItem();
final String id = attributes.getValue("id");
if (id == null || "*".equals(id)) {
genericConfigs.add(beanConfig);
}
push(childParser(id, beanConfig));
} else {
throw new IllegalStateException("Unsupported Element: " + localName);
}
}
protected DefaultHandler childParser(final String id, final PojoConfig beanConfig) {
return new Pojo(id, beanConfig);
}
protected PojoConfig newItem() {
return new PojoConfig();
}
@Override
public void endElement(final String uri, final String localName, final String qName) throws SAXException {
for (PojoConfig generic : genericConfigs) {
for (PojoConfiguration config : module.getPojoConfigurations().values()) {
for (String key : generic.getProperties().stringPropertyNames()) {
if (!config.getProperties().containsKey(key)) {
config.getProperties().put(key, generic.getProperties().get(key));
}
}
}
}
}
}
private class ModuleContext extends DefaultHandler {
protected final String id;
private ModuleContext(final String id) {
this.id = id;
}
@Override
public void startElement(final String uri, final String localName, final String qName, final Attributes attributes) throws SAXException {
final String name = localName.toLowerCase();
if (BEAN_CONTEXTS_ALIASES.contains(name)) {
push(new BeanContexts(id));
} else if (POJOS_ALIASES.contains(name)) {
push(new Pojos());
} else if (CONFIGURATION_ALIASES.contains(name)) {
push(new MultipleConfiguration("", propertiesForModule(id)));
} else {
throw new IllegalStateException("Unsupported Element: " + localName);
}
}
protected Collection<Properties> propertiesForModule(final String id) {
final Collection<Properties> props = new ArrayList<Properties>();
for (DeploymentModule m : module.getDeploymentModule()) {
if (acceptModule(id, m)) {
props.add(m.getProperties());
}
}
return props;
}
}
private class WebAppContext extends ModuleContext {
private WebAppContext(final String id) {
super(id);
}
@Override
protected Collection<Properties> propertiesForModule(final String id) {
final Collection<Properties> props = new ArrayList<Properties>();
for (WebModule m : module.getWebModules()) {
if (acceptModule(id, m)) {
props.add(m.getProperties());
}
}
return props;
}
}
private class BeanContexts extends Pojos {
private final String id;
public BeanContexts(final String id) {
super(BEAN_CONTEXT_ALIASES);
this.id = id;
}
@Override
protected DefaultHandler childParser(final String beanId, final PojoConfig beanConfig) {
return new BeanContext(id, beanId, (BeanContextConfig) beanConfig);
}
@Override
protected PojoConfig newItem() {
return new BeanContextConfig();
}
@Override
public void endElement(final String uri, final String localName, final String qName) throws SAXException {
for (PojoConfig generic : genericConfigs) { // BeanContextConfig
if (generic.hasProperties()) {
beanPropertiesDeployer.addGlobalProperties(id, generic.getProperties());
}
}
}
}
private class Pojo extends DefaultHandler {
protected final PojoConfig pojoConfig;
protected final String id;
public Pojo(final String id, final PojoConfig beanConfig) {
this.id = id;
pojoConfig = beanConfig;
}
@Override
public void startElement(final String uri, final String localName, final String qName, final Attributes attributes) throws SAXException {
if (CONFIGURATION_ALIASES.contains(localName.toLowerCase())) {
push(new Configuration("", pojoConfig.getProperties()));
} else {
throw new IllegalStateException("Unsupported Element: " + localName);
}
}
@Override
public void endElement(final String uri, final String localName, final String qName) throws SAXException {
module.getPojoConfigurations().put(id, new PojoConfiguration(pojoConfig.getProperties()));
}
}
private class BeanContext extends Pojo {
private final String moduleId;
public BeanContext(final String moduleId, final String id, final BeanContextConfig beanConfig) {
super(id, beanConfig);
this.moduleId = moduleId;
}
@Override
public void endElement(final String uri, final String localName, final String qName) throws SAXException {
for (EjbModule ejbModule : module.getEjbModules()) {
if (!acceptModule(moduleId, ejbModule)) {
continue;
}
if (pojoConfig.hasProperties()) {
beanPropertiesDeployer.addProperties(id, pojoConfig.getProperties());
}
}
}
}
private class ResourcesConfig extends DefaultHandler {
@Override
public void startElement(final String uri, final String localName, final String qName, final Attributes attributes) throws SAXException {
final String name = localName.toLowerCase();
if (SERVICE_ALIASES.contains(name)) {
push(new DeclaredServiceElement(module.getServices()));
} else if (RESOURCE_ALIASES.contains(name)) {
push(new ResourceElement(module.getResources()));
} else {
throw new IllegalStateException("Unsupported Element: " + localName);
}
get().startElement(uri, localName, qName, attributes);
}
}
private class EnvEntries extends DefaultHandler {
@Override
public void startElement(final String uri, final String localName, final String qName, final Attributes attributes) throws SAXException {
if (ENV_ENTRY_ALIASES.contains(localName.toLowerCase())) {
push(new EnvEntry());
get().startElement(uri, localName, qName, attributes);
} else {
throw new IllegalStateException("Unsupported Element: " + localName);
}
}
}
private class EnvEntry extends Content {
private String key;
@Override
public void startElement(final String uri, final String localName, final String qName, final Attributes attributes) {
if (ENV_ENTRY_ALIASES.contains(localName.toLowerCase())) {
key = attributes.getValue("key");
} else {
throw new IllegalStateException("Unsupported Element: " + localName);
}
}
@Override
public void setValue(final String text) {
envEntriesDeployer.addEnvEntries(key, text);
}
}
}
private static boolean acceptModule(final String id, final DeploymentModule ejbModule) {
return id == null || id.equals(ejbModule.getModuleId());
}
}