/*
 * JBoss, Home of Professional Open Source.
 * Copyright 2012, 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.naming.subsystem;

import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.OP_ADDR;
import static org.jboss.as.controller.parsing.ParseUtils.missingRequired;
import static org.jboss.as.controller.parsing.ParseUtils.requireAttributes;
import static org.jboss.as.controller.parsing.ParseUtils.requireNoAttributes;
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.naming.subsystem.NamingExtension.SUBSYSTEM_PATH;
import static org.jboss.as.naming.subsystem.NamingSubsystemModel.BINDING;
import static org.jboss.as.naming.subsystem.NamingSubsystemModel.BINDING_TYPE;
import static org.jboss.as.naming.subsystem.NamingSubsystemModel.EXTERNAL_CONTEXT;
import static org.jboss.as.naming.subsystem.NamingSubsystemModel.LOOKUP;
import static org.jboss.as.naming.subsystem.NamingSubsystemModel.OBJECT_FACTORY;
import static org.jboss.as.naming.subsystem.NamingSubsystemModel.SIMPLE;

import java.util.EnumSet;
import java.util.List;
import javax.xml.stream.XMLStreamConstants;
import javax.xml.stream.XMLStreamException;

import org.jboss.as.controller.PathAddress;
import org.jboss.as.controller.operations.common.Util;
import org.jboss.dmr.ModelNode;
import org.jboss.staxmapper.XMLElementReader;
import org.jboss.staxmapper.XMLExtendedStreamReader;

/**
 * @author Eduardo Martins
 */
public class NamingSubsystem14Parser implements XMLElementReader<List<ModelNode>> {

    private final NamingSubsystemNamespace validNamespace;

    NamingSubsystem14Parser() {
        this.validNamespace = NamingSubsystemNamespace.NAMING_1_4;
    }

    NamingSubsystem14Parser(NamingSubsystemNamespace validNamespace) {
        this.validNamespace = validNamespace;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void readElement(final XMLExtendedStreamReader reader, final List<ModelNode> operations) throws XMLStreamException {

        PathAddress address = PathAddress.pathAddress(SUBSYSTEM_PATH);
        final ModelNode ejb3SubsystemAddOperation = Util.createAddOperation(address);
        operations.add(ejb3SubsystemAddOperation);

        // elements
        final EnumSet<NamingSubsystemXMLElement> encountered = EnumSet.noneOf(NamingSubsystemXMLElement.class);
        while (reader.hasNext() && reader.nextTag() != XMLStreamConstants.END_ELEMENT) {
            if (validNamespace == NamingSubsystemNamespace.forUri(reader.getNamespaceURI())) {
                final NamingSubsystemXMLElement element = NamingSubsystemXMLElement.forName(reader.getLocalName());
                if (!encountered.add(element)) {
                    throw unexpectedElement(reader);
                }
                switch (element) {
                    case BINDINGS: {
                        parseBindings(reader, operations, address);
                        break;
                    }
                    case REMOTE_NAMING: {
                        parseRemoteNaming(reader, operations, address);
                        break;
                    }
                    default: {
                        throw unexpectedElement(reader);
                    }
                }
            }
            else {
                throw unexpectedElement(reader);
            }
        }
    }

    private void parseRemoteNaming(final XMLExtendedStreamReader reader, final List<ModelNode> operations, PathAddress parent) throws XMLStreamException {
        requireNoAttributes(reader);
        requireNoContent(reader);
        operations.add(Util.createAddOperation(parent.append(NamingSubsystemModel.SERVICE, NamingSubsystemModel.REMOTE_NAMING)));
    }

    private void parseBindings(final XMLExtendedStreamReader reader, final List<ModelNode> operations, PathAddress address) throws XMLStreamException {
        // no attributes expected
        requireNoAttributes(reader);
        while (reader.hasNext() && reader.nextTag() != XMLStreamConstants.END_ELEMENT) {
            switch (NamingSubsystemXMLElement.forName(reader.getLocalName())) {
                case SIMPLE: {
                    this.parseSimpleBinding(reader, operations, address);
                    break;
                }
                case OBJECT_FACTORY: {
                    this.parseObjectFactoryBinding(reader, operations, address);
                    break;
                }
                case LOOKUP: {
                    this.parseLookupBinding(reader, operations, address);
                    break;
                }
                case EXTERNAL_CONTEXT: {
                    this.parseExternalContext(reader, operations, address);
                    break;
                }
                default: {
                    throw unexpectedElement(reader);
                }
            }
        }
    }

    private void parseSimpleBinding(final XMLExtendedStreamReader reader, List<ModelNode> operations, PathAddress parentAddress) throws XMLStreamException {
        String name = null;
        final ModelNode bindingAdd = Util.createAddOperation();
        bindingAdd.get(BINDING_TYPE).set(SIMPLE);
        final EnumSet<NamingSubsystemXMLAttribute> required = EnumSet.of(NamingSubsystemXMLAttribute.NAME, NamingSubsystemXMLAttribute.VALUE);
        for (int i = 0; i < reader.getAttributeCount(); i++) {
            requireNoNamespaceAttribute(reader, i);
            final String value = reader.getAttributeValue(i);
            final NamingSubsystemXMLAttribute attribute = NamingSubsystemXMLAttribute.forName(reader.getAttributeLocalName(i));
            required.remove(attribute);
            switch (attribute) {
                case NAME:
                    name = value.trim();
                    break;
                case VALUE:
                    NamingBindingResourceDefinition.VALUE.parseAndSetParameter(value, bindingAdd, reader);
                    break;
                case TYPE:
                    NamingBindingResourceDefinition.TYPE.parseAndSetParameter(value, bindingAdd, reader);
                    break;
                default:
                    throw unexpectedAttribute(reader, i);
            }
        }
        if (!required.isEmpty()) {
            throw missingRequired(reader, required);
        }

        requireNoContent(reader);
        final PathAddress address = parentAddress.append(BINDING, name);
        bindingAdd.get(OP_ADDR).set(address.toModelNode());
        operations.add(bindingAdd);
    }

    private void parseObjectFactoryBinding(final XMLExtendedStreamReader reader, List<ModelNode> operations, PathAddress parentAddress) throws XMLStreamException {
        final int attCount = reader.getAttributeCount();
        String name = null;
        final ModelNode bindingAdd = Util.createAddOperation();
        bindingAdd.get(BINDING_TYPE).set(OBJECT_FACTORY);
        final EnumSet<NamingSubsystemXMLAttribute> required = EnumSet.of(NamingSubsystemXMLAttribute.NAME, NamingSubsystemXMLAttribute.MODULE, NamingSubsystemXMLAttribute.CLASS);
        for (int i = 0; i < attCount; i++) {
            requireNoNamespaceAttribute(reader, i);
            final String value = reader.getAttributeValue(i);
            final NamingSubsystemXMLAttribute attribute = NamingSubsystemXMLAttribute.forName(reader.getAttributeLocalName(i));
            required.remove(attribute);
            switch (attribute) {
                case NAME:
                    name = value.trim();
                    break;
                case MODULE:
                    NamingBindingResourceDefinition.MODULE.parseAndSetParameter(value, bindingAdd, reader);
                    break;
                case CLASS:
                    NamingBindingResourceDefinition.CLASS.parseAndSetParameter(value, bindingAdd, reader);
                    break;
                default:
                    throw unexpectedAttribute(reader, i);
            }
        }
        if (!required.isEmpty()) {
            throw missingRequired(reader, required);
        }
        bindingAdd.get(OP_ADDR).set(parentAddress.append(BINDING, name).toModelNode());
        // if present, parse the optional environment
        while (reader.hasNext() && reader.nextTag() != XMLStreamConstants.END_ELEMENT) {
            switch (NamingSubsystemXMLElement.forName(reader.getLocalName())) {
                case ENVIRONMENT: {
                    parseObjectFactoryBindingEnvironment(reader, bindingAdd);
                    break;
                }
                default: {
                    throw unexpectedElement(reader);
                }
            }
        }

        operations.add(bindingAdd);
    }

    private void parseExternalContext(final XMLExtendedStreamReader reader, List<ModelNode> operations, PathAddress parentAddress) throws XMLStreamException {
        final int attCount = reader.getAttributeCount();
        String name = null;
        final ModelNode bindingAdd = Util.createAddOperation();
        bindingAdd.get(BINDING_TYPE).set(EXTERNAL_CONTEXT);
        final EnumSet<NamingSubsystemXMLAttribute> required = EnumSet.of(NamingSubsystemXMLAttribute.NAME, NamingSubsystemXMLAttribute.CLASS, NamingSubsystemXMLAttribute.MODULE);
        for (int i = 0; i < attCount; i++) {
            requireNoNamespaceAttribute(reader, i);
            final String value = reader.getAttributeValue(i);
            final NamingSubsystemXMLAttribute attribute = NamingSubsystemXMLAttribute.forName(reader.getAttributeLocalName(i));
            required.remove(attribute);
            switch (attribute) {
                case NAME:
                    name = value.trim();
                    break;
                case MODULE:
                    NamingBindingResourceDefinition.MODULE.parseAndSetParameter(value, bindingAdd, reader);
                    break;
                case CLASS:
                    NamingBindingResourceDefinition.CLASS.parseAndSetParameter(value, bindingAdd, reader);
                    break;
                case CACHE:
                    NamingBindingResourceDefinition.CACHE.parseAndSetParameter(value, bindingAdd, reader);
                    break;
                default:
                    throw unexpectedAttribute(reader, i);
            }
        }
        if (!required.isEmpty()) {
            throw missingRequired(reader, required);
        }
        bindingAdd.get(OP_ADDR).set(parentAddress.append(BINDING, name).toModelNode());
        // if present, parse the optional environment
        while (reader.hasNext() && reader.nextTag() != XMLStreamConstants.END_ELEMENT) {
            switch (NamingSubsystemXMLElement.forName(reader.getLocalName())) {
                case ENVIRONMENT: {
                    parseObjectFactoryBindingEnvironment(reader, bindingAdd);
                    break;
                }
                default: {
                    throw unexpectedElement(reader);
                }
            }
        }

        operations.add(bindingAdd);
    }

    /**
     * <p>
     * Parses the optional {@code ObjectFactory environment}.
     * </p>
     *
     * @param reader     the {@code XMLExtendedStreamReader} used to read the configuration XML.
     * @param bindingAdd where to add
     * @throws javax.xml.stream.XMLStreamException
     *          if an error occurs while parsing the XML.
     */
    private void parseObjectFactoryBindingEnvironment(XMLExtendedStreamReader reader, ModelNode bindingAdd) throws XMLStreamException {
        // no attributes expected
        requireNoAttributes(reader);
        while (reader.hasNext() && reader.nextTag() != XMLStreamConstants.END_ELEMENT) {
            switch (NamingSubsystemXMLElement.forName(reader.getLocalName())) {
                case ENVIRONMENT_PROPERTY: {
                    final String[] array = requireAttributes(reader, org.jboss.as.controller.parsing.Attribute.NAME.getLocalName(), org.jboss.as.controller.parsing.Attribute.VALUE.getLocalName());
                    NamingBindingResourceDefinition.ENVIRONMENT.parseAndAddParameterElement(array[0], array[1], bindingAdd, reader);
                    requireNoContent(reader);
                    break;
                }
                default: {
                    throw unexpectedElement(reader);
                }
            }
        }
    }

    private void parseLookupBinding(final XMLExtendedStreamReader reader, List<ModelNode> operations, PathAddress parentAddress) throws XMLStreamException {
        final int attCount = reader.getAttributeCount();
        String name = null;
        final ModelNode bindingAdd = Util.createAddOperation();
        bindingAdd.get(BINDING_TYPE).set(LOOKUP);
        final EnumSet<NamingSubsystemXMLAttribute> required = EnumSet.of(NamingSubsystemXMLAttribute.NAME, NamingSubsystemXMLAttribute.LOOKUP);
        for (int i = 0; i < attCount; i++) {
            requireNoNamespaceAttribute(reader, i);
            final String value = reader.getAttributeValue(i);
            final NamingSubsystemXMLAttribute attribute = NamingSubsystemXMLAttribute.forName(reader.getAttributeLocalName(i));
            required.remove(attribute);
            switch (attribute) {
                case NAME:
                    name = value.trim();
                    break;
                case LOOKUP:
                    NamingBindingResourceDefinition.LOOKUP.parseAndSetParameter(value, bindingAdd, reader);
                    break;
                default:
                    throw unexpectedAttribute(reader, i);
            }
        }
        if (!required.isEmpty()) {
            throw missingRequired(reader, required);
        }

        requireNoContent(reader);
        bindingAdd.get(OP_ADDR).set(parentAddress.append(BINDING, name).toModelNode());
        operations.add(bindingAdd);
    }
}


/*
 * JBoss, Home of Professional Open Source.
 * Copyright 2012, 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.clustering.infinispan.subsystem;

import org.jboss.dmr.ModelNode;

/**
 * Convert the 1.4 SEGMENTS value to VIRTUAL_NODES in model and operations, if defined and not an expression
 *
 * @author Tomaz Cerar
 * @author Richard Achmatowicz (c) RedHat 2013
 */
public class SegmentsAndVirtualNodeConverter  {

