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 java.io.File;
21  import java.io.FileInputStream;
22  import java.io.FileOutputStream;
23  import java.io.IOException;
24  import java.io.PrintStream;
25  import java.util.Enumeration;
26  
27  import net.wotonomy.foundation.NSArray;
28  import net.wotonomy.foundation.NSDictionary;
29  import net.wotonomy.foundation.NSMutableArray;
30  import net.wotonomy.foundation.NSMutableDictionary;
31  import net.wotonomy.foundation.NSPropertyListSerialization;
32  
33  /***
34  * An EOModel is a set of entities and stored procedures, along with a connection
35  * dictionary to connect to a database.
36  *
37  * @author ezamudio@nasoft.com
38  * @author $Author: cgruber $
39  * @version $Revision: 894 $
40  */
41  public class EOModel {
42  
43  	protected static final String IDX_NAME = "index.eomodeld";
44  
45  	//This array contains dictionaries with "className" and "name"
46  	protected NSMutableArray _entities = new NSMutableArray();
47  	protected NSMutableDictionary _entitiesByName = new NSMutableDictionary();
48  	protected NSMutableDictionary _entitiesByClass = new NSMutableDictionary();
49  	protected NSDictionary _connectionDictionary = NSDictionary.EmptyDictionary;
50  	protected String _adaptorName = "JDBC";
51  	protected NSMutableDictionary _prototypesByName = new NSMutableDictionary();
52  	protected NSMutableDictionary _storedProcedures = new NSMutableDictionary();
53  	protected NSMutableArray _storedProcedureNames = new NSMutableArray();
54  	protected NSDictionary _userInfo = NSDictionary.EmptyDictionary;
55  	protected String _name;
56  	protected String _path;
57  	protected NSDictionary _internalInfo = NSDictionary.EmptyDictionary;
58  	protected EOModelGroup _group;
59  
60  	public EOModel() {
61  		super();
62  	}
63  
64  	public EOModel(NSDictionary dict, Object o) {
65  		this();
66  	}
67  
68  	public EOModel(String path) {
69  		this();
70  		File f = new File(path);
71  		_path = f.getAbsolutePath();
72  		if (!(f.exists() && f.isDirectory()))
73  			throw new IllegalArgumentException("The path is invalid (" + f + ")");
74  		_name = f.getName();
75  		f = new File(f, "index.eomodeld");
76  		if (!(f.exists() && f.isFile()))
77  			throw new IllegalArgumentException("Cannot find " + f);
78  		String x = null;
79  		try {
80  			FileInputStream in = new FileInputStream(f);
81  			byte[] b = new byte[in.available()];
82  			in.read(b);
83  			in.close();
84  			x = new String(b);
85  		} catch (IOException e) {
86  			throw new IllegalArgumentException("Cannot read index.eomodeld");
87  		}
88  		NSDictionary d = NSPropertyListSerialization.dictionaryForString(x);
89  		String version = (String)d.objectForKey("EOModelVersion");
90  		if (version == null || !version.startsWith("2."))
91  			throw new IllegalArgumentException("Invalid eomodel version: " + version);
92  		setAdaptorName((String)d.objectForKey("adaptorName"));
93  		setConnectionDictionary((NSDictionary)d.objectForKey("connectionDictionary"));
94  		_entities = ((NSArray)d.objectForKey("entities")).mutableClone();
95  		if (d.objectForKey("storedProcedures") != null)
96  			_storedProcedureNames.addObjectsFromArray((NSArray)d.objectForKey("storedProcedures"));
97  		if (d.objectForKey("internalInfo") != null)
98  			_internalInfo = (NSDictionary)d.objectForKey("internalInfo");
99  		if (d.objectForKey("userInfo") != null)
100 			_userInfo = (NSDictionary)d.objectForKey("userInfo");
101 		entityNamed("EOPrototypes");
102 	}
103 
104 	public void setConnectionDictionary(NSDictionary dict) {
105 		_connectionDictionary = dict;
106 	}
107 	public NSDictionary connectionDictionary() {
108 		return _connectionDictionary;
109 	}
110 
111 	public void addEntity(EOEntity ent) {
112 		_entitiesByName.setObjectForKey(ent, ent.name());
113 		_entitiesByClass.setObjectForKey(ent, ent.className());
114 	}
115 
116 	public void removeEntity(EOEntity ent) {
117 		_entitiesByName.removeObjectForKey(ent.name());
118 		_entitiesByClass.removeObjectForKey(ent.className());
119 	}
120 
121 	public void addStoredProcedure(EOStoredProcedure proc) {
122 		if (!_storedProcedureNames.containsObject(proc))
123 			_storedProcedureNames.addObject(proc);
124 		_storedProcedures.setObjectForKey(proc, proc.name());
125 	}
126 
127 	public void removeStoredProcedure(EOStoredProcedure proc) {
128 		_storedProcedureNames.removeObject(proc.name());
129 		_storedProcedures.removeObjectForKey(proc.name());
130 	}
131 
132 	public EOStoredProcedure storedProcedureNamed(String name) {
133 		EOStoredProcedure proc = (EOStoredProcedure)_storedProcedures.objectForKey(name);
134 		//if we can't find it, check if we should load it
135 		if (proc == null && _path != null && _storedProcedureNames.containsObject(name)) {
136 			//try to read it from file
137 			File f = new File(new File(_path), name + ".storedProcedure");
138 			if (!f.exists())
139 				return null;
140 			String sdict = null;
141 			try {
142 				FileInputStream fin = new FileInputStream(f);
143 				byte[] b = new byte[fin.available()];
144 				fin.read(b);
145 				fin.close();
146 				sdict = new String(b);
147 			} catch (IOException ex) {
148 				return null;
149 			}
150 			NSDictionary plist = NSPropertyListSerialization.dictionaryForString(sdict);
151 			if (plist == null)
152 				throw new IllegalArgumentException("File " + f + " does not contain a valid stored procedure property list.");
153 			proc = new EOStoredProcedure(plist, this);
154 			//add it to our collection
155 			_storedProcedures.setObjectForKey(proc, proc.name());
156 		}
157 		return proc;
158 	}
159 
160 	public NSArray storedProcedures() {
161 		if (_storedProcedures.count() < _storedProcedureNames.count()) {
162 			for (int i=0; i<_storedProcedureNames.count(); i++)
163 				storedProcedureNamed((String)_storedProcedureNames.objectAtIndex(i));
164 		}
165 		return _storedProcedures.allValues();
166 	}
167 
168 	public NSArray storedProcedureNames() {
169 		return _storedProcedures.allKeys();
170 	}
171 
172 	public void setAdaptorName(String value) {
173 		_adaptorName = value;
174 	}
175 	public String adaptorName() {
176 		return _adaptorName;
177 	}
178 
179 	public NSArray entities() {
180 		if (_entitiesByName.count() >= _entities.count())
181 			return _entitiesByName.allValues();
182 		NSMutableArray es = new NSMutableArray();
183 		for (int i = 0; i < _entities.count(); i++) {
184 			NSDictionary d = (NSDictionary)_entities.objectAtIndex(i);
185 			es.addObject(entityNamed((String)d.objectForKey("name")));
186 		}
187 		return es;
188 	}
189 
190 	public NSArray entityNames() {
191 		if (_entitiesByName.count() >= _entities.count())
192 			return _entitiesByName.allKeys();
193 		NSMutableArray names = new NSMutableArray();
194 		for (int i = 0; i < _entities.count(); i++) {
195 			NSDictionary d = (NSDictionary)_entities.objectAtIndex(i);
196 			names.addObject(d.objectForKey("name"));
197 		}
198 		return names;
199 	}
200 
201 	public EOEntity entityNamed(String name) {
202 		EOEntity e = (EOEntity)_entitiesByName.objectForKey(name);
203 		if (e == null && path() != null) {
204 			boolean exists = false;
205 			for (int i = 0; i < _entities.count(); i++) {
206 				NSDictionary d = (NSDictionary)_entities.objectAtIndex(i);
207 				if (d.objectForKey("name").equals(name))
208 					exists = true;
209 			}
210 			if (!exists)
211 				return null;
212 			File f = new File(new File(path()), name + ".plist");
213 			if (!(f.exists() && f.isFile()))
214 				throw new IllegalArgumentException("Cannot find " + name + ".plist");
215 			String s = null;
216 			try {
217 				FileInputStream fin = new FileInputStream(f);
218 				byte[] b = new byte[fin.available()];
219 				fin.read(b);
220 				fin.close();
221 				s = new String(b);
222 			} catch (IOException ex) {
223 				throw new IllegalArgumentException("Cannot read " + f);
224 			}
225 			NSDictionary d = NSPropertyListSerialization.dictionaryForString(s);
226 			if (d == null)
227 				throw new IllegalArgumentException("Cannot parse dictionary for " + f);
228 			e = new EOEntity(d, this);
229 			_entitiesByName.setObjectForKey(e, e.name());
230 		}
231 		return e;
232 	}
233 
234 	public String name() {
235 		return _name;
236 	}
237 
238 	public String path() {
239 		return _path;
240 	}
241 
242 	public void setModelGroup(EOModelGroup group) {
243 		_group = group;
244 	}
245 	public EOModelGroup modelGroup() {
246 		return _group;
247 	}
248 
249 	public void setUserInfo(NSDictionary dict) {
250 		_userInfo = dict;
251 	}
252 
253 	public NSDictionary userInfo() {
254 		return _userInfo;
255 	}
256 
257 	public void write() {
258 	}
259 
260 	public void writeToFile(String path) {
261 		if (!path.endsWith(".eomodeld"))
262 			path += ".eomodeld";
263 		File f = new File(path);
264 		if (f.exists()) {
265 			if (f.isDirectory()) {
266 				File[] kids = f.listFiles();
267 				for (int i = 0; i < kids.length; i++) {
268 					String fname = kids[i].getName();
269 					if (kids[i].isFile() && (fname.endsWith(".plist") || fname.endsWith(".eomodeld") || fname.endsWith(".fspec") || fname.endsWith(".storedProcedure")))
270 						kids[i].delete();
271 				}
272 			} else
273 				f.delete();
274 		} else
275 			f.mkdirs();
276 		File kid = new File(f, "index.eomodeld");
277 
278 		//encode the index file
279 		NSMutableDictionary d = new NSMutableDictionary();
280 		d.setObjectForKey(_adaptorName, "adaptorName");
281 		d.setObjectForKey("2.1", "EOModelVersion");
282 		d.setObjectForKey(_connectionDictionary, "connectionDictionary");
283 		if (_internalInfo != null && _internalInfo.count() > 0)
284 			d.setObjectForKey(_internalInfo, "internalInfo");
285 		if (_userInfo != null && _userInfo.count() > 0)
286 			d.setObjectForKey(_userInfo, "userInfo");
287 		if (_storedProcedureNames.count() > 0)
288 			d.setObjectForKey(_storedProcedureNames, "storedProcedures");
289 
290 		//encode the entity list
291 		entities();
292 		storedProcedures();
293 		NSMutableArray arr = new NSMutableArray(_entitiesByName.count());
294 		Enumeration enumeration = _entitiesByName.keyEnumerator();
295 		NSMutableDictionary md = new NSMutableDictionary();
296 		while (enumeration.hasMoreElements()) {
297 			String key = (String)enumeration.nextElement();
298 			EOEntity ent = (EOEntity)_entitiesByName.objectForKey(key);
299 			md.removeAllObjects();
300 			ent.encodeIntoPropertyList(md);
301 			File plist;
302 			NSDictionary fetchSpecs = (NSDictionary)md.objectForKey("fetchSpecificationDictionary");
303 			if (fetchSpecs != null) {
304 				if (fetchSpecs.count() > 0) {
305 					plist = new File(f, key + ".fspec");
306 					String ps = NSPropertyListSerialization.stringForPropertyList(md.objectForKey("fetchSpecificationDictionary"));
307 					try {
308 						PrintStream stream = new PrintStream(new FileOutputStream(plist));
309 						stream.println(ps);
310 						stream.close();
311 					} catch (IOException ex) {
312 					}
313 				}
314 				md.removeObjectForKey("fetchSpecificationDictionary");
315 			}
316 			plist = new File(f, key + ".plist");
317 			String ps = NSPropertyListSerialization.stringForPropertyList(md);
318 			try {
319 				PrintStream stream = new PrintStream(new FileOutputStream(plist));
320 				stream.println(ps);
321 				stream.close();
322 			} catch (IOException ex) {
323 			}
324 			//add to the entity list for the index
325 			arr.addObject(new NSDictionary(
326 				new Object[]{ ent.name(), ent.className() },
327 				new Object[]{ "name", "className" }));
328 		}
329 		d.setObjectForKey(arr, "entities");
330 
331 		//write the index file
332 		String s = NSPropertyListSerialization.stringForPropertyList(d);
333 		try {
334 			PrintStream stream = new PrintStream(new FileOutputStream(kid));
335 			stream.println(s);
336 			stream.close();
337 		} catch (IOException ex) {
338 			throw new RuntimeException("Cannot write index.eomodeld");
339 		}
340 
341 		//write the stored procedures
342 		for (int i = 0; i < _storedProcedureNames.count(); i++) {
343 			EOStoredProcedure proc = (EOStoredProcedure)_storedProcedures.objectForKey(_storedProcedureNames.objectAtIndex(i));
344 			kid = new File(f, proc.name() + ".storedProcedure");
345 			d.removeAllObjects();
346 			proc.encodeIntoPropertyList(d);
347 			s = NSPropertyListSerialization.stringForPropertyList(d);
348 			try {
349 				PrintStream stream = new PrintStream(new FileOutputStream(kid));
350 				stream.println(s);
351 				stream.close();
352 			} catch (IOException ex) {
353 				throw new RuntimeException("Cannot write " + f);
354 			}
355 		}
356 		_path = f.getAbsolutePath();
357 	}
358 
359 }
360 /*
361  * $Log$
362  * Revision 1.2  2006/02/16 16:47:14  cgruber
363  * Move some classes in to "internal" packages and re-work imports, etc.
364  *
365  * Also use UnsupportedOperationExceptions where appropriate, instead of WotonomyExceptions.
366  *
367  * Revision 1.1  2006/02/16 13:19:57  cgruber
368  * Check in all sources in eclipse-friendly maven-enabled packages.
369  *
370  * Revision 1.8  2005/05/11 15:21:53  cgruber
371  * Change enum to enumeration, since enum is now a keyword as of Java 5.0
372  *
373  * A few other comments in the code.
374  *
375  * Revision 1.7  2003/08/13 20:46:12  chochos
376  * entityNamed() only throws if the searched entity is in the entities array and not in a file.
377  *
378  * Revision 1.6  2003/08/12 01:45:04  chochos
379  * added some code to handle prototypes
380  *
381  * Revision 1.5  2003/08/11 19:38:27  chochos
382  * Can now read from a file and re-write to another file.
383  *
384  * Revision 1.4  2003/08/11 18:20:08  chochos
385  * saving to a file seems to work now.
386  *
387  * Revision 1.3  2003/08/08 02:16:55  chochos
388  * can now read stored procedures from file.
389  *
390  * Revision 1.2  2003/08/08 00:37:00  chochos
391  * add stored procedure functionality
392  *
393  * Revision 1.1  2003/08/07 02:42:28  chochos
394  * EOModel can read an .eomodeld file. EOModelGroup doesn't do much for now.
395  *
396 */