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

package org.wildfly.extension.undertow;

import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.function.Consumer;
import javax.security.jacc.PolicyContext;
import javax.security.jacc.PolicyContextException;

import io.undertow.Version;
import org.jboss.as.controller.PathAddress;
import org.jboss.msc.service.Service;
import org.jboss.msc.service.ServiceName;
import org.jboss.msc.service.StartContext;
import org.jboss.msc.service.StartException;
import org.jboss.msc.service.StopContext;
import org.jboss.security.SecurityConstants;
import org.wildfly.extension.undertow.logging.UndertowLogger;
import org.wildfly.extension.undertow.security.jacc.HttpServletRequestPolicyContextHandler;

/**
 * @author Tomaz Cerar (c) 2013 Red Hat Inc.
 * @author Stuart Douglas
 */
@SuppressWarnings("ALL")
public class UndertowService implements Service<UndertowService> {

    @Deprecated
    public static final ServiceName UNDERTOW = ServiceName.JBOSS.append("undertow");
    @Deprecated
    public static final ServiceName SERVLET_CONTAINER = UNDERTOW.append(Constants.SERVLET_CONTAINER);
    @Deprecated
    public static final ServiceName SERVER = UNDERTOW.append(Constants.SERVER);
    /**
     * service name under which default server is bound.
     */
    public static final ServiceName DEFAULT_SERVER = UNDERTOW.append("default-server");

    /**
     * service name under which default host of default server is bound.
     */
    public static final ServiceName DEFAULT_HOST = DEFAULT_SERVER.append("default-host");

    public static final ServiceName UNDERTOW_DEPLOYMENT = ServiceName.of("undertow-deployment");
    /**
     * The base name for listener/handler/filter services.
     */
    public static final ServiceName HANDLER = UNDERTOW.append(Constants.HANDLER);
    public static final ServiceName FILTER = UNDERTOW.append(Constants.FILTER);

    /**
     * The base name for web deployments.
     */
    static final ServiceName WEB_DEPLOYMENT_BASE = UNDERTOW.append("deployment");
    private final String defaultContainer;
    private final String defaultServer;
    private final String defaultVirtualHost;
    private final Set<Server> registeredServers = new CopyOnWriteArraySet<>();
    private final List<UndertowEventListener> listeners = Collections.synchronizedList(new LinkedList<UndertowEventListener>());
    private final String instanceId;
    private volatile boolean statisticsEnabled;
    private final Set<Consumer<Boolean>> statisticsChangeListenters = new HashSet<>();

    protected UndertowService(String defaultContainer, String defaultServer, String defaultVirtualHost, String instanceId, boolean statisticsEnabled) {
        this.defaultContainer = defaultContainer;
        this.defaultServer = defaultServer;
        this.defaultVirtualHost = defaultVirtualHost;
        this.instanceId = instanceId;
        this.statisticsEnabled = statisticsEnabled;
    }

    public static ServiceName deploymentServiceName(ServiceName deploymentServiceName) {
        return deploymentServiceName.append(UNDERTOW_DEPLOYMENT);
    }

    /**
     * The old deployment unit service name. This is still registered as an alias, however {{@link #deploymentServiceName(ServiceName)}}
     * should be used instead.
     * @param serverName The server name
     * @param virtualHost The virtual host
     * @param contextPath The context path
     * @return The legacy deployment service alias
     */
    @Deprecated
    public static ServiceName deploymentServiceName(final String serverName, final String virtualHost, final String contextPath) {
        return WEB_DEPLOYMENT_BASE.append(serverName).append(virtualHost).append("".equals(contextPath) ? "/" : contextPath);
    }

    @Deprecated
    public static ServiceName virtualHostName(final String server, final String virtualHost) {
        return SERVER.append(server).append(virtualHost);
    }

    public static ServiceName locationServiceName(final String server, final String virtualHost, final String locationName) {
        return virtualHostName(server, virtualHost).append(Constants.LOCATION, locationName);
    }

    public static ServiceName accessLogServiceName(final String server, final String virtualHost) {
        return virtualHostName(server, virtualHost).append(Constants.ACCESS_LOG);
    }

    public static ServiceName ssoServiceName(final String server, final String virtualHost) {
        return virtualHostName(server, virtualHost).append("single-sign-on");
    }

    public static ServiceName consoleRedirectServiceName(final String server, final String virtualHost) {
        return virtualHostName(server, virtualHost).append("console", "redirect");
    }

    public static ServiceName filterRefName(final String server, final String virtualHost, final String locationName, final String filterName) {
        return virtualHostName(server, virtualHost).append(Constants.LOCATION, locationName).append("filter-ref").append(filterName);
    }

    public static ServiceName filterRefName(final String server, final String virtualHost, final String filterName) {
        return SERVER.append(server).append(virtualHost).append("filter-ref").append(filterName);
    }

    public static ServiceName getFilterRefServiceName(final PathAddress address, String name) {
        final PathAddress oneUp = address.subAddress(0, address.size() - 1);
        final PathAddress twoUp = oneUp.subAddress(0, oneUp.size() - 1);
        final PathAddress threeUp = twoUp.subAddress(0, twoUp.size() - 1);
        ServiceName serviceName;
        if (address.getLastElement().getKey().equals(Constants.FILTER_REF)) {
            if (oneUp.getLastElement().getKey().equals(Constants.HOST)) { //adding reference
                String host = oneUp.getLastElement().getValue();
                String server = twoUp.getLastElement().getValue();
                serviceName = UndertowService.filterRefName(server, host, name);
            } else {
                String location = oneUp.getLastElement().getValue();
                String host = twoUp.getLastElement().getValue();
                String server = threeUp.getLastElement().getValue();
                serviceName = UndertowService.filterRefName(server, host, location, name);
            }
        } else if (address.getLastElement().getKey().equals(Constants.HOST)) {
            String host = address.getLastElement().getValue();
            String server = oneUp.getLastElement().getValue();
            serviceName = UndertowService.filterRefName(server, host, name);
        } else {
            String location = address.getLastElement().getValue();
            String host = oneUp.getLastElement().getValue();
            String server = twoUp.getLastElement().getValue();
            serviceName = UndertowService.filterRefName(server, host, location, name);
        }
        return serviceName;
    }

    @Deprecated
    public static ServiceName listenerName(String listenerName) {
        return UNDERTOW.append(Constants.LISTENER).append(listenerName);
    }

    @Override
    public void start(StartContext context) throws StartException {
        UndertowLogger.ROOT_LOGGER.serverStarting(Version.getVersionString());
        // Register the active request PolicyContextHandler
        try {
            PolicyContext.registerHandler(SecurityConstants.WEB_REQUEST_KEY,
                    new HttpServletRequestPolicyContextHandler(), true);
        } catch (PolicyContextException pce) {
            UndertowLogger.ROOT_LOGGER.failedToRegisterPolicyContextHandler(SecurityConstants.WEB_REQUEST_KEY, pce);
        }
    }

    @Override
    public void stop(StopContext context) {
        // Remove PolicyContextHandler
        Set handlerKeys = PolicyContext.getHandlerKeys();
        handlerKeys.remove(SecurityConstants.WEB_REQUEST_KEY);

        UndertowLogger.ROOT_LOGGER.serverStopping(Version.getVersionString());

        fireEvent(new EventInvoker() {
            @Override
            public void invoke(UndertowEventListener listener) {
                listener.onShutdown();
            }
        });
    }

    @Override
    public UndertowService getValue() throws IllegalStateException, IllegalArgumentException {
        return this;
    }

    protected void registerServer(final Server server) {
        registeredServers.add(server);
        fireEvent(new EventInvoker() {
            @Override
            public void invoke(UndertowEventListener listener) {
                listener.onServerStart(server);
            }
        });
    }

    protected void unregisterServer(final Server server) {
        registeredServers.remove(server);
        fireEvent(new EventInvoker() {
            @Override
            public void invoke(UndertowEventListener listener) {
                listener.onServerStop(server);
            }
        });
    }

    public String getDefaultContainer() {
        return defaultContainer;
    }

    public String getDefaultServer() {
        return defaultServer;
    }

    public String getDefaultVirtualHost() {
        return defaultVirtualHost;
    }

    public Set<Server> getServers() {
        return Collections.unmodifiableSet(registeredServers);
    }

    public String getInstanceId() {
        return instanceId;
    }

    public boolean isStatisticsEnabled() {
        return statisticsEnabled;
    }

    public synchronized void setStatisticsEnabled(boolean statisticsEnabled) {
        this.statisticsEnabled = statisticsEnabled;
        for(Consumer<Boolean> listener: statisticsChangeListenters) {
            listener.accept(statisticsEnabled);
        }
    }

    public synchronized void registerStatisticsListener(Consumer<Boolean> listener) {
        statisticsChangeListenters.add(listener);
    }

    public synchronized void unregisterStatisticsListener(Consumer<Boolean> listener) {
        statisticsChangeListenters.remove(listener);
    }