    // ratio of segments to virtual nodes to convert between the two
    public static final int SEGMENTS_PER_VIRTUAL_NODE = 6;
    public static final int VIRTUAL_NODES_DEFAULT = 1;
    public static final int SEGMENTS_DEFAULT = SegmentedCacheResourceDefinition.Attribute.SEGMENTS.getDefinition().getDefaultValue().asInt();

    /*
     * Convert a 1.3 virtual nodes value to a 1.4 segments value
     */
    public static int virtualNodesToSegments(int virtualNodes) {
        return virtualNodes * SEGMENTS_PER_VIRTUAL_NODE;
    }

    /*
     * Convert a 1.4 segments value to a 1.3 virtual nodes value
     */
    public static int segmentsToVirtualNodes(int segments) {
        // divide by zero should not occur as segments is required to be > 0
        return segments / SEGMENTS_PER_VIRTUAL_NODE;
    }

    /*
     * Helper methods
     */
    public static String virtualNodesToSegments(String virtualNodesValue) {
        int segments = SEGMENTS_DEFAULT;
        try {
            segments =  virtualNodesToSegments(Integer.parseInt(virtualNodesValue));
        }
        catch(NumberFormatException nfe) {
            // in case of expression
        }
        return Integer.toString(segments);
    }

    public static String segmentsToVirtualNodes(String segmentsValue) {
        int virtualNodes = VIRTUAL_NODES_DEFAULT;
        try {
            virtualNodes =  segmentsToVirtualNodes(Integer.parseInt(segmentsValue));
        }
        catch(NumberFormatException nfe) {
            // in case of expression
        }
        return Integer.toString(virtualNodes);
    }

    public static ModelNode virtualNodesToSegments(ModelNode virtualNodes) {
        int segments = SEGMENTS_DEFAULT;
        if (virtualNodes.isDefined()) {
           segments = virtualNodesToSegments(virtualNodes.asInt());
        }
        return new ModelNode(segments);
    }

    public static ModelNode segmentsToVirtualNodes(ModelNode segments) {
        int virtualNodes = VIRTUAL_NODES_DEFAULT;
        if (segments.isDefined()) {
           virtualNodes = segmentsToVirtualNodes(segments.asInt());
        }
        return new ModelNode(virtualNodes);
    }
}


/*
 * JBoss, Home of Professional Open Source
 * Copyright (c) 2010, JBoss 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.ejb3.tx;

import javax.ejb.EJBException;
import javax.transaction.SystemException;
import javax.transaction.Transaction;

import org.jboss.as.ejb3.component.EJBComponent;
import org.jboss.invocation.Interceptor;
import org.jboss.invocation.InterceptorContext;
import org.wildfly.transaction.client.ContextTransactionManager;

/**
 * Suspend an incoming tx.
 *
 * @author Bill Burke
 * @author Ole Husgaard
 * @author Carlo de Wolf
 */
public abstract class BMTInterceptor implements Interceptor {

    private final EJBComponent component;

    public BMTInterceptor(final EJBComponent component) {
        this.component = component;
    }

    protected abstract Object handleInvocation(InterceptorContext invocation) throws Exception;

    @Override
    public Object processInvocation(final InterceptorContext context) throws Exception {
        final ContextTransactionManager tm = ContextTransactionManager.getInstance();
        final int oldTimeout = tm.getTransactionTimeout();
        try {
            Transaction oldTx = tm.suspend();
            try {
                return handleInvocation(context);
            } finally {
                if (oldTx != null) tm.resume(oldTx);
            }
        } finally {
            // See also https://issues.jboss.org/browse/WFTC-44
            tm.setTransactionTimeout(oldTimeout == ContextTransactionManager.getGlobalDefaultTransactionTimeout() ? 0 : oldTimeout);
        }
    }

    /**
     * Checks if the passed exception is an application exception. If yes, then throws back the
     * exception as-is. Else, wraps the exception in a {@link javax.ejb.EJBException} and throws the EJBException
     *
     * @param ex The exception to handle
     * @throws Exception Either the passed exception or an EJBException
     */
    protected Exception handleException(final InterceptorContext invocation, Throwable ex) throws Exception {
        ApplicationExceptionDetails ae = component.getApplicationException(ex.getClass(), invocation.getMethod());
        // it's an application exception, so just throw it back as-is
        if (ae != null) {
            throw (Exception)ex;
        }
        if (ex instanceof EJBException) {
            throw (EJBException) ex;
        } else if(ex instanceof Exception){
            throw new EJBException((Exception)ex);
        } else {
            throw new EJBException(new RuntimeException(ex));
        }
    }

    protected int getCurrentTransactionTimeout(final EJBComponent component) throws SystemException {
        return ContextTransactionManager.getInstance().getTransactionTimeout();
    }

