|
|||||||||||||||||||
30 day Evaluation Version distributed via the Maven Jar Repository. Clover is not free. You have 30 days to evaluate it. Please visit http://www.thecortex.net/clover to obtain a licensed version of Clover | |||||||||||||||||||
Source file | Conditionals | Statements | Methods | TOTAL | |||||||||||||||
BeanProvider.java | 78.9% | 85.9% | 90% | 84% |
|
1 |
// Copyright 2004, 2005 The Apache Software Foundation
|
|
2 |
//
|
|
3 |
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
4 |
// you may not use this file except in compliance with the License.
|
|
5 |
// You may obtain a copy of the License at
|
|
6 |
//
|
|
7 |
// http://www.apache.org/licenses/LICENSE-2.0
|
|
8 |
//
|
|
9 |
// Unless required by applicable law or agreed to in writing, software
|
|
10 |
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
11 |
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12 |
// See the License for the specific language governing permissions and
|
|
13 |
// limitations under the License.
|
|
14 |
|
|
15 |
package org.apache.tapestry.bean;
|
|
16 |
|
|
17 |
import java.util.Collection;
|
|
18 |
import java.util.Collections;
|
|
19 |
import java.util.HashMap;
|
|
20 |
import java.util.HashSet;
|
|
21 |
import java.util.Iterator;
|
|
22 |
import java.util.List;
|
|
23 |
import java.util.Map;
|
|
24 |
import java.util.Set;
|
|
25 |
|
|
26 |
import org.apache.commons.logging.Log;
|
|
27 |
import org.apache.commons.logging.LogFactory;
|
|
28 |
import org.apache.hivemind.ApplicationRuntimeException;
|
|
29 |
import org.apache.hivemind.ClassResolver;
|
|
30 |
import org.apache.tapestry.IBeanProvider;
|
|
31 |
import org.apache.tapestry.IComponent;
|
|
32 |
import org.apache.tapestry.IEngine;
|
|
33 |
import org.apache.tapestry.Tapestry;
|
|
34 |
import org.apache.tapestry.event.PageDetachListener;
|
|
35 |
import org.apache.tapestry.event.PageEndRenderListener;
|
|
36 |
import org.apache.tapestry.event.PageEvent;
|
|
37 |
import org.apache.tapestry.spec.BeanLifecycle;
|
|
38 |
import org.apache.tapestry.spec.IBeanSpecification;
|
|
39 |
import org.apache.tapestry.spec.IComponentSpecification;
|
|
40 |
|
|
41 |
/**
|
|
42 |
* Basic implementation of the {@link IBeanProvider}interface.
|
|
43 |
*
|
|
44 |
* @author Howard Lewis Ship
|
|
45 |
* @since 1.0.4
|
|
46 |
*/
|
|
47 |
|
|
48 |
public class BeanProvider implements IBeanProvider, PageDetachListener, PageEndRenderListener |
|
49 |
{ |
|
50 |
private static final Log LOG = LogFactory.getLog(BeanProvider.class); |
|
51 |
|
|
52 |
/**
|
|
53 |
* Indicates whether this instance has been registered with its page as a PageDetachListener.
|
|
54 |
* Registration only occurs the first time a bean with lifecycle REQUEST is instantiated.
|
|
55 |
*/
|
|
56 |
|
|
57 |
private boolean _registeredForDetach = false; |
|
58 |
|
|
59 |
/**
|
|
60 |
* Indicates whether this instance has been registered as a render listener with the page.
|
|
61 |
*/
|
|
62 |
|
|
63 |
private boolean _registeredForRender = false; |
|
64 |
|
|
65 |
/**
|
|
66 |
* The component for which beans are being created and tracked.
|
|
67 |
*/
|
|
68 |
|
|
69 |
private IComponent _component;
|
|
70 |
|
|
71 |
/**
|
|
72 |
* Used for instantiating classes.
|
|
73 |
*/
|
|
74 |
|
|
75 |
private ClassResolver _resolver;
|
|
76 |
|
|
77 |
/**
|
|
78 |
* Map of beans, keyed on name.
|
|
79 |
*/
|
|
80 |
|
|
81 |
private Map _beans;
|
|
82 |
|
|
83 |
/**
|
|
84 |
* Set of bean names provided by this provider.
|
|
85 |
*
|
|
86 |
* @since 2.2
|
|
87 |
*/
|
|
88 |
|
|
89 |
private Set _beanNames;
|
|
90 |
|
|
91 | 55 |
public BeanProvider(IComponent component)
|
92 |
{ |
|
93 | 55 |
this._component = component;
|
94 | 55 |
IEngine engine = component.getPage().getEngine(); |
95 | 55 |
_resolver = engine.getClassResolver(); |
96 |
|
|
97 | 55 |
if (LOG.isDebugEnabled())
|
98 | 0 |
LOG.debug("Created BeanProvider for " + component);
|
99 |
|
|
100 |
} |
|
101 |
|
|
102 |
/** @since 1.0.6 * */
|
|
103 |
|
|
104 | 73 |
public Collection getBeanNames()
|
105 |
{ |
|
106 | 73 |
if (_beanNames == null) |
107 |
{ |
|
108 | 22 |
Collection c = _component.getSpecification().getBeanNames(); |
109 |
|
|
110 | 22 |
if (c == null || c.isEmpty()) |
111 | 0 |
_beanNames = Collections.EMPTY_SET; |
112 |
else
|
|
113 | 22 |
_beanNames = Collections.unmodifiableSet(new HashSet(c));
|
114 |
} |
|
115 |
|
|
116 | 73 |
return _beanNames;
|
117 |
} |
|
118 |
|
|
119 |
/**
|
|
120 |
* @since 1.0.5
|
|
121 |
*/
|
|
122 |
|
|
123 | 8 |
public IComponent getComponent()
|
124 |
{ |
|
125 | 8 |
return _component;
|
126 |
} |
|
127 |
|
|
128 | 142 |
public Object getBean(String name)
|
129 |
{ |
|
130 | 142 |
Object bean = null;
|
131 |
|
|
132 | 142 |
if (_beans != null) |
133 | 87 |
bean = _beans.get(name); |
134 |
|
|
135 | 142 |
if (bean != null) |
136 | 73 |
return bean;
|
137 |
|
|
138 | 69 |
IBeanSpecification spec = _component.getSpecification().getBeanSpecification(name); |
139 |
|
|
140 | 69 |
if (spec == null) |
141 | 0 |
throw new ApplicationRuntimeException(Tapestry.format( |
142 |
"BeanProvider.bean-not-defined",
|
|
143 |
_component.getExtendedId(), |
|
144 |
name)); |
|
145 |
|
|
146 | 69 |
bean = instantiateBean(name, spec); |
147 |
|
|
148 | 69 |
BeanLifecycle lifecycle = spec.getLifecycle(); |
149 |
|
|
150 | 69 |
if (lifecycle == BeanLifecycle.NONE)
|
151 | 0 |
return bean;
|
152 |
|
|
153 | 69 |
if (_beans == null) |
154 | 55 |
_beans = new HashMap();
|
155 |
|
|
156 | 69 |
_beans.put(name, bean); |
157 |
|
|
158 |
// The first time in a request that a REQUEST lifecycle bean is created,
|
|
159 |
// register with the page to be notified at the end of the
|
|
160 |
// request cycle.
|
|
161 |
|
|
162 | 69 |
if (lifecycle == BeanLifecycle.REQUEST && !_registeredForDetach)
|
163 |
{ |
|
164 | 54 |
_component.getPage().addPageDetachListener(this);
|
165 | 54 |
_registeredForDetach = true;
|
166 |
} |
|
167 |
|
|
168 | 69 |
if (lifecycle == BeanLifecycle.RENDER && !_registeredForRender)
|
169 |
{ |
|
170 | 1 |
_component.getPage().addPageEndRenderListener(this);
|
171 | 1 |
_registeredForRender = true;
|
172 |
} |
|
173 |
|
|
174 |
// No need to register if a PAGE lifecycle bean; those can stick around
|
|
175 |
// forever.
|
|
176 |
|
|
177 | 69 |
return bean;
|
178 |
} |
|
179 |
|
|
180 | 69 |
private Object instantiateBean(String beanName, IBeanSpecification spec)
|
181 |
{ |
|
182 | 69 |
String className = spec.getClassName(); |
183 | 69 |
Object bean = null;
|
184 |
|
|
185 | 69 |
if (LOG.isDebugEnabled())
|
186 | 0 |
LOG.debug("Instantiating instance of " + className);
|
187 |
|
|
188 |
// Do it the hard way!
|
|
189 |
|
|
190 | 69 |
try
|
191 |
{ |
|
192 | 69 |
Class beanClass = _resolver.findClass(className); |
193 |
|
|
194 | 69 |
bean = beanClass.newInstance(); |
195 |
} |
|
196 |
catch (Exception ex)
|
|
197 |
{ |
|
198 |
|
|
199 | 0 |
throw new ApplicationRuntimeException(Tapestry.format( |
200 |
"BeanProvider.instantiation-error",
|
|
201 |
new Object[]
|
|
202 |
{ beanName, _component.getExtendedId(), className, ex.getMessage() }), spec |
|
203 |
.getLocation(), ex); |
|
204 |
} |
|
205 |
|
|
206 |
// OK, have the bean, have to initialize it.
|
|
207 |
|
|
208 | 69 |
List initializers = spec.getInitializers(); |
209 |
|
|
210 | 69 |
if (initializers == null) |
211 | 66 |
return bean;
|
212 |
|
|
213 | 3 |
Iterator i = initializers.iterator(); |
214 | 3 |
while (i.hasNext())
|
215 |
{ |
|
216 | 8 |
IBeanInitializer iz = (IBeanInitializer) i.next(); |
217 |
|
|
218 | 8 |
if (LOG.isDebugEnabled())
|
219 | 0 |
LOG.debug("Initializing property " + iz.getPropertyName());
|
220 |
|
|
221 | 8 |
iz.setBeanProperty(this, bean);
|
222 |
} |
|
223 |
|
|
224 | 3 |
return bean;
|
225 |
} |
|
226 |
|
|
227 |
/**
|
|
228 |
* Removes all beans with the REQUEST lifecycle. Beans with the PAGE lifecycle stick around, and
|
|
229 |
* beans with no lifecycle were never stored in the first place.
|
|
230 |
*/
|
|
231 |
|
|
232 | 114 |
public void pageDetached(PageEvent event) |
233 |
{ |
|
234 | 114 |
removeBeans(BeanLifecycle.REQUEST); |
235 |
} |
|
236 |
|
|
237 |
/**
|
|
238 |
* Removes any beans with the specified lifecycle.
|
|
239 |
*
|
|
240 |
* @since 2.2
|
|
241 |
*/
|
|
242 |
|
|
243 | 115 |
private void removeBeans(BeanLifecycle lifecycle) |
244 |
{ |
|
245 | 115 |
if (_beans == null) |
246 | 0 |
return;
|
247 |
|
|
248 | 115 |
IComponentSpecification spec = null;
|
249 |
|
|
250 | 115 |
Iterator i = _beans.entrySet().iterator(); |
251 | 115 |
while (i.hasNext())
|
252 |
{ |
|
253 | 69 |
Map.Entry e = (Map.Entry) i.next(); |
254 | 69 |
String name = (String) e.getKey(); |
255 |
|
|
256 | 69 |
if (spec == null) |
257 | 62 |
spec = _component.getSpecification(); |
258 |
|
|
259 | 69 |
IBeanSpecification s = spec.getBeanSpecification(name); |
260 |
|
|
261 | 69 |
if (s.getLifecycle() == lifecycle)
|
262 |
{ |
|
263 | 65 |
Object bean = e.getValue(); |
264 |
|
|
265 | 65 |
if (LOG.isDebugEnabled())
|
266 | 0 |
LOG.debug("Removing " + lifecycle.getName() + " bean " + name + ": " + bean); |
267 |
|
|
268 | 65 |
i.remove(); |
269 |
} |
|
270 |
} |
|
271 |
} |
|
272 |
|
|
273 |
/** @since 1.0.8 * */
|
|
274 |
|
|
275 | 0 |
public ClassResolver getClassResolver()
|
276 |
{ |
|
277 | 0 |
return _resolver;
|
278 |
} |
|
279 |
|
|
280 |
/** @since 2.2 * */
|
|
281 |
|
|
282 | 1 |
public void pageEndRender(PageEvent event) |
283 |
{ |
|
284 | 1 |
removeBeans(BeanLifecycle.RENDER); |
285 |
} |
|
286 |
|
|
287 |
/** @since 2.2 * */
|
|
288 |
|
|
289 | 73 |
public boolean canProvideBean(String name) |
290 |
{ |
|
291 | 73 |
return getBeanNames().contains(name);
|
292 |
} |
|
293 |
|
|
294 |
} |
|