1 /*
2 * EL4J, the Extension Library for the J2EE, adds incremental enhancements to
3 * the spring framework, http://el4j.sf.net
4 * Copyright (C) 2005 by ELCA Informatique SA, Av. de la Harpe 22-24,
5 * 1000 Lausanne, Switzerland, http://www.elca.ch
6 *
7 * EL4J is published under the GNU Lesser General Public License (LGPL)
8 * Version 2.1. See http://www.gnu.org/licenses/
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU Lesser General Public License for more details.
14 *
15 * For alternative licensing, please contact info@elca.ch
16 */
17 package ch.elca.el4j.util.objectwrapper;
18
19 import java.util.HashMap;
20 import java.util.Map;
21
22 import ch.elca.el4j.util.objectwrapper.impl.AbstractWrapper;
23
24 /**
25 * Main class of the object wrapper package. The purpose of this package is to treat objects of different classes
26 * as if they implemented exactly the utility interfaces we want to use. This prevents us from having to include the
27 * interfaces in every domain class.
28 * <p>
29 * For example, Keyed is an interface indicating an object has a key. But domain classes may have keys without
30 * implementing the keyed interface. As long as we have an algorithm to get/set keys on an object,
31 * we can pretend it does actually implement Keyed.
32 * <p>
33 * All methods and the interfaces they create throw ObjectWrapperRTException if an object does not have the interface we
34 * want and we cannot emulate it either. As it is a RuntimeException it is not
35 * always declared; getting such an exception is under most circumstances non-recoverable anyway.
36 *
37 * @svnLink $Revision: 4083 $;$Date: 2010-01-08 13:32:17 +0100 (Fr, 08. Jan 2010) $;$Author: jonasha $;$URL: https://el4j.svn.sourceforge.net/svnroot/el4j/branches/el4j_3_1/el4j/framework/modules/hibernate/src/main/java/ch/elca/el4j/util/objectwrapper/ObjectWrapper.java $
38 *
39 * @author David Bernhard (DBD)
40 */
41 public class ObjectWrapper {
42
43 /**
44 * All known wrappers, created as map Wrappable->Implementation.
45 */
46 private Map<Class<? extends Wrappable>, AbstractWrapper> m_wrappables;
47
48 /**
49 * Set up the apsects object.
50 */
51 public ObjectWrapper() {
52 m_wrappables = new HashMap<Class<? extends Wrappable>, AbstractWrapper>();
53 }
54
55 /**
56 * Get the wrappables.
57 * @return The wrappables.
58 */
59 public Map<Class<? extends Wrappable>, AbstractWrapper> getWrappables() {
60 return m_wrappables;
61 }
62
63 /**
64 * Setter for wrappabless.
65 * @param wrappables The new wrappables to set.
66 */
67 public void setWrappables(Map<Class<? extends Wrappable>, AbstractWrapper> wrappables) {
68 m_wrappables = wrappables;
69 }
70
71 /**
72 * Register a wrappable.
73 * @param wrappableClass The wrappable class to register.
74 * @param implementation The implementation.
75 */
76 public void addWrappable(Class<? extends Wrappable> wrappableClass, AbstractWrapper implementation) {
77 m_wrappables.put(wrappableClass, implementation);
78 }
79
80 /**
81 * Cast an object to a wrapper.
82 * @param <T> The type parameter. (This eliminates a cast of the return value.)
83 * @param wrappable The wrappable to cast the object to.
84 * @param object the object.
85 * @return The wrapped object.
86 */
87 public <T extends Wrappable> T wrap(Class<T> wrappable, Object object) {
88 // If the object in question already implements this interface, just return it.
89
90 if (wrappable.isAssignableFrom(object.getClass())) {
91 // Safe because we've just checked it against the class object.
92 @SuppressWarnings("unchecked")
93 T cast = (T) object;
94 return cast;
95 }
96
97
98 AbstractWrapper impl = null;
99 for (Class<? extends Wrappable> candidate : m_wrappables.keySet()) {
100 if (candidate == wrappable) {
101 impl = m_wrappables.get(candidate);
102 }
103 }
104 if (impl == null) {
105 throw new IllegalArgumentException("Wrappable " + wrappable + " is not registered.");
106 }
107
108 try {
109 impl = (AbstractWrapper) impl.clone();
110 } catch (CloneNotSupportedException e) {
111 throw new ObjectWrapperRTException("Clone on wrappable failed.", e);
112 }
113
114 impl.setTarget(object);
115 impl.setWrapper(this);
116 try {
117 impl.create();
118 } catch (ObjectWrapperRTException ex) {
119 // Provide a standard message and chain the exception.
120 throw new ObjectWrapperRTException("Failed to create wrappable " + wrappable
121 + " for object of class " + object.getClass(), ex);
122 }
123
124 // An exception here is an error in the set-up of the APSECTS mapping.
125 // As long as that is ok this cast is safe.
126 @SuppressWarnings("unchecked")
127 T result = (T) impl;
128 return result;
129 }
130
131 /**
132 * Check if a wrappable is registered. Note that even if it is not, an object might
133 * implement the interface already in which case wrap() will succeed on it.
134 * To be sure of this, use wrappablePresent(wrappableClass, objectClass).
135 * @param cls The wrappable class.
136 * @return <code>true</code> if the wrappable exists.
137 */
138 public boolean wrappablePresent(Class<? extends Wrappable> cls) {
139 return m_wrappables.containsKey(cls);
140 }
141
142 /**
143 * Check if a call to wrap() has a chance of creating a wrapper on an object class.
144 * This is the case if a) the object implements the interface or b) the wrappable is registered.
145 * Note that even if this returns true, the wrapper implementation may throw an expection
146 * in create(). This can happen if the wrapper is present but does not apply to this class.
147 * @param wrappableClass The wrappable class.
148 * @param objectClass The object class.
149 * @return <code>false</code> if there is definitely no way to create the wrapper for this
150 * class, <code>true</code> if it can be tried (and will only fail if the implementation does).
151 */
152 public boolean wrappablePresent(Class<? extends Wrappable> wrappableClass, Class<?> objectClass) {
153 return wrappableClass.isAssignableFrom(objectClass) || wrappablePresent(wrappableClass);
154 }
155 }