    public EJBComponent getComponent() {
        return component;
    }
}


/*
 * 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.ejb3.deployment.processors;

import org.jboss.as.ee.component.Attachments;
import org.jboss.as.ee.component.ComponentDescription;
import org.jboss.as.ee.component.ComponentNamingMode;
import org.jboss.as.ee.component.EEModuleDescription;
import org.jboss.as.ee.structure.DeploymentType;
import org.jboss.as.ee.structure.DeploymentTypeMarker;
import org.jboss.as.ejb3.iiop.handle.HandleDelegateImpl;
import org.jboss.as.naming.ManagedReferenceInjector;
import org.jboss.as.naming.ServiceBasedNamingStore;
import org.jboss.as.naming.ValueManagedReferenceFactory;
import org.jboss.as.naming.deployment.ContextNames;
import org.jboss.as.naming.service.BinderService;
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.modules.Module;
import org.jboss.msc.service.ServiceName;
import org.jboss.msc.service.ServiceTarget;
import org.jboss.msc.value.ImmediateValue;
import org.omg.CORBA.ORB;
import org.wildfly.iiop.openjdk.deployment.IIOPDeploymentMarker;
import org.wildfly.iiop.openjdk.service.CorbaORBService;

/**
 * Processor responsible for binding IIOP related resources to JNDI.
 * </p>
 * Unlike other resource injections this binding happens for all eligible components,
 * regardless of the presence of the {@link javax.annotation.Resource} annotation.
 *
 * @author Stuart Douglas
 */
public class IIOPJndiBindingProcessor implements DeploymentUnitProcessor {
    @Override
    public void deploy(DeploymentPhaseContext phaseContext) throws DeploymentUnitProcessingException {
        final DeploymentUnit deploymentUnit = phaseContext.getDeploymentUnit();
        final EEModuleDescription moduleDescription = deploymentUnit.getAttachment(Attachments.EE_MODULE_DESCRIPTION);
        final Module module = deploymentUnit.getAttachment(org.jboss.as.server.deployment.Attachments.MODULE);

        if (moduleDescription == null) {
            return;
        }

        //do not bind if jacORB not present
        if (!IIOPDeploymentMarker.isIIOPDeployment(deploymentUnit)) {
            return;
        }

        final ServiceTarget serviceTarget = phaseContext.getServiceTarget();
        //if this is a war we need to bind to the modules comp namespace

        if (DeploymentTypeMarker.isType(DeploymentType.WAR, deploymentUnit) || DeploymentTypeMarker.isType(DeploymentType.APPLICATION_CLIENT, deploymentUnit)) {
            final ServiceName moduleContextServiceName = ContextNames.contextServiceNameOfModule(moduleDescription.getApplicationName(), moduleDescription.getModuleName());
            bindService(serviceTarget, moduleContextServiceName, module);
        }

        for (ComponentDescription component : moduleDescription.getComponentDescriptions()) {
            if (component.getNamingMode() == ComponentNamingMode.CREATE) {
                final ServiceName compContextServiceName = ContextNames.contextServiceNameOfComponent(moduleDescription.getApplicationName(), moduleDescription.getModuleName(), component.getComponentName());
                bindService(serviceTarget, compContextServiceName, module);
            }
        }

    }

    /**
     * Binds java:comp/ORB
     *
     * @param serviceTarget      The service target
     * @param contextServiceName The service name of the context to bind to
     */
    private void bindService(final ServiceTarget serviceTarget, final ServiceName contextServiceName, final Module module) {

        final ServiceName orbServiceName = contextServiceName.append("ORB");
        final BinderService orbService = new BinderService("ORB");
        serviceTarget.addService(orbServiceName, orbService)
                .addDependency(CorbaORBService.SERVICE_NAME, ORB.class,
                        new ManagedReferenceInjector<ORB>(orbService.getManagedObjectInjector()))
                .addDependency(contextServiceName, ServiceBasedNamingStore.class, orbService.getNamingStoreInjector())
                .install();

        final ServiceName handleDelegateServiceName = contextServiceName.append("HandleDelegate");
        final BinderService handleDelegateBindingService = new BinderService("HandleDelegate");
        handleDelegateBindingService.getManagedObjectInjector().inject(new ValueManagedReferenceFactory(new ImmediateValue(new HandleDelegateImpl(module.getClassLoader()))));
        serviceTarget.addService(handleDelegateServiceName, handleDelegateBindingService)
                .addDependency(contextServiceName, ServiceBasedNamingStore.class, handleDelegateBindingService.getNamingStoreInjector())
                .install();

    }

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


/*
 * JBoss, Home of Professional Open Source.
 * Copyright 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.subsystem.deployment;

import java.util.Map;

import org.jboss.as.controller.AttributeDefinition;
import org.jboss.as.controller.ListAttributeDefinition;
import org.jboss.as.controller.ObjectTypeAttributeDefinition;
import org.jboss.as.controller.OperationContext;
import org.jboss.as.controller.OperationFailedException;
import org.jboss.as.controller.PathElement;
import org.jboss.as.controller.PrimitiveListAttributeDefinition;
import org.jboss.as.controller.SimpleAttributeDefinition;
import org.jboss.as.controller.SimpleAttributeDefinitionBuilder;
import org.jboss.as.controller.SimpleResourceDefinition;
import org.jboss.as.controller.operations.validation.StringLengthValidator;
import org.jboss.as.controller.registry.AttributeAccess;
import org.jboss.as.controller.registry.ManagementResourceRegistration;
import org.jboss.as.ejb3.component.EJBComponent;
import org.jboss.as.ejb3.component.invocationmetrics.InvocationMetrics;
import org.jboss.as.ejb3.component.stateful.StatefulSessionComponent;
import org.jboss.as.ejb3.subsystem.EJB3Extension;
import org.jboss.dmr.ModelNode;
import org.jboss.dmr.ModelType;

/**
 * Base class for {@link org.jboss.as.controller.ResourceDefinition}s describing runtime {@link EJBComponent}s.
 *
 * @author Brian Stansberry (c) 2011 Red Hat Inc.
 */
public abstract class AbstractEJBComponentResourceDefinition extends SimpleResourceDefinition {

    public static final SimpleAttributeDefinition COMPONENT_CLASS_NAME = new SimpleAttributeDefinitionBuilder("component-class-name", ModelType.STRING)
            .setValidator(new StringLengthValidator(1))
            .setFlags(AttributeAccess.Flag.STORAGE_RUNTIME)
            .build();

    private static final AttributeDefinition EXECUTION_TIME = new SimpleAttributeDefinitionBuilder("execution-time", ModelType.LONG)
            .setUndefinedMetricValue(new ModelNode(0))
            .setFlags(AttributeAccess.Flag.STORAGE_RUNTIME, AttributeAccess.Flag.COUNTER_METRIC)
            .build();

    private static final AttributeDefinition INVOCATIONS = new SimpleAttributeDefinitionBuilder("invocations", ModelType.LONG)
            .setUndefinedMetricValue(new ModelNode(0))
            .setFlags(AttributeAccess.Flag.STORAGE_RUNTIME, AttributeAccess.Flag.COUNTER_METRIC)
            .build();

    private static final AttributeDefinition PEAK_CONCURRENT_INVOCATIONS = new SimpleAttributeDefinitionBuilder("peak-concurrent-invocations", ModelType.LONG)
            .setUndefinedMetricValue(new ModelNode(0))
            .setFlags(AttributeAccess.Flag.STORAGE_RUNTIME)
            .build();

    public static final SimpleAttributeDefinition SECURITY_DOMAIN = new SimpleAttributeDefinitionBuilder("security-domain", ModelType.STRING, true)
            .setValidator(new StringLengthValidator(1, true))
            .build();

    private static final AttributeDefinition WAIT_TIME = new SimpleAttributeDefinitionBuilder("wait-time", ModelType.LONG)
            .setUndefinedMetricValue(new ModelNode(0))
            .setFlags(AttributeAccess.Flag.STORAGE_RUNTIME, AttributeAccess.Flag.COUNTER_METRIC)
            .build();

    private static final AttributeDefinition METHODS = ObjectTypeAttributeDefinition.Builder.of("methods", EXECUTION_TIME, INVOCATIONS, WAIT_TIME)
            .setRequired(false)
            .setFlags(AttributeAccess.Flag.STORAGE_RUNTIME)
            .build();

    public static final SimpleAttributeDefinition RUN_AS_ROLE = new SimpleAttributeDefinitionBuilder("run-as-role", ModelType.STRING, true)
            .setValidator(new StringLengthValidator(1, true))
            .setFlags(AttributeAccess.Flag.STORAGE_RUNTIME)
            .build();

    public static final ListAttributeDefinition DECLARED_ROLES = new PrimitiveListAttributeDefinition.Builder("declared-roles", ModelType.STRING)
            .setRequired(false)
            .setElementValidator(new StringLengthValidator(1))
            .setStorageRuntime()
            .build();

    private static final AttributeDefinition CACHE_SIZE = new SimpleAttributeDefinitionBuilder("cache-size", ModelType.LONG)
            .setUndefinedMetricValue(new ModelNode(0))
            .setFlags(AttributeAccess.Flag.STORAGE_RUNTIME)
            .build();

    private static final AttributeDefinition PASSIVATED_SIZE = new SimpleAttributeDefinitionBuilder("passivated-count",
            ModelType.LONG)
            .setUndefinedMetricValue(new ModelNode(0))
            .setFlags(AttributeAccess.Flag.STORAGE_RUNTIME)
            .build();

    private static final AttributeDefinition TOTAL_SIZE = new SimpleAttributeDefinitionBuilder("total-size", ModelType.LONG)
            .setUndefinedMetricValue(new ModelNode(0))
            .setFlags(AttributeAccess.Flag.STORAGE_RUNTIME)
            .build();

    // Pool attributes

