001    /**
002     * Copyright (c) 2000-present Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
013     */
014    
015    package com.liferay.portal.deploy.hot;
016    
017    import com.liferay.portal.kernel.bean.ClassLoaderBeanHandler;
018    import com.liferay.portal.kernel.util.ProxyUtil;
019    import com.liferay.portal.service.ServiceWrapper;
020    
021    import java.lang.reflect.InvocationHandler;
022    
023    import org.springframework.aop.TargetSource;
024    import org.springframework.aop.framework.AdvisedSupport;
025    import org.springframework.aop.target.SingletonTargetSource;
026    
027    /**
028     * @author Raymond Aug??
029     */
030    public class ServiceBag<V> {
031    
032            public ServiceBag(
033                    ClassLoader classLoader, AdvisedSupport advisedSupport,
034                    Class<?> serviceTypeClass, final ServiceWrapper<V> serviceWrapper) {
035    
036                    _advisedSupport = advisedSupport;
037    
038                    Object previousService = serviceWrapper.getWrappedService();
039    
040                    if (!(previousService instanceof ServiceWrapper)) {
041                            Class<?> previousServiceClass = previousService.getClass();
042    
043                            ClassLoader previousServiceClassLoader =
044                                    previousServiceClass.getClassLoader();
045    
046                            previousService = ProxyUtil.newProxyInstance(
047                                    previousServiceClassLoader, new Class<?>[] {serviceTypeClass},
048                                    new ClassLoaderBeanHandler(
049                                            previousService, previousServiceClassLoader));
050    
051                            serviceWrapper.setWrappedService((V)previousService);
052                    }
053    
054                    Object nextTarget = ProxyUtil.newProxyInstance(
055                            serviceTypeClass.getClassLoader(),
056                            new Class<?>[] {serviceTypeClass, ServiceWrapper.class},
057                            new ClassLoaderBeanHandler(serviceWrapper, classLoader));
058    
059                    TargetSource nextTargetSource = new SingletonTargetSource(nextTarget) {
060    
061                            @Override
062                            public Class<?> getTargetClass() {
063                                    return serviceWrapper.getClass();
064                            }
065    
066                    };
067    
068                    _advisedSupport.setTargetSource(nextTargetSource);
069    
070                    _serviceWrapper = (ServiceWrapper<?>)nextTarget;
071            }
072    
073            @SuppressWarnings("unchecked")
074            public <T> void replace() throws Exception {
075                    TargetSource targetSource = _advisedSupport.getTargetSource();
076    
077                    Object currentService = targetSource.getTarget();
078                    ServiceWrapper<T> previousService = null;
079    
080                    // Loop through services
081    
082                    while (true) {
083    
084                            // A matching service was found
085    
086                            if (currentService == _serviceWrapper) {
087                                    Object wrappedService = _serviceWrapper.getWrappedService();
088    
089                                    if (previousService == null) {
090    
091                                            // There is no previous service, so we need to unwrap the
092                                            // portal class loader bean handler and change the target
093                                            // source
094    
095                                            if (!(wrappedService instanceof ServiceWrapper) &&
096                                                    ProxyUtil.isProxyClass(wrappedService.getClass())) {
097    
098                                                    InvocationHandler invocationHandler =
099                                                            ProxyUtil.getInvocationHandler(wrappedService);
100    
101                                                    if (invocationHandler instanceof
102                                                                    ClassLoaderBeanHandler) {
103    
104                                                            ClassLoaderBeanHandler classLoaderBeanHandler =
105                                                                    (ClassLoaderBeanHandler)invocationHandler;
106    
107                                                            wrappedService = classLoaderBeanHandler.getBean();
108                                                    }
109                                            }
110    
111                                            TargetSource previousTargetSource =
112                                                    new SingletonTargetSource(wrappedService);
113    
114                                            _advisedSupport.setTargetSource(previousTargetSource);
115                                    }
116                                    else {
117    
118                                            // Take ourselves out of the chain by setting our
119                                            // wrapped service as the previous without changing the
120                                            // target source
121    
122                                            previousService.setWrappedService((T)wrappedService);
123                                    }
124    
125                                    break;
126                            }
127    
128                            // Every item in the chain is a ServiceWrapper except the original
129                            // service
130    
131                            if (!(currentService instanceof ServiceWrapper)) {
132                                    break;
133                            }
134    
135                            // Check the next service because no matching service was found
136    
137                            previousService = (ServiceWrapper<T>)currentService;
138    
139                            currentService = previousService.getWrappedService();
140                    }
141            }
142    
143            private final AdvisedSupport _advisedSupport;
144            private final ServiceWrapper<?> _serviceWrapper;
145    
146    }