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

import java.util.List;

import org.jboss.as.ee.component.EEApplicationClasses;
import org.jboss.as.ee.component.EEModuleClassDescription;
import org.jboss.as.ee.metadata.ClassAnnotationInformation;
import org.jboss.as.ejb3.component.messagedriven.MessageDrivenComponentDescription;
import org.jboss.as.ejb3.deployment.EjbDeploymentAttachmentKeys;
import org.jboss.as.ejb3.logging.EjbLogger;
import org.jboss.as.ejb3.resourceadapterbinding.metadata.EJBBoundResourceAdapterBindingMetaData;
import org.jboss.as.server.deployment.DeploymentUnit;
import org.jboss.as.server.deployment.DeploymentUnitProcessingException;
import org.jboss.as.server.deployment.reflect.DeploymentReflectionIndex;
import org.jboss.ejb3.annotation.ResourceAdapter;
import org.jboss.metadata.ejb.spec.AssemblyDescriptorMetaData;
import org.jboss.metadata.ejb.spec.EjbJarMetaData;

/**
 * Handles the {@link org.jboss.ejb3.annotation.ResourceAdapter} annotation merging
 *
 * @author Stuart DouglasrunAs
 */
public class ResourceAdaptorMergingProcessor extends AbstractMergingProcessor<MessageDrivenComponentDescription> {

    public ResourceAdaptorMergingProcessor() {
        super(MessageDrivenComponentDescription.class);
    }

    @Override
    protected void handleAnnotations(final DeploymentUnit deploymentUnit, final EEApplicationClasses applicationClasses, final DeploymentReflectionIndex deploymentReflectionIndex, final Class<?> componentClass, final MessageDrivenComponentDescription componentConfiguration) throws DeploymentUnitProcessingException {

        final EEModuleClassDescription clazz = applicationClasses.getClassByName(componentClass.getName());

        //we only care about annotations on the bean class itself
        if (clazz == null) {
            return;
        }
        final ClassAnnotationInformation<ResourceAdapter, String> resourceAdapter = clazz.getAnnotationInformation(ResourceAdapter.class);
        if (resourceAdapter == null || resourceAdapter.getClassLevelAnnotations().isEmpty()) {
            return;
        }

        final String configuredAdapterName = resourceAdapter.getClassLevelAnnotations().get(0);
        final String adapterName = addEarPrefixIfRelativeName(configuredAdapterName, deploymentUnit, componentClass);

        componentConfiguration.setResourceAdapterName(adapterName);
    }

    @Override
    protected void handleDeploymentDescriptor(final DeploymentUnit deploymentUnit, final DeploymentReflectionIndex deploymentReflectionIndex, final Class<?> componentClass, final MessageDrivenComponentDescription componentConfiguration) throws DeploymentUnitProcessingException {

        final String ejbName = componentConfiguration.getEJBName();
        final EjbJarMetaData metaData = deploymentUnit.getAttachment(EjbDeploymentAttachmentKeys.EJB_JAR_METADATA);
        if (metaData == null) {
            return;
        }
        final AssemblyDescriptorMetaData assemblyDescriptor = metaData.getAssemblyDescriptor();
        if (assemblyDescriptor == null) {
            return;
        }
        final List<EJBBoundResourceAdapterBindingMetaData> resourceAdapterBindingDataList = assemblyDescriptor.getAny(EJBBoundResourceAdapterBindingMetaData.class);

        String configuredAdapterName = null;
        if (resourceAdapterBindingDataList != null) {
            for (EJBBoundResourceAdapterBindingMetaData resourceAdapterBindingData: resourceAdapterBindingDataList) {
                if ("*".equals(resourceAdapterBindingData.getEjbName()) && configuredAdapterName == null) {
                    configuredAdapterName = resourceAdapterBindingData.getResourceAdapterName();
                } else if (ejbName.equals(resourceAdapterBindingData.getEjbName())) {
                    configuredAdapterName = resourceAdapterBindingData.getResourceAdapterName();
                }
            }
        }
        if (configuredAdapterName != null) {
            final String adapterName = addEarPrefixIfRelativeName(configuredAdapterName,deploymentUnit,componentClass);
            componentConfiguration.setResourceAdapterName(adapterName);
        }
    }

    // adds ear prefix to configured adapter name if it is specified in relative form
    private String addEarPrefixIfRelativeName(final String configuredName, final DeploymentUnit deploymentUnit,
            final Class<?> componentClass) throws DeploymentUnitProcessingException {
        if (!configuredName.startsWith("#")) {
            return configuredName;
        }
        final DeploymentUnit parent = deploymentUnit.getParent();
        if (parent == null) {
            throw EjbLogger.ROOT_LOGGER.relativeResourceAdapterNameInStandaloneModule(deploymentUnit.getName(),
                    componentClass.getName(), configuredName);
        }
        return new StringBuilder().append(parent.getName()).append(configuredName).toString();
    }
}


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

import java.util.Map;

import org.jboss.as.ee.component.Attachments;
import org.jboss.as.ee.component.EEApplicationClasses;
import org.jboss.as.ee.component.EEModuleDescription;
import org.jboss.as.server.deployment.DeploymentUnit;
import org.jboss.as.server.deployment.module.ResourceRoot;
import org.jboss.as.web.common.WebComponentDescription;

/**
 * Various utilities for working with WildFly APIs
 *
 * @author Jozef Hartinger
 *
 */
public class Utils {

    private Utils() {
    }

    public static boolean isClassesRoot(ResourceRoot resourceRoot) {
        return "classes".equals(resourceRoot.getRootName());
    }

    /**
     * Returns the parent of the given deployment unit if such a parent exists. If the given deployment unit is the parent
     * deployment unit, it is returned.
     */
    public static DeploymentUnit getRootDeploymentUnit(DeploymentUnit deploymentUnit) {
        if (deploymentUnit.getParent() == null) {
            return deploymentUnit;
        }
        return deploymentUnit.getParent();
    }

    public static String getDeploymentUnitId(DeploymentUnit deploymentUnit) {
        String id = deploymentUnit.getName();
        if (deploymentUnit.getParent() != null) {
            id = deploymentUnit.getParent().getName() + "/" + id;
        }
        return id;
    }

    public static void registerAsComponent(String listener, DeploymentUnit deploymentUnit) {
        final EEApplicationClasses applicationClasses = deploymentUnit.getAttachment(Attachments.EE_APPLICATION_CLASSES_DESCRIPTION);
        final EEModuleDescription module = deploymentUnit.getAttachment(Attachments.EE_MODULE_DESCRIPTION);
        final WebComponentDescription componentDescription = new WebComponentDescription(listener, listener, module, deploymentUnit.getServiceName(),
                applicationClasses);
        module.addComponent(componentDescription);
        deploymentUnit.addToAttachmentList(WebComponentDescription.WEB_COMPONENTS, componentDescription.getStartServiceName());
    }

    public static <K, V> void putIfValueNotNull(Map<K, V> map, K key, V value) {
        if (value != null) {
            map.put(key, value);
        }
    }
}


/*
 * 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.ee.component;

import java.lang.reflect.Method;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Deque;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.jboss.as.ee.component.interceptors.ComponentDispatcherInterceptor;
import org.jboss.as.ee.component.interceptors.InterceptorOrder;
import org.jboss.as.server.deployment.DeploymentPhaseContext;
import org.jboss.as.server.deployment.DeploymentUnitProcessingException;
import org.jboss.as.server.deployment.reflect.ClassReflectionIndex;
import org.jboss.as.server.deployment.reflect.ClassReflectionIndexUtil;
import org.jboss.as.server.deployment.reflect.DeploymentReflectionIndex;
import org.jboss.invocation.ImmediateInterceptorFactory;
import org.jboss.invocation.Interceptor;
import org.jboss.invocation.InterceptorContext;
import org.jboss.invocation.Interceptors;
import org.jboss.invocation.proxy.MethodIdentifier;
import org.jboss.invocation.proxy.ProxyFactory;
import org.jboss.msc.service.ServiceName;
import org.jboss.msc.value.Value;
import org.jboss.msc.value.Values;

import static java.lang.reflect.Modifier.ABSTRACT;
import static java.lang.reflect.Modifier.PUBLIC;
import static java.lang.reflect.Modifier.STATIC;
import static org.jboss.as.server.deployment.Attachments.REFLECTION_INDEX;

/**
 * A description of a view.
 *
 * @author David M. Lloyd
 */
public class ViewDescription {

    //JVM bridge method flag
    public static final int BRIDGE = 0x0040;

    private final String viewClassName;
    private final ComponentDescription componentDescription;
    private final List<String> viewNameParts = new ArrayList<String>();
    private final Set<String> bindingNames = new HashSet<String>();
    private final Deque<ViewConfigurator> configurators = new ArrayDeque<ViewConfigurator>();
    private boolean serializable;
    private boolean useWriteReplace;

    /**
     * Construct a new instance.
     *
     * @param componentDescription the associated component description
     * @param viewClassName        the view class name
     */
    public ViewDescription(final ComponentDescription componentDescription, final String viewClassName) {
        this(componentDescription, viewClassName, true);
    }

    /**
     * Construct a new instance.
     *
     * @param componentDescription        the associated component description
     * @param viewClassName               the view class name
     * @param defaultConfiguratorRequired
     */
    public ViewDescription(final ComponentDescription componentDescription, final String viewClassName, final boolean defaultConfiguratorRequired) {
        this.componentDescription = componentDescription;
        this.viewClassName = viewClassName;
        if (defaultConfiguratorRequired) {
            configurators.addFirst(DefaultConfigurator.INSTANCE);
        }
        configurators.addFirst(ViewBindingConfigurator.INSTANCE);
    }

