1 /**
2 * AUTOHIT 2003
3 * Copyright Erich P Gatejen (c) 1989,1997,2003,2004
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or (at
8 * your option) any later version.
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
11 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 *
18 * Additional license information can be found in the documentation.
19 * @author Erich P Gatejen
20 */
21 package autohit.universe.service;
22
23 import java.io.File;
24 import java.io.FileInputStream;
25 import java.io.FileOutputStream;
26 import java.io.InputStream;
27 import java.io.ObjectInputStream;
28 import java.io.ObjectOutputStream;
29 import java.io.OutputStream;
30 import java.util.Random;
31
32 import javax.activation.DataSource;
33 import javax.activation.FileDataSource;
34
35 import autohit.common.AutohitProperties;
36 import autohit.common.Utils;
37 import autohit.universe.Universe;
38 import autohit.universe.UniverseDataSource;
39 import autohit.universe.UniverseException;
40 import autohit.universe.UniverseProperties;
41
42 /**
43 * Universe server implimentation for a local filesystem. This
44 * does NOT implement caching! Every object is unique.
45 *
46 * The 'root' property should be a path to the root of the
47 * universe on the filesystem. It should begin with a '/', and
48 * should have no trailing slashes.
49 *
50 * This universe assumes that storable objects can be serialized completely.
51 * If you plan on moving data that isn't in objects or are not inherently
52 * able to seriously completely, then you should obtain streams for put and get, and handle
53 * the IO yourself.
54 *
55 * @author Erich P. Gatejen
56 * @version 1.0
57 * <i>Version History</i>
58 * <code>EPG - New - 24Apr03</code>
59 *
60 */
61 public class UniverseLocal implements Universe {
62
63 private UniverseProperties myProp;
64 private String root;
65 private Random relement;
66
67 /**
68 * Impliment the genesis.
69 *
70 * @param props a universe properties set
71 * @throws autohit.universe.UniverseException
72 * @return the loaded object
73 */
74 public void genesis(UniverseProperties props) throws UniverseException {
75
76 // Save the properties
77 myProp = props;
78
79 // Get random element
80 relement = new Random();
81
82 // cleanse the root
83 root = myProp.getRoot().trim();
84 if ((root.length() < 1)
85 || (root.charAt(0) != AutohitProperties.literal_PATH_SEPERATOR)) {
86 throw new UniverseException(
87 "Bad root. Either empty or doesn't start with /.",
88 UniverseException.UE_MALFORMED_REFERENCE);
89 }
90 try {
91 while (root.charAt(root.length() - 1)
92 == AutohitProperties.literal_PATH_SEPERATOR) {
93 root = root.substring(0, root.length() - 2);
94 }
95 } catch (Exception e) {
96 throw new UniverseException(
97 "Malformed root property =" + myProp.getRoot(),
98 UniverseException.UE_MALFORMED_REFERENCE, e);
99 }
100 }
101
102 /**
103 * This will always be called when the universe is destroyed
104 * @throws autohit.universe.UniverseException
105 */
106 public void close() throws UniverseException {
107 // Don't do anything
108 }
109
110 /**
111 * Load an object from the universe. It will be unique.
112 * There is no caching.
113 * @param name universe name
114 * @return the loaded object
115 * @throws autohit.universe.UniverseException
116 */
117 public Object get(String name) throws UniverseException {
118 Object thing = null;
119
120 try {
121 // construct the path
122 File target = new File(root + AutohitProperties.literal_PATH_SEPERATOR + name);
123 if (target.exists() == false) {
124 throw new UniverseException(
125 "No object =" + name,
126 UniverseException.UE_OBJECT_DOESNT_EXIST);
127 }
128 // deserialize it
129 FileInputStream istream = new FileInputStream(target);
130 ObjectInputStream p = new ObjectInputStream(istream);
131 thing = p.readObject();
132 istream.close();
133
134 } catch (UniverseException e) {
135 throw e;
136 } catch (Exception e) {
137 // Every other exception should be consider an IO error
138 throw new UniverseException(
139 "IO Error on object get. Message=" + e.getMessage(),
140 UniverseException.UE_IO_ERROR, e);
141 }
142 return thing;
143 }
144
145 /**
146 * Same as get, so just chain it.
147 * @param name universe name
148 * @return the loaded object
149 * @throws autohit.universe.UniverseException
150 */
151 public Object getUnique(String name) throws UniverseException {
152 return get(name);
153 }
154
155 /**
156 * Reserve unique object universe. Guarantee it is a unique
157 * instance of it. Great for temp objects.
158 * @param base base path for the object (including root object name)
159 * @return name of the reserved unique object.
160 * @throws autohit.universe.UniverseException
161 * TODO make sure the object can actually be used
162 */
163 public synchronized String reserveUnique(String base) throws UniverseException {
164
165 // Cludge hack!
166 String name = base + "-" + System.currentTimeMillis() + "-" + relement.nextInt(1000000);
167
168 // Check to see if it is unique. Since this is sychroninzed
169 // any wait will guarentee the new name is unique.
170 try {
171 File target = new File(root + AutohitProperties.literal_PATH_SEPERATOR + name);
172 if (target.exists() == true) {
173 this.wait(1);
174 name = base + "-" + System.currentTimeMillis() + "-" + relement.nextInt(1000000);
175 }
176 } catch (Exception io) {
177 // Every other exception should be consider an IO error
178 throw new UniverseException(
179 "IO Error on object. Message=" + io.getMessage(),
180 UniverseException.UE_IO_ERROR, io);
181 }
182 return name;
183 }
184
185 /**
186 * Get an InputStream that can read from a universe object dump.
187 * It does not assume the target is anything--object, bytes, whatever.
188 * @param name universe name
189 * @return a stream to the object
190 * @throws autohit.universe.UniverseException
191 */
192 public InputStream getStream(String name) throws UniverseException {
193 InputStream thing = null;
194
195 try {
196 // construct the path
197 File target = new File(root + AutohitProperties.literal_PATH_SEPERATOR + name);
198 if (target.exists() == false) {
199 throw new UniverseException(
200 "No object =" + name,
201 UniverseException.UE_OBJECT_DOESNT_EXIST);
202 }
203 // get a stream reference to it
204 thing = new FileInputStream(target);
205
206 } catch (UniverseException e) {
207 throw e;
208 } catch (Exception e) {
209 // Every other exception should be consider an IO error
210 throw new UniverseException(
211 "IO Error on object. Message=" + e.getMessage(),
212 UniverseException.UE_IO_ERROR, e);
213 }
214 return thing;
215 }
216
217 /**
218 * Get a Data Source that can interact with this universe object
219 * @param name universe name
220 * @return a data source
221 * @throws autohit.universe.UniverseException
222 * @throws autohit.universe.UniverseDataSource
223 */
224 public DataSource getDataSource(String name) throws UniverseException {
225
226 UniverseDataSource uds = new UniverseDataSource();
227 uds.init(name,this);
228 return uds;
229 }
230
231 /**
232 * Get a FileDataSource that can interact with this universe object.
233 * The universe must handle making sure the object at least appears local to the
234 * FileDataSource
235 * @param name universe name
236 * @return a data source
237 * @throws autohit.universe.UniverseException
238 */
239 public FileDataSource getFileDataSource(String name) throws UniverseException {
240
241 //This one is easy. Just get the local file.
242 FileDataSource candidate = null;
243
244 try {
245 // construct the path
246 File target = new File(root + AutohitProperties.literal_PATH_SEPERATOR + name);
247 if (target.exists() == false) {
248 throw new UniverseException(
249 "No object =" + name,
250 UniverseException.UE_OBJECT_DOESNT_EXIST);
251 }
252 // deserialize it
253 candidate = new FileDataSource(target);
254
255 } catch (UniverseException e) {
256 throw e;
257 } catch (Exception e) {
258 // Every other exception should be consider an IO error
259 throw new UniverseException(
260 "IO Error while getting FileDataSource. Message=" + e.getMessage(),
261 UniverseException.UE_IO_ERROR, e);
262 }
263 return candidate;
264
265 }
266
267
268 /**
269 * Save an object into the universe. If a file is already there,
270 * it will overwrite it.
271 * @param name universe name
272 * @param o the object
273 * @throws autohit.universe.UniverseException
274 */
275 public void put(String name, Object o) throws UniverseException {
276
277 try {
278 // construct the path
279 File target = Utils.makeFile(root + AutohitProperties.literal_PATH_SEPERATOR + name);
280
281 // deserialize it
282 FileOutputStream ostream = new FileOutputStream(target);
283 ObjectOutputStream sobj = new ObjectOutputStream(ostream);
284 sobj.writeObject(o);
285 sobj.flush();
286 ostream.close();
287
288 } catch (Exception e) {
289 // Every other exception should be consider an IO error
290
291 throw new UniverseException(
292 "IO Error on object put. Message=" + e.getMessage(),
293 UniverseException.UE_IO_ERROR, e);
294 }
295 }
296
297 /**
298 * Get an output stream to a universe object. CAller responsible
299 * for streaming and closing.
300 * @param name universe name
301 * @return a stream to the object
302 * @throws autohit.universe.UniverseException
303 */
304 public OutputStream putStream(String name) throws UniverseException {
305 FileOutputStream tempOS = null;
306
307 try {
308 // construct the path
309 File target = Utils.makeFile(root + AutohitProperties.literal_PATH_SEPERATOR + name);
310
311 // deserialize it
312 tempOS = new FileOutputStream(target);
313
314 } catch (Exception e) {
315
316 // Every other exception should be consider an IO error
317 throw new UniverseException(
318 "IO Error on object put. Message=" + e.getMessage(),
319 UniverseException.UE_IO_ERROR, e);
320 }
321 return (OutputStream) tempOS;
322 }
323
324 /**
325 * There is no locking. Always immeadiately return.
326 * @param name universe name
327 * @throws autohit.universe.UniverseException
328 */
329 public void lock(String name) throws UniverseException {
330 // do nothing
331 }
332
333 /**
334 * There is no locking, so return true, since the caller is
335 * always allowed to get an object.
336 * @param name universe name
337 * @return always true
338 * @throws autohit.universe.UniverseException
339 */
340 public boolean lockIfNotLocked(String name) throws UniverseException {
341 return true;
342 }
343
344 /**
345 * Since objects can never be locked, this will always return false.
346 * @param name universe name
347 * @return always false
348 * @throws autohit.universe.UniverseException
349 */
350 public boolean isLocked(String name) throws UniverseException {
351 return false;
352 }
353
354 /**
355 * Release a lock on an object. Do nothing.
356 * @param name universe name
357 * @throws autohit.universe.UniverseException
358 */
359 public void release(String name) throws UniverseException {
360 // do nothing
361 }
362
363 /**
364 * Check to see if an object exists
365 * @param name universe name
366 * @return true if the object exists, otherwise false
367 * @throws autohit.universe.UniverseException
368 */
369 public boolean exists(String name) throws UniverseException {
370 // assume it doesn't exist
371 boolean answer = false;
372
373 try {
374 // Check for the file
375 File target = new File(root + AutohitProperties.literal_PATH_SEPERATOR + name);
376 if (target.exists() == true) {
377 answer = true;
378 }
379
380 } catch (Exception e) {
381 // Every other exception should be consider an IO error
382 throw new UniverseException(
383 "IO Error on object check. Message=" + e.getMessage(),
384 UniverseException.UE_IO_ERROR, e);
385 }
386 return answer;
387 }
388
389 /**
390 * Flush an object. Does nothing, since there is no caching.
391 * @param name universe name
392 * @return true if the object exists, otherwise false
393 * @throws autohit.universe.UniverseException
394 */
395 public void flush(String name) throws UniverseException {
396 // do nothing
397 }
398
399 /**
400 * Discard an object. Does nothing, since there is no caching.
401 * @param name universe name
402 * @return true if the object exists, otherwise false
403 * @throws autohit.universe.UniverseException
404 */
405 public void discard(String name) throws UniverseException {
406 // do nothing.
407 }
408
409 /**
410 * Remove an object from the universe
411 * @param name universe name
412 * @return true if the object exists, otherwise false
413 * @throws autohit.universe.UniverseException
414 */
415 public void remove(String name) throws UniverseException {
416
417 try {
418 // Check for the file
419 File target = new File(root + AutohitProperties.literal_PATH_SEPERATOR + name);
420 if (target.exists() == true) {
421 // object is there. remove it
422 target.delete();
423 } else {
424 // object doesn't exist. error.
425 throw new UniverseException(
426 "No object =" + name,
427 UniverseException.UE_OBJECT_DOESNT_EXIST);
428 }
429
430 } catch (Exception e) {
431 // Every other exception should be consider an IO error
432 throw new UniverseException(
433 "IO Error on object remove. Message=" + e.getMessage(),
434 UniverseException.UE_IO_ERROR, e);
435 }
436 }
437
438 /**
439 * Report the size object from the universe
440 * @param name universe name
441 * @return the size or 0 if empty
442 * @throws autohit.universe.UniverseException
443 */
444 public long size(String name) throws UniverseException {
445
446 long size = 0;
447 try {
448 // Check for the file
449 File target = new File(root + AutohitProperties.literal_PATH_SEPERATOR + name);
450 if (target.exists() == true) {
451 // object is there. remove it
452 size = target.length();
453 } else {
454 // object doesn't exist. error.
455 throw new UniverseException(
456 "No object =" + name,
457 UniverseException.UE_OBJECT_DOESNT_EXIST);
458 }
459
460 } catch (Exception e) {
461 // Every other exception should be consider an IO error
462 throw new UniverseException(
463 "IO Error on object remove. Message=" + e.getMessage(),
464 UniverseException.UE_IO_ERROR, e);
465 }
466 return size;
467 }
468
469
470 }
|