Package org.apache.openejb.server.ejbd

Source Code of org.apache.openejb.server.ejbd.JndiRequestHandler

/**
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements.  See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License.  You may obtain a copy of the License at
*
*     http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.openejb.server.ejbd;

import org.apache.openejb.BeanContext;
import org.apache.openejb.Injection;
import org.apache.openejb.ProxyInfo;
import org.apache.openejb.client.CallbackMetaData;
import org.apache.openejb.client.DataSourceMetaData;
import org.apache.openejb.client.EJBMetaDataImpl;
import org.apache.openejb.client.HandlerChainMetaData;
import org.apache.openejb.client.HandlerMetaData;
import org.apache.openejb.client.InjectionMetaData;
import org.apache.openejb.client.JNDIRequest;
import org.apache.openejb.client.JNDIResponse;
import org.apache.openejb.client.NameClassPairEnumeration;
import org.apache.openejb.client.PortRefMetaData;
import org.apache.openejb.client.ProtocolMetaData;
import org.apache.openejb.client.Response;
import org.apache.openejb.client.ResponseCodes;
import org.apache.openejb.client.ThrowableArtifact;
import org.apache.openejb.client.WsMetaData;
import org.apache.openejb.core.ivm.BaseEjbProxyHandler;
import org.apache.openejb.core.ivm.naming.IvmContext;
import org.apache.openejb.core.webservices.HandlerChainData;
import org.apache.openejb.core.webservices.HandlerData;
import org.apache.openejb.core.webservices.PortAddress;
import org.apache.openejb.core.webservices.PortAddressRegistry;
import org.apache.openejb.core.webservices.PortRefData;
import org.apache.openejb.core.webservices.ServiceRefData;
import org.apache.openejb.loader.SystemInstance;
import org.apache.openejb.resource.jdbc.DataSourceFactory;
import org.apache.openejb.server.context.RequestInfos;
import org.apache.openejb.server.stream.CountingInputStream;
import org.apache.openejb.server.stream.CountingOutputStream;
import org.apache.openejb.spi.ContainerSystem;
import org.apache.openejb.util.LogCategory;
import org.apache.openejb.util.Logger;
import org.apache.openejb.util.proxy.ProxyManager;
import org.omg.CORBA.ORB;

import javax.jms.ConnectionFactory;
import javax.jms.Topic;
import javax.naming.Context;
import javax.naming.NameClassPair;
import javax.naming.NameNotFoundException;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import javax.resource.Referenceable;
import javax.sql.DataSource;
import javax.validation.Validator;
import javax.validation.ValidatorFactory;
import javax.xml.namespace.QName;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Queue;
import java.util.Set;

import static org.apache.openejb.server.ejbd.ClientObjectFactory.convert;

class JndiRequestHandler extends RequestHandler {

    private static final Logger logger = Logger.getInstance(LogCategory.OPENEJB_SERVER_REMOTE.createChild("jndi"), "org.apache.openejb.server.util.resources");

    private final Context ejbJndiTree;
    private Context clientJndiTree;
    private final Context deploymentsJndiTree;

    private Context globalJndiTree;

    private final ClusterableRequestHandler clusterableRequestHandler;
    private Context rootContext;

    JndiRequestHandler(final EjbDaemon daemon) throws Exception {
        super(daemon);
        final ContainerSystem containerSystem = SystemInstance.get().getComponent(ContainerSystem.class);
        ejbJndiTree = (Context) containerSystem.getJNDIContext().lookup("openejb/remote");
        deploymentsJndiTree = (Context) containerSystem.getJNDIContext().lookup("openejb/Deployment");

        globalJndiTree = (Context) containerSystem.getJNDIContext().lookup("openejb/global");

        rootContext = containerSystem.getJNDIContext();
        try {
            clientJndiTree = (Context) containerSystem.getJNDIContext().lookup("openejb/client");
        } catch (NamingException ignore) {
        }
        clusterableRequestHandler = newClusterableRequestHandler();
    }

    protected BasicClusterableRequestHandler newClusterableRequestHandler() {
        return new BasicClusterableRequestHandler();
    }

    @Override
    public Logger getLogger() {
        return logger;
    }

    @Override
    public String getName() {
        return "JNDI";
    }

    @Override
    public Response processRequest(final ObjectInputStream in, final ProtocolMetaData metaData) {

        final JNDIRequest req = new JNDIRequest();
        final JNDIResponse res = new JNDIResponse();
        res.setRequest(req);

        try {
            req.setMetaData(metaData);
            req.readExternal(in);
        } catch (Throwable e) {
            res.setResponseCode(ResponseCodes.JNDI_NAMING_EXCEPTION);
            final NamingException namingException = new NamingException("Could not read jndi request");
            namingException.setRootCause(e);
            res.setResult(new ThrowableArtifact(namingException));

            if (logger.isDebugEnabled()) {
                try {
                    logRequestResponse(req, res);
                } catch (Exception ignore) {
                    // no-op
                }
            }
        }
        return res;
    }

    @Override
    public void processResponse(final Response response, final ObjectOutputStream out, final ProtocolMetaData metaData) throws Exception {

        if (JNDIResponse.class.isInstance(response)) {

            final JNDIResponse res = (JNDIResponse) response;
            final JNDIRequest req = res.getRequest();

            try {

                //Only process if 'processRequest' was ok...
                final Object result = res.getResult();
                if (null == result || !ThrowableArtifact.class.isInstance(result)) {

                    if (req.getRequestString().startsWith("/")) {
                        req.setRequestString(req.getRequestString().substring(1));
                    }

                    final String prefix = getPrefix(req);

                    switch (req.getRequestMethod()) {
                        case JNDI_LOOKUP:
                            doLookup(req, res, prefix);
                            break;
                        case JNDI_LIST:
                            doList(req, res, prefix);
                            break;
                    }
                }

            } catch (Throwable e) {
                res.setResponseCode(ResponseCodes.JNDI_NAMING_EXCEPTION);
                final NamingException namingException = new NamingException("Unknown error in container");
                namingException.setRootCause(e);
                res.setResult(new ThrowableArtifact(namingException));
            } finally {

                try {
                    res.setMetaData(metaData);
                    res.writeExternal(out);
                } catch (Throwable e) {
                    logger.fatal("Could not write JndiResponse to output stream", e);
                }

                if (logger.isDebugEnabled()) {
                    try {
                        out.flush(); // force it to as correct as possible response size
                        logRequestResponse(req, res);
                    } catch (Exception ignore) {
                        // no-op
                    }
                }
            }

        } else {
            logger.error("JndiRequestHandler cannot process an instance of: " + response.getClass().getName());
        }
    }

    private void logRequestResponse(final JNDIRequest req, final JNDIResponse res) {
        final RequestInfos.RequestInfo info = RequestInfos.info();
        final CountingInputStream cis = info.getInputStream();
        final CountingOutputStream cos = info.getOutputStream();

        logger.debug("JNDI REQUEST: " + req + " (size = " + (null != cis ? cis.getCount() : 0)
            + "b, remote-ip =" + info.ip
            + ") -- RESPONSE: " + res + " (size = " + (null != cos ? cos.getCount() : 0) + "b)");
    }

    private String getPrefix(final JNDIRequest req) throws NamingException {
        final String prefix;
        final String name = req.getRequestString();

        if (name.startsWith("openejb/Deployment/")) {
            prefix = "";
        } else if (req.getModuleId() != null && req.getModuleId().equals("openejb/Deployment")) {
            prefix = "openejb/Deployment/";
        } else if (req.getModuleId() != null && req.getModuleId().equals("openejb/global")) {
            prefix = "openejb/global/";
        } else if (req.getModuleId() != null && clientJndiTree != null) {
            prefix = "openejb/client/" + req.getModuleId() + "/";// + (Context) clientJndiTree.lookup(req.getModuleId());
        } else {
            prefix = "openejb/remote/";
        }
        return prefix;
    }

    private void doLookup(final JNDIRequest req, final JNDIResponse res, final String prefix) {
        Object object;
        final String name = req.getRequestString();

        try {

            if (name.equals("info/injections")) {

                //noinspection unchecked
                final List<Injection> injections = (List<Injection>) rootContext.lookup(prefix + name);
                final InjectionMetaData metaData = new InjectionMetaData();
                for (final Injection injection : injections) {
                    if (injection.getTarget() == null) {
                        continue;
                    }
                    metaData.addInjection(injection.getTarget().getName(), injection.getName(), injection.getJndiName());
                }
                res.setResponseCode(ResponseCodes.JNDI_INJECTIONS);
                res.setResult(metaData);
                return;
            } else {
                try {
                    object = rootContext.lookup(prefix + name);
                } catch (NameNotFoundException nnfe) { // fallback to resources
                    object = rootContext.lookup("openejb/Resource/" + name);
                }
            }

            if (object instanceof Context) {
                res.setResponseCode(ResponseCodes.JNDI_CONTEXT);
                return;
            } else if (object == null) {
                throw new NullPointerException("lookup of '" + name + "' returned null");
            } else if (object instanceof DataSource) {
                if (DataSourceFactory.knows(object)) {
                    try {
                        final DbcpDataSource cf = new DbcpDataSource(object);
                        final DataSourceMetaData dataSourceMetaData = new DataSourceMetaData(cf.getDriverClassName(), cf.getUrl(), cf.getUsername(), cf.getPassword());
                        res.setResponseCode(ResponseCodes.JNDI_DATA_SOURCE);
                        res.setResult(dataSourceMetaData);
                    } catch (Exception e) {
                        res.setResponseCode(ResponseCodes.JNDI_ERROR);
                        res.setResult(new ThrowableArtifact(e));
                    }
                    return;
                } else if (object instanceof Referenceable) {
                    res.setResponseCode(ResponseCodes.JNDI_REFERENCE);
                    res.setResult(((Referenceable) object).getReference());
                    return;
                }
            } else if (object instanceof ConnectionFactory) {
                res.setResponseCode(ResponseCodes.JNDI_RESOURCE);
                res.setResult(ConnectionFactory.class.getName());
                return;
            } else if (object instanceof ORB) {
                res.setResponseCode(ResponseCodes.JNDI_RESOURCE);
                res.setResult(ORB.class.getName());
                return;
            } else if (object instanceof ValidatorFactory) {
                res.setResponseCode(ResponseCodes.JNDI_RESOURCE);
                res.setResult(ValidatorFactory.class.getName());
                return;
            } else if (object instanceof Validator) {
                res.setResponseCode(ResponseCodes.JNDI_RESOURCE);
                res.setResult(Validator.class.getName());
                return;
            } else if (object instanceof Queue) {
                res.setResponseCode(ResponseCodes.JNDI_RESOURCE);
                res.setResult(Queue.class.getName());
                return;
            } else if (object instanceof Topic) {
                res.setResponseCode(ResponseCodes.JNDI_RESOURCE);
                res.setResult(Topic.class.getName());
                return;
            }

            final ServiceRefData serviceRef;
            if (object instanceof ServiceRefData) {
                serviceRef = (ServiceRefData) object;
            } else {
                serviceRef = ServiceRefData.getServiceRefData(object);
            }

            if (serviceRef != null) {
                final WsMetaData serviceMetaData = new WsMetaData();

                // service class
                String serviceClassName = null;
                if (serviceRef.getServiceClass() != null) {
                    serviceClassName = serviceRef.getServiceClass().getName();
                }
                serviceMetaData.setServiceClassName(serviceClassName);

                // reference class
                String referenceClassName = null;
                if (serviceRef.getReferenceClass() != null) {
                    referenceClassName = serviceRef.getReferenceClass().getName();
                }
                serviceMetaData.setReferenceClassName(referenceClassName);

                // set service qname
                if (serviceRef.getServiceQName() != null) {
                    serviceMetaData.setServiceQName(serviceRef.getServiceQName().toString());
                }

                // get the port addresses for this service
                final PortAddressRegistry portAddressRegistry = SystemInstance.get().getComponent(PortAddressRegistry.class);
                Set<PortAddress> portAddresses = null;
                if (portAddressRegistry != null) {
                    portAddresses = portAddressRegistry.getPorts(serviceRef.getId(), serviceRef.getServiceQName(), referenceClassName);
                }

                // resolve the wsdl url
                if (serviceRef.getWsdlURL() != null) {
                    serviceMetaData.setWsdlUrl(serviceRef.getWsdlURL().toExternalForm());
                }
                if (portAddresses.size() == 1) {
                    final PortAddress portAddress = portAddresses.iterator().next();
                    serviceMetaData.setWsdlUrl(portAddress.getAddress() + "?wsdl");
                }

                // add handler chains
                for (final HandlerChainData handlerChain : serviceRef.getHandlerChains()) {
                    final HandlerChainMetaData handlerChainMetaData = new HandlerChainMetaData();
                    handlerChainMetaData.setServiceNamePattern(handlerChain.getServiceNamePattern());
                    handlerChainMetaData.setPortNamePattern(handlerChain.getPortNamePattern());
                    handlerChainMetaData.getProtocolBindings().addAll(handlerChain.getProtocolBindings());
                    for (final HandlerData handler : handlerChain.getHandlers()) {
                        final HandlerMetaData handlerMetaData = new HandlerMetaData();
                        handlerMetaData.setHandlerClass(handler.getHandlerClass().getName());
                        for (final Method method : handler.getPostConstruct()) {
                            final CallbackMetaData callbackMetaData = new CallbackMetaData();
                            callbackMetaData.setClassName(method.getDeclaringClass().getName());
                            callbackMetaData.setMethod(method.getName());
                            handlerMetaData.getPostConstruct().add(callbackMetaData);
                        }
                        for (final Method method : handler.getPreDestroy()) {
                            final CallbackMetaData callbackMetaData = new CallbackMetaData();
                            callbackMetaData.setClassName(method.getDeclaringClass().getName());
                            callbackMetaData.setMethod(method.getName());
                            handlerMetaData.getPreDestroy().add(callbackMetaData);
                        }
                        handlerChainMetaData.getHandlers().add(handlerMetaData);
                    }
                    serviceMetaData.getHandlerChains().add(handlerChainMetaData);
                }

                // add port refs
                final Map<QName, PortRefMetaData> portsByQName = new HashMap<QName, PortRefMetaData>();
                for (final PortRefData portRef : serviceRef.getPortRefs()) {
                    final PortRefMetaData portRefMetaData = new PortRefMetaData();
                    portRefMetaData.setQName(portRef.getQName());
                    portRefMetaData.setServiceEndpointInterface(portRef.getServiceEndpointInterface());
                    portRefMetaData.setEnableMtom(portRef.isEnableMtom());
                    portRefMetaData.getProperties().putAll(portRef.getProperties());
                    portRefMetaData.getAddresses().addAll(portRef.getAddresses());
                    if (portRef.getQName() != null) {
                        portsByQName.put(portRef.getQName(), portRefMetaData);
                    }
                    serviceMetaData.getPortRefs().add(portRefMetaData);
                }

                // add PortRefMetaData for any portAddress not added above
                for (final PortAddress portAddress : portAddresses) {
                    PortRefMetaData portRefMetaData = portsByQName.get(portAddress.getPortQName());
                    if (portRefMetaData == null) {
                        portRefMetaData = new PortRefMetaData();
                        portRefMetaData.setQName(portAddress.getPortQName());
                        portRefMetaData.setServiceEndpointInterface(portAddress.getServiceEndpointInterface());
                        portRefMetaData.getAddresses().add(portAddress.getAddress());
                        serviceMetaData.getPortRefs().add(portRefMetaData);
                    } else {
                        portRefMetaData.getAddresses().add(portAddress.getAddress());
                        if (portRefMetaData.getServiceEndpointInterface() == null) {
                            portRefMetaData.setServiceEndpointInterface(portAddress.getServiceEndpointInterface());
                        }
                    }
                }

                res.setResponseCode(ResponseCodes.JNDI_WEBSERVICE);
                res.setResult(serviceMetaData);
                return;
            }
        } catch (NameNotFoundException e) {
            res.setResponseCode(ResponseCodes.JNDI_NOT_FOUND);
            return;
        } catch (NamingException e) {
            res.setResponseCode(ResponseCodes.JNDI_NAMING_EXCEPTION);
            res.setResult(new ThrowableArtifact(e));
            return;
        }

        BaseEjbProxyHandler handler;
        try {
            handler = (BaseEjbProxyHandler) ProxyManager.getInvocationHandler(object);
        } catch (Exception e) {
            try {
                final Field field = object.getClass().getDeclaredField("invocationHandler");
                field.setAccessible(true);
                handler = (BaseEjbProxyHandler) field.get(object);
            } catch (Exception e1) {
                // Not a proxy.  See if it's serializable and send it
                if (object instanceof java.io.Serializable) {
                    res.setResponseCode(ResponseCodes.JNDI_OK);
                    res.setResult(object);
                    return;
                } else {
                    res.setResponseCode(ResponseCodes.JNDI_NAMING_EXCEPTION);
                    final NamingException namingException = new NamingException("Expected an ejb proxy, found unknown object: type=" +
                        object.getClass().getName() +
                        ", toString=" +
                        object);
                    res.setResult(new ThrowableArtifact(namingException));
                    return;
                }
            }
        }

        final ProxyInfo proxyInfo = handler.getProxyInfo();
        final BeanContext beanContext = proxyInfo.getBeanContext();
        final String deploymentID = beanContext.getDeploymentID().toString();

        updateServer(req, res, proxyInfo);

        switch (proxyInfo.getInterfaceType()) {
            case EJB_HOME: {
                res.setResponseCode(ResponseCodes.JNDI_EJBHOME);
                final EJBMetaDataImpl metaData = new EJBMetaDataImpl(beanContext.getHomeInterface(),
                    beanContext.getRemoteInterface(),
                    beanContext.getPrimaryKeyClass(),
                    beanContext.getComponentType().toString(),
                    deploymentID,
                    -1,
                    convert(proxyInfo.getInterfaceType()),
                    null,
                    beanContext.getAsynchronousMethodSignatures());
                metaData.loadProperties(beanContext.getProperties());
                log(metaData);
                res.setResult(metaData);
                break;
            }
            case EJB_LOCAL_HOME: {
                res.setResponseCode(ResponseCodes.JNDI_NAMING_EXCEPTION);
                final NamingException namingException = new NamingException("Not remotable: '" +
                    name +
                    "'. EJBLocalHome interfaces are not remotable as per the EJB specification.");
                res.setResult(new ThrowableArtifact(namingException));
                break;
            }
            case BUSINESS_REMOTE: {
                res.setResponseCode(ResponseCodes.JNDI_BUSINESS_OBJECT);
                final EJBMetaDataImpl metaData = new EJBMetaDataImpl(null,
                    null,
                    beanContext.getPrimaryKeyClass(),
                    beanContext.getComponentType().toString(),
                    deploymentID,
                    -1,
                    convert(proxyInfo.getInterfaceType()),
                    proxyInfo.getInterfaces(),
                    beanContext.getAsynchronousMethodSignatures());
                metaData.setPrimaryKey(proxyInfo.getPrimaryKey());
                metaData.loadProperties(beanContext.getProperties());

                log(metaData);
                res.setResult(metaData);
                break;
            }
            case BUSINESS_LOCAL: {
                res.setResponseCode(ResponseCodes.JNDI_NAMING_EXCEPTION);
                final NamingException namingException = new NamingException("Not remotable: '" +
                    name +
                    "'. Business Local interfaces are not remotable as per the EJB specification.  To disable this restriction, set the system property 'openejb.remotable.businessLocals=true' in the server.");
                res.setResult(new ThrowableArtifact(namingException));
                break;
            }
            case LOCALBEAN: {
                res.setResponseCode(ResponseCodes.JNDI_NAMING_EXCEPTION);
                final NamingException namingException = new NamingException("Not remotable: '" + name + "'. LocalBean classes are not remotable as per the EJB specification.");
                res.setResult(new ThrowableArtifact(namingException));
                break;
            }
            default: {
                res.setResponseCode(ResponseCodes.JNDI_NAMING_EXCEPTION);
                final NamingException namingException = new NamingException("Not remotable: '" + name + "'.");
                res.setResult(new ThrowableArtifact(namingException));
            }
        }

    }

    private void log(final EJBMetaDataImpl metaData) {
        if (logger.isDebugEnabled()) {
            final StringBuilder sb = new StringBuilder();
            sb.append("Sending Ejb(");

            sb.append("deployment-id").append("=");
            sb.append(metaData.getDeploymentID());
            sb.append(", properties=[");
            final String delimiter = "|";
            for (final Map.Entry<Object, Object> entry : metaData.getProperties().entrySet()) {
                sb.append(entry.getKey()).append("=").append(entry.getValue()).append(delimiter);
            }
            if (metaData.getProperties().size() > 1) {
                sb.delete(sb.length() - delimiter.length(), sb.length());
            }
            sb.append("])");
            logger.debug(sb.toString());
        }
    }

    protected void updateServer(final JNDIRequest req, final JNDIResponse res, final ProxyInfo proxyInfo) {
        clusterableRequestHandler.updateServer(proxyInfo.getBeanContext(), req, res);
    }

    private void doList(final JNDIRequest req, final JNDIResponse res, final String prefix) {
        final String name = req.getRequestString();
        try {
            final NamingEnumeration<NameClassPair> namingEnumeration = rootContext.list(prefix + name);
            if (namingEnumeration == null) {
                res.setResponseCode(ResponseCodes.JNDI_OK);
                res.setResult(null);
            } else {
                res.setResponseCode(ResponseCodes.JNDI_ENUMERATION);
                final ArrayList<NameClassPair> list = Collections.list(namingEnumeration);
                for (final NameClassPair pair : list) {
                    if (pair.getClassName().equals(IvmContext.class.getName())) {
                        pair.setClassName(javax.naming.Context.class.getName());
                    }
                }
                res.setResult(new NameClassPairEnumeration(list));
            }
        } catch (NameNotFoundException e) {
            res.setResponseCode(ResponseCodes.JNDI_NOT_FOUND);
        } catch (NamingException e) {
            res.setResponseCode(ResponseCodes.JNDI_NAMING_EXCEPTION);
            res.setResult(new ThrowableArtifact(e));
        }
    }

    @SuppressWarnings("unchecked")
    public static class DbcpDataSource {

        private final Object object;
        private final Class clazz;

        public DbcpDataSource(final Object object) {
            clazz = object.getClass();
            this.object = object;
        }

        public java.lang.String getDriverClassName() throws Exception {
            try {
                return (String) clazz.getMethod("getDriverClassName").invoke(object);
            } catch (NoSuchMethodException nsme) {
                return (String) clazz.getMethod("getDriverClass").invoke(object);
            }
        }

        public java.lang.String getPassword() throws Exception {
            return (String) clazz.getMethod("getPassword").invoke(object);
        }

        public java.lang.String getUrl() throws Exception {
            try {
                return (String) clazz.getMethod("getUrl").invoke(object);
            } catch (NoSuchMethodException nsme) {
                return (String) clazz.getMethod("getJdbcUrl").invoke(object);
            }
        }

        public java.lang.String getUsername() throws Exception {
            return (String) clazz.getMethod("getUsername").invoke(object);
        }
    }
}
TOP

Related Classes of org.apache.openejb.server.ejbd.JndiRequestHandler

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.