    /**
     * Get the view's class name.
     *
     * @return the class name
     */
    public String getViewClassName() {
        return viewClassName;
    }

    /**
     * Get the associated component description.
     *
     * @return the component description
     */
    public ComponentDescription getComponentDescription() {
        return componentDescription;
    }

    /**
     * Get the strings to append to the view base name.  The view base name is the component base name
     * followed by {@code "VIEW"} followed by these strings.
     *
     * @return the list of strings
     */
    public List<String> getViewNameParts() {
        return viewNameParts;
    }

    /**
     * Get the service name for this view.
     *
     * @return the service name
     */
    public ServiceName getServiceName() {
        //TODO: need to set viewNameParts somewhere
        if (!viewNameParts.isEmpty()) {
            return componentDescription.getServiceName().append("VIEW").append(viewNameParts.toArray(new String[viewNameParts.size()]));
        } else {
            return componentDescription.getServiceName().append("VIEW").append(viewClassName);
        }
    }

    /**
     * Creates view configuration. Allows for extensibility in EE sub components.
     *
     * @param viewClass              view class
     * @param componentConfiguration component config
     * @param proxyFactory           proxy factory
     * @return new view configuration
     */
    public ViewConfiguration createViewConfiguration(final Class<?> viewClass, final ComponentConfiguration componentConfiguration, final ProxyFactory<?> proxyFactory) {
        return new ViewConfiguration(viewClass, componentConfiguration, getServiceName(), proxyFactory);
    }

    /**
     * Get the set of binding names for this view.
     *
     * @return the set of binding names
     */
    public Set<String> getBindingNames() {
        return bindingNames;
    }

    /**
     * Get the configurators for this view.
     *
     * @return the configurators
     */
    public Deque<ViewConfigurator> getConfigurators() {
        return configurators;
    }

    /**
     * Create the injection source
     *
     * @param serviceName     The view service name
     * @param viewClassLoader
     */
    protected InjectionSource createInjectionSource(final ServiceName serviceName, Value<ClassLoader> viewClassLoader, boolean appclient) {
        return new ViewBindingInjectionSource(serviceName);
    }

    public static final ImmediateInterceptorFactory CLIENT_DISPATCHER_INTERCEPTOR_FACTORY = new ImmediateInterceptorFactory(new Interceptor() {
        public Object processInvocation(final InterceptorContext context) throws Exception {
            ComponentView view = context.getPrivateData(ComponentView.class);
            return view.invoke(context);
        }
    });

    private static class DefaultConfigurator implements ViewConfigurator {

        public static final DefaultConfigurator INSTANCE = new DefaultConfigurator();

        public void configure(final DeploymentPhaseContext context, final ComponentConfiguration componentConfiguration, final ViewDescription description, final ViewConfiguration configuration) throws DeploymentUnitProcessingException {
            // Create method indexes
            final DeploymentReflectionIndex reflectionIndex = context.getDeploymentUnit().getAttachment(REFLECTION_INDEX);
            final List<Method> methods = configuration.getProxyFactory().getCachedMethods();
            for (final Method method : methods) {
                MethodIdentifier methodIdentifier = MethodIdentifier.getIdentifierForMethod(method);
                Method componentMethod = ClassReflectionIndexUtil.findMethod(reflectionIndex, componentConfiguration.getComponentClass(), methodIdentifier);

                if (componentMethod == null && method.getDeclaringClass().isInterface() && (method.getModifiers() & (ABSTRACT | PUBLIC | STATIC)) == PUBLIC) {
                    // no component method and the interface method is defaulted, so we really do want to invoke on the interface method
                    componentMethod = method;
                }
                if (componentMethod != null) {

                    if ((BRIDGE & componentMethod.getModifiers()) != 0) {
                        Method other = findRealMethodForBridgeMethod(componentMethod, componentConfiguration, reflectionIndex, methodIdentifier);
                        //try and find the non-bridge method to delegate to
                        if(other != null) {
                                componentMethod = other;
                        }
                    }

                    configuration.addViewInterceptor(method, new ImmediateInterceptorFactory(new ComponentDispatcherInterceptor(componentMethod)), InterceptorOrder.View.COMPONENT_DISPATCHER);
                    configuration.addClientInterceptor(method, CLIENT_DISPATCHER_INTERCEPTOR_FACTORY, InterceptorOrder.Client.CLIENT_DISPATCHER);
                    configuration.getViewToComponentMethodMap().put(method, componentMethod);
                }
            }

            configuration.addClientPostConstructInterceptor(Interceptors.getTerminalInterceptorFactory(), InterceptorOrder.ClientPostConstruct.TERMINAL_INTERCEPTOR);
            configuration.addClientPreDestroyInterceptor(Interceptors.getTerminalInterceptorFactory(), InterceptorOrder.ClientPreDestroy.TERMINAL_INTERCEPTOR);
        }

        private Method findRealMethodForBridgeMethod(final Method componentMethod, final ComponentConfiguration componentConfiguration, final DeploymentReflectionIndex reflectionIndex, final MethodIdentifier methodIdentifier) {
            final ClassReflectionIndex classIndex = reflectionIndex.getClassIndex(componentMethod.getDeclaringClass()); //the non-bridge method will be on the same class as the bridge method
            final Collection<Method> methods = classIndex.getAllMethods(componentMethod.getName(), componentMethod.getParameterTypes().length);
            for(final Method method : methods) {
                if ((BRIDGE & method.getModifiers()) == 0) {
                    if(componentMethod.getReturnType().isAssignableFrom(method.getReturnType())) {
                        boolean ok = true;
                        for(int i = 0; i < method.getParameterTypes().length; ++i) {
                            if(!componentMethod.getParameterTypes()[i].isAssignableFrom(method.getParameterTypes()[i])) {
                                ok = false;
                                break;
                            }
                        }
                        if(ok) {
                            return method;
                        }
                    }
                }
            }
            return null;
        }
    }

    private static class ViewBindingConfigurator implements ViewConfigurator {

        public static final ViewBindingConfigurator INSTANCE = new ViewBindingConfigurator();

        @Override
        public void configure(final DeploymentPhaseContext context, final ComponentConfiguration componentConfiguration, final ViewDescription description, final ViewConfiguration configuration) throws DeploymentUnitProcessingException {
            boolean appclient = context.getDeploymentUnit().getAttachment(Attachments.EE_MODULE_DESCRIPTION).isAppClient();
            // Create view bindings
            final List<BindingConfiguration> bindingConfigurations = configuration.getBindingConfigurations();
            for (String bindingName : description.getBindingNames()) {
                bindingConfigurations.add(new BindingConfiguration(bindingName, description.createInjectionSource(description.getServiceName(), Values.immediateValue(componentConfiguration.getModuleClassLoader()), appclient)));
            }
        }
    }

    public boolean isSerializable() {
        return serializable;
    }

    public void setSerializable(final boolean serializable) {
        this.serializable = serializable;
    }

    public boolean isUseWriteReplace() {
        return useWriteReplace;
    }

    public void setUseWriteReplace(final boolean useWriteReplace) {
        this.useWriteReplace = useWriteReplace;
    }

    @Override
    public String toString() {
        return "View of type " + viewClassName + " for " + componentDescription;
    }

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

        final ViewDescription that = (ViewDescription) o;

        //compare the component description based on ==
        if (componentDescription != that.componentDescription)
            return false;
        if (viewClassName != null ? !viewClassName.equals(that.viewClassName) : that.viewClassName != null)
            return false;

        return true;
    }

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


/*
 * 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.DefinitionKind;
import org.omg.CORBA.IDLType;
import org.omg.CORBA.IDLTypeHelper;
import org.omg.CORBA.IRObject;
import org.omg.CORBA.SequenceDef;
import org.omg.CORBA.SequenceDefOperations;
import org.omg.CORBA.SequenceDefPOATie;
import org.omg.CORBA.TypeCode;
import org.omg.CORBA.TypeCodePackage.BadKind;
import org.wildfly.iiop.openjdk.logging.IIOPLogger;

/**
 * SequenceDef IR object.
 *
 * @author Ole Husgaard
 * @version $Revision: 81018 $
 */
class SequenceDefImpl
        extends IDLTypeImpl
        implements SequenceDefOperations {
    // Constants -----------------------------------------------------

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

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

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

    SequenceDefImpl(TypeCode typeCode, RepositoryImpl repository) {
        super(typeCode, DefinitionKind.dk_Sequence, repository);
    }

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

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

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

    public void allDone()
            throws IRConstructionException {
        // Get my element type definition: It should have been created now.
        try {
            element_type_def = IDLTypeImpl.getIDLType(type().content_type(),
                    repository);
        } catch (BadKind ex) {
            throw IIOPLogger.ROOT_LOGGER.badKindForTypeCode(type().kind().value());
        }

        getReference();
    }

    // SequenceDefOperations implementation --------------------------

    public int bound() {
        try {
            return type().length();
        } catch (BadKind ex) {
            // should never happen
            throw new RuntimeException();
        }
    }

    public void bound(int arg) {
        throw IIOPLogger.ROOT_LOGGER.cannotChangeRMIIIOPMapping();
    }

    public TypeCode element_type() {
        try {
            return type().content_type();
        } catch (BadKind ex) {
            // should never happen
            throw new RuntimeException();
        }
    }

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

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

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

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

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

    /**
     * My element type.
     */
    private LocalIDLType element_type_def;
}


