/*
 * JBoss, Home of Professional Open Source
 * Copyright 2010, Red Hat Inc., and individual contributors as indicated
 * by the @authors tag. See the copyright.txt in the distribution for a
 * full listing of individual contributors.
 *
 * This is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; either version 2.1 of
 * the License, or (at your option) any later version.
 *
 * This software is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this software; if not, write to the Free
 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
 */
package org.jboss.as.appclient.subsystem;

import java.io.File;
import java.io.IOException;
import java.io.PrintStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.ExecutorService;

import javax.xml.namespace.QName;

import org.jboss.as.appclient.logging.AppClientLogger;
import org.jboss.as.appclient.subsystem.parsing.AppClientXml;
import org.jboss.as.controller.extension.ExtensionRegistry;
import org.jboss.as.controller.parsing.Namespace;
import org.jboss.as.controller.persistence.ExtensibleConfigurationPersister;
import org.jboss.as.process.CommandLineConstants;
import org.jboss.as.server.Bootstrap;
import org.jboss.as.server.ServerEnvironment;
import org.jboss.as.server.SystemExiter;
import org.jboss.as.version.ProductConfig;
import org.jboss.modules.Module;
import org.jboss.modules.ModuleIdentifier;
import org.jboss.msc.service.ServiceActivator;
import org.jboss.stdio.LoggingOutputStream;
import org.jboss.stdio.NullInputStream;
import org.jboss.stdio.SimpleStdioContextSelector;
import org.jboss.stdio.StdioContext;
import org.wildfly.security.manager.WildFlySecurityManager;

/**
 * The application client entry point
 *
 * @author Stuart Douglas
 */
public final class Main {
    // Capture System.out and System.err before they are redirected by STDIO
    private static final PrintStream STDOUT = System.out;
    private static final PrintStream STDERR = System.err;

    private static void usage() {
        CommandLineArgumentUsageImpl.printUsage(STDOUT);
    }

    private Main() {
    }

    /**
     * The main method.
     *
     * @param args the command-line arguments
     */
    public static void main(String[] args) {

        if (java.util.logging.LogManager.getLogManager().getClass().getName().equals("org.jboss.logmanager.LogManager")) {
            // Make sure our original stdio is properly captured.
            try {
                Class.forName(org.jboss.logmanager.handlers.ConsoleHandler.class.getName(), true, org.jboss.logmanager.handlers.ConsoleHandler.class.getClassLoader());
            } catch (Throwable ignored) {
            }
            // Install JBoss Stdio to avoid any nasty crosstalk, after command line arguments are processed.
            StdioContext.install();
            final StdioContext context = StdioContext.create(
                    new NullInputStream(),
                    new LoggingOutputStream(org.jboss.logmanager.Logger.getLogger("stdout"), org.jboss.logmanager.Level.INFO),
                    new LoggingOutputStream(org.jboss.logmanager.Logger.getLogger("stderr"), org.jboss.logmanager.Level.ERROR)
            );
            StdioContext.setStdioContextSelector(new SimpleStdioContextSelector(context));
        }

        try {
            Module.registerURLStreamHandlerFactoryModule(Module.getBootModuleLoader().loadModule(ModuleIdentifier.create("org.jboss.vfs")));

            final ParsedOptions options = determineEnvironment(args, new Properties(WildFlySecurityManager.getSystemPropertiesPrivileged()), WildFlySecurityManager.getSystemEnvironmentPrivileged(), ServerEnvironment.LaunchType.APPCLIENT);
            if(options == null) {
                //this happens if --version was specified
                return;
            }
            ServerEnvironment serverEnvironment = options.environment;
            final List<String> clientArgs = options.clientArguments;

            if (clientArgs.isEmpty()) {
                STDERR.println(AppClientLogger.ROOT_LOGGER.appClientNotSpecified());
                usage();
                abort(null);
            } else {

                final QName rootElement = new QName(Namespace.CURRENT.getUriString(), "server");
                final String file = clientArgs.get(0);
                final List<String> params = clientArgs.subList(1, clientArgs.size());
                final String deploymentName;
                final String earPath;

                int pos = file.lastIndexOf("#");
                if (pos == -1) {
                    earPath = file;
                    deploymentName = null;
                } else {
                    deploymentName = file.substring(pos + 1);
                    earPath = file.substring(0, pos);
                }

                File realFile = new File(earPath);

                if (!realFile.exists()) {
                    throw AppClientLogger.ROOT_LOGGER.cannotFindAppClientFile(realFile.getAbsoluteFile());
                }

                final Bootstrap bootstrap = Bootstrap.Factory.newInstance();
                final Bootstrap.Configuration configuration = new Bootstrap.Configuration(serverEnvironment);
                configuration.setModuleLoader(Module.getBootModuleLoader());
                final ExtensionRegistry extensionRegistry = configuration.getExtensionRegistry();
                final AppClientXml parser = new AppClientXml(Module.getBootModuleLoader(), extensionRegistry);
                final Bootstrap.ConfigurationPersisterFactory configurationPersisterFactory = new Bootstrap.ConfigurationPersisterFactory() {

                    @Override
                    public ExtensibleConfigurationPersister createConfigurationPersister(ServerEnvironment serverEnvironment, ExecutorService executorService) {
                        ApplicationClientConfigurationPersister persister = new ApplicationClientConfigurationPersister(earPath, deploymentName, options.hostUrl,options.propertiesFile, params,
                                serverEnvironment.getServerConfigurationFile().getBootFile(), rootElement, parser);
                        for (Namespace namespace : Namespace.domainValues()) {
                            if (!namespace.equals(Namespace.CURRENT)) {
                                persister.registerAdditionalRootElement(new QName(namespace.getUriString(), "server"), parser);
                            }
                        }
                        extensionRegistry.setWriterRegistry(persister);
                        return persister;
                    }
                };
                configuration.setConfigurationPersisterFactory(configurationPersisterFactory);
                bootstrap.bootstrap(configuration, Collections.<ServiceActivator>emptyList()).get();
            }
        } catch (Throwable t) {
            abort(t);
        }
    }

    private static void abort(Throwable t) {
        try {
            if (t != null) {
                t.printStackTrace(STDERR);
            }
        } finally {
            SystemExiter.exit(1);
        }
    }

    public static ParsedOptions determineEnvironment(String[] args, Properties systemProperties, Map<String, String> systemEnvironment, ServerEnvironment.LaunchType launchType) {
        List<String> clientArguments = new ArrayList<String>();
        ParsedOptions ret = new ParsedOptions();
        ret.clientArguments = clientArguments;
        final int argsLength = args.length;
        String appClientConfig = "appclient.xml";
        boolean clientArgs = false;
        ProductConfig productConfig;
        boolean hostSet = false;

        for (int i = 0; i < argsLength; i++) {
            final String arg = args[i];
            try {
                if (clientArgs) {
                    clientArguments.add(arg);
                } else if (CommandLineConstants.VERSION.equals(arg) || CommandLineConstants.SHORT_VERSION.equals(arg)
                        || CommandLineConstants.OLD_VERSION.equals(arg) || CommandLineConstants.OLD_SHORT_VERSION.equals(arg)) {
                    productConfig = new ProductConfig(Module.getBootModuleLoader(), WildFlySecurityManager.getPropertyPrivileged(ServerEnvironment.HOME_DIR, null), null);
                    STDOUT.println(productConfig.getPrettyVersionString());
                    return null;
                } else if (CommandLineConstants.HELP.equals(arg) || CommandLineConstants.SHORT_HELP.equals(arg) || CommandLineConstants.OLD_HELP.equals(arg)) {
                    usage();
                    return null;
                } else if (CommandLineConstants.PROPERTIES.equals(arg) || CommandLineConstants.OLD_PROPERTIES.equals(arg)
                        || CommandLineConstants.SHORT_PROPERTIES.equals(arg)) {
                    // Set system properties from url/file
                    if (!processProperties(arg, args[++i])) {
                        return null;
                    }
                } else if (arg.startsWith(CommandLineConstants.PROPERTIES)) {
                    String urlSpec = parseValue(arg, CommandLineConstants.PROPERTIES);
                    if (urlSpec == null || !processProperties(arg, urlSpec)) {
                        return null;
                    }
                } else if (arg.startsWith(CommandLineConstants.SHORT_PROPERTIES)) {
                    String urlSpec = parseValue(arg, CommandLineConstants.SHORT_PROPERTIES);
                    if (urlSpec == null || !processProperties(arg, urlSpec)) {
                        return null;
                    }
                } else if (arg.startsWith(CommandLineConstants.OLD_PROPERTIES)) {
                    String urlSpec = parseValue(arg, CommandLineConstants.OLD_PROPERTIES);
                    if (urlSpec == null || !processProperties(arg, urlSpec)) {
                        return null;
                    }
                } else if (arg.equals(CommandLineConstants.SHORT_HOST) || arg.equals(CommandLineConstants.HOST)) {
                    if(ret.propertiesFile != null) {
                        throw AppClientLogger.ROOT_LOGGER.cannotSpecifyBothHostAndPropertiesFile();
                    }
                    hostSet = true;
                    String urlSpec = args[++i];
                    ret.hostUrl = urlSpec;
                } else if (arg.startsWith(CommandLineConstants.SHORT_HOST)) {
                    if(ret.propertiesFile != null) {
                        throw AppClientLogger.ROOT_LOGGER.cannotSpecifyBothHostAndPropertiesFile();
                    }
                    hostSet = true;
                    String urlSpec = parseValue(arg, CommandLineConstants.SHORT_HOST);
                    ret.hostUrl = urlSpec;
                } else if (arg.startsWith(CommandLineConstants.HOST)) {
                    if(ret.propertiesFile != null) {
                        throw AppClientLogger.ROOT_LOGGER.cannotSpecifyBothHostAndPropertiesFile();
                    }
                    hostSet = true;
                    String urlSpec = parseValue(arg, CommandLineConstants.HOST);
                    ret.hostUrl = urlSpec;
                } else if (arg.startsWith(CommandLineConstants.CONNECTION_PROPERTIES)) {
                    if(hostSet) {
                        throw AppClientLogger.ROOT_LOGGER.cannotSpecifyBothHostAndPropertiesFile();
                    }
                    String fileUrl = parseValue(arg, CommandLineConstants.CONNECTION_PROPERTIES);
                    ret.propertiesFile = fileUrl;
                }else if (arg.startsWith(CommandLineConstants.SYS_PROP)) {

                    // set a system property
                    String name, value;
                    int idx = arg.indexOf("=");
                    if (idx == -1) {
                        name = arg.substring(2);
                        value = "true";
                    } else {
                        name = arg.substring(2, idx);
                        value = arg.substring(idx + 1, arg.length());
                    }
                    systemProperties.setProperty(name, value);
                    WildFlySecurityManager.setPropertyPrivileged(name, value);
                } else if (arg.startsWith(CommandLineConstants.APPCLIENT_CONFIG)) {
                    appClientConfig = parseValue(arg, CommandLineConstants.APPCLIENT_CONFIG);
                } else if (CommandLineConstants.SECMGR.equals(arg)) {
                    // ignore the argument as it's allowed, but passed to jboss-modules and not used here
                } else {
                    if (arg.startsWith("-")) {
                        STDOUT.println(AppClientLogger.ROOT_LOGGER.unknownOption(arg));
                        usage();

                        return null;
                    }
                    clientArgs = true;
                    clientArguments.add(arg);
                }
            } catch (IndexOutOfBoundsException e) {
                STDERR.println(AppClientLogger.ROOT_LOGGER.argumentExpected(arg));
                usage();
                return null;
            }
        }

        String hostControllerName = null; // No host controller unless in domain mode.
        productConfig = new ProductConfig(Module.getBootModuleLoader(), WildFlySecurityManager.getPropertyPrivileged(ServerEnvironment.HOME_DIR, null), systemProperties);
        ret.environment = new ServerEnvironment(hostControllerName, systemProperties, systemEnvironment, appClientConfig, null, launchType, null, productConfig);
        return ret;
    }

