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

net.e6tech.elements.web.cxf.InstanceResourceProvider Maven / Gradle / Ivy

There is a newer version: 2.7.12
Show newest version
/*
 * Copyright 2017 Futeh Kao
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package net.e6tech.elements.web.cxf;

import net.e6tech.elements.common.inject.Module;
import net.e6tech.elements.common.interceptor.CallFrame;
import net.e6tech.elements.common.interceptor.InterceptorHandler;
import net.e6tech.elements.common.logging.LogLevel;
import net.e6tech.elements.common.logging.Logger;
import net.e6tech.elements.common.reflection.ClassSignature;
import net.e6tech.elements.common.reflection.MethodSignature;
import net.e6tech.elements.common.reflection.Reflection;
import net.e6tech.elements.common.reflection.Signature;
import net.e6tech.elements.common.resources.ResourcesFactory;
import net.e6tech.elements.common.resources.UnitOfWork;
import net.e6tech.elements.common.util.ExceptionMapper;
import net.e6tech.elements.common.util.datastructure.Pair;
import org.apache.cxf.io.CachedOutputStream;
import org.apache.cxf.jaxrs.lifecycle.PerRequestResourceProvider;
import org.apache.cxf.message.Message;

import javax.annotation.PreDestroy;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

class InstanceResourceProvider extends PerRequestResourceProvider {
    private ResourcesFactory factory;
    private Observer observer;
    private Map methods = new ConcurrentHashMap<>();
    private Object prototype;
    private CXFServer server;
    private Map, Annotation>> annotations;

    @SuppressWarnings("unchecked")
    InstanceResourceProvider(JaxRSServer server, Class resourceClass, Object prototype, Module module, ResourcesFactory factory, Observer observer) {
        super(resourceClass);
        this.server = server;
        this.observer = observer;
        this.factory = factory;
        this.prototype = prototype;
        factory.preOpen(res -> {
            if (module != null)
                res.addModule(module);
            if (server.getExceptionMapper() != null) {
                res.rebind(ExceptionMapper.class, server.getExceptionMapper());
                res.rebind((Class) server.getExceptionMapper().getClass(), server.getExceptionMapper());
            }
        });
        annotations = Reflection.getAnnotations(resourceClass);
    }

    @SuppressWarnings("unchecked")
    @Override
    protected Object createInstance(Message message) {
        Object instance = super.createInstance(message);
        if (prototype != null)
            Reflection.copyInstance(instance, prototype);
        Observer cloneObserver = (observer == null) ? null : observer.clone();
        UnitOfWork uow = (cloneObserver != null) ? cloneObserver.open(factory) : factory.open();
        return server.getInterceptor().newInterceptor(instance, new Handler(uow, methods, cloneObserver, message));
    }

    private class Handler implements InterceptorHandler {
        UnitOfWork uow;
        Message message;
        Observer observer;
        Map methods;

        Handler(UnitOfWork uow, Map methods, Observer observer, Message message) {
            this.uow = uow;
            this.message = message;
            this.observer = observer;
            this.methods = methods;
        }

        @SuppressWarnings("unchecked")
        private void open(Object target, Method method) {
            Class cls = target.getClass();
            ClassSignature classSignature = new ClassSignature(cls);
            Map, Annotation> map = annotations.getOrDefault(classSignature, new HashMap<>());
            MethodSignature methodSignature = new MethodSignature(method);
            Map, Annotation> map2 = annotations.getOrDefault(methodSignature, new HashMap<>());

            for (Map.Entry, Annotation> entry : map.entrySet()) {
                uow.put((Class) entry.getKey(), entry.getValue());
            }

            for (Map.Entry, Annotation> entry : map2.entrySet()) {
                uow.put((Class) entry.getKey(), entry.getValue());
            }

            uow.open();
        }

        @Override
        @SuppressWarnings("squid:S3776")
        public Object invoke(CallFrame frame) throws Throwable {
            boolean exception = false;
            Object result = null;
            boolean ignored = false;

            // Note PostConstruct is handled by CXF during createInstance
            boolean uowOpen = false;
            if (frame.getAnnotation(PreDestroy.class) != null) {
                ignored = true;
            } else {
                try {
                    open(frame.getTarget(), frame.getMethod());
                    uowOpen = true;
                } catch (Exception th) {
                    JaxRSServer.getLogger().debug(th.getMessage(), th);
                    server.handleException(message, frame, th);
                }
            }

            try {
                server.checkInvocation(frame.getMethod(), frame.getArguments());
                Pair pair = server.getServletRequestResponse(message);
                if (!ignored) {
                    long start = System.currentTimeMillis();
                    result = uow.submit(() -> {
                        try {
                            if (observer != null) {
                                uow.getResources().inject(observer);
                                CachedOutputStream cachedOutputStream = message.getContent(CachedOutputStream.class);
                                if (cachedOutputStream != null) {
                                    pair.key().setAttribute("Content", cachedOutputStream.getBytes());
                                }
                                observer.beforeInvocation(pair.key(), pair.value(), frame.getTarget(), frame.getMethod(), frame.getArguments());
                            }
                            uow.getResources().inject(frame.getTarget());
                            Object ret = frame.invoke();
                            if (observer != null)
                                observer.afterInvocation(ret);
                            return ret;
                        } catch (Exception th) {
                            if (observer != null) { // this code is here so that the Resources object has not been clean up
                                                    // so that the observer can still use the Resources to retrieve information.
                                try {
                                    observer.onException(th);
                                } catch (Exception ex) {
                                    Logger.suppress(ex);
                                }
                            }
                            // uow will abort the resources and do clean up after this
                            throw th;
                        }
                    });
                    long duration = System.currentTimeMillis() - start;
                    server.computePerformance(frame.getMethod(), methods, duration);
                } else {
                    // PreDestroy is called
                    result = frame.invoke();
                }
            } catch (Exception th) {
                server.recordFailure(frame.getMethod(), methods);
                exception = true;
                server.getProvision().log(JaxRSServer.getLogger(), LogLevel.DEBUG, th.getMessage(), th);
                server.handleException(message, frame, th);
            } finally {
                if (uowOpen) {
                    if (exception)
                        uow.abort();
                    else if (!uow.isAborted()) // application can call abort
                        uow.commit();
                }
            }
            return result;
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy