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

package org.jboss.as.jpa.config;

import java.util.HashMap;
import java.util.Map;

import javax.persistence.EntityManagerFactory;

import org.jipijapa.plugin.spi.PersistenceUnitMetadata;

/**
 * configuration properties that may appear in persistence.xml
 *
 * @author Scott Marlow
 */
public class Configuration {
    /**
     * name of the AS module that contains the persistence provider
     */
    public static final String PROVIDER_MODULE = "jboss.as.jpa.providerModule";

    /**
     * Hibernate main module (default) persistence provider
     */
    public static final String PROVIDER_MODULE_HIBERNATE = "org.hibernate";

    /**
     * Hibernate 4.1.x persistence provider, note that Hibernate 4.1.x is expected to be in the 4.1 slot
     */
    public static final String PROVIDER_MODULE_HIBERNATE4_1 = "org.hibernate:4.1";

    /**
     * Hibernate OGM persistence provider
     */
    public static final String PROVIDER_MODULE_HIBERNATE_OGM = "org.hibernate.ogm";

    public static final String PROVIDER_MODULE_ECLIPSELINK = "org.eclipse.persistence";

    public static final String PROVIDER_MODULE_TOPLINK = "oracle.toplink";

    public static final String PROVIDER_MODULE_DATANUCLEUS = "org.datanucleus";

    public static final String PROVIDER_MODULE_DATANUCLEUS_GAE = "org.datanucleus:appengine";

    public static final String PROVIDER_MODULE_OPENJPA = "org.apache.openjpa";

    /**
     * default if no PROVIDER_MODULE is specified.
     */
    public static final String PROVIDER_MODULE_DEFAULT = PROVIDER_MODULE_HIBERNATE;

    /**
     * Hibernate 4.1.x persistence provider class
     */
    public static final String PROVIDER_CLASS_HIBERNATE4_1 = "org.hibernate.ejb.HibernatePersistence";

    /**
     * Hibernate 4.3.x persistence provider class
     */
    public static final String PROVIDER_CLASS_HIBERNATE = "org.hibernate.jpa.HibernatePersistenceProvider";

    /**
     * Hibernate OGM persistence provider class
     */
    public static final String PROVIDER_CLASS_HIBERNATE_OGM = "org.hibernate.ogm.jpa.HibernateOgmPersistence";

    /**
     * TopLink provider class names
     */
    public static final String PROVIDER_CLASS_TOPLINK_ESSENTIALS = "oracle.toplink.essentials.PersistenceProvider";

    public static final String PROVIDER_CLASS_TOPLINK = "oracle.toplink.essentials.ejb.cmp3.EntityManagerFactoryProvider";

    /**
     * EclipseLink provider class name
     */
    public static final String PROVIDER_CLASS_ECLIPSELINK = "org.eclipse.persistence.jpa.PersistenceProvider";

    /**
     * DataNucleus provider
     */
    public static final String PROVIDER_CLASS_DATANUCLEUS = "org.datanucleus.api.jpa.PersistenceProviderImpl";

    /**
     * DataNucleus provider GAE
     */
    public static final String PROVIDER_CLASS_DATANUCLEUS_GAE = "org.datanucleus.store.appengine.jpa.DatastorePersistenceProvider";

    public static final String PROVIDER_CLASS_OPENJPA = "org.apache.openjpa.persistence.PersistenceProviderImpl";
    /**
     * default provider class
     */
    public static final String PROVIDER_CLASS_DEFAULT = PROVIDER_CLASS_HIBERNATE;

    /**
     * if the PROVIDER_MODULE is this value, it is expected that the application has its own provider
     * in the deployment.
     */
    public static final String PROVIDER_MODULE_APPLICATION_SUPPLIED = "application";

    public static final String ADAPTER_MODULE_OPENJPA = "org.jboss.as.jpa.openjpa";

    /**
     * name of the AS module that contains the persistence provider adapter
     */
    public static final String ADAPTER_MODULE = "jboss.as.jpa.adapterModule";

    /**
     * defaults to true, if changed to false (in the persistence.xml),
     * the JPA container will not start the persistence unit service.
     */
    public static final String JPA_CONTAINER_MANAGED = "jboss.as.jpa.managed";

    public static final String JPA_DEFAULT_PERSISTENCE_UNIT = "wildfly.jpa.default-unit";

    /**
     * defaults to true, if false, persistence unit will not support javax.persistence.spi.ClassTransformer Interface
     * which means no application class rewriting
     */
    public static final String JPA_CONTAINER_CLASS_TRANSFORMER = "jboss.as.jpa.classtransformer";

    private static final String HIBERNATE_USE_CLASS_ENHANCER = "hibernate.ejb.use_class_enhancer";
    private static final String HIBERNATE_ENABLE_DIRTY_TRACKING = "hibernate.enhancer.enableDirtyTracking";
    private static final String HIBERNATE_ENABLE_LAZY_INITIALIZATION = "hibernate.enhancer.enableLazyInitialization";
    private static final String HIBERNATE_ENABLE_ASSOCIATION_MANAGEMENT = "hibernate.enhancer.enableAssociationManagement";

    /**
     * set to false to force a single phase persistence unit bootstrap to be used (default is true
     * which uses two phases to start the persistence unit).
     */
    public static final String JPA_ALLOW_TWO_PHASE_BOOTSTRAP = "wildfly.jpa.twophasebootstrap";

    /**
     * set to false to ignore default data source (defaults to true)
     */
    private static final String JPA_ALLOW_DEFAULT_DATA_SOURCE_USE = "wildfly.jpa.allowdefaultdatasourceuse";

    /**
     * set to true to defer detaching entities until persistence context is closed (WFLY-3674)
     */
    private static final String JPA_DEFER_DETACH = "jboss.as.jpa.deferdetach";

    /**
     * unique name for the persistence unit that is unique across all deployments (
     * defaults to include the application name prepended to the persistence unit name)
     */
    private static final String JPA_SCOPED_PERSISTENCE_UNIT_NAME = "jboss.as.jpa.scopedname";

    /**
     * name of the persistence provider adapter class
     */
    public static final String ADAPTER_CLASS = "jboss.as.jpa.adapterClass";

    public static final String ALLOWJOINEDUNSYNCPC = "wildfly.jpa.allowjoinedunsync";

    public static final String SKIPMIXEDSYNCTYPECHECKING = "wildfly.jpa.skipmixedsynctypechecking";

    /**
     * Document properties that allow JPA apps to disable WildFly JTA platform/2lc integration for Hibernate ORM 5.3+ (WFLY-10433)
     * public static final String CONTROLJTAINTEGRATION = "wildfly.jpa.jtaplatform";
     * public static final String CONTROL2LCINTEGRATION = "wildfly.jpa.regionfactory";
     */

    /**
     * name of the Hibernate Search module name configuration setting in persistence unit definition
     */
    public static final String HIBERNATE_SEARCH_MODULE = "wildfly.jpa.hibernate.search.module";

    /**
     * name of the Hibernate Search module name
     */
    public static final String PROVIDER_MODULE_HIBERNATE_SEARCH = "org.hibernate.search.orm";

    private static final String EE_DEFAULT_DATASOURCE = "java:comp/DefaultDataSource";
    // key = provider class name, value = module name
    private static final Map<String, String> providerClassToModuleName = new HashMap<String, String>();

    static {
        // always choose the default hibernate version for the Hibernate provider class mapping
        // if the user wants a different version. they can specify the provider module name
        providerClassToModuleName.put(PROVIDER_CLASS_HIBERNATE, PROVIDER_MODULE_HIBERNATE);
        // WFLY-2136/HHH-8543 to make migration to Hibernate 4.3.x easier, we also map the (now)
        // deprecated PROVIDER_CLASS_HIBERNATE4_1 to the org.hibernate:main module
        // when PROVIDER_CLASS_HIBERNATE4_1 is no longer in a future Hibernate version (5.x?)
        // we can map PROVIDER_CLASS_HIBERNATE4_1 to org.hibernate:4.3 at that time.
        // persistence units can set "jboss.as.jpa.providerModule=org.hibernate:4.1" to use Hibernate 4.1.x/4.2.x
        providerClassToModuleName.put(PROVIDER_CLASS_HIBERNATE4_1, PROVIDER_MODULE_HIBERNATE);
        providerClassToModuleName.put(PROVIDER_CLASS_HIBERNATE_OGM, PROVIDER_MODULE_HIBERNATE_OGM);
        providerClassToModuleName.put(PROVIDER_CLASS_TOPLINK_ESSENTIALS, PROVIDER_MODULE_TOPLINK);
        providerClassToModuleName.put(PROVIDER_CLASS_TOPLINK, PROVIDER_MODULE_TOPLINK);
        providerClassToModuleName.put(PROVIDER_CLASS_ECLIPSELINK, PROVIDER_MODULE_ECLIPSELINK);
        providerClassToModuleName.put(PROVIDER_CLASS_DATANUCLEUS, PROVIDER_MODULE_DATANUCLEUS);
        providerClassToModuleName.put(PROVIDER_CLASS_DATANUCLEUS_GAE, PROVIDER_MODULE_DATANUCLEUS_GAE);
        providerClassToModuleName.put(PROVIDER_CLASS_OPENJPA, PROVIDER_MODULE_OPENJPA);
    }

    /**
     * Get the provider module name for the specified provider class.
     *
     * @param providerClassName the PU class name
     * @return provider module name or null if not known
     */
    public static String getProviderModuleNameFromProviderClassName(final String providerClassName) {
        return providerClassToModuleName.get(providerClassName);
    }

    /**
     * Determine if class file transformer is needed for the specified persistence unit
     *
     * if the persistence provider is Hibernate and use_class_enhancer is not true, don't need a class transformer.
     * for other persistence providers, the transformer is assumed to be needed.
     *
     * @param pu the PU
     * @return true if class file transformer support is needed for pu
     */
    public static boolean needClassFileTransformer(PersistenceUnitMetadata pu) {
        boolean result = true;
        String provider = pu.getPersistenceProviderClassName();
        if (pu.getProperties().containsKey(Configuration.JPA_CONTAINER_CLASS_TRANSFORMER)) {
            result = Boolean.parseBoolean(pu.getProperties().getProperty(Configuration.JPA_CONTAINER_CLASS_TRANSFORMER));
        }
        else if (isHibernateProvider(provider)) {
            result = (Boolean.TRUE.toString().equals(pu.getProperties().getProperty(HIBERNATE_USE_CLASS_ENHANCER))
                    || Boolean.TRUE.toString().equals(pu.getProperties().getProperty(HIBERNATE_ENABLE_DIRTY_TRACKING))
                    || Boolean.TRUE.toString().equals(pu.getProperties().getProperty(HIBERNATE_ENABLE_LAZY_INITIALIZATION))
                    || Boolean.TRUE.toString().equals(pu.getProperties().getProperty(HIBERNATE_ENABLE_ASSOCIATION_MANAGEMENT)));
        }
        return result;
    }

