All Downloads are FREE. Search and download functionalities are using the official Maven repository.

cloud.piranha.extension.naming.NamingExtension Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (c) 2002-2024 Manorrock.com. All Rights Reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 *   1. Redistributions of source code must retain the above copyright notice,
 *      this list of conditions and the following disclaimer.
 *   2. Redistributions in binary form must reproduce the above copyright
 *      notice, this list of conditions and the following disclaimer in the
 *      documentation and/or other materials provided with the distribution.
 *   3. Neither the name of the copyright holder nor the names of its
 *      contributors may be used to endorse or promote products derived from
 *      this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */
package cloud.piranha.extension.naming;

import cloud.piranha.core.api.WebApplication;
import cloud.piranha.core.api.WebApplicationExtension;
import com.manorrock.herring.DefaultInitialContext;
import jakarta.annotation.Resource;
import static java.lang.System.Logger.Level.DEBUG;
import static java.lang.System.Logger.Level.WARNING;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Arrays;
import java.util.Optional;
import javax.naming.CompositeName;
import javax.naming.Context;
import static javax.naming.Context.INITIAL_CONTEXT_FACTORY;
import javax.naming.NamingException;
import javax.naming.Reference;
import javax.naming.spi.NamingManager;

/**
 * The WebApplicationExtension that is responsible for setting up the proper
 * Context instance so it can be made available during web application
 * initialization and subsequently during request processing as well as
 * delivering listeners to set/remove the Context from the current thread.
 *
 * @author Manfred Riem ([email protected])
 */
public class NamingExtension implements WebApplicationExtension {

    /**
     * Stores the logger.
     */
    private static final System.Logger LOGGER = System.getLogger(NamingExtension.class.getName());

    /**
     * Configure the web application.
     *
     * @param webApplication the web application.
     */
    @Override
    public void configure(WebApplication webApplication) {
        LOGGER.log(DEBUG, "Configuring NamingExtension");
        if (System.getProperty(INITIAL_CONTEXT_FACTORY) == null) {
            LOGGER.log(DEBUG, "Setting " + INITIAL_CONTEXT_FACTORY + " to " + NamingInitialContextFactory.class.getName());
            System.setProperty(INITIAL_CONTEXT_FACTORY, NamingInitialContextFactory.class.getName());
        }
        if (!System.getProperty(INITIAL_CONTEXT_FACTORY).equals(NamingInitialContextFactory.class.getName())) {
            LOGGER.log(WARNING, INITIAL_CONTEXT_FACTORY + " is not set to " + NamingInitialContextFactory.class.getName());
        }

        Context context = new DefaultInitialContext();

        Context proxyContext = (Context) Proxy.newProxyInstance(
            Thread.currentThread().getContextClassLoader(),
            new Class[] { Context.class },
            new InvocationHandler() {
                @Override
                public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                    try {
                        Object returnValue = null;
                        try {
                            returnValue = method.invoke(context, args);
                        } catch (InvocationTargetException e) {
                            boolean invoked = false;
                            try {
                                if (method.getName().equals("lookup") && e.getCause() instanceof NamingException) {
                                    String jndiName = args[0].toString();

                                    if (jndiName.startsWith("java:comp/env/")) {
                                        String classNameWithField = jndiName.substring("java:comp/env/".length());
                                        String[] classNameAndField =  classNameWithField.split("/");
                                        if (classNameAndField.length == 2) {
                                            String className = classNameAndField[0];
                                            String fieldName = classNameAndField[1];

                                            Class beanClass = Class.forName(className, false, Thread.currentThread().getContextClassLoader());

                                            Resource[] resources = null;
                                            Class type = null;

                                            try {
                                                Field beanField = beanClass.getDeclaredField(fieldName);
                                                resources = beanField.getAnnotationsByType(Resource.class);
                                                type = beanField.getType();
                                            } catch (NoSuchFieldException | SecurityException exception) {
                                                char[] chars = fieldName.toCharArray();
                                                chars[0] = Character.toUpperCase(chars[0]);
                                                String methodName = "set" + new String(chars);

                                                Optional optionalMethod = Arrays.stream(beanClass.getDeclaredMethods())
                                                      .filter(m -> m.getName().equals(methodName))
                                                      .filter(m -> m.getParameterCount() == 1)
                                                      .filter(m -> m.getAnnotationsByType(Resource.class) != null)
                                                      .findFirst(); // ignore overloaded for now

                                                if (optionalMethod.isPresent()) {
                                                    resources = optionalMethod.get().getAnnotationsByType(Resource.class);
                                                    type = optionalMethod.get().getParameterTypes()[0];
                                                }
                                            }

                                            if (resources != null && resources.length > 0) {
                                                Resource resourceAnnnotation = resources[0];

                                                String lookup = resourceAnnnotation.lookup();
                                                if (!"".equals(lookup)) {
                                                    returnValue = method.invoke(context, new Object[] {lookup});
                                                    args = new Object[] {lookup};
                                                    invoked = true;
                                                } else {
                                                    throw new IllegalStateException("Cannot find " + type);
                                                }
                                            }
                                        }
                                    }
                                }
                            } catch (Throwable t) {
                                if (t instanceof InvocationTargetException invocationException &&
                                    invocationException.getTargetException() instanceof NamingException namingException) {
                                   throw namingException;
                                }
                                e.addSuppressed(t);
                            }

                            if (!invoked) {
                                throw e;
                            }
                        }

                        // De-referencing can eventually be moved to DefaultInitialContext
                        if (method.getName().equals("lookup") && returnValue instanceof Reference) {
                            returnValue = NamingManager.getObjectInstance(
                                returnValue, new CompositeName(args[0].toString()), null, null);
                        }

                        return returnValue;
                    } catch (InvocationTargetException e) {
                        throw e.getCause();
                    }
                }
            });

        NamingInitialContextFactory.setInitialContext(proxyContext);
        webApplication.setAttribute(Context.class.getName(), proxyContext);
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy