1
14 package gate.util.persistence;
15
16 import java.io.*;
17 import java.net.MalformedURLException;
18 import java.net.URL;
19 import java.text.NumberFormat;
20 import java.util.*;
21
22 import gate.*;
23 import gate.creole.*;
24 import gate.event.ProgressListener;
25 import gate.event.StatusListener;
26 import gate.gui.MainFrame;
27 import gate.persist.PersistenceException;
28 import gate.util.*;
29
30
34 public class PersistenceManager {
35
36
42 static protected class ObjectHolder{
43 ObjectHolder(Object target){
44 this.target = target;
45 }
46
47 public int hashCode(){
48 return System.identityHashCode(target);
49 }
50
51 public boolean equals(Object obj){
52 if(obj instanceof ObjectHolder)
53 return ((ObjectHolder)obj).target == this.target;
54 else return false;
55 }
56
57 public Object getTarget(){
58 return target;
59 }
60
61 private Object target;
62 }
64
75 public static class SlashDevSlashNull implements Persistence{
76
79 public void extractDataFromSource(Object source)throws PersistenceException{
80 }
81
82
85 public Object createObject()throws PersistenceException,
86 ResourceInstantiationException{
87 return null;
88 }
89 static final long serialVersionUID = -8665414981783519937L;
90 }
91
92
98 public static class URLHolder implements Persistence{
99
103 public void extractDataFromSource(Object source)throws PersistenceException{
104 try{
105 URL url = (URL)source;
106 if(url.getProtocol().equals("file")){
107 try{
108 urlString = relativePathMarker +
109 getRelativePath(persistenceFile.toURL(), url);
110 }catch(MalformedURLException mue){
111 urlString = ((URL)source).toExternalForm();
112 }
113 }else{
114 urlString = ((URL)source).toExternalForm();
115 }
116 }catch(ClassCastException cce){
117 throw new PersistenceException(cce);
118 }
119 }
120
121
125 public Object createObject()throws PersistenceException{
126 try{
127 if(urlString.startsWith(relativePathMarker)){
128 URL context = persistenceFile.toURL();
129 return new URL(context,
130 urlString.substring(relativePathMarker.length()));
131 }else return new URL(urlString);
132 }catch(MalformedURLException mue){
133 throw new PersistenceException(mue);
134 }
135 }
136 String urlString;
137
141 private static final String relativePathMarker = "$relpath$";
142 static final long serialVersionUID = 7943459208429026229L;
143 }
144
145 public static class ClassComparator implements Comparator{
146
157 public int compare(Object o1, Object o2){
158 Class c1 = (Class)o1;
159 Class c2 = (Class)o2;
160
161 if(c1.equals(c2)) return 0;
162 if(c1.isAssignableFrom(c2)) return 1;
163 if(c2.isAssignableFrom(c1)) return -1;
164 throw new NotComparableException();
165 }
166 }
167
168
172 public static class NotComparableException extends RuntimeException{
173 public NotComparableException(String message){
174 super(message);
175 }
176 public NotComparableException(){
177 }
178 }
179
180
188 static Serializable getPersistentRepresentation(Object target)
189 throws PersistenceException{
190 if(target == null) return null;
191 Persistence res = (Persistence)existingPersitentReplacements.
193 get(new ObjectHolder(target));
194 if(res != null) return res;
195
196 Class type = target.getClass();
197 Class newType = getMostSpecificPersistentType(type);
198 if(newType == null){
199 if(target instanceof Serializable) return (Serializable)target;
201 else throw new PersistenceException(
202 "Could not find a serialisable replacement for " + type);
203 }
204
205 try{
207 res = (Persistence)newType.newInstance();
208 }catch(Exception e){
209 throw new PersistenceException(e);
210 }
211 if(target instanceof NameBearer){
212 StatusListener sListener = (StatusListener)MainFrame.getListeners().
213 get("gate.event.StatusListener");
214 if(sListener != null){
215 sListener.statusChanged("Storing " + ((NameBearer)target).getName());
216 }
217 }
218 res.extractDataFromSource(target);
219 existingPersitentReplacements.put(new ObjectHolder(target), res);
220 return res;
221 }
222
223
224 static Object getTransientRepresentation(Object target)
225 throws PersistenceException,
226 ResourceInstantiationException{
227
228 if(target == null || target instanceof SlashDevSlashNull) return null;
229 if(target instanceof Persistence){
230 Object resultKey = new ObjectHolder(target);
231 Object result = existingTransientValues.get(resultKey);
233 if(result != null) return result;
234
235 result = ((Persistence)target).createObject();
237 existingTransientValues.put(resultKey, result);
238 return result;
239 }else return target;
240 }
241
242
243
259 protected static Class getMostSpecificPersistentType(Class type){
260 List expansionSet = new ArrayList();
264 expansionSet.add(type);
265
266
270 List userInterfaces = new ArrayList();
273 List gateInterfaces = new ArrayList();
274 List javaInterfaces = new ArrayList();
275 while(!expansionSet.isEmpty()){
276 Iterator typesIter = expansionSet.iterator();
278 while(typesIter.hasNext()){
279 Class result = (Class)persistentReplacementTypes.get(typesIter.next());
280 if(result != null){
281 return result;
282 }
283 }
284
288 if(type != null) type = type.getSuperclass();
290
291
292 userInterfaces.clear();
293 gateInterfaces.clear();
294 javaInterfaces.clear();
295
296 typesIter = expansionSet.iterator();
297 while(typesIter.hasNext()){
298 Class aType = (Class)typesIter.next();
299 Class[] interfaces = aType.getInterfaces();
300 for(int i = 0; i < interfaces.length; i++){
302 Class anIterf = interfaces[i];
303 String interfType = anIterf.getName();
304 if(interfType.startsWith("java")){
305 javaInterfaces.add(anIterf);
306 }else if(interfType.startsWith("gate")){
307 gateInterfaces.add(anIterf);
308 }else userInterfaces.add(anIterf);
309 }
310 }
311
312 expansionSet.clear();
313 if(type != null) expansionSet.add(type);
314 expansionSet.addAll(userInterfaces);
315 expansionSet.addAll(gateInterfaces);
316 expansionSet.addAll(javaInterfaces);
317 }
318 return null;
320
321 }
363
364
372 public static String getRelativePath(URL context, URL target){
373 if(context.getProtocol().equals("file") &&
374 target.getProtocol().equals("file")){
375
376 try{
378 context = new File(context.getPath()).toURL();
379 }catch(MalformedURLException mue){
380 throw new GateRuntimeException("Could not normalise the file URL:\n"+
381 context + "\nThe problem was:\n" +mue);
382 }
383 try{
384 target = new File(target.getPath()).toURL();
385 }catch(MalformedURLException mue){
386 throw new GateRuntimeException("Could not normalise the file URL:\n"+
387 target + "\nThe problem was:\n" +mue);
388 }
389 List targetPathComponents = new ArrayList();
390 File aFile = new File(target.getPath()).getParentFile();
391 while(aFile != null){
392 targetPathComponents.add(0, aFile);
393 aFile = aFile.getParentFile();
394 }
395 List contextPathComponents = new ArrayList();
396 aFile = new File(context.getPath()).getParentFile();
397 while(aFile != null){
398 contextPathComponents.add(0, aFile);
399 aFile = aFile.getParentFile();
400 }
401 int commonPathElements = 0;
404 while(commonPathElements < targetPathComponents.size() &&
405 commonPathElements < contextPathComponents.size() &&
406 targetPathComponents.get(commonPathElements).
407 equals(contextPathComponents.get(commonPathElements)))
408 commonPathElements++;
409 String relativePath = "";
411 for(int i = commonPathElements;
412 i < contextPathComponents.size(); i++){
413 if(relativePath.length() == 0) relativePath += "..";
414 else relativePath += "/..";
415 }
416 for(int i = commonPathElements; i < targetPathComponents.size(); i++){
417 String aDirName = ((File)targetPathComponents.get(i)).getName();
418 if(aDirName.length() == 0){
419 aDirName = ((File)targetPathComponents.get(i)).getAbsolutePath();
420 if(aDirName.endsWith(File.separator)){
421 aDirName = aDirName.substring(0, aDirName.length() -
422 File.separator.length());
423 }
424 }
425 if(relativePath.length() == 0){
427 relativePath += aDirName;
428 }else{
429 relativePath += "/" + aDirName;
430 }
431 }
432 if(relativePath.length() == 0){
434 relativePath += new File(target.getPath()).getName();
435 }else{
436 relativePath += "/" + new File(target.getPath()).getName();
437 }
438
439 return relativePath;
440 }else{
441 throw new GateRuntimeException("Both the target and the context URLs " +
442 "need to be \"file:\" URLs!");
443 }
444 }
445
446 public static void saveObjectToFile(Object obj, File file)
447 throws PersistenceException, IOException {
448 ProgressListener pListener = (ProgressListener)MainFrame.getListeners()
449 .get("gate.event.ProgressListener");
450 StatusListener sListener = (gate.event.StatusListener)
451 MainFrame.getListeners().
452 get("gate.event.StatusListener");
453 long startTime = System.currentTimeMillis();
454 if(pListener != null) pListener.progressChanged(0);
455 ObjectOutputStream oos = null;
456 persistenceFile = file;
457 try{
458 existingPersitentReplacements.clear();
460 existingPersitentReplacements.clear();
461
462 oos = new ObjectOutputStream(new FileOutputStream(file));
463
464 List urlList = new ArrayList(Gate.getCreoleRegister().getDirectories());
466 Object persistentList = getPersistentRepresentation(urlList);
467 oos.writeObject(persistentList);
468
469 Object persistentObject = getPersistentRepresentation(obj);
471 oos.writeObject(persistentObject);
472 }finally{
473 persistenceFile = null;
474 if(oos != null){
475 oos.flush();
476 oos.close();
477 }
478 long endTime = System.currentTimeMillis();
479 if(sListener != null) sListener.statusChanged(
480 "Storing completed in " +
481 NumberFormat.getInstance().format(
482 (double)(endTime - startTime) / 1000) + " seconds");
483 if(pListener != null) pListener.processFinished();
484 }
485 }
486
487 public static Object loadObjectFromFile(File file)
488 throws PersistenceException, IOException,
489 ResourceInstantiationException {
490 exceptionOccured = false;
491 ProgressListener pListener = (ProgressListener)MainFrame.getListeners().
492 get("gate.event.ProgressListener");
493 StatusListener sListener = (gate.event.StatusListener)
494 MainFrame.getListeners()
495 .get("gate.event.StatusListener");
496 if(pListener != null) pListener.progressChanged(0);
497 long startTime = System.currentTimeMillis();
498 persistenceFile = file;
499 ObjectInputStream ois = new ObjectInputStream(new FileInputStream(file));
500 Object res = null;
501 try{
502 Iterator urlIter = ((Collection)
504 getTransientRepresentation(ois.readObject())).
505 iterator();
506 while(urlIter.hasNext()){
507 URL anUrl = (URL)urlIter.next();
508 try{
509 if(!Gate.getCreoleRegister().getDirectories().contains(anUrl))
510 Gate.getCreoleRegister().registerDirectories(anUrl);
511 }catch(GateException ge){
512 Err.prln("Could not reload creole directory " +
513 anUrl.toExternalForm());
514 }
515 }
516 res = ois.readObject();
518 ois.close();
519
520 existingTransientValues.clear();
522 res = getTransientRepresentation(res);
523 existingTransientValues.clear();
524 long endTime = System.currentTimeMillis();
525 if(sListener != null) sListener.statusChanged(
526 "Loading completed in " +
527 NumberFormat.getInstance().format(
528 (double)(endTime - startTime) / 1000) + " seconds");
529 if(pListener != null) pListener.processFinished();
530 if(exceptionOccured){
531 throw new PersistenceException("There were errors!\n" +
532 "See messages for details...");
533 }
534 return res;
535 }catch(ResourceInstantiationException rie){
536 if(sListener != null) sListener.statusChanged("Loading failed!");
537 if(pListener != null) pListener.processFinished();
538 throw rie;
539 }catch(Exception ex){
540 if(sListener != null) sListener.statusChanged("Loading failed!");
541 if(pListener != null) pListener.processFinished();
542 throw new PersistenceException(ex);
543 }finally{
544 persistenceFile = null;
545 }
546 }
547
548
549
559 public static Class registerPersitentEquivalent(Class transientType,
560 Class persistentType)
561 throws PersistenceException{
562 if(!Persistence.class.isAssignableFrom(persistentType)){
563 throw new PersistenceException(
564 "Persistent equivalent types have to implement " +
565 Persistence.class.getName() + "!\n" +
566 persistentType.getName() + " does not!");
567 }
568 return (Class)persistentReplacementTypes.put(transientType, persistentType);
569 }
570
571
572
576 private static Map persistentReplacementTypes;
577
578
584 private static Map existingPersitentReplacements;
585
586
593 private static Map existingTransientValues;
594
595 private static ClassComparator classComparator = new ClassComparator();
596
597
601 static boolean exceptionOccured = false;
602
603
607 static File persistenceFile;
608
609 static{
610 persistentReplacementTypes = new HashMap();
611 try{
612 registerPersitentEquivalent(VisualResource.class,
614 SlashDevSlashNull.class);
615
616 registerPersitentEquivalent(URL.class, URLHolder.class);
617
618 registerPersitentEquivalent(Map.class, MapPersistence.class);
619 registerPersitentEquivalent(Collection.class,
620 CollectionPersistence.class);
621
622 registerPersitentEquivalent(ProcessingResource.class,
623 PRPersistence.class);
624
625 registerPersitentEquivalent(DataStore.class,
626 DSPersistence.class);
627
628 registerPersitentEquivalent(LanguageResource.class,
629 LRPersistence.class);
630
631 registerPersitentEquivalent(Corpus.class,
632 CorpusPersistence.class);
633
634 registerPersitentEquivalent(Controller.class,
635 ControllerPersistence.class);
636
637 registerPersitentEquivalent(ConditionalController.class,
638 ConditionalControllerPersistence.class);
639
640 registerPersitentEquivalent(LanguageAnalyser.class,
641 LanguageAnalyserPersistence.class);
642
643 registerPersitentEquivalent(SerialAnalyserController.class,
644 SerialAnalyserControllerPersistence.class);
645
646 registerPersitentEquivalent(gate.persist.JDBCDataStore.class,
647 JDBCDSPersistence.class);
648 registerPersitentEquivalent(gate.creole.AnalyserRunningStrategy.class,
649 AnalyserRunningStrategyPersistence.class);
650 }catch(PersistenceException pe){
651 pe.printStackTrace();
653 }
654 existingPersitentReplacements = new HashMap();
655 existingTransientValues = new HashMap();
656 }
657 }