001: /*
002: * Copyright (c) 1998-2008 Caucho Technology -- all rights reserved
003: *
004: * This file is part of Resin(R) Open Source
005: *
006: * Each copy or derived work must preserve the copyright notice and this
007: * notice unmodified.
008: *
009: * Resin Open Source is free software; you can redistribute it and/or modify
010: * it under the terms of the GNU General Public License as published by
011: * the Free Software Foundation; either version 2 of the License, or
012: * (at your option) any later version.
013: *
014: * Resin Open Source is distributed in the hope that it will be useful,
015: * but WITHOUT ANY WARRANTY; without even the implied warranty of
016: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
017: * of NON-INFRINGEMENT. See the GNU General Public License for more
018: * details.
019: *
020: * You should have received a copy of the GNU General Public License
021: * along with Resin Open Source; if not, write to the
022: *
023: * Free Software Foundation, Inc.
024: * 59 Temple Place, Suite 330
025: * Boston, MA 02111-1307 USA
026: *
027: * @author Scott Ferguson
028: */
029:
030: package com.caucho.webbeans.component;
031:
032: import com.caucho.config.program.FieldComponentProgram;
033: import com.caucho.config.*;
034: import com.caucho.config.j2ee.*;
035: import com.caucho.config.program.ConfigProgram;
036: import com.caucho.config.program.ContainerProgram;
037: import com.caucho.config.types.*;
038: import com.caucho.naming.*;
039: import com.caucho.util.*;
040: import com.caucho.webbeans.*;
041: import com.caucho.webbeans.bytecode.*;
042: import com.caucho.webbeans.cfg.*;
043: import com.caucho.webbeans.context.*;
044:
045: import java.lang.reflect.*;
046: import java.lang.annotation.*;
047: import java.util.*;
048:
049: import javax.annotation.*;
050: import javax.webbeans.*;
051:
052: /**
053: * Configuration for the xml web bean component.
054: */
055: public class ComponentImpl implements ComponentFactory, ObjectProxy {
056: private static final L10N L = new L10N(ComponentImpl.class);
057:
058: private static final Object[] NULL_ARGS = new Object[0];
059: private static final ConfigProgram[] NULL_INJECT = new ConfigProgram[0];
060:
061: protected WbWebBeans _webbeans;
062:
063: private WbComponentType _type;
064:
065: private Type _targetType;
066:
067: private boolean _isFromClass;
068:
069: private String _name;
070:
071: private boolean _hasBinding;
072:
073: private ArrayList<WbBinding> _bindingList = new ArrayList<WbBinding>();
074:
075: private WebBeansHandle _handle;
076:
077: protected ScopeContext _scope;
078: private String _scopeId;
079:
080: protected ConfigProgram[] _injectProgram = NULL_INJECT;
081: protected ConfigProgram[] _initProgram = NULL_INJECT;
082: protected ConfigProgram[] _destroyProgram = NULL_INJECT;
083:
084: private ContainerProgram _init;
085:
086: public ComponentImpl(WbWebBeans webbeans) {
087: _webbeans = webbeans;
088: }
089:
090: public WbWebBeans getWebBeans() {
091: return _webbeans;
092: }
093:
094: /**
095: * Returns the component's EL binding name.
096: */
097: public void setName(String name) {
098: _name = name;
099: }
100:
101: /**
102: * Gets the component's EL binding name.
103: */
104: public String getName() {
105: return _name;
106: }
107:
108: public void addNameBinding(String name) {
109: WbBinding binding = new WbBinding();
110: binding.setClass(Named.class);
111: binding.addValue("value", name);
112:
113: _bindingList.add(binding);
114: }
115:
116: /**
117: * Gets the component type.
118: */
119: public WbComponentType getType() {
120: return _type;
121: }
122:
123: /**
124: * Sets the component type.
125: */
126: public void setType(WbComponentType type) {
127: if (type == null)
128: throw new NullPointerException();
129:
130: _type = type;
131: }
132:
133: public void setTargetType(Type type) {
134: _targetType = type;
135: }
136:
137: public Type getTargetType() {
138: return _targetType;
139: }
140:
141: public String getTargetSimpleName() {
142: if (_targetType instanceof Class)
143: return ((Class) _targetType).getSimpleName();
144: else
145: return String.valueOf(_targetType);
146: }
147:
148: public Class getTargetClass() {
149: if (_targetType instanceof Class)
150: return ((Class) _targetType);
151: else if (_targetType instanceof ParameterizedType)
152: return (Class) ((ParameterizedType) _targetType)
153: .getRawType();
154: else
155: return (Class) _targetType;
156: }
157:
158: public String getClassName() {
159: if (_targetType instanceof Class)
160: return ((Class) _targetType).getName();
161: else
162: return String.valueOf(_targetType);
163: }
164:
165: /**
166: * Adds a component binding.
167: */
168: public void setBindingList(ArrayList<WbBinding> bindingList) {
169: _bindingList = bindingList;
170: }
171:
172: public ArrayList<WbBinding> getBindingList() {
173: return _bindingList;
174: }
175:
176: /**
177: * Sets the scope annotation.
178: */
179: public void setScope(ScopeContext scope) {
180: _scope = scope;
181: }
182:
183: /**
184: * Gets the scope annotation.
185: */
186: public ScopeContext getScope() {
187: return _scope;
188: }
189:
190: public boolean isSingleton() {
191: return (_scope instanceof SingletonScope || _scope instanceof ApplicationScope);
192: }
193:
194: /**
195: * Sets the init program.
196: */
197: public void setInit(ContainerProgram init) {
198: _init = init;
199: }
200:
201: /**
202: * Add to the init program.
203: */
204: public void addProgram(ConfigProgram program) {
205: if (_init == null)
206: _init = new ContainerProgram();
207:
208: _init.addProgram(program);
209: }
210:
211: /**
212: * True if the component was defined by class introspection.
213: */
214: public void setFromClass(boolean isFromClass) {
215: _isFromClass = isFromClass;
216: }
217:
218: /**
219: * True if the component was defined by class introspection.
220: */
221: public boolean isFromClass() {
222: return _isFromClass;
223: }
224:
225: /**
226: * Returns the serialization handle
227: */
228: public WebBeansHandle getHandle() {
229: return _handle;
230: }
231:
232: /**
233: * Initialization.
234: */
235: public void init() {
236: introspect();
237:
238: if (_type == null)
239: _type = _webbeans.createComponentType(Component.class);
240:
241: generateScopeId();
242:
243: _handle = new WebBeansHandle(_targetType, _bindingList);
244: }
245:
246: protected void introspect() {
247: }
248:
249: private void generateScopeId() {
250: long crc64 = 17;
251:
252: crc64 = Crc64.generate(crc64, String.valueOf(_targetType));
253:
254: if (_name != null)
255: crc64 = Crc64.generate(crc64, _name);
256:
257: for (WbBinding binding : _bindingList) {
258: crc64 = binding.generateCrc64(crc64);
259: }
260:
261: StringBuilder sb = new StringBuilder();
262: Base64.encode(sb, crc64);
263:
264: _scopeId = sb.toString();
265: }
266:
267: /**
268: * Called for implicit introspection.
269: */
270: protected void introspectScope(Class type) {
271: Class scopeClass = null;
272:
273: if (getScope() == null) {
274: for (Annotation ann : type.getDeclaredAnnotations()) {
275: if (ann.annotationType().isAnnotationPresent(
276: ScopeType.class)) {
277: if (scopeClass != null)
278: throw new ConfigException(
279: L
280: .l(
281: "{0}: @ScopeType annotation @{1} conflicts with @{2}. WebBeans components may only have a single @ScopeType.",
282: type.getName(),
283: scopeClass.getName(),
284: ann.annotationType()
285: .getName()));
286:
287: scopeClass = ann.annotationType();
288: setScope(_webbeans.getScopeContext(scopeClass));
289: }
290: }
291: }
292: }
293:
294: /**
295: * Introspects the methods for any @Produces
296: */
297: protected void introspectBindings() {
298: }
299:
300: public boolean isMatch(ArrayList<Annotation> bindList) {
301: for (int i = 0; i < bindList.size(); i++) {
302: if (!isMatch(bindList.get(i)))
303: return false;
304: }
305:
306: return true;
307: }
308:
309: /**
310: * Returns true if at least one of this component's bindings match
311: * the injection binding.
312: */
313: public boolean isMatch(Annotation bindAnn) {
314: for (int i = 0; i < _bindingList.size(); i++) {
315: if (_bindingList.get(i).isMatch(bindAnn))
316: return true;
317: }
318:
319: return false;
320: }
321:
322: public boolean isMatchByBinding(ArrayList<Binding> bindList) {
323: for (int i = 0; i < bindList.size(); i++) {
324: if (!isMatchByBinding(bindList.get(i)))
325: return false;
326: }
327:
328: return true;
329: }
330:
331: /**
332: * Returns true if at least one of this component's bindings match
333: * the injection binding.
334: */
335: public boolean isMatchByBinding(Binding binding) {
336: for (int i = 0; i < _bindingList.size(); i++) {
337: if (_bindingList.get(i).isMatch(binding))
338: return true;
339: }
340:
341: return false;
342: }
343:
344: /**
345: * Returns the component object if it already exists
346: */
347: public Object getIfExists() {
348: if (_scope != null)
349: return _scope.get(this , false);
350: else
351: return get();
352: }
353:
354: /**
355: * Returns the component object, creating if necessary
356: */
357: public Object get() {
358: if (_scope != null) {
359: Object value = _scope.get(this , false);
360:
361: if (value != null) {
362: return value;
363: }
364: }
365:
366: return create();
367: }
368:
369: public Object get(ConfigContext env) {
370: if (_scope != null) {
371: Object value = _scope.get(this , false);
372:
373: if (value != null)
374: return value;
375: } else {
376: Object value = env.get(this );
377:
378: if (value != null)
379: return value;
380: }
381:
382: Object value;
383:
384: if (_scope != null) {
385: value = createNew(null);
386: _scope.put(this , value);
387: env = new ConfigContext(this , value, _scope);
388: } else {
389: value = createNew(env);
390: }
391:
392: init(value, env);
393:
394: return value;
395: }
396:
397: /**
398: * Creates a new instance of the component.
399: */
400: public Object create() {
401: try {
402: ConfigContext env = new ConfigContext(_scope);
403:
404: Object value = createNew(env);
405:
406: env.put(this , value);
407:
408: if (_scope != null)
409: _scope.put(this , value);
410:
411: init(value, env);
412:
413: return value;
414: } catch (RuntimeException e) {
415: throw e;
416: } catch (Exception e) {
417: throw new RuntimeException(e);
418: }
419: }
420:
421: /**
422: * Creates a new instance of the component.
423: */
424: public Object createNoInit() {
425: try {
426: Object value = createNew(null);
427:
428: if (_injectProgram.length > 0) {
429: ConfigContext env = new ConfigContext(this , value, null);
430:
431: for (ConfigProgram program : _injectProgram) {
432: program.inject(value, env);
433: }
434: }
435:
436: return value;
437: } catch (RuntimeException e) {
438: throw e;
439: } catch (Exception e) {
440: throw new RuntimeException(e);
441: }
442: }
443:
444: /**
445: * Creates a new instance of the component
446: *
447: * @param env the configuration environment
448: * @return the new object
449: */
450: protected Object createNew(ConfigContext env) {
451: throw new UnsupportedOperationException(getClass().getName());
452: }
453:
454: /**
455: * Initialize the created value
456: */
457: protected Object init(Object value, ConfigContext env) {
458: if (_init != null)
459: _init.inject(value, env);
460:
461: for (ConfigProgram inject : _injectProgram) {
462: inject.inject(value, env);
463: }
464:
465: for (ConfigProgram inject : _initProgram) {
466: inject.inject(value, env);
467: }
468:
469: if (_destroyProgram.length > 0) {
470: env.addDestructor(this , value);
471: }
472:
473: return value;
474: }
475:
476: /**
477: * Returns true if there's a destroy program.
478: */
479: public boolean isDestroyPresent() {
480: return _destroyProgram.length > 0;
481: }
482:
483: /**
484: * Destroys the value
485: */
486: public void destroy(Object value, ConfigContext env) {
487: for (ConfigProgram inject : _destroyProgram)
488: inject.inject(value, env);
489: }
490:
491: /**
492: * Destroys the value
493: */
494: public void destroy(Object value) {
495: destroy(value, null);
496: }
497:
498: /**
499: * Binds parameters
500: */
501: public void bind() {
502: }
503:
504: public void createProgram(ArrayList<ConfigProgram> initList,
505: Field field) throws ConfigException {
506: initList.add(new FieldComponentProgram(this , field));
507: }
508:
509: public String getScopeId() {
510: return _scopeId;
511: }
512:
513: //
514: // ObjectProxy
515: //
516:
517: /**
518: * Returns the new object for JNDI
519: */
520: public Object createObject(Hashtable env) {
521: return get();
522: }
523:
524: protected ConfigException error(Method method, String msg) {
525: return new ConfigException(LineConfigException.loc(method)
526: + msg);
527: }
528:
529: public boolean equals(Object obj) {
530: if (this == obj)
531: return true;
532: else if (!(obj instanceof ComponentImpl))
533: return false;
534:
535: ComponentImpl comp = (ComponentImpl) obj;
536:
537: if (!_targetType.equals(comp._targetType)) {
538: return false;
539: }
540:
541: int size = _bindingList.size();
542:
543: if (size != comp._bindingList.size()) {
544: return false;
545: }
546:
547: for (int i = size - 1; i >= 0; i--) {
548: if (!comp._bindingList.contains(_bindingList.get(i))) {
549: return false;
550: }
551: }
552:
553: return true;
554: }
555:
556: public String toDebugString() {
557: StringBuilder sb = new StringBuilder();
558:
559: if (_targetType instanceof Class)
560: sb.append(((Class) _targetType).getSimpleName());
561: else
562: sb.append(String.valueOf(_targetType));
563: sb.append("[");
564:
565: for (WbBinding binding : _bindingList) {
566: sb.append(binding.toDebugString());
567: sb.append(",");
568: }
569:
570: if (_type != null) {
571: sb.append("@");
572: sb.append(_type.getType().getSimpleName());
573: } else
574: sb.append("@null");
575:
576: if (_scope != null) {
577: sb.append(", @");
578: sb.append(_scope.getClass().getSimpleName());
579: }
580:
581: if (_name != null) {
582: sb.append(", name=");
583: sb.append(_name);
584: }
585:
586: sb.append("]");
587:
588: return sb.toString();
589: }
590:
591: public String toString() {
592: StringBuilder sb = new StringBuilder();
593:
594: sb.append(getClass().getSimpleName());
595: sb.append("[");
596:
597: if (_targetType instanceof Class)
598: sb.append(((Class) _targetType).getSimpleName());
599: else
600: sb.append(String.valueOf(_targetType));
601: sb.append(", ");
602:
603: if (_type != null) {
604: sb.append("@");
605: sb.append(_type.getType().getSimpleName());
606: } else
607: sb.append("@null");
608:
609: if (_name != null) {
610: sb.append(", ");
611: sb.append("name=");
612: sb.append(_name);
613: }
614:
615: if (_scope != null) {
616: sb.append(", @");
617: sb.append(_scope.getClass().getSimpleName());
618: }
619:
620: sb.append("]");
621:
622: return sb.toString();
623: }
624:
625: protected static String getSimpleName(Type type) {
626: if (type instanceof Class)
627: return ((Class) type).getSimpleName();
628: else
629: return String.valueOf(type);
630: }
631: }
|