001 /* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017 018 package org.apache.commons.proxy.interceptor; 019 020 import org.apache.commons.proxy.ObjectProvider; 021 import org.apache.commons.proxy.ProxyFactory; 022 import org.apache.commons.proxy.ProxyUtils; 023 import org.apache.commons.proxy.Interceptor; 024 025 /** 026 * An <code>InterceptorChain</code> assists with creating proxies which go through a series of 027 * {@link Interceptor interceptors}. 028 * 029 * <pre> 030 * MyServiceInterface serviceImpl = ...; 031 * ProxyFactory factory = ...; 032 * Interceptor[] interceptors = ...; 033 * InterceptorChain chain = new InterceptorChain(interceptors); 034 * ObjectProvider provider = chain.createProxyProvider(factory, serviceImpl); 035 * MyServiceInterface serviceProxy = ( MyServiceInterface )provider.getObject(); 036 * serviceProxy.someServiceMethod(...); // This will go through the interceptors! 037 * </pre> 038 * 039 * @author James Carman 040 * @since 1.0 041 */ 042 public class InterceptorChain 043 { 044 //---------------------------------------------------------------------------------------------------------------------- 045 // Fields 046 //---------------------------------------------------------------------------------------------------------------------- 047 private final Interceptor[] interceptors; 048 049 //---------------------------------------------------------------------------------------------------------------------- 050 // Constructors 051 //---------------------------------------------------------------------------------------------------------------------- 052 053 public InterceptorChain( Interceptor[] interceptors ) 054 { 055 this.interceptors = interceptors; 056 } 057 058 //---------------------------------------------------------------------------------------------------------------------- 059 // Other Methods 060 //---------------------------------------------------------------------------------------------------------------------- 061 062 private Object createProxy( ProxyFactory proxyFactory, ClassLoader classLoader, Object terminus, 063 Class[] proxyClasses ) 064 { 065 Object currentTarget = terminus; 066 for( int i = interceptors.length - 1; i >= 0; --i ) 067 { 068 currentTarget = proxyFactory 069 .createInterceptorProxy( classLoader, currentTarget, interceptors[i], proxyClasses ); 070 } 071 return currentTarget; 072 } 073 074 /** 075 * Creates an {@link ObjectProvider} which will return a proxy that sends method invocations through this 076 * chain of interceptors and ultimately arrive at the supplied terminus object. The proxy will support all 077 * interfaces implemented by the terminus object. The thread context classloader will be used to generate the 078 * proxy class. 079 * 080 * @param proxyFactory the {@link ProxyFactory} to use to create the proxy 081 * @param terminus the terminus 082 * @return an {@link ObjectProvider} which will return a proxy that sends method invocations through this 083 * chain of interceptors and ultimately arrive at the supplied terminus object 084 */ 085 public ObjectProvider createProxyProvider( ProxyFactory proxyFactory, Object terminus ) 086 { 087 return createProxyProvider( proxyFactory, terminus, null ); 088 } 089 090 /** 091 * Creates an {@link ObjectProvider} which will return a proxy that sends method invocations through this 092 * chain of interceptors and ultimately arrive at the supplied terminus object. The proxy will support only 093 * the specified interfaces/classes. The thread context classloader will be used to generate the 094 * proxy class. 095 * 096 * @param proxyFactory the {@link ProxyFactory} to use to create the proxy 097 * @param terminus the terminus 098 * @param proxyClasses the interfaces to support 099 * @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