    private static String parseValue(final String arg, final String key) {
        String value = null;
        int splitPos = key.length();
        if (arg.length() <= splitPos + 1 || arg.charAt(splitPos) != '=') {
            usage();
        } else {
            value = arg.substring(splitPos + 1);
        }
        return value;
    }

    private static boolean processProperties(final String arg, final String urlSpec) {
        URL url = null;
        try {
            url = makeURL(urlSpec);
            Properties props = System.getProperties();
            props.load(url.openConnection().getInputStream());
            return true;
        } catch (MalformedURLException e) {
            STDERR.println(AppClientLogger.ROOT_LOGGER.malformedUrl(arg));
            usage();
            return false;
        } catch (IOException e) {
            STDERR.println(AppClientLogger.ROOT_LOGGER.cannotLoadProperties(url));
            usage();
            return false;
        }
    }

    private static URL makeURL(String urlspec) throws MalformedURLException {
        urlspec = urlspec.trim();

        URL url;

        try {
            url = new URL(urlspec);
            if (url.getProtocol().equals("file")) {
                // make sure the file is absolute & canonical file url
                File file = new File(url.getFile()).getCanonicalFile();
                url = file.toURI().toURL();
            }
        } catch (Exception e) {
            // make sure we have an absolute & canonical file url
            try {
                File file = new File(urlspec).getCanonicalFile();
                url = file.toURI().toURL();
            } catch (Exception n) {
                throw new MalformedURLException(n.toString());
            }
        }

        return url;
    }

    private static final class ParsedOptions {
        ServerEnvironment environment;
        List<String> clientArguments;
        // by default we use http upgrade support of the Undertow web server
        String hostUrl = "http-remoting://localhost:8080";
        String propertiesFile;
    }
}


/*
 * JBoss, Home of Professional Open Source.
 * Copyright 2008, Red Hat Middleware LLC, and individual contributors
 * as indicated by the @author tags. See the copyright.txt file in the
 * distribution for a full listing of individual contributors.
 *
 * This is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; either version 2.1 of
 * the License, or (at your option) any later version.
 *
 * This software is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this software; if not, write to the Free
 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
 */
package org.wildfly.iiop.openjdk.rmi.ir;

import org.omg.CORBA.Any;
import org.omg.CORBA.AttributeDef;
import org.omg.CORBA.AttributeDefOperations;
import org.omg.CORBA.AttributeDefPOATie;
import org.omg.CORBA.AttributeDescription;
import org.omg.CORBA.AttributeDescriptionHelper;
import org.omg.CORBA.AttributeMode;
import org.omg.CORBA.ContainedOperations;
import org.omg.CORBA.ContainedPackage.Description;
import org.omg.CORBA.DefinitionKind;
import org.omg.CORBA.IDLType;
import org.omg.CORBA.IDLTypeHelper;
import org.omg.CORBA.IRObject;
import org.omg.CORBA.TypeCode;
import org.wildfly.iiop.openjdk.logging.IIOPLogger;

/**
 * Attribute IR object.
 *
 * @author Ole Husgaard
 * @version $Revision: 81018 $
 */
public class AttributeDefImpl
        extends ContainedImpl
        implements AttributeDefOperations {
    // Constants -----------------------------------------------------

    // Attributes ----------------------------------------------------

    // Static --------------------------------------------------------

    // Constructors --------------------------------------------------

    AttributeDefImpl(String id, String name, String version,
                     AttributeMode mode, TypeCode typeCode,
                     LocalContainer defined_in, RepositoryImpl repository) {
        super(id, name, version, defined_in,
                DefinitionKind.dk_Attribute, repository);

        this.mode = mode;
        this.typeCode = typeCode;
    }

    // Public --------------------------------------------------------

    // LocalIRObject implementation ---------------------------------

    public IRObject getReference() {
        if (ref == null) {
            ref = org.omg.CORBA.AttributeDefHelper.narrow(
                    servantToReference(new AttributeDefPOATie(this)));
        }
        return ref;
    }

    public void allDone()
            throws IRConstructionException {
        // Get my type definition: It should have been created now.
        type_def = IDLTypeImpl.getIDLType(typeCode, repository);

        getReference();
    }

    // AttributeDefOperations implementation ----------------------------

    public TypeCode type() {
        return typeCode;
    }

    public IDLType type_def() {
        return IDLTypeHelper.narrow(type_def.getReference());
    }

    public void type_def(IDLType arg) {
        throw IIOPLogger.ROOT_LOGGER.cannotChangeRMIIIOPMapping();
    }

    public AttributeMode mode() {
        return mode;
    }

    public void mode(AttributeMode arg) {
        throw IIOPLogger.ROOT_LOGGER.cannotChangeRMIIIOPMapping();
    }

    // ContainedImpl implementation ----------------------------------

    public Description describe() {
        String defined_in_id = "IR";

        if (defined_in instanceof ContainedOperations)
            defined_in_id = ((ContainedOperations) defined_in).id();

        AttributeDescription d =
                new AttributeDescription(name, id, defined_in_id, version,
                        typeCode, mode);

        Any any = getORB().create_any();

        AttributeDescriptionHelper.insert(any, d);

        return new Description(DefinitionKind.dk_Attribute, any);
    }

    // Y overrides ---------------------------------------------------

    // Package protected ---------------------------------------------

    // Protected -----------------------------------------------------

    // Private -------------------------------------------------------

    /**
     * My CORBA reference.
     */
    private AttributeDef ref = null;

    /**
     * My mode.
     */
    private AttributeMode mode;

    /**
     * My TypeCode.
     */
    private TypeCode typeCode;

    /**
     * My type definition.
     */
    private LocalIDLType type_def;

    // Inner classes -------------------------------------------------
}


/*
 * JBoss, Home of Professional Open Source.
 * Copyright 2014, Red Hat, Inc., and individual contributors
 * as indicated by the @author tags. See the copyright.txt file in the
 * distribution for a full listing of individual contributors.
 *
 * This is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; either version 2.1 of
 * the License, or (at your option) any later version.
 *
 * This software is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this software; if not, write to the Free
 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
 */

package org.wildfly.extension.messaging.activemq.ha;

import static org.jboss.as.controller.OperationContext.Stage.MODEL;

import java.util.Collection;
import java.util.Set;

import org.jboss.as.controller.AbstractAddStepHandler;
import org.jboss.as.controller.AttributeDefinition;
import org.jboss.as.controller.OperationContext;
import org.jboss.as.controller.OperationFailedException;
import org.jboss.as.controller.OperationStepHandler;
import org.jboss.as.controller.PathAddress;
import org.jboss.as.controller.registry.Resource;
import org.jboss.dmr.ModelNode;
import org.wildfly.extension.messaging.activemq.ActiveMQReloadRequiredHandlers;
import org.wildfly.extension.messaging.activemq.logging.MessagingLogger;

/**
 * @author Jeff Mesnil (c) 2014 Red Hat inc.
 */
public class ManagementHelper {

    /**
     * Create an ADD operation that can check that there is no other sibling when the resource is added.
     *
     * @param childType the type of children to check for the existence of siblings
     * @param allowSibling whether it is allowed to have sibling for the resource that is added.
     * @param attributes the attributes of the ADD operation
     */
    static AbstractAddStepHandler createAddOperation(final String childType, final boolean allowSibling, Collection<? extends AttributeDefinition> attributes) {
        return new ActiveMQReloadRequiredHandlers.AddStepHandler(attributes) {
            @Override
            public void execute(OperationContext context, ModelNode operation) throws OperationFailedException {
                super.execute(context, operation);
                if (!allowSibling) {
                    context.addStep(checkNoOtherSibling(childType), MODEL);
                }
            }
        };
    }

    static OperationStepHandler checkNoOtherSibling(final String childType) {
        return new OperationStepHandler() {
            @Override
            public void execute(OperationContext context, ModelNode operation) throws OperationFailedException {
                PathAddress parentAddress = context.getCurrentAddress().getParent();
                Resource parent = context.readResourceFromRoot(parentAddress, false);
                Set<String> children = parent.getChildrenNames(childType);
                if (children.size() > 1) {
                    throw MessagingLogger.ROOT_LOGGER.onlyOneChildIsAllowed(childType, children);
                }
            }
        };
    }
}


/*
 * JBoss, Home of Professional Open Source.
 * Copyright 2010, Red Hat, Inc., and individual contributors
 * as indicated by the @author tags. See the copyright.txt file in the
 * distribution for a full listing of individual contributors.
 *
 * This is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; either version 2.1 of
 * the License, or (at your option) any later version.
 *
 * This software is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this software; if not, write to the Free
 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
 */

package org.jboss.as.connector.services.resourceadapters.deployment;

import static org.jboss.as.connector.logging.ConnectorLogger.DEPLOYMENT_CONNECTOR_LOGGER;

import javax.security.auth.Subject;
import java.io.File;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.Collection;
import java.util.Collections;