    /**
     * Registers custom Event listener to server
     *
     * @param listener event listener to register
     */
    public void registerListener(UndertowEventListener listener) {
        this.listeners.add(listener);
    }

    public void unregisterListener(UndertowEventListener listener) {
        this.listeners.remove(listener);
    }

    protected void fireEvent(EventInvoker invoker) {
        synchronized (listeners) {
            for (UndertowEventListener listener : listeners) {
                invoker.invoke(listener);
            }
        }
    }
}


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

import org.jboss.as.pojo.logging.PojoLogger;
import org.jboss.as.pojo.descriptor.ValueConfig;
import org.jboss.as.server.deployment.reflect.ClassReflectionIndex;
import org.jboss.as.server.deployment.reflect.DeploymentReflectionIndex;
import org.jboss.common.beans.property.PropertiesValueResolver;

import java.beans.PropertyEditor;
import java.beans.PropertyEditorManager;
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.Arrays;
import java.util.Collection;

/**
 * Configuration util.
 *
 * @author Ales Justin
 */
public class Configurator {

    /**
     * No parameter types
     */
    public static final String[] NO_PARAMS_TYPES = new String[0];

    /**
     * Turn type into class.
     *
     * @param type the type
     * @return class
     */
    public static Class<?> toClass(Type type) {
        if (type instanceof Class) {
            return (Class) type;
        } else if (type instanceof ParameterizedType) {
            ParameterizedType pt = (ParameterizedType) type;
            return toClass(pt.getRawType());
        } else {
            throw PojoLogger.ROOT_LOGGER.unknownType(type);
        }
    }

    /**
     * Convert a value
     *
     * @param clazz             the class
     * @param value             the value
     * @param replaceProperties whether to replace system properties
     * @param trim              whether to trim string value
     * @return the value or null if there is no editor
     * @throws Throwable for any error
     */
    @SuppressWarnings("unchecked")
    public static Object convertValue(Class<?> clazz, Object value, boolean replaceProperties, boolean trim) throws Throwable {
        if (clazz == null)
            return value;
        if (value == null)
            return null;

        Class<?> valueClass = value.getClass();

        // If we have a string, trim and replace any system properties when requested
        if (valueClass == String.class) {
            String string = (String) value;
            if (trim)
                string = string.trim();
            if (replaceProperties)
                value = PropertiesValueResolver.replaceProperties(string);
        }

        if (clazz.isAssignableFrom(valueClass))
            return value;

        // First see if this is an Enum
        if (clazz.isEnum()) {
            Class<? extends Enum> eclazz = clazz.asSubclass(Enum.class);
            return Enum.valueOf(eclazz, value.toString());
        }

        // Next look for a property editor
        if (valueClass == String.class) {
            PropertyEditor editor = PropertyEditorManager.findEditor(clazz);
            if (editor != null) {
                editor.setAsText((String) value);
                return editor.getValue();
            }
        }

        // Try a static clazz.valueOf(value)
        try {
            Method method = clazz.getMethod("valueOf", valueClass);
            int modifiers = method.getModifiers();
            if (Modifier.isPublic(modifiers) && Modifier.isStatic(modifiers)
                    && clazz.isAssignableFrom(method.getReturnType()))
                return method.invoke(null, value);
        } catch (Exception ignored) {
        }

        if (valueClass == String.class) {
            try {
                Constructor constructor = clazz.getConstructor(valueClass);
                if (Modifier.isPublic(constructor.getModifiers()))
                    return constructor.newInstance(value);
            } catch (Exception ignored) {
            }
        }

        return value;
    }

    /**
     * Get types from values.
     *
     * @param values the values
     * @return the values' types
     */
    public static String[] getTypes(ValueConfig[] values) {
        if (values == null || values.length == 0)
            return NO_PARAMS_TYPES;

        String[] types = new String[values.length];
        for (int i =0; i < types.length; i++)
            types[i] = values[i].getType();
        return types;
    }

    /**
     * Find method info
     *
     * @param index      the deployment reflection index
     * @param classInfo  the class info
     * @param name       the method name
     * @param paramTypes the parameter types
     * @param isStatic   must the method be static
     * @param isPublic   must the method be public
     * @param strict     is strict about method modifiers
     * @return the method info
     * @throws IllegalArgumentException when no such method
     */
    @SuppressWarnings("unchecked")
    public static Method findMethod(DeploymentReflectionIndex index, Class classInfo, String name, String[] paramTypes, boolean isStatic, boolean isPublic, boolean strict) throws IllegalArgumentException {
        if (name == null)
            throw PojoLogger.ROOT_LOGGER.nullName();

        if (classInfo == null)
            throw PojoLogger.ROOT_LOGGER.nullClassInfo();

        if (paramTypes == null)
            paramTypes = NO_PARAMS_TYPES;

        Class current = classInfo;
        while (current != null) {
            ClassReflectionIndex cri = index.getClassIndex(classInfo);
            Method result = locateMethod(cri, name, paramTypes, isStatic, isPublic, strict);
            if (result != null)
                return result;
            current = current.getSuperclass();
        }
        throw PojoLogger.ROOT_LOGGER.methodNotFound(name, Arrays.toString(paramTypes), classInfo.getName());
    }

    /**
     * Find method info
     *
     * @param classInfo  the class info
     * @param name       the method name
     * @param paramTypes the parameter types
     * @param isStatic   must the method be static
     * @param isPublic   must the method be public
     * @param strict     is strict about method modifiers
     * @return the method info or null if not found
     */
    @SuppressWarnings("unchecked")
    private static Method locateMethod(ClassReflectionIndex classInfo, String name, String[] paramTypes, boolean isStatic, boolean isPublic, boolean strict) {
        Collection<Method> methods = classInfo.getMethods();
        if (methods != null) {
            for (Method method : methods) {
                if (name.equals(method.getName()) &&
                        equals(paramTypes, method.getParameterTypes()) &&
                        (strict == false || (Modifier.isStatic(method.getModifiers()) == isStatic && Modifier.isPublic(method.getModifiers()) == isPublic)))
                    return method;
            }
        }
        return null;
    }

    /**
     * Test whether type names are equal to type infos
     *
     * @param typeNames the type names
     * @param typeInfos the type infos
     * @return true when they are equal
     */
    public static boolean equals(String[] typeNames, Class<?>[] typeInfos) {
        if (simpleCheck(typeNames, typeInfos) == false)
            return false;

        for (int i = 0; i < typeNames.length; ++i) {
            if (typeNames[i] != null && typeNames[i].equals(typeInfos[i].getName()) == false)
                return false;
        }
        return true;
    }

    /**
     * A simple null and length check.
     *
     * @param typeNames the type names
     * @param typeInfos the type infos
     * @return false if either argument is null or lengths differ, else true
     */
    protected static boolean simpleCheck(String[] typeNames, Class<?>[] typeInfos) {
        return typeNames != null && typeInfos != null && typeNames.length == typeInfos.length;
    }
}


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

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

import javax.persistence.SharedCacheMode;
import javax.persistence.ValidationMode;
import javax.persistence.spi.PersistenceUnitTransactionType;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;

import org.jboss.as.jpa.config.Configuration;
import org.jboss.as.jpa.config.PersistenceUnitMetadataHolder;
import org.jboss.as.jpa.config.PersistenceUnitMetadataImpl;
import org.jboss.metadata.parser.util.MetaDataElementParser;
import org.jboss.metadata.property.PropertyReplacer;
import org.jipijapa.plugin.spi.PersistenceUnitMetadata;

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

/**
 * Parse a persistence.xml into a list of persistence unit definitions.
 *
 * @author Scott Marlow
 */
public class PersistenceUnitXmlParser extends MetaDataElementParser {
    // cache the trace enabled flag
    private static final boolean traceEnabled = ROOT_LOGGER.isTraceEnabled();