    public static final SimpleAttributeDefinition POOL_AVAILABLE_COUNT = new SimpleAttributeDefinitionBuilder("pool-available-count", ModelType.INT, false)
            .setFlags(AttributeAccess.Flag.STORAGE_RUNTIME)
            .build();
    public static final SimpleAttributeDefinition POOL_CREATE_COUNT = new SimpleAttributeDefinitionBuilder("pool-create-count", ModelType.INT, false)
            .setFlags(AttributeAccess.Flag.STORAGE_RUNTIME, AttributeAccess.Flag.COUNTER_METRIC).build();
    public static final SimpleAttributeDefinition POOL_CURRENT_SIZE = new SimpleAttributeDefinitionBuilder("pool-current-size", ModelType.INT, false)
            .setFlags(AttributeAccess.Flag.STORAGE_RUNTIME).build();
    public static final SimpleAttributeDefinition POOL_NAME = new SimpleAttributeDefinitionBuilder("pool-name", ModelType.STRING, true)
            .setFlags(AttributeAccess.Flag.STORAGE_RUNTIME).build();
    public static final SimpleAttributeDefinition POOL_REMOVE_COUNT = new SimpleAttributeDefinitionBuilder("pool-remove-count", ModelType.INT, false)
            .setFlags(AttributeAccess.Flag.STORAGE_RUNTIME, AttributeAccess.Flag.COUNTER_METRIC).build();
    public static final SimpleAttributeDefinition POOL_MAX_SIZE = new SimpleAttributeDefinitionBuilder("pool-max-size", ModelType.INT, false)
            .setFlags(AttributeAccess.Flag.STORAGE_RUNTIME).build();

    private final EJBComponentType componentType;

    public AbstractEJBComponentResourceDefinition(final EJBComponentType componentType) {
        super(PathElement.pathElement(componentType.getResourceType()),
                EJB3Extension.getResourceDescriptionResolver(componentType.getResourceType()));
        this.componentType = componentType;
    }

    @Override
    public void registerAttributes(ManagementResourceRegistration resourceRegistration) {
        final AbstractEJBComponentRuntimeHandler<?> handler = componentType.getRuntimeHandler();
        resourceRegistration.registerReadOnlyAttribute(COMPONENT_CLASS_NAME, handler);
        resourceRegistration.registerReadOnlyAttribute(SECURITY_DOMAIN, handler);
        resourceRegistration.registerReadOnlyAttribute(RUN_AS_ROLE, handler);
        resourceRegistration.registerReadOnlyAttribute(DECLARED_ROLES, handler);
        if (componentType.hasTimer()) {
            resourceRegistration.registerReadOnlyAttribute(TimerAttributeDefinition.INSTANCE, handler);
        }

        if (componentType.hasPool()) {
            resourceRegistration.registerReadOnlyAttribute(POOL_AVAILABLE_COUNT, handler);
            resourceRegistration.registerReadOnlyAttribute(POOL_CREATE_COUNT, handler);
            resourceRegistration.registerReadOnlyAttribute(POOL_NAME, handler);
            resourceRegistration.registerReadOnlyAttribute(POOL_REMOVE_COUNT, handler);
            resourceRegistration.registerReadOnlyAttribute(POOL_CURRENT_SIZE, handler);
            resourceRegistration.registerReadWriteAttribute(POOL_MAX_SIZE, handler, handler);
        }

        if (componentType.equals(EJBComponentType.STATEFUL)) {
            resourceRegistration.registerMetric(CACHE_SIZE, new AbstractRuntimeMetricsHandler() {
                @Override
                protected void executeReadMetricStep(final OperationContext context, final ModelNode operation, final EJBComponent component) throws OperationFailedException {
                    context.getResult().set(((StatefulSessionComponent)component).getCache().getCacheSize());
                }
            });
            resourceRegistration.registerMetric(PASSIVATED_SIZE, new AbstractRuntimeMetricsHandler() {
                @Override
                protected void executeReadMetricStep(final OperationContext context, final ModelNode operation, final EJBComponent component) throws OperationFailedException {
                    context.getResult().set(((StatefulSessionComponent)component).getCache().getPassivatedCount());
                }
            });
            resourceRegistration.registerMetric(TOTAL_SIZE, new AbstractRuntimeMetricsHandler() {
                @Override
                protected void executeReadMetricStep(final OperationContext context, final ModelNode operation, final EJBComponent component) throws OperationFailedException {
                    context.getResult().set(((StatefulSessionComponent)component).getCache().getTotalSize());
                }
            });
        }

        resourceRegistration.registerMetric(EXECUTION_TIME, new AbstractRuntimeMetricsHandler() {
            @Override
            protected void executeReadMetricStep(final OperationContext context, final ModelNode operation, final EJBComponent component) throws OperationFailedException {
                context.getResult().set(component.getInvocationMetrics().getExecutionTime());
            }
        });
        resourceRegistration.registerMetric(INVOCATIONS, new AbstractRuntimeMetricsHandler() {
            @Override
            protected void executeReadMetricStep(final OperationContext context, final ModelNode operation, final EJBComponent component) throws OperationFailedException {
                context.getResult().set(component.getInvocationMetrics().getInvocations());
            }
        });
        resourceRegistration.registerMetric(PEAK_CONCURRENT_INVOCATIONS, new AbstractRuntimeMetricsHandler() {
            @Override
            protected void executeReadMetricStep(final OperationContext context, final ModelNode operation, final EJBComponent component) throws OperationFailedException {
                context.getResult().set(component.getInvocationMetrics().getPeakConcurrent());
            }
        });
        resourceRegistration.registerMetric(WAIT_TIME, new AbstractRuntimeMetricsHandler() {
            @Override
            protected void executeReadMetricStep(final OperationContext context, final ModelNode operation, final EJBComponent component) throws OperationFailedException {
                context.getResult().set(component.getInvocationMetrics().getWaitTime());
            }
        });
        resourceRegistration.registerMetric(METHODS, new AbstractRuntimeMetricsHandler() {
            @Override
            protected void executeReadMetricStep(final OperationContext context, final ModelNode operation, final EJBComponent component) throws OperationFailedException {
                context.getResult().setEmptyObject();
                for (final Map.Entry<String, InvocationMetrics.Values> entry : component.getInvocationMetrics().getMethods().entrySet()) {
                    final InvocationMetrics.Values values = entry.getValue();
                    final ModelNode result = new ModelNode();
                    result.get("execution-time").set(values.getExecutionTime());
                    result.get("invocations").set(values.getInvocations());
                    result.get("wait-time").set(values.getWaitTime());
                    context.getResult().get(entry.getKey()).set(result);
                }
            }
        });
    }

    /* (non-Javadoc)
     * @see org.jboss.as.controller.SimpleResourceDefinition#registerChildren(org.jboss.as.controller.registry.ManagementResourceRegistration)
     */
    @Override
    public void registerChildren(ManagementResourceRegistration resourceRegistration) {
        super.registerChildren(resourceRegistration);
        // /deployment=DU/**/subsystem=ejb3/*=EJBName/service=timer-service
        final AbstractEJBComponentRuntimeHandler<?> handler = componentType.getRuntimeHandler();
        resourceRegistration.registerSubModel(new TimerServiceResourceDefinition(handler));
    }
}


/*
 * 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;

import java.lang.ref.SoftReference;
import java.lang.reflect.Method;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import org.wildfly.iiop.openjdk.logging.IIOPLogger;

/**
 * Instances of this class cache the most complex analyse types.
 *

 * The analyse types cached are:
 *

 *
InterfaceAnalysis for interfaces.

 *
ValueAnalysis for value types.

 *
ExceptionAnalysis for exceptions.

 *

 *

 * Besides caching work already done, this caches work in progress,
 * as we need to know about this to handle cyclic graphs of analyses.
 * When a thread re-enters the getAnalysis() method, an
 * unfinished analysis will be returned if the same thread is already
 * working on this analysis.
 *
 * @author Ole Husgaard
 */
class WorkCacheManager {

    /**
     * The analysis constructor of our analysis class.
     * This constructor takes a single argument of type Class.
     */
    private final Constructor constructor;

    /**
     * The analysis initializer of our analysis class.
     * This method takes no arguments, and is named doAnalyze.
     */
    private final Method initializer;

    /**
     * This maps the classes of completely done analyses to soft
     * references of their analysis.
     */
    private final Map<Class, SoftReference<ContainerAnalysis>> workDone;

    /**
     * This maps the classes of analyses in progress to their
     * analysis.
     */
    private final Map<InProgressKey, ContainerAnalysis> workInProgress;

    private final Map<ClassLoader, Set<Class<?>>> classesByLoader;

    /**
     * Create a new work cache manager.
     *
     * @param cls The class of the analysis type we cache here.
     */
    WorkCacheManager(final Class cls) {
        // Find the constructor and initializer.
        try {
            constructor = cls.getDeclaredConstructor(new Class[]{Class.class});
            initializer = cls.getDeclaredMethod("doAnalyze");
        } catch (NoSuchMethodException ex) {
            throw IIOPLogger.ROOT_LOGGER.unexpectedException(ex);
        }
        workDone = new HashMap<Class, SoftReference<ContainerAnalysis>>();
        workInProgress = new HashMap<InProgressKey, ContainerAnalysis>();
        classesByLoader = new HashMap<ClassLoader, Set<Class<?>>>();
    }

