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

import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.ServiceLoader;
import java.util.Set;
import java.util.function.BiConsumer;

import org.jboss.as.ee.component.ComponentDescription;
import org.jboss.as.ee.component.EEModuleDescription;
import org.jboss.as.server.deployment.Attachments;
import org.jboss.as.server.deployment.DeploymentPhaseContext;
import org.jboss.as.server.deployment.DeploymentUnit;
import org.jboss.as.server.deployment.DeploymentUnitProcessingException;
import org.jboss.as.server.deployment.DeploymentUnitProcessor;
import org.jboss.as.weld._private.WeldDeploymentMarker;
import org.jboss.as.weld.deployment.BeanDeploymentArchiveImpl;
import org.jboss.as.weld.deployment.BeanDeploymentArchiveImpl.BeanArchiveType;
import org.jboss.as.weld.deployment.ExplicitBeanArchiveMetadata;
import org.jboss.as.weld.deployment.ExplicitBeanArchiveMetadataContainer;
import org.jboss.as.weld.deployment.PropertyReplacingBeansXmlParser;
import org.jboss.as.weld.deployment.WeldAttachments;
import org.jboss.as.weld.deployment.processors.UrlScanner.ClassFile;
import org.jboss.as.weld.discovery.AnnotationType;
import org.jboss.as.weld.logging.WeldLogger;
import org.jboss.as.weld.spi.ComponentSupport;
import org.jboss.as.weld.spi.ModuleServicesProvider;
import org.jboss.as.weld.util.Reflections;
import org.jboss.as.weld.util.ServiceLoaders;
import org.jboss.jandex.AnnotationInstance;
import org.jboss.jandex.ClassInfo;
import org.jboss.jandex.DotName;
import org.jboss.jandex.Index;
import org.jboss.jandex.IndexReader;
import org.jboss.jandex.Indexer;
import org.jboss.modules.DependencySpec;
import org.jboss.modules.Module;
import org.jboss.modules.ModuleDependencySpec;
import org.jboss.modules.ModuleLoadException;
import org.jboss.modules.ModuleLoader;
import org.jboss.weld.bootstrap.api.Service;
import org.jboss.weld.bootstrap.spi.BeanDiscoveryMode;
import org.jboss.weld.bootstrap.spi.BeansXml;
import org.jboss.weld.xml.BeansXmlParser;
import org.wildfly.security.manager.WildFlySecurityManager;

/**
 * Deployment processor that builds bean archives from external deployments.
 *

 * This is only run at the top level, as multiple sub deployments can reference the same
 * beans.xml information, so we have to iterate through all bean deployment archives in this processor, to prevent
 * beans.xml from being potentially parsed twice.
 *

 *
 * @author Stuart Douglas
 * @author Jozef Hartinger
 */
public class ExternalBeanArchiveProcessor implements DeploymentUnitProcessor {

    private static final String META_INF_BEANS_XML = "META-INF/beans.xml";

    private static final String META_INF_JANDEX_IDX = "META-INF/jandex.idx";

    private final String ALL_KNOWN_CLASSES = "ALL_KNOWN_CLASSES";
    private final String BEAN_CLASSES = "BEAN_CLASSES";

    @Override
    public void deploy(DeploymentPhaseContext phaseContext) throws DeploymentUnitProcessingException {
        final DeploymentUnit deploymentUnit = phaseContext.getDeploymentUnit();

        if (!WeldDeploymentMarker.isPartOfWeldDeployment(deploymentUnit)) {
            return;
        }

        if (deploymentUnit.getParent() != null) {
            return;
        }

        final Set<String> componentClassNames = new HashSet<>();
        final ServiceLoader<ComponentSupport> supportServices = ServiceLoader.load(ComponentSupport.class,
                WildFlySecurityManager.getClassLoaderPrivileged(ExternalBeanArchiveProcessor.class));

        final String beanArchiveIdPrefix = deploymentUnit.getName() + ".external.";

        // This set is used for external bean archives with annotated discovery mode
        final Set<AnnotationType> beanDefiningAnnotations = new HashSet<>(deploymentUnit.getAttachment(WeldAttachments.BEAN_DEFINING_ANNOTATIONS));

        final List<DeploymentUnit> deploymentUnits = new ArrayList<DeploymentUnit>();
        deploymentUnits.add(deploymentUnit);
        deploymentUnits.addAll(deploymentUnit.getAttachmentList(Attachments.SUB_DEPLOYMENTS));

        PropertyReplacingBeansXmlParser parser = new PropertyReplacingBeansXmlParser(deploymentUnit);

        final HashSet<URL> existing = new HashSet<URL>();

        for (DeploymentUnit deployment : deploymentUnits) {
            try {
                final ExplicitBeanArchiveMetadataContainer weldDeploymentMetadata = deployment.getAttachment(ExplicitBeanArchiveMetadataContainer.ATTACHMENT_KEY);
                if (weldDeploymentMetadata != null) {
                    for (ExplicitBeanArchiveMetadata md : weldDeploymentMetadata.getBeanArchiveMetadata().values()) {
                        existing.add(md.getBeansXmlFile().toURL());
                        if (md.getAdditionalBeansXmlFile() != null) {
                            existing.add(md.getAdditionalBeansXmlFile().toURL());
                        }
                    }
                }
            } catch (MalformedURLException e) {
                throw new DeploymentUnitProcessingException(e);
            }

            EEModuleDescription moduleDesc = deployment.getAttachment(org.jboss.as.ee.component.Attachments.EE_MODULE_DESCRIPTION);
            if(moduleDesc != null) {
                for(ComponentDescription component : moduleDesc.getComponentDescriptions()) {
                    for (ComponentSupport support : supportServices) {
                        if (!support.isDiscoveredExternalType(component)) {
                            componentClassNames.add(component.getComponentClassName());
                            break;
                        }
                    }
                }
            }
        }

        final ServiceLoader<ModuleServicesProvider> moduleServicesProviders = ServiceLoader.load(ModuleServicesProvider.class,
                WildFlySecurityManager.getClassLoaderPrivileged(WeldDeploymentProcessor.class));

        for (DeploymentUnit deployment : deploymentUnits) {
            final Module module = deployment.getAttachment(Attachments.MODULE);
            if (module == null) {
                return;
            }
            for (DependencySpec dep : module.getDependencies()) {
                final Module dependency = loadModuleDependency(dep);
                if (dependency == null) {
                    continue;
                }
                Map<URL, URL> resourcesMap = findExportedResources(dependency);
                if (!resourcesMap.isEmpty()) {
                    List<BeanDeploymentArchiveImpl> moduleBdas = new ArrayList<>();
                    for (Entry<URL,URL> entry : resourcesMap.entrySet()) {
                        URL beansXmlUrl = entry.getKey();
                        if (existing.contains(beansXmlUrl)) {
                            continue;
                        }
                        /*
                         * Workaround for http://java.net/jira/browse/JAVASERVERFACES-2837
                         */
                        if (beansXmlUrl.toString().contains("jsf-impl-2.2")) {
                            continue;
                        }
                        /*
                         * Workaround for resteasy-cdi bundling beans.xml
                         */
                        if (beansXmlUrl.toString().contains("resteasy-cdi")) {
                            continue;
                        }

                        WeldLogger.DEPLOYMENT_LOGGER.debugf("Found external beans.xml: %s", beansXmlUrl.toString());
                        final BeansXml beansXml = parseBeansXml(beansXmlUrl, parser, deploymentUnit);

                        if (BeanDiscoveryMode.NONE.equals(beansXml.getBeanDiscoveryMode())) {
                            // Scanning suppressed per spec
                            continue;
                        }

                        Map<String, List<String>> allAndBeanClasses = discover(beansXml.getBeanDiscoveryMode(), beansXmlUrl, entry.getValue(),
                                beanDefiningAnnotations);
                        Collection<String> discoveredBeanClasses = allAndBeanClasses.get(BEAN_CLASSES);
                        Collection<String> allKnownClasses = allAndBeanClasses.get(ALL_KNOWN_CLASSES);
                        if (discoveredBeanClasses == null) {
                            // URL scanner probably does not understand the protocol
                            continue;
                        }
                        discoveredBeanClasses.removeAll(componentClassNames);

                        final BeanDeploymentArchiveImpl bda = new BeanDeploymentArchiveImpl(new HashSet<String>(discoveredBeanClasses), new HashSet<String>(allKnownClasses), beansXml, dependency, beanArchiveIdPrefix + beansXmlUrl.toExternalForm(), BeanArchiveType.EXTERNAL);
                        WeldLogger.DEPLOYMENT_LOGGER.beanArchiveDiscovered(bda);

                        // Add module services to external bean deployment archive
                        for (Entry<Class<? extends Service>, Service> moduleService : ServiceLoaders
                                .loadModuleServices(moduleServicesProviders, deploymentUnit, deployment, module, null).entrySet()) {
                            bda.getServices().add(moduleService.getKey(), Reflections.cast(moduleService.getValue()));
                        }

                        deploymentUnit.addToAttachmentList(WeldAttachments.ADDITIONAL_BEAN_DEPLOYMENT_MODULES, bda);
                        moduleBdas.add(bda);

                        // make sure that if this beans.xml is seen by some other module, it is not processed twice
                        existing.add(beansXmlUrl);
                    }
                    //BDA's from inside the same module have visibility on each other
                    for(BeanDeploymentArchiveImpl i : moduleBdas) {
                        for(BeanDeploymentArchiveImpl j : moduleBdas) {
                            if(i != j) {
                                i.addBeanDeploymentArchive(j);
                            }
                        }
                    }
                }
            }
        }
    }

