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    }