    public void clearClassLoader(final ClassLoader cl) {
        Set<Class<?>> classes = classesByLoader.remove(cl);
        if(classes != null) {
            for(Class<?> clazz : classes) {
                workDone.remove(clazz);
            }
        }
    }

    /**
     * Returns an analysis.
     * If the calling thread is currently doing an analysis of this
     * class, an unfinished analysis is returned.
     */
    ContainerAnalysis getAnalysis(final Class cls) throws RMIIIOPViolationException {
        ContainerAnalysis ret = null;
        boolean created = false;
        try {
            synchronized (this) {
                ret = lookupDone(cls);
                if (ret != null) {
                    return ret;
                }

                // is it work-in-progress?
                final ContainerAnalysis inProgress = workInProgress.get(new InProgressKey(cls, Thread.currentThread()));
                if (inProgress != null) {
                        return inProgress; // return unfinished

                    // Do not wait for the other thread: We may deadlock
                    // Double work is better that deadlock...
                }

                ret = createWorkInProgress(cls);
            }
            created = true;
            // Do the work
            doTheWork(cls, ret);
        } finally {
            // We did it
            synchronized (this) {
                if(created) {
                    workInProgress.remove(new InProgressKey(cls, Thread.currentThread()));
                    workDone.put(cls, new SoftReference<ContainerAnalysis>(ret));
                    ClassLoader classLoader = cls.getClassLoader();
                    if (classLoader != null) {
                        Set<Class<?>> classes = classesByLoader.get(classLoader);
                        if (classes == null) {
                            classesByLoader.put(classLoader, classes = new HashSet<Class<?>>());
                        }
                        classes.add(cls);
                    }
                }
                notifyAll();
            }
        }
        return ret;
    }

    /**
     * Lookup an analysis in the fully done map.
     */
    private ContainerAnalysis lookupDone(Class cls) {
        SoftReference ref = (SoftReference) workDone.get(cls);
        if (ref == null)
            return null;
        ContainerAnalysis ret = (ContainerAnalysis) ref.get();
        if (ret == null)
            workDone.remove(cls); // clear map entry if soft ref. was cleared.
        return ret;
    }

    /**
     * Create new work-in-progress.
     */
    private ContainerAnalysis createWorkInProgress(final Class cls) {
        final ContainerAnalysis analysis;
        try {
            analysis = (ContainerAnalysis) constructor.newInstance(cls);
        } catch (InstantiationException ex) {
            throw new RuntimeException(ex.toString());
        } catch (IllegalAccessException ex) {
            throw new RuntimeException(ex.toString());
        } catch (InvocationTargetException ex) {
            throw new RuntimeException(ex.toString());
        }

        workInProgress.put(new InProgressKey(cls, Thread.currentThread()), analysis);

        return analysis;
    }

    private void doTheWork(final Class cls, final ContainerAnalysis ret)
            throws RMIIIOPViolationException {
        try {
            initializer.invoke(ret);
        } catch (Throwable t) {
            synchronized (this) {
                workInProgress.remove(new InProgressKey(cls, Thread.currentThread()));
            }
            if (t instanceof InvocationTargetException) // unwrap
                t = ((InvocationTargetException) t).getTargetException();

            if (t instanceof RMIIIOPViolationException)
                throw (RMIIIOPViolationException) t;
            if (t instanceof RuntimeException)
                throw (RuntimeException) t;
            if (t instanceof Error)
                throw (Error) t;
            throw new RuntimeException(t.toString());
        }
    }

    private static class InProgressKey {
        final Class<?> clazz;
        final Thread thread;

        private InProgressKey(Class<?> clazz, Thread thread) {
            this.clazz = clazz;
            this.thread = thread;
        }

        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;

            InProgressKey that = (InProgressKey) o;

            if (clazz != null ? !clazz.equals(that.clazz) : that.clazz != null) return false;
            if (thread != null ? !thread.equals(that.thread) : that.thread != null) return false;

            return true;
        }

        @Override
        public int hashCode() {
            int result = clazz != null ? clazz.hashCode() : 0;
            result = 31 * result + (thread != null ? thread.hashCode() : 0);
            return result;
        }
    }
}


/*
 * JBoss, Home of Professional Open Source.
 * Copyright 2006, 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;

import java.io.Externalizable;
import java.io.ObjectStreamClass;
import java.io.Serializable;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Locale;

import org.wildfly.iiop.openjdk.logging.IIOPLogger;

/**
 * Common base class of ValueAnalysis and InterfaceAnalysis.
 *

 * Routines here are conforming to the "Java(TM) Language to IDL Mapping
 * Specification", version 1.1 (01-06-07).
 *
 * @author Ole Husgaard
 * @author Dimitris Andreadis
 * @version $Revision: 63378 $
 */
public abstract class ContainerAnalysis  extends ClassAnalysis {

    /**
     * A cache for the fully qualified IDL name of the IDL module we
     * belong to.
     */
    private String idlModuleName = null;

    /**
     * Flags a method as overloaded.
     */
    protected final byte M_OVERLOADED = 1;

    /**
     * Flags a method as the accessor of a read-write property.
     */
    protected final byte M_READ = 2;

    /**
     * Flags a method as the mutator of a read-write property.
     */
    protected final byte M_WRITE = 4;

    /**
     * Flags a method as the accessor of a read-only property.
     */
    protected final byte M_READONLY = 8;

    /**
     * Flags a method as being inherited.
     */
    protected final byte M_INHERITED = 16;

    /**
     * Flags a method as being the writeObject() method
     * used for serialization.
     */
    protected final byte M_WRITEOBJECT = 32;

    /**
     * Flags a field as being a constant (public final static).
     */
    protected final byte F_CONSTANT = 1;

    /**
     * Flags a field as being the special  public final static
     * java.io.ObjectStreamField[] serialPersistentFields field.
     */
    protected final byte F_SPFFIELD = 2;

    /**
     * Array of all java methods.
     */
    protected Method[] methods;

    /**
     * Array with flags for all java methods.
     */
    protected byte[] m_flags;

    /**
     * Index of the mutator for read-write attributes.
     * Only entries i where (m_flags[i]&M_READ) != 0
     * are used. These entries contain the index of the mutator method
     * corresponding to the accessor method.
     */
    protected int[] mutators;

    /**
     * Array of all java fields.
     */
    protected Field[] fields;

    /**
     * Array with flags for all java fields.
     */
    protected byte[] f_flags;

    /**
     * The class hash code, as specified in "The Common Object Request
     * Broker: Architecture and Specification" (01-02-33), section 10.6.2.
     */
    protected long classHashCode = 0;

    /**
     * The repository ID.
     * This is in the RMI hashed format, like
     * "RMI:java.util.Hashtable:C03324C0EA357270:13BB0F25214AE4B8".
     */
    protected String repositoryId;

    /**
     * The prefix and postfix of members repository ID.
     * These are used to calculate member repository IDs and are like
     * "RMI:java.util.Hashtable." and ":C03324C0EA357270:13BB0F25214AE4B8".
     */
    protected String memberPrefix, memberPostfix;

    /**
     * Array of analysis of the interfaces implemented/extended here.
     */
    protected InterfaceAnalysis[] interfaces;

    /**
     * Array of analysis of the abstract base valuetypes implemented/extended here.
     */
    protected ValueAnalysis[] abstractBaseValuetypes;

    /**
     * Array of attributes.
     */
    protected AttributeAnalysis[] attributes;

    /**
     * Array of Constants.
     */
    protected ConstantAnalysis[] constants;

    /**
     * Array of operations.
     */
    protected OperationAnalysis[] operations;

    protected ContainerAnalysis(Class cls) {
        super(cls);

        if (cls == java.lang.Object.class || cls == java.io.Serializable.class || cls == java.io.Externalizable.class)
            throw IIOPLogger.ROOT_LOGGER.cannotAnalyzeSpecialClass(cls.getName());

        this.cls = cls;
    }

    protected void doAnalyze() throws RMIIIOPViolationException {
        analyzeInterfaces();
        analyzeMethods();
        analyzeFields();
        calculateClassHashCode();
        calculateRepositoryId();
        analyzeAttributes();
        analyzeConstants();
        analyzeOperations();
        fixupOverloadedOperationNames();
    }

    /**
     * Return the interfaces.
     */
    public InterfaceAnalysis[] getInterfaces() {
        return (InterfaceAnalysis[]) interfaces.clone();
    }

    /**
     * Return the abstract base valuetypes.
     */
    public ValueAnalysis[] getAbstractBaseValuetypes() {
        return (ValueAnalysis[]) abstractBaseValuetypes.clone();
    }

    /**
     * Return the attributes.
     */
    public AttributeAnalysis[] getAttributes() {
        return (AttributeAnalysis[]) attributes.clone();
    }

    /**
     * Return the constants.
     */
    public ConstantAnalysis[] getConstants() {
        return (ConstantAnalysis[]) constants.clone();
    }

    /**
     * Return the operations.
     */
    public OperationAnalysis[] getOperations() {
        return (OperationAnalysis[]) operations.clone();
    }

    /**
     * Return the repository ID.
     */
    public String getRepositoryId() {
        return repositoryId;
    }

    /**
     * Return a repository ID for a member.
     *
     * @param memberName The Java name of the member.
     */
    public String getMemberRepositoryId(String memberName) {
        return memberPrefix + escapeIRName(memberName) + memberPostfix;
    }

