View Javadoc

1   /*
2    Wotonomy: OpenStep design patterns for pure Java applications.
3    Copyright (C) 2001 Michael Powers
4   
5    This library is free software; you can redistribute it and/or
6    modify it under the terms of the GNU Lesser General Public
7    License as published by the Free Software Foundation; either
8    version 2.1 of the License, or (at your option) any later version.
9   
10   This library 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 GNU
13   Lesser General Public License for more details.
14  
15   You should have received a copy of the GNU Lesser General Public
16   License along with this library; if not, see http://www.gnu.org
17   */
18  package net.wotonomy.access;
19  
20  import net.wotonomy.foundation.NSArray;
21  import net.wotonomy.foundation.NSData;
22  import net.wotonomy.foundation.NSDictionary;
23  import net.wotonomy.foundation.NSKeyValueCoding;
24  import net.wotonomy.foundation.NSMutableArray;
25  import net.wotonomy.foundation.NSMutableDictionary;
26  import net.wotonomy.foundation.NSTimestamp;
27  
28  /***
29  *
30  * @author ezamudio@nasoft.com
31  * @author $Author: cgruber $
32  * @version $Revision: 894 $
33  */
34  
35  public abstract class EOAdaptor {
36  
37  	protected String _name;
38  	protected NSDictionary _connectionDictionary = NSDictionary.EmptyDictionary;
39  	protected NSMutableArray _contexts = new NSMutableArray();
40  	protected Class _expressionClass;
41  	private static NSMutableDictionary _expressionClassesByName = new NSMutableDictionary();
42  
43  	public EOAdaptor(String name) {
44  		super();
45  		_name = name;
46  	}
47  
48  	/***
49  	 * Creates an adaptor with model's adaptorName and sets its connection
50  	 * dictionary to the model's connection dictionary.
51  	 * @param model The model to take adaptorName and connectionDictionary from.
52  	 * @return The adaptor specified in model.
53  	 */
54  	public static EOAdaptor adaptorWithModel(EOModel model) {
55  		if (model == null)
56  			throw new IllegalArgumentException("Model must not be null.");
57  		if (model.adaptorName() == null || model.adaptorName().length() == 0)
58  			throw new IllegalArgumentException("Cannot create an adaptor with an empty name.");
59  		EOAdaptor adaptor = adaptorWithName(model.adaptorName());
60  		if (adaptor == null)
61  			throw new IllegalArgumentException("Cannot create adaptor with name " + model.adaptorName());
62  		adaptor.setConnectionDictionary(model.connectionDictionary());
63  		return adaptor;
64  	}
65  
66  	/***
67  	 * Instantiates an adaptor of a concrete EOAdaptor subclass, based on name.
68  	 * If name is a fully qualified class name, then it returns an instance of that class
69  	 * by invoking the constructor with a string argument. Otherwise, it
70  	 * tries to find a class called (name)Adaptor in a package called
71  	 * net.wotonomy.(lowercase name)adaptor; if it can't find one, an exception is raised.
72  	 * @param name The name of the adaptor, or a fully qualified class name.
73  	 * @return
74  	 */
75  	public static EOAdaptor adaptorWithName(String name) {
76  		Class adaptorClass = null;
77  		String cname = null;
78  		if (name.endsWith("Adaptor") && name.indexOf('.') > 0) {
79  			cname = name;
80  			int lastdot = name.lastIndexOf('.');
81  			//take off the package and the 'Adaptor' suffix
82  			name = cname.substring(lastdot, cname.length() - 7);
83  		} else {
84  			//construct the fully qualified class name
85  			cname = "net.wotonomy." + name.toLowerCase() + "adaptor." + name + "Adaptor";
86  		}
87  		try {
88  			adaptorClass = Class.forName(cname);
89  		} catch (ClassNotFoundException ex) {
90  			throw new IllegalArgumentException("Cannot find class named " + name);
91  		}
92  		EOAdaptor adaptor = null;
93  		java.lang.reflect.Constructor callme = null;
94  		try {
95  			callme = adaptorClass.getConstructor(new Class[]{ String.class });
96  			adaptor = (EOAdaptor)callme.newInstance((Object[])new String[]{ name });
97  		} catch (ClassCastException ex) {
98  			throw new IllegalArgumentException("Class " + adaptorClass.getName() + " must inherit from net.wotonomy.access.EOAdaptor");
99  		}catch (Exception ex) {
100 			throw new IllegalArgumentException("Cannot find or invoke constructor with name argument in class " + adaptorClass.getName());
101 		}
102 		return adaptor;
103 	}
104 
105 	public static void setExpressionClassName(String expClassName, String adaptorClassName) {
106 		_expressionClassesByName.setObjectForKey(expClassName, adaptorClassName);
107 	}
108 	public static String expressionClassName(String adaptorClassName) {
109 		return (String)_expressionClassesByName.objectForKey(adaptorClassName);
110 	}
111 
112 	public void assignExternalInfoForAttribute(EOAttribute attribute) {
113 		if (!attribute.isDerived()) {
114 			attribute.setColumnName(attribute.name().toUpperCase());
115 		}
116 		assignExternalTypeForAttribute(attribute);
117 	}
118 
119 	public void assignExternalTypeForAttribute(EOAttribute attribute) {
120 	}
121 
122 	public void assignExternalInfoForEntity(EOEntity entity) {
123 		entity.setExternalName(entity.name().toUpperCase());
124 	}
125 
126 	public void assignExternalInfoForEntireModel(EOModel model) {
127 		NSArray ents = model.entities();
128 		for (int i = 0; i < ents.count(); i++) {
129 			EOEntity e = (EOEntity)ents.objectAtIndex(i);
130 			//TODO: check that entity is not a prototypes entity
131 			NSArray atts = e.attributes();
132 			for (int j = 0; j < atts.count(); j++) {
133 				EOAttribute a = (EOAttribute)atts.objectAtIndex(i);
134 				assignExternalInfoForAttribute(a);
135 			}
136 			assignExternalInfoForEntity(e);
137 		}
138 	}
139 
140 	public boolean canServiceModel(EOModel model) {
141 		NSDictionary mcd = model.connectionDictionary();
142 		if (mcd == null && _connectionDictionary == null)
143 			return true;
144 		if (mcd == null || _connectionDictionary == null)
145 			return false;
146 		return mcd.equals(_connectionDictionary);
147 	}
148 
149 	public void setConnectionDictionary(NSDictionary connection) {
150 		_connectionDictionary = connection;
151 	}
152 	public NSDictionary connectionDictionary() {
153 		return _connectionDictionary;
154 	}
155 
156 	public NSArray contexts() {
157 		return new NSArray(_contexts);
158 	}
159 
160 	public abstract void assertConnectionDictionaryIsValid();
161 
162 	public abstract EOAdaptorContext createAdaptorContext();
163 
164 	public abstract Class defaultExpressionClass();
165 
166 	public abstract EOSQLExpressionFactory expressionFactory();
167 
168 	public abstract boolean isValidQualifierType(String typeName, EOModel model);
169 
170 	public Class expressionClass() {
171 		if (_expressionClass != null)
172 			return _expressionClass;
173 		String cname = expressionClassName(name());
174 		if (cname != null) {
175 			try {
176 				_expressionClass = Class.forName(cname);
177 			} catch (ClassNotFoundException ex) {
178 				throw new IllegalStateException("Cannot find expression class named " + cname);
179 			}
180 		}
181 		return defaultExpressionClass();
182 	}
183 
184 	public NSArray externalTypesWithModel(EOModel model) {
185 		return NSArray.EmptyArray;
186 	}
187 
188 	public NSData fetchedValueForDataValue(NSData value, EOAttribute attr) {
189 		return value;
190 	}
191 
192 	public NSTimestamp fetchedValueForDateValue(NSTimestamp value, EOAttribute attr) {
193 		return value;
194 	}
195 
196 	public Number fetchedValueForNumberValue(Number value, EOAttribute attr) {
197 		return value;
198 	}
199 
200 	public String fetchedValueForStringValue(String value, EOAttribute attr) {
201 		return value;
202 	}
203 
204 	public Object fetchedValueForValue(Object value, EOAttribute attr) {
205 		if (value == NSKeyValueCoding.NullValue)
206 			return value;
207 		if (value instanceof String)
208 			return fetchedValueForStringValue((String)value, attr);
209 		if (value instanceof NSData)
210 			return fetchedValueForDataValue((NSData)value, attr);
211 		if (value instanceof Number)
212 			return fetchedValueForNumberValue((Number)value, attr);
213 		if (value instanceof NSTimestamp)
214 			return fetchedValueForDateValue((NSTimestamp)value, attr);
215 		return value;
216 	}
217 
218 	public void handleDroppedConnection() {
219 		for (int i = 0; i < _contexts.count(); i++) {
220 			EOAdaptorContext c = (EOAdaptorContext)_contexts.objectAtIndex(i);
221 			c.transactionDidRollback();
222 			c.handleDroppedConnection();
223 		}
224 		_contexts.removeAllObjects();
225 	}
226 
227 	public boolean hasOpenChannels() {
228 		for (int i = 0; i < _contexts.count(); i++) {
229 			EOAdaptorContext c = (EOAdaptorContext)_contexts.objectAtIndex(i);
230 			if (c.hasOpenChannels())
231 				return true;
232 		}
233 		return false;
234 	}
235 
236 	public String internalTypeForExternalType(String extType, EOModel model) {
237 		return null;
238 	}
239 
240 	public boolean isDroppedConnectionException(Exception ex) {
241 		return false;
242 	}
243 
244 	public String name() {
245 		return _name;
246 	}
247 
248 	public NSArray prototypeAttributes() {
249 		return NSArray.EmptyArray;
250 	}
251 
252 }
253 /*
254  * $Log$
255  * Revision 1.2  2006/02/16 16:47:14  cgruber
256  * Move some classes in to "internal" packages and re-work imports, etc.
257  *
258  * Also use UnsupportedOperationExceptions where appropriate, instead of WotonomyExceptions.
259  *
260  * Revision 1.1  2006/02/16 13:19:57  cgruber
261  * Check in all sources in eclipse-friendly maven-enabled packages.
262  *
263  * Revision 1.2  2005/12/08 06:52:32  cgruber
264  * Move tests, improve build.xml, and make certain casts explicit so that Java 1.5 doesn't complain about varargs.
265  *
266  * Revision 1.1  2003/08/13 00:37:45  chochos
267  * an almost complete implementation of the abstract adaptor-layer classes
268  *
269  */