    /**
     *
     * @param beanDiscoveryMode
     * @param beansXmlUrl
     * @param indexUrl
     * @param beanDefiningAnnotations
     * @return the set of discovered bean classes or null if unable to handle the provided beans.xml url
     */
    private Map<String, List<String>> discover(BeanDiscoveryMode beanDiscoveryMode, URL beansXmlUrl, URL indexUrl, Set<AnnotationType> beanDefiningAnnotations) {
        List<String> discoveredBeanClasses = new ArrayList<String>();
        List<String> allKnownClasses = new ArrayList<String>();
        BiConsumer<String, ClassFile> consumer;

        if (BeanDiscoveryMode.ANNOTATED.equals(beanDiscoveryMode)) {
            // We must only consider types with bean defining annotations
            Index index = tryLoadIndex(indexUrl);
            if (index != null) {
                // Use the provided index to find ClassInfo
                consumer = (name, classFile) -> {
                    ClassInfo classInfo = index.getClassByName(DotName.createSimple(name));
                    allKnownClasses.add(name);
                    if (classInfo != null && hasBeanDefiningAnnotation(classInfo, beanDefiningAnnotations)) {
                        discoveredBeanClasses.add(name);
                    }
                };
            } else {
                // Build ClassInfo on the fly
                Indexer indexer = new Indexer();
                consumer = (name, classFile) -> {
                    try (InputStream in = classFile.openStream()) {
                        ClassInfo classInfo = indexer.index(in);
                        allKnownClasses.add(name);
                        if (classInfo != null && hasBeanDefiningAnnotation(classInfo, beanDefiningAnnotations)) {
                            discoveredBeanClasses.add(name);
                        }
                    } catch (IOException e) {
                        WeldLogger.DEPLOYMENT_LOGGER.cannotIndexClassName(name, beansXmlUrl);
                    }
                };
            }
        } else {
            // Bean discovery mode ALL
            consumer = (name, classFile) -> {
                allKnownClasses.add(name);
                discoveredBeanClasses.add(name);
            };
        }
        Map<String, List<String>> result = new HashMap<>();
        result.put(ALL_KNOWN_CLASSES, allKnownClasses);
        result.put(BEAN_CLASSES, discoveredBeanClasses);
        UrlScanner scanner = new UrlScanner(beansXmlUrl, consumer);
        return scanner.scan() ? result : null;
    }

    private Index tryLoadIndex(URL indexUrl) {
        if (indexUrl == null) {
            return null;
        }
        try (InputStream in = indexUrl.openStream()) {
            return new IndexReader(in).read();
        } catch (Exception e) {
            WeldLogger.DEPLOYMENT_LOGGER.cannotLoadAnnotationIndexOfExternalBeanArchive(indexUrl);
            return null;
        }
    }

    /**
     * The entry key is bean.xml URL, value is (optional) jandex index URL.
     *
     * @param dependencyModule
     * @return the map of exported resources
     */
    private Map<URL, URL> findExportedResources(Module dependencyModule) {
        Set<URL> beanXmls = findExportedResource(dependencyModule, META_INF_BEANS_XML);
        if (beanXmls.isEmpty()) {
            return Collections.emptyMap();
        }
        Set<URL> indexes = findExportedResource(dependencyModule, META_INF_JANDEX_IDX);
        Map<URL, URL> ret = new HashMap<>();
        for (URL beansXml : beanXmls) {
            String urlBase = beansXml.toString().substring(0, beansXml.toString().length() - META_INF_BEANS_XML.length());
            URL idx = null;
            for (URL index : indexes) {
                if (index.toString().startsWith(urlBase)) {
                    idx = index;
                    break;
                }
            }
            ret.put(beansXml, idx);
        }
        return ret;
    }

    private Set<URL> findExportedResource(Module dependencyModule, String name) {
        Enumeration<URL> exported = dependencyModule.getExportedResources(name);
        return new HashSet<>(Collections.list(exported));
    }

    private boolean hasBeanDefiningAnnotation(ClassInfo classInfo, Set<AnnotationType> beanDefiningAnnotations) {
        Map<DotName, List<AnnotationInstance>> annotationsMap = classInfo.annotations();
        for (AnnotationType beanDefiningAnnotation : beanDefiningAnnotations) {
            List<AnnotationInstance> annotations = annotationsMap.get(beanDefiningAnnotation.getName());
            if (annotations != null) {
                for (AnnotationInstance annotationInstance : annotations) {
                    if (annotationInstance.target().equals(classInfo)) {
                        return true;
                    }
                }
            }
        }
        return false;
    }

    private Module loadModuleDependency(DependencySpec dep) {
        if (dep instanceof ModuleDependencySpec) {
            ModuleDependencySpec dependency = (ModuleDependencySpec) dep;
            final ModuleLoader loader = dependency.getModuleLoader();
            if (loader != null) {
                try {
                    return dependency.getModuleLoader().loadModule(dependency.getIdentifier());
                } catch (ModuleLoadException e) {
                    return null;
                }
            }
        }
        return null;
    }

    @Override
    public void undeploy(DeploymentUnit context) {
    }

    private BeansXml parseBeansXml(URL beansXmlFile, BeansXmlParser parser, final DeploymentUnit deploymentUnit) throws DeploymentUnitProcessingException {
        return parser.parse(beansXmlFile);
    }
}


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

import static org.wildfly.extension.messaging.activemq.jms.ConnectionFactoryAttributes.Common.ENTRIES;

import java.util.List;

import org.jboss.as.controller.AbstractRemoveStepHandler;
import org.jboss.as.controller.OperationContext;
import org.wildfly.extension.messaging.activemq.MessagingServices;
import org.jboss.as.naming.deployment.ContextNames;
import org.jboss.dmr.ModelNode;
import org.jboss.msc.service.ServiceName;

/**
 * @author Andy Taylor
 *         Date: 5/13/11
 *         Time: 3:30 PM
 */
public class PooledConnectionFactoryRemove extends AbstractRemoveStepHandler {

    public static final PooledConnectionFactoryRemove INSTANCE = new PooledConnectionFactoryRemove();

    @Override
    protected void performRuntime(OperationContext context, ModelNode operation, ModelNode model) {
        ServiceName serviceName = MessagingServices.getActiveMQServiceName(context.getCurrentAddress());
        context.removeService(JMSServices.getPooledConnectionFactoryBaseServiceName(serviceName).append(context.getCurrentAddressValue()));
        removeJNDIAliases(context, model.require(ENTRIES.getName()).asList());
    }

    @Override
    protected void recoverServices(OperationContext context, ModelNode operation, ModelNode model) {
        // TODO:  RE-ADD SERVICES
    }

    /**
     * Remove JNDI alias' binder services.
     *
     * The 1st JNDI entry is not removed by this method as it is already handled when removing
     * the pooled-connection-factory service
     */
    protected void removeJNDIAliases(OperationContext context, List<ModelNode> entries) {
        if (entries.size() > 1) {
            for (int i = 1; i < entries.size() ; i++) {
                ContextNames.BindInfo aliasBindInfo = ContextNames.bindInfoFor(entries.get(i).asString());
                context.removeService(aliasBindInfo.getBinderServiceName());
            }
        }
    }
}


/*
 * JBoss, Home of Professional Open Source
 * Copyright 2018, Red Hat Middleware LLC, and individual contributors
 * by the @authors tag. See the copyright.txt in the distribution for a
 * full listing of individual contributors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.jboss.as.jpa.hibernate5.service;

import javax.transaction.Status;
import javax.transaction.Synchronization;
import javax.transaction.TransactionSynchronizationRegistry;

import org.hibernate.engine.transaction.jta.platform.internal.JBossAppServerJtaPlatform;
import org.hibernate.engine.transaction.jta.platform.internal.JtaSynchronizationStrategy;
import org.wildfly.common.Assert;

/**
 * WildFlyCustomJtaPlatform can obtain the JTA TransactionSynchronizationRegistry to be used by
 * Hibernate ORM JPA + native applications.
 * For JPA applications, we could of passed the TransactionSynchronizationRegistry into the
 * constructor but Hibernate native apps wouldn't be able to do that, so this covers all app types.
 *
 * @author Scott Marlow
 */
public class WildFlyCustomJtaPlatform extends JBossAppServerJtaPlatform implements JtaSynchronizationStrategy {

    // The 'transactionSynchronizationRegistry' used by JPA container managed applications,
    // is reset every time the Transaction Manager service is restarted,
    // as (application deployment) JPA persistence unit service depends on the TM service.
    // For this reason, the static 'transactionSynchronizationRegistry' can be updated.
    // Note that Hibernate native applications currently have to be (manually) restarted when the TM
    // service restarts, as native applications do not have WildFly service dependencies set for them.
    private static volatile TransactionSynchronizationRegistry transactionSynchronizationRegistry;
    private static final String TSR_NAME = "java:jboss/TransactionSynchronizationRegistry";

    // JtaSynchronizationStrategy
    @Override
    public void registerSynchronization(Synchronization synchronization) {
        locateTransactionSynchronizationRegistry().
                registerInterposedSynchronization(synchronization);
    }

    // JtaSynchronizationStrategy
    @Override
    public boolean canRegisterSynchronization() {
        return locateTransactionSynchronizationRegistry().
                getTransactionStatus() == Status.STATUS_ACTIVE;
    }

    @Override
    protected JtaSynchronizationStrategy getSynchronizationStrategy() {
        return this;
    }

    private TransactionSynchronizationRegistry locateTransactionSynchronizationRegistry() {
        TransactionSynchronizationRegistry curTsr = transactionSynchronizationRegistry;
        return curTsr != null ? curTsr : (TransactionSynchronizationRegistry) jndiService().locate(TSR_NAME);
    }