    /**
     * Return the fully qualified IDL module name that this
     * analysis should be placed in.
     */
    public String getIDLModuleName() {
        if (idlModuleName == null) {
            String pkgName = cls.getPackage().getName();
            StringBuffer b = new StringBuffer();

            while (!"".equals(pkgName)) {
                int idx = pkgName.indexOf('.');
                String n = (idx == -1) ? pkgName : pkgName.substring(0, idx);

                b.append("::").append(Util.javaToIDLName(n));

                pkgName = (idx == -1) ? "" : pkgName.substring(idx + 1);
            }
            idlModuleName = b.toString();
        }
        return idlModuleName;
    }

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

    /**
     * Convert an integer to a 16-digit hex string.
     */
    protected String toHexString(int i) {
        String s = Integer.toHexString(i).toUpperCase(Locale.ENGLISH);

        if (s.length() < 8)
            return "00000000".substring(0, 8 - s.length()) + s;
        else
            return s;
    }

    /**
     * Convert a long to a 16-digit hex string.
     */
    protected String toHexString(long l) {
        String s = Long.toHexString(l).toUpperCase(Locale.ENGLISH);

        if (s.length() < 16)
            return "0000000000000000".substring(0, 16 - s.length()) + s;
        else
            return s;
    }

    /**
     * Check if a method is an accessor.
     */
    protected boolean isAccessor(Method m) {
        Class returnType = m.getReturnType();
        // JBAS-4473, look for get<name>()
        String name = m.getName();
        if (!(name.startsWith("get") && name.length() > "get".length()))
            if (!(name.startsWith("is") && name.length() > "is".length())
                    || !(returnType == Boolean.TYPE))
                return false;
        if (returnType == Void.TYPE)
            return false;
        if (m.getParameterTypes().length != 0)
            return false;

        return hasNonAppExceptions(m);
    }

    /**
     * Check if a method is a mutator.
     */
    protected boolean isMutator(Method m) {
        // JBAS-4473, look for set<name>()
        String name = m.getName();
        if (!(name.startsWith("set") && name.length() > "set".length()))
            return false;
        if (m.getReturnType() != Void.TYPE)
            return false;
        if (m.getParameterTypes().length != 1)
            return false;
        return hasNonAppExceptions(m);
    }

    /**
     * Check if a method throws anything checked other than
     * java.rmi.RemoteException and its subclasses.
     */
    protected boolean hasNonAppExceptions(Method m) {
        Class[] ex = m.getExceptionTypes();

        for (int i = 0; i < ex.length; ++i)
            if (!java.rmi.RemoteException.class.isAssignableFrom(ex[i]))
                return false;
        return true;
    }

    /**
     * Analyze the fields of the class.
     * This will fill in the fields and f_flags
     * arrays.
     */
    protected void analyzeFields() {

        //fields = cls.getFields();
        fields = cls.getDeclaredFields();
        f_flags = new byte[fields.length];

        for (int i = 0; i < fields.length; ++i) {
            int mods = fields[i].getModifiers();

            if (Modifier.isFinal(mods) &&
                    Modifier.isStatic(mods) &&
                    Modifier.isPublic(mods))
                f_flags[i] |= F_CONSTANT;
        }
    }

    /**
     * Analyze the interfaces of the class.
     * This will fill in the interfaces array.
     */
    protected void analyzeInterfaces() throws RMIIIOPViolationException {

        Class[] intfs = cls.getInterfaces();
        ArrayList a = new ArrayList();
        ArrayList b = new ArrayList();

        for (int i = 0; i < intfs.length; ++i) {
            // Ignore java.rmi.Remote
            if (intfs[i] == java.rmi.Remote.class)
                continue;
            // Ignore java.io.Serializable
            if (intfs[i] == java.io.Serializable.class)
                continue;
            // Ignore java.io.Externalizable
            if (intfs[i] == java.io.Externalizable.class)
                continue;
            if (!RmiIdlUtil.isAbstractValueType(intfs[i])) {
                a.add(InterfaceAnalysis.getInterfaceAnalysis(intfs[i]));
            } else {
                b.add(ValueAnalysis.getValueAnalysis(intfs[i]));
            }
        }

        interfaces = new InterfaceAnalysis[a.size()];
        interfaces = (InterfaceAnalysis[]) a.toArray(interfaces);

        abstractBaseValuetypes = new ValueAnalysis[b.size()];
        abstractBaseValuetypes = (ValueAnalysis[]) b.toArray(abstractBaseValuetypes);
    }

    /**
     * Analyze the methods of the class.
     * This will fill in the methods and m_flags
     * arrays.
     */
    protected void analyzeMethods() {

        // The dynamic stub and skeleton strategy generation mechanism
        // requires the inclusion of inherited methods in the analysis of
        // remote interfaces. To speed things up, inherited methods are
        // not considered in the analysis of a class or non-remote interface.
        if (cls.isInterface() && java.rmi.Remote.class.isAssignableFrom(cls))
            methods = cls.getMethods();
        else
            methods = cls.getDeclaredMethods();
        m_flags = new byte[methods.length];
        mutators = new int[methods.length];

        // Find read-write properties
        for (int i = 0; i < methods.length; ++i)
            mutators[i] = -1; // no mutator here
        for (int i = 0; i < methods.length; ++i) {

            if (isAccessor(methods[i]) && (m_flags[i] & M_READ) == 0) {
                String attrName = attributeReadName(methods[i].getName());
                Class iReturn = methods[i].getReturnType();
                for (int j = i + 1; j < methods.length; ++j) {
                    if (isMutator(methods[j]) && (m_flags[j] & M_WRITE) == 0 &&
                            attrName.equals(attributeWriteName(methods[j].getName()))) {
                        Class[] jParams = methods[j].getParameterTypes();
                        if (jParams.length == 1 && jParams[0] == iReturn) {
                            m_flags[i] |= M_READ;
                            m_flags[j] |= M_WRITE;
                            mutators[i] = j;
                            break;
                        }
                    }
                }
            } else if (isMutator(methods[i]) && (m_flags[i] & M_WRITE) == 0) {
                String attrName = attributeWriteName(methods[i].getName());
                Class[] iParams = methods[i].getParameterTypes();
                for (int j = i + 1; j < methods.length; ++j) {
                    if (isAccessor(methods[j]) && (m_flags[j] & M_READ) == 0 &&
                            attrName.equals(attributeReadName(methods[j].getName()))) {
                        Class jReturn = methods[j].getReturnType();
                        if (iParams.length == 1 && iParams[0] == jReturn) {
                            m_flags[i] |= M_WRITE;
                            m_flags[j] |= M_READ;
                            mutators[j] = i;
                            break;
                        }
                    }
                }
            }
        }

        // Find read-only properties
        for (int i = 0; i < methods.length; ++i)
            if ((m_flags[i] & (M_READ | M_WRITE)) == 0 && isAccessor(methods[i]))
                m_flags[i] |= M_READONLY;

        // Check for overloaded and inherited methods
        for (int i = 0; i < methods.length; ++i) {
            if ((m_flags[i] & (M_READ | M_WRITE | M_READONLY)) == 0) {
                String iName = methods[i].getName();

                for (int j = i + 1; j < methods.length; ++j) {
                    if (iName.equals(methods[j].getName())) {
                        m_flags[i] |= M_OVERLOADED;
                        m_flags[j] |= M_OVERLOADED;
                    }
                }
            }

            if (methods[i].getDeclaringClass() != cls)
                m_flags[i] |= M_INHERITED;
        }

    }

    /**
     * Convert an attribute read method name in Java format to
     * an attribute name in Java format.
     */
    protected String attributeReadName(String name) {
        if (name.startsWith("get"))
            name = name.substring(3);
        else if (name.startsWith("is"))
            name = name.substring(2);
        else
            throw IIOPLogger.ROOT_LOGGER.notAnAccessor(name);

        return name;
    }

    /**
     * Convert an attribute write method name in Java format to
     * an attribute name in Java format.
     */
    protected String attributeWriteName(String name) {
        if (name.startsWith("set"))
            name = name.substring(3);
        else
            throw IIOPLogger.ROOT_LOGGER.notAnAccessor(name);

        return name;
    }

    /**
     * Analyse constants.
     * This will fill in the constants array.
     */
    protected void analyzeConstants()
            throws RMIIIOPViolationException {

        ArrayList a = new ArrayList();

        for (int i = 0; i < fields.length; ++i) {
            if ((f_flags[i] & F_CONSTANT) == 0)
                continue;

            Class type = fields[i].getType();

            // Only map primitives and java.lang.String
            if (!type.isPrimitive() && type != java.lang.String.class) {
                // It is an RMI/IIOP violation for interfaces.
                if (cls.isInterface())
                    throw IIOPLogger.ROOT_LOGGER.badRMIIIOPConstantType(fields[i].getName(), cls.getName(), "1.2.3");
                continue;
            }

            String name = fields[i].getName();

            Object value;
            try {
                value = fields[i].get(null);
            } catch (Exception ex) {
                throw new RuntimeException(ex.toString());
            }

            a.add(new ConstantAnalysis(name, type, value));
        }

        constants = new ConstantAnalysis[a.size()];
        constants = (ConstantAnalysis[]) a.toArray(constants);
    }