    private static boolean isHibernateProvider(String provider) {
        return provider == null ||
                PROVIDER_CLASS_HIBERNATE.equals(provider) ||
                PROVIDER_CLASS_HIBERNATE_OGM.equals(provider) ||
                PROVIDER_CLASS_HIBERNATE4_1.equals(provider);
    }

    // key = provider class name, value = adapter module name
    private static final Map<String, String> providerClassToAdapterModuleName = new HashMap<String, String>();

    static {
        providerClassToAdapterModuleName.put(PROVIDER_CLASS_OPENJPA, ADAPTER_MODULE_OPENJPA);
    }

    public static String getProviderAdapterModuleNameFromProviderClassName(final String providerClassName) {
        return providerClassToAdapterModuleName.get(providerClassName);
    }

    public static String getDefaultProviderModuleName() {
        return PROVIDER_MODULE_DEFAULT;
    }

    /**
     * Determine if two phase persistence unit start is allowed
     *
     * @param pu
     * @return
     */
    public static boolean allowTwoPhaseBootstrap(PersistenceUnitMetadata pu) {
        boolean result = true;

        if (EE_DEFAULT_DATASOURCE.equals(pu.getJtaDataSourceName())) {
            result = false;
        }
        if (pu.getProperties().containsKey(Configuration.JPA_ALLOW_TWO_PHASE_BOOTSTRAP)) {
            result = Boolean.parseBoolean(pu.getProperties().getProperty(Configuration.JPA_ALLOW_TWO_PHASE_BOOTSTRAP));
        }
        return result;
    }

    /**
     * Determine if the default data-source should be used
     *
     * @param pu
     * @return true if the default data-source should be used
     */
    public static boolean allowDefaultDataSourceUse(PersistenceUnitMetadata pu) {
        boolean result = true;
        if (pu.getProperties().containsKey(Configuration.JPA_ALLOW_DEFAULT_DATA_SOURCE_USE)) {
            result = Boolean.parseBoolean(pu.getProperties().getProperty(Configuration.JPA_ALLOW_DEFAULT_DATA_SOURCE_USE));
        }
        return result;
    }

    /**
     * Return true if detaching of managed entities should be deferred until the entity manager is closed.
     * Note:  only applies to transaction scoped entity managers used without an active JTA transaction.
     *
     * @param properties
     * @return
     */
    public static boolean deferEntityDetachUntilClose(final Map<String, Object> properties) {
        boolean result = false;
        if ( properties.containsKey(JPA_DEFER_DETACH))
            result = Boolean.parseBoolean((String)properties.get(JPA_DEFER_DETACH));
        return result;
    }

    public static String getScopedPersistenceUnitName(PersistenceUnitMetadata pu) {

        Object name = pu.getProperties().get(JPA_SCOPED_PERSISTENCE_UNIT_NAME);
        if (name instanceof String) {
            return (String)name;
        }
        return null;
    }

    /**
     * Allow the mixed synchronization checking to be skipped for backward compatibility with WildFly 10.1.0
     *
     *
     * @param emf
     * @param targetEntityManagerProperties
     * @return
     */
    public static boolean skipMixedSynchronizationTypeCheck(EntityManagerFactory emf, Map targetEntityManagerProperties) {
        boolean result = false;
        // EntityManager properties will take priority over persistence.xml level (emf) properties
        if(targetEntityManagerProperties != null && targetEntityManagerProperties.containsKey(SKIPMIXEDSYNCTYPECHECKING)) {
            result = Boolean.parseBoolean((String) targetEntityManagerProperties.get(SKIPMIXEDSYNCTYPECHECKING));
        }
        else if(emf.getProperties() != null && emf.getProperties().containsKey(SKIPMIXEDSYNCTYPECHECKING)) {
            result = Boolean.parseBoolean((String) emf.getProperties().get(SKIPMIXEDSYNCTYPECHECKING));
        }
        return result;
    }

    /**
     * Allow an unsynchronized persistence context that is joined to the transaction, be treated the same as a synchronized
     * persistence context, with respect to the checking for mixed unsync/sync types.
     *
     *
     * @param emf
     * @param targetEntityManagerProperties
     * @return
     */
    public static boolean allowJoinedUnsyncPersistenceContext(EntityManagerFactory emf, Map targetEntityManagerProperties) {
        boolean result = false;
        // EntityManager properties will take priority over persistence.xml (emf) properties
        if(targetEntityManagerProperties != null && targetEntityManagerProperties.containsKey(ALLOWJOINEDUNSYNCPC)) {
            result = Boolean.parseBoolean((String) targetEntityManagerProperties.get(ALLOWJOINEDUNSYNCPC));
        }
        else if(emf.getProperties() != null && emf.getProperties().containsKey(ALLOWJOINEDUNSYNCPC)) {
            result = Boolean.parseBoolean((String) emf.getProperties().get(ALLOWJOINEDUNSYNCPC));
        }
        return result;
    }
}


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

package org.jboss.as.ejb3.subsystem;

import static org.jboss.as.ejb3.component.pool.StrictMaxPoolConfigService.Derive;

import java.util.concurrent.TimeUnit;

import org.jboss.as.controller.AbstractAddStepHandler;
import org.jboss.as.controller.AttributeDefinition;
import org.jboss.as.controller.OperationContext;
import org.jboss.as.controller.OperationFailedException;
import org.jboss.as.controller.PathAddress;
import org.jboss.as.controller.descriptions.ModelDescriptionConstants;
import org.jboss.as.ejb3.component.pool.StrictMaxPoolConfig;
import org.jboss.as.ejb3.component.pool.StrictMaxPoolConfigService;
import org.jboss.dmr.ModelNode;
import org.jboss.msc.service.ServiceBuilder;
import org.jboss.msc.service.ServiceName;

/**
 * Adds a strict-max-pool to the EJB3 subsystem's bean-instance-pools. The {#performRuntime runtime action}
 * will create and install a {@link org.jboss.as.ejb3.component.pool.StrictMaxPoolConfigService}
 *

 * User: Jaikiran Pai
 */
public class StrictMaxPoolAdd extends AbstractAddStepHandler {

    public static final StrictMaxPoolAdd INSTANCE = new StrictMaxPoolAdd();

    static final String IO_MAX_THREADS_RUNTIME_CAPABILITY_NAME = "org.wildfly.io.max-threads";

    /**
     * Populate the strictMaxPoolModel from the operation
     *
     * @param operation          the operation
     * @param strictMaxPoolModel strict-max-pool ModelNode
     * @throws OperationFailedException
     */
    @Override
    protected void populateModel(ModelNode operation, ModelNode strictMaxPoolModel) throws OperationFailedException {
        for (AttributeDefinition attr : StrictMaxPoolResourceDefinition.ATTRIBUTES.values()) {
            attr.validateAndSet(operation, strictMaxPoolModel);
        }
    }

    @Override
    protected void performRuntime(OperationContext context, ModelNode operation, ModelNode strictMaxPoolModel) throws OperationFailedException {

        final String poolName = PathAddress.pathAddress(operation.get(ModelDescriptionConstants.ADDRESS)).getLastElement().getValue();
        final int maxPoolSize = StrictMaxPoolResourceDefinition.MAX_POOL_SIZE.resolveModelAttribute(context, strictMaxPoolModel).asInt();
        final Derive derive = StrictMaxPoolResourceDefinition.parseDeriveSize(context, strictMaxPoolModel);
        final long timeout = StrictMaxPoolResourceDefinition.INSTANCE_ACQUISITION_TIMEOUT.resolveModelAttribute(context, strictMaxPoolModel).asLong();
        final String unit = StrictMaxPoolResourceDefinition.INSTANCE_ACQUISITION_TIMEOUT_UNIT.resolveModelAttribute(context, strictMaxPoolModel).asString();
        // create and install the service
        final StrictMaxPoolConfigService poolConfigService = new StrictMaxPoolConfigService(poolName, maxPoolSize, derive, timeout, TimeUnit.valueOf(unit));

        final ServiceName serviceName = StrictMaxPoolConfigService.EJB_POOL_CONFIG_BASE_SERVICE_NAME.append(poolName);
        ServiceBuilder<StrictMaxPoolConfig> svcBuilder = context.getServiceTarget().addService(serviceName, poolConfigService);

        if (context.hasOptionalCapability(IO_MAX_THREADS_RUNTIME_CAPABILITY_NAME, null, null)) {
            ServiceName name = context.getCapabilityServiceName(IO_MAX_THREADS_RUNTIME_CAPABILITY_NAME, Integer.class);
            svcBuilder.addDependency(name, Integer.class, poolConfigService.getMaxThreadsInjector());
        }

        svcBuilder.install();
    }

}


/*
 * Copyright (c) 1999, 2000, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code 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 General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */

package org.wildfly.iiop.openjdk.naming.jndi;

// Needed for RMI/IIOP

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.rmi.Remote;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Properties;

import javax.naming.ConfigurationException;
import javax.naming.Context;

import org.omg.CORBA.ORB;
import org.wildfly.iiop.openjdk.logging.IIOPLogger;

/**
 * Contains utilities for performing CORBA-related tasks:
 * 1. Get the org.omg.CORBA.Object for a java.rmi.Remote object.
 * 2. Create an ORB to use for a given host/port, and environment properties.
 *
 * @author Simon Nash
 * @author Bryan Atsatt
 */

public class CorbaUtils {

    private static volatile Properties orbProperties;