    /**
     * Hibernate native applications cannot know when the TransactionManager + TransactionSynchronizationRegistry
     * services are stopped but JPA container managed applications can and will call setTransactionSynchronizationRegistry
     * with the new (global) TransactionSynchronizationRegistry to use.
     *
     * @param tsr
     */
    public static void setTransactionSynchronizationRegistry(TransactionSynchronizationRegistry tsr) {

        if ((Assert.checkNotNullParam("tsr", tsr)) != transactionSynchronizationRegistry) {
            synchronized (WildFlyCustomJtaPlatform.class) {
                if (tsr != transactionSynchronizationRegistry) {
                    transactionSynchronizationRegistry = tsr;
                }
            }
        }
    }

}


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

package org.jboss.as.ejb3.subsystem;

import java.util.function.Consumer;

import org.jboss.ejb.client.EJBClientContext;
import org.jboss.ejb.client.EJBTransportProvider;
import org.jboss.ejb.protocol.remote.RemoteTransportProvider;
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;
import org.jboss.msc.value.InjectedValue;
import org.jboss.remoting3.Endpoint;
import org.wildfly.httpclient.ejb.HttpClientProvider;

/**
 * A service to configure an {@code EJBClientContext} with any information defined in the subsystem model.
 *
 * @author David M. Lloyd
 */
public final class EJBClientConfiguratorService implements Consumer<EJBClientContext.Builder>, Service<EJBClientConfiguratorService> {

    public static final ServiceName SERVICE_NAME = ServiceName.JBOSS.append("ejb", "client", "configurator");

    private final InjectedValue<Endpoint> endpointInjector = new InjectedValue<>();

    private volatile EJBTransportProvider remoteTransportProvider;
    private volatile EJBTransportProvider remoteHttpTransportProvider;

    public void start(final StartContext context) throws StartException {
        remoteTransportProvider = new RemoteTransportProvider();
        remoteHttpTransportProvider = new HttpClientProvider();
    }

    public void stop(final StopContext context) {
        remoteTransportProvider = null;
        remoteHttpTransportProvider = null;
    }

    public EJBClientConfiguratorService getValue() throws IllegalStateException, IllegalArgumentException {
        return this;
    }

    /**
     * Perform the configuration of the transport provider.
     *
     * @param builder the EJB client context builder (not {@code null})
     */
    public void accept(final EJBClientContext.Builder builder) {
        final EJBTransportProvider remoteTransportProvider = this.remoteTransportProvider;
        if (remoteTransportProvider != null) {
            builder.addTransportProvider(remoteTransportProvider);
            builder.addTransportProvider(remoteHttpTransportProvider);
        }
    }

    /**
     * Get the endpoint injector.  This is populated only when the Remoting subsystem is present.
     *
     * @return the endpoint injector
     */
    public InjectedValue<Endpoint> getEndpointInjector() {
        return endpointInjector;
    }
}


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

import org.jboss.as.naming.ImmediateManagedReference;
import org.jboss.as.naming.ManagedReference;
import org.jboss.as.naming.ManagedReferenceFactory;
import org.jboss.as.naming.NamingContext;
import org.jboss.as.naming.NamingStore;
import org.jboss.as.naming.context.external.ExternalContexts;
import org.jboss.as.server.CurrentServiceContainer;
import org.jboss.as.server.deployment.DeploymentUnit;
import org.jboss.as.naming.logging.NamingLogger;
import org.jboss.msc.inject.InjectionException;
import org.jboss.msc.inject.Injector;
import org.jboss.msc.service.ServiceBuilder;
import org.jboss.msc.service.ServiceContainer;
import org.jboss.msc.service.ServiceName;

import javax.naming.NamingException;

/**
 * @author John Bailey
 * @author Eduardo Martins
 */
public class ContextNames {

    /**
     * Parent ServiceName for all naming services.
     */
    public static final ServiceName NAMING = ServiceName.JBOSS.append("naming");

    /**
     * ServiceName for java: namespace
     */
    public static final ServiceName JAVA_CONTEXT_SERVICE_NAME = NAMING.append("context", "java");

    /**
     * Parent ServiceName for java:comp namespace
     */
    public static final ServiceName COMPONENT_CONTEXT_SERVICE_NAME = JAVA_CONTEXT_SERVICE_NAME.append("comp");

    /**
     * ServiceName for java:jboss namespace
     */
    public static final ServiceName JBOSS_CONTEXT_SERVICE_NAME = JAVA_CONTEXT_SERVICE_NAME.append("jboss");

    /**
     * ServiceName for java:global namespace
     */
    public static final ServiceName GLOBAL_CONTEXT_SERVICE_NAME = JAVA_CONTEXT_SERVICE_NAME.append("global");

    /**
     * Parent ServiceName for java:app namespace
     */
    public static final ServiceName APPLICATION_CONTEXT_SERVICE_NAME = JAVA_CONTEXT_SERVICE_NAME.append("app");

    /**
     * Parent ServiceName for java:module namespace
     */
    public static final ServiceName MODULE_CONTEXT_SERVICE_NAME = JAVA_CONTEXT_SERVICE_NAME.append("module");

    /**
     * ServiceName for java:jboss/exported namespace
     */
    public static final ServiceName EXPORTED_CONTEXT_SERVICE_NAME = JBOSS_CONTEXT_SERVICE_NAME.append("exported");

    /**
     * Get the base service name of a component's JNDI namespace.
     *
     * @param app    the application name (must not be {@code null})
     * @param module the module name (must not be {@code null})
     * @param comp   the component name (must not be {@code null})
     * @return the base service name
     */
    public static ServiceName contextServiceNameOfComponent(String app, String module, String comp) {
        return COMPONENT_CONTEXT_SERVICE_NAME.append(app, module, comp);
    }

    /**
     * Get the base service name of a module's JNDI namespace.
     *
     * @param app    the application name (must not be {@code null})
     * @param module the module name (must not be {@code null})
     * @return the base service name
     */
    public static ServiceName contextServiceNameOfModule(String app, String module) {
        return MODULE_CONTEXT_SERVICE_NAME.append(app, module);
    }

    /**
     * Get the base service name of an application's JNDI namespace.
     *
     * @param app the application name (must not be {@code null})
     * @return the base service name
     */
    public static ServiceName contextServiceNameOfApplication(String app) {
        return APPLICATION_CONTEXT_SERVICE_NAME.append(app);
    }

    /**
     * Get the service name of a context, or {@code null} if there is no service mapping for the context name.
     *
     * @param app     the application name
     * @param module  the module name
     * @param comp    the component name
     * @param context the context to check
     * @return the BindInfo
     */
    public static BindInfo bindInfoFor(String app, String module, String comp, String context) {
        if (context.startsWith("java:")) {
            final String namespace;
            final int i = context.indexOf('/');
            if (i == -1) {
                namespace = context.substring(5);
            } else if (i == 5) {
                // Absolute path
                return new BindInfo(JAVA_CONTEXT_SERVICE_NAME, context.substring(6));
            } else {
                namespace = context.substring(5, i);
            }

            sanitazeNameSpace(namespace,context);
            if (namespace.equals("global")) {
                return new BindInfo(GLOBAL_CONTEXT_SERVICE_NAME, context.substring(12));
            } else if (namespace.equals("jboss")) {
                String rest = context.substring(i);
                if(rest.startsWith("/exported/")) {
                    return new BindInfo(EXPORTED_CONTEXT_SERVICE_NAME, context.substring(20));
                } else {
                    return new BindInfo(JBOSS_CONTEXT_SERVICE_NAME, context.substring(11));
                }
            } else if (namespace.equals("app")) {
                return new BindInfo(contextServiceNameOfApplication(app), context.substring(9));
            } else if (namespace.equals("module")) {
                return new BindInfo(contextServiceNameOfModule(app, module), context.substring(12));
            } else if (namespace.equals("comp")) {
                return new BindInfo(contextServiceNameOfComponent(app, module, comp), context.substring(10));
            } else {
                return new BindInfo(JBOSS_CONTEXT_SERVICE_NAME, context);
            }
        } else {
            return null;
        }
    }

    private static void sanitazeNameSpace(final String namespace, final String inContext) {
        //URL might be:
        // java:context/restOfURL - where nameSpace is part between ':' and '/'
        if(namespace.contains(":")){
            throw NamingLogger.ROOT_LOGGER.invalidJndiName(inContext);
        }
    }
    /**
     * Get the service name of an environment entry
     *
     * @param app              the application name
     * @param module           the module name
     * @param comp             the component name
     * @param useCompNamespace If the component has its own comp namespace
     * @param envEntryName     The env entry name
     * @return the service name or {@code null} if there is no service
     */
    public static BindInfo bindInfoForEnvEntry(String app, String module, String comp, boolean useCompNamespace, final String envEntryName) {
        if (envEntryName.startsWith("java:")) {
            if (useCompNamespace) {
                return bindInfoFor(app, module, comp, envEntryName);
            } else {
                if (envEntryName.startsWith("java:comp")) {
                    return bindInfoFor(app, module, module, "java:module" + envEntryName.substring("java:comp".length()));
                } else {
                    return bindInfoFor(app, module, module, envEntryName);
                }
            }
        } else {
            if (useCompNamespace) {
                return bindInfoFor(app, module, comp, "java:comp/env/" + envEntryName);
            } else {
                return bindInfoFor(app, module, module, "java:module/env/" + envEntryName);
            }
        }
    }

    public static ServiceName buildServiceName(final ServiceName parentName, final String relativeName) {
        return parentName.append(relativeName.split("/"));
    }

    public static class BindInfo {
        private final ServiceName parentContextServiceName;
        private final ServiceName binderServiceName;
        private final String bindName;
        // absolute jndi name inclusive of the namespace
        private final String absoluteJndiName;