import org.jboss.as.connector.logging.ConnectorLogger;
import org.jboss.as.connector.metadata.deployment.ResourceAdapterDeployment;
import org.jboss.as.connector.metadata.xmldescriptors.ConnectorXmlDescriptor;
import org.jboss.as.connector.security.ElytronSubjectFactory;
import org.jboss.as.connector.services.resourceadapters.ResourceAdapterService;
import org.jboss.as.connector.subsystems.resourceadapters.ModifiableResourceAdapter;
import org.jboss.as.connector.util.ConnectorServices;
import org.jboss.as.core.security.ServerSecurityManager;
import org.jboss.as.naming.WritableServiceBasedNamingStore;
import org.jboss.jca.common.api.metadata.common.SecurityMetadata;
import org.jboss.jca.common.api.metadata.resourceadapter.Activation;
import org.jboss.jca.common.api.metadata.spec.Connector;
import org.jboss.jca.common.metadata.merge.Merger;
import org.jboss.jca.core.security.picketbox.PicketBoxSubjectFactory;
import org.jboss.jca.deployers.DeployersLogger;
import org.jboss.jca.deployers.common.CommonDeployment;
import org.jboss.jca.deployers.common.DeployException;
import org.jboss.logging.Logger;
import org.jboss.modules.Module;
import org.jboss.msc.service.Service;
import org.jboss.msc.service.ServiceBuilder;
import org.jboss.msc.service.ServiceController;
import org.jboss.msc.service.ServiceName;
import org.jboss.msc.service.ServiceTarget;
import org.jboss.msc.service.StartContext;
import org.jboss.msc.service.StartException;
import org.jboss.msc.service.StopContext;
import org.wildfly.security.manager.WildFlySecurityManager;

/**
 * A ResourceAdapterXmlDeploymentService.
 * @author Stefano Maestri
 * @author Jesper Pedersen
 */
public final class ResourceAdapterXmlDeploymentService extends AbstractResourceAdapterDeploymentService implements
        Service<ResourceAdapterDeployment> {

    private static final DeployersLogger DEPLOYERS_LOGGER = Logger.getMessageLogger(DeployersLogger.class, "org.jboss.as.connector.deployers.RaXmlDeployer");

    private final Module module;
    private final ConnectorXmlDescriptor connectorXmlDescriptor;

    private Activation raxml;
    private final String deployment;

    private String raName;
    private ServiceName deploymentServiceName;
    private CommonDeployment raxmlDeployment = null;
    private final ServiceName duServiceName;

    public ResourceAdapterXmlDeploymentService(ConnectorXmlDescriptor connectorXmlDescriptor, Activation raxml,
                                               Module module, final String deployment, final ServiceName deploymentServiceName, final ServiceName duServiceName) {
        this.connectorXmlDescriptor = connectorXmlDescriptor;
        synchronized (this) {
            this.raxml = raxml;
        }
        this.module = module;
        this.deployment = deployment;
        this.raName = deployment;
        this.deploymentServiceName = deploymentServiceName;
        this.duServiceName = duServiceName;
    }

    /**
     * Start
     */
    @Override
    public void start(StartContext context) throws StartException {
        try {
            Connector cmd = mdr.getValue().getResourceAdapter(deployment);
            File root = mdr.getValue().getRoot(deployment);

            Activation localRaXml = getRaxml();
            cmd = (new Merger()).mergeConnectorWithCommonIronJacamar(localRaXml, cmd);

            String id = ((ModifiableResourceAdapter) raxml).getId();
            final ServiceName raServiceName;
            if (id == null || id.trim().isEmpty()) {
                raServiceName = ConnectorServices.getResourceAdapterServiceName(raName);
                this.connectorServicesRegistrationName = raName;
            } else {
                raServiceName = ConnectorServices.getResourceAdapterServiceName(id);
                this.connectorServicesRegistrationName = id;
            }
            final WildFlyRaXmlDeployer raDeployer = new WildFlyRaXmlDeployer(context.getChildTarget(), connectorXmlDescriptor.getUrl(),
                raName, root, module.getClassLoader(), cmd, localRaXml, deploymentServiceName);

            raDeployer.setConfiguration(config.getValue());

            WritableServiceBasedNamingStore.pushOwner(duServiceName);
            ClassLoader old = WildFlySecurityManager.getCurrentContextClassLoaderPrivileged();
            try {
                WildFlySecurityManager.setCurrentContextClassLoaderPrivileged(module.getClassLoader());
                raxmlDeployment = raDeployer.doDeploy();
            } finally {
                WildFlySecurityManager.setCurrentContextClassLoaderPrivileged(old);
                WritableServiceBasedNamingStore.popOwner();
            }
            value = new ResourceAdapterDeployment(raxmlDeployment, raName, raServiceName);
            managementRepository.getValue().getConnectors().add(value.getDeployment().getConnector());
            registry.getValue().registerResourceAdapterDeployment(value);
            final ServiceBuilder raServiceSB = context.getChildTarget()
                .addService(raServiceName,
                        new ResourceAdapterService(raServiceName, value.getDeployment().getResourceAdapter()));
            raServiceSB.requires(deploymentServiceName);
            raServiceSB.setInitialMode(ServiceController.Mode.ACTIVE).install();
        } catch (Throwable t) {
            cleanupStartAsync(context, raName, deploymentServiceName, t);
        }
    }

    /**
     * Stop
     */
    @Override
    public void stop(StopContext context) {
        stopAsync(context, raName, deploymentServiceName);
    }

    @Override
    public Collection<String> getJndiAliases() {
        return Collections.emptyList();
    }

    public CommonDeployment getRaxmlDeployment() {
        return raxmlDeployment;
    }

    public synchronized void setRaxml(Activation raxml) {
            this.raxml = raxml;
    }

    public synchronized Activation getRaxml() {
            return raxml;
    }

    private class WildFlyRaXmlDeployer extends AbstractWildFlyRaDeployer {

        private final Activation activation;

        public WildFlyRaXmlDeployer(ServiceTarget serviceTarget, URL url, String deploymentName, File root, ClassLoader cl,
                                    Connector cmd, Activation activation, final ServiceName deploymentServiceName) {
            super(serviceTarget, url, deploymentName, root, cl, cmd, deploymentServiceName);
            this.activation = activation;
        }

        @Override
        public CommonDeployment doDeploy() throws Throwable {

            this.setConfiguration(getConfig().getValue());

            this.start();

            CommonDeployment dep = this.createObjectsAndInjectValue(url, deploymentName, root, cl, cmd, activation);

            return dep;
        }

        @Override
        protected boolean checkActivation(Connector cmd, Activation activation) {
            return true;
        }

        @Override
        protected DeployersLogger getLogger() {
            return DEPLOYERS_LOGGER;
        }

        @Override
        protected void setRecoveryForResourceAdapterInResourceAdapterRepository(String key, boolean isXA) {
            try {
                raRepository.getValue().setRecoveryForResourceAdapter(key, isXA);
            } catch (Throwable t) {
                DEPLOYMENT_CONNECTOR_LOGGER.unableToRegisterRecovery(key, isXA);
            }
        }

        @Override
        protected org.jboss.jca.core.spi.security.SubjectFactory getSubjectFactory(
                SecurityMetadata securityMetadata, final String jndiName) throws DeployException {
            if (securityMetadata == null)
                return null;
            final String securityDomain = securityMetadata.resolveSecurityDomain();
            if (securityMetadata instanceof org.jboss.as.connector.metadata.api.common.SecurityMetadata &&
                    ((org.jboss.as.connector.metadata.api.common.SecurityMetadata)securityMetadata).isElytronEnabled()) {
                try {
                    return new ElytronSubjectFactory(null, new URI(jndiName));
                } catch (URISyntaxException e) {
                    throw ConnectorLogger.ROOT_LOGGER.cannotDeploy(e);
                }
            } else if (securityDomain == null || securityDomain.trim().equals("")) {
                return null;
            } else if (((ModifiableResourceAdapter) raxml).getSubjectFactory() != null) {
                return new PicketBoxSubjectFactory(((ModifiableResourceAdapter) raxml).getSubjectFactory()){

                    @Override
                    public Subject createSubject(final String sd) {
                        ServerSecurityManager sm = ((ModifiableResourceAdapter) raxml).getSecManager();
                        if (sm != null) {
                            sm.push(sd);
                        }
                        try {
                            return super.createSubject(sd);
                        } finally {
                            if (sm != null) {
                                sm.pop();
                            }
                        }
                    }
                };
            }
            return null;
        }
    }
}


/*
 * JBoss, Home of Professional Open Source.
 * Copyright (c) 2011, Red Hat, Inc., and individual contributors
 * as indicated by the @author tags. See the copyright.txt file in the
 * distribution for a full listing of individual contributors.
 *
 * This is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; either version 2.1 of
 * the License, or (at your option) any later version.
 *
 * This software is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this software; if not, write to the Free
 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
 */

package org.jboss.as.ejb3.deployment.processors;

import static org.jboss.as.server.deployment.EjbDeploymentMarker.isEjbDeployment;

import org.jboss.as.ee.structure.DeploymentType;
import org.jboss.as.ee.structure.DeploymentTypeMarker;
import org.jboss.as.server.deployment.Attachments;
import org.jboss.as.server.deployment.DeploymentPhaseContext;
import org.jboss.as.server.deployment.DeploymentUnit;
import org.jboss.as.server.deployment.DeploymentUnitProcessingException;
import org.jboss.as.server.deployment.DeploymentUnitProcessor;
import org.jboss.as.server.deployment.module.ModuleDependency;
import org.jboss.as.server.deployment.module.ModuleSpecification;
import org.jboss.modules.Module;
import org.jboss.modules.ModuleIdentifier;
import org.jboss.modules.ModuleLoader;
import org.wildfly.iiop.openjdk.deployment.IIOPDeploymentMarker;

/**
 * Responsible for adding appropriate Java EE {@link org.jboss.as.server.deployment.module.ModuleDependency module dependencies}
 * <p/>
 * Author : Jaikiran Pai
 */
public class EjbDependencyDeploymentUnitProcessor implements DeploymentUnitProcessor {

    /**
     * Needed for timer handle persistence
     * TODO: restrict visibility
     */
    private static final ModuleIdentifier EJB_SUBSYSTEM = ModuleIdentifier.create("org.jboss.as.ejb3");
    private static final ModuleIdentifier EJB_CLIENT = ModuleIdentifier.create("org.jboss.ejb-client");
    private static final ModuleIdentifier EJB_NAMING_CLIENT = ModuleIdentifier.create("org.wildfly.naming-client");
    private static final ModuleIdentifier EJB_IIOP_CLIENT = ModuleIdentifier.create("org.jboss.iiop-client");
    private static final ModuleIdentifier IIOP_OPENJDK = ModuleIdentifier.create("org.wildfly.iiop-openjdk");
    private static final ModuleIdentifier EJB_API = ModuleIdentifier.create("javax.ejb.api");
    private static final ModuleIdentifier JAX_RPC_API = ModuleIdentifier.create("javax.xml.rpc.api");
    private static final ModuleIdentifier HTTP_EJB = ModuleIdentifier.create("org.wildfly.http-client.ejb");
    private static final ModuleIdentifier HTTP_TRANSACTION = ModuleIdentifier.create("org.wildfly.http-client.transaction");
    private static final ModuleIdentifier HTTP_NAMING = ModuleIdentifier.create("org.wildfly.http-client.naming");