/*
 * 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.ee.component;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.IdentityHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.jboss.as.ee.component.interceptors.OrderedItemContainer;
import org.jboss.invocation.InterceptorFactory;
import org.jboss.invocation.proxy.ProxyFactory;
import org.jboss.msc.service.ServiceName;

/**
 * A configuration of a component view.
 *
 * @author David M. Lloyd
 * @author Stuart Douglas
 */
public class ViewConfiguration {
    private final ComponentConfiguration componentConfiguration;
    private final ServiceName viewServiceName;
    private final Map<Method, OrderedItemContainer<InterceptorFactory>> viewInterceptors = new IdentityHashMap<Method, OrderedItemContainer<InterceptorFactory>>();
    private final Map<Method, OrderedItemContainer<InterceptorFactory>> clientInterceptors = new IdentityHashMap<Method, OrderedItemContainer<InterceptorFactory>>();
    private final OrderedItemContainer<InterceptorFactory> clientPostConstructInterceptors = new OrderedItemContainer<InterceptorFactory>();
    private final OrderedItemContainer<InterceptorFactory> clientPreDestroyInterceptors = new OrderedItemContainer<InterceptorFactory>();
    private final ProxyFactory<?> proxyFactory;
    private final List<BindingConfiguration> bindingConfigurations = new ArrayList<BindingConfiguration>();
    private final Class<?> viewClass;
    private final Set<Method> asyncMethods = new HashSet<Method>();
    private final Map<Class<?>, Object> privateData = new HashMap<Class<?>, Object>();
    private final List<DependencyConfigurator<ViewService>> dependencies = new ArrayList<DependencyConfigurator<ViewService>>();
    private final Map<Method, Method> viewToComponentMethodMap = new HashMap<>();
    private ViewInstanceFactory viewInstanceFactory;

    /**
     * Construct a new instance.
     *
     * @param viewClass              the view class
     * @param componentConfiguration the associated component configuration
     * @param viewServiceName        the service name of this view
     * @param proxyFactory           the proxy factory to use to locally construct client proxy instances
     */
    public ViewConfiguration(final Class<?> viewClass, final ComponentConfiguration componentConfiguration, final ServiceName viewServiceName, final ProxyFactory<?> proxyFactory) {
        this.componentConfiguration = componentConfiguration;
        this.viewServiceName = viewServiceName;
        this.proxyFactory = proxyFactory;
        this.viewClass = viewClass;
    }

    /**
     * Get the component configuration for this view.
     *
     * @return the component configuration
     */
    public ComponentConfiguration getComponentConfiguration() {
        return componentConfiguration;
    }

    /**
     * Get the view service name for this view.
     *
     * @return the view service name
     */
    public ServiceName getViewServiceName() {
        return viewServiceName;
    }

    /**
     * Get the view interceptors for a method.  These interceptors are run sequentially on the "server side" of an
     * invocation.  The interceptor factories are used every time a new view instance is constructed, called with a
     * new factory context each time.  The factory may return the same interceptor instance or a new interceptor
     * instance as appropriate.
     *
     * @param method the method to look up
     * @return the interceptors for this method
     */
    public List<InterceptorFactory> getViewInterceptors(Method method) {
        OrderedItemContainer<InterceptorFactory> container = viewInterceptors.get(method);
        if (container == null) {
            return Collections.emptyList();
        }
        return container.getSortedItems();
    }

    /**
     * Adds an interceptor factory to all methods of a view
     *
     * @param interceptorFactory The factory to add
     * @param priority           The interceptor order
     */
    public void addViewInterceptor(InterceptorFactory interceptorFactory, int priority) {
        for (Method method : proxyFactory.getCachedMethods()) {
            addViewInterceptor(method, interceptorFactory, priority);
        }
    }

    /**
     * Adds a view interceptor to the given method
     *
     * @param method             The method to add
     * @param interceptorFactory The interceptor factory
     * @param priority           The priority
     */
    public void addViewInterceptor(Method method, InterceptorFactory interceptorFactory, int priority) {
        OrderedItemContainer<InterceptorFactory> container = viewInterceptors.get(method);
        if (container == null) {
            viewInterceptors.put(method, container = new OrderedItemContainer<InterceptorFactory>());
        }
        container.add(interceptorFactory, priority);
    }

    /**
     * Get the client interceptors for a method.  These interceptors are run sequentially on the "client side" of an
     * invocation.  The interceptor factories are used every time a new client proxy instance is constructed, called with a
     * new factory context each time.  The factory may return the same interceptor instance or a new interceptor
     * instance as appropriate.
     *
     * @param method the method to look up
     * @return the interceptors for this method
     */
    public List<InterceptorFactory> getClientInterceptors(Method method) {
        OrderedItemContainer<InterceptorFactory> container = clientInterceptors.get(method);
        if (container == null) {
            return Collections.emptyList();
        }
        return container.getSortedItems();
    }

    /**
     * Adds a client interceptor factory to all methods of a view
     *
     * @param interceptorFactory The factory to add
     * @param priority           The interceptor order
     */
    public void addClientInterceptor(InterceptorFactory interceptorFactory, int priority) {
        for (Method method : proxyFactory.getCachedMethods()) {
            addClientInterceptor(method, interceptorFactory, priority);
        }
    }

    /**
     * Adds a client interceptor to the given method
     *
     * @param method             The method to add
     * @param interceptorFactory The interceptor factory
     * @param priority           The priority
     */
    public void addClientInterceptor(Method method, InterceptorFactory interceptorFactory, int priority) {
        OrderedItemContainer<InterceptorFactory> container = clientInterceptors.get(method);
        if (container == null) {
            clientInterceptors.put(method, container = new OrderedItemContainer<InterceptorFactory>());
        }
        container.add(interceptorFactory, priority);
    }

    /**
     * Get the post-construct interceptors for client proxy instances.
     *

     * This method should only be called after all interceptors have been added.
     *
     * @return the interceptors
     */
    public List<InterceptorFactory> getClientPostConstructInterceptors() {
        return clientPostConstructInterceptors.getSortedItems();
    }

    /**
     * Adds a client post construct interceptor
     *
     * @param interceptorFactory The interceptor
     * @param priority           The interceptor order
     */
    public void addClientPostConstructInterceptor(final InterceptorFactory interceptorFactory, final int priority) {
        clientPostConstructInterceptors.add(interceptorFactory, priority);
    }

    /**
     * Get the pre-destroy interceptors for client proxy instances.
     *

     * This method should only be called after all interceptors have been added.
     *
     * @return the interceptors
     */
    public List<InterceptorFactory> getClientPreDestroyInterceptors() {
        return clientPreDestroyInterceptors.getSortedItems();
    }

    /**
     * Adds a client pre-destroy interceptor
     *
     * @param interceptorFactory The interceptor
     * @param priority           The interceptor order
     */
    public void addClientPreDestroyInterceptor(final InterceptorFactory interceptorFactory, final int priority) {
        clientPreDestroyInterceptors.add(interceptorFactory, priority);
    }

    /**
     * Get the client proxy factory to use to construct proxy instances.
     *
     * @return the proxy factory
     */
    public ProxyFactory<?> getProxyFactory() {
        return proxyFactory;
    }

    /**
     * Get the binding configurations for this view.
     *
     * @return the binding configurations
     */
    public List<BindingConfiguration> getBindingConfigurations() {
        return bindingConfigurations;
    }

    /**
     * Get the view class.
     *
     * @return the view class
     */
    public Class<?> getViewClass() {
        return viewClass;
    }

    /**
     * Gets all async methods for the view
     * @return The async methods
     */
    public Set<Method> getAsyncMethods() {
        return Collections.unmodifiableSet(asyncMethods);
    }

    /**
     * Marks a method on the view as asynchronous
     *
     * @param method The method
     */
    public void addAsyncMethod(Method method) {
        this.asyncMethods.add(method);
    }

    public ViewInstanceFactory getViewInstanceFactory() {
        return viewInstanceFactory;
    }

    /**
     *
     * @param viewInstanceFactory The instance factory that is used to create the view instances
     */
    public void setViewInstanceFactory(final ViewInstanceFactory viewInstanceFactory) {
        this.viewInstanceFactory = viewInstanceFactory;
    }

    /**
     * Attaches arbitrary private data to this view instance
     *
     * @param type The type of data
     * @param data The data
     */
    public <T> void putPrivateData(final Class<T> type, T data ) {
        privateData.put(type, data);
    }

    /**
     * retrieves private data
     */
    public Map<Class<?>, Object> getPrivateData() {
        return privateData;
    }

    public List<DependencyConfigurator<ViewService>> getDependencies() {
        return dependencies;
    }

    public Map<Method, Method> getViewToComponentMethodMap() {
        return viewToComponentMethodMap;
    }
}


/*
 * 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.security.plugins;

import java.security.Principal;
import java.security.PrivilegedAction;
import java.util.List;

import org.wildfly.security.manager.action.GetModuleClassLoaderAction;
import org.jboss.as.security.plugins.ModuleClassLoaderLocator.CombinedClassLoader;
import org.jboss.modules.Module;
import org.jboss.modules.ModuleClassLoader;
import org.jboss.modules.ModuleIdentifier;
import org.jboss.modules.ModuleLoadException;
import org.jboss.modules.ModuleLoader;
import org.jboss.security.SecurityContext;
import org.jboss.security.SecurityContextAssociation;
import org.wildfly.security.manager.WildFlySecurityManager;

import static java.security.AccessController.doPrivileged;

/**
 * Privileged blocks for this package
 *
 * @author Marcus Moyses
 */
class SecurityActions {