        private BindInfo(final ServiceName parentContextServiceName, final String bindName) {
            this.parentContextServiceName = parentContextServiceName;
            this.binderServiceName = buildServiceName(parentContextServiceName, bindName);
            this.bindName = bindName;

            this.absoluteJndiName = this.generateAbsoluteJndiName();
        }

        /**
         * The service name for the target namespace the binding will occur.
         *
         * @return The target service name
         */
        public ServiceName getParentContextServiceName() {
            return parentContextServiceName;
        }

        /**
         * The service name for binder
         *
         * @return the binder service name
         */
        public ServiceName getBinderServiceName() {
            return binderServiceName;
        }

        /**
         * The name for the binding
         *
         * @return The binding name
         */
        public String getBindName() {
            return bindName;
        }

        /**
         * Returns the absolute jndi name of this {@link BindInfo}. The absolute jndi name is inclusive of the jndi namespace
         *
         * @return
         */
        public String getAbsoluteJndiName() {
            return this.absoluteJndiName;
        }

        public String toString() {
            return "BindInfo{" +
                    "parentContextServiceName=" + parentContextServiceName +
                    ", binderServiceName=" + binderServiceName +
                    ", bindName='" + bindName + '\'' +
                    '}';
        }

        private String generateAbsoluteJndiName() {
            final StringBuffer sb = new StringBuffer();
            if (this.parentContextServiceName.equals(ContextNames.EXPORTED_CONTEXT_SERVICE_NAME)) {
                sb.append("java:jboss/exported/");
            } else if (this.parentContextServiceName.equals(ContextNames.JBOSS_CONTEXT_SERVICE_NAME)) {
                sb.append("java:jboss/");
            } else if (this.parentContextServiceName.equals(ContextNames.APPLICATION_CONTEXT_SERVICE_NAME)) {
                sb.append("java:app/");
            } else if (this.parentContextServiceName.equals(ContextNames.MODULE_CONTEXT_SERVICE_NAME)) {
                sb.append("java:module/");
            } else if (this.parentContextServiceName.equals(ContextNames.COMPONENT_CONTEXT_SERVICE_NAME)) {
                sb.append("java:comp/");
            } else if (this.parentContextServiceName.equals(ContextNames.GLOBAL_CONTEXT_SERVICE_NAME)) {
                sb.append("java:global/");
            } else if (this.parentContextServiceName.equals(ContextNames.JAVA_CONTEXT_SERVICE_NAME)) {
                sb.append("java:/");
            }
            sb.append(this.bindName);
            return sb.toString();
        }

        /**
         * Setup a lookup with respect to {@link javax.annotation.Resource} injection.
         *
         * @param serviceBuilder the builder that should depend on the lookup
         * @param targetInjector the injector which will receive the lookup result once the builded service starts
         */
        public void setupLookupInjection(final ServiceBuilder<?> serviceBuilder,
                final Injector<ManagedReferenceFactory> targetInjector, final DeploymentUnit deploymentUnit, final boolean optional) {

            // set dependency to the binder or its parent external context's service name
            final ExternalContexts externalContexts = deploymentUnit.getAttachment(Attachments.EXTERNAL_CONTEXTS);
            final ServiceName parentExternalContextServiceName = externalContexts != null ? externalContexts.getParentExternalContext(getBinderServiceName()) : null;
            final ServiceName dependencyServiceName = parentExternalContextServiceName == null ? getBinderServiceName() : parentExternalContextServiceName;
            final ServiceContainer container = CurrentServiceContainer.getServiceContainer();
            if (optional) {
                if (container.getService(dependencyServiceName) != null) serviceBuilder.requires(dependencyServiceName);
            } else {
                serviceBuilder.requires(dependencyServiceName);
            }

            // an injector which upon being injected with the naming store, injects a factory - which does the lookup - to the
            // target injector
            final Injector<NamingStore> lookupInjector = new Injector<NamingStore>() {
                @Override
                public void uninject() {
                    targetInjector.uninject();
                }
                @Override
                public void inject(final NamingStore value) throws InjectionException {
                    final NamingContext storeBaseContext = new NamingContext(value, null);
                    final ManagedReferenceFactory factory = new ManagedReferenceFactory() {
                        @Override
                        public ManagedReference getReference() {
                            try {
                                return new ImmediateManagedReference(storeBaseContext.lookup(getBindName()));
                            } catch (NamingException e) {
                                if(!optional) {
                                    throw NamingLogger.ROOT_LOGGER.resourceLookupForInjectionFailed(getAbsoluteJndiName(), e);
                                } else {
                                    NamingLogger.ROOT_LOGGER.tracef(e,"failed to lookup %s", getAbsoluteJndiName());
                                }
                            }
                            return null;
                        }
                    };
                    targetInjector.inject(factory);
                }
            };
            // sets dependency to the parent context service (holds the naming store), which will trigger the lookup injector
            serviceBuilder.addDependency(getParentContextServiceName(), NamingStore.class, lookupInjector);
        }

    }

    /**
     * Get the service name of a NamingStore
     *
     * @param jndiName the jndi name
     * @return the bind info for the jndi name
     */
    public static BindInfo bindInfoFor(final String jndiName) {
        // TODO: handle non java: schemes
        String bindName;
        if (jndiName.startsWith("java:")) {
            bindName = jndiName.substring(5);
        } else if (!jndiName.startsWith("jboss") && !jndiName.startsWith("global") && !jndiName.startsWith("/")) {
            bindName = "/" + jndiName;
        } else {
            bindName = jndiName;
        }
        final ServiceName parentContextName;
        if(bindName.startsWith("jboss/exported/")) {
            parentContextName = EXPORTED_CONTEXT_SERVICE_NAME;
            bindName = bindName.substring(15);
        } else if (bindName.startsWith("jboss/")) {
            parentContextName = JBOSS_CONTEXT_SERVICE_NAME;
            bindName = bindName.substring(6);
        } else if (bindName.startsWith("global/")) {
            parentContextName = GLOBAL_CONTEXT_SERVICE_NAME;
            bindName = bindName.substring(7);
        } else if (bindName.startsWith("/")) {
            parentContextName = JAVA_CONTEXT_SERVICE_NAME;
            bindName = bindName.substring(1);
        } else {
            throw NamingLogger.ROOT_LOGGER.illegalContextInName(jndiName);
        }
        return new BindInfo(parentContextName, bindName);
    }
}


/*
 * 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.wildfly.extension.picketlink.idm.jpa.transaction;

import org.wildfly.extension.picketlink.logging.PicketLinkLogger;

import javax.persistence.EntityManager;
import javax.transaction.Transaction;
import javax.transaction.TransactionManager;
import javax.transaction.TransactionSynchronizationRegistry;

/**
 *
A helper that knows how to associate {@link javax.persistence.EntityManager} instances with active transactions.

 *
 * @author Pedro Igor (reusing code from JPA subsystem)
 */
public class TransactionalEntityManagerHelper {

    private final TransactionSynchronizationRegistry transactionSynchronizationRegistry;
    private final TransactionManager transactionManager;

    public TransactionalEntityManagerHelper(TransactionSynchronizationRegistry transactionSynchronizationRegistry,
        TransactionManager transactionManager) {
        this.transactionSynchronizationRegistry = transactionSynchronizationRegistry;
        this.transactionManager = transactionManager;
    }

    /**
     * Get current persistence context.  Only call while a transaction is active in the current thread.
     *
     * @param puScopedName
     * @return
     */
    public EntityManager getTransactionScopedEntityManager(String puScopedName) {
        return (EntityManager) this.transactionSynchronizationRegistry.getResource(puScopedName);
    }

    /**
     * Save the specified EntityManager in the local threads active transaction.  The TransactionSynchronizationRegistry
     * will clear the reference to the EntityManager when the transaction completes.
     *
     * @param scopedPuName
     * @param entityManager
     */
    public  void putEntityManagerInTransactionRegistry(String scopedPuName, EntityManager entityManager) {
        try {
            Transaction transaction = this.transactionManager.getTransaction();

            transaction.registerSynchronization(new TransactionalEntityManagerSynchronization(entityManager));

            this.transactionSynchronizationRegistry.putResource(scopedPuName, entityManager);
        } catch (Exception e) {
            throw PicketLinkLogger.ROOT_LOGGER.idmJpaFailedCreateTransactionEntityManager(e);
        }
    }
}


/*
 * 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.jboss.as.connector.util;

import static javax.xml.stream.XMLStreamConstants.END_ELEMENT;
import static javax.xml.stream.XMLStreamConstants.START_ELEMENT;
import static org.jboss.as.controller.parsing.ParseUtils.requireSingleAttribute;

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

import org.jboss.as.controller.PropertiesAttributeDefinition;
import org.jboss.as.controller.SimpleAttributeDefinition;
import org.jboss.as.controller.parsing.ParseUtils;
import org.jboss.dmr.ModelNode;
import org.jboss.jca.common.CommonBundle;
import org.jboss.jca.common.api.metadata.common.Extension;
import org.jboss.jca.common.api.validator.ValidateException;
import org.jboss.logging.Messages;
import org.jboss.staxmapper.XMLExtendedStreamReader;

/**
 * An AbstractParser.
 *
 * @author Stefano Maestri
 */
public abstract class AbstractParser {
    /**
     * The bundle
     */
    private static CommonBundle bundle = Messages.getBundle(CommonBundle.class);

    /**
     * Reads and trims the element text and returns it or {@code null}
     *
     * @param reader  source for the element text
     * @return the string representing the trimmed element text or {@code null} if there is none or it is an empty string
     * @throws XMLStreamException
     */
    public String rawElementText(XMLStreamReader reader) throws XMLStreamException {
        String elementText = reader.getElementText();
        elementText = elementText == null || elementText.trim().length() == 0 ? null : elementText.trim();
        return elementText;
    }