    /**
     * Adds Java EE module as a dependency to any deployment unit which is an EJB deployment
     *
     * @param phaseContext the deployment unit context
     * @throws DeploymentUnitProcessingException
     *
     */
    @Override
    public void deploy(DeploymentPhaseContext phaseContext) throws DeploymentUnitProcessingException {

        // get hold of the deployment unit
        DeploymentUnit deploymentUnit = phaseContext.getDeploymentUnit();

        final ModuleLoader moduleLoader = Module.getBootModuleLoader();
        final ModuleSpecification moduleSpecification = deploymentUnit.getAttachment(Attachments.MODULE_SPECIFICATION);

        //always add EE API
        moduleSpecification.addSystemDependency(new ModuleDependency(moduleLoader, EJB_API, false, false, true, false));
        // previously exported by EJB_API prior to WFLY-5922 TODO WFLY-5967 look into moving this to WS subsystem
        moduleSpecification.addSystemDependency(new ModuleDependency(moduleLoader, JAX_RPC_API, false, false, true, false));
        //we always give them the EJB client
        moduleSpecification.addSystemDependency(new ModuleDependency(moduleLoader, EJB_CLIENT, false, false, true, false));
        moduleSpecification.addSystemDependency(new ModuleDependency(moduleLoader, EJB_NAMING_CLIENT, false, false, true, false));
        moduleSpecification.addSystemDependency(new ModuleDependency(moduleLoader, EJB_IIOP_CLIENT, false, false, false, false));

        //we always have to add this, as even non-ejb deployments may still lookup IIOP ejb's
        moduleSpecification.addSystemDependency(new ModuleDependency(moduleLoader, EJB_SUBSYSTEM, false, false, true, false));
        moduleSpecification.addSystemDependency(new ModuleDependency(moduleLoader, HTTP_EJB, false, false, true, false));
        moduleSpecification.addSystemDependency(new ModuleDependency(moduleLoader, HTTP_NAMING, false, false, true, false));
        moduleSpecification.addSystemDependency(new ModuleDependency(moduleLoader, HTTP_TRANSACTION, false, false, true, false));

        if (IIOPDeploymentMarker.isIIOPDeployment(deploymentUnit)) {
            //needed for dynamic IIOP stubs
            moduleSpecification.addSystemDependency(new ModuleDependency(moduleLoader, IIOP_OPENJDK, false, false, false, false));
        }

        // fetch the EjbJarMetaData
        //TODO: remove the app client bit after the next EJB release
        if (!isEjbDeployment(deploymentUnit) && !DeploymentTypeMarker.isType(DeploymentType.APPLICATION_CLIENT, deploymentUnit)) {
            // nothing to do
            return;
        }

        // FIXME: still not the best way to do it
        //this must be the first dep listed in the module
        if (Boolean.getBoolean("org.jboss.as.ejb3.EMBEDDED"))
            moduleSpecification.addSystemDependency(new ModuleDependency(moduleLoader, ModuleIdentifier.CLASSPATH, false, false, false, false));

    }

    @Override
    public void undeploy(DeploymentUnit context) {
    }
}


/*
 * JBoss, Home of Professional Open Source.
 * Copyright 2017, Red Hat, Inc., and individual contributors
 * as indicated by the @author tags. See the copyright.txt file in the
 * distribution for a full listing of individual contributors.
 *
 * This is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; either version 2.1 of
 * the License, or (at your option) any later version.
 *
 * This software is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this software; if not, write to the Free
 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
 */

package org.wildfly.extension.undertow.security.jacc;

import org.jboss.security.SecurityConstants;
import org.wildfly.extension.undertow.security.SecurityContextAssociationHandler;

import javax.security.jacc.PolicyContextException;
import javax.security.jacc.PolicyContextHandler;

/**
 * A PolicyContextHandler for the active HttpServletRequest
 *
 * @author Scott.Stark@jboss.org
 * @author Marcus Moyses
 */
public class HttpServletRequestPolicyContextHandler implements PolicyContextHandler {

    /** {@inheritDoc} */
    @Override
    public Object getContext(String key, Object data) throws PolicyContextException {
        if (!key.equalsIgnoreCase(SecurityConstants.WEB_REQUEST_KEY))
            return null;
        return SecurityContextAssociationHandler.getActiveRequest();
    }

    /** {@inheritDoc} */
    @Override
    public String[] getKeys() throws PolicyContextException {
        String[] keys = { SecurityConstants.WEB_REQUEST_KEY };
        return keys;
    }

    /** {@inheritDoc} */
    @Override
    public boolean supports(String key) throws PolicyContextException {
        return key.equalsIgnoreCase(SecurityConstants.WEB_REQUEST_KEY);
    }
}


/*
 * JBoss, Home of Professional Open Source.
 * Copyright 2010, Red Hat, Inc., and individual contributors
 * as indicated by the @author tags. See the copyright.txt file in the
 * distribution for a full listing of individual contributors.
 *
 * This is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; either version 2.1 of
 * the License, or (at your option) any later version.
 *
 * This software is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this software; if not, write to the Free
 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
 */

package org.jboss.as.web;

import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.ADD;
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.OP;
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.OP_ADDR;
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.SUBSYSTEM;
import static org.jboss.as.controller.parsing.ParseUtils.missingRequired;
import static org.jboss.as.controller.parsing.ParseUtils.readStringAttributeElement;
import static org.jboss.as.controller.parsing.ParseUtils.requireAttributes;
import static org.jboss.as.controller.parsing.ParseUtils.requireNoContent;
import static org.jboss.as.controller.parsing.ParseUtils.requireNoNamespaceAttribute;
import static org.jboss.as.controller.parsing.ParseUtils.unexpectedAttribute;
import static org.jboss.as.controller.parsing.ParseUtils.unexpectedElement;
import static org.jboss.as.web.Constants.ALIAS;
import static org.jboss.as.web.Constants.CONDITION;
import static org.jboss.as.web.Constants.CONFIGURATION;
import static org.jboss.as.web.Constants.CONNECTOR;
import static org.jboss.as.web.Constants.CONTAINER;
import static org.jboss.as.web.Constants.JSP_CONFIGURATION;
import static org.jboss.as.web.Constants.MIME_MAPPING;
import static org.jboss.as.web.Constants.NAME;
import static org.jboss.as.web.Constants.PARAM;
import static org.jboss.as.web.Constants.PATH;
import static org.jboss.as.web.Constants.RELATIVE_TO;
import static org.jboss.as.web.Constants.REWRITE;
import static org.jboss.as.web.Constants.SSO;
import static org.jboss.as.web.Constants.STATIC_RESOURCES;
import static org.jboss.as.web.Constants.VALVE;
import static org.jboss.as.web.Constants.VIRTUAL_SERVER;
import static org.jboss.as.web.Constants.WELCOME_FILE;
import static org.jboss.as.web.WebExtension.ACCESS_LOG_PATH;
import static org.jboss.as.web.WebExtension.DIRECTORY_PATH;
import static org.jboss.as.web.WebExtension.SSL_PATH;
import static org.jboss.as.web.WebExtension.SSO_PATH;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

import javax.xml.stream.XMLStreamConstants;
import javax.xml.stream.XMLStreamException;

import org.jboss.as.controller.AttributeDefinition;
import org.jboss.as.controller.PathAddress;
import org.jboss.as.controller.PathElement;
import org.jboss.as.controller.SimpleAttributeDefinition;
import org.jboss.as.controller.operations.common.Util;
import org.jboss.as.controller.persistence.SubsystemMarshallingContext;
import org.jboss.dmr.ModelNode;
import org.jboss.dmr.Property;
import org.jboss.staxmapper.XMLElementReader;
import org.jboss.staxmapper.XMLElementWriter;
import org.jboss.staxmapper.XMLExtendedStreamReader;
import org.jboss.staxmapper.XMLExtendedStreamWriter;

/**
 * The web subsystem parser.
 *
 * @author Emanuel Muckenhuber
 * @author Brian Stansberry
 * @author Tomaz Cerar
 */