    static ModuleClassLoader getModuleClassLoader(final ModuleLoader loader, final String moduleSpec) throws ModuleLoadException {
        final Module module = loader.loadModule(ModuleIdentifier.fromString(moduleSpec));
        return WildFlySecurityManager.isChecking() ? doPrivileged(new GetModuleClassLoaderAction(module)) : module.getClassLoader();
    }

    static SecurityContext getSecurityContext() {
        if (WildFlySecurityManager.isChecking()) {
            return doPrivileged(new PrivilegedAction<SecurityContext>() {
                public SecurityContext run() {
                    return SecurityContextAssociation.getSecurityContext();
                }
            });
        } else {
            return SecurityContextAssociation.getSecurityContext();
        }
    }

    static Principal getPrincipal() {
        if (WildFlySecurityManager.isChecking()) {
            return doPrivileged(new PrivilegedAction<Principal>() {
                public Principal run() {
                    Principal principal = null;
                    SecurityContext sc = getSecurityContext();
                    if (sc != null) {
                        principal = sc.getUtil().getUserPrincipal();
                    }
                    return principal;
                }
            });
        } else {
            Principal principal = null;
            SecurityContext sc = getSecurityContext();
            if (sc != null) {
                principal = sc.getUtil().getUserPrincipal();
            }
            return principal;
        }
    }

    static Object getCredential() {
        if (WildFlySecurityManager.isChecking()) {
            return doPrivileged(new PrivilegedAction<Object>() {
                public Object run() {
                    Object credential = null;
                    SecurityContext sc = getSecurityContext();
                    if (sc != null) {
                        credential = sc.getUtil().getCredential();
                    }
                    return credential;
                }
            });
        } else {
            Object credential = null;
            SecurityContext sc = getSecurityContext();
            if (sc != null) {
                credential = sc.getUtil().getCredential();
            }
            return credential;
        }
    }

    /**
     * Returns the ModuleClassLoaderLocator.CombinedClassLoader instance with consideration of security manager enabled
     *
     * @param classLoaders the delegated ClassLoaders
     * @return the ModuleClassLoaderLocator.CombinedClassLoader instance
     */
    static ModuleClassLoaderLocator.CombinedClassLoader createCombinedClassLoader(final List<ClassLoader> classLoaders) {
        if (WildFlySecurityManager.isChecking()) {
            return doPrivileged(new PrivilegedAction<ModuleClassLoaderLocator.CombinedClassLoader>() {
                @Override
                public CombinedClassLoader run() {
                    return new ModuleClassLoaderLocator.CombinedClassLoader(classLoaders);
                }
            });
        } else {
            return new ModuleClassLoaderLocator.CombinedClassLoader(classLoaders);
        }
    }

}


/*
 * 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.jboss.as.ee.structure;

import static javax.xml.stream.XMLStreamConstants.ATTRIBUTE;
import static javax.xml.stream.XMLStreamConstants.CDATA;
import static javax.xml.stream.XMLStreamConstants.CHARACTERS;
import static javax.xml.stream.XMLStreamConstants.COMMENT;
import static javax.xml.stream.XMLStreamConstants.DTD;
import static javax.xml.stream.XMLStreamConstants.END_DOCUMENT;
import static javax.xml.stream.XMLStreamConstants.END_ELEMENT;
import static javax.xml.stream.XMLStreamConstants.ENTITY_DECLARATION;
import static javax.xml.stream.XMLStreamConstants.ENTITY_REFERENCE;
import static javax.xml.stream.XMLStreamConstants.NAMESPACE;
import static javax.xml.stream.XMLStreamConstants.NOTATION_DECLARATION;
import static javax.xml.stream.XMLStreamConstants.PROCESSING_INSTRUCTION;
import static javax.xml.stream.XMLStreamConstants.SPACE;
import static javax.xml.stream.XMLStreamConstants.START_DOCUMENT;
import static javax.xml.stream.XMLStreamConstants.START_ELEMENT;

import java.util.EnumSet;
import java.util.Set;

import javax.xml.stream.Location;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;

import org.jboss.as.ee.logging.EeLogger;
import org.jboss.as.ee.metadata.EJBClientDescriptorMetaData;
import org.jboss.metadata.property.PropertyReplacer;
import org.jboss.staxmapper.XMLElementReader;
import org.jboss.staxmapper.XMLExtendedStreamReader;

/**
 * Parser for urn:jboss:ejb-client:1.0:jboss-ejb-client
 *
 * @author Jaikiran Pai
 * @author Tomasz Adamski
 * @author Wolf-Dieter Fink
 */
class EJBClientDescriptor10Parser implements XMLElementReader<EJBClientDescriptorMetaData> {

    public static final String NAMESPACE_1_0 = "urn:jboss:ejb-client:1.0";

    protected final PropertyReplacer propertyReplacer;

    protected EJBClientDescriptor10Parser(final PropertyReplacer propertyReplacer) {
        this.propertyReplacer = propertyReplacer;
    }

    @Override
    public void readElement(final XMLExtendedStreamReader reader, final EJBClientDescriptorMetaData ejbClientDescriptorMetaData) throws XMLStreamException {
        while (reader.hasNext()) {
            switch (reader.nextTag()) {
                case END_ELEMENT: {
                    return;
                }
                case START_ELEMENT: {
                    final EJBClientDescriptorXMLElement element = EJBClientDescriptorXMLElement.forName(reader.getLocalName());

                    switch (element) {
                        case CLIENT_CONTEXT:
                            this.parseClientContext(reader, ejbClientDescriptorMetaData);
                            break;
                        default:
                            unexpectedElement(reader);
                    }
                    break;
                }
                default: {
                    unexpectedContent(reader);
                }
            }
        }
        unexpectedEndOfDocument(reader.getLocation());
    }

    protected void parseClientContext(final XMLExtendedStreamReader reader, final EJBClientDescriptorMetaData ejbClientDescriptorMetaData) throws XMLStreamException {
        final Set<EJBClientDescriptorXMLElement> visited = EnumSet.noneOf(EJBClientDescriptorXMLElement.class);
        while (reader.hasNext()) {
            switch (reader.nextTag()) {
                case END_ELEMENT: {
                    return;
                }
                case START_ELEMENT: {
                    final EJBClientDescriptorXMLElement element = EJBClientDescriptorXMLElement.forName(reader.getLocalName());
                    if (visited.contains(element)) {
                        unexpectedElement(reader);
                    }
                    visited.add(element);
                    switch (element) {
                        case EJB_RECEIVERS:
                            this.parseEJBReceivers(reader, ejbClientDescriptorMetaData);
                            break;
                        default:
                            unexpectedElement(reader);
                    }
                    break;
                }
                default: {
                    unexpectedContent(reader);
                }
            }
        }
        unexpectedEndOfDocument(reader.getLocation());
    }

    protected void parseEJBReceivers(final XMLExtendedStreamReader reader, final EJBClientDescriptorMetaData ejbClientDescriptorMetaData) throws XMLStreamException {

        // initialize the local-receiver-pass-by-value to the default null - to indicate it has not been initialized via XML
        // check for 'true' - localReceiverPassByValue != Boolean.FALSE
        Boolean localReceiverPassByValue = null;

        final int count = reader.getAttributeCount();
        for (int i = 0; i < count; i++) {
            final EJBClientDescriptorXMLAttribute attribute = EJBClientDescriptorXMLAttribute.forName(reader.getAttributeLocalName(i));
            final String value = readResolveValue(reader, i);
            switch (attribute) {
                case EXCLUDE_LOCAL_RECEIVER:
                    final boolean excludeLocalReceiver = Boolean.parseBoolean(value);
                    ejbClientDescriptorMetaData.setExcludeLocalReceiver(excludeLocalReceiver);
                    break;
                case LOCAL_RECEIVER_PASS_BY_VALUE:
                    localReceiverPassByValue = Boolean.parseBoolean(value);
                    break;
                default:
                    unexpectedContent(reader);
            }
        }
        // set the local receiver pass by value into the metadata
        ejbClientDescriptorMetaData.setLocalReceiverPassByValue(localReceiverPassByValue != Boolean.FALSE);
        while (reader.hasNext()) {
            switch (reader.nextTag()) {
                case END_ELEMENT: {
                    return;
                }
                case START_ELEMENT: {
                    final EJBClientDescriptorXMLElement element = EJBClientDescriptorXMLElement.forName(reader.getLocalName());
                    switch (element) {
                        case REMOTING_EJB_RECEIVER:
                            this.parseRemotingReceiver(reader, ejbClientDescriptorMetaData);
                            break;
                        default:
                            unexpectedElement(reader);
                    }
                    break;
                }
                default: {
                    unexpectedContent(reader);
                }
            }
        }
        unexpectedEndOfDocument(reader.getLocation());
    }

    protected void parseRemotingReceiver(final XMLExtendedStreamReader reader, final EJBClientDescriptorMetaData ejbClientDescriptorMetaData) throws XMLStreamException {
        String outboundConnectionRef = null;
        final Set<EJBClientDescriptorXMLAttribute> required = EnumSet.of(EJBClientDescriptorXMLAttribute.OUTBOUND_CONNECTION_REF);
        final int count = reader.getAttributeCount();
        for (int i = 0; i < count; i++) {
            final EJBClientDescriptorXMLAttribute attribute = EJBClientDescriptorXMLAttribute.forName(reader.getAttributeLocalName(i));
            required.remove(attribute);
            switch (attribute) {
                case OUTBOUND_CONNECTION_REF:
                    outboundConnectionRef = readResolveValue(reader, i);
                    ejbClientDescriptorMetaData.addRemotingReceiverConnectionRef(outboundConnectionRef);
                    break;
                default:
                    unexpectedContent(reader);
            }
        }
        if (!required.isEmpty()) {
            missingAttributes(reader.getLocation(), required);
        }
        // This element is just composed of attributes which we already processed, so no more content
        // is expected
        if (reader.hasNext() && reader.nextTag() != END_ELEMENT) {
            unexpectedContent(reader);
        }
    }

