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 }