    /**
     * Returns the CORBA object reference associated with a Remote
     * object by using the javax.rmi.CORBA package.
     *

     * Use reflection to avoid hard dependencies on javax.rmi.CORBA package.
     * This method effective does the following:
     *

     * java.lang.Object stub;
     * try {
     *     stub = PortableRemoteObject.toStub(remoteObj);
     * } catch (Exception e) {
     *     throw new ConfigurationException("Object not exported or not found");
     * }
     * if (!(stub instanceof javax.rmi.CORBA.Stub)) {
     *     return null; // JRMP impl or JRMP stub
     * }
     * try {
     *     ((javax.rmi.CORBA.Stub)stub).connect(orb);  // try to connect IIOP stub
     * } catch (RemoteException e) {
     *     // ignore 'already connected' error
     * }
     * return (javax.rmi.CORBA.Stub)stub;
     *
     * @param remoteObj The non-null remote object for
     * @param orb       The non-null ORB to connect the remote object to
     * @return The CORBA Object for remoteObj; null if <tt>remoteObj</tt>
     *         is a JRMP implementation or JRMP stub.
     * @throws ClassNotFoundException The RMI-IIOP package is not available
     * @throws ConfigurationException The CORBA Object cannot be obtained
     *                                because of configuration problems.
     */
    public static org.omg.CORBA.Object remoteToCorba(Remote remoteObj, ORB orb)
            throws ClassNotFoundException, ConfigurationException {
        synchronized (CorbaUtils.class) {
            if (toStubMethod == null) {
                initMethodHandles();
            }
        }

// First, get remoteObj's stub

        // javax.rmi.CORBA.Stub stub = PortableRemoteObject.toStub(remoteObj);

        java.lang.Object stub;

        try {
            stub = toStubMethod.invoke(null, new java.lang.Object[]{remoteObj});

        } catch (InvocationTargetException e) {
            Throwable realException = e.getTargetException();
            // realException.printStackTrace();
            ConfigurationException ce = IIOPLogger.ROOT_LOGGER.problemInvokingPortableRemoteObjectToStub();
            ce.setRootCause(realException);
            throw ce;
        } catch (IllegalAccessException e) {
            ConfigurationException ce = IIOPLogger.ROOT_LOGGER.cannotInvokePortableRemoteObjectToStub();
            ce.setRootCause(e);
            throw ce;
        }

// Next, make sure that the stub is javax.rmi.CORBA.Stub

        if (!corbaStubClass.isInstance(stub)) {
            return null;  // JRMP implementation or JRMP stub
        }

// Next, make sure that the stub is connected
        // Invoke stub.connect(orb)
        try {
            connectMethod.invoke(stub, new java.lang.Object[]{orb});

        } catch (InvocationTargetException e) {
            Throwable realException = e.getTargetException();
            // realException.printStackTrace();

            if (!(realException instanceof java.rmi.RemoteException)) {
                ConfigurationException ce = IIOPLogger.ROOT_LOGGER.problemInvokingStubConnect();
                ce.setRootCause(realException);
                throw ce;
            }
            // ignore RemoteException because stub might have already
            // been connected
        } catch (IllegalAccessException e) {
            ConfigurationException ce = IIOPLogger.ROOT_LOGGER.cannotInvokeStubConnect();
            ce.setRootCause(e);
            throw ce;
        }
// Finally, return stub
        return (org.omg.CORBA.Object) stub;
    }

    /**
     * Get ORB using given server and port number, and properties from environment.
     *
     * @param server Possibly null server; if null means use default;
     *               For applet, it is the applet host; for app, it is localhost.
     * @param port   Port number, -1 means default port
     * @param env    Possibly null environment. Contains environment properties.
     *               Could contain ORB itself; or applet used for initializing ORB.
     *               Use all String properties from env for initializing ORB
     * @return A non-null ORB.
     */
    public static ORB getOrb(String server, int port, Hashtable env) {
        // See if we can get info from environment
        Properties orbProp;

        // Extract any org.omg.CORBA properties from environment
        if (env != null) {
            // Get all String properties
            orbProp = new Properties();
            final Enumeration envProp = env.keys();
            while (envProp.hasMoreElements()) {
                String key = (String) envProp.nextElement();
                Object val = env.get(key);
                if (val instanceof String) {
                    orbProp.put(key, val);
                }
            }
            final Enumeration mainProps = orbProperties.keys();
            while (mainProps.hasMoreElements()) {
                String key = (String) mainProps.nextElement();
                Object val = orbProperties.get(key);
                if (val instanceof String) {
                    orbProp.put(key, val);
                }
            }
        } else {
            orbProp = orbProperties;
        }

        if (server != null) {
            orbProp.put("org.omg.CORBA.ORBInitialHost", server);
        }
        if (port >= 0) {
            orbProp.put("org.omg.CORBA.ORBInitialPort", "" + port);
        }

        // Get Applet from environment
        if (env != null) {
            Object applet = env.get(Context.APPLET);
            if (applet != null) {
                // Create ORBs for an applet
                return initAppletORB(applet, orbProp);
            }
        }

        // Create ORBs using orbProp for a standalone application
        return ORB.init(new String[0], orbProp);
    }

    /**
     * This method returns a new ORB instance for the given applet
     * without creating a static dependency on java.applet.
     */
    private static ORB initAppletORB(Object applet, Properties orbProp) {
        try {
            Class<?> appletClass = Class.forName("java.applet.Applet", true, null);
            if (!appletClass.isInstance(applet)) {
                throw new ClassCastException(applet.getClass().getName());
            }

            // invoke the static method ORB.init(applet, orbProp);
            Method method = ORB.class.getMethod("init", appletClass, Properties.class);
            return (ORB) method.invoke(null, applet, orbProp);
        } catch (ClassNotFoundException e) {
            // java.applet.Applet doesn't exist and the applet parameter is
            // non-null; so throw CCE
            throw new ClassCastException(applet.getClass().getName());
        } catch (NoSuchMethodException e) {
            throw new AssertionError(e);
        } catch (InvocationTargetException e) {
            Throwable cause = e.getCause();
            if (cause instanceof RuntimeException) {
                throw (RuntimeException) cause;
            } else if (cause instanceof Error) {
                throw (Error) cause;
            }
            throw new AssertionError(e);
        } catch (IllegalAccessException iae) {
            throw new AssertionError(iae);
        }
    }

    // Fields used for reflection of RMI-IIOP
    private static Method toStubMethod = null;
    private static Method connectMethod = null;
    private static Class corbaStubClass = null;

    /**
     * Initializes reflection method handles for RMI-IIOP.
     *
     * @throws ClassNotFoundException javax.rmi.CORBA.* not available
     */
    private static void initMethodHandles() throws ClassNotFoundException {
        // Get javax.rmi.CORBA.Stub class
        corbaStubClass = Class.forName("javax.rmi.CORBA.Stub");

        // Get javax.rmi.CORBA.Stub.connect(org.omg.CORBA.ORB) method

        try {
            connectMethod = corbaStubClass.getMethod("connect", new Class[]{org.omg.CORBA.ORB.class});
        } catch (NoSuchMethodException e) {
            throw IIOPLogger.ROOT_LOGGER.noMethodDefForStubConnect();
        }

        // Get javax.rmi.PortableRemoteObject method
        Class proClass = Class.forName("javax.rmi.PortableRemoteObject");

        // Get javax.rmi.PortableRemoteObject(java.rmi.Remote) method
        try {
            toStubMethod = proClass.getMethod("toStub", new Class[]{java.rmi.Remote.class});

        } catch (NoSuchMethodException e) {
            throw IIOPLogger.ROOT_LOGGER.noMethodDefForPortableRemoteObjectToStub();
        }
    }

    public static Properties getOrbProperties() {
        return orbProperties;
    }

    public static void setOrbProperties(final Properties orbProperties) {
        CorbaUtils.orbProperties = orbProperties;
    }
}


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

import static org.jboss.as.naming.logging.NamingLogger.ROOT_LOGGER;
import static org.jboss.as.naming.util.NamingUtils.isEmpty;
import static org.jboss.as.naming.util.NamingUtils.namingEnumeration;
import static org.jboss.as.naming.util.NamingUtils.namingException;
import static org.jboss.as.naming.util.NamingUtils.notAContextException;

import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.Arrays;
import java.util.Hashtable;

import javax.naming.Binding;
import javax.naming.CannotProceedException;
import javax.naming.CompositeName;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.LinkRef;
import javax.naming.Name;
import javax.naming.NameClassPair;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import javax.naming.Reference;
import javax.naming.Referenceable;
import javax.naming.event.EventContext;
import javax.naming.event.NamingListener;
import javax.naming.spi.NamingManager;
import javax.naming.spi.ObjectFactory;
import javax.naming.spi.ResolveResult;

import org.wildfly.naming.java.permission.JndiPermission;
import org.jboss.as.naming.context.ObjectFactoryBuilder;
import org.jboss.as.naming.logging.NamingLogger;
import org.jboss.as.naming.util.NameParser;
import org.wildfly.security.manager.WildFlySecurityManager;

/**
 * Naming context implementation which proxies calls to a {@code NamingStore} instance.  This context is
 * read-only.
 *
 * @author John E. Bailey
 */
public class NamingContext implements EventContext {

    /**
     * A {@link org.jboss.as.naming.NamingPermission} needed to set the active {@link org.jboss.as.naming.NamingStore}. The name of the permission is "{@code setActiveNamingStore}."
     */
    private static final NamingPermission SET_ACTIVE_NAMING_STORE = new NamingPermission("setActiveNamingStore");
    /*
     * The active naming store to use for any context created without a name store.
     */
    private static volatile NamingStore ACTIVE_NAMING_STORE = new InMemoryNamingStore();

    /**
     * Set the active naming store
     *
     * @param namingStore The naming store
     */
    public static void setActiveNamingStore(final NamingStore namingStore) {
        if(WildFlySecurityManager.isChecking()) {
            System.getSecurityManager().checkPermission(SET_ACTIVE_NAMING_STORE);
        }
        ACTIVE_NAMING_STORE = namingStore;
    }

    private static final String PACKAGE_PREFIXES = "org.jboss.as.naming.interfaces";

    static {
        try {
            NamingManager.setObjectFactoryBuilder(ObjectFactoryBuilder.INSTANCE);
        } catch(Throwable t) {
            ROOT_LOGGER.failedToSet(t, "ObjectFactoryBuilder");
        }
    }

    /**
     * Initialize the naming components required by {@link javax.naming.spi.NamingManager}.
     */
    public static void initializeNamingManager() {
        // Setup naming environment
        final String property = WildFlySecurityManager.getPropertyPrivileged(Context.URL_PKG_PREFIXES, null);
        if(property == null || property.isEmpty()) {
            WildFlySecurityManager.setPropertyPrivileged(Context.URL_PKG_PREFIXES, PACKAGE_PREFIXES);
        } else if(!Arrays.asList(property.split(":")).contains(PACKAGE_PREFIXES)) {
            WildFlySecurityManager.setPropertyPrivileged(Context.URL_PKG_PREFIXES, PACKAGE_PREFIXES + ":" + property);
        }
        try {
            //If we are reusing the JVM. e.g. in tests we should not set this again
            if (!NamingManager.hasInitialContextFactoryBuilder())
                NamingManager.setInitialContextFactoryBuilder(new InitialContextFactoryBuilder());
        } catch (NamingException e) {
            ROOT_LOGGER.failedToSet(e, "InitialContextFactoryBuilder");
        }
    }