    protected static void unexpectedEndOfDocument(final Location location) throws XMLStreamException {
        throw EeLogger.ROOT_LOGGER.errorParsingEJBClientDescriptor("Unexpected end of document", location);
    }

    protected static void missingAttributes(final Location location, final Set<EJBClientDescriptorXMLAttribute> required) throws XMLStreamException {
        final StringBuilder b = new StringBuilder("Missing one or more required attributes:");
        for (EJBClientDescriptorXMLAttribute attribute : required) {
            b.append(' ').append(attribute);
        }
        throw EeLogger.ROOT_LOGGER.errorParsingEJBClientDescriptor(b.toString(), location);
    }

    /**
     * Throws a XMLStreamException for the unexpected element that was encountered during the parse
     *
     * @param reader the stream reader
     * @throws XMLStreamException
     */
    protected static void unexpectedElement(final XMLExtendedStreamReader reader) throws XMLStreamException {
        throw EeLogger.ROOT_LOGGER.unexpectedElement(reader.getName(), reader.getLocation());
    }

    protected static void unexpectedContent(final XMLStreamReader reader) throws XMLStreamException {
        final String kind;
        switch (reader.getEventType()) {
            case ATTRIBUTE:
                kind = "attribute";
                break;
            case CDATA:
                kind = "cdata";
                break;
            case CHARACTERS:
                kind = "characters";
                break;
            case COMMENT:
                kind = "comment";
                break;
            case DTD:
                kind = "dtd";
                break;
            case END_DOCUMENT:
                kind = "document end";
                break;
            case END_ELEMENT:
                kind = "element end";
                break;
            case ENTITY_DECLARATION:
                kind = "entity declaration";
                break;
            case ENTITY_REFERENCE:
                kind = "entity ref";
                break;
            case NAMESPACE:
                kind = "namespace";
                break;
            case NOTATION_DECLARATION:
                kind = "notation declaration";
                break;
            case PROCESSING_INSTRUCTION:
                kind = "processing instruction";
                break;
            case SPACE:
                kind = "whitespace";
                break;
            case START_DOCUMENT:
                kind = "document start";
                break;
            case START_ELEMENT:
                kind = "element start";
                break;
            default:
                kind = "unknown";
                break;
        }
        final StringBuilder b = new StringBuilder("Unexpected content of type '").append(kind).append('\'');
        if (reader.hasName()) {
            b.append(" named '").append(reader.getName()).append('\'');
        }
        if (reader.hasText()) {
            b.append(", text is: '").append(reader.getText()).append('\'');
        }
        throw EeLogger.ROOT_LOGGER.errorParsingEJBClientDescriptor(b.toString(), reader.getLocation());
    }

    protected String readResolveValue(final XMLExtendedStreamReader reader, final int index) {
        return propertyReplacer.replaceProperties(reader.getAttributeValue(index).trim());
    }

}


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

import java.util.Map;
import java.util.function.Predicate;

import org.jboss.as.controller.AbstractRemoveStepHandler;
import org.jboss.as.controller.AttributeDefinition;
import org.jboss.as.controller.CapabilityReferenceRecorder;
import org.jboss.as.controller.OperationContext;
import org.jboss.as.controller.OperationFailedException;
import org.jboss.as.controller.PathAddress;
import org.jboss.as.controller.SimpleOperationDefinitionBuilder;
import org.jboss.as.controller.descriptions.ModelDescriptionConstants;
import org.jboss.as.controller.registry.ImmutableManagementResourceRegistration;
import org.jboss.as.controller.registry.ManagementResourceRegistration;
import org.jboss.as.controller.registry.OperationEntry;
import org.jboss.as.controller.registry.Resource;
import org.jboss.dmr.ModelNode;

/**
 * Generic remove operation step handler that delegates service removal/recovery to a dedicated {@link ResourceServiceHandler}.
 * @author Paul Ferraro
 */
public class RemoveStepHandler extends AbstractRemoveStepHandler implements Registration<ManagementResourceRegistration> {

    private final RemoveStepHandlerDescriptor descriptor;
    private final ResourceServiceHandler handler;
    private final OperationEntry.Flag flag;

    public RemoveStepHandler(RemoveStepHandlerDescriptor descriptor, ResourceServiceHandler handler) {
        this(descriptor, handler, OperationEntry.Flag.RESTART_RESOURCE_SERVICES);
    }

    protected RemoveStepHandler(RemoveStepHandlerDescriptor descriptor, OperationEntry.Flag flag) {
        this(descriptor, null, flag);
    }

    private RemoveStepHandler(RemoveStepHandlerDescriptor descriptor, ResourceServiceHandler handler, OperationEntry.Flag flag) {
        this.descriptor = descriptor;
        this.handler = handler;
        this.flag = flag;
    }

    @Override
    protected boolean requiresRuntime(OperationContext context) {
        return super.requiresRuntime(context) && (this.handler != null);
    }

    @Override
    protected void performRemove(OperationContext context, ModelNode operation, ModelNode model) throws OperationFailedException {
        Resource resource = context.readResource(PathAddress.EMPTY_ADDRESS);
        if (removeInCurrentStep(resource)) {
            // We need to remove capabilities *before* removing the resource, since the capability reference resolution might involve reading the resource
            PathAddress address = context.getCurrentAddress();
            for (Map.Entry<Capability, Predicate<ModelNode>> entry : this.descriptor.getCapabilities().entrySet()) {
                if (entry.getValue().test(model)) {
                    context.deregisterCapability(entry.getKey().resolve(address).getName());
                }
            }

            ImmutableManagementResourceRegistration registration = context.getResourceRegistration();
            for (String attributeName : registration.getAttributeNames(PathAddress.EMPTY_ADDRESS)) {
                AttributeDefinition attribute = registration.getAttributeAccess(PathAddress.EMPTY_ADDRESS, attributeName).getAttributeDefinition();
                if (attribute.hasCapabilityRequirements()) {
                    attribute.removeCapabilityRequirements(context, resource, model.get(attributeName));
                }
            }

            for (CapabilityReferenceRecorder recorder : registration.getRequirements()) {
                recorder.removeCapabilityRequirements(context, resource, null);
            }

            if (this.requiresRuntime(context)) {
                for (RuntimeResourceRegistration runtimeRegistration : this.descriptor.getRuntimeResourceRegistrations()) {
                    runtimeRegistration.unregister(context);
                }
            }
        }

        super.performRemove(context, operation, model);
    }

    /*
     * Determines whether resource removal happens in this step, or a subsequent step
     */
    private static boolean removeInCurrentStep(Resource resource) {
        for (String childType : resource.getChildTypes()) {
            for (Resource.ResourceEntry entry : resource.getChildren(childType)) {
                if (!entry.isRuntime() && resource.hasChild(entry.getPathElement())) {
                    return false;
                }
            }
        }
        return true;
    }

    @Override
    protected void performRuntime(OperationContext context, ModelNode operation, ModelNode model) throws OperationFailedException {
        if (context.isResourceServiceRestartAllowed()) {
            this.handler.removeServices(context, model);
        } else {
            context.reloadRequired();
        }
    }

    @Override
    protected void recoverServices(OperationContext context, ModelNode operation, ModelNode model) throws OperationFailedException {
        if (context.isResourceServiceRestartAllowed()) {
            this.handler.installServices(context, model);
        } else {
            context.revertReloadRequired();
        }
    }

    @Override
    protected void recordCapabilitiesAndRequirements(OperationContext context, ModelNode operation, Resource resource) throws OperationFailedException {
        // We already unregistered our capabilities in performRemove(...)
    }

    @Override
    public void register(ManagementResourceRegistration registration) {
        registration.registerOperationHandler(new SimpleOperationDefinitionBuilder(ModelDescriptionConstants.REMOVE, this.descriptor.getDescriptionResolver()).withFlag(this.flag).build(), this.descriptor.getOperationTransformation().apply(this));
    }
}


/*
 * 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.wildfly.extension.messaging.activemq.jms;

import static java.lang.System.arraycopy;
import static org.wildfly.extension.messaging.activemq.AbstractTransportDefinition.CONNECTOR_CAPABILITY_NAME;
import static org.wildfly.extension.messaging.activemq.jms.ConnectionFactoryAttribute.getDefinitions;

import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

import org.jboss.as.controller.AbstractAttributeDefinitionBuilder;
import org.jboss.as.controller.AttributeDefinition;
import org.jboss.as.controller.AttributeMarshaller;
import org.jboss.as.controller.AttributeParser;
import org.jboss.as.controller.PersistentResourceDefinition;
import org.jboss.as.controller.PrimitiveListAttributeDefinition;
import org.jboss.as.controller.ReloadRequiredWriteAttributeHandler;
import org.jboss.as.controller.SimpleAttributeDefinition;
import org.jboss.as.controller.SimpleAttributeDefinitionBuilder;
import org.jboss.as.controller.SimpleListAttributeDefinition;
import org.jboss.as.controller.SimpleMapAttributeDefinition;
import org.jboss.as.controller.SimpleResourceDefinition;
import org.jboss.as.controller.StringListAttributeDefinition;
import org.jboss.as.controller.capability.DynamicNameMappers;
import org.jboss.as.controller.capability.RuntimeCapability;
import org.jboss.as.controller.registry.AttributeAccess;
import org.jboss.as.controller.registry.ManagementResourceRegistration;
import org.wildfly.extension.messaging.activemq.AbstractTransportDefinition;
import org.wildfly.extension.messaging.activemq.CommonAttributes;
import org.wildfly.extension.messaging.activemq.MessagingExtension;
import org.wildfly.extension.messaging.activemq.jms.ConnectionFactoryAttributes.Common;
import org.wildfly.extension.messaging.activemq.jms.ConnectionFactoryAttributes.Pooled;

/**
 * JMS pooled Connection Factory resource definition.
 *
 * @author Jeff Mesnil (c) 2012 Red Hat Inc.
 */