    /**
     * Analyse attributes.
     * This will fill in the attributes array.
     */
    protected void analyzeAttributes() throws RMIIIOPViolationException {
        ArrayList a = new ArrayList();

        for (int i = 0; i < methods.length; ++i) {
            //if ((m_flags[i]&M_INHERITED) != 0)
            //  continue;

            if ((m_flags[i] & (M_READ | M_READONLY)) != 0) {
                // Read method of an attribute.
                String name = attributeReadName(methods[i].getName());

                if ((m_flags[i] & M_READONLY) != 0)
                    a.add(new AttributeAnalysis(name, methods[i]));
                else
                    a.add(new AttributeAnalysis(name, methods[i],
                            methods[mutators[i]]));
            }
        }

        attributes = new AttributeAnalysis[a.size()];
        attributes = (AttributeAnalysis[]) a.toArray(attributes);

    }

    /**
     * Analyse operations.
     * This will fill in the operations array.
     * This implementation just creates an empty array; override
     * in subclasses for a real analysis.
     */
    protected void analyzeOperations()
            throws RMIIIOPViolationException {
        operations = new OperationAnalysis[0];
    }

    /**
     * Fixup overloaded operation names.
     * As specified in section 1.3.2.6.
     */
    protected void fixupOverloadedOperationNames()
            throws RMIIIOPViolationException {
        for (int i = 0; i < methods.length; ++i) {
            if ((m_flags[i] & M_OVERLOADED) == 0)
                continue;

            // Find the operation
            OperationAnalysis oa = null;
            String javaName = methods[i].getName();
            for (int opIdx = 0; oa == null && opIdx < operations.length; ++opIdx)
                if (operations[opIdx].getMethod().equals(methods[i]))
                    oa = operations[opIdx];

            if (oa == null)
                continue; // This method is not mapped.

            // Calculate new IDL name
            ParameterAnalysis[] params = oa.getParameters();
            StringBuffer b = new StringBuffer(oa.getIDLName());
            if (params.length == 0)
                b.append("__");
            for (int j = 0; j < params.length; ++j) {
                String s = params[j].getTypeIDLName();

                if (s.startsWith("::"))
                    s = s.substring(2);

                if (s.startsWith("_")) {
                    // remove leading underscore in IDL escaped identifier
                    s = s.substring(1);
                }

                b.append('_');

                while (!"".equals(s)) {
                    int idx = s.indexOf("::");

                    b.append('_');

                    if (idx == -1) {
                        b.append(s);
                        s = "";
                    } else {
                        b.append(s.substring(0, idx));
                        if (s.length() > idx + 2 && s.charAt(idx + 2) == '_') {
                            // remove leading underscore in IDL escaped identifier
                            s = s.substring(idx + 3);
                        } else {
                            s = s.substring(idx + 2);
                        }
                    }
                }
            }

            // Set new IDL name
            oa.setIDLName(b.toString());
        }
    }

    /**
     * Fixup names differing only in case.
     * As specified in section 1.3.2.7.
     */
    protected void fixupCaseNames()
            throws RMIIIOPViolationException {
        ArrayList entries = getContainedEntries();
        boolean[] clash = new boolean[entries.size()];
        String[] upperNames = new String[entries.size()];

        for (int i = 0; i < entries.size(); ++i) {
            AbstractAnalysis aa = (AbstractAnalysis) entries.get(i);

            clash[i] = false;
            upperNames[i] = aa.getIDLName().toUpperCase(Locale.ENGLISH);

            for (int j = 0; j < i; ++j) {
                if (upperNames[i].equals(upperNames[j])) {
                    clash[i] = true;
                    clash[j] = true;
                }
            }
        }

        for (int i = 0; i < entries.size(); ++i) {
            if (!clash[i])
                continue;

            AbstractAnalysis aa = (AbstractAnalysis) entries.get(i);
            boolean noUpper = true;
            String name = aa.getIDLName();
            StringBuffer b = new StringBuffer(name);
            b.append('_');
            for (int j = 0; j < name.length(); ++j) {
                if (!Character.isUpperCase(name.charAt(j)))
                    continue;
                if (noUpper)
                    noUpper = false;
                else
                    b.append('_');
                b.append(j);
            }

            aa.setIDLName(b.toString());
        }
    }

    /**
     * Return a list of all the entries contained here.
     *
     */
    protected abstract ArrayList getContainedEntries();

    /**
     * Return the class hash code, as specified in "The Common Object
     * Request Broker: Architecture and Specification" (01-02-33),
     * section 10.6.2.
     */
    protected void calculateClassHashCode() {
        // The simple cases
        if (cls.isInterface())
            classHashCode = 0;
        else if (!Serializable.class.isAssignableFrom(cls))
            classHashCode = 0;
        else if (Externalizable.class.isAssignableFrom(cls))
            classHashCode = 1;
        else // Go ask Util class for the hash code
            classHashCode = Util.getClassHashCode(cls);
    }

    /**
     * Escape non-ISO characters for an IR name.
     */
    protected String escapeIRName(String name) {
        StringBuffer b = new StringBuffer();

        for (int i = 0; i < name.length(); ++i) {
            char c = name.charAt(i);

            if (c < 256)
                b.append(c);
            else
                b.append("\\U").append(toHexString((int) c));
        }
        return b.toString();
    }

    /**
     * Return the IR global ID of the given class or interface.
     * This is described in section 1.3.5.7.
     * The returned string is in the RMI hashed format, like
     * "RMI:java.util.Hashtable:C03324C0EA357270:13BB0F25214AE4B8".
     */
    protected void calculateRepositoryId() {
        if (cls.isArray() || cls.isPrimitive())
            throw IIOPLogger.ROOT_LOGGER.notAnClassOrInterface(cls.getName());

        if (cls.isInterface() &&
                org.omg.CORBA.Object.class.isAssignableFrom(cls) &&
                org.omg.CORBA.portable.IDLEntity.class.isAssignableFrom(cls)) {

            StringBuffer b = new StringBuffer("IDL:");
            b.append(cls.getPackage().getName().replace('.', '/'));
            b.append('/');
            String base = cls.getName();
            base = base.substring(base.lastIndexOf('.') + 1);
            b.append(base).append(":1.0");
            repositoryId = b.toString();
        } else {
            StringBuffer b = new StringBuffer("RMI:");
            b.append(escapeIRName(cls.getName()));
            memberPrefix = b.toString() + ".";
            String hashStr = toHexString(classHashCode);
            b.append(':').append(hashStr);
            ObjectStreamClass osClass = ObjectStreamClass.lookup(cls);
            if (osClass != null) {
                long serialVersionUID = osClass.getSerialVersionUID();
                String SVUID = toHexString(serialVersionUID);

                if (classHashCode != serialVersionUID)
                    b.append(':').append(SVUID);
                memberPostfix = ":" + hashStr + ":" + SVUID;
            } else
                memberPostfix = ":" + hashStr;

            repositoryId = b.toString();
        }
    }
}


/*
 * JBoss, Home of Professional Open Source.
 * Copyright 2012, 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.xts;

import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.ADD;
import static org.jboss.as.xts.XTSSubsystemDefinition.DEFAULT_CONTEXT_PROPAGATION;
import static org.jboss.as.xts.XTSSubsystemDefinition.ASYNC_REGISTRATION;
import static org.jboss.as.xts.XTSSubsystemDefinition.ENVIRONMENT_URL;
import static org.jboss.as.xts.XTSSubsystemDefinition.HOST_NAME;

import java.util.ArrayList;
import java.util.EnumSet;
import java.util.List;

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

import org.jboss.as.controller.PathAddress;
import org.jboss.as.controller.operations.common.Util;
import org.jboss.as.controller.parsing.ParseUtils;
import org.jboss.as.controller.persistence.SubsystemMarshallingContext;
import org.jboss.dmr.ModelNode;
import org.jboss.staxmapper.XMLElementReader;
import org.jboss.staxmapper.XMLElementWriter;
import org.jboss.staxmapper.XMLExtendedStreamReader;
import org.jboss.staxmapper.XMLExtendedStreamWriter;

/**
 * @author Andrew Dinn
 * @author Tomaz Cerar
 */
class XTSSubsystemParser implements XMLStreamConstants, XMLElementReader<List<ModelNode>>, XMLElementWriter<SubsystemMarshallingContext> {

    /**
     * {@inheritDoc}
     */
    @Override
    public void readElement(XMLExtendedStreamReader reader, List<ModelNode> list) throws XMLStreamException {
        // no attributes
        if (reader.getAttributeCount() > 0) {
            throw ParseUtils.unexpectedAttribute(reader, 0);
        }

        final ModelNode subsystem = Util.getEmptyOperation(ADD, PathAddress.pathAddress(XTSExtension.SUBSYSTEM_PATH)
                .toModelNode());
        list.add(subsystem);

        final EnumSet<Element> encountered = EnumSet.noneOf(Element.class);
        final List<Element> expected = getExpectedElements(reader);

        while (reader.hasNext() && reader.nextTag() != END_ELEMENT) {
            final Element element = Element.forName(reader.getLocalName());

            if (!expected.contains(element) || !encountered.add(element)) {
                throw ParseUtils.unexpectedElement(reader);
            }

            switch (element) {
                case HOST: {
                    parseHostElement(reader, subsystem);
                    break;
                }
                case XTS_ENVIRONMENT: {
                    parseXTSEnvironmentElement(reader,subsystem);
                    break;
                }
                case DEFAULT_CONTEXT_PROPAGATION: {
                    parseDefaultContextPropagationElement(reader, subsystem);
                    break;
                }
                case ASYNC_REGISTRATION: {
                    parseAsyncRegistrationElement(reader, subsystem);
                    break;
                }
                default: {
                    throw ParseUtils.unexpectedElement(reader);
                }
            }
        }
    }