    /**
     * Reads and trims the text for the given attribute and returns it or {@code null}
     *
     * @param reader source for the attribute text
     * @param attributeName  the name of the attribute
     * @return the string representing trimmed attribute text or {@code null} if there is none
     */
    public String rawAttributeText(XMLStreamReader reader, String attributeName) {
        return rawAttributeText(reader, attributeName, null);
    }

    /**
     * Reads and trims the text for the given attribute and returns it or {@code defaultValue} if there is no
     * value for the attribute
     * @param reader source for the attribute text
     * @param attributeName  the name of the attribute
     * @param defaultValue value to return if there is no value for the attribute
     * @return the string representing raw attribute text or {@code defaultValue} if there is none
     */
    public String rawAttributeText(XMLStreamReader reader, String attributeName, String defaultValue) {
        return reader.getAttributeValue("", attributeName) == null
                ? defaultValue :
                reader.getAttributeValue("", attributeName).trim();
    }

    protected void parseExtension(XMLExtendedStreamReader reader, String enclosingTag, final ModelNode operation,
                                  final SimpleAttributeDefinition extensionClassName, final PropertiesAttributeDefinition extensionProperties)
            throws XMLStreamException, ParserException, ValidateException {

        for (Extension.Attribute attribute : Extension.Attribute.values()) {
            switch (attribute) {
                case CLASS_NAME: {
                    requireSingleAttribute(reader, attribute.getLocalName());
                    final String value = reader.getAttributeValue(0);
                    extensionClassName.parseAndSetParameter(value, operation, reader);
                    break;

                }
                default:
                    break;
            }
        }

        while (reader.hasNext()) {
            switch (reader.nextTag()) {
                case END_ELEMENT: {
                    if (reader.getLocalName().equals(enclosingTag)) {
                        //It's fine doing nothing
                        return;
                    } else {
                        if (Extension.Tag.forName(reader.getLocalName()) == Extension.Tag.UNKNOWN) {
                            throw ParseUtils.unexpectedEndElement(reader);
                        }
                    }
                    break;
                }
                case START_ELEMENT: {
                    switch (Extension.Tag.forName(reader.getLocalName())) {
                        case CONFIG_PROPERTY: {
                            requireSingleAttribute(reader, "name");
                            final String name = reader.getAttributeValue(0);
                            String value = rawElementText(reader);
                            final String trimmed = value == null ? null : value.trim();
                            extensionProperties.parseAndAddParameterElement(name, trimmed, operation, reader);
                            break;
                        }
                        default:
                            throw new ParserException(bundle.unexpectedElement(reader.getLocalName()));
                    }
                    break;
                }
            }
        }
        throw new ParserException(bundle.unexpectedEndOfDocument());
    }

}


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

package org.jboss.as.ejb3.deployment;

import org.jboss.as.ejb3.security.EjbJaccConfig;
import org.jboss.as.ejb3.security.EjbJaccService;
import org.jboss.as.security.deployment.AbstractSecurityDeployer;
import org.jboss.as.security.service.JaccService;
import org.jboss.as.server.deployment.AttachmentKey;
import org.jboss.as.server.deployment.AttachmentList;

/**
 * Handles ejb jar deployments
 *
 * @author Marcus Moyses
 */
public class EjbSecurityDeployer extends AbstractSecurityDeployer<AttachmentList<EjbJaccConfig>> {

    /**
     * {@inheritDoc}
     */
    @Override
    protected AttachmentKey<AttachmentList<EjbJaccConfig>> getMetaDataType() {
        return EjbDeploymentAttachmentKeys.JACC_PERMISSIONS;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    protected JaccService<AttachmentList<EjbJaccConfig>> createService(String contextId, AttachmentList<EjbJaccConfig> metaData, Boolean standalone) {
        return new EjbJaccService(contextId, metaData, standalone);
    }
}


/*
 * 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.wildfly.iiop.openjdk.service;

import org.jboss.as.naming.ServiceBasedNamingStore;
import org.jboss.as.naming.ValueManagedReferenceFactory;
import org.jboss.as.naming.deployment.ContextNames;
import org.jboss.as.naming.service.BinderService;
import org.jboss.msc.service.ServiceTarget;
import org.jboss.msc.value.Values;

/**
 *

 * Utility class used by the CORBA related services.
 *

 *
 * @author Stefan Guilhen
 */
public class CorbaServiceUtil {

    /**
     *

     * Private constructor as required by the {@code Singleton} pattern.
     *

     */
    private CorbaServiceUtil() {
    }

    /**
     *

     * Adds a {@code BinderService} to the specified target. The service binds the specified value to JNDI under the
     * {@code java:/jboss/contextName} context.
     *

     *
     * @param target      the {@code ServiceTarget} where the service will be added.
     * @param contextName the JNDI context name where the value will be bound.
     * @param value       the value to be bound.
     */
    public static void bindObject(final ServiceTarget target, final String contextName, final Object value) {
        final BinderService binderService = new BinderService(contextName);
        binderService.getManagedObjectInjector().inject(new ValueManagedReferenceFactory(Values.immediateValue(value)));
        target.addService(ContextNames.buildServiceName(ContextNames.JBOSS_CONTEXT_SERVICE_NAME, contextName), binderService)
                .addDependency(ContextNames.JBOSS_CONTEXT_SERVICE_NAME, ServiceBasedNamingStore.class, binderService.getNamingStoreInjector())
                .install();
    }
}


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

import java.security.Principal;
import java.util.concurrent.ConcurrentMap;

import org.jboss.as.security.lru.LRUCache;
import org.jboss.security.authentication.JBossCachedAuthenticationManager.DomainInfo;

/**
 * Factory that creates default {@code ConcurrentMap}s for authentication cache.
 *
 * @author Marcus Moyses
 */
public class DefaultAuthenticationCacheFactory implements AuthenticationCacheFactory {

    /**
     * Returns a default cache implementation
     *
     * @return cache implementation
     */
    public ConcurrentMap<Principal, DomainInfo> getCache() {
        return new LRUCache<>(1000, (key, value) -> {
            if (value != null) {
                value.logout();
            }
        });
    }
}


/*
 * 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.AliasDef;
import org.omg.CORBA.Any;
import org.omg.CORBA.AttributeDef;
import org.omg.CORBA.AttributeDescription;
import org.omg.CORBA.AttributeMode;
import org.omg.CORBA.ConstantDef;
import org.omg.CORBA.Contained;
import org.omg.CORBA.ContainedPackage.Description;
import org.omg.CORBA.DefinitionKind;
import org.omg.CORBA.EnumDef;
import org.omg.CORBA.ExceptionDef;
import org.omg.CORBA.IDLType;
import org.omg.CORBA.IRObject;
import org.omg.CORBA.Initializer;
import org.omg.CORBA.InterfaceDef;
import org.omg.CORBA.InterfaceDefHelper;
import org.omg.CORBA.ModuleDef;
import org.omg.CORBA.NativeDef;
import org.omg.CORBA.OperationDef;
import org.omg.CORBA.OperationDescription;
import org.omg.CORBA.OperationMode;
import org.omg.CORBA.ParameterDescription;
import org.omg.CORBA.StructDef;
import org.omg.CORBA.StructMember;
import org.omg.CORBA.TCKind;
import org.omg.CORBA.TypeCode;
import org.omg.CORBA.TypeCodePackage.BadKind;
import org.omg.CORBA.UnionDef;
import org.omg.CORBA.UnionMember;
import org.omg.CORBA.VM_ABSTRACT;
import org.omg.CORBA.VM_CUSTOM;
import org.omg.CORBA.VM_NONE;
import org.omg.CORBA.ValueBoxDef;
import org.omg.CORBA.ValueDef;
import org.omg.CORBA.ValueDefHelper;
import org.omg.CORBA.ValueDefOperations;
import org.omg.CORBA.ValueDefPOATie;
import org.omg.CORBA.ValueDefPackage.FullValueDescription;
import org.omg.CORBA.ValueDescription;
import org.omg.CORBA.ValueDescriptionHelper;
import org.omg.CORBA.ValueMember;
import org.omg.CORBA.ValueMemberDef;
import org.wildfly.iiop.openjdk.logging.IIOPLogger;

/**
 * Interface IR object.
 *
 * @author Ole Husgaard
 * @version $Revision: 81018 $
 */
class ValueDefImpl  extends ContainedImpl  implements ValueDefOperations, LocalContainer, LocalContainedIDLType {

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

    ValueDefImpl(String id, String name, String version,
                 LocalContainer defined_in,
                 boolean is_abstract, boolean is_custom,
                 String[] supported_interfaces,
                 String[] abstract_base_valuetypes,
                 TypeCode baseValueTypeCode,
                 RepositoryImpl repository) {
        super(id, name, version, defined_in,
                DefinitionKind.dk_Value, repository);

        this.is_abstract = is_abstract;
        this.is_custom = is_custom;
        this.supported_interfaces = supported_interfaces;
        this.abstract_base_valuetypes = abstract_base_valuetypes;
        this.baseValueTypeCode = baseValueTypeCode;
        this.delegate = new ContainerImplDelegate(this);
    }

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

    // LocalContainer implementation ---------------------------------

    public LocalContained _lookup(String search_name) {
        return delegate._lookup(search_name);
    }

    public LocalContained[] _contents(DefinitionKind limit_type,
                                      boolean exclude_inherited) {
        return delegate._contents(limit_type, exclude_inherited);
    }