public class PooledConnectionFactoryDefinition extends PersistentResourceDefinition {
    static final String CAPABILITY_NAME = "org.wildfly.messaging.activemq.server.pooled-connection-factory";
    static final RuntimeCapability<Void> CAPABILITY = RuntimeCapability.Builder.of(CAPABILITY_NAME, true, PooledConnectionFactoryService.class)
            .setDynamicNameMapper(DynamicNameMappers.PARENT)
            .build();
    // the generation of the Pooled CF attributes is a bit ugly but it is with purpose:
    // * factorize the attributes which are common between the regular CF and the pooled CF
    // * keep in a single place the subtle differences (e.g. different default values for reconnect-attempts between
    //   the regular and pooled CF
    private static ConnectionFactoryAttribute[] define(ConnectionFactoryAttribute[] specific, ConnectionFactoryAttribute... common) {
        int size = common.length + specific.length;
        ConnectionFactoryAttribute[] result = new ConnectionFactoryAttribute[size];
        arraycopy(specific, 0, result, 0, specific.length);
        for (int i = 0; i < common.length; i++) {
            ConnectionFactoryAttribute attr = common[i];
            AttributeDefinition definition = attr.getDefinition();

            ConnectionFactoryAttribute newAttr;
            // replace the reconnect-attempts attribute to use a different default value for pooled CF
            if (definition == Common.RECONNECT_ATTEMPTS) {
                AttributeDefinition copy = copy(Pooled.RECONNECT_ATTEMPTS, AttributeAccess.Flag.RESTART_ALL_SERVICES);
                newAttr = ConnectionFactoryAttribute.create(copy, Pooled.RECONNECT_ATTEMPTS_PROP_NAME, true);
            } else if (definition == Common.CONNECTORS) {
                StringListAttributeDefinition copy = new StringListAttributeDefinition.Builder(Common.CONNECTORS)
                        .setAlternatives(CommonAttributes.DISCOVERY_GROUP)
                        .setRequired(true)
                        .setAttributeParser(AttributeParser.STRING_LIST)
                        .setAttributeMarshaller(AttributeMarshaller.STRING_LIST)
                        .setCapabilityReference(new AbstractTransportDefinition.TransportCapabilityReferenceRecorder(CAPABILITY_NAME, CONNECTOR_CAPABILITY_NAME, false))
                        .setRestartAllServices()
                        .build();
                newAttr = ConnectionFactoryAttribute.create(copy, attr.getPropertyName(), attr.isResourceAdapterProperty(), attr.getConfigType());
            }else {
                AttributeDefinition copy = copy(definition, AttributeAccess.Flag.RESTART_ALL_SERVICES);
                newAttr = ConnectionFactoryAttribute.create(copy, attr.getPropertyName(), attr.isResourceAdapterProperty(), attr.getConfigType());
            }
            result[specific.length + i] = newAttr;
        }
        return result;
    }

    private static AttributeDefinition copy(AttributeDefinition attribute, AttributeAccess.Flag flag) {
        AbstractAttributeDefinitionBuilder builder;
        if (attribute instanceof  SimpleListAttributeDefinition) {
            builder =  new SimpleListAttributeDefinition.Builder((SimpleListAttributeDefinition)attribute);
        } else if (attribute instanceof  SimpleMapAttributeDefinition) {
            builder = new SimpleMapAttributeDefinition.Builder((SimpleMapAttributeDefinition)attribute);
        } else if (attribute instanceof PrimitiveListAttributeDefinition) {
            builder = new PrimitiveListAttributeDefinition.Builder((PrimitiveListAttributeDefinition)attribute);
        } else {
            builder = new SimpleAttributeDefinitionBuilder((SimpleAttributeDefinition)attribute);
        }
        builder.setFlags(flag);
        return builder.build();
    }

    public static final ConnectionFactoryAttribute[] ATTRIBUTES = define(Pooled.ATTRIBUTES, Common.ATTRIBUTES);

    public static Map<String, ConnectionFactoryAttribute> getAttributesMap() {
        Map<String, ConnectionFactoryAttribute> attrs = new HashMap<String, ConnectionFactoryAttribute>(ATTRIBUTES.length);
        for (ConnectionFactoryAttribute attribute : ATTRIBUTES) {
            attrs.put(attribute.getDefinition().getName(), attribute);
        }
        return attrs;
    }

    private final boolean deployed;

    public static final PooledConnectionFactoryDefinition INSTANCE = new PooledConnectionFactoryDefinition(false);

    public static final PooledConnectionFactoryDefinition DEPLOYMENT_INSTANCE = new PooledConnectionFactoryDefinition(true);

    public PooledConnectionFactoryDefinition(final boolean deployed) {
        this(new SimpleResourceDefinition.Parameters(MessagingExtension.POOLED_CONNECTION_FACTORY_PATH, MessagingExtension.getResourceDescriptionResolver(CommonAttributes.POOLED_CONNECTION_FACTORY))
                .setAddHandler(PooledConnectionFactoryAdd.INSTANCE)
                .setRemoveHandler(PooledConnectionFactoryRemove.INSTANCE)
                .setCapabilities(CAPABILITY), deployed);
    }

    protected PooledConnectionFactoryDefinition(SimpleResourceDefinition.Parameters parameters, final boolean deployed) {
        super(parameters);
        this.deployed = deployed;
    }

    @Override
    public Collection<AttributeDefinition> getAttributes() {
        return Arrays.asList(getDefinitions(ATTRIBUTES));
    }

    @Override
    public void registerAttributes(ManagementResourceRegistration registry) {
        Collection<AttributeDefinition> definitions = getAttributes();
        ReloadRequiredWriteAttributeHandler reloadRequiredWriteAttributeHandler = new ReloadRequiredWriteAttributeHandler(definitions);
        for (AttributeDefinition attr : definitions) {
            if (!attr.getFlags().contains(AttributeAccess.Flag.STORAGE_RUNTIME)) {
                if (deployed) {
                    registry.registerReadOnlyAttribute(attr, PooledConnectionFactoryConfigurationRuntimeHandler.INSTANCE);
                } else {
                    registry.registerReadWriteAttribute(attr, null, reloadRequiredWriteAttributeHandler);
                }
            }
        }
    }
}


/*
 * JBoss, Home of Professional Open Source.
 * Copyright 2011, 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.jboss.as.webservices.util;

import static org.jboss.as.server.deployment.Attachments.DEPLOYMENT_ROOT;
import static org.jboss.as.server.deployment.Attachments.RESOURCE_ROOTS;
import static org.jboss.as.webservices.util.DotNames.JAXWS_SERVICE_CLASS;
import static org.jboss.as.webservices.util.DotNames.WEB_SERVICE_ANNOTATION;
import static org.jboss.as.webservices.util.DotNames.WEB_SERVICE_PROVIDER_ANNOTATION;
import static org.jboss.as.webservices.util.WSAttachmentKeys.JAXWS_ENDPOINTS_KEY;
import static org.jboss.as.webservices.util.WSAttachmentKeys.JBOSS_WEBSERVICES_METADATA_KEY;

import java.lang.reflect.Modifier;
import java.util.Collections;
import java.util.List;

import javax.jws.WebService;
import javax.xml.ws.WebServiceProvider;

import org.jboss.as.ee.component.EEModuleClassDescription;
import org.jboss.as.ee.metadata.ClassAnnotationInformation;
import org.jboss.as.server.CurrentServiceContainer;
import org.jboss.as.server.deployment.AttachmentKey;
import org.jboss.as.server.deployment.AttachmentList;
import org.jboss.as.server.deployment.Attachments;
import org.jboss.as.server.deployment.DeploymentUnit;
import org.jboss.as.server.deployment.EjbDeploymentMarker;
import org.jboss.as.server.deployment.annotation.CompositeIndex;
import org.jboss.as.server.deployment.module.ResourceRoot;
import org.jboss.as.web.common.WarMetaData;
import org.jboss.as.webservices.deployers.WebServiceAnnotationInfo;
import org.jboss.as.webservices.deployers.WebServiceProviderAnnotationInfo;
import org.jboss.as.webservices.logging.WSLogger;
import org.jboss.as.webservices.metadata.model.EJBEndpoint;
import org.jboss.as.webservices.metadata.model.JAXWSDeployment;
import org.jboss.as.webservices.metadata.model.POJOEndpoint;
import org.jboss.as.webservices.webserviceref.WSRefRegistry;
import org.jboss.jandex.AnnotationInstance;
import org.jboss.jandex.ClassInfo;
import org.jboss.jandex.DotName;
import org.jboss.jandex.Index;
import org.jboss.metadata.ear.jboss.JBossAppMetaData;
import org.jboss.metadata.ear.spec.ModuleMetaData;
import org.jboss.metadata.ear.spec.WebModuleMetaData;
import org.jboss.metadata.web.jboss.JBossServletMetaData;
import org.jboss.metadata.web.jboss.JBossWebMetaData;
import org.jboss.metadata.web.spec.ServletMetaData;
import org.jboss.msc.service.ServiceController;
import org.jboss.msc.service.ServiceName;
import org.jboss.ws.common.integration.WSHelper;
import org.jboss.wsf.spi.deployment.Deployment;
import org.jboss.wsf.spi.metadata.webservices.JBossPortComponentMetaData;
import org.jboss.wsf.spi.metadata.webservices.JBossWebservicesMetaData;

/**
 * JBoss AS integration helper class.
 *
 * @author Richard Opalka
 * @author Alessio Soldano
 */