    /* The naming store providing the back-end storage */
    private final NamingStore namingStore;

    /* The name prefix the context represents. */
    private final Name prefix;

    /* The environment configuration */
    private final Hashtable environment;

    /**
     * Create a new naming context with no prefix or naming store.  This will default to a prefix of "" and
     * the active naming store.
     *
     * @param environment The naming environment
     */
    public NamingContext(final Hashtable environment) {
        this(new CompositeName(), ACTIVE_NAMING_STORE, environment);
    }

    /**
     * Create a context with a prefix name.
     *
     * @param prefix The prefix for this context
     * @param environment The naming environment
     * @throws NamingException if an error occurs
     */
    public NamingContext(final Name prefix, final Hashtable environment) throws NamingException {
        this(prefix, ACTIVE_NAMING_STORE, environment);
    }

    /**
     * Create a new naming context with a prefix name and a NamingStore instance to use as a backing.
     *
     * @param prefix The prefix for this context
     * @param namingStore The NamingStore
     * @param environment The naming environment
     */
    public NamingContext(final Name prefix, final NamingStore namingStore, final Hashtable environment) {
        if(prefix == null) {
            throw NamingLogger.ROOT_LOGGER.nullVar("Naming prefix");
        }
        this.prefix = prefix;
        if(namingStore == null) {
            throw NamingLogger.ROOT_LOGGER.nullVar("NamingStore");
        }
        this.namingStore = namingStore;
        if(environment != null) {
            this.environment = new Hashtable(environment);
        } else {
            this.environment = new Hashtable();
        }
    }

    /**
     * Create a new naming context with the given namingStore and an empty name.
     *
     * @param namingStore the naming store to use
     * @param environment the environment to use
     */
    public NamingContext(final NamingStore namingStore, final Hashtable environment) {
        this(new CompositeName(), namingStore, environment);
    }

    /** {@inheritDoc} */
    public Object lookup(final Name name) throws NamingException {
        return lookup(name, true);
    }

    /** {@inheritDoc} */
    public Object lookup(final String name) throws NamingException {
        return lookup(name, true);
    }

    public Object lookup(final String name, boolean dereference) throws NamingException {
        return lookup(parseName(name), dereference);
    }

    public Object lookup(final Name name, boolean dereference) throws NamingException {
        check(name, JndiPermission.ACTION_LOOKUP);

        if (isEmpty(name)) {
            return new NamingContext(prefix, namingStore, environment);
        }

        final Name absoluteName = getAbsoluteName(name);

        Object result;
        try {
            result = namingStore.lookup(absoluteName,dereference);
        } catch(CannotProceedException cpe) {
            final Context continuationContext = NamingManager.getContinuationContext(cpe);
            if (continuationContext instanceof NamingContext) {
                result = ((NamingContext)continuationContext).lookup(cpe.getRemainingName(), dereference);
            } else {
                result = continuationContext.lookup(cpe.getRemainingName());
            }
        }

        if (result instanceof ResolveResult) {
            final ResolveResult resolveResult = (ResolveResult) result;
            final Object resolvedObject = resolveResult.getResolvedObj();

            Object context;
            if (resolvedObject instanceof Context){
                context = resolvedObject;
            } else if (resolvedObject instanceof LinkRef) {
                context = resolveLink(resolvedObject,dereference);
            } else {
                context = getObjectInstance(resolvedObject, absoluteName, environment);
            }
            if (!(context instanceof Context)) {
                throw notAContextException(absoluteName.getPrefix(absoluteName.size() - resolveResult.getRemainingName().size()));
            }
            final Context namingContext = (Context) context;
            if (namingContext instanceof NamingContext) {
                return ((NamingContext)namingContext).lookup(resolveResult.getRemainingName(), dereference);
            } else {
                return namingContext.lookup(resolveResult.getRemainingName());
            }
        } else if (result instanceof LinkRef) {
            result = resolveLink(result,dereference);
        } else if (result instanceof Reference) {
            result = getObjectInstance(result, absoluteName, environment);
            if (result instanceof LinkRef) {
                result = resolveLink(result,dereference);
            }
        }
        return result;
    }

    /** {@inheritDoc} */
    public void bind(final Name name, final Object object) throws NamingException {
        check(name, JndiPermission.ACTION_BIND);

        if(namingStore instanceof WritableNamingStore) {
            final Name absoluteName = getAbsoluteName(name);
            final Object value;
            if (object instanceof Referenceable) {
                value = ((Referenceable) object).getReference();
            } else {
                value = object;
            }
            if (System.getSecurityManager() == null) {
                getWritableNamingStore().bind(absoluteName, value);
            } else {
                // The permissions check has already happened for the binding further permissions should be allowed
                final NamingException e = AccessController.doPrivileged(new PrivilegedAction<NamingException>() {
                    @Override
                    public NamingException run() {
                        try {
                            getWritableNamingStore().bind(absoluteName, value);
                        } catch (NamingException e) {
                            return e;
                        }
                        return null;
                    }
                });
                // Check that a NamingException wasn't thrown during the bind
                if (e != null) {
                    throw e;
                }
            }
        } else {
            throw NamingLogger.ROOT_LOGGER.readOnlyNamingContext();
        }

    }

    /** {@inheritDoc} */
    public void bind(final String name, final Object obj) throws NamingException {
        bind(parseName(name), obj);
    }

    /** {@inheritDoc} */
    public void rebind(final Name name, Object object) throws NamingException {
        check(name, JndiPermission.ACTION_REBIND);

        if(namingStore instanceof WritableNamingStore) {
            final Name absoluteName = getAbsoluteName(name);
            if (object instanceof Referenceable) {
                object = ((Referenceable) object).getReference();
            }
            getWritableNamingStore().rebind(absoluteName, object);
        } else {
            throw NamingLogger.ROOT_LOGGER.readOnlyNamingContext();
        }
    }

    /** {@inheritDoc} */
    public void rebind(final String name, final Object object) throws NamingException {
        rebind(parseName(name), object);
    }

    /** {@inheritDoc} */
    public void unbind(final Name name) throws NamingException {
        check(name, JndiPermission.ACTION_UNBIND);

        if(namingStore instanceof WritableNamingStore) {
            final Name absoluteName = getAbsoluteName(name);
            getWritableNamingStore().unbind(absoluteName);
        } else {
            throw NamingLogger.ROOT_LOGGER.readOnlyNamingContext();
        }
    }

    /** {@inheritDoc} */
    public void unbind(final String name) throws NamingException {
        unbind(parseName(name));
    }

    /** {@inheritDoc} */
    public void rename(final Name oldName, final Name newName) throws NamingException {
        //check for appropriate permissions first so that no other info leaks from this context
        //in case of insufficient perms (like the fact if it is readonly or not)
        check(oldName, JndiPermission.ACTION_LOOKUP | JndiPermission.ACTION_UNBIND);
        check(newName, JndiPermission.ACTION_BIND);

        if (namingStore instanceof WritableNamingStore) {
            bind(newName, lookup(oldName));
            unbind(oldName);
        } else {
            throw NamingLogger.ROOT_LOGGER.readOnlyNamingContext();
        }
    }

    /** {@inheritDoc} */
    public void rename(final String oldName, final String newName) throws NamingException {
        rename(parseName(oldName), parseName(newName));
    }

    /** {@inheritDoc} */
    public NamingEnumeration<NameClassPair> list(final Name name) throws NamingException {
        check(name, JndiPermission.ACTION_LIST);

        try {
            return namingEnumeration(namingStore.list(getAbsoluteName(name)));
        } catch(CannotProceedException cpe) {
            final Context continuationContext = NamingManager.getContinuationContext(cpe);
            return continuationContext.list(cpe.getRemainingName());
        }  catch (RequireResolveException r) {
            final Object o = lookup(r.getResolve());
            if (o instanceof Context) {
                return ((Context)o).list(name.getSuffix(r.getResolve().size()));
            }

            throw notAContextException(r.getResolve());
        }
    }

    /** {@inheritDoc} */
    public NamingEnumeration<NameClassPair> list(final String name) throws NamingException {
        return list(parseName(name));
    }

    /** {@inheritDoc} */
    public NamingEnumeration<Binding> listBindings(final Name name) throws NamingException {
        check(name, JndiPermission.ACTION_LIST_BINDINGS);

        try {
            return namingEnumeration(namingStore.listBindings(getAbsoluteName(name)));
        } catch(CannotProceedException cpe) {
            final Context continuationContext = NamingManager.getContinuationContext(cpe);
            return continuationContext.listBindings(cpe.getRemainingName());
        } catch (RequireResolveException r) {
            final Object o = lookup(r.getResolve());
            if (o instanceof Context) {
                return ((Context)o).listBindings(name.getSuffix(r.getResolve().size()));
            }

            throw notAContextException(r.getResolve());
        }
    }

    /** {@inheritDoc} */
    public NamingEnumeration<Binding> listBindings(final String name) throws NamingException {
        return listBindings(parseName(name));
    }

    /** {@inheritDoc} */
    public void destroySubcontext(final Name name) throws NamingException {
        check(name, JndiPermission.ACTION_DESTROY_SUBCONTEXT);

        if(!(namingStore instanceof WritableNamingStore)) {
            throw NamingLogger.ROOT_LOGGER.readOnlyNamingContext();
        }
    }

    /** {@inheritDoc} */
    public void destroySubcontext(String name) throws NamingException {
        destroySubcontext(parseName(name));
    }

    /** {@inheritDoc} */
    public Context createSubcontext(Name name) throws NamingException {
        check(name, JndiPermission.ACTION_CREATE_SUBCONTEXT);

        if(namingStore instanceof WritableNamingStore) {
            final Name absoluteName = getAbsoluteName(name);
            return getWritableNamingStore().createSubcontext(absoluteName);
        } else {
            throw NamingLogger.ROOT_LOGGER.readOnlyNamingContext();
        }
    }

    /** {@inheritDoc} */
    public Context createSubcontext(String name) throws NamingException {
        return createSubcontext(parseName(name));
    }