    public LocalContained[] _lookup_name(String search_name,
                                         int levels_to_search,
                                         DefinitionKind limit_type,
                                         boolean exclude_inherited) {
        return delegate._lookup_name(search_name, levels_to_search, limit_type,
                exclude_inherited);
    }

    public void add(String name, LocalContained contained)
            throws IRConstructionException {
        delegate.add(name, contained);
    }

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

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

    public void allDone()
            throws IRConstructionException {
        getReference();
        delegate.allDone();

        if (baseValueTypeCode != null && baseValueTypeCode.kind() != TCKind.tk_null) {
            try {
                baseValue = baseValueTypeCode.id();
            } catch (BadKind ex) {
                throw IIOPLogger.ROOT_LOGGER.badKindForSuperValueType(id());
            }
            Contained c = repository.lookup_id(baseValue);
            base_value_ref = ValueDefHelper.narrow(c);
        } else
            baseValue = "IDL:omg.org/CORBA/ValueBase:1.0"; // TODO: is this right?

        // Resolve supported interfaces
        supported_interfaces_ref = new InterfaceDef[supported_interfaces.length];
        for (int i = 0; i < supported_interfaces.length; ++i) {
            InterfaceDef iDef = InterfaceDefHelper.narrow(
                    repository.lookup_id(supported_interfaces[i]));
            if (iDef == null)
                throw IIOPLogger.ROOT_LOGGER.errorResolvingRefToImplementedInterface(id(), supported_interfaces[i]);
            supported_interfaces_ref[i] = iDef;
        }

        // Resolve abstract base valuetypes
        abstract_base_valuetypes_ref =
                new ValueDef[abstract_base_valuetypes.length];
        for (int i = 0; i < abstract_base_valuetypes.length; ++i) {
            ValueDef vDef = ValueDefHelper.narrow(
                    repository.lookup_id(abstract_base_valuetypes[i]));
            if (vDef == null)
                throw IIOPLogger.ROOT_LOGGER.errorResolvingRefToAbstractValuetype(id(), abstract_base_valuetypes[i]);
            abstract_base_valuetypes_ref[i] = vDef;
        }
    }

    public void shutdown() {
        delegate.shutdown();
        super.shutdown();
    }

    // ContainerOperations implementation ----------------------------

    public Contained lookup(String search_name) {
        return delegate.lookup(search_name);
    }

    public Contained[] contents(DefinitionKind limit_type,
                                boolean exclude_inherited) {
        return delegate.contents(limit_type, exclude_inherited);
    }

    public Contained[] lookup_name(String search_name, int levels_to_search,
                                   DefinitionKind limit_type,
                                   boolean exclude_inherited) {
        return delegate.lookup_name(search_name, levels_to_search, limit_type,
                exclude_inherited);
    }

    public org.omg.CORBA.ContainerPackage.Description[]
    describe_contents(DefinitionKind limit_type,
                      boolean exclude_inherited,
                      int max_returned_objs) {
        return delegate.describe_contents(limit_type, exclude_inherited,
                max_returned_objs);
    }

    public ModuleDef create_module(String id, String name, String version) {
        return delegate.create_module(id, name, version);
    }

    public ConstantDef create_constant(String id, String name, String version,
                                       IDLType type, Any value) {
        return delegate.create_constant(id, name, version, type, value);
    }

    public StructDef create_struct(String id, String name, String version,
                                   StructMember[] members) {
        return delegate.create_struct(id, name, version, members);
    }

    public UnionDef create_union(String id, String name, String version,
                                 IDLType discriminator_type,
                                 UnionMember[] members) {
        return delegate.create_union(id, name, version, discriminator_type,
                members);
    }

    public EnumDef create_enum(String id, String name, String version,
                               String[] members) {
        return delegate.create_enum(id, name, version, members);
    }

    public AliasDef create_alias(String id, String name, String version,
                                 IDLType original_type) {
        return delegate.create_alias(id, name, version, original_type);
    }

    public InterfaceDef create_interface(String id, String name, String version,
                                         InterfaceDef[] base_interfaces,
                                         boolean is_abstract) {
        return delegate.create_interface(id, name, version,
                base_interfaces, is_abstract);
    }

    public ValueDef create_value(String id, String name, String version,
                                 boolean is_custom, boolean is_abstract,
                                 ValueDef base_value, boolean is_truncatable,
                                 ValueDef[] abstract_base_values,
                                 InterfaceDef[] supported_interfaces,
                                 Initializer[] initializers) {
        return delegate.create_value(id, name, version, is_custom, is_abstract,
                base_value, is_truncatable,
                abstract_base_values, supported_interfaces,
                initializers);
    }

    public ValueBoxDef create_value_box(String id, String name, String version,
                                        IDLType original_type_def) {
        return delegate.create_value_box(id, name, version, original_type_def);
    }

    public ExceptionDef create_exception(String id, String name, String version,
                                         StructMember[] members) {
        return delegate.create_exception(id, name, version, members);
    }

    public NativeDef create_native(String id, String name, String version) {
        return delegate.create_native(id, name, version);
    }

    // ValueDefOperations implementation -------------------------

    public InterfaceDef[] supported_interfaces() {
        return supported_interfaces_ref;
    }

    public void supported_interfaces(InterfaceDef[] arg) {
        throw IIOPLogger.ROOT_LOGGER.cannotChangeRMIIIOPMapping();
    }

    public Initializer[] initializers() {
        // We do not (currently) map constructors, as that is optional according
        // to the specification.
        return new Initializer[0];
    }

    public void initializers(Initializer[] arg) {
        throw IIOPLogger.ROOT_LOGGER.cannotChangeRMIIIOPMapping();
    }

    public ValueDef base_value() {
        return base_value_ref;
    }

    public void base_value(ValueDef arg) {
        throw IIOPLogger.ROOT_LOGGER.cannotChangeRMIIIOPMapping();
    }

    public ValueDef[] abstract_base_values() {
        return abstract_base_valuetypes_ref;
    }

    public void abstract_base_values(ValueDef[] arg) {
        throw IIOPLogger.ROOT_LOGGER.cannotChangeRMIIIOPMapping();
    }

    public boolean is_abstract() {
        return is_abstract;
    }

    public void is_abstract(boolean arg) {
        throw IIOPLogger.ROOT_LOGGER.cannotChangeRMIIIOPMapping();
    }

    public boolean is_custom() {
        return is_custom;
    }

    public void is_custom(boolean arg) {
        throw IIOPLogger.ROOT_LOGGER.cannotChangeRMIIIOPMapping();
    }

    public boolean is_truncatable() {
        return false;
    }

    public void is_truncatable(boolean arg) {
        throw IIOPLogger.ROOT_LOGGER.cannotChangeRMIIIOPMapping();
    }

    public boolean is_a(String id) {
        // TODO
        return id().equals(id);
    }

    public FullValueDescription describe_value() {
        if (fullValueDescription != null)
            return fullValueDescription;

        // Has to create the FullValueDescription

        // TODO
        OperationDescription[] operations = new OperationDescription[0];
        AttributeDescription[] attributes = new AttributeDescription[0];

        String defined_in_id = "IDL:Global:1.0";
        if (defined_in instanceof org.omg.CORBA.ContainedOperations)
            defined_in_id = ((org.omg.CORBA.ContainedOperations) defined_in).id();

        fullValueDescription = new FullValueDescription(name, id,
                is_abstract, is_custom,
                defined_in_id, version,
                operations, attributes,
                getValueMembers(),
                new Initializer[0], // TODO
                supported_interfaces,
                abstract_base_valuetypes,
                false,
                baseValue,
                typeCode);

        return fullValueDescription;
    }

    public ValueMemberDef create_value_member(String id, String name,
                                              String version, IDLType type,
                                              short access) {
        throw IIOPLogger.ROOT_LOGGER.cannotChangeRMIIIOPMapping();
    }

    public AttributeDef create_attribute(String id, String name, String version,
                                         IDLType type, AttributeMode mode) {
        throw IIOPLogger.ROOT_LOGGER.cannotChangeRMIIIOPMapping();
    }

    public OperationDef create_operation(String id, String name, String version,
                                         IDLType result, OperationMode mode,
                                         ParameterDescription[] params,
                                         ExceptionDef[] exceptions,
                                         String[] contexts) {
        throw IIOPLogger.ROOT_LOGGER.cannotChangeRMIIIOPMapping();
    }

    // IDLTypeOperations implementation ------------------------------

    public TypeCode type() {
        if (typeCode == null) {
            short modifier = VM_NONE.value;
            if (is_custom)
                modifier = VM_CUSTOM.value;
            else if (is_abstract)
                modifier = VM_ABSTRACT.value;

            typeCode = getORB().create_value_tc(id, name, modifier,
                    baseValueTypeCode,
                    getValueMembersForTypeCode());
        }
        return typeCode;
    }

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

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

        if (defined_in instanceof org.omg.CORBA.ContainedOperations)
            defined_in_id = ((org.omg.CORBA.ContainedOperations) defined_in).id();

        ValueDescription md = new ValueDescription(name, id, is_abstract,
                is_custom,
                defined_in_id, version,
                supported_interfaces,
                abstract_base_valuetypes,
                false,
                baseValue);

        Any any = getORB().create_any();

        ValueDescriptionHelper.insert(any, md);

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

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

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

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

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

    /**
     * My delegate for Container functionality.
     */
    private ContainerImplDelegate delegate;

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

    /**
     * Flag that I am abstract.
     */
    private boolean is_abstract;

    /**
     * Flag that I use custom marshaling.
     */
    private boolean is_custom;

    /**
     * IDs of my implemented interfaces.
     */
    private String[] supported_interfaces;

    /**
     * CORBA references to my implemented interfaces.
     */
    private InterfaceDef[] supported_interfaces_ref;

