001 package org.apache.fulcrum.yaafi.service.advice; 002 003 /* 004 * Licensed to the Apache Software Foundation (ASF) under one 005 * or more contributor license agreements. See the NOTICE file 006 * distributed with this work for additional information 007 * regarding copyright ownership. The ASF licenses this file 008 * to you under the Apache License, Version 2.0 (the 009 * "License"); you may not use this file except in compliance 010 * with the License. You may obtain a copy of the License at 011 * 012 * http://www.apache.org/licenses/LICENSE-2.0 013 * 014 * Unless required by applicable law or agreed to in writing, 015 * software distributed under the License is distributed on an 016 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 017 * KIND, either express or implied. See the License for the 018 * specific language governing permissions and limitations 019 * under the License. 020 */ 021 022 import java.lang.reflect.InvocationHandler; 023 import java.lang.reflect.Proxy; 024 025 import org.apache.avalon.framework.configuration.Configuration; 026 import org.apache.avalon.framework.configuration.ConfigurationException; 027 import org.apache.avalon.framework.configuration.Reconfigurable; 028 import org.apache.avalon.framework.context.Context; 029 import org.apache.avalon.framework.context.ContextException; 030 import org.apache.avalon.framework.context.Contextualizable; 031 import org.apache.avalon.framework.logger.AbstractLogEnabled; 032 import org.apache.avalon.framework.service.ServiceException; 033 import org.apache.avalon.framework.service.ServiceManager; 034 import org.apache.avalon.framework.service.Serviceable; 035 import org.apache.fulcrum.yaafi.framework.interceptor.AvalonInterceptorFactory; 036 import org.apache.fulcrum.yaafi.framework.interceptor.AvalonInterceptorInvocationHandler; 037 import org.apache.fulcrum.yaafi.framework.util.Validate; 038 039 /** 040 * Simple service providing interceptor advices for ordinary POJOs. Since the 041 * implementation uses Dynamic Proxies only methods invoked by an interface 042 * can be advised. 043 * 044 * @author <a href="mailto:siegfried.goeschl@it20one.at">Siegfried Goeschl</a> 045 */ 046 047 public class AdviceServiceImpl 048 extends AbstractLogEnabled 049 implements AdviceService, Serviceable, Contextualizable, Reconfigurable 050 { 051 /** the service manager supplied by the Avalon framework */ 052 private ServiceManager serviceManager; 053 054 /** the list of default interceptors */ 055 private String[] defaultInterceptorList; 056 057 ///////////////////////////////////////////////////////////////////////// 058 // Avalon Service Lifecycle Implementation 059 ///////////////////////////////////////////////////////////////////////// 060 061 /** 062 * @see org.apache.avalon.framework.service.Serviceable#service(org.apache.avalon.framework.service.ServiceManager) 063 */ 064 public void service(ServiceManager serviceManager) throws ServiceException 065 { 066 this.serviceManager = serviceManager; 067 } 068 069 /** 070 * @see org.apache.avalon.framework.context.Contextualizable#contextualize(org.apache.avalon.framework.context.Context) 071 */ 072 public void contextualize(Context context) throws ContextException 073 { 074 // nothing to do 075 } 076 077 /** 078 * @see org.apache.avalon.framework.configuration.Configurable#configure(org.apache.avalon.framework.configuration.Configuration) 079 */ 080 public void configure(Configuration configuration) throws ConfigurationException 081 { 082 Configuration[] interceptorConfigList = configuration.getChild("interceptors").getChildren("interceptor"); 083 this.defaultInterceptorList = new String[interceptorConfigList.length]; 084 085 for( int i=0; i<interceptorConfigList.length; i++ ) 086 { 087 this.defaultInterceptorList[i] = interceptorConfigList[i].getValue(); 088 } 089 } 090 091 /** 092 * @see org.apache.avalon.framework.configuration.Reconfigurable#reconfigure(org.apache.avalon.framework.configuration.Configuration) 093 */ 094 public void reconfigure(Configuration configuration) throws ConfigurationException 095 { 096 this.configure(configuration); 097 } 098 099 ///////////////////////////////////////////////////////////////////////// 100 // Service interface implementation 101 ///////////////////////////////////////////////////////////////////////// 102 103 /** 104 * @see org.apache.fulcrum.yaafi.service.advice.AdviceService#advice(java.lang.Object) 105 */ 106 public Object advice(Object object) 107 { 108 Validate.notNull(object,"object"); 109 return this.advice( this.getDefaultInterceptorList(), object ); 110 } 111 112 /** 113 * @see org.apache.fulcrum.yaafi.service.advice.AdviceService#advice(java.lang.String, java.lang.Object) 114 */ 115 public Object advice(String name, Object object) 116 { 117 Validate.notNull(object,"object"); 118 return this.doAdvice( name, this.getDefaultInterceptorList(), object ); 119 } 120 121 /** 122 * @see org.apache.fulcrum.yaafi.service.advice.AdviceService#advice(java.lang.String[], java.lang.Object) 123 */ 124 public Object advice(String [] interceptorList, Object object) 125 { 126 Validate.notNull(object,"object"); 127 String className = object.getClass().getName(); 128 return this.doAdvice(className, interceptorList, object); 129 } 130 131 /** 132 * @see org.apache.fulcrum.yaafi.service.advice.AdviceService#advice(java.lang.String, java.lang.String[], java.lang.Object) 133 */ 134 public Object advice(String name, String [] interceptorList, Object object ) 135 { 136 Validate.notNull(object,"object"); 137 return this.doAdvice(name, interceptorList, object); 138 } 139 140 /** 141 * @see org.apache.fulcrum.yaafi.service.advice.AdviceService#isAdviced(java.lang.Object) 142 */ 143 public boolean isAdviced(Object object) 144 { 145 InvocationHandler invocationHandler = null; 146 147 if ((object != null ) && Proxy.isProxyClass(object.getClass())) 148 { 149 invocationHandler = Proxy.getInvocationHandler(object); 150 return invocationHandler instanceof AvalonInterceptorInvocationHandler; 151 } 152 153 return false; 154 } 155 156 ///////////////////////////////////////////////////////////////////////// 157 // Service implementation 158 ///////////////////////////////////////////////////////////////////////// 159 160 /** 161 * Does the actual work of advising the object. 162 * 163 * @param name the name of the object to be advised 164 * @param interceptorList the list of interceptor services to advise the object 165 * @param object the object to be advised 166 * @return the advised object. 167 */ 168 protected Object doAdvice(String name, String [] interceptorList, Object object ) 169 { 170 Validate.notEmpty(name,"name"); 171 Validate.notNull(interceptorList,"interceptorList"); 172 Validate.notNull(object,"object"); 173 174 Object result = null; 175 String clazzName = object.getClass().getName(); 176 177 // do nothing if no interceptor services are requested 178 179 if( interceptorList.length == 0 ) 180 { 181 if( this.getLogger().isInfoEnabled() ) 182 { 183 String msg = "Skipping creation of dynamic proxy since no interceptors are requested : " + name; 184 this.getLogger().info(msg); 185 } 186 187 return object; 188 } 189 190 // skip creating a dynamic proxy if it is already advised 191 192 if( this.isAdviced(object) ) 193 { 194 if( this.getLogger().isInfoEnabled() ) 195 { 196 String msg = "Skipping creation of dynamic proxy since it is already advised : " + name; 197 this.getLogger().info(msg); 198 } 199 200 return object; 201 } 202 203 // create the advised object 204 205 try 206 { 207 result = AvalonInterceptorFactory.create( 208 clazzName, 209 name, 210 this.getServiceManager(), 211 interceptorList, 212 object 213 ); 214 } 215 catch (ServiceException e) 216 { 217 String msg = "Unable to advice the object : " + name; 218 this.getLogger().error(msg,e); 219 throw new IllegalArgumentException(msg); 220 } 221 222 return result; 223 } 224 225 /** 226 * @return Returns the serviceManager. 227 */ 228 private ServiceManager getServiceManager() 229 { 230 return serviceManager; 231 } 232 233 /** 234 * @return Returns the defaultInterceptorList. 235 */ 236 private String[] getDefaultInterceptorList() 237 { 238 return defaultInterceptorList; 239 } 240 }