1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18 package org.apache.commons.proxy.interceptor; 19 20 import org.apache.commons.proxy.ObjectProvider; 21 import org.apache.commons.proxy.ProxyFactory; 22 import org.apache.commons.proxy.ProxyUtils; 23 import org.apache.commons.proxy.Interceptor; 24 25 /** 26 * An <code>InterceptorChain</code> assists with creating proxies which go through a series of 27 * {@link Interceptor interceptors}. 28 * 29 * <pre> 30 * MyServiceInterface serviceImpl = ...; 31 * ProxyFactory factory = ...; 32 * Interceptor[] interceptors = ...; 33 * InterceptorChain chain = new InterceptorChain(interceptors); 34 * ObjectProvider provider = chain.createProxyProvider(factory, serviceImpl); 35 * MyServiceInterface serviceProxy = ( MyServiceInterface )provider.getObject(); 36 * serviceProxy.someServiceMethod(...); // This will go through the interceptors! 37 * </pre> 38 * 39 * @author James Carman 40 * @since 1.0 41 */ 42 public class InterceptorChain 43 { 44 //---------------------------------------------------------------------------------------------------------------------- 45 // Fields 46 //---------------------------------------------------------------------------------------------------------------------- 47 private final Interceptor[] interceptors; 48 49 //---------------------------------------------------------------------------------------------------------------------- 50 // Constructors 51 //---------------------------------------------------------------------------------------------------------------------- 52 53 public InterceptorChain( Interceptor[] interceptors ) 54 { 55 this.interceptors = interceptors; 56 } 57 58 //---------------------------------------------------------------------------------------------------------------------- 59 // Other Methods 60 //---------------------------------------------------------------------------------------------------------------------- 61 62 private Object createProxy( ProxyFactory proxyFactory, ClassLoader classLoader, Object terminus, 63 Class[] proxyClasses ) 64 { 65 Object currentTarget = terminus; 66 for( int i = interceptors.length - 1; i >= 0; --i ) 67 { 68 currentTarget = proxyFactory 69 .createInterceptorProxy( classLoader, currentTarget, interceptors[i], proxyClasses ); 70 } 71 return currentTarget; 72 } 73 74 /** 75 * Creates an {@link ObjectProvider} which will return a proxy that sends method invocations through this 76 * chain of interceptors and ultimately arrive at the supplied terminus object. The proxy will support all 77 * interfaces implemented by the terminus object. The thread context classloader will be used to generate the 78 * proxy class. 79 * 80 * @param proxyFactory the {@link ProxyFactory} to use to create the proxy 81 * @param terminus the terminus 82 * @return an {@link ObjectProvider} which will return a proxy that sends method invocations through this 83 * chain of interceptors and ultimately arrive at the supplied terminus object 84 */ 85 public ObjectProvider createProxyProvider( ProxyFactory proxyFactory, Object terminus ) 86 { 87 return createProxyProvider( proxyFactory, terminus, null ); 88 } 89 90 /** 91 * Creates an {@link ObjectProvider} which will return a proxy that sends method invocations through this 92 * chain of interceptors and ultimately arrive at the supplied terminus object. The proxy will support only 93 * the specified interfaces/classes. The thread context classloader will be used to generate the 94 * proxy class. 95 * 96 * @param proxyFactory the {@link ProxyFactory} to use to create the proxy 97 * @param terminus the terminus 98 * @param proxyClasses the interfaces to support 99 * @return an {@link ObjectProvider} which will return a proxy that sends method invocations through this 100 * chain of interceptors and ultimately arrive at the supplied terminus object 101 */ 102 public ObjectProvider createProxyProvider( ProxyFactory proxyFactory, Object terminus, Class[] proxyClasses ) 103 { 104 return createProxyProvider( proxyFactory, Thread.currentThread().getContextClassLoader(), terminus, 105 proxyClasses ); 106 } 107 108 /** 109 * Creates an {@link ObjectProvider} which will return a proxy that sends method invocations through this 110 * chain of interceptors and ultimately arrive at the supplied terminus object. The proxy will support only 111 * the specified interfaces/classes. The specified classloader will be used to generate the 112 * proxy class. 113 * 114 * @param proxyFactory the {@link ProxyFactory} to use to create the proxy 115 * @param classLoader the classloader to be used to generate the proxy class 116 * @param terminus the terminus 117 * @param proxyClasses the interfaces to support 118 * @return an {@link ObjectProvider} which will return a proxy that sends method invocations through this 119 * chain of interceptors and ultimately arrive at the supplied terminus object 120 */ 121 public ObjectProvider createProxyProvider( ProxyFactory proxyFactory, ClassLoader classLoader, Object terminus, 122 Class[] proxyClasses ) 123 { 124 if( proxyClasses == null || proxyClasses.length == 0 ) 125 { 126 proxyClasses = ProxyUtils.getAllInterfaces( terminus.getClass() ); 127 } 128 return new ProxyObjectProvider( proxyFactory, classLoader, terminus, proxyClasses ); 129 } 130 131 //---------------------------------------------------------------------------------------------------------------------- 132 // Inner Classes 133 //---------------------------------------------------------------------------------------------------------------------- 134 135 private class ProxyObjectProvider implements ObjectProvider 136 { 137 private final ClassLoader classLoader; 138 private final Class[] proxyClasses; 139 private final Object terminus; 140 private final ProxyFactory proxyFactory; 141 142 public ProxyObjectProvider( ProxyFactory proxyFactory, ClassLoader classLoader, Object terminus, 143 Class[] proxyClasses ) 144 { 145 this.classLoader = classLoader; 146 this.proxyClasses = proxyClasses; 147 this.terminus = terminus; 148 this.proxyFactory = proxyFactory; 149 } 150 151 public Object getObject() 152 { 153 return createProxy( proxyFactory, classLoader, terminus, proxyClasses ); 154 } 155 } 156 } 157