    /** {@inheritDoc} */
    public Object lookupLink(Name name) throws NamingException {
        check(name, JndiPermission.ACTION_LOOKUP);

        if (name.isEmpty()) {
            return lookup(name);
        }
        try {
            final Name absoluteName = getAbsoluteName(name);
            Object link = namingStore.lookup(absoluteName);
            if (!(link instanceof LinkRef) && link instanceof Reference) {
                link = getObjectInstance(link, name, null);
            }
            return link;
        } catch (Exception e) {
            throw namingException(NamingLogger.ROOT_LOGGER.cannotLookupLink(), e, name);
        }
    }

    /** {@inheritDoc} */
    public Object lookupLink(String name) throws NamingException {
        return lookupLink(parseName(name));
    }

    /** {@inheritDoc} */
    public NameParser getNameParser(Name name) throws NamingException {
        return NameParser.INSTANCE;
    }

    /** {@inheritDoc} */
    public NameParser getNameParser(String name) throws NamingException {
        return NameParser.INSTANCE;
    }

    /** {@inheritDoc} */
    public Name composeName(Name name, Name prefix) throws NamingException {
        final Name result = (Name) prefix.clone();
        if (name instanceof CompositeName) {
            if (name.size() == 1) {
                // name could be a nested name
                final String firstComponent = name.get(0);
                result.addAll(parseName(firstComponent));
            } else {
                result.addAll(name);
            }
        } else {
            result.addAll(new CompositeName(name.toString()));
        }
        return result;
    }

    /** {@inheritDoc} */
    public String composeName(String name, String prefix) throws NamingException {
        return composeName(parseName(name), parseName(prefix)).toString();
    }

    /** {@inheritDoc} */
    public Object addToEnvironment(String propName, Object propVal) throws NamingException {
        final Object existing = environment.get(propName);
        environment.put(propName, propVal);
        return existing;
    }

    /** {@inheritDoc} */
    public Object removeFromEnvironment(String propName) throws NamingException {
        return environment.remove(propName);
    }

    /** {@inheritDoc} */
    public Hashtable<?, ?> getEnvironment() throws NamingException {
        return environment;
    }

    /** {@inheritDoc} */
    public void close() throws NamingException {
        // NO-OP
    }

    /** {@inheritDoc} */
    public String getNameInNamespace() throws NamingException {
        return prefix.toString();
    }

    /** {@inheritDoc} */
    public void addNamingListener(final Name target, final int scope, final NamingListener listener) throws NamingException {
        check(target, JndiPermission.ACTION_ADD_NAMING_LISTENER);
        namingStore.addNamingListener(target, scope, listener);
    }

    /** {@inheritDoc} */
    public void addNamingListener(final String target, final int scope, final NamingListener listener) throws NamingException {
        addNamingListener(parseName(target), scope, listener);
    }

    /** {@inheritDoc} */
    public void removeNamingListener(final NamingListener listener) throws NamingException {
        namingStore.removeNamingListener(listener);
    }

    /** {@inheritDoc} */
    public boolean targetMustExist() throws NamingException {
        return false;
    }

    private Name parseName(final String name) throws NamingException {
        return getNameParser(name).parse(name);
    }

    private Name getAbsoluteName(final Name name) throws NamingException {
        if(name.isEmpty()) {
            return composeName(name, prefix);
        }
        final String firstComponent = name.get(0);
        if(firstComponent.startsWith("java:")) {
            final String cleaned = firstComponent.substring(5);
            final Name suffix = name.getSuffix(1);
            if(cleaned.isEmpty()) {
                return suffix;
            }
            return suffix.add(0, cleaned);
        } else if(firstComponent.isEmpty()) {
            return name.getSuffix(1);
        } else {
            return composeName(name, prefix);
        }
    }

    private Object getObjectInstance(final Object object, final Name name, final Hashtable<?, ?> environment) throws NamingException {
        try {
            final ObjectFactoryBuilder factoryBuilder = ObjectFactoryBuilder.INSTANCE;
            final ObjectFactory objectFactory = factoryBuilder.createObjectFactory(object, environment);
            return objectFactory == null ? null : objectFactory.getObjectInstance(object, name, this, environment);
        } catch(NamingException e) {
            throw e;
        } catch(Throwable t) {
            throw NamingLogger.ROOT_LOGGER.cannotDeferenceObject(t);
        }
    }

    private Object resolveLink(Object result, boolean dereference) throws NamingException {
        final Object linkResult;
        try {
            final LinkRef linkRef = (LinkRef) result;
            final String referenceName = linkRef.getLinkName();
            if (referenceName.startsWith("./")) {
                linkResult = lookup(parseName(referenceName.substring(2)) ,dereference);
            } else {
                linkResult = new InitialContext().lookup(referenceName);
            }
        } catch (Throwable t) {
            throw NamingLogger.ROOT_LOGGER.cannotDeferenceObject(t);
        }
        return linkResult;
    }

    private void check(Name name, int actions) throws NamingException {
        final SecurityManager sm = System.getSecurityManager();
        if (sm != null && WildFlySecurityManager.isChecking()) {
            // build absolute name (including store's base name)
            Name absoluteName = (Name) namingStore.getBaseName().clone();
            if (name.isEmpty()) {
                absoluteName.addAll(prefix);
            } else {
                final String firstComponent = name.get(0);
                if (firstComponent.startsWith("java:")) {
                    absoluteName = name;
                } else if (firstComponent.isEmpty()) {
                    absoluteName.addAll(name.getSuffix(1));
                } else {
                    absoluteName.addAll(prefix);
                    if(name instanceof CompositeName) {
                        if (name.size() == 1) {
                            // name could be a nested name
                            absoluteName.addAll(parseName(firstComponent));
                        } else {
                            absoluteName.addAll(name);
                        }
                    } else {
                        absoluteName.addAll(new CompositeName(name.toString()));
                    }
                }
            }
            sm.checkPermission(new JndiPermission(absoluteName.toString(), actions));
        }
    }

    Name getPrefix() {
        return prefix;
    }

    NamingStore getNamingStore() {
        return namingStore;
    }

    WritableNamingStore getWritableNamingStore() {
        return WritableNamingStore.class.cast(getNamingStore());
    }
}


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

package org.jboss.as.ee.component;

import org.jboss.as.ee.component.interceptors.InterceptorOrder;
import org.jboss.as.ee.naming.InjectedEENamespaceContextSelector;
import org.jboss.as.naming.NamingStore;
import org.jboss.as.naming.deployment.ContextNames;
import org.jboss.as.server.deployment.DeploymentPhaseContext;
import org.jboss.as.server.deployment.DeploymentUnitProcessingException;
import org.jboss.invocation.ImmediateInterceptorFactory;
import org.jboss.invocation.InterceptorFactory;
import org.jboss.msc.inject.Injector;
import org.jboss.msc.service.ServiceBuilder;
import org.jboss.msc.service.ServiceName;

/**
 * A configurator which adds interceptors to the component which establish the naming context.  The interceptor is
 * added to the beginning of each chain.
 *
 * @author David M. Lloyd
 */
public final class NamespaceConfigurator implements ComponentConfigurator {

    /** {@inheritDoc} */
    public void configure(final DeploymentPhaseContext context, final ComponentDescription description, final ComponentConfiguration configuration) throws DeploymentUnitProcessingException {
        final ComponentNamingMode namingMode = description.getNamingMode();
        final InjectedEENamespaceContextSelector selector = new InjectedEENamespaceContextSelector();
        final String applicationName = configuration.getApplicationName();
        final String moduleName = configuration.getModuleName();
        final String compName = configuration.getComponentName();
        final ServiceName appContextServiceName = ContextNames.contextServiceNameOfApplication(applicationName);
        final ServiceName moduleContextServiceName = ContextNames.contextServiceNameOfModule(applicationName, moduleName);
        final ServiceName compContextServiceName = ContextNames.contextServiceNameOfComponent(applicationName, moduleName, compName);
        final Injector<NamingStore> appInjector = selector.getAppContextInjector();
        final Injector<NamingStore> moduleInjector = selector.getModuleContextInjector();
        final Injector<NamingStore> compInjector = selector.getCompContextInjector();
        final Injector<NamingStore> jbossInjector = selector.getJbossContextInjector();
        final Injector<NamingStore> globalInjector = selector.getGlobalContextInjector();
        final Injector<NamingStore> exportedInjector = selector.getExportedContextInjector();

        configuration.getStartDependencies().add(new DependencyConfigurator<ComponentStartService>() {
            public void configureDependency(final ServiceBuilder<?> serviceBuilder, ComponentStartService service) {
                serviceBuilder.addDependency(appContextServiceName, NamingStore.class, appInjector);
                serviceBuilder.addDependency(moduleContextServiceName, NamingStore.class, moduleInjector);
                if (namingMode == ComponentNamingMode.CREATE) {
                    serviceBuilder.addDependency(compContextServiceName, NamingStore.class, compInjector);
                } else if(namingMode == ComponentNamingMode.USE_MODULE) {
                    serviceBuilder.addDependency(moduleContextServiceName, NamingStore.class, compInjector);
                }
                serviceBuilder.addDependency(ContextNames.GLOBAL_CONTEXT_SERVICE_NAME, NamingStore.class, globalInjector);
                serviceBuilder.addDependency(ContextNames.JBOSS_CONTEXT_SERVICE_NAME, NamingStore.class, jbossInjector);
                serviceBuilder.addDependency(ContextNames.EXPORTED_CONTEXT_SERVICE_NAME, NamingStore.class, exportedInjector);
            }
        });
        final InterceptorFactory interceptorFactory = new ImmediateInterceptorFactory(new NamespaceContextInterceptor(selector, context.getDeploymentUnit().getServiceName()));
        configuration.addPostConstructInterceptor(interceptorFactory, InterceptorOrder.ComponentPostConstruct.JNDI_NAMESPACE_INTERCEPTOR);
        configuration.addPreDestroyInterceptor(interceptorFactory, InterceptorOrder.ComponentPreDestroy.JNDI_NAMESPACE_INTERCEPTOR);
        if(description.isPassivationApplicable()) {
            configuration.addPrePassivateInterceptor(interceptorFactory, InterceptorOrder.ComponentPassivation.JNDI_NAMESPACE_INTERCEPTOR);
            configuration.addPostActivateInterceptor(interceptorFactory, InterceptorOrder.ComponentPassivation.JNDI_NAMESPACE_INTERCEPTOR);
        }

        configuration.setNamespaceContextInterceptorFactory(interceptorFactory);
        configuration.setNamespaceContextSelector(selector);
    }
}


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

package org.jboss.as.web;