    /**
     * IR ID of my base value (the class I extend from).
     */
    private String baseValue;

    /**
     * TypeCode of my base value (the class I extend from).
     */
    private TypeCode baseValueTypeCode;

    /**
     * CORBA reference to my base type.
     */
    private ValueDef base_value_ref;

    /**
     * IDs of my abstract base valuetypes.
     */
    private String[] abstract_base_valuetypes;

    /**
     * CORBA references to my abstract base valuetypes.
     */
    private ValueDef[] abstract_base_valuetypes_ref;

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

    /**
     * My Cached ValueMember[].
     */
    private ValueMember[] valueMembers;

    /**
     * My cached FullValueDescription.
     */
    private FullValueDescription fullValueDescription;

    /**
     * Create the valueMembers array, and return it.
     */
    private ValueMember[] getValueMembers() {
        if (valueMembers != null)
            return valueMembers;

        LocalContained[] c = _contents(DefinitionKind.dk_ValueMember, false);
        valueMembers = new ValueMember[c.length];
        for (int i = 0; i < c.length; ++i) {
            ValueMemberDefImpl vmdi = (ValueMemberDefImpl) c[i];

            valueMembers[i] = new ValueMember(vmdi.name(), vmdi.id(),
                    ((LocalContained) vmdi.defined_in).id(),
                    vmdi.version(),
                    vmdi.type(), vmdi.type_def(),
                    vmdi.access());
        }

        return valueMembers;
    }

    /**
     * Create a valueMembers array for TypeCode creation only, and return it.
     */
    private ValueMember[] getValueMembersForTypeCode() {
        LocalContained[] c = _contents(DefinitionKind.dk_ValueMember, false);
        ValueMember[] vms = new ValueMember[c.length];
        for (int i = 0; i < c.length; ++i) {
            ValueMemberDefImpl vmdi = (ValueMemberDefImpl) c[i];

            vms[i] = new ValueMember(vmdi.name(),
                    null, // ignore id
                    null, // ignore defined_in
                    null, // ignore version
                    vmdi.type(),
                    null, // ignore type_def
                    vmdi.access());
        }

        return vms;
    }

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


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

import org.jboss.as.ee.component.EEModuleDescription;
import org.jboss.as.naming.ServiceBasedNamingStore;
import org.jboss.as.naming.ValueManagedReferenceFactory;
import org.jboss.as.naming.deployment.ContextNames;
import org.jboss.as.naming.service.BinderService;
import org.jboss.as.naming.service.NamingStoreService;
import org.jboss.as.server.deployment.DeploymentPhaseContext;
import org.jboss.as.server.deployment.DeploymentUnit;
import org.jboss.as.server.deployment.DeploymentUnitProcessingException;
import org.jboss.as.server.deployment.DeploymentUnitProcessor;
import org.jboss.msc.service.ServiceName;
import org.jboss.msc.service.ServiceTarget;
import org.jboss.msc.value.Values;

/**
 * Deployment processor that deploys a naming context for the current application.
 *
 * @author John E. Bailey
 * @author Eduardo Martins
 */
public class ApplicationContextProcessor implements DeploymentUnitProcessor {

    /**
     * Add a ContextService for this module.
     *
     * @param phaseContext the deployment unit context
     * @throws DeploymentUnitProcessingException
     */
    public void deploy(DeploymentPhaseContext phaseContext) throws DeploymentUnitProcessingException {
        final DeploymentUnit deploymentUnit = phaseContext.getDeploymentUnit();
        if (deploymentUnit.getParent() != null) {
            return;
        }
        EEModuleDescription moduleDescription = deploymentUnit.getAttachment(org.jboss.as.ee.component.Attachments.EE_MODULE_DESCRIPTION);
        final ServiceTarget serviceTarget = phaseContext.getServiceTarget();
        final ServiceName applicationContextServiceName = ContextNames.contextServiceNameOfApplication(moduleDescription.getApplicationName());
        final NamingStoreService contextService = new NamingStoreService(true);
        serviceTarget.addService(applicationContextServiceName, contextService).install();
        final ServiceName appNameServiceName = applicationContextServiceName.append("AppName");
        final BinderService applicationNameBinder = new BinderService("AppName");
        applicationNameBinder.getManagedObjectInjector().inject(new ValueManagedReferenceFactory(Values.immediateValue(moduleDescription.getApplicationName())));
        serviceTarget.addService(appNameServiceName, applicationNameBinder)
                .addDependency(applicationContextServiceName, ServiceBasedNamingStore.class, applicationNameBinder.getNamingStoreInjector())
                .install();
        deploymentUnit.addToAttachmentList(org.jboss.as.server.deployment.Attachments.JNDI_DEPENDENCIES, appNameServiceName);
        deploymentUnit.putAttachment(Attachments.APPLICATION_CONTEXT_CONFIG, applicationContextServiceName);
    }

    public void undeploy(DeploymentUnit deploymentUnit) {
        deploymentUnit.removeAttachment(Attachments.APPLICATION_CONTEXT_CONFIG);
    }
}


/*
 * 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.picketlink.federation.model.parser;

import org.jboss.as.controller.SimpleAttributeDefinition;
import org.jboss.as.controller.descriptions.ModelDescriptionConstants;
import org.jboss.as.controller.operations.common.Util;
import org.jboss.dmr.ModelNode;
import org.jboss.staxmapper.XMLElementReader;
import org.jboss.staxmapper.XMLExtendedStreamReader;
import org.wildfly.extension.picketlink.common.model.ModelElement;
import org.wildfly.extension.picketlink.common.model.XMLElement;
import org.wildfly.extension.picketlink.federation.FederationExtension;
import org.wildfly.extension.picketlink.federation.Namespace;
import org.wildfly.extension.picketlink.federation.model.FederationResourceDefinition;
import org.wildfly.extension.picketlink.federation.model.handlers.HandlerParameterResourceDefinition;
import org.wildfly.extension.picketlink.federation.model.handlers.HandlerResourceDefinition;
import org.wildfly.extension.picketlink.federation.model.idp.AttributeManagerResourceDefinition;
import org.wildfly.extension.picketlink.federation.model.idp.IdentityProviderResourceDefinition;
import org.wildfly.extension.picketlink.federation.model.idp.RoleGeneratorResourceDefinition;
import org.wildfly.extension.picketlink.federation.model.idp.TrustDomainResourceDefinition;
import org.wildfly.extension.picketlink.federation.model.keystore.KeyStoreProviderResourceDefinition;
import org.wildfly.extension.picketlink.federation.model.saml.SAMLResourceDefinition;
import org.wildfly.extension.picketlink.federation.model.sp.ServiceProviderResourceDefinition;

import javax.xml.stream.XMLStreamConstants;
import javax.xml.stream.XMLStreamException;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.ADD;
import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.OP_ADDR;
import static org.jboss.as.controller.parsing.ParseUtils.duplicateNamedElement;
import static org.jboss.as.controller.parsing.ParseUtils.requireNoAttributes;
import static org.jboss.as.controller.parsing.ParseUtils.unexpectedAttribute;
import static org.jboss.as.controller.parsing.ParseUtils.unexpectedElement;
import static org.wildfly.extension.picketlink.common.model.ModelElement.COMMON_HANDLER;
import static org.wildfly.extension.picketlink.common.model.ModelElement.COMMON_HANDLER_PARAMETER;
import static org.wildfly.extension.picketlink.common.model.ModelElement.COMMON_NAME;
import static org.wildfly.extension.picketlink.common.model.ModelElement.FEDERATION;
import static org.wildfly.extension.picketlink.common.model.ModelElement.IDENTITY_PROVIDER;
import static org.wildfly.extension.picketlink.common.model.ModelElement.IDENTITY_PROVIDER_ATTRIBUTE_MANAGER;
import static org.wildfly.extension.picketlink.common.model.ModelElement.IDENTITY_PROVIDER_ROLE_GENERATOR;
import static org.wildfly.extension.picketlink.common.model.ModelElement.IDENTITY_PROVIDER_TRUST_DOMAIN;
import static org.wildfly.extension.picketlink.common.model.ModelElement.KEY_STORE;
import static org.wildfly.extension.picketlink.common.model.ModelElement.SAML;
import static org.wildfly.extension.picketlink.common.model.ModelElement.SERVICE_PROVIDER;

/**
 * @author Pedro Igor
 */
public abstract class AbstractFederationSubsystemReader implements XMLStreamConstants, XMLElementReader<List<ModelNode>> {

    @Override
    public void readElement(XMLExtendedStreamReader reader, List<ModelNode> addOperations) throws XMLStreamException {
        requireNoAttributes(reader);

        Namespace nameSpace = Namespace.forUri(reader.getNamespaceURI());

        ModelNode subsystemNode = createSubsystemRoot();

        addOperations.add(subsystemNode);

        switch (nameSpace) {
            case PICKETLINK_FEDERATION_1_0:
                this.readElement(reader, subsystemNode, addOperations);
                break;
            case PICKETLINK_FEDERATION_1_1:
            case PICKETLINK_FEDERATION_2_0:
                this.readElement(reader, subsystemNode, addOperations);
                break;
            default:
                throw unexpectedElement(reader);
        }
    }

    private void readElement(XMLExtendedStreamReader reader, ModelNode subsystemNode, List<ModelNode> addOperations)
        throws XMLStreamException {
        while (reader.hasNext() && reader.nextTag() != END_DOCUMENT) {
            if (!reader.isStartElement()) {
                continue;
            }

            // if the current element is supported but is not a model element
            if (XMLElement.forName(reader.getLocalName()) != null) {
                continue;
            }

            ModelElement modelKey = ModelElement.forName(reader.getLocalName());

            if (modelKey == null) {
                throw unexpectedElement(reader);
            }

            switch (modelKey) {
                case FEDERATION:
                    parseFederation(reader, subsystemNode, addOperations);
                    break;
                default:
                    throw unexpectedElement(reader);
            }
        }
    }