public final class ASHelper {

    private ASHelper() {
    }

    /**
     * Gets list of JAXWS EJBs meta data.
     *
     * @param unit deployment unit
     * @return list of JAXWS EJBs meta data
     */
    public static List<EJBEndpoint> getJaxwsEjbs(final DeploymentUnit unit) {
        final JAXWSDeployment jaxwsDeployment = getOptionalAttachment(unit, WSAttachmentKeys.JAXWS_ENDPOINTS_KEY);
        return jaxwsDeployment != null ? jaxwsDeployment.getEjbEndpoints() : Collections.<EJBEndpoint>emptyList();
    }

    /**
     * Gets list of JAXWS POJOs meta data.
     *
     * @param unit deployment unit
     * @return list of JAXWS POJOs meta data
     */
    public static List<POJOEndpoint> getJaxwsPojos(final DeploymentUnit unit) {
        final JAXWSDeployment jaxwsDeployment = unit.getAttachment(WSAttachmentKeys.JAXWS_ENDPOINTS_KEY);
        return jaxwsDeployment != null ? jaxwsDeployment.getPojoEndpoints() : Collections.<POJOEndpoint>emptyList();
    }

    /**
     * Returns endpoint name.
     *
     * @param servletMD servlet meta data
     * @return endpoint name
     */
    public static String getEndpointName(final ServletMetaData servletMD) {
        final String endpointName = servletMD.getName();
        return endpointName != null ? endpointName.trim() : null;
    }

    /**
     * Returns endpoint class name.
     *
     * @param servletMD servlet meta data
     * @return endpoint class name
     */
    public static String getEndpointClassName(final ServletMetaData servletMD) {
        final String endpointClass = servletMD.getServletClass();
        return endpointClass != null ? endpointClass.trim() : null;
    }

    /**
     * Returns servlet meta data for requested servlet name.
     *
     * @param jbossWebMD jboss web meta data
     * @param servletName servlet name
     * @return servlet meta data
     */
    public static ServletMetaData getServletForName(final JBossWebMetaData jbossWebMD, final String servletName) {
        for (JBossServletMetaData servlet : jbossWebMD.getServlets()) {
            if (servlet.getName().equals(servletName)) {
                return servlet;
            }
        }

        return null;
    }

    /**
     * Returns required attachment value from deployment unit.
     *
     * @param  expected value
     * @param unit deployment unit
     * @param key attachment key
     * @return required attachment
     * @throws IllegalStateException if attachment value is null
     */
    public static  A getRequiredAttachment(final DeploymentUnit unit, final AttachmentKey key) {
        final A value = unit.getAttachment(key);
        if (value == null) {
            throw new IllegalStateException();
        }

        return value;
    }

    /**
     * Returns optional attachment value from deployment unit or null if not bound.
     *
     * @param  expected value
     * @param unit deployment unit
     * @param key attachment key
     * @return optional attachment value or null
     */
    public static  A getOptionalAttachment(final DeploymentUnit unit, final AttachmentKey key) {
        return unit.getAttachment(key);
    }

    public static boolean isJaxwsService(final ClassInfo current, final CompositeIndex index) {
        ClassInfo tmp = current;
        while (tmp != null) {
            final DotName superName = tmp.superName();
            if (JAXWS_SERVICE_CLASS.equals(superName)) {
                return true;
            }
            tmp = index.getClassByName(superName);
        }
        return false;
    }

    public static boolean isJaxwsService(final ClassInfo current, final Index index) {
        ClassInfo tmp = current;
        while (tmp != null) {
            final DotName superName = tmp.superName();
            if (JAXWS_SERVICE_CLASS.equals(superName)) {
                return true;
            }
            tmp = index.getClassByName(superName);
        }
        return false;
    }

    public static boolean isJaxwsEndpointInterface(final ClassInfo clazz) {
        final short flags = clazz.flags();
        if (!Modifier.isInterface(flags)) return false;
        if (!Modifier.isPublic(flags)) return false;
        return clazz.annotations().containsKey(WEB_SERVICE_ANNOTATION);
    }

    public static boolean hasClassesFromPackage(final Index index, final String pck) {
        for (ClassInfo ci : index.getKnownClasses()) {
            if (ci.name().toString().startsWith(pck)) {
                return true;
            }
        }
        return false;
    }

    public static boolean isJaxwsEndpoint(final ClassInfo clazz, final CompositeIndex index) {
        return isJaxwsEndpoint(clazz, index, true);
    }

    public static boolean isJaxwsEndpoint(final ClassInfo clazz, final CompositeIndex index, boolean log) {
        // assert JAXWS endpoint class flags
        final short flags = clazz.flags();
        if (Modifier.isInterface(flags)) return false;
        if (Modifier.isAbstract(flags)) return false;
        if (!Modifier.isPublic(flags)) return false;
        if (isJaxwsService(clazz, index)) return false;
        final boolean hasWebServiceAnnotation = clazz.annotations().containsKey(WEB_SERVICE_ANNOTATION);
        final boolean hasWebServiceProviderAnnotation = clazz.annotations().containsKey(WEB_SERVICE_PROVIDER_ANNOTATION);
        if (!hasWebServiceAnnotation && !hasWebServiceProviderAnnotation) {
            return false;
        }
        if (hasWebServiceAnnotation && hasWebServiceProviderAnnotation) {
            if (log) {
                WSLogger.ROOT_LOGGER.mutuallyExclusiveAnnotations(clazz.name().toString());
            }
            return false;
        }
        if (Modifier.isFinal(flags)) {
            if (log) {
                WSLogger.ROOT_LOGGER.finalEndpointClassDetected(clazz.name().toString());
            }
            return false;
        }
        return true;
    }

    public static boolean isJaxwsEndpoint(final EEModuleClassDescription classDescription, final CompositeIndex index) {
        ClassInfo classInfo = null;
        WebServiceAnnotationInfo webserviceAnnoationInfo = null;
        final ClassAnnotationInformation<WebService, WebServiceAnnotationInfo> classAnnotationInfo = classDescription.getAnnotationInformation(WebService.class);
        if (classAnnotationInfo!= null && !classAnnotationInfo.getClassLevelAnnotations().isEmpty()) {
            webserviceAnnoationInfo = classAnnotationInfo.getClassLevelAnnotations().get(0);
            classInfo = (ClassInfo)webserviceAnnoationInfo.getTarget();
        }
        WebServiceProviderAnnotationInfo webserviceProviderAnnoationInfo = null;
        final ClassAnnotationInformation<WebServiceProvider, WebServiceProviderAnnotationInfo> providerAnnotationInfo = classDescription.getAnnotationInformation(WebServiceProvider.class);
        if (providerAnnotationInfo!= null && !providerAnnotationInfo.getClassLevelAnnotations().isEmpty()) {
            webserviceProviderAnnoationInfo = providerAnnotationInfo.getClassLevelAnnotations().get(0);
            classInfo = (ClassInfo)webserviceProviderAnnoationInfo.getTarget();
        }
        if (classInfo == null) {
            return false;
        }
        // assert JAXWS endpoint class flags
        final short flags = classInfo.flags();
        if (Modifier.isInterface(flags)) return false;
        if (Modifier.isAbstract(flags)) return false;
        if (!Modifier.isPublic(flags)) return false;
        if (isJaxwsService(classInfo, index)) return false;

        if (webserviceAnnoationInfo !=null && webserviceProviderAnnoationInfo != null) {
            WSLogger.ROOT_LOGGER.mutuallyExclusiveAnnotations(classInfo.name().toString());
            return false;
        }
        if (Modifier.isFinal(flags)) {
            WSLogger.ROOT_LOGGER.finalEndpointClassDetected(classInfo.name().toString());
            return false;
        }
        return true;
    }

    /**
     * Gets the JBossWebMetaData from the WarMetaData attached to the provided deployment unit, if any.
     *
     * @param unit
     * @return the JBossWebMetaData or null if either that or the parent WarMetaData are not found.
     */
    public static JBossWebMetaData getJBossWebMetaData(final DeploymentUnit unit) {
        final WarMetaData warMetaData = getOptionalAttachment(unit, WarMetaData.ATTACHMENT_KEY);
        JBossWebMetaData result = null;
        if (warMetaData != null) {
            result = warMetaData.getMergedJBossWebMetaData();
            if (result == null) {
                result = warMetaData.getJBossWebMetaData();
            }
        } else {
            result = getOptionalAttachment(unit, WSAttachmentKeys.JBOSSWEB_METADATA_KEY);
        }
        return result;
    }

    public static List<AnnotationInstance> getAnnotations(final DeploymentUnit unit, final DotName annotation) {
       final CompositeIndex compositeIndex = getRequiredAttachment(unit, Attachments.COMPOSITE_ANNOTATION_INDEX);
       return compositeIndex.getAnnotations(annotation);
    }