import org.jboss.as.controller.AttributeDefinition;
import org.jboss.as.controller.ListAttributeDefinition;
import org.jboss.as.controller.ModelOnlyResourceDefinition;
import org.jboss.as.controller.OperationDefinition;
import org.jboss.as.controller.PropertiesAttributeDefinition;
import org.jboss.as.controller.SimpleAttributeDefinition;
import org.jboss.as.controller.SimpleAttributeDefinitionBuilder;
import org.jboss.as.controller.SimpleOperationDefinitionBuilder;
import org.jboss.as.controller.StringListAttributeDefinition;
import org.jboss.as.controller.operations.validation.StringLengthValidator;
import org.jboss.as.controller.registry.AttributeAccess;
import org.jboss.as.controller.registry.ManagementResourceRegistration;
import org.jboss.dmr.ModelType;

/**
 * @author Tomaz Cerar
 * @created 23.2.12 18:03
 */
public class WebContainerDefinition extends ModelOnlyResourceDefinition {

    protected static final ListAttributeDefinition WELCOME_FILES = new StringListAttributeDefinition.Builder(Constants.WELCOME_FILE)
            .setXmlName(Constants.WELCOME_FILE)
            .setFlags(AttributeAccess.Flag.RESTART_RESOURCE_SERVICES)
            .setElementValidator(new StringLengthValidator(1, true, true))
            .setAllowExpression(true)
            .setRequired(false)
            .build();
    protected static final PropertiesAttributeDefinition MIME_MAPPINGS = new PropertiesAttributeDefinition.Builder(Constants.MIME_MAPPING, true)
            .setAllowExpression(true)
            .setWrapXmlElement(false)
            .setXmlName(Constants.MIME_MAPPING)
            .build();
    protected static final AttributeDefinition[] CONTAINER_ATTRIBUTES = {
            WELCOME_FILES,
            MIME_MAPPINGS,
    };
    private static final SimpleAttributeDefinition MIME_NAME = new SimpleAttributeDefinitionBuilder(Constants.NAME, ModelType.STRING, true)
            .setFlags(AttributeAccess.Flag.RESTART_ALL_SERVICES)
            .setValidator(new StringLengthValidator(1, true))
            .build();
    private static final SimpleAttributeDefinition MIME_VALUE = new SimpleAttributeDefinitionBuilder(Constants.VALUE, ModelType.STRING, true)
            .setFlags(AttributeAccess.Flag.RESTART_ALL_SERVICES)
            .setValidator(new StringLengthValidator(1, true))
            .build();
    private static final OperationDefinition ADD_MIME = new SimpleOperationDefinitionBuilder("add-mime", WebExtension.getResourceDescriptionResolver("container.mime-mapping"))
            .setParameters(MIME_NAME, MIME_VALUE)
            .build();
    private static final OperationDefinition REMOVE_MIME = new SimpleOperationDefinitionBuilder("remove-mime", WebExtension.getResourceDescriptionResolver("container.mime-mapping"))
            .addParameter(MIME_NAME)
            .build();

    static final WebContainerDefinition INSTANCE = new WebContainerDefinition();

    private WebContainerDefinition() {
        super(WebExtension.CONTAINER_PATH,
                WebExtension.getResourceDescriptionResolver(Constants.CONTAINER), WELCOME_FILES, MIME_MAPPINGS);
                setDeprecated(WebExtension.DEPRECATED_SINCE);
    }

    /**
     * {@inheritDoc}
     * Registers an add operation handler or a remove operation handler if one was provided to the constructor.
     */
    @Override
    public void registerOperations(ManagementResourceRegistration container) {
        super.registerOperations(container);
        container.registerOperationHandler(ADD_MIME, MimeMappingAdd.INSTANCE);
        container.registerOperationHandler(REMOVE_MIME, MimeMappingRemove.INSTANCE);
    }

}


package org.jboss.as.jaxrs.deployment;

import org.jboss.as.ee.structure.DeploymentType;
import org.jboss.as.ee.structure.DeploymentTypeMarker;
import org.jboss.as.jaxrs.JaxrsAnnotations;
import org.jboss.as.server.deployment.Attachments;
import org.jboss.as.server.deployment.DeploymentPhaseContext;
import org.jboss.as.server.deployment.DeploymentUnit;
import org.jboss.as.server.deployment.DeploymentUnitProcessingException;
import org.jboss.as.server.deployment.DeploymentUnitProcessor;
import org.jboss.as.server.deployment.annotation.CompositeIndex;
import org.jboss.jandex.AnnotationInstance;
import org.jboss.jandex.ClassInfo;
import org.jboss.jandex.DotName;
import org.jboss.jandex.Indexer;
import org.jboss.modules.Module;

import javax.ws.rs.DefaultValue;
import javax.ws.rs.ext.ParamConverter;
import javax.ws.rs.ext.ParamConverterProvider;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import static org.jboss.as.jaxrs.logging.JaxrsLogger.JAXRS_LOGGER;

/**
 * This class addresses the spec requirement of pre-processing resource
 * method parameters with DefaultValue annotations at application deployment
 * time.
 * (section 3.2 of the jax-rs 2.1 specification)
 */
public class JaxrsMethodParameterProcessor implements DeploymentUnitProcessor {
    private final DotName PARAM_CONVERTER_PROVIDER_DOTNAME =
            DotName.createSimple("javax.ws.rs.ext.ParamConverterProvider");
    private final DotName PARAM_CONVERTER_DOTNAME =
            DotName.createSimple("javax.ws.rs.ext.ParamConverter");
    private final DotName PARAM_CONVERTER_LAZY_DOTNAME =
            DotName.createSimple("javax.ws.rs.ext.ParamConverter$Lazy");
    private final DotName DEFAULT_VALUE_DOTNAME =
            DotName.createSimple("javax.ws.rs.DefaultValue");
    @Override
    public void deploy(DeploymentPhaseContext phaseContext)
            throws DeploymentUnitProcessingException {

        final DeploymentUnit deploymentUnit = phaseContext.getDeploymentUnit();
        if (!JaxrsDeploymentMarker.isJaxrsDeployment(deploymentUnit)) {
            return;
        }

        if (!DeploymentTypeMarker.isType(DeploymentType.WAR, deploymentUnit)) {
            return;
        }

        final ResteasyDeploymentData resteasy = deploymentUnit.getAttachment(
                JaxrsAttachments.RESTEASY_DEPLOYMENT_DATA);
        if (resteasy == null) {
            return;
        }
        final Module module = deploymentUnit.getAttachment(Attachments.MODULE);
        final CompositeIndex index = deploymentUnit.getAttachment(
                Attachments.COMPOSITE_ANNOTATION_INDEX);

        processData(index, module.getClassLoader(), resteasy, false);
    }

    /**
     *
     * @param index
     * @param classLoader
     * @param resteasy
     * @param isFromUnitTest
     * @throws DeploymentUnitProcessingException
     */
    private void processData(final CompositeIndex index, final ClassLoader classLoader,
                             ResteasyDeploymentData resteasy, boolean isFromUnitTest)
            throws DeploymentUnitProcessingException {

        List<ParamDetail> detailList = getResouceClasses(index, classLoader,
                resteasy.getScannedResourceClasses(), isFromUnitTest);

        if (!detailList.isEmpty()) {
            HashMap<String, List<Validator>> paramConverterMap =
                    getParamConverters(index, classLoader,
                            resteasy.getScannedProviderClasses(), isFromUnitTest);

            validateDefaultValues(detailList, paramConverterMap);
        }

    }

    /**
     * Process all parameter DefaulValue objects.  Flag all parameters with
     * missing and invalid converters.
     *
     * @param detailList
     * @param paramConverterMap
     */
    private void validateDefaultValues(List<ParamDetail> detailList,
                                       HashMap<String, List<Validator>> paramConverterMap)
            throws DeploymentUnitProcessingException {

        for(ParamDetail detail : detailList) {

            // check param converter for specific return type
            List<Validator> validators = paramConverterMap.get(
                    detail.parameter.getName());

            if (validators == null) {
                // check for paramConverterProvider
                validators = paramConverterMap.get(Object.class.getName());
            }

            boolean isCheckClazzMethods = true;
            if (validators != null) {
                for (Validator v : validators) {
                    if (!v.isLazyLoad()) {
                        try {
                            Object obj = v.verify(detail);
                            if (obj != null) {
                                isCheckClazzMethods = false;
                                break;
                            }
                        } catch (Exception e) {
                            JAXRS_LOGGER.paramConverterFailed(detail.defaultValue.value(),
                                    detail.parameter.getSimpleName(),
                                    detail.method.toString(),
                                    v.toString(), e.getClass().getName(),
                                    e.getMessage());
                        }
                    }
                }
            }

            if (isCheckClazzMethods) {
                Class baseType = detail.parameter;
                Method valueOf = null;

                // constructor rule
                try {
                    Constructor<?> ctor = baseType.getConstructor(String.class);
                    if (Modifier.isPublic(ctor.getModifiers())) {
                        continue; // success move to next detail
                    }
                } catch (NoSuchMethodException ignored) { }

                // method fromValue(String.class) rule
                try {
                    Method fromValue = baseType.getDeclaredMethod("fromValue", String.class);
                    if (Modifier.isPublic(fromValue.getModifiers())) {
                        for (Annotation ann : baseType.getAnnotations()) {
                            if (ann.annotationType().getName()
                                    .equals("javax.xml.bind.annotation.XmlEnum")) {
                                valueOf = fromValue;
                            }
                        }
                        validateBaseType(fromValue, detail.defaultValue.value(), detail);
                        continue; // success move to next detail
                    }
                } catch (NoSuchMethodException ignoredA) { }

                // method fromString(String.class) rule
                Method fromString = null;
                try {
                    fromString = baseType.getDeclaredMethod("fromString", String.class);
                    if (Modifier.isStatic(fromString.getModifiers())) {
                        validateBaseType(fromString, detail.defaultValue.value(), detail);
                        continue; // success move to next detail
                    }
                } catch (NoSuchMethodException ignoredB) {
                }

                // method valueof(String.class) rule
                try {
                    valueOf = baseType.getDeclaredMethod("valueOf", String.class);
                    if (Modifier.isStatic(valueOf.getModifiers())) {
                        validateBaseType(valueOf, detail.defaultValue.value(), detail);
                        continue; // success move to next detail
                    }
                } catch (NoSuchMethodException ignored) {
                }

            }
        }

    }