    private void parseFederation(final XMLExtendedStreamReader reader, final ModelNode subsystemNode,
        final List<ModelNode> addOperations) throws XMLStreamException {
        ModelNode federationNode = parseConfig(reader, FEDERATION, COMMON_NAME.getName(), subsystemNode,
            Arrays.asList(FederationResourceDefinition.ATTRIBUTE_DEFINITIONS), addOperations);

        parseElement(new ElementParser() {
            @Override
            public void parse(final XMLExtendedStreamReader reader, final ModelElement element, final ModelNode parentNode,
                List<ModelNode> addOperations) throws XMLStreamException {
                switch (element) {
                    case KEY_STORE:
                        parseKeyStore(reader, parentNode, addOperations);
                        break;
                    case SAML:
                        parseConfig(reader, SAML, null, parentNode, SAMLResourceDefinition.INSTANCE.getAttributes(),
                            addOperations);
                        break;
                    case IDENTITY_PROVIDER:
                        parseIdentityProviderConfig(reader, parentNode, addOperations);
                        break;
                    case SERVICE_PROVIDER:
                        parseServiceProviderConfig(reader, parentNode, addOperations);
                        break;
                    default:
                        throw unexpectedElement(reader);
                }
            }
        }, FEDERATION, federationNode, reader, addOperations);
    }

    protected void parseKeyStore(XMLExtendedStreamReader reader, ModelNode parentNode, List<ModelNode> addOperations) throws XMLStreamException {
        ModelNode identityProviderNode = parseConfig(reader, KEY_STORE, null, parentNode,
            KeyStoreProviderResourceDefinition.INSTANCE.getAttributes(), addOperations);

        parseElement(new ElementParser() {
            @Override
            public void parse(final XMLExtendedStreamReader reader, final ModelElement element, final ModelNode parentNode,
                List<ModelNode> addOperations) throws XMLStreamException {
                throw unexpectedElement(reader);
            }
        }, KEY_STORE, identityProviderNode, reader, addOperations);
    }

    private void parseServiceProviderConfig(final XMLExtendedStreamReader reader, ModelNode federationNode,
        final List<ModelNode> addOperations) throws XMLStreamException {
        ModelNode serviceProviderNode = parseConfig(reader, SERVICE_PROVIDER,
            COMMON_NAME.getName(), federationNode, Arrays.asList(ServiceProviderResourceDefinition.ATTRIBUTE_DEFINITIONS), addOperations);

        parseElement(new ElementParser() {
            @Override
            public void parse(final XMLExtendedStreamReader reader, final ModelElement element, final ModelNode parentNode,
                List<ModelNode> addOperations) throws XMLStreamException {
                switch (element) {
                    case COMMON_HANDLER:
                        parseHandlerConfig(reader, parentNode, addOperations);
                        break;
                }
            }
        }, SERVICE_PROVIDER, serviceProviderNode, reader, addOperations);
    }

    protected void parseHandlerConfig(final XMLExtendedStreamReader reader, final ModelNode entityProviderNode, final List<ModelNode> addOperations) throws XMLStreamException {
        ModelNode handlerNode = parseConfig(reader, COMMON_HANDLER, COMMON_NAME.getName(), entityProviderNode, HandlerResourceDefinition.INSTANCE
            .getAttributes(), addOperations);

        parseElement(new ElementParser() {
            @Override
            public void parse(final XMLExtendedStreamReader reader, final ModelElement element, final ModelNode parentNode,
                List<ModelNode> addOperations) throws XMLStreamException {
                switch (element) {
                    case COMMON_HANDLER_PARAMETER:
                        parseConfig(reader, COMMON_HANDLER_PARAMETER, COMMON_NAME.getName(), parentNode,
                            HandlerParameterResourceDefinition.INSTANCE.getAttributes(), addOperations);
                        break;
                    default:
                        throw unexpectedElement(reader);
                }
            }
        }, COMMON_HANDLER, handlerNode, reader, addOperations);
    }

    private void parseIdentityProviderConfig(final XMLExtendedStreamReader reader, final ModelNode federationNode,
        final List<ModelNode> addOperations) throws XMLStreamException {
        ModelNode identityProviderNode = parseConfig(reader, IDENTITY_PROVIDER,
            COMMON_NAME.getName(), federationNode,
            Arrays.asList(IdentityProviderResourceDefinition.ATTRIBUTE_DEFINITIONS), addOperations);

        parseElement(new ElementParser() {
            @Override
            public void parse(final XMLExtendedStreamReader reader, final ModelElement element, final ModelNode parentNode,
                List<ModelNode> addOperations) throws XMLStreamException {
                switch (element) {
                    case IDENTITY_PROVIDER_TRUST_DOMAIN:
                        parseConfig(reader, IDENTITY_PROVIDER_TRUST_DOMAIN, COMMON_NAME.getName(), parentNode,
                            TrustDomainResourceDefinition.INSTANCE.getAttributes(), addOperations);
                        break;
                    case IDENTITY_PROVIDER_ROLE_GENERATOR:
                        parseConfig(reader, IDENTITY_PROVIDER_ROLE_GENERATOR, COMMON_NAME.getName(), parentNode,
                            RoleGeneratorResourceDefinition.INSTANCE.getAttributes(), addOperations);
                        break;
                    case IDENTITY_PROVIDER_ATTRIBUTE_MANAGER:
                        parseConfig(reader, IDENTITY_PROVIDER_ATTRIBUTE_MANAGER, COMMON_NAME.getName(), parentNode,
                            AttributeManagerResourceDefinition.INSTANCE.getAttributes(), addOperations);
                        break;
                    case COMMON_HANDLER:
                        parseHandlerConfig(reader, parentNode, addOperations);
                        break;
                    default:
                        throw unexpectedElement(reader);
                }
            }
        }, IDENTITY_PROVIDER, identityProviderNode, reader, addOperations);
    }

    /**
     * Creates the root subsystem's root address.
     *
     * @return
     */
    private ModelNode createSubsystemRoot() {
        ModelNode subsystemAddress = new ModelNode();

        subsystemAddress.add(ModelDescriptionConstants.SUBSYSTEM, FederationExtension.SUBSYSTEM_NAME);

        subsystemAddress.protect();

        return Util.getEmptyOperation(ADD, subsystemAddress);
    }

    /**
     * Reads a element from the stream considering the parameters.
     *
     * @param reader XMLExtendedStreamReader instance from which the elements are read.
     * @param xmlElement Name of the Model Element to be parsed.
     * @param key Name of the attribute to be used to as the key for the model.
     * @param addOperations List of operations.
     * @param lastNode Parent ModelNode instance.
     * @param attributes AttributeDefinition instances to be used to extract the attributes and populate the resulting model.
     *
     * @return A ModelNode instance populated.
     *
     * @throws javax.xml.stream.XMLStreamException
     */
    protected ModelNode parseConfig(XMLExtendedStreamReader reader, ModelElement xmlElement, String key, ModelNode lastNode,
        List<SimpleAttributeDefinition> attributes, List<ModelNode> addOperations) throws XMLStreamException {
        if (!reader.getLocalName().equals(xmlElement.getName())) {
            return null;
        }

        ModelNode modelNode = Util.getEmptyOperation(ADD, null);

        int attributeCount = reader.getAttributeCount();

        for (int i = 0; i < attributeCount; i++) {
            String attributeLocalName = reader.getAttributeLocalName(i);

            if (ModelElement.forName(attributeLocalName) == null) {
                throw unexpectedAttribute(reader, i);
            }
        }

        for (SimpleAttributeDefinition simpleAttributeDefinition : attributes) {
            String attributeValue = reader.getAttributeValue("", simpleAttributeDefinition.getXmlName());
            simpleAttributeDefinition.parseAndSetParameter(attributeValue, modelNode, reader);
        }

        String name = xmlElement.getName();

        if (key != null) {
            name = key;

            if (modelNode.hasDefined(key)) {
                name = modelNode.get(key).asString();
            } else {
                String attributeValue = reader.getAttributeValue("", key);

                if (attributeValue != null) {
                    name = attributeValue;
                }
            }
        }

        modelNode.get(ModelDescriptionConstants.OP_ADDR).set(lastNode.clone().get(OP_ADDR).add(xmlElement.getName(), name));

        addOperations.add(modelNode);

        return modelNode;
    }

    protected void parseElement(final ElementParser parser, ModelElement parentElement, final ModelNode parentNode,
        final XMLExtendedStreamReader reader, final List<ModelNode> addOperations) throws XMLStreamException {
        Set<String> visited = new HashSet<>();

        while (reader.hasNext() && reader.nextTag() != END_DOCUMENT) {
            String tagName = reader.getLocalName();

            if (!reader.isStartElement()) {
                if (reader.isEndElement() && tagName.equals(parentElement.getName())) {
                    break;
                }

                continue;
            }

            if (!tagName.equals(parentElement.getName())) {
                ModelElement element = ModelElement.forName(tagName);

                if (element != null) {
                    parser.parse(reader, element, parentNode, addOperations);
                } else {
                    if (XMLElement.forName(tagName) != null) {
                        if (visited.contains(tagName)) {
                            throw duplicateNamedElement(reader, tagName);
                        }
                    } else {
                        throw unexpectedElement(reader);
                    }
                }
            }

            visited.add(tagName);
        }
    }

    interface ElementParser {

        void parse(XMLExtendedStreamReader reader, ModelElement element, ModelNode parentNode, List<ModelNode> addOperations)
            throws XMLStreamException;
    }

}