    public static JAXWSDeployment getJaxwsDeployment(final DeploymentUnit unit) {
        JAXWSDeployment wsDeployment = unit.getAttachment(JAXWS_ENDPOINTS_KEY);
        if (wsDeployment == null) {
            wsDeployment = new JAXWSDeployment();
            unit.putAttachment(JAXWS_ENDPOINTS_KEY, wsDeployment);
        }
        return wsDeployment;
    }

    /**
     * Return a named port-component from the jboss-webservices.xml
     * @param unit
     * @param name
     * @return
     */
    public static JBossPortComponentMetaData getJBossWebserviceMetaDataPortComponent(
        final DeploymentUnit unit, final String name) {

        if (name != null) {
            final JBossWebservicesMetaData jbossWebserviceMetaData = unit.getAttachment(JBOSS_WEBSERVICES_METADATA_KEY);

            if (jbossWebserviceMetaData != null) {
                JBossPortComponentMetaData[] portComponent = jbossWebserviceMetaData.getPortComponents();

                if (portComponent != null) {
                    for (JBossPortComponentMetaData component : portComponent) {
                        if (name.equals(component.getEjbName())) {
                            return component;
                        }
                    }
                }
            }
        }
        return null;
    }

    /**
     * Returns an EJBEndpoint based upon fully qualified classname.
     * @param jaxwsDeployment
     * @param className
     * @return
     */
    public static EJBEndpoint getWebserviceMetadataEJBEndpoint(final JAXWSDeployment jaxwsDeployment,
                                                               final String className) {

        java.util.List<EJBEndpoint> ejbEndpointList = jaxwsDeployment.getEjbEndpoints();
        for (EJBEndpoint ejbEndpoint : ejbEndpointList) {
            if (className.equals(ejbEndpoint.getClassName())) {
                return ejbEndpoint;
            }
        }
        return null;
    }

    /**
     * Returns context root associated with webservice deployment.
     *
     * If there's application.xml descriptor provided defining nested web module, then context root defined there will be
     * returned. Otherwise context root defined in jboss-web.xml will be returned.
     *
     * @param dep webservice deployment
     * @param jbossWebMD jboss web meta data
     * @return context root
     */
    public static String getContextRoot(final Deployment dep, final JBossWebMetaData jbossWebMD) {
        final DeploymentUnit unit = WSHelper.getRequiredAttachment(dep, DeploymentUnit.class);
        final JBossAppMetaData jbossAppMD = unit.getParent() == null ? null : ASHelper.getOptionalAttachment(unit.getParent(),
                WSAttachmentKeys.JBOSS_APP_METADATA_KEY);

        String contextRoot = null;

        // prefer context root defined in application.xml over one defined in jboss-web.xml
        if (jbossAppMD != null) {
            final ModuleMetaData moduleMD = jbossAppMD.getModules().get(dep.getSimpleName());
            if (moduleMD != null) {
                final WebModuleMetaData webModuleMD = (WebModuleMetaData) moduleMD.getValue();
                contextRoot = webModuleMD.getContextRoot();
            }
        }

        if (contextRoot == null) {
            contextRoot = jbossWebMD != null ? jbossWebMD.getContextRoot() : null;
        }

        return contextRoot;
    }

    @SuppressWarnings("unchecked")
    public static <T> T getMSCService(final ServiceName serviceName, final Class<T> clazz) {
        ServiceController<T> service = (ServiceController<T>) CurrentServiceContainer.getServiceContainer().getService(serviceName);
        return service != null ? service.getValue() : null;
    }

    public static WSRefRegistry getWSRefRegistry(final DeploymentUnit unit) {
        WSRefRegistry refRegistry = unit.getAttachment(WSAttachmentKeys.WS_REFREGISTRY);
        if (refRegistry == null) {
            refRegistry = WSRefRegistry.newInstance();
            unit.putAttachment(WSAttachmentKeys.WS_REFREGISTRY, refRegistry);
        }
        return refRegistry;
    }

    public static List<ResourceRoot> getResourceRoots(DeploymentUnit unit) {
        // wars define resource roots
        AttachmentList<ResourceRoot> resourceRoots = unit.getAttachment(RESOURCE_ROOTS);
        if (!unit.getName().endsWith(".war") && EjbDeploymentMarker.isEjbDeployment(unit)) {
            // ejb archives don't define resource roots, using root resource
            resourceRoots = new AttachmentList<ResourceRoot>(ResourceRoot.class);
            final ResourceRoot root = unit.getAttachment(DEPLOYMENT_ROOT);
            resourceRoots.add(root);
        }
        return resourceRoots;
    }
}


/*
 * 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.jboss.as.clustering.controller.transform;

import java.util.ArrayList;
import java.util.Deque;
import java.util.LinkedList;
import java.util.List;
import java.util.ListIterator;

import org.jboss.as.clustering.controller.Operations;
import org.jboss.as.controller.OperationFailedException;
import org.jboss.as.controller.PathAddress;
import org.jboss.as.controller.descriptions.ModelDescriptionConstants;
import org.jboss.as.controller.transform.OperationResultTransformer;
import org.jboss.as.controller.transform.OperationTransformer;
import org.jboss.as.controller.transform.TransformationContext;
import org.jboss.dmr.ModelNode;

/**
 * Chained operation transformer implementation.
 * @author Paul Ferraro
 */
public class ChainedOperationTransformer implements OperationTransformer {

    private final List<OperationTransformer> transformers;
    private final boolean collate;

    public ChainedOperationTransformer(List<OperationTransformer> transformers) {
        this.transformers = transformers;
        this.collate = true;
    }

    /**
     * Constructs ChainedOperationTransformer with control over collation. Disable collation in cases where operations
     * cannot be collated (e.g. the original operation is no longer at the same path) and all
     * {@link OperationTransformer}s can deal with the fact.
     *
     * @param transformers list of transformers to process
     * @param collate      true if the results of the operation should be collated in a composite operation;
     *                     false if no further processing should be done on the resulting operations
     */
    public ChainedOperationTransformer(List<OperationTransformer> transformers, boolean collate) {
        this.transformers = transformers;
        this.collate = collate;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public TransformedOperation transformOperation(TransformationContext context, PathAddress address, ModelNode originalOperation) throws OperationFailedException {
        String originalName = Operations.getName(originalOperation);
        PathAddress originalAddress = Operations.getPathAddress(originalOperation);
        Deque<ModelNode> preSteps = new LinkedList<>();
        Deque<ModelNode> postSteps = new LinkedList<>();
        ModelNode operation = originalOperation;
        for (OperationTransformer transformer: this.transformers) {
            operation = transformer.transformOperation(context, address, operation).getTransformedOperation();
            // If the transformed operation is a composite operation, locate the modified operation and record any pre/post operations
            if (this.collate && operation.get(ModelDescriptionConstants.OP).asString().equals(ModelDescriptionConstants.COMPOSITE)) {
                List<ModelNode> stepList = operation.get(ModelDescriptionConstants.STEPS).asList();
                ListIterator<ModelNode> steps = stepList.listIterator();
                while (steps.hasNext()) {
                    ModelNode step = steps.next();
                    String operationName = Operations.getName(step);
                    PathAddress operationAddress = Operations.getPathAddress(step);
                    if (operationName.equals(originalName) && operationAddress.equals(originalAddress)) {
                        operation = step;
                        break;
                    }
                    preSteps.addLast(step);
                }
                steps = stepList.listIterator(stepList.size());
                while (steps.hasPrevious()) {
                    ModelNode step = steps.previous();
                    String operationName = Operations.getName(step);
                    PathAddress operationAddress = Operations.getPathAddress(step);
                    if (operationName.equals(originalName) && operationAddress.equals(originalAddress)) {
                        break;
                    }
                    postSteps.addFirst(step);
                }
            }
        }
        if (this.collate) {
            int count = preSteps.size() + postSteps.size() + 1;
            // If there are any pre or post steps, we need a composite operation
            if (count > 1) {
                List<ModelNode> steps = new ArrayList<>(count);
                steps.addAll(preSteps);
                steps.add(operation);
                steps.addAll(postSteps);
                operation = Operations.createCompositeOperation(steps);
            }
        }
        return new TransformedOperation(operation, OperationResultTransformer.ORIGINAL_RESULT);
    }
}


/*
 * 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.security.service;

import javax.security.auth.login.Configuration;

import org.jboss.as.security.SecurityExtension;
import org.jboss.as.security.logging.SecurityLogger;
import org.jboss.msc.service.Service;
import org.jboss.msc.service.ServiceName;
import org.jboss.msc.service.StartContext;
import org.jboss.msc.service.StartException;
import org.jboss.msc.service.StopContext;

/**
 * Jaas service to install a {@code Configuration}
 *
 * @author Marcus Moyses
 */
public class JaasConfigurationService implements Service<Configuration> {

    public static final ServiceName SERVICE_NAME = SecurityExtension.JBOSS_SECURITY.append("jaas");

    private final Configuration configuration;

    public JaasConfigurationService(Configuration configuration) {
        this.configuration = configuration;
    }

    /** {@inheritDoc} */
    @Override
    public void start(StartContext context) throws StartException {
        SecurityLogger.ROOT_LOGGER.debug("Starting JaasConfigurationService");

        // set new configuration
        synchronized(Configuration.class) {
            Configuration.setConfiguration(configuration);
        }
    }

    /** {@inheritDoc} */
    @Override
    public void stop(StopContext context) {
        // Trigger a reload of configuration if anything else uses it.
        synchronized(Configuration.class) {
            Configuration.setConfiguration(null);
        }
    }

    /** {@inheritDoc} */
    @Override
    public Configuration getValue() throws IllegalStateException, IllegalArgumentException {
        return configuration;
    }
}