    /**
     * Create a list of ParamConverters and ParamConverterProviders present
     * in the application.
     *
     * When running unitTest the classes must be indexed.  In normal deployment
     * the indexing is already done.
     *
     * @param index
     * @param classLoader
     * @return
     */
    private HashMap<String, List<Validator>>  getParamConverters(
            final CompositeIndex index, final ClassLoader classLoader,
            Set<String> knownProviderClasses, boolean isFromUnitTest) {

        HashMap<String, List<Validator>> paramConverterMap = new HashMap<>();
        List<Validator> converterProviderList = new ArrayList<>();
        paramConverterMap.put(Object.class.getName(), converterProviderList);

        Set<ClassInfo> paramConverterSet = new HashSet<ClassInfo>();
        if(isFromUnitTest) {
            Indexer indexer = new Indexer();
            for (String className : knownProviderClasses) {
                try {
                    String pathName = className.replace(".", File.separator);
                    InputStream stream = classLoader.getResourceAsStream(
                            pathName + ".class");
                    indexer.index(stream);
                    stream.close();
                } catch (IOException e) {
                    JAXRS_LOGGER.classIntrospectionFailure(e.getClass().getName(),
                            e.getMessage());
                }
            }

            List<ClassInfo> paramConverterList =
                    indexer.complete().getKnownDirectImplementors(PARAM_CONVERTER_DOTNAME);
            List<ClassInfo> paramConverterProviderList =
                    indexer.complete().getKnownDirectImplementors(PARAM_CONVERTER_PROVIDER_DOTNAME);
            paramConverterSet.addAll(paramConverterList);
            paramConverterSet.addAll(paramConverterProviderList);

        } else {

            for (String clazzName : knownProviderClasses) {
                ClassInfo classInfo = index.getClassByName(DotName.createSimple(clazzName));
                if (classInfo != null) {
                    List<DotName> intfNamesList = classInfo.interfaceNames();
                    for (DotName dotName : intfNamesList) {
                        if (dotName.compareTo(PARAM_CONVERTER_DOTNAME) == 0
                                || dotName.compareTo(PARAM_CONVERTER_PROVIDER_DOTNAME) == 0) {
                            paramConverterSet.add(classInfo);
                            break;
                        }
                    }
                }
            }
        }

        for (ClassInfo classInfo : paramConverterSet) {

            Class<?> clazz = null;
            Method method = null;
            try {
                String clazzName = classInfo.name().toString();
                if (clazzName.endsWith("$1")) {
                    clazzName = clazzName.substring(0, clazzName.length()-2);
                }

                clazz = classLoader.loadClass(clazzName);
                Constructor<?> ctor = clazz.getConstructor();
                Object object = ctor.newInstance();

                List<AnnotationInstance> lazyLoadAnnotations =classInfo
                        .annotations().get(PARAM_CONVERTER_LAZY_DOTNAME);

                if (object instanceof ParamConverterProvider) {
                    ParamConverterProvider pcpObj = (ParamConverterProvider) object;
                    method = pcpObj.getClass().getMethod(
                            "getConverter",
                            Class.class,
                            Type.class,
                            Annotation[].class);
                    converterProviderList.add(new ConverterProvider(pcpObj, method, lazyLoadAnnotations));
                }

                if (object instanceof ParamConverter) {
                    ParamConverter pc = (ParamConverter) object;
                    method = getFromStringMethod(pc.getClass());
                    Class<?> returnClazz = method.getReturnType();
                    List<Validator> verifiers = paramConverterMap.get(returnClazz.getName());
                    PConverter pConverter = new PConverter(pc, method, lazyLoadAnnotations);
                    if (verifiers == null){
                        List<Validator> vList = new ArrayList<>();
                        vList.add(pConverter);
                        paramConverterMap.put(returnClazz.getName(), vList);
                    } else {
                        verifiers.add(pConverter);
                    }
                }

            } catch(NoSuchMethodException nsne) {
                JAXRS_LOGGER.classIntrospectionFailure(nsne.getClass().getName(),
                        nsne.getMessage());
            } catch (Exception e) {
                JAXRS_LOGGER.classIntrospectionFailure(e.getClass().getName(),
                        e.getMessage());
            }
        }

        return paramConverterMap;
    }

    private Method getFromStringMethod(final Class clazz) {
        Method method = null;
        try {
            method = clazz.getMethod("fromString", String.class);
        }catch(NoSuchMethodException nsme) {
            JAXRS_LOGGER.classIntrospectionFailure(nsme.getClass().getName(),
                    nsme.getMessage());
        }
        return method;
    }

    /**
     * Create list of objects that represents resource method parameters with a
     * DefaultValue annontation assigned to it.
     *
     * When running unitTest the classes must be indexed.  In normal deployment
     * the indexing is already done.
     *
     * @param index
     * @param classLoader
     * @return
     */
    private ArrayList<ParamDetail> getResouceClasses(final CompositeIndex index,
                                   final ClassLoader classLoader,
                                   Set<String> knownResourceClasses,
                                   boolean isFromUnitTest) {

        ArrayList<ParamDetail> detailList = new ArrayList<>();
        ArrayList<String> classNameArr = new ArrayList<>();

        if (isFromUnitTest) {
            Indexer indexer = new Indexer();
            for (String className : knownResourceClasses) {
                try {
                    String pathName = className.replace(".", File.separator);
                    InputStream stream = classLoader.getResourceAsStream(pathName + ".class");
                    ClassInfo classInfo = indexer.index(stream);

                    List<AnnotationInstance> defaultValuesList =
                            classInfo.annotations().get(DEFAULT_VALUE_DOTNAME);

                    if (!defaultValuesList.isEmpty()) {
                        classNameArr.add((classInfo).name().toString());
                    }

                    stream.close();

                } catch (IOException e) {
                    JAXRS_LOGGER.classIntrospectionFailure(e.getClass().getName(),
                            e.getMessage());
                }
            }
        } else {

            for (String clazzName : knownResourceClasses) {

                ClassInfo classInfo = index.getClassByName(DotName.createSimple(clazzName));
                if (classInfo != null) {
                    Map<DotName, List<AnnotationInstance>> annotationsMap =
                            classInfo.annotations();

                    if (annotationsMap != null && !annotationsMap.isEmpty()) {
                        List<AnnotationInstance> xInstance = annotationsMap.get(
                                JaxrsAnnotations.PATH.getDotName());
                        List<AnnotationInstance> xdefaultValuesList =
                                annotationsMap.get(DEFAULT_VALUE_DOTNAME);
                        if ((xInstance != null && !xInstance.isEmpty()) &&
                             (xdefaultValuesList != null && !xdefaultValuesList.isEmpty())) {
                            classNameArr.add((classInfo).name().toString());
                        }
                    }
                }
            }
        }

        // resource classes with @DefaultValue
        // find methods and method params with @DefaultValue
        for (String className : classNameArr) {
            Class<?> clazz = null;
            try {
                clazz = classLoader.loadClass(className);
                for (Method method : clazz.getMethods()) {
                    if (clazz == method.getDeclaringClass()) {
                        Type[] genParamTypeArr = method.getGenericParameterTypes();
                        Annotation[][] annotationMatrix = method.getParameterAnnotations();

                        for (int j = 0; j < genParamTypeArr.length; j++) {
                            DefaultValue defaultValue = lookupDefaultValueAnn(annotationMatrix[j]);

                            if (defaultValue != null) {
                                Class paramClazz = checkParamType(genParamTypeArr[j],
                                        method, j, classLoader);

                                if (paramClazz != null) {
                                    detailList.add(new ParamDetail(method,
                                            defaultValue, paramClazz, annotationMatrix[j]));
                                }
                            }
                        }
                    }
                }

            } catch (ClassNotFoundException e) {
                JAXRS_LOGGER.classIntrospectionFailure(e.getClass().getName(),
                        e.getMessage());
            }
        }
        return detailList;
    }

    /**
     * Take steps to properly identify the parameter's data type
     * @param genParamType
     * @param method
     * @param paramPos
     * @param classLoader
     * @return
     */
    private Class checkParamType(Type genParamType, final Method method,
                                 final int paramPos, final ClassLoader classLoader){

        Class paramClazz = null;

        if (genParamType instanceof ParameterizedType) {
            ParameterizedType pType = (ParameterizedType) genParamType;
            Type[] actualTypeArgs = pType.getActualTypeArguments();
            // skip Map types. Don't know how to set default value for these
            if (actualTypeArgs.length == 1) {
                try {
                    paramClazz = classLoader.loadClass(actualTypeArgs[0].getTypeName());
                } catch (Exception ee) {
                    JAXRS_LOGGER.classIntrospectionFailure(ee.getClass().getName(),
                            ee.getMessage());
                }
            }
        } else {
            Class<?>[] paramArr = method.getParameterTypes();
            if (paramArr[paramPos].isArray()) {
                Class compClazz = paramArr[paramPos].getComponentType();
                if (!compClazz.isPrimitive()) {
                    paramClazz = compClazz;
                }
            } else {
                if (!paramArr[paramPos].isPrimitive()) {
                    paramClazz = paramArr[paramPos];
                }
            }
        }
        return paramClazz;
    }

    /**
     * Extract a DefaultValue annotation from the list of parameter annotations
     * @param annotationArr
     * @return
     */
    private DefaultValue lookupDefaultValueAnn(Annotation[] annotationArr) {
        for (Annotation ann :  annotationArr) {

            if (ann instanceof DefaultValue) {
                return (DefaultValue)ann;
            }
        }
        return null;
    }

    /**
     * Data structure for passing around related parameter information
     */
    private class ParamDetail {
        public Method method;
        public DefaultValue defaultValue;
        public Class parameter;
        public Annotation[] annotations;

        public ParamDetail(Method method, DefaultValue defaultValue, Class parameter,
                           Annotation[] annotations) {
            this.method = method;
            this.defaultValue = defaultValue;
            this.parameter = parameter;
            this.annotations = annotations;
        }
    }

    private interface Validator {
      public Object verify(ParamDetail detail) throws Exception;
      public boolean isLazyLoad();
    }

    /**
     * ParamConverterProvider's getConverter method used for validation
     */
    private class ConverterProvider implements Validator {
        private ParamConverterProvider pcp;
        private ParamConverter pc = null;
        private Method method;
        private boolean isLazyLoad = false;

        public ConverterProvider(ParamConverterProvider pcp, Method method,
                                 List<AnnotationInstance> lazyAnnotations) {
           this.pcp = pcp;
           this.method = method;
           if (lazyAnnotations != null && !lazyAnnotations.isEmpty()) {
               isLazyLoad = true;
           }
        }

        public boolean isLazyLoad() {
            return isLazyLoad;
        }

