001 // Copyright 2006 Howard M. Lewis Ship
002 //
003 // Licensed under the Apache License, Version 2.0 (the "License");
004 // you may not use this file except in compliance with the License.
005 // You may obtain a copy of the License at
006 //
007 // http://www.apache.org/licenses/LICENSE-2.0
008 //
009 // Unless required by applicable law or agreed to in writing, software
010 // distributed under the License is distributed on an "AS IS" BASIS,
011 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
012 // See the License for the specific language governing permissions and
013 // limitations under the License.
014
015 package com.javaforge.tapestry.spring;
016
017 import java.lang.reflect.Modifier;
018
019 import org.apache.hivemind.ApplicationRuntimeException;
020 import org.apache.hivemind.Location;
021 import org.apache.hivemind.service.BodyBuilder;
022 import org.apache.hivemind.service.MethodSignature;
023 import org.apache.hivemind.util.Defense;
024 import org.apache.tapestry.enhance.EnhancementOperation;
025 import org.apache.tapestry.enhance.InjectEnhancementWorker;
026 import org.apache.tapestry.spec.InjectSpecification;
027 import org.springframework.beans.factory.BeanFactory;
028
029 /**
030 * Injects a spring bean into a Tapestry page or component. This is done a bit differently than
031 * injecting a HiveMind service. With HiveMind, a proxy can be obtained and injected, and the
032 * HiveMind proxy will encapsulate the lifecycle of the underlying service (the client doesn't have
033 * to be aware of when the service is instantiated, or what is lifecycle is). Spring is a bit
034 * different, for beans with the prototype lifecycle, it is necessary to keep re-acquiring them.
035 * This form of injection, "spring" injection, does just that; the implementation of the property
036 * getter method will go to the default Spring BeanFactory at ask for each bean; no caching of
037 * Spring beans occurs.
038 *
039 * @author Howard M. Lewis Ship
040 */
041 public final class SpringBeanInjectionWorker implements InjectEnhancementWorker
042 {
043
044 private BeanFactory _beanFactory;
045
046 public void performEnhancement(EnhancementOperation op, InjectSpecification is)
047 {
048 String propertyName = is.getProperty();
049 String objectReference = is.getObject();
050 Location location = is.getLocation();
051
052 injectSpringBean(op, objectReference, propertyName, location);
053 }
054
055 private void injectSpringBean(EnhancementOperation op, String beanName, String propertyName,
056 Location location)
057 {
058 Defense.notNull(op, "op");
059 Defense.notNull(beanName, "beanName");
060 Defense.notNull(propertyName, "propertyName");
061
062 Class propertyType = op.getPropertyType(propertyName);
063
064 // In case there's just the <inject> in the XML and no property in
065 // the Java class
066
067 if (propertyType == null)
068 propertyType = Object.class;
069
070 Class beanType = _beanFactory.getType(beanName);
071
072 if (!propertyType.isAssignableFrom(beanType))
073 throw new ApplicationRuntimeException(SpringMessages.beanTypeNotCompatibleWithProperty(
074 beanName,
075 propertyName,
076 propertyType), location, null);
077
078 op.claimReadonlyProperty(propertyName);
079
080 // Inject the bean factory into the component class
081
082 String beanFactoryName = op.addInjectedField(
083 "_$beanFactory",
084 BeanFactory.class,
085 _beanFactory);
086 String locationName = op.addInjectedField("_$location", Location.class, location);
087
088 BodyBuilder builder = new BodyBuilder();
089
090 builder.begin();
091 builder.addln("try");
092 builder.begin();
093 builder.addln(
094 "return ({0}) {1}.getBean(\"{2}\");",
095 propertyType.getName(),
096 beanFactoryName,
097 beanName);
098 builder.end();
099 builder.addln("catch (Exception ex)");
100 builder.begin();
101 builder.addln("throw new {0}(ex.getMessage(), {1}, ex);", ApplicationRuntimeException.class
102 .getName(), locationName);
103 builder.end();
104 builder.end();
105
106 String methodName = op.getAccessorMethodName(propertyName);
107
108 MethodSignature sig = new MethodSignature(propertyType, methodName, null, null);
109
110 op.addMethod(Modifier.PUBLIC, sig, builder.toString(), location);
111 }
112
113 /** For injection. */
114 public void setBeanFactory(BeanFactory beanFactory)
115 {
116 _beanFactory = beanFactory;
117 }
118
119 }