    public static PersistenceUnitMetadataHolder parse(final XMLStreamReader reader, final PropertyReplacer propertyReplacer) throws XMLStreamException {

        reader.require(START_DOCUMENT, null, null);  // check for a bogus document and throw error

        // Read until the first start element
        Version version = null;
        while (reader.hasNext() && reader.next() != START_ELEMENT) {
            if (reader.getEventType() == DTD) {
                final String dtdLocation = readDTDLocation(reader);
                if (dtdLocation != null) {
                    version = Version.forLocation(dtdLocation);
                }
            }
        }
        final String schemaLocation = readSchemaLocation(reader);
        if (schemaLocation != null) {
            version = Version.forLocation(schemaLocation);
        }
        if (version == null || Version.UNKNOWN.equals(version)) {
            // Look at the version attribute
            String versionString = null;
            final int count = reader.getAttributeCount();
            for (int i = 0; i < count; i++) {
                final String attributeNamespace = reader.getAttributeNamespace(i);
                if (attributeNamespace != null && !attributeNamespace.isEmpty()) {
                    continue;
                }
                final Attribute attribute = Attribute.forName(reader.getAttributeLocalName(i));
                if (attribute == Attribute.VERSION) {
                    versionString = reader.getAttributeValue(i);
                }
            }
            if ("1.0".equals(versionString)) {
                version = Version.JPA_1_0;
            } else if ("1".equals(versionString)) {
                version = Version.JPA_1_0;
            } else if ("2.0".equals(versionString)) {
                version = Version.JPA_2_0;
            } else if ("2.1".equals(versionString)) {
                version = Version.JPA_2_1;
            } else if ("2.2".equals(versionString)) {
                version = Version.JPA_2_2;
            } else if ("2".equals(versionString)) {
                version = Version.JPA_2_0;
            } else {
                version = Version.JPA_2_1;
            }
        }

        final int count = reader.getAttributeCount();
        for (int i = 0; i < count; i++) {
            final String attributeNamespace = reader.getAttributeNamespace(i);
            if (attributeNamespace != null && !attributeNamespace.isEmpty()) {
                continue;
            }
            final Attribute attribute = Attribute.forName(reader.getAttributeLocalName(i));
            switch (attribute) {
                case VERSION:
                    // log.info("version = " + value);
                    // TODO:  handle version
                    break;
                default:
                    throw unexpectedAttribute(reader, i);
            }
        }
        final List<PersistenceUnitMetadata> PUs = new ArrayList<PersistenceUnitMetadata>();
        // until the ending PERSISTENCE tag
        while (reader.hasNext() && reader.nextTag() != END_ELEMENT) {
            final Element element = Element.forName(reader.getLocalName());
            switch (element) {
                case PERSISTENCEUNIT:
                    PersistenceUnitMetadata pu = parsePU(reader, version, propertyReplacer);
                    PUs.add(pu);
                    ROOT_LOGGER.readingPersistenceXml(pu.getPersistenceUnitName());
                    break;

                default:
                    throw unexpectedElement(reader);
            }
        }
        PersistenceUnitMetadataHolder result = new PersistenceUnitMetadataHolder(PUs);
        if (ROOT_LOGGER.isTraceEnabled())
            ROOT_LOGGER.trace(result.toString());

        return result;
    }

    /**
     * Parse the persistence unit definitions based on persistence_2_0.xsd.
     *
     *
     * @param reader
     * @param propertyReplacer
     * @return
     * @throws XMLStreamException
     */
    private static PersistenceUnitMetadata parsePU(XMLStreamReader reader, Version version, final PropertyReplacer propertyReplacer) throws XMLStreamException {
        PersistenceUnitMetadata pu = new PersistenceUnitMetadataImpl();
        List<String> classes = new ArrayList<String>(1);
        List<String> jarFiles = new ArrayList<String>(1);
        List<String> mappingFiles = new ArrayList<String>(1);
        Properties properties = new Properties();

        // set defaults
        pu.setTransactionType(PersistenceUnitTransactionType.JTA);
        pu.setValidationMode(ValidationMode.AUTO);
        pu.setSharedCacheMode(SharedCacheMode.UNSPECIFIED);
        pu.setPersistenceProviderClassName(Configuration.PROVIDER_CLASS_DEFAULT);
        if (version.equals(Version.JPA_1_0)) {
            pu.setPersistenceXMLSchemaVersion("1.0");
        } else if (version.equals(Version.JPA_2_0)) {
            pu.setPersistenceXMLSchemaVersion("2.0");
        } else if (version.equals(Version.JPA_2_1)) {
            pu.setPersistenceXMLSchemaVersion("2.1");
        } else {
            pu.setPersistenceXMLSchemaVersion("2.2");
        }

        final int count = reader.getAttributeCount();
        for (int i = 0; i < count; i++) {
            final String value = reader.getAttributeValue(i);
            if (traceEnabled) {
                ROOT_LOGGER.tracef("parse persistence.xml: attribute value(%d) = %s", i, value);
            }
            final String attributeNamespace = reader.getAttributeNamespace(i);
            if (attributeNamespace != null && !attributeNamespace.isEmpty()) {
                continue;
            }
            final Attribute attribute = Attribute.forName(reader.getAttributeLocalName(i));
            switch (attribute) {
                case NAME:
                    pu.setPersistenceUnitName(value);
                    break;
                case TRANSACTIONTYPE:
                    if (value.equalsIgnoreCase("RESOURCE_LOCAL"))
                        pu.setTransactionType(PersistenceUnitTransactionType.RESOURCE_LOCAL);
                    break;
                default:
                    throw unexpectedAttribute(reader, i);
            }
        }

        // until the ending PERSISTENCEUNIT tag
        while (reader.hasNext() && reader.nextTag() != END_ELEMENT) {
            final Element element = Element.forName(reader.getLocalName());
            if (traceEnabled) {
                ROOT_LOGGER.tracef("parse persistence.xml: element=%s", element.getLocalName());
            }
            switch (element) {
                case CLASS:
                    classes.add(getElement(reader, propertyReplacer));
                    break;

                case DESCRIPTION:
                    final String description = getElement(reader, propertyReplacer);
                    break;

                case EXCLUDEUNLISTEDCLASSES:
                    String text = getElement(reader, propertyReplacer);
                    if (text == null || text.isEmpty()) {
                        //the spec has examples where an empty
                        //exclude-unlisted-classes element has the same
                        //effect as setting it to true
                        pu.setExcludeUnlistedClasses(true);
                    } else {
                        pu.setExcludeUnlistedClasses(Boolean.valueOf(text));
                    }
                    break;

                case JARFILE:
                    String file = getElement(reader, propertyReplacer);
                    jarFiles.add(file);
                    break;

                case JTADATASOURCE:
                    pu.setJtaDataSourceName(getElement(reader, propertyReplacer));
                    break;

                case NONJTADATASOURCE:
                    pu.setNonJtaDataSourceName(getElement(reader, propertyReplacer));
                    break;

                case MAPPINGFILE:
                    mappingFiles.add(getElement(reader, propertyReplacer));
                    break;

                case PROPERTIES:
                    parseProperties(reader, properties, propertyReplacer);
                    break;

                case PROVIDER:
                    pu.setPersistenceProviderClassName(getElement(reader, propertyReplacer));
                    break;

                case SHAREDCACHEMODE:
                    String cm = getElement(reader, propertyReplacer);
                    pu.setSharedCacheMode(SharedCacheMode.valueOf(cm));
                    break;

                case VALIDATIONMODE:
                    String validationMode = getElement(reader, propertyReplacer);
                    pu.setValidationMode(ValidationMode.valueOf(validationMode));
                    break;

                default:
                    throw unexpectedElement(reader);
            }
        }
        if (traceEnabled) {
            ROOT_LOGGER.trace("parse persistence.xml: reached ending persistence-unit tag");
        }
        pu.setManagedClassNames(classes);
        pu.setJarFiles(jarFiles);
        pu.setMappingFiles(mappingFiles);
        pu.setProperties(properties);
        return pu;
    }