        public Object verify(ParamDetail detail) throws Exception {

            Object obj = method.invoke(pcp,
                    detail.parameter,
                    detail.parameter.getComponentType(),
                    detail.annotations);

            if (obj != null) {
                if (obj instanceof ParamConverter) {
                    this.pc = (ParamConverter) obj;
                    return pc.fromString(detail.defaultValue.value());
                }
            }
            return obj;
        }

        @Override
        public String toString() {
            if (pc == null) {
                return pcp.getClass().getName();
            }
            return pc.getClass().getName();
        }
    }

    /**
     * ParamConverter's method fromString  used for validation
     */
    private class PConverter implements Validator {
        private ParamConverter pc;
        private Method method;
        private boolean isLazyLoad = false;

        public PConverter(ParamConverter pc, Method method,
                          List<AnnotationInstance> lazyAnnotations) {
            this.pc = pc;
            this.method = method;
            if (lazyAnnotations != null && !lazyAnnotations.isEmpty()) {
                isLazyLoad = true;
            }
        }

        public boolean isLazyLoad() {
            return isLazyLoad;
        }

        public Object verify(ParamDetail detail) throws Exception {
                Object obj = method.invoke(pc, detail.defaultValue.value());
                return obj;
        }

        @Override
        public String toString() {
            return pc.getClass().getName();
        }
    }

    /**
     * Confirm the method can handle the default value without throwing
     * and exception.
     *
     * @param method
     * @param defaultValue
     */
    private void validateBaseType(Method method, String defaultValue, ParamDetail detail)
        throws DeploymentUnitProcessingException {
        if (defaultValue != null) {
            try {
                method.invoke(method.getDeclaringClass(), defaultValue);
            } catch (Exception e) {
                JAXRS_LOGGER.baseTypeMethodFailed(defaultValue,
                        detail.parameter.getSimpleName(), detail.method.toString(),
                        method.toString(), e.getClass().getName(),
                        e.getMessage());
            }
        }
    }

    /**
     * Method allows unit-test to provide processing data.
     * @param resteasyDeploymentData
     */
    public void testProcessor(final ClassLoader classLoader,
                              final ResteasyDeploymentData resteasyDeploymentData)
            throws DeploymentUnitProcessingException {
        processData(null, classLoader, resteasyDeploymentData, true);
    }

    @Override
    public void undeploy(DeploymentUnit context) {

    }
}


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

package org.jboss.as.ejb3.subsystem;

import org.jboss.as.controller.Extension;
import org.jboss.as.controller.ExtensionContext;
import org.jboss.as.controller.ModelVersion;
import org.jboss.as.controller.PathElement;
import org.jboss.as.controller.ResourceDefinition;
import org.jboss.as.controller.SimpleResourceDefinition;
import org.jboss.as.controller.SimpleResourceDefinition.Parameters;
import org.jboss.as.controller.SubsystemRegistration;
import org.jboss.as.controller.descriptions.ModelDescriptionConstants;
import org.jboss.as.controller.descriptions.ResourceDescriptionResolver;
import org.jboss.as.controller.descriptions.StandardResourceDescriptionResolver;
import org.jboss.as.controller.parsing.ExtensionParsingContext;
import org.jboss.as.controller.registry.ManagementResourceRegistration;
import org.jboss.as.controller.services.path.PathManager;
import org.jboss.as.ejb3.subsystem.deployment.MessageDrivenBeanResourceDefinition;
import org.jboss.as.ejb3.subsystem.deployment.SingletonBeanDeploymentResourceDefinition;
import org.jboss.as.ejb3.subsystem.deployment.StatefulSessionBeanDeploymentResourceDefinition;
import org.jboss.as.ejb3.subsystem.deployment.StatelessSessionBeanDeploymentResourceDefinition;

/**
 * Extension that provides the EJB3 subsystem.
 *
 * @author Emanuel Muckenhuber
 * @author Brian Stansberry (c) 2011 Red Hat Inc.
 */
public class EJB3Extension implements Extension {

    public static final String SUBSYSTEM_NAME = "ejb3";
    public static final String NAMESPACE_1_0 = EJB3SubsystemNamespace.EJB3_1_0.getUriString();
    public static final String NAMESPACE_1_1 = EJB3SubsystemNamespace.EJB3_1_1.getUriString();
    public static final String NAMESPACE_1_2 = EJB3SubsystemNamespace.EJB3_1_2.getUriString();
    public static final String NAMESPACE_1_3 = EJB3SubsystemNamespace.EJB3_1_3.getUriString();
    public static final String NAMESPACE_1_4 = EJB3SubsystemNamespace.EJB3_1_4.getUriString();
    public static final String NAMESPACE_1_5 = EJB3SubsystemNamespace.EJB3_1_5.getUriString();
    public static final String NAMESPACE_2_0 = EJB3SubsystemNamespace.EJB3_2_0.getUriString();
    public static final String NAMESPACE_3_0 = EJB3SubsystemNamespace.EJB3_3_0.getUriString();
    public static final String NAMESPACE_4_0 = EJB3SubsystemNamespace.EJB3_4_0.getUriString();
    public static final String NAMESPACE_5_0 = EJB3SubsystemNamespace.EJB3_5_0.getUriString();

    static final PathElement SUBSYSTEM_PATH = PathElement.pathElement(ModelDescriptionConstants.SUBSYSTEM, SUBSYSTEM_NAME);

    static final ModelVersion CURRENT_MODEL_VERSION = ModelVersion.create(5, 0, 0);

    private static final String RESOURCE_NAME = EJB3Extension.class.getPackage().getName() + ".LocalDescriptions";

    public static ResourceDescriptionResolver getResourceDescriptionResolver(final String keyPrefix) {
        return new StandardResourceDescriptionResolver(keyPrefix, RESOURCE_NAME, EJB3Extension.class.getClassLoader(), true, true);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void initialize(ExtensionContext context) {

        final boolean registerRuntimeOnly = context.isRuntimeOnlyRegistrationValid();

        final SubsystemRegistration subsystem = context.registerSubsystem(SUBSYSTEM_NAME, CURRENT_MODEL_VERSION);

        subsystem.registerXMLElementWriter(EJB3SubsystemXMLPersister.INSTANCE);

        PathManager pathManager = context.getProcessType().isServer() ? context.getPathManager() : null;
        subsystem.registerSubsystemModel(new EJB3SubsystemRootResourceDefinition(registerRuntimeOnly, pathManager));

        if (registerRuntimeOnly) {
            ResourceDefinition deploymentsDef = new SimpleResourceDefinition(new Parameters(PathElement.pathElement(ModelDescriptionConstants.SUBSYSTEM, SUBSYSTEM_NAME),
                    getResourceDescriptionResolver("deployed")).setFeature(false));
            final ManagementResourceRegistration deploymentsRegistration = subsystem.registerDeploymentModel(deploymentsDef);
            deploymentsRegistration.registerSubModel(MessageDrivenBeanResourceDefinition.INSTANCE);
            deploymentsRegistration.registerSubModel(SingletonBeanDeploymentResourceDefinition.INSTANCE);
            deploymentsRegistration.registerSubModel(StatelessSessionBeanDeploymentResourceDefinition.INSTANCE);
            deploymentsRegistration.registerSubModel(StatefulSessionBeanDeploymentResourceDefinition.INSTANCE);
        }

    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void initializeParsers(ExtensionParsingContext context) {
        context.setSubsystemXmlMapping(SUBSYSTEM_NAME, NAMESPACE_1_0, EJB3Subsystem10Parser::new);
        context.setSubsystemXmlMapping(SUBSYSTEM_NAME, NAMESPACE_1_1, EJB3Subsystem11Parser::new);
        context.setSubsystemXmlMapping(SUBSYSTEM_NAME, NAMESPACE_1_2, EJB3Subsystem12Parser::new);
        context.setSubsystemXmlMapping(SUBSYSTEM_NAME, NAMESPACE_1_3, EJB3Subsystem13Parser::new);
        context.setSubsystemXmlMapping(SUBSYSTEM_NAME, NAMESPACE_1_4, EJB3Subsystem14Parser::new);
        context.setSubsystemXmlMapping(SUBSYSTEM_NAME, NAMESPACE_1_5, EJB3Subsystem15Parser::new);
        context.setSubsystemXmlMapping(SUBSYSTEM_NAME, NAMESPACE_2_0, EJB3Subsystem20Parser::new);
        context.setSubsystemXmlMapping(SUBSYSTEM_NAME, NAMESPACE_3_0, EJB3Subsystem30Parser::new);
        context.setSubsystemXmlMapping(SUBSYSTEM_NAME, NAMESPACE_4_0, EJB3Subsystem40Parser::new);
        context.setSubsystemXmlMapping(SUBSYSTEM_NAME, NAMESPACE_5_0, EJB3Subsystem50Parser::new);
    }
}


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

package org.jboss.as.jpa.container;

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

import org.jboss.as.jpa.messages.JpaLogger;

/**
 * Tracks the lifecycle of created XPC Entity Managers
 *
 * @author Scott Marlow
 */
public class CreatedEntityManagers {

    private static ExtendedEntityManager[] EMPTY = new ExtendedEntityManager[0];

    // at injection time, the SFSB that is being created isn't registered right away
    // that happens later at postConstruct time.
    //
    // The deferToPostConstruct is a one item length store (hack)
    private static ThreadLocal<List<ExtendedEntityManager>> deferToPostConstruct = new ThreadLocal<List<ExtendedEntityManager>>() {
        protected List<ExtendedEntityManager> initialValue() {
            return new ArrayList<ExtendedEntityManager>(1);
        }
    };

    /**
     * At injection time of a XPC, register the XPC (step 1 of 2)
     * finishRegistrationOfPersistenceContext is step 2
     *
     * @param xpc The ExtendedEntityManager
     */
    public static void registerPersistenceContext(ExtendedEntityManager xpc) {
        if (xpc == null) {
            throw JpaLogger.ROOT_LOGGER.nullParameter("SFSBXPCMap.RegisterPersistenceContext", "EntityManager");
        }
        final List<ExtendedEntityManager> store = deferToPostConstruct.get();
        store.add(xpc);
    }

    /**
     * Called by postconstruct interceptor
     */
    public static ExtendedEntityManager[] getDeferredEntityManagers() {
        List<ExtendedEntityManager> store = deferToPostConstruct.get();
        try {
            if(store.isEmpty()) {
                return EMPTY;
            } else {
                return store.toArray(new ExtendedEntityManager[store.size()]);
            }
        } finally {
            store.clear();
        }
    }

}