class WebSubsystemParser implements XMLStreamConstants, XMLElementReader<List<ModelNode>>,
        XMLElementWriter<SubsystemMarshallingContext> {

    private static final String RULE_PREFIX = "rule-";
    private static final String CONDITION_PREFIX = "condition-";

    /**
     * {@inheritDoc}
     */
    @Override
    public void writeContent(XMLExtendedStreamWriter writer, SubsystemMarshallingContext context) throws XMLStreamException {

        context.startSubsystemElement(Namespace.CURRENT.getUriString(), false);

        ModelNode node = context.getModelNode();
        WebDefinition.DEFAULT_VIRTUAL_SERVER.marshallAsAttribute(node, true, writer);
        WebDefinition.INSTANCE_ID.marshallAsAttribute(node, false, writer);
        WebDefinition.NATIVE.marshallAsAttribute(node, true, writer);
        WebDefinition.DEFAULT_SESSION_TIMEOUT.marshallAsAttribute(node, false, writer);
        if (node.hasDefined(CONFIGURATION)) {
            writeContainerConfig(writer, node.get(CONFIGURATION));
        }
        if (node.hasDefined(CONNECTOR)) {
            for (final Property connector : node.get(CONNECTOR).asPropertyList()) {
                final ModelNode config = connector.getValue();
                writer.writeStartElement(Element.CONNECTOR.getLocalName());
                writer.writeAttribute(NAME, connector.getName());
                 List<AttributeDefinition> connectorAttributes =  new ArrayList<>(Arrays.asList(WebConnectorDefinition.CONNECTOR_ATTRIBUTES));
                if(config.hasDefined(Constants.PROXY_BINDING)) {
                    connectorAttributes.remove(WebConnectorDefinition.PROXY_PORT);
                    connectorAttributes.remove(WebConnectorDefinition.PROXY_NAME);
                } else {
                    connectorAttributes.remove(WebConnectorDefinition.PROXY_BINDING);
                }
                if(config.hasDefined(Constants.REDIRECT_BINDING)) {
                    connectorAttributes.remove(WebConnectorDefinition.REDIRECT_PORT);
                } else {
                    connectorAttributes.remove(WebConnectorDefinition.REDIRECT_BINDING);
                }
                for (AttributeDefinition attr : connectorAttributes) {
                    if (attr instanceof SimpleAttributeDefinition) {
                        ((SimpleAttributeDefinition) attr).marshallAsAttribute(config, true, writer);
                    }
                }
                if (config.get(SSL_PATH.getKey(), SSL_PATH.getValue()).isDefined()) {
                    ModelNode sslConfig = config.get(SSL_PATH.getKey(), SSL_PATH.getValue());
                    writer.writeStartElement(Element.SSL.getLocalName());
                    WebSSLDefinition.NAME.marshallAsAttribute(sslConfig, writer);
                    for (SimpleAttributeDefinition attr : WebSSLDefinition.SSL_ATTRIBUTES) {
                        attr.marshallAsAttribute(sslConfig, false, writer);
                    }
                    writer.writeEndElement();
                }
                if (config.hasDefined(VIRTUAL_SERVER)) {
                    for (final ModelNode virtualServer : config.get(VIRTUAL_SERVER).asList()) {
                        writer.writeEmptyElement(VIRTUAL_SERVER);
                        writer.writeAttribute(NAME, virtualServer.asString());
                    }
                }

                writer.writeEndElement();
            }
        }
        if (node.hasDefined(VIRTUAL_SERVER)) {
            for (final Property host : node.get(VIRTUAL_SERVER).asPropertyList()) {
                final ModelNode config = host.getValue();
                writer.writeStartElement(Element.VIRTUAL_SERVER.getLocalName());
                writer.writeAttribute(NAME, host.getName());
                WebVirtualHostDefinition.ENABLE_WELCOME_ROOT.marshallAsAttribute(config, true, writer);
                WebVirtualHostDefinition.DEFAULT_WEB_MODULE.marshallAsAttribute(config, true, writer);

                if (config.hasDefined(ALIAS)) {
                    for (final ModelNode alias : config.get(ALIAS).asList()) {
                        writer.writeEmptyElement(ALIAS);
                        writer.writeAttribute(NAME, alias.asString());
                    }
                }
                if (config.get(ACCESS_LOG_PATH.getKey(), ACCESS_LOG_PATH.getValue()).isDefined()) {
                    ModelNode accessLog = config.get(ACCESS_LOG_PATH.getKey(), ACCESS_LOG_PATH.getValue());
                    writer.writeStartElement(Element.ACCESS_LOG.getLocalName());

                    for (SimpleAttributeDefinition attr : WebAccessLogDefinition.ACCESS_LOG_ATTRIBUTES) {
                        attr.marshallAsAttribute(accessLog, false, writer);
                    }

                    if (accessLog.get(DIRECTORY_PATH.getKey(), DIRECTORY_PATH.getValue()).isDefined()) {
                        ModelNode directory = accessLog.get(DIRECTORY_PATH.getKey(), DIRECTORY_PATH.getValue());
                        String name = Element.DIRECTORY.getLocalName();
                        boolean startwritten = false;
                        startwritten = writeAttribute(writer, WebAccessLogDirectoryDefinition.PATH, directory, startwritten,
                                name);
                        startwritten = writeAttribute(writer, WebAccessLogDirectoryDefinition.RELATIVE_TO, directory,
                                startwritten, name);
                        if (startwritten) {
                            writer.writeEndElement();
                        }
                    }
                    writer.writeEndElement();
                }

                if (config.hasDefined(REWRITE)) {
                    for (final ModelNode rewritenode : config.get(REWRITE).asList()) {
                        Property prop = rewritenode.asProperty();
                        ModelNode rewrite = prop.getValue();
                        writer.writeStartElement(REWRITE);
                        writer.writeAttribute(NAME, prop.getName());
                        WebReWriteDefinition.PATTERN.marshallAsAttribute(rewrite, false, writer);
                        WebReWriteDefinition.SUBSTITUTION.marshallAsAttribute(rewrite, false, writer);
                        WebReWriteDefinition.FLAGS.marshallAsAttribute(rewrite, false, writer);
                        if (rewrite.hasDefined(CONDITION)) {
                            for (final ModelNode conditionnode : rewrite.get(CONDITION).asList()) {
                                Property conditionProp = conditionnode.asProperty();
                                ModelNode condition = conditionProp.getValue();
                                writer.writeStartElement(CONDITION);
                                writer.writeAttribute(NAME, conditionProp.getName());
                                WebReWriteConditionDefinition.TEST.marshallAsAttribute(condition, false, writer);
                                WebReWriteConditionDefinition.PATTERN.marshallAsAttribute(condition, false, writer);
                                WebReWriteConditionDefinition.FLAGS.marshallAsAttribute(condition, false, writer);
                                writer.writeEndElement();
                            }
                        }
                        writer.writeEndElement();
                    }
                }

                if (config.get(SSO_PATH.getKey(), SSO_PATH.getValue()).isDefined()) {
                    final ModelNode sso;
                    sso = config.get(SSO_PATH.getKey(), SSO_PATH.getValue());
                    writer.writeStartElement(SSO);
                    for (SimpleAttributeDefinition attr : WebSSODefinition.SSO_ATTRIBUTES) {
                        attr.marshallAsAttribute(sso, false, writer);
                    }
                    writer.writeEndElement();
                }

                // End of the VIRTUAL_SERVER
                writer.writeEndElement();
            }
            if (node.hasDefined(VALVE)) {
                for (final Property valve : node.get(VALVE).asPropertyList()) {
                    final ModelNode config = valve.getValue();
                    writer.writeStartElement(Element.VALVE.getLocalName());
                    writer.writeAttribute(NAME, valve.getName());
                    for (AttributeDefinition attr : WebValveDefinition.ATTRIBUTES) {
                        if (attr instanceof SimpleAttributeDefinition) {
                            ((SimpleAttributeDefinition) attr).marshallAsAttribute(config, false, writer);
                        }
                    }
                    if (config.hasDefined(PARAM)) {
                        for (final Property entry : config.get(PARAM).asPropertyList()) {
                            writer.writeEmptyElement(Element.PARAM.getLocalName());
                            writer.writeAttribute(Attribute.PARAM_NAME.getLocalName(), entry.getName());
                            writer.writeAttribute(Attribute.PARAM_VALUE.getLocalName(), entry.getValue().asString());
                        }
                    }
                    writer.writeEndElement();

                }
            }

        }
        writer.writeEndElement();
    }

    private void writeContainerConfig(XMLExtendedStreamWriter writer, ModelNode config) throws XMLStreamException {
        boolean containerConfigStartWritten = false;
        if (config.hasDefined(STATIC_RESOURCES)) {
            containerConfigStartWritten = writeStaticResources(writer, config.get(STATIC_RESOURCES));
        }
        if (config.hasDefined(JSP_CONFIGURATION)) {
            containerConfigStartWritten = writeJSPConfiguration(writer, config.get(JSP_CONFIGURATION),
                    containerConfigStartWritten) || containerConfigStartWritten;
        }
        ModelNode container = config;
        if (config.hasDefined(CONTAINER)) {
            // this has been added to get the stuff manageable
            container = config.get(CONTAINER);
        }
        if (container.hasDefined(MIME_MAPPING)) {
            if (!containerConfigStartWritten) {
                writer.writeStartElement(Element.CONTAINER_CONFIG.getLocalName());
                containerConfigStartWritten = true;
            }
            WebContainerDefinition.MIME_MAPPINGS.marshallAsElement(container, writer);
        }
        if (container.hasDefined(WELCOME_FILE)) {
            if (!containerConfigStartWritten) {
                writer.writeStartElement(Element.CONTAINER_CONFIG.getLocalName());
                containerConfigStartWritten = true;
            }
            for (final ModelNode file : container.get(WELCOME_FILE).asList()) {
                writer.writeStartElement(Element.WELCOME_FILE.getLocalName());
                writer.writeCharacters(file.asString());
                writer.writeEndElement();
            }
        }
        if (containerConfigStartWritten) {
            writer.writeEndElement();
        }
    }

    private boolean writeStaticResources(XMLExtendedStreamWriter writer, ModelNode config) throws XMLStreamException {

        boolean startWritten = false;
        for (SimpleAttributeDefinition def : WebStaticResources.STATIC_ATTRIBUTES) {
            startWritten = writeStaticResourceAttribute(writer, def, config, startWritten) || startWritten;
        }
        if (startWritten) {
            writer.writeEndElement();
        }
        return startWritten;
    }

    private boolean writeStaticResourceAttribute(XMLExtendedStreamWriter writer, SimpleAttributeDefinition attribute,
                                                 ModelNode config, boolean startWritten) throws XMLStreamException {
        if (attribute.isMarshallable(config, false)) {
            if (!startWritten) {
                writer.writeStartElement(Element.CONTAINER_CONFIG.getLocalName());
                writer.writeStartElement(Element.STATIC_RESOURCES.getLocalName());
            }
            attribute.marshallAsAttribute(config, false, writer);
            return true;
        }
        return false;
    }

    private boolean writeJSPConfiguration(XMLExtendedStreamWriter writer, ModelNode jsp, boolean containerConfigStartWritten)
            throws XMLStreamException {

        boolean startWritten = false;
        for (SimpleAttributeDefinition def : WebJSPDefinition.JSP_ATTRIBUTES) {
            startWritten = writeJspConfigAttribute(writer, def, jsp, startWritten, containerConfigStartWritten) || startWritten;
        }

        if (startWritten) {
            writer.writeEndElement();
        }

        return startWritten;
    }

    private boolean writeJspConfigAttribute(XMLExtendedStreamWriter writer, SimpleAttributeDefinition attribute,
                                            ModelNode config, boolean startWritten, boolean containerConfigStartWritten) throws XMLStreamException {
        if (attribute.isMarshallable(config, false)) {
            if (!startWritten) {
                if (!containerConfigStartWritten) {
                    writer.writeStartElement(Element.CONTAINER_CONFIG.getLocalName());
                }
                writer.writeStartElement(Element.JSP_CONFIGURATION.getLocalName());
            }
            attribute.marshallAsAttribute(config, false, writer);
            return true;
        }
        return false;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void readElement(XMLExtendedStreamReader reader, List<ModelNode> list) throws XMLStreamException {
        PathAddress address = PathAddress.pathAddress(PathElement.pathElement(SUBSYSTEM, WebExtension.SUBSYSTEM_NAME));

        final ModelNode subsystem = new ModelNode();
        subsystem.get(OP).set(ADD);
        subsystem.get(OP_ADDR).set(address.toModelNode());
        final int count = reader.getAttributeCount();
        for (int i = 0; i < count; i++) {
            requireNoNamespaceAttribute(reader, i);
            final String value = reader.getAttributeValue(i);
            final Attribute attribute = Attribute.forName(reader.getAttributeLocalName(i));
            switch (attribute) {
                case NATIVE:
                    WebDefinition.NATIVE.parseAndSetParameter(value, subsystem, reader);
                    break;
                case DEFAULT_VIRTUAL_SERVER:
                    WebDefinition.DEFAULT_VIRTUAL_SERVER.parseAndSetParameter(value, subsystem, reader);
                    break;
                case INSTANCE_ID:
                    WebDefinition.INSTANCE_ID.parseAndSetParameter(value, subsystem, reader);
                    break;
                case DEFAULT_SESSION_TIMEOUT:
                    attributeSupportedSince(Namespace.WEB_2_2, reader, i);
                    WebDefinition.DEFAULT_SESSION_TIMEOUT.parseAndSetParameter(value, subsystem, reader);
                    break;
                default:
                    throw unexpectedAttribute(reader, i);
            }
        }
        list.add(subsystem);
        boolean containerConfigDefined = false;
        final Namespace namespace = Namespace.forUri(reader.getNamespaceURI());
        // elements
        while (reader.hasNext() && reader.nextTag() != END_ELEMENT) {
            switch (namespace) {
                case WEB_1_0:
                case WEB_1_1:
                case WEB_1_2:
                case WEB_1_3: {
                    final Element element = Element.forName(reader.getLocalName());
                    switch (element) {
                        case CONTAINER_CONFIG: {
                            parseContainerConfig(reader, address, list);
                            containerConfigDefined = true;
                            break;
                        }
                        case CONNECTOR: {
                            parseConnector(reader, address, list);
                            break;
                        }
                        case VIRTUAL_SERVER: {
                            parseHost(reader, address, list);
                            break;
                        }
                        default: {
                            throw unexpectedElement(reader);
                        }
                    }
                    break;
                }
                case WEB_1_4:
                case WEB_1_5:
                case WEB_2_0:
                case WEB_2_1:
                case WEB_2_2:
                {
                    final Element element = Element.forName(reader.getLocalName());
                    switch (element) {
                        case CONTAINER_CONFIG: {
                            parseContainerConfig(reader, address, list);
                            containerConfigDefined = true;
                            break;
                        }
                        case CONNECTOR: {
                            parseConnector(reader, address, list);
                            break;
                        }
                        case VIRTUAL_SERVER: {
                            parseHost(reader, address, list);
                            break;
                        }
                        case VALVE: {
                            parseValve(reader, address, list);
                            break;
                        }
                        default: {
                            throw unexpectedElement(reader);
                        }
                    }
                    break;
                }
                default: {
                    throw unexpectedElement(reader);
                }
            }
        }
        if (!containerConfigDefined) {
            addDefaultContainerConfig(address, list);
        }

    }

    private static void parseValve(XMLExtendedStreamReader reader, PathAddress parent, List<ModelNode> list) throws XMLStreamException {
        String name = null;
        final ModelNode valve = new ModelNode();
        final int count = reader.getAttributeCount();
        for (int i = 0; i < count; i++) {
            requireNoNamespaceAttribute(reader, i);
            final String value = reader.getAttributeValue(i);
            final Attribute attribute = Attribute.forName(reader.getAttributeLocalName(i));
            switch (attribute) {
                case NAME:
                    name = value;
                    break;
                case MODULE:
                    WebValveDefinition.MODULE.parseAndSetParameter(value, valve, reader);
                    break;
                case CLASS_NAME:
                    WebValveDefinition.CLASS_NAME.parseAndSetParameter(value, valve, reader);
                    break;
                case ENABLED:
                    WebValveDefinition.ENABLED.parseAndSetParameter(value, valve, reader);
                    break;
                default:
                    throw unexpectedAttribute(reader, i);
            }
        }

        if (name == null) {
            throw missingRequired(reader, Collections.singleton(Attribute.NAME));
        }
        valve.get(OP).set(ADD);
        PathAddress address = PathAddress.pathAddress(parent, PathElement.pathElement(VALVE, name));
        valve.get(OP_ADDR).set(address.toModelNode());
        list.add(valve);

        while (reader.hasNext() && reader.nextTag() != END_ELEMENT) {
            final Element element = Element.forName(reader.getLocalName());
            switch (element) {
                case PARAM:
                    final String[] array = requireAttributes(reader, Attribute.PARAM_NAME.getLocalName(),
                            Attribute.PARAM_VALUE.getLocalName());
                    valve.get(PARAM).get(array[0]).set(array[1]);
                    requireNoContent(reader);
                    break;
                default:
                    throw unexpectedElement(reader);
            }
        }
    }

    private static void parseDirOrFile(XMLExtendedStreamReader reader, PathAddress address, List<ModelNode> list,
                                       PathElement filePath) throws XMLStreamException {
        final PathAddress dirAddress = PathAddress.pathAddress(address, filePath);
        final ModelNode directory = new ModelNode();
        directory.get(OP).set(ADD);
        directory.get(OP_ADDR).set(dirAddress.toModelNode());
        final int count2 = reader.getAttributeCount();
        for (int i = 0; i < count2; i++) {
            requireNoNamespaceAttribute(reader, i);
            final String value = reader.getAttributeValue(i);
            final Attribute attribute = Attribute.forName(reader.getAttributeLocalName(i));
            switch (attribute) {
                case PATH:
                    directory.get(PATH).set(value);
                    break;
                case RELATIVE_TO:
                    directory.get(RELATIVE_TO).set(value);
                    break;
                default:
                    throw unexpectedAttribute(reader, i);
            }
        }
        requireNoContent(reader);
        list.add(directory);
    }

    static void addDefaultContainerConfig(final PathAddress parent, List<ModelNode> list) {
        final ModelNode config = new ModelNode();
        PathAddress containerPath = PathAddress.pathAddress(parent, WebExtension.CONTAINER_PATH);
        config.get(OP).set(ADD);
        config.get(OP_ADDR).set(containerPath.toModelNode());
        list.add(config);
        addDefaultStaticConfiguration(parent, list);
        addDefaultJSPConfiguration(parent, list);

    }

    private static void addDefaultJSPConfiguration(final PathAddress parent, List<ModelNode> list) {
        final PathAddress jspAddress = PathAddress.pathAddress(parent, WebExtension.JSP_CONFIGURATION_PATH);
        final ModelNode jsp = new ModelNode();
        jsp.get(OP).set(ADD);
        jsp.get(OP_ADDR).set(jspAddress.toModelNode());
        list.add(jsp);
    }

    private static void addDefaultStaticConfiguration(final PathAddress parent, List<ModelNode> list) {
        PathAddress address = PathAddress.pathAddress(parent, WebExtension.STATIC_RESOURCES_PATH);
        final ModelNode resources = new ModelNode();
        resources.get(OP).set(ADD);
        resources.get(OP_ADDR).set(address.toModelNode());
        list.add(resources);
    }

    static void parseContainerConfig(XMLExtendedStreamReader reader, PathAddress parent, List<ModelNode> list)
            throws XMLStreamException {

        PathAddress address = PathAddress.pathAddress(parent, WebExtension.CONTAINER_PATH);
        final ModelNode config = new ModelNode();
        config.get(OP).set(ADD);
        config.get(OP_ADDR).set(address.toModelNode());
        // no attributes
        list.add(config);
        if (reader.getAttributeCount() > 0) {
            throw unexpectedAttribute(reader, 0);
        }
        // elements
        boolean staticResourcesConfigured = false;
        boolean jspConfigured = false;
        while (reader.hasNext() && reader.nextTag() != END_ELEMENT) {
            final Element element = Element.forName(reader.getLocalName());
            switch (element) {
                case STATIC_RESOURCES: {
                    parseStaticResources(reader, parent, list);
                    staticResourcesConfigured = true;
                    break;
                }
                case JSP_CONFIGURATION: {
                    parseJSPConfiguration(reader, parent, list);
                    jspConfigured = true;
                    break;
                }
                case MIME_MAPPING: {
                    final String[] array = requireAttributes(reader, Attribute.NAME.getLocalName(),
                            Attribute.VALUE.getLocalName());
                    WebContainerDefinition.MIME_MAPPINGS.parseAndAddParameterElement(array[0], array[1], config, reader);

                    requireNoContent(reader);
                    break;
                }
                case WELCOME_FILE: {
                    final String welcomeFile = reader.getElementText().trim();
                    WebContainerDefinition.WELCOME_FILES.parseAndAddParameterElement(welcomeFile, config, reader);
                    break;
                }
                default:
                    throw unexpectedElement(reader);
            }
        }
        if (!staticResourcesConfigured) {
            addDefaultStaticConfiguration(parent, list);
        }
        if (!jspConfigured) {
            addDefaultJSPConfiguration(parent, list);
        }

    }

    static void parseJSPConfiguration(XMLExtendedStreamReader reader, final PathAddress parent, List<ModelNode> list)
            throws XMLStreamException {
        final PathAddress address = PathAddress.pathAddress(parent, WebExtension.JSP_CONFIGURATION_PATH);

        final ModelNode jsp = new ModelNode();
        jsp.get(OP).set(ADD);
        jsp.get(OP_ADDR).set(address.toModelNode());
        final int count = reader.getAttributeCount();
        for (int i = 0; i < count; i++) {
            requireNoNamespaceAttribute(reader, i);
            final String value = reader.getAttributeValue(i);
            final Attribute attribute = Attribute.forName(reader.getAttributeLocalName(i));
            switch (attribute) {
                case DEVELOPMENT:
                case DISABLED:
                case KEEP_GENERATED:
                case TRIM_SPACES:
                case TAG_POOLING:
                case MAPPED_FILE:
                case CHECK_INTERVAL:
                case MODIFICATION_TEST_INTERVAL:
                case RECOMPILE_ON_FAIL:
                case SMAP:
                case DUMP_SMAP:
                case GENERATE_STRINGS_AS_CHAR_ARRAYS:
                case ERROR_ON_USE_BEAN_INVALID_CLASS_ATTRIBUTE:
                case SCRATCH_DIR:
                case SOURCE_VM:
                case TARGET_VM:
                case JAVA_ENCODING:
                case X_POWERED_BY:
                case DISPLAY_SOURCE_FRAGMENT:
                    WebJSPDefinition.ATTRIBUTES_MAP.get(attribute.getLocalName()).parseAndSetParameter(value, jsp, reader);
                    break;
                default:
                    throw unexpectedAttribute(reader, i);
            }
        }
        requireNoContent(reader);
        list.add(jsp);
    }

    static void parseStaticResources(XMLExtendedStreamReader reader, PathAddress parent, List<ModelNode> list)
            throws XMLStreamException {
        PathAddress address = PathAddress.pathAddress(parent, WebExtension.STATIC_RESOURCES_PATH);
        final ModelNode resources = new ModelNode();
        resources.get(OP).set(ADD);
        resources.get(OP_ADDR).set(address.toModelNode());
        final int count = reader.getAttributeCount();
        for (int i = 0; i < count; i++) {
            requireNoNamespaceAttribute(reader, i);
            final String value = reader.getAttributeValue(i);
            final Attribute attribute = Attribute.forName(reader.getAttributeLocalName(i));
            switch (attribute) {
                case LISTINGS:
                    WebStaticResources.LISTINGS.parseAndSetParameter(value, resources, reader);
                    break;
                case SENDFILE:
                    WebStaticResources.SENDFILE.parseAndSetParameter(value, resources, reader);
                    break;
                case FILE_ENCODING:
                    WebStaticResources.FILE_ENCODING.parseAndSetParameter(value, resources, reader);
                    break;
                case READ_ONLY:
                    WebStaticResources.READ_ONLY.parseAndSetParameter(value, resources, reader);
                    break;
                case WEBDAV:
                    WebStaticResources.WEBDAV.parseAndSetParameter(value, resources, reader);
                    break;
                case SECRET:
                    WebStaticResources.SECRET.parseAndSetParameter(value, resources, reader);
                    break;
                case MAX_DEPTH:
                    WebStaticResources.MAX_DEPTH.parseAndSetParameter(value, resources, reader);
                    break;
                case DISABLED:
                    WebStaticResources.DISABLED.parseAndSetParameter(value, resources, reader);
                    break;
                default:
                    throw unexpectedAttribute(reader, i);
            }
        }
        requireNoContent(reader);
        list.add(resources);
    }

    static void parseHost(XMLExtendedStreamReader reader, final PathAddress parent, List<ModelNode> list)
            throws XMLStreamException {
        String name = null;
        final ModelNode host = new ModelNode();
        final int count = reader.getAttributeCount();
        for (int i = 0; i < count; i++) {
            requireNoNamespaceAttribute(reader, i);
            final String value = reader.getAttributeValue(i);
            final Attribute attribute = Attribute.forName(reader.getAttributeLocalName(i));
            switch (attribute) {
                case NAME:
                    name = value;
                    break;
                case DEFAULT_WEB_MODULE:
                    WebVirtualHostDefinition.DEFAULT_WEB_MODULE.parseAndSetParameter(value, host, reader);
                    break;
                case ENABLE_WELCOME_ROOT:
                    WebVirtualHostDefinition.ENABLE_WELCOME_ROOT.parseAndSetParameter(value, host, reader);
                    break;
                default:
                    throw unexpectedAttribute(reader, i);
            }
        }
        if (name == null) {
            throw missingRequired(reader, Collections.singleton(Attribute.NAME));
        }
        final PathAddress address = PathAddress.pathAddress(parent, PathElement.pathElement(VIRTUAL_SERVER, name));

        host.get(OP).set(ADD);
        host.get(OP_ADDR).set(address.toModelNode());
        list.add(host);
        int rewriteCount = 0;
        while (reader.hasNext() && reader.nextTag() != END_ELEMENT) {

            switch (Namespace.forUri(reader.getNamespaceURI())) {
                case WEB_1_0: {
                    final Element element = Element.forName(reader.getLocalName());
                    switch (element) {
                        case ALIAS:
                            host.get(ALIAS).add(readStringAttributeElement(reader, Attribute.NAME.getLocalName()));
                            break;
                        case ACCESS_LOG:
                            parseHostAccessLog(reader, address, list);
                            break;
                        case REWRITE:
                            parseHostRewrite(reader, address, list, ++rewriteCount);
                            break;
                        default:
                            throw unexpectedElement(reader);
                    }
                    break;
                }
                case WEB_1_1:
                case WEB_1_2:
                case WEB_1_3: {
                    final Element element = Element.forName(reader.getLocalName());
                    switch (element) {
                        case ALIAS:
                            host.get(ALIAS).add(readStringAttributeElement(reader, Attribute.NAME.getLocalName()));
                            break;
                        case ACCESS_LOG:
                            parseHostAccessLog(reader, address, list);
                            break;
                        case REWRITE:
                            parseHostRewrite(reader, address, list, ++rewriteCount);
                            break;
                        case SSO:
                            parseSso(reader, address, list);
                            break;
                        default:
                            throw unexpectedElement(reader);
                    }
                    break;
                }
                case WEB_1_4:
                case WEB_1_5:
                case WEB_2_0:
                case WEB_2_1:
                case WEB_2_2: {
                    final Element element = Element.forName(reader.getLocalName());
                    switch (element) {
                        case ALIAS:
                            host.get(ALIAS).add(readStringAttributeElement(reader, Attribute.NAME.getLocalName()));
                            break;
                        case ACCESS_LOG:
                            parseHostAccessLog(reader, address, list);
                            break;
                        case REWRITE:
                            parseHostRewrite(reader, address, list, ++rewriteCount);
                            break;
                        case SSO:
                            parseSso(reader, address, list);
                            break;
                        case VALVE:
                            parseValve(reader, address, list);
                            break;

                        default:
                            throw unexpectedElement(reader);
                    }
                    break;
                }
                default:
                    throw unexpectedElement(reader);
            }
        }
    }

    static void parseSso(XMLExtendedStreamReader reader, final PathAddress parent, List<ModelNode> list)
            throws XMLStreamException {
        final PathAddress address = PathAddress.pathAddress(parent, WebExtension.SSO_PATH);
        final ModelNode operation = new ModelNode();
        operation.get(OP).set(ADD);
        operation.get(OP_ADDR).set(address.toModelNode());
        final int count = reader.getAttributeCount();
        for (int i = 0; i < count; i++) {
            requireNoNamespaceAttribute(reader, i);
            final String value = reader.getAttributeValue(i);
            final Attribute attribute = Attribute.forName(reader.getAttributeLocalName(i));
            switch (attribute) {
                case CACHE_CONTAINER:
                    WebSSODefinition.CACHE_CONTAINER.parseAndSetParameter(value, operation, reader);
                    break;
                case CACHE_NAME:
                    WebSSODefinition.CACHE_NAME.parseAndSetParameter(value, operation, reader);
                    break;
                case DOMAIN:
                    WebSSODefinition.DOMAIN.parseAndSetParameter(value, operation, reader);
                    break;
                case REAUTHENTICATE:
                    WebSSODefinition.REAUTHENTICATE.parseAndSetParameter(value, operation, reader);
                    break;
                case HTTP_ONLY:
                    attributeSupportedSince(Namespace.WEB_2_2, reader, i);
                    WebSSODefinition.HTTP_ONLY.parseAndSetParameter(value, operation, reader);
                    break;
                default:
                    throw unexpectedAttribute(reader, i);
            }
        }
        requireNoContent(reader);
        list.add(operation);
    }

    static void parseHostRewrite(XMLExtendedStreamReader reader, final PathAddress parent, List<ModelNode> list, int rewriteCount) throws XMLStreamException {
        final ModelNode rewrite = Util.createAddOperation();
        final int count = reader.getAttributeCount();
        String name = RULE_PREFIX + rewriteCount;
        for (int i = 0; i < count; i++) {
            requireNoNamespaceAttribute(reader, i);
            final String value = reader.getAttributeValue(i);
            final Attribute attribute = Attribute.forName(reader.getAttributeLocalName(i));
            switch (attribute) {
                case PATTERN:
                    WebReWriteDefinition.PATTERN.parseAndSetParameter(value, rewrite, reader);
                    break;
                case SUBSTITUTION:
                    WebReWriteDefinition.SUBSTITUTION.parseAndSetParameter(value, rewrite, reader);
                    break;
                case FLAGS:
                    WebReWriteDefinition.FLAGS.parseAndSetParameter(value, rewrite, reader);
                    break;
                case NAME:
                    name = value;
                    break;
                default:
                    throw unexpectedAttribute(reader, i);
            }
        }
        final PathAddress address = PathAddress.pathAddress(parent, PathElement.pathElement(REWRITE, name));
        rewrite.get(OP_ADDR).set(address.toModelNode());
        list.add(rewrite);
        int conditionCount = 0;
        while (reader.hasNext() && reader.nextTag() != END_ELEMENT) {
            switch (Namespace.forUri(reader.getNamespaceURI())) {
                case WEB_1_0:
                case WEB_1_1:
                case WEB_1_2:
                case WEB_1_3:
                case WEB_1_4:
                case WEB_1_5:
                case WEB_2_0:
                case WEB_2_1:
                case WEB_2_2: {
                    final Element element = Element.forName(reader.getLocalName());
                    switch (element) {
                        case CONDITION:
                            final ModelNode condition = Util.createAddOperation();
                            String condName = CONDITION_PREFIX + conditionCount;
                            final int count2 = reader.getAttributeCount();
                            for (int i = 0; i < count2; i++) {
                                requireNoNamespaceAttribute(reader, i);
                                final String value = reader.getAttributeValue(i);
                                final Attribute attribute = Attribute.forName(reader.getAttributeLocalName(i));
                                switch (attribute) {
                                    case NAME:
                                        condName = value;
                                        break;
                                    case TEST:
                                        WebReWriteConditionDefinition.TEST.parseAndSetParameter(value, condition, reader);
                                        break;
                                    case PATTERN:
                                        WebReWriteConditionDefinition.PATTERN.parseAndSetParameter(value, condition, reader);
                                        break;
                                    case FLAGS:
                                        WebReWriteConditionDefinition.FLAGS.parseAndSetParameter(value, condition, reader);
                                        break;
                                    default:
                                        throw unexpectedAttribute(reader, i);
                                }
                            }
                            PathAddress condAddress = address.append(PathElement.pathElement(CONDITION, condName));
                            condition.get(OP_ADDR).set(condAddress.toModelNode());
                            requireNoContent(reader);
                            list.add(condition);
                            conditionCount++;
                            break;
                        default:
                            throw unexpectedElement(reader);
                    }
                    break;
                }
                default:
                    throw unexpectedElement(reader);
            }
        }

    }

    static void parseHostAccessLog(XMLExtendedStreamReader reader, final PathAddress parent, List<ModelNode> list)
            throws XMLStreamException {
        PathAddress address = PathAddress.pathAddress(parent, ACCESS_LOG_PATH);
        final ModelNode log = new ModelNode();
        log.get(OP).set(ADD);
        log.get(OP_ADDR).set(address.toModelNode());

        final int count = reader.getAttributeCount();
        for (int i = 0; i < count; i++) {
            requireNoNamespaceAttribute(reader, i);
            final String value = reader.getAttributeValue(i);
            final Attribute attribute = Attribute.forName(reader.getAttributeLocalName(i));
            switch (attribute) {
                case PATTERN:
                    WebAccessLogDefinition.PATTERN.parseAndSetParameter(value, log, reader);
                    break;
                case RESOLVE_HOSTS:
                    WebAccessLogDefinition.RESOLVE_HOSTS.parseAndSetParameter(value, log, reader);
                    break;
                case EXTENDED:
                    WebAccessLogDefinition.EXTENDED.parseAndSetParameter(value, log, reader);
                    break;
                case PREFIX:
                    WebAccessLogDefinition.PREFIX.parseAndSetParameter(value, log, reader);
                    break;
                case ROTATE:
                    WebAccessLogDefinition.ROTATE.parseAndSetParameter(value, log, reader);
                    break;
                default:
                    throw unexpectedAttribute(reader, i);
            }
        }
        list.add(log);
        while (reader.hasNext() && reader.nextTag() != END_ELEMENT) {
            switch (Namespace.forUri(reader.getNamespaceURI())) {
                case WEB_1_0:
                case WEB_1_1:
                case WEB_1_2:
                case WEB_1_3:
                case WEB_1_4:
                case WEB_1_5:
                case WEB_2_0:
                case WEB_2_1:
                case WEB_2_2: {
                    final Element element = Element.forName(reader.getLocalName());
                    switch (element) {
                        case DIRECTORY:
                            parseDirOrFile(reader, address, list, WebExtension.DIRECTORY_PATH);
                            break;
                        default:
                            throw unexpectedElement(reader);
                    }
                    break;
                }
                default:
                    throw unexpectedElement(reader);
            }
        }

    }

    private static void attributeSupportedSince(Namespace namespace, XMLExtendedStreamReader reader, int i) throws XMLStreamException {
        Namespace currentNamespace= Namespace.forUri(reader.getNamespaceURI());
        if (currentNamespace.compareTo(namespace) >= 0) {
            return;
        }
        throw unexpectedAttribute(reader, i);
    }

    static void parseConnector(XMLExtendedStreamReader reader, PathAddress parent, List<ModelNode> list)
            throws XMLStreamException {
        String name = null;
        final ModelNode connector = new ModelNode();

        final int count = reader.getAttributeCount();
        for (int i = 0; i < count; i++) {
            requireNoNamespaceAttribute(reader, i);
            final String value = reader.getAttributeValue(i);
            final Attribute attribute = Attribute.forName(reader.getAttributeLocalName(i));
            switch (attribute) {
                case NAME:
                    name = value;
                    break;
                case SOCKET_BINDING:
                    WebConnectorDefinition.SOCKET_BINDING.parseAndSetParameter(value, connector, reader);
                    break;
                case SCHEME:
                    WebConnectorDefinition.SCHEME.parseAndSetParameter(value, connector, reader);
                    break;
                case PROTOCOL:
                    WebConnectorDefinition.PROTOCOL.parseAndSetParameter(value, connector, reader);
                    break;
                case EXECUTOR:
                    WebConnectorDefinition.EXECUTOR.parseAndSetParameter(value, connector, reader);
                    break;
                case ENABLED:
                    WebConnectorDefinition.ENABLED.parseAndSetParameter(value, connector, reader);
                    break;
                case ENABLE_LOOKUPS:
                    WebConnectorDefinition.ENABLE_LOOKUPS.parseAndSetParameter(value, connector, reader);
                    break;
                case PROXY_BINDING:
                    attributeSupportedSince(Namespace.WEB_2_1, reader, i);
                    WebConnectorDefinition.PROXY_BINDING.parseAndSetParameter(value, connector, reader);
                    break;
                case PROXY_NAME:
                    WebConnectorDefinition.PROXY_NAME.parseAndSetParameter(value, connector, reader);
                    break;
                case PROXY_PORT:
                    WebConnectorDefinition.PROXY_PORT.parseAndSetParameter(value, connector, reader);
                    break;
                case MAX_POST_SIZE:
                    WebConnectorDefinition.MAX_POST_SIZE.parseAndSetParameter(value, connector, reader);
                    break;
                case MAX_SAVE_POST_SIZE:
                    WebConnectorDefinition.MAX_SAVE_POST_SIZE.parseAndSetParameter(value, connector, reader);
                    break;
                case SECURE:
                    WebConnectorDefinition.SECURE.parseAndSetParameter(value, connector, reader);
                    break;
                case REDIRECT_BINDING:
                    attributeSupportedSince(Namespace.WEB_2_1, reader, i);
                    WebConnectorDefinition.REDIRECT_BINDING.parseAndSetParameter(value, connector, reader);
                    connector.remove(WebConnectorDefinition.REDIRECT_PORT.getName());
                    break;
                case REDIRECT_PORT:
                    WebConnectorDefinition.REDIRECT_PORT.parseAndSetParameter(value, connector, reader);
                    break;
                case MAX_CONNECTIONS:
                    WebConnectorDefinition.MAX_CONNECTIONS.parseAndSetParameter(value, connector, reader);
                    break;
                default:
                    throw unexpectedAttribute(reader, i);
            }
        }
        if (name == null) {
            throw missingRequired(reader, Collections.singleton(Attribute.NAME));
        }
        connector.get(OP).set(ADD);
        PathAddress address = PathAddress.pathAddress(parent, PathElement.pathElement(CONNECTOR, name));
        connector.get(OP_ADDR).set(address.toModelNode());
        list.add(connector);

        while (reader.hasNext() && reader.nextTag() != END_ELEMENT) {
            switch (Namespace.forUri(reader.getNamespaceURI())) {
                case WEB_1_0:
                case WEB_1_1:
                case WEB_1_2:
                case WEB_1_3:
                case WEB_1_4:
                case WEB_1_5:
                case WEB_2_0:
                case WEB_2_1:
                case WEB_2_2: {
                    final Element element = Element.forName(reader.getLocalName());
                    switch (element) {
                        case SSL:
                            parseSsl(reader, address, list);
                            break;
                        case VIRTUAL_SERVER:
                            String value = readStringAttributeElement(reader, Attribute.NAME.getLocalName());
                            WebConnectorDefinition.VIRTUAL_SERVER.parseAndAddParameterElement(value, connector, reader);
                            break;
                        default:
                            throw unexpectedElement(reader);
                    }
                    break;
                }
                default:
                    throw unexpectedElement(reader);
            }
        }

    }

    static void parseSsl(XMLExtendedStreamReader reader, PathAddress parent, List<ModelNode> list) throws XMLStreamException {
        PathAddress address = PathAddress.pathAddress(parent, WebExtension.SSL_PATH);
        final ModelNode ssl = Util.createAddOperation(address);
        final int count = reader.getAttributeCount();
        for (int i = 0; i < count; i++) {
            requireNoNamespaceAttribute(reader, i);
            final String value = reader.getAttributeValue(i);
            final Attribute attribute = Attribute.forName(reader.getAttributeLocalName(i));
            switch (attribute) {
                case NAME:
                    WebSSLDefinition.NAME.parseAndSetParameter(value, ssl, reader);
                    break;
                case KEY_ALIAS:
                    WebSSLDefinition.KEY_ALIAS.parseAndSetParameter(value, ssl, reader);
                    break;
                case PASSWORD:
                    WebSSLDefinition.PASSWORD.parseAndSetParameter(value, ssl, reader);
                    break;
                case CERTIFICATE_KEY_FILE:
                    WebSSLDefinition.CERTIFICATE_KEY_FILE.parseAndSetParameter(value, ssl, reader);
                    break;
                case CIPHER_SUITE:
                    WebSSLDefinition.CIPHER_SUITE.parseAndSetParameter(value, ssl, reader);
                    break;
                case PROTOCOL:
                    WebSSLDefinition.PROTOCOL.parseAndSetParameter(value, ssl, reader);
                    break;
                case VERIFY_CLIENT:
                    WebSSLDefinition.VERIFY_CLIENT.parseAndSetParameter(value, ssl, reader);
                    break;
                case VERIFY_DEPTH:
                    WebSSLDefinition.VERIFY_DEPTH.parseAndSetParameter(value, ssl, reader);
                    break;
                case CERTIFICATE_FILE:
                    WebSSLDefinition.CERTIFICATE_FILE.parseAndSetParameter(value, ssl, reader);
                    break;
                case CA_CERTIFICATE_FILE:
                    WebSSLDefinition.CA_CERTIFICATE_FILE.parseAndSetParameter(value, ssl, reader);
                    break;
                case CA_REVOCATION_URL:
                    WebSSLDefinition.CA_REVOCATION_URL.parseAndSetParameter(value, ssl, reader);
                    break;
                case SESSION_CACHE_SIZE:
                    WebSSLDefinition.SESSION_CACHE_SIZE.parseAndSetParameter(value, ssl, reader);
                    break;
                case SESSION_TIMEOUT:
                    WebSSLDefinition.SESSION_TIMEOUT.parseAndSetParameter(value, ssl, reader);
                    break;
                case CA_CERTIFICATE_PASSWORD:
                    WebSSLDefinition.CA_CERTIFICATE_PASSWORD.parseAndSetParameter(value, ssl, reader);
                    break;
                case KEYSTORE_TYPE:
                    WebSSLDefinition.KEYSTORE_TYPE.parseAndSetParameter(value, ssl, reader);
                    break;
                case TRUSTSTORE_TYPE:
                    WebSSLDefinition.TRUSTSTORE_TYPE.parseAndSetParameter(value, ssl, reader);
                    break;
                case SSL_PROTOCOL:
                    WebSSLDefinition.SSL_PROTOCOL.parseAndSetParameter(value, ssl, reader);
                    break;
                default:
                    throw unexpectedAttribute(reader, i);
            }
        }
        Namespace namespace = Namespace.forUri(reader.getNamespaceURI());
        if (namespace == Namespace.WEB_1_1 || namespace == Namespace.WEB_1_0) { // workaround to set default for old schema
            if (!ssl.hasDefined(WebSSLDefinition.KEY_ALIAS.getName())) {
                ssl.get(WebSSLDefinition.KEY_ALIAS.getName()).set("jboss");
            }
        }

        requireNoContent(reader);
        list.add(ssl);
    }

    // todo, attribute.marshallAsAttribute should return boolean
    private boolean writeAttribute(XMLExtendedStreamWriter writer, SimpleAttributeDefinition attribute, ModelNode node,
                                   boolean startWriten, String origin) throws XMLStreamException {

        if (attribute.isMarshallable(node, false)) {
            if (!startWriten) {
                startWriten = true;
                writer.writeStartElement(origin);
            }
            attribute.marshallAsAttribute(node, false, writer);
        }
        return startWriten;
    }

}