    /**
     * {@inheritDoc}          XMLExtendedStreamReader reader
     */
    @Override
    public void writeContent(XMLExtendedStreamWriter writer, SubsystemMarshallingContext context) throws XMLStreamException {
        context.startSubsystemElement(Namespace.CURRENT.getUriString(), false);
        ModelNode node = context.getModelNode();

        if (node.hasDefined(HOST_NAME.getName())) {
            writer.writeStartElement(Element.HOST.getLocalName());
            HOST_NAME.marshallAsAttribute(node, writer);
            writer.writeEndElement();
        }

        if (node.hasDefined(ENVIRONMENT_URL.getName())) {
            writer.writeStartElement(Element.XTS_ENVIRONMENT.getLocalName());
            ENVIRONMENT_URL.marshallAsAttribute(node, writer);
            writer.writeEndElement();
        }

        if (node.hasDefined(DEFAULT_CONTEXT_PROPAGATION.getName())) {
            writer.writeStartElement(Element.DEFAULT_CONTEXT_PROPAGATION.getLocalName());
            DEFAULT_CONTEXT_PROPAGATION.marshallAsAttribute(node, writer);
            writer.writeEndElement();
        }

        if (node.hasDefined(ASYNC_REGISTRATION.getName())) {
            writer.writeStartElement(Element.ASYNC_REGISTRATION.getLocalName());
            ASYNC_REGISTRATION.marshallAsAttribute(node, writer);
            writer.writeEndElement();
        }

        writer.writeEndElement();
    }

    private void parseHostElement(XMLExtendedStreamReader reader, ModelNode subsystem) throws XMLStreamException {
        final EnumSet<Attribute> required = EnumSet.of(Attribute.NAME);
        processAttributes(reader, (index, attribute) -> {
            required.remove(attribute);
            final String value = reader.getAttributeValue(index);
            switch (attribute) {
                case NAME:
                    HOST_NAME.parseAndSetParameter(value, subsystem, reader);
                    break;
                default:
                    throw ParseUtils.unexpectedAttribute(reader, index);
            }
        });
        // Handle elements
        ParseUtils.requireNoContent(reader);

        if (!required.isEmpty()) {
            throw ParseUtils.missingRequired(reader, required);
        }
    }

    /**
     * Handle the xts-environment element
     *
     *
     * @param reader
     * @param subsystem
     * @return ModelNode for the core-environment
     * @throws javax.xml.stream.XMLStreamException
     *
     */
    private void parseXTSEnvironmentElement(XMLExtendedStreamReader reader, ModelNode subsystem) throws XMLStreamException {
        processAttributes(reader, (index, attribute) -> {
            final String value = reader.getAttributeValue(index);
            switch (attribute) {
                case URL:
                    ENVIRONMENT_URL.parseAndSetParameter(value, subsystem, reader);
                    break;
                default:
                    throw ParseUtils.unexpectedAttribute(reader, index);
            }
        });
        // Handle elements
        ParseUtils.requireNoContent(reader);
    }

    /**
     * Handle the enable-client-handler element.
     *
     * @param reader
     * @param subsystem
     * @throws XMLStreamException
     */
    private void parseDefaultContextPropagationElement(XMLExtendedStreamReader reader, ModelNode subsystem) throws XMLStreamException {
        processAttributes(reader, (index, attribute) -> {
            final String value = reader.getAttributeValue(index);
            switch (attribute) {
                case ENABLED:
                    if (value == null || (!value.toLowerCase().equals("true") && !value.toLowerCase().equals("false"))) {
                        throw ParseUtils.invalidAttributeValue(reader, index);
                    }
                    DEFAULT_CONTEXT_PROPAGATION.parseAndSetParameter(value, subsystem, reader);
                    break;
                default:
                    throw ParseUtils.unexpectedAttribute(reader, index);
            }
        });

        // Handle elements
        ParseUtils.requireNoContent(reader);
    }

    /**
     * Handle the async-registration element.
     */
    private void parseAsyncRegistrationElement(XMLExtendedStreamReader reader, ModelNode subsystem) throws XMLStreamException {
        processAttributes(reader, (index, attribute) -> {
            final String value = reader.getAttributeValue(index);
            switch (attribute) {
                case ENABLED:
                    if (value == null || (!value.toLowerCase().equals("true") && !value.toLowerCase().equals("false"))) {
                        throw ParseUtils.invalidAttributeValue(reader, index);
                    }
                    ASYNC_REGISTRATION.parseAndSetParameter(value, subsystem, reader);
                    break;
                default:
                    throw ParseUtils.unexpectedAttribute(reader, index);
            }
        });

        // Handle elements
        ParseUtils.requireNoContent(reader);
    }

    private List<Element> getExpectedElements(final XMLExtendedStreamReader reader) {
        final Namespace namespace = Namespace.forUri(reader.getNamespaceURI());
        final List<Element> elements = new ArrayList<>();

        if (Namespace.XTS_1_0.equals(namespace)) {
            elements.add(Element.XTS_ENVIRONMENT);
        } else if (Namespace.XTS_2_0.equals(namespace)) {
            elements.add(Element.XTS_ENVIRONMENT);
            elements.add(Element.HOST);
            elements.add(Element.DEFAULT_CONTEXT_PROPAGATION);
        } else if (Namespace.XTS_3_0.equals(namespace)) {
            elements.add(Element.XTS_ENVIRONMENT);
            elements.add(Element.HOST);
            elements.add(Element.DEFAULT_CONTEXT_PROPAGATION);
            elements.add(Element.ASYNC_REGISTRATION);
        }

        return elements;
    }

    /**
     * Functional interface to provide similar functionality as {@link BiConsumer}
     * but with cought exception {@link XMLStreamException} declared.
     */
    @FunctionalInterface
    private interface AttributeProcessor<T, R> {
        void process(T t, R r) throws XMLStreamException;
    }

    /**
     * Iterating over all attributes got from the reader parameter.
     *
     * @param reader  reading the parameters from
     * @param attributeProcessorCallback  callback being processed for each attribute
     * @throws XMLStreamException troubles parsing xml
     */
    private void processAttributes(final XMLExtendedStreamReader reader, AttributeProcessor<Integer, Attribute> attributeProcessorCallback) throws XMLStreamException {
        final int count = reader.getAttributeCount();
        for (int i = 0; i < count; i++) {
            ParseUtils.requireNoNamespaceAttribute(reader, i);
            // final String value = reader.getAttributeValue(i);
            final Attribute attribute = Attribute.forName(reader.getAttributeLocalName(i));
            attributeProcessorCallback.process(i, attribute);
        }
    }
}


/*
 * JBoss, Home of Professional Open Source.
 * Copyright 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.jpa.persistenceprovider;

import java.util.ArrayList;
import java.util.List;
import java.util.ServiceLoader;

import javax.persistence.spi.PersistenceProvider;

import org.jboss.as.jpa.config.Configuration;
import org.jboss.modules.Module;
import org.jboss.modules.ModuleIdentifier;
import org.jboss.modules.ModuleLoadException;
import org.jboss.modules.ModuleLoader;

/**
 * For loading persistence provider modules
 *
 * @author Scott Marlow
 */
public class PersistenceProviderLoader {

    /**
     * pre-loads the default persistence provider
     *
     * @throws ModuleLoadException
     */
    public static void loadDefaultProvider() throws ModuleLoadException {
        String defaultProviderModule = Configuration.getDefaultProviderModuleName();
        loadProviderModuleByName(defaultProviderModule);
    }

    /**
     * Loads the specified JPA persistence provider module
     *
     * @param moduleName is the static module to be loaded
     * @throws ModuleLoadException
     * @return list of persistence providers in specified module
     *
     * Note: side effect of saving loaded persistence providers to static api in javax.persistence.spi.PersistenceProvider.
     */
    public static List<PersistenceProvider> loadProviderModuleByName(String moduleName) throws ModuleLoadException {
        final ModuleLoader moduleLoader = Module.getBootModuleLoader();
        Module module = moduleLoader.loadModule(ModuleIdentifier.fromString(moduleName));
        final ServiceLoader<PersistenceProvider> serviceLoader =
            module.loadService(PersistenceProvider.class);
        List<PersistenceProvider> result = new ArrayList<>();
        if (serviceLoader != null) {
            for (PersistenceProvider provider1 : serviceLoader) {
                // persistence provider jar may contain multiple provider service implementations
                // save each provider
                PersistenceProviderResolverImpl.getInstance().addPersistenceProvider(provider1);
                result.add(provider1);
            }
        }
        return result;
    }

    public static PersistenceProvider loadProviderFromDeployment(ClassLoader classLoader, String persistenceProviderClassName) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
        return (PersistenceProvider) classLoader.loadClass(persistenceProviderClassName).newInstance();
    }
}