    private static void parseProperties(XMLStreamReader reader, Properties properties, final PropertyReplacer propertyReplacer) throws XMLStreamException {

        while (reader.hasNext() && reader.nextTag() != END_ELEMENT) {
            final Element element = Element.forName(reader.getLocalName());
            switch (element) {
                case PROPERTY:
                    final int count = reader.getAttributeCount();
                    String name = null, value = null;
                    for (int i = 0; i < count; i++) {
                        final String attributeValue = getAttribute(reader, i, propertyReplacer);
                        final String attributeNamespace = reader.getAttributeNamespace(i);
                        if (attributeNamespace != null && !attributeNamespace.isEmpty()) {
                            continue;
                        }
                        final Attribute attribute = Attribute.forName(reader.getAttributeLocalName(i));
                        switch (attribute) {
                            case NAME:
                                name = attributeValue;
                                break;
                            case VALUE:
                                value = attributeValue;
                                if (name != null && value != null) {
                                    properties.put(name, value);
                                }
                                name = value = null;
                                break;
                            default:
                                throw unexpectedAttribute(reader, i);
                        }
                    }
                    if (reader.hasNext() && (reader.nextTag() != END_ELEMENT))
                        throw unexpectedElement(reader);

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

    private static String getElement(final XMLStreamReader reader, final PropertyReplacer propertyReplacer) throws XMLStreamException {
        return propertyReplacer.replaceProperties(reader.getElementText());
    }

    private static String getAttribute(final XMLStreamReader reader, int i, final PropertyReplacer propertyReplacer) throws XMLStreamException {
        return propertyReplacer.replaceProperties(reader.getAttributeValue(i));
    }
}


/*
 * Copyright (c) 1999, 2005, 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;

import java.util.Hashtable;
import java.util.NoSuchElementException;

import javax.naming.Name;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import javax.naming.spi.NamingManager;

import org.omg.CosNaming.BindingIterator;
import org.omg.CosNaming.BindingIteratorHolder;
import org.omg.CosNaming.BindingListHolder;
import org.omg.CosNaming.NameComponent;
import org.wildfly.iiop.openjdk.logging.IIOPLogger;

/**
 * Implements the JNDI NamingEnumeration interface for COS
 * Naming. Gets hold of a list of bindings from the COS Naming Server
 * and allows the client to iterate through them.
 *
 * @author Raj Krishnamurthy
 * @author Rosanna Lee
 */

final class CNBindingEnumeration implements NamingEnumeration {

    private static final int DEFAULT_BATCHSIZE = 100;
    private BindingListHolder _bindingList; // list of bindings
    private BindingIterator _bindingIter;   // iterator for getting list of bindings
    private int counter;                    // pointer in _bindingList
    private int batchsize = DEFAULT_BATCHSIZE;  // how many to ask for each time
    private CNCtx _ctx;                     // ctx to list
    private Hashtable _env;                 // environment for getObjectInstance
    private boolean more = false;           // iterator done?
    private boolean isLookedUpCtx = false;  // iterating on a context beneath this context ?

    /**
     * Creates a CNBindingEnumeration object.
     *
     * @param ctx Context to enumerate
     */
    CNBindingEnumeration(CNCtx ctx, boolean isLookedUpCtx, Hashtable env) {
        // Get batch size to use
        String batch = (env != null ? (String) env.get(javax.naming.Context.BATCHSIZE) : null);
        if (batch != null) {
            try {
                batchsize = Integer.parseInt(batch);
            } catch (NumberFormatException e) {
                throw IIOPLogger.ROOT_LOGGER.illegalBatchSize(batch);
            }
        }
        _ctx = ctx;
        this.isLookedUpCtx = isLookedUpCtx;
        _env = env;
        _bindingList = new BindingListHolder();
        BindingIteratorHolder _bindingIterH = new BindingIteratorHolder();

        // Perform listing and request that bindings be returned in _bindingIter
        // Upon return,_bindingList returns a zero length list
        _ctx._nc.list(0, _bindingList, _bindingIterH);

        _bindingIter = _bindingIterH.value;

        // Get first batch using _bindingIter
        if (_bindingIter != null) {
            more = _bindingIter.next_n(batchsize, _bindingList);
        } else {
            more = false;
        }
        counter = 0;
    }

    /**
     * Returns the next binding in the list.
     *
     * @throws NamingException any naming exception.
     */

    public java.lang.Object next() throws NamingException {
        if (more && counter >= _bindingList.value.length) {
            getMore();
        }
        if (more && counter < _bindingList.value.length) {
            org.omg.CosNaming.Binding bndg = _bindingList.value[counter];
            counter++;
            return mapBinding(bndg);
        } else {
            throw new NoSuchElementException();
        }
    }

    /**
     * Returns true or false depending on whether there are more bindings.
     *
     * @return boolean value
     */

    public boolean hasMore() throws NamingException {
        // If there's more, check whether current bindingList has been exhausted,
        // and if so, try to get more.
        // If no more, just say so.
        return more ? (counter < _bindingList.value.length || getMore()) : false;
    }

    /**
     * Returns true or false depending on whether there are more bindings.
     * Need to define this to satisfy the Enumeration api requirement.
     *
     * @return boolean value
     */

    public boolean hasMoreElements() {
        try {
            return hasMore();
        } catch (NamingException e) {
            return false;
        }
    }

    /**
     * Returns the next binding in the list.
     *
     * @throws NoSuchElementException Thrown when the end of the
     *                                list is reached.
     */

    public java.lang.Object nextElement() {
        try {
            return next();
        } catch (NamingException ne) {
            throw new NoSuchElementException();
        }
    }

    public void close() throws NamingException {
        more = false;
        if (_bindingIter != null) {
            _bindingIter.destroy();
            _bindingIter = null;
        }
        if (_ctx != null) {

            /**
             * context was obtained by CNCtx, the user doesn't have a handle to
             * it, close it as we are done enumerating through the context
             */
            if (isLookedUpCtx) {
                _ctx.close();
            }
            _ctx = null;
        }
    }

    protected void finalize() {
        try {
            close();
        } catch (NamingException e) {
            // ignore failures
        }
    }

    /**
     * Get the next batch using _bindingIter. Update the 'more' field.
     */
    private boolean getMore() throws NamingException {
        try {
            more = _bindingIter.next_n(batchsize, _bindingList);
            counter = 0; // reset
        } catch (Exception e) {
            more = false;
            NamingException ne = IIOPLogger.ROOT_LOGGER.errorGettingBindingList();
            ne.setRootCause(e);
            throw ne;
        }
        return more;
    }

    /**
     * Constructs a JNDI Binding object from the COS Naming binding
     * object.
     *
     * @throws org.omg.CosNaming.NamingContextPackage.CannotProceed   Unable to obtain a continuation context
     * @throws org.omg.CosNaming.NamingContextPackage.InvalidNameCNCtx     Name not understood.
     * @throws NamingException One of the above.
     */

    private javax.naming.Binding mapBinding(org.omg.CosNaming.Binding bndg)
            throws NamingException {
        java.lang.Object obj = _ctx.callResolve(bndg.binding_name);

        Name cname = org.wildfly.iiop.openjdk.naming.jndi.CNNameParser.cosNameToName(bndg.binding_name);

        try {
            obj = NamingManager.getObjectInstance(obj, cname, _ctx, _env);
        } catch (NamingException e) {
            throw e;
        } catch (Exception e) {
            NamingException ne = IIOPLogger.ROOT_LOGGER.errorGeneratingObjectViaFactory();
            ne.setRootCause(e);
            throw ne;
        }

        // Use cname.toString() instead of bindingName because the name
        // in the binding should be a composite name
        String cnameStr = cname.toString();
        javax.naming.Binding jbndg = new javax.naming.Binding(cnameStr, obj);

        NameComponent[] comps = _ctx.makeFullName(bndg.binding_name);
        String fullName = org.wildfly.iiop.openjdk.naming.jndi.CNNameParser.cosNameToInsString(comps);
        jbndg.setNameInNamespace(fullName);
        return jbndg;
    }
}


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

import org.jboss.as.ee.component.InjectionSource;
import org.jboss.metadata.javaee.spec.PropertiesMetaData;
import org.jboss.metadata.javaee.spec.PropertyMetaData;
import org.jboss.metadata.property.PropertyReplacer;

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

/**
 * The abstract InjectionSource for EE Resource Definitions.
 * @author Eduardo Martins
 */
public abstract class ResourceDefinitionInjectionSource extends InjectionSource {

    protected final String jndiName;
    protected final Map<String, String> properties = new HashMap<>();

    public ResourceDefinitionInjectionSource(final String jndiName) {
        if (jndiName.startsWith("java:")) {
            this.jndiName = jndiName;
        } else {
            this.jndiName = "java:comp/env/" + jndiName;
        }
    }

    public String getJndiName() {
        return jndiName;
    }

    /**
     * Add the specified properties.
     * @param annotationProperties an array of propertyName = propertyValue strings
     */
    public void addProperties(final String[] annotationProperties) {
        addProperties(annotationProperties, null);
    }

    /**
     * Add the specified properties.
     * @param annotationProperties an array of propertyName = propertyValue strings
     * @param propertyReplacer if not null all property names and values will be processed by the replacer.
     */
    public void addProperties(final String[] annotationProperties, final PropertyReplacer propertyReplacer) {
        if (annotationProperties != null) {
            for (String annotationProperty : annotationProperties) {
                if (propertyReplacer != null) {
                    annotationProperty = propertyReplacer.replaceProperties(annotationProperty);
                }
                final int index = annotationProperty.indexOf('=');
                String propertyName;
                String propertyValue;
                if (index != -1) {
                    propertyName = annotationProperty.substring(0, index);
                    propertyValue = annotationProperty.length() > index ? annotationProperty.substring(index + 1, annotationProperty.length()) : "";
                } else {
                    propertyName = annotationProperty;
                    propertyValue = "";
                }
                this.properties.put(propertyName, propertyValue);
            }
        }
    }

    /**
     * Add the specified properties.
     * @param descriptorProperties the metadata properties to add
     */
    public void addProperties(final PropertiesMetaData descriptorProperties) {
        if (descriptorProperties != null) {
            for (PropertyMetaData descriptorProperty : descriptorProperties) {
                this.properties.put(descriptorProperty.getName(), descriptorProperty.getValue());
            }
        }
    }

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

        ResourceDefinitionInjectionSource that = (ResourceDefinitionInjectionSource) o;

        if (!jndiName.equals(that.jndiName)) return false;
        if (!properties.equals(that.properties)) return false;

        return true;
    }

    @Override
    public int hashCode() {
        int result = jndiName.hashCode();
        result = 31 * result + properties.hashCode();
        return result;
    }
}


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

package org.wildfly.extension.microprofile.health.deployment;

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

import javax.enterprise.event.Observes;
import javax.enterprise.inject.spi.AfterDeploymentValidation;
import javax.enterprise.inject.spi.AnnotatedType;
import javax.enterprise.inject.spi.BeanManager;
import javax.enterprise.inject.spi.BeforeShutdown;
import javax.enterprise.inject.spi.Extension;
import javax.enterprise.inject.spi.ProcessAnnotatedType;
import javax.enterprise.inject.spi.Unmanaged;
import javax.enterprise.inject.spi.Unmanaged.UnmanagedInstance;
import javax.enterprise.inject.spi.WithAnnotations;

import io.smallrye.health.SmallRyeHealthReporter;
import org.eclipse.microprofile.health.Health;
import org.eclipse.microprofile.health.HealthCheck;
import org.wildfly.extension.microprofile.health._private.MicroProfileHealthLogger;

/**
 * @author Jeff Mesnil (c) 2017 Red Hat inc.
 */
public class CDIExtension implements Extension {

    private final SmallRyeHealthReporter healthReporter;
    private List<AnnotatedType<? extends HealthCheck>> delegates = new ArrayList<>();
    private Collection<UnmanagedInstance<HealthCheck>> healthCheckInstances = new ArrayList<>();

    public CDIExtension(SmallRyeHealthReporter healthReporter) {
        this.healthReporter = healthReporter;
    }

    /**
     * Discover all classes that implements HealthCheckProcedure
     */
    public void observeResources(@Observes @WithAnnotations({Health.class})  ProcessAnnotatedType<? extends HealthCheck> event) {
        AnnotatedType<? extends HealthCheck> annotatedType = event.getAnnotatedType();
        Class<? extends HealthCheck> javaClass = annotatedType.getJavaClass();
        MicroProfileHealthLogger.LOGGER.infof("Discovered health check procedure %s", javaClass);
        delegates.add(annotatedType);
    }

    /**
     * Instantiates unmanaged instances of HealthCheckProcedure and
     * handle manually their CDI creation lifecycle.
     * Add them to the {@link SmallRyeHealthReporter}.
     */
    private void afterDeploymentValidation(@Observes final AfterDeploymentValidation avd, BeanManager bm) {
        for (AnnotatedType delegate : delegates) {
            try {
                Unmanaged<HealthCheck> unmanagedHealthCheck = new Unmanaged<HealthCheck>(bm, delegate.getJavaClass());
                UnmanagedInstance<HealthCheck> healthCheckInstance = unmanagedHealthCheck.newInstance();
                HealthCheck healthCheck =  healthCheckInstance.produce().inject().postConstruct().get();
                healthCheckInstances.add(healthCheckInstance);
                healthReporter.addHealthCheck(healthCheck);
            } catch (Exception e) {
                throw new RuntimeException("Failed to register health bean", e);
            }
        }
    }

    /**
     * Called when the deployment is undeployed.
     *
     * Remove all the instances of {@link HealthCheck} from the {@link SmallRyeHealthReporter}.
     * Handle manually their CDI destroy lifecycle.
     */
    public void close(@Observes final BeforeShutdown bs) {
        healthCheckInstances.forEach(healthCheck -> {
            healthReporter.removeHealthCheck(healthCheck.get());
            healthCheck.preDestroy().dispose();
        });
        healthCheckInstances.clear();
    }
}


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

import java.io.ByteArrayOutputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;

import javax.ejb.EJBHome;
import javax.ejb.EJBMetaData;
import javax.rmi.PortableRemoteObject;
import javax.transaction.TransactionManager;

import com.arjuna.ats.jbossatx.jta.TransactionManagerService;
import org.jboss.as.ee.component.ComponentView;
import org.jboss.as.ejb3.logging.EjbLogger;
import org.jboss.as.ejb3.component.EJBComponent;
import org.jboss.as.ejb3.component.stateless.StatelessSessionComponent;
import org.jboss.as.ejb3.iiop.stub.DynamicStubFactoryFactory;
import org.jboss.as.server.moduleservice.ServiceModuleLoader;
import org.jboss.ejb.client.EJBHomeLocator;
import org.jboss.ejb.client.EJBLocator;
import org.jboss.ejb.client.EntityEJBLocator;
import org.jboss.ejb.client.StatefulEJBLocator;
import org.jboss.ejb.client.StatelessEJBLocator;
import org.jboss.ejb.iiop.EJBMetaDataImplIIOP;
import org.jboss.ejb.iiop.HandleImplIIOP;
import org.jboss.ejb.iiop.HomeHandleImplIIOP;
import org.jboss.marshalling.Marshaller;
import org.jboss.marshalling.MarshallerFactory;
import org.jboss.marshalling.MarshallingConfiguration;
import org.jboss.marshalling.ModularClassResolver;
import org.jboss.marshalling.OutputStreamByteOutput;
import org.jboss.marshalling.river.RiverMarshallerFactory;
import org.jboss.metadata.ejb.jboss.IIOPMetaData;
import org.jboss.metadata.ejb.jboss.IORSecurityConfigMetaData;
import org.jboss.metadata.ejb.jboss.IORTransportConfigMetaData;
import org.jboss.modules.Module;
import org.jboss.msc.service.Service;
import org.jboss.msc.service.ServiceName;
import org.jboss.msc.service.StartContext;
import org.jboss.msc.service.StartException;
import org.jboss.msc.service.StopContext;
import org.jboss.msc.value.InjectedValue;
import org.omg.CORBA.Any;
import org.omg.CORBA.InterfaceDef;
import org.omg.CORBA.InterfaceDefHelper;
import org.omg.CORBA.ORB;
import org.omg.CORBA.Policy;
import org.omg.CORBA.Repository;
import org.omg.CosNaming.NameComponent;
import org.omg.CosNaming.NamingContext;
import org.omg.CosNaming.NamingContextExt;
import org.omg.CosNaming.NamingContextHelper;
import org.omg.CosNaming.NamingContextPackage.CannotProceed;
import org.omg.CosNaming.NamingContextPackage.InvalidName;
import org.omg.CosNaming.NamingContextPackage.NotFound;
import org.omg.PortableServer.Current;
import org.omg.PortableServer.CurrentHelper;
import org.omg.PortableServer.POA;
import org.wildfly.iiop.openjdk.csiv2.CSIv2Policy;
import org.wildfly.iiop.openjdk.rmi.ir.InterfaceRepository;
import org.wildfly.iiop.openjdk.rmi.marshal.strategy.SkeletonStrategy;
import org.wildfly.security.manager.WildFlySecurityManager;

import com.sun.corba.se.spi.extension.ZeroPortPolicy;
import org.wildfly.transaction.client.ContextTransactionManager;

/**
 * This is an IIOP "proxy factory" for EJBHomes and
 * EJBObjects. Rather than creating Java proxies (as the JRMP
 * proxy factory does), this factory creates CORBA IORs.
 *

 * An EjbIIOPService is associated to a given enterprise bean. It
 * registers with the IIOP invoker two CORBA servants: an
 * EjbHomeCorbaServant for the bean's
 * EJBHome and an EjbObjectCorbaServant for the
 * bean's EJBObjects.
 */
public class EjbIIOPService implements Service<EjbIIOPService> {

    /**
     * The service name
     */
    public static final ServiceName SERVICE_NAME = ServiceName.of("EjbIIOPService");

    /**
     * The component
     */
    private final InjectedValue<EJBComponent> ejbComponentInjectedValue = new InjectedValue<EJBComponent>();

    /**
     * The home view
     */
    private final InjectedValue<ComponentView> homeView = new InjectedValue<ComponentView>();

    /**
     * the ejbObject view
     */
    private final InjectedValue<ComponentView> remoteView = new InjectedValue<ComponentView>();

    private final InjectedValue<POARegistry> poaRegistry = new InjectedValue<POARegistry>();

    /**
     * The corba naming context
     */
    private final InjectedValue<NamingContextExt> corbaNamingContext = new InjectedValue<NamingContextExt>();

    /**
     * A reference for the ORB.
     */
    private final InjectedValue<ORB> orb = new InjectedValue<ORB>();

    /**
     * The module loader
     */
    private final InjectedValue<ServiceModuleLoader> serviceModuleLoaderInjectedValue = new InjectedValue<ServiceModuleLoader>();

    /**
     * The JTS underlying transaction manager service (not ContextTransactionManager)
     */
    private final InjectedValue<TransactionManagerService> transactionManagerInjectedValue = new InjectedValue<>();

    /**
     * Used for serializing EJB id's
     */
    private MarshallerFactory factory;
    private MarshallingConfiguration configuration;

    /**
     * EJBMetaData the enterprise bean in the container.
     */
    private EJBMetaData ejbMetaData;

    /**
     * Mapping from bean methods to SkeletonStrategy instances.
     */
    private final Map<String, SkeletonStrategy> beanMethodMap;

    /**
     * Mapping from home methods to SkeletonStrategy instances.
     */
    private final Map<String, SkeletonStrategy> homeMethodMap;

    /**
     * CORBA repository ids of the RMI-IDL interfaces implemented by the bean
     * (EJBObject instance).
     */
    private final String[] beanRepositoryIds;

    /**
     * CORBA repository ids of the RMI-IDL interfaces implemented by the bean's
     * home (EJBHome instance).
     */
    private final String[] homeRepositoryIds;

    private final boolean useQualifiedName;

    private final Module module;

    /**
     * ServantRegistry for the container's EJBHome.
     */
    private ServantRegistry homeServantRegistry;

    /**
     * ServantRegistry for the container's EJBObjects.
     */
    private ServantRegistry beanServantRegistry;

    /**
     * ReferenceFactory for EJBObjects.
     */
    private ReferenceFactory beanReferenceFactory;

    /**
     * The container's EJBHome.
     */
    private EJBHome ejbHome;

    /**
     * The enterprise bean's interface repository implementation, or null
     * if the enterprise bean does not have its own interface repository.
     */
    private InterfaceRepository iri;

    /**
     * POA for the enterprise bean's interface repository.
     */
    private final InjectedValue<POA> irPoa = new InjectedValue<POA>();

    /**
     * Default IOR security config metadata (defined in the iiop subsystem).
     */
    private final InjectedValue<IORSecurityConfigMetaData> iorSecConfigMetaData = new InjectedValue<IORSecurityConfigMetaData>();

    /**
     * The IIOP metadata, configured in the assembly descriptor.
     */
    private IIOPMetaData iiopMetaData;

    /**
     * The fully qualified name
     */
    private String name = null;

    public EjbIIOPService(final Map<String, SkeletonStrategy> beanMethodMap, final String[] beanRepositoryIds,
                          final Map<String, SkeletonStrategy> homeMethodMap, final String[] homeRepositoryIds,
                          final boolean useQualifiedName, final IIOPMetaData iiopMetaData, final Module module) {
        this.useQualifiedName = useQualifiedName;
        this.module = module;
        this.beanMethodMap = Collections.unmodifiableMap(beanMethodMap);
        this.beanRepositoryIds = beanRepositoryIds;
        this.homeMethodMap = Collections.unmodifiableMap(homeMethodMap);
        this.homeRepositoryIds = homeRepositoryIds;
        this.iiopMetaData = iiopMetaData;
    }

    public synchronized void start(final StartContext startContext) throws StartException {

        try {
            final RiverMarshallerFactory factory = new RiverMarshallerFactory();
            final MarshallingConfiguration configuration = new MarshallingConfiguration();
            configuration.setClassResolver(ModularClassResolver.getInstance(serviceModuleLoaderInjectedValue.getValue()));
            this.configuration = configuration;
            this.factory = factory;
            final TransactionManager jtsTransactionManager = transactionManagerInjectedValue.getValue().getTransactionManager();
            assert ! (jtsTransactionManager instanceof ContextTransactionManager);

            // Should create a CORBA interface repository?
            final boolean interfaceRepositorySupported = false;

            // Build binding name of the bean.
            final EJBComponent component = ejbComponentInjectedValue.getValue();
            final String earApplicationName = component.getEarApplicationName();
            if (iiopMetaData != null && iiopMetaData.getBindingName() != null) {
                name = iiopMetaData.getBindingName();
            } else if (useQualifiedName) {
                if (component.getDistinctName() == null || component.getDistinctName().isEmpty()) {
                    name = earApplicationName == null || earApplicationName.isEmpty() ? "" : earApplicationName + "/";
                    name = name + component.getModuleName() + "/" + component.getComponentName();
                } else {
                    name = earApplicationName == null || earApplicationName.isEmpty() ? "" : earApplicationName + "/";
                    name = name + component.getModuleName() + "/" + component.getDistinctName() + "/" + component.getComponentName();
                }
            } else {
                name = component.getComponentName();
            }
            name = name.replace(".", "_");

            final ORB orb = this.orb.getValue();
            if (interfaceRepositorySupported) {
                // Create a CORBA interface repository for the enterprise bean
                iri = new InterfaceRepository(orb, irPoa.getValue(), name);
                // Add bean interface info to the interface repository
                iri.mapClass(remoteView.getValue().getViewClass());
                iri.mapClass(homeView.getValue().getViewClass());
                iri.finishBuild();
                EjbLogger.ROOT_LOGGER.cobraInterfaceRepository(name, orb.object_to_string(iri.getReference()));
            }

            IORSecurityConfigMetaData iorSecurityConfigMetaData = this.iorSecConfigMetaData.getOptionalValue();
            if (this.iiopMetaData != null && this.iiopMetaData.getIorSecurityConfigMetaData() != null)
                iorSecurityConfigMetaData = this.iiopMetaData.getIorSecurityConfigMetaData();

            // Create security policies if security metadata has been provided.
            List<Policy> policyList = new ArrayList<Policy>();
            if (iorSecurityConfigMetaData != null) {

                // Create csiv2Policy for both home and remote containing IorSecurityConfigMetadata.
                final Any secPolicy = orb.create_any();
                secPolicy.insert_Value(iorSecurityConfigMetaData);
                Policy csiv2Policy = orb.create_policy(CSIv2Policy.TYPE, secPolicy);

                policyList.add(csiv2Policy);

                //  Add ZeroPortPolicy if ssl is required (it ensures home and remote IORs will have port 0 in the primary address).
                boolean sslRequired = false;
                if (iorSecurityConfigMetaData != null && iorSecurityConfigMetaData.getTransportConfig() != null) {
                    IORTransportConfigMetaData tc = iorSecurityConfigMetaData.getTransportConfig();
                    sslRequired = IORTransportConfigMetaData.INTEGRITY_REQUIRED.equals(tc.getIntegrity())
                            || IORTransportConfigMetaData.CONFIDENTIALITY_REQUIRED.equals(tc.getConfidentiality())
                            || IORTransportConfigMetaData.ESTABLISH_TRUST_IN_CLIENT_REQUIRED.equals(tc.getEstablishTrustInClient());
                }
                if(sslRequired){
                    policyList.add(ZeroPortPolicy.getPolicy());
                }
            }

            String securityDomain = "CORBA_REMOTE"; //TODO: what should this default to
            if (component.getSecurityMetaData() != null) {
                securityDomain = component.getSecurityMetaData().getSecurityDomain();
            }

            Policy[] policies = policyList.toArray(new Policy[policyList.size()]);

            // If there is an interface repository, then get the homeInterfaceDef from the IR
            InterfaceDef homeInterfaceDef = null;
            if (iri != null) {
                Repository ir = iri.getReference();
                homeInterfaceDef = InterfaceDefHelper.narrow(ir.lookup_id(homeRepositoryIds[0]));
            }

            // Get the POACurrent object
            Current poaCurrent = CurrentHelper.narrow(orb.resolve_initial_references("POACurrent"));

            // Instantiate home servant, bind it to the servant registry, and create CORBA reference to the EJBHome.
            final EjbCorbaServant homeServant = new EjbCorbaServant(poaCurrent, homeMethodMap, homeRepositoryIds, homeInterfaceDef,
                    orb, homeView.getValue(), factory, configuration, jtsTransactionManager, module.getClassLoader(), true, securityDomain,
                    component.getSecurityDomain());

            homeServantRegistry = poaRegistry.getValue().getRegistryWithPersistentPOAPerServant();
            ReferenceFactory homeReferenceFactory = homeServantRegistry.bind(homeServantName(name), homeServant, policies);

            final org.omg.CORBA.Object corbaRef = homeReferenceFactory.createReference(homeRepositoryIds[0]);

            //we do this twice to force eager dynamic stub creation
            ejbHome = (EJBHome) PortableRemoteObject.narrow(corbaRef, EJBHome.class);

            final HomeHandleImplIIOP homeHandle = new HomeHandleImplIIOP(orb.object_to_string(corbaRef));
            homeServant.setHomeHandle(homeHandle);

            // Initialize beanPOA and create metadata
            // This is a session bean (lifespan: transient)
            beanServantRegistry = poaRegistry.getValue().getRegistryWithTransientPOAPerServant();
            if (component instanceof StatelessSessionComponent) {
                // Stateless session bean
                ejbMetaData = new EJBMetaDataImplIIOP(remoteView.getValue().getViewClass(), homeView.getValue().getViewClass(), null, true, true, homeHandle);
            } else {
                // Stateful session bean
                ejbMetaData = new EJBMetaDataImplIIOP(remoteView.getValue().getViewClass(), homeView.getValue().getViewClass(), null, true, false, homeHandle);
            }

            homeServant.setEjbMetaData(ejbMetaData);

            // If there is an interface repository, then get the beanInterfaceDef from the IR
            InterfaceDef beanInterfaceDef = null;
            if (iri != null) {
                final Repository ir = iri.getReference();
                beanInterfaceDef = InterfaceDefHelper.narrow(ir.lookup_id(beanRepositoryIds[0]));
            }

            // Instantiate the ejb object servant and bind it to the servant registry.
            final EjbCorbaServant beanServant = new EjbCorbaServant(poaCurrent, beanMethodMap, beanRepositoryIds,
                    beanInterfaceDef, orb, remoteView.getValue(), factory, configuration, jtsTransactionManager,
                    module.getClassLoader(), false, securityDomain, component.getSecurityDomain());
            beanReferenceFactory = beanServantRegistry.bind(beanServantName(name), beanServant, policies);

            // Register bean home in local CORBA naming context
            rebind(corbaNamingContext.getValue(), name, corbaRef);
            EjbLogger.ROOT_LOGGER.debugf("Home IOR for %s bound to %s in CORBA naming service", component.getComponentName(), this.name);

            //now eagerly force stub creation, so de-serialization of stubs will work correctly
            final ClassLoader cl = WildFlySecurityManager.getCurrentContextClassLoaderPrivileged();
            try {
                WildFlySecurityManager.setCurrentContextClassLoaderPrivileged(module.getClassLoader());
                try {
                    DynamicStubFactoryFactory.makeStubClass(homeView.getValue().getViewClass());
                } catch (Exception e) {
                    EjbLogger.ROOT_LOGGER.dynamicStubCreationFailed(homeView.getValue().getViewClass().getName(), e);
                }
                try {
                    DynamicStubFactoryFactory.makeStubClass(remoteView.getValue().getViewClass());
                } catch (Exception e) {
                    EjbLogger.ROOT_LOGGER.dynamicStubCreationFailed(remoteView.getValue().getViewClass().getName(), e);
                }
            } finally {
                WildFlySecurityManager.setCurrentContextClassLoaderPrivileged(cl);
            }

        } catch (Exception e) {
            throw new StartException(e);
        }
    }

    @Override
    public synchronized void stop(final StopContext context) {
        // Get local (in-VM) CORBA naming context
        final NamingContextExt corbaContext = corbaNamingContext.getValue();

        // Unregister bean home from local CORBA naming context
        try {
            NameComponent[] name = corbaContext.to_name(this.name);
            corbaContext.unbind(name);
        } catch (InvalidName invalidName) {
            EjbLogger.ROOT_LOGGER.cannotUnregisterEJBHomeFromCobra(invalidName);
        } catch (NotFound notFound) {
            EjbLogger.ROOT_LOGGER.cannotUnregisterEJBHomeFromCobra(notFound);
        } catch (CannotProceed cannotProceed) {
            EjbLogger.ROOT_LOGGER.cannotUnregisterEJBHomeFromCobra(cannotProceed);
        }

        // Deactivate the home servant and the bean servant
        try {
            homeServantRegistry.unbind(homeServantName(this.name));
        } catch (Exception e) {
            EjbLogger.ROOT_LOGGER.cannotDeactivateHomeServant(e);
        }
        try {
            beanServantRegistry.unbind(beanServantName(this.name));
        } catch (Exception e) {
            EjbLogger.ROOT_LOGGER.cannotDeactivateBeanServant(e);
        }

        if (iri != null) {
            // Deactivate the interface repository
            iri.shutdown();
        }
        this.name = null;
    }

    /**
     * Returns a corba reference for the given locator
     *
     * @param locator The locator
     * @return The corba reference
     */
    public org.omg.CORBA.Object referenceForLocator(final EJBLocator<?> locator) {
        final EJBComponent ejbComponent = ejbComponentInjectedValue.getValue();
        try {
            final String earApplicationName = ejbComponent.getEarApplicationName() == null ? "" : ejbComponent.getEarApplicationName();
            if (locator.getBeanName().equals(ejbComponent.getComponentName()) &&
                    locator.getAppName().equals(earApplicationName) &&
                    locator.getModuleName().equals(ejbComponent.getModuleName()) &&
                    locator.getDistinctName().equals(ejbComponent.getDistinctName())) {
                if (locator instanceof EJBHomeLocator) {
                    return (org.omg.CORBA.Object) ejbHome;
                } else if (locator instanceof StatelessEJBLocator) {
                    return beanReferenceFactory.createReference(beanRepositoryIds[0]);
                } else if (locator instanceof StatefulEJBLocator) {
                    final Marshaller marshaller = factory.createMarshaller(configuration);
                    final ByteArrayOutputStream stream = new ByteArrayOutputStream();
                    marshaller.start(new OutputStreamByteOutput(stream));
                    marshaller.writeObject(((StatefulEJBLocator<?>) locator).getSessionId());
                    marshaller.finish();
                    return beanReferenceFactory.createReferenceWithId(stream.toByteArray(), beanRepositoryIds[0]);
                } else if (locator instanceof EntityEJBLocator) {
                    final Marshaller marshaller = factory.createMarshaller(configuration);
                    final ByteArrayOutputStream stream = new ByteArrayOutputStream();
                    marshaller.start(new OutputStreamByteOutput(stream));
                    marshaller.writeObject(((EntityEJBLocator<?>) locator).getPrimaryKey());
                    marshaller.finish();
                    return beanReferenceFactory.createReferenceWithId(stream.toByteArray(), beanRepositoryIds[0]);
                }
                throw EjbLogger.ROOT_LOGGER.unknownEJBLocatorType(locator);
            } else {
                throw EjbLogger.ROOT_LOGGER.incorrectEJBLocatorForBean(locator, ejbComponent.getComponentName());
            }
        } catch (Exception e) {
            throw EjbLogger.ROOT_LOGGER.couldNotCreateCorbaObject(e, locator);
        }
    }

    /**
     * Gets a handle for the given ejb locator.
     *
     * @param locator The locator to get the handle for
     * @return The {@link org.jboss.ejb.client.EJBHandle} or {@link org.jboss.ejb.client.EJBHomeHandle}
     */
    public Object handleForLocator(final EJBLocator<?> locator) {
        final org.omg.CORBA.Object reference = referenceForLocator(locator);
        if(locator instanceof EJBHomeLocator) {
            return new HomeHandleImplIIOP(orb.getValue().object_to_string(reference));
        }
        return new HandleImplIIOP(orb.getValue().object_to_string(reference));
    }

    /**
     * (Re)binds an object to a name in a given CORBA naming context, creating
     * any non-existent intermediate contexts along the way.
     *

     * This method is synchronized on the class object, if multiple services attempt to bind the
     * same context name at once it will fail
     *
     * @param ctx     a reference to the COSNaming service.
     * @param strName the name under which the CORBA object is to be bound.
     * @param obj     the CORBA object to be bound.
     * @throws Exception if an error occurs while binding the object.
     */
    public static synchronized void rebind(final NamingContextExt ctx, final String strName, final org.omg.CORBA.Object obj) throws Exception {
        final NameComponent[] name = ctx.to_name(strName);
        NamingContext intermediateCtx = ctx;

        for (int i = 0; i < name.length - 1; i++) {
            final NameComponent[] relativeName = new NameComponent[]{name[i]};
            try {
                intermediateCtx = NamingContextHelper.narrow(
                        intermediateCtx.resolve(relativeName));
            } catch (NotFound e) {
                intermediateCtx = intermediateCtx.bind_new_context(relativeName);
            }
        }
        intermediateCtx.rebind(new NameComponent[]{name[name.length - 1]}, obj);
    }

    /**
     * Returns the name of a home servant for an EJB with the given jndiName.
     * The home servant will be bound to this name in a ServantRegistry.
     */
    private static String homeServantName(final String jndiName) {
        return jndiName + "/home";
    }

    /**
     * Returns the name of a bean servant for an EJB with the given jndiName.
     * The bean servant will be bound to this name in a ServantRegistry.
     */
    private static String beanServantName(final String jndiName) {
        return jndiName + "/remote";
    }

    @Override
    public EjbIIOPService getValue() throws IllegalStateException, IllegalArgumentException {
        return this;
    }

    public InjectedValue<ComponentView> getRemoteView() {
        return remoteView;
    }

    public InjectedValue<ComponentView> getHomeView() {
        return homeView;
    }

    public InjectedValue<EJBComponent> getEjbComponentInjectedValue() {
        return ejbComponentInjectedValue;
    }

    public InjectedValue<ORB> getOrb() {
        return orb;
    }

    public InjectedValue<NamingContextExt> getCorbaNamingContext() {
        return corbaNamingContext;
    }

    public InjectedValue<POARegistry> getPoaRegistry() {
        return poaRegistry;
    }

    public InjectedValue<POA> getIrPoa() {
        return irPoa;
    }

    public InjectedValue<ServiceModuleLoader> getServiceModuleLoaderInjectedValue() {
        return serviceModuleLoaderInjectedValue;
    }

    public InjectedValue<IORSecurityConfigMetaData> getIORSecConfigMetaDataInjectedValue() {
        return iorSecConfigMetaData;
    }

    public InjectedValue<TransactionManagerService> getTransactionManagerInjectedValue() {
        return transactionManagerInjectedValue;
    }
}


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

package org.jboss.as.security.service;

import java.util.concurrent.ConcurrentMap;

import javax.security.auth.login.Configuration;

import org.jboss.as.security.SecurityExtension;
import org.jboss.as.security.logging.SecurityLogger;
import org.jboss.as.security.plugins.AuthenticationCacheFactory;
import org.jboss.as.security.plugins.DefaultAuthenticationCacheFactory;
import org.jboss.as.security.plugins.JNDIBasedSecurityManagement;
import org.jboss.as.security.plugins.SecurityDomainContext;
import org.jboss.msc.inject.Injector;
import org.jboss.msc.service.Service;
import org.jboss.msc.service.ServiceName;
import org.jboss.msc.service.StartContext;
import org.jboss.msc.service.StartException;
import org.jboss.msc.service.StopContext;
import org.jboss.msc.value.InjectedValue;
import org.jboss.security.ISecurityManagement;
import org.jboss.security.JSSESecurityDomain;
import org.jboss.security.config.ApplicationPolicy;
import org.jboss.security.config.ApplicationPolicyRegistration;

/**
 * Service to install security domains.
 *
 * @author Marcus Moyses
 */
public class SecurityDomainService implements Service<SecurityDomainContext> {

    public static final ServiceName SERVICE_NAME = SecurityExtension.JBOSS_SECURITY.append("security-domain");

    private final InjectedValue<ISecurityManagement> securityManagementValue = new InjectedValue<ISecurityManagement>();

    private final InjectedValue<Configuration> configurationValue = new InjectedValue<Configuration>();

    private final InjectedValue<ConcurrentMap> cacheValue = new InjectedValue<>();

    private final String name;

    private final ApplicationPolicy applicationPolicy;

    private final JSSESecurityDomain jsseSecurityDomain;

    private volatile SecurityDomainContext securityDomainContext;

    private final String cacheType;

    public SecurityDomainService(String name, ApplicationPolicy applicationPolicy, JSSESecurityDomain jsseSecurityDomain,
            String cacheType) {
        this.name = name;
        this.applicationPolicy = applicationPolicy;
        this.jsseSecurityDomain = jsseSecurityDomain;
        this.cacheType = cacheType;
    }

    /** {@inheritDoc} */
    @Override
    public void start(StartContext context) throws StartException {
        SecurityLogger.ROOT_LOGGER.debugf("Starting SecurityDomainService(%s)", name);
        if (applicationPolicy != null) {
            final ApplicationPolicyRegistration applicationPolicyRegistration = (ApplicationPolicyRegistration) configurationValue
                    .getValue();
            applicationPolicyRegistration.addApplicationPolicy(applicationPolicy.getName(), applicationPolicy);
        }
        final JNDIBasedSecurityManagement securityManagement = (JNDIBasedSecurityManagement) securityManagementValue.getValue();
        AuthenticationCacheFactory cacheFactory = null;
        if ("infinispan".equals(cacheType)) {
            cacheFactory = () -> this.cacheValue.getValue();
        } else if ("default".equals(cacheType)) {
            cacheFactory = new DefaultAuthenticationCacheFactory();
        }
        SecurityDomainContext sdc;
        try {
            sdc = securityManagement.createSecurityDomainContext(name, cacheFactory, jsseSecurityDomain);
        } catch (Exception e) {
            throw SecurityLogger.ROOT_LOGGER.unableToStartException("SecurityDomainService", e);
        }
        if (jsseSecurityDomain != null) {
            try {
                jsseSecurityDomain.reloadKeyAndTrustStore();
            } catch (Exception e) {
                throw SecurityLogger.ROOT_LOGGER.unableToStartException("SecurityDomainService", e);
            }
        }
        securityManagement.getSecurityManagerMap().put(name, sdc);
        this.securityDomainContext = sdc;
    }

    /** {@inheritDoc} */
    @Override
    public void stop(StopContext context) {
        SecurityLogger.ROOT_LOGGER.debugf("Stopping security domain service %s", name);
        final JNDIBasedSecurityManagement securityManagement = (JNDIBasedSecurityManagement) securityManagementValue.getValue();
        securityManagement.removeSecurityDomain(name);
        // TODO clear auth cache?
        final ApplicationPolicyRegistration applicationPolicyRegistration = (ApplicationPolicyRegistration) configurationValue
                .getValue();
        applicationPolicyRegistration.removeApplicationPolicy(name);
    }

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

    /**
     * Target {@code Injector}
     *
     * @return target
     */
    public Injector<ISecurityManagement> getSecurityManagementInjector() {
        return securityManagementValue;
    }

    /**
     * Target {@code Injector}
     *
     * @return target
     */
    public Injector<Configuration> getConfigurationInjector() {
        return configurationValue;
    }

    /**
     * Target {@code Injector}
     *
     * @return target
     */
    public Injector<ConcurrentMap> getCacheInjector() {
        return cacheValue;
    }
}


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

package org.jboss.as.clustering.dmr;

import java.util.List;
import java.util.Optional;
import java.util.OptionalDouble;
import java.util.OptionalInt;
import java.util.OptionalLong;

import org.jboss.dmr.ModelNode;
import org.jboss.dmr.Property;

/**
 * Utility methods for extracting values from a {@link ModelNode}.
 * @author Paul Ferraro
 */
public class ModelNodes {

    /**
     * Returns the value of the node as a float.
     * @param value a model node
     * @return the value of the node as a float.
     */
    public static float asFloat(ModelNode value) {
        return Double.valueOf(value.asDouble()).floatValue();
    }

    /**
     * Returns the value of the node as an Enum value.
     * @param value a model node
     * @return the value of the node as an Enum.
     */
    public static <E extends Enum<E>> E asEnum(ModelNode value, Class<E> targetClass) {
        return Enum.valueOf(targetClass, value.asString());
    }

    /**
     * Returns the optional boolean value of the specified {@link ModelNode}.
     * @param value the model node
     * @return an optional value
     */
    public static Optional<Boolean> optionalBoolean(ModelNode value) {
        return value.isDefined() ? Optional.of(value.asBoolean()) : Optional.empty();
    }

    /**
     * Returns the optional double value of the specified {@link ModelNode}.
     * @param value the model node
     * @return an optional value
     */
    public static OptionalDouble optionalDouble(ModelNode value) {
        return value.isDefined() ? OptionalDouble.of(value.asDouble()) : OptionalDouble.empty();
    }

    /**
     * Returns the optional float value of the specified {@link ModelNode}.
     * @param value the model node
     * @return an optional value
     */
    public static Optional<Float> optionalFloat(ModelNode value) {
        return value.isDefined() ? Optional.of(asFloat(value)) : Optional.empty();
    }

    /**
     * Returns the optional int value of the specified {@link ModelNode}.
     * @param value the model node
     * @return an optional value
     */
    public static OptionalInt optionalInt(ModelNode value) {
        return value.isDefined() ? OptionalInt.of(value.asInt()) : OptionalInt.empty();
    }

    /**
     * Returns the optional long value of the specified {@link ModelNode}.
     * @param value the model node
     * @return an optional value
     */
    public static OptionalLong optionalLong(ModelNode value) {
        return value.isDefined() ? OptionalLong.of(value.asInt()) : OptionalLong.empty();
    }

    /**
     * Returns the optional string value of the specified {@link ModelNode}.
     * @param value the model node
     * @return an optional value
     */
    public static Optional<String> optionalString(ModelNode value) {
        return value.isDefined() ? Optional.of(value.asString()) : Optional.empty();
    }

    /**
     * Returns the optional property value of the specified {@link ModelNode}.
     * @param value the model node
     * @return an optional value
     */
    public static Optional<Property> optionalProperty(ModelNode value) {
        return value.isDefined() ? Optional.of(value.asProperty()) : Optional.empty();
    }

    /**
     * Returns the optional property list value of the specified {@link ModelNode}.
     * @param value the model node
     * @return an optional value
     */
    public static Optional<List<Property>> optionalPropertyList(ModelNode value) {
        return value.isDefined() ? Optional.of(value.asPropertyList()) : Optional.empty();
    }

    /**
     * Returns the optional list value of the specified {@link ModelNode}.
     * @param value the model node
     * @return an optional value
     */
    public static Optional<List<ModelNode>> optionalList(ModelNode value) {
        return value.isDefined() ? Optional.of(value.asList()) : Optional.empty();
    }

    /**
     * Returns the optional enum value of the specified {@link ModelNode}.
     * @param value the model node
     * @return an optional value
     */
    public static <E extends Enum<E>> Optional<E> optionalEnum(ModelNode value, Class<E> targetClass) {
        return value.isDefined() ? Optional.of(asEnum(value, targetClass)) : Optional.empty();
    }

    private ModelNodes() {
        // Hide
    }
}