Source code: nextapp/echoservlet/util/PeerFactory.java
1 /*
2 * This file is part of the Echo Web Application Framework (hereinafter "Echo").
3 * Copyright (C) 2002-2004 NextApp, Inc.
4 *
5 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
6 *
7 * The contents of this file are subject to the Mozilla Public License Version
8 * 1.1 (the "License"); you may not use this file except in compliance with
9 * the License. You may obtain a copy of the License at
10 * http://www.mozilla.org/MPL/
11 *
12 * Software distributed under the License is distributed on an "AS IS" basis,
13 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
14 * for the specific language governing rights and limitations under the
15 * License.
16 *
17 * Alternatively, the contents of this file may be used under the terms of
18 * either the GNU General Public License Version 2 or later (the "GPL"), or
19 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
20 * in which case the provisions of the GPL or the LGPL are applicable instead
21 * of those above. If you wish to allow use of your version of this file only
22 * under the terms of either the GPL or the LGPL, and not to allow others to
23 * use your version of this file under the terms of the MPL, indicate your
24 * decision by deleting the provisions above and replace them with the notice
25 * and other provisions required by the GPL or the LGPL. If you do not delete
26 * the provisions above, a recipient may use your version of this file under
27 * the terms of any one of the MPL, the GPL or the LGPL.
28 */
29
30 package nextapp.echoservlet.util;
31
32 import java.io.Serializable;
33 import java.util.Map;
34 import java.util.MissingResourceException;
35
36 /**
37 * Generates "peer" objects for objects based on associations.
38 * Associations are stored in a properties files, where the keys are the fully
39 * qualified class names of objects and the values are the fully qualified
40 * class names of their peers. When an object is passed to the createPeer()
41 * method its peer will be returned based on the bindings in the properties file.
42 * An objects superclass(es) will also be tested for available peers if none is
43 * available for the derived class. If no peer is found, a PeerFactoryException
44 * is thrown.
45 */
46 public class PeerFactory
47 implements Serializable {
48
49 /**
50 * An exception used to describe a problem that was encountered loading
51 * a peer object.
52 */
53 public class PeerFactoryException extends Exception {
54
55 /**
56 * Creates a <code>PeerFactoryException</code>.
57 *
58 * @param description A description of the problem which caused this
59 * exception to occur.
60 */
61 public PeerFactoryException(String description) {
62 super(description);
63 }
64 }
65
66 /** A map of associations */
67 private Map associations = null;
68
69 /**
70 * Creates a new <code>PeerFactory</code>.
71 */
72 public PeerFactory() {
73 super();
74 }
75
76 /**
77 * Creates a new <code>PeerFactory</code> with initial associations.
78 *
79 * @param propertiesFile The name for the properties file containing the
80 * initial peer bindings.
81 */
82 public PeerFactory(String propertiesFile)
83 throws PeerFactoryException {
84 super();
85
86 addAssociations(propertiesFile);
87 }
88
89 /**
90 * Adds a single peer binding.
91 *
92 * @param className The fully qualified name of the class.
93 * @param peerClassName The fully qualified name of the peer class.
94 */
95 public void addAssociation(String className, String peerClassName) {
96 associations.put(className, peerClassName);
97 }
98
99 /**
100 * Loads peer bindings. Invoking this method will result in the new
101 * associations supplementing existing associations. Existing associations
102 * will not be removed. If two associations have the same key, the most
103 * recently added one will be used.
104 *
105 * @param propertiesFile The name of a properties file containing the peer
106 * bindings to be loaded.
107 */
108 public void addAssociations(String propertiesFile)
109 throws PeerFactoryException {
110 try {
111 if (associations == null) {
112 associations = new PropertyMap(propertiesFile);
113 } else {
114 associations.putAll(new PropertyMap(propertiesFile));
115 }
116 } catch (MissingResourceException ex) {
117 throw new PeerFactoryException("Unable to load associations file \"" + propertiesFile + "\":" + ex);
118 }
119 }
120
121 /**
122 * Instantiates a new peer for the specified object by invoking its
123 * default constructor.
124 *
125 * @param object The object for which to create an peer instance.
126 * @return A new instance of the peer object for <code>object</code>.
127 * @throws PeerFactoryException if the peer cannot be instantiated.
128 */
129 public Object createPeer(Object object)
130 throws PeerFactoryException {
131 Object peer = null;
132 Class peerClass = getPeerClass(object.getClass());
133
134 try {
135 peer = peerClass.newInstance();
136 } catch (InstantiationException ex) {
137 throw new PeerFactoryException("Unable to instantiate peer class \"" + peerClass.getName()
138 + "\":" + ex);
139 } catch (IllegalAccessException ex) {
140 throw new PeerFactoryException("Unable to access peer class \"" + peerClass.getName()
141 + "\":" + ex);
142 }
143
144 return peer;
145 }
146
147 /**
148 * Returns the peer class associated for the given object class.
149 *
150 * @param objectClass The <code>Class</code> of the object whose peer
151 * <code>Class</code> is to be determined.
152 * @return The <code>Class</code> of the corresponding peer.
153 * @throws PeerFactoryException if the peer class cannot be determined.
154 */
155 public Class getPeerClass(Class objectClass)
156 throws PeerFactoryException {
157 String objectClassName = null;
158 String originalObjectClassName = objectClass.getName();
159 String peerClassName = null;
160 Class peerClass;
161
162 while (peerClassName == null) {
163 objectClassName = objectClass.getName();
164
165 peerClassName = (String) associations.get(objectClassName);
166
167 if (peerClassName == null) {
168 objectClass = objectClass.getSuperclass();
169 if (objectClass == null) {
170 throw new PeerFactoryException("No peer class is registered for \"" + originalObjectClassName + "\".");
171 }
172 }
173 }
174
175 try {
176 peerClass = Thread.currentThread().getContextClassLoader().loadClass(peerClassName);
177 } catch (ClassNotFoundException ex) {
178 throw new PeerFactoryException("Unable to find peer class \"" + peerClassName
179 + "\" for object \"" + objectClassName + "\": ");
180 }
181
182 return peerClass;
183 }
184 }