View Javadoc

1   /*
2   * Licensed to the Apache Software Foundation (ASF) under one or more
3   * contributor license agreements.  See the NOTICE file distributed with
4   * this work for additional information regarding copyright ownership.
5   * The ASF licenses this file to You under the Apache License, Version 2.0
6   * (the "License"); you may not use this file except in compliance with
7   * the License.  You may obtain a copy of the License at
8   *
9   *     http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17  package org.apache.jetspeed.serializer;
18  
19  import java.io.File;
20  import java.io.FileInputStream;
21  import java.io.FileOutputStream;
22  import java.sql.Date;
23  import java.util.ArrayList;
24  import java.util.HashMap;
25  import java.util.Iterator;
26  import java.util.Map;
27  import java.util.StringTokenizer;
28  
29  import javolution.xml.XMLBinding;
30  import javolution.xml.XMLObjectReader;
31  import javolution.xml.XMLObjectWriter;
32  
33  import org.apache.commons.configuration.Configuration;
34  import org.apache.commons.configuration.PropertiesConfiguration;
35  import org.apache.commons.logging.Log;
36  import org.apache.commons.logging.LogFactory;
37  import org.apache.jetspeed.Jetspeed;
38  import org.apache.jetspeed.components.ComponentManager;
39  import org.apache.jetspeed.components.SpringComponentManager;
40  import org.apache.jetspeed.engine.JetspeedEngineConstants;
41  import org.apache.jetspeed.serializer.objects.JSSnapshot;
42  
43  public abstract class JetspeedSerializerBase
44  {
45  
46      /*** Logger */
47      protected static final Log log = LogFactory.getLog(JetspeedSerializer.class);
48  
49      private ComponentManager cm = null;
50      private Object sem = new Object();
51  
52      int refCouter = 0;
53  
54      /*** the main wrapper class for an XML file */
55      private JSSnapshot snapshot;
56  
57      /*** processing flags */
58      /*** export/import instructions */
59  
60      private HashMap processSettings = new HashMap();
61  
62      private boolean initialized = false;
63  
64      /*** current indent for XML files - defaults to tab */
65      private String currentIndent = null;
66  
67      private static String ENCODING_STRING = "JETSPEED 2.1 - 2006";
68      private static String JETSPEED = "JETSPEED";
69      
70      protected final ComponentManager getCM()
71      {
72          if (cm == null)
73          {
74              cm = Jetspeed.getComponentManager();
75          }
76      	return cm;
77      }
78      
79      public JetspeedSerializerBase()
80      {
81      }
82  
83      
84      
85      /***
86       * hand over existing component manager
87       * 
88       * @param cm
89       */
90      public JetspeedSerializerBase(ComponentManager cm)
91      {
92          this.setComponentManager(cm);
93          this.initialized = true;
94      }
95  
96      /***
97       * This constructor takes the application root, the search path for the boot
98       * component configuration files and the search path for the application
99       * component configuration files.
100      * <p>
101      * For example: new JetspeedSerializerSecondaryImpl("./", "assembly/boot/*.xml",
102      * "assembly/*.xml") will establish the current directory as the root,
103      * process all xml files in the assembly/boot directory before processing
104      * all xml files in the assembly directory itself.
105      * 
106      * @param appRoot
107      *            working directory
108      * @param bootConfig
109      *            boot (primary) file or files (wildcards are allowed)
110      * @param appConfig
111      *            application (secondary) file or files (wildcards are allowed)
112      */
113     public JetspeedSerializerBase(String appRoot, String[] bootConfig,
114             String[] appConfig) throws SerializerException
115     {
116         this.initializeComponentManager(appRoot, bootConfig, appConfig);
117         this.initialized = true;
118     }
119 
120     /*
121      * (non-Javadoc)
122      * 
123      * @see org.apache.jetspeed.serializer.JetspeedSerializer#nitializeComponentManager(String,String[],String[])
124      */
125     public final void initializeComponentManager(String appRoot, String[] bootConfig,
126             String[] appConfig) throws SerializerException
127     {
128 
129     	
130     	
131     	if (this.initialized)
132             throw new SerializerException(
133                     SerializerException.COMPONENT_MANAGER_EXISTS.create(""));
134         SpringComponentManager cm = new SpringComponentManager(bootConfig,
135                 appConfig, appRoot);
136         cm.start();
137         Configuration properties = new PropertiesConfiguration();
138         properties.setProperty(JetspeedEngineConstants.APPLICATION_ROOT_KEY,
139                 appRoot);
140         this.setComponentManager(cm);
141     }
142 
143     /*
144      * (non-Javadoc)
145      * 
146      * @see org.apache.jetspeed.serializer.JetspeedSerializer#setComponentManager(ComponentManager)
147      */
148     public final void setComponentManager(ComponentManager cm)
149     {
150         this.cm = cm;
151     }
152 
153     /*
154      * (non-Javadoc)
155      * 
156      * @see org.apache.jetspeed.serializer.JetspeedSerializer#closeUp()
157      */
158     public final void closeUp()
159     {
160         if (cm != null) cm.stop();
161         cm = null;
162     }
163 
164     /*
165      * (non-Javadoc)
166      * 
167      * @see org.apache.jetspeed.serializer.JetspeedSerializer#setDefaultIndent(String)
168      */
169     public final void setDefaultIndent(String indent)
170     {
171         this.currentIndent = indent;
172     }
173 
174     /*
175      * (non-Javadoc)
176      * 
177      * @see org.apache.jetspeed.serializer.JetspeedSerializer#getDefaultIndent()
178      */
179     public final String getDefaultIndent()
180     {
181         return this.currentIndent;
182     }
183 
184     /*
185      * (non-Javadoc)
186      * 
187      * @see org.apache.jetspeed.serializer.JetspeedSerializer#importData(String,
188      *      Map)
189      */
190     public final  void importData(String importFileName, Map settings)
191             throws SerializerException
192     {
193         if (cm == null)
194         {
195             cm = Jetspeed.getComponentManager();
196         }        
197         /*** pre-processing homework... */
198         XMLBinding binding = new XMLBinding();
199         setupAliases(binding);
200         checkSettings(settings);
201         setSnapshot(readFile(importFileName, binding));
202         if (getSnapshot() == null)
203             throw new SerializerException(
204                     SerializerException.FILE_PROCESSING_ERROR
205                             .create(new String[]
206                             { importFileName, "Snapshot is NULL"}));
207 
208         if (!(getSnapshot().checkVersion()))
209             throw new SerializerException(
210                     SerializerException.INCOMPETIBLE_VERSION
211                             .create(new String[]
212                             {
213                                     importFileName,
214                                     String.valueOf(getSnapshot()
215                                             .getSoftwareVersion()),
216                                     String.valueOf(getSnapshot()
217                                             .getSavedSubversion())}));
218 
219         /*** ok, now we have a valid snapshot and can start processing it */
220 
221         /*** ensure we can work undisturbed */
222         synchronized (sem)
223         {
224             logMe("*********Reading data*********");
225             this.processImport();
226         }
227         return;
228     }
229 
230    
231     /*
232      * (non-Javadoc)
233      * 
234      * @see org.apache.jetspeed.serializer.JetspeedSerializer#exportData(String,String,Map)
235      */
236     public final void exportData(String name, String exportFileName, Map settings)
237             throws SerializerException
238     {
239         /*** pre-processing homework... */
240         XMLBinding binding = new XMLBinding();
241         setupAliases(binding);
242         checkSettings(settings);
243         if (cm == null)
244         {
245             cm = Jetspeed.getComponentManager();
246         }
247         /*** ensure we can work undisturbed */
248         synchronized (sem)
249         {
250             /*** get the snapshot construct */
251             this.processExport(name, binding);
252             XMLObjectWriter writer = openWriter(exportFileName);
253             writer.setBinding(binding);
254 
255             if (this.getDefaultIndent() != null)
256                 writer.setIndentation(this.getDefaultIndent());
257 
258             try
259             {
260                 logMe("*********Writing data*********");
261                 writer.write(getSnapshot(),  getSerializerDataTag(),
262                 		getSerializerDataClass());
263 
264             } catch (Exception e)
265             {
266                 throw new SerializerException(
267                         SerializerException.FILE_PROCESSING_ERROR
268                                 .create(new String[]
269                                 { exportFileName, e.getMessage()}));
270             } finally
271             {
272                 /*** ensure the writer is closed */
273                 try
274                 {
275                     logMe("*********closing up********");
276                     writer.close();
277                 } catch (Exception e)
278                 {
279                     logMe("Error in closing writer " + e.getMessage());
280                     /***
281                      * don't do anything with this exception - never let the
282                      * bubble out of the finally block
283                      */
284                 }
285             }
286         }
287         return;
288     }
289 
290     /***
291      * create a backup of the current environment in case the import fails
292      * 
293      */
294     protected final void doBackupOfCurrent(String importFileName, Map currentSettings)
295     {
296         // TODO: HJB create backup of current content
297     }
298 
299     /***
300      * read a snapshot and return the reconstructed class tree
301      * 
302      * @param importFileName
303      * @throws SerializerException
304      */
305 
306     /***
307      * read a snapshot and return the reconstructed class tree
308      * 
309      * @param importFileName
310      * @throws SerializerException
311      */
312 
313     protected final  JSSnapshot readFile(String importFileName, XMLBinding binding)
314             throws SerializerException
315     {
316         XMLObjectReader reader = null;
317         JSSnapshot snap = null;
318         try
319         {
320             reader = XMLObjectReader.newInstance(new FileInputStream(
321                     importFileName));
322         } catch (Exception e)
323         {
324             throw new SerializerException(SerializerException.FILE_READER_ERROR
325                     .create(new String[]
326                     { importFileName, e.getMessage()}));
327         }
328         try
329         {
330             if (binding != null) reader.setBinding(binding);
331             snap = (JSSnapshot) reader.read(this.getSerializerDataTag(),
332             		getSerializerDataClass());
333 
334         } catch (Exception e)
335         {
336             e.printStackTrace();
337             new SerializerException(SerializerException.FILE_PROCESSING_ERROR
338                     .create(new String[]
339                     { importFileName, e.getMessage()}));
340         } finally
341         {
342             /*** ensure the reader is closed */
343             try
344             {
345                 logMe("*********closing up reader ********");
346                 reader.close();
347             } catch (Exception e1)
348             {
349                 logMe("Error in closing reader " + e1.getMessage());
350                 /***
351                  * don't do anything with this exception - never let the bubble
352                  * out of the finally block
353                  */
354                 return null;
355             }
356         }
357         return snap;
358     }   
359     /***
360      * create or open a given file for writing
361      */
362     protected final  XMLObjectWriter openWriter(String filename)
363             throws SerializerException
364     {
365         File f;
366 
367         try
368         {
369             f = new File(filename);
370         } catch (Exception e)
371         {
372             throw new SerializerException(
373                     SerializerException.FILE_PROCESSING_ERROR
374                             .create(new String[]
375                             { filename, e.getMessage()}));
376         }
377         boolean exists = f.exists();
378 
379         if (exists)
380         {
381             if (!(this.getSetting(JetspeedSerializer.KEY_OVERWRITE_EXISTING)))
382                 throw new SerializerException(
383                         SerializerException.FILE_ALREADY_EXISTS
384                                 .create(filename));
385             if (this.getSetting(JetspeedSerializer.KEY_BACKUP_BEFORE_PROCESS))
386             {
387                 String backName = createUniqueBackupFilename(f.getName());
388                 if (backName == null)
389                     throw new SerializerException(
390                             SerializerException.FILE_BACKUP_FAILED
391                                     .create(filename));
392                 File ftemp = new File(backName);
393                 f.renameTo(ftemp);
394             }
395         }
396         try
397         {
398             XMLObjectWriter writer = XMLObjectWriter
399                     .newInstance(new FileOutputStream(filename));
400             return writer;
401         } catch (Exception e)
402         {
403             throw new SerializerException(SerializerException.FILE_WRITER_ERROR
404                     .create(new String[]
405                     { filename, e.getMessage()}));
406         }
407     }
408 
409     /***
410      * returns the key for a particular process setting. False if the key
411      * doesn't exist.
412      * 
413      * @param key
414      * @return
415      */
416     public final boolean getSetting(String key)
417     {
418         Object o = processSettings.get(key);
419         if ((o == null) || (!(o instanceof Boolean))) return false;
420         return ((Boolean) o).booleanValue();
421     }
422 
423     /***
424      * set a process setting for a given key
425      * 
426      * @param key
427      *            instruction to set
428      * @param value
429      *            true or false
430      */
431     protected final void setSetting(String key, boolean value)
432     {
433         processSettings.put(key, (value ? Boolean.TRUE : Boolean.FALSE));
434     }
435 
436 
437     /***
438      * set instruction flags to new settings
439      * 
440      * @param settings
441      */
442     protected final void checkSettings(Map settings)
443     {
444         /*** ensure we don't have settings from a previous run */
445         resetSettings();
446         /*** process the new isntructionSet */
447         if ((settings == null) || (settings.size() == 0)) return;
448         Iterator _it = settings.keySet().iterator();
449         while (_it.hasNext())
450         {
451             try
452             {
453                 String key = (String) _it.next();
454                 Object o = settings.get(key);
455                 if ((o != null) && (o instanceof Boolean))
456                     setSetting(key, ((Boolean) o).booleanValue());
457             } catch (Exception e)
458             {
459                 log.error("checkSettings", e);
460             }
461         }
462     }
463 
464     /***
465      * On import, get the basic SnapShot data
466      * 
467      */
468     protected void getSnapshotData()
469     {
470         logMe("date created : " + getSnapshot().getDateCreated());
471         logMe("software Version : " + getSnapshot().getSavedVersion());
472         logMe("software SUbVersion : " + getSnapshot().getSavedSubversion());
473     }
474 
475     /***
476      * On export, set the basic SnapShot data
477      * 
478      */
479     protected void setSnapshotData()
480     {
481     	java.util.Date d1 = new java.util.Date();
482         Date d = new Date(d1.getTime());
483         getSnapshot().setDateCreated(d.toString());
484         getSnapshot().setSavedVersion(getSnapshot().getSoftwareVersion());
485         getSnapshot().setSavedSubversion(getSnapshot().getSoftwareSubVersion());
486     }
487 
488 
489 
490  
491     /***
492      * simple lookup for object from a map
493      * @param map
494      * @param _fullPath
495      * @return
496      */
497     protected final Object getObjectBehindPath(Map map, String _fullPath)
498     {
499         return map.get(_fullPath);
500     }
501 
502     
503     /***
504      * ++++++++++++++++++++++++++++++HELPERS
505      * +++++++++++++++++++++++++++++++++++++++++++++
506      */
507 
508     /***
509      * remove a given sequence from the beginning of a string
510      */
511     protected final String removeFromString(String base, String excess)
512     {
513         return base.replaceFirst(excess, "").trim();
514     }
515 
516     /***
517      * 
518      * just a Simple helper to make code more readable
519      * 
520      * @param text
521      */
522     protected final void logMe(String text)
523     {
524         if (log.isDebugEnabled()) 
525             log.debug(text);
526     }
527 
528     /***
529      * Helper routine to create a unique filename for a backup of an existing
530      * filename....not intended to be rocket science...
531      * 
532      * @param name
533      * @return
534      */
535     protected final String createUniqueBackupFilename(String name)
536     {
537         String newName = name + ".bak";
538 
539         File f = new File(newName);
540         int counter = 0;
541         if (!(f.exists())) return newName;
542         while (counter < 100)
543         {
544             String newName1 = newName + counter;
545             if (!(new File(newName1).exists())) return newName1;
546             counter++;
547         }
548         return null;
549     }
550 
551  /***
552   * convert a list of elements in a string, seperated by ',' into an arraylist of strings
553   * @param _line Strinbg containing one or more elements seperated by ','
554   * @return list of elements of null
555   */    
556     protected final ArrayList getTokens(String _line)
557     {
558         if ((_line == null) || (_line.length() == 0)) return null;
559 
560         StringTokenizer st = new StringTokenizer(_line, ",");
561         ArrayList list = new ArrayList();
562 
563         while (st.hasMoreTokens())
564             list.add(st.nextToken());
565         return list;
566     }
567 
568 
569     protected final String recreatePassword(char[] savedPassword)
570 	{
571 		if (savedPassword == null)
572 			return null;
573 		return new String(savedPassword);
574 	}
575 
576     
577     /***
578      * reset instruction flags to default settings (all true)
579      * 
580      */
581     protected abstract void resetSettings();
582 
583     
584     /***
585      * The workhorse for exporting data
586      * 
587      * @param binding
588      *            established XML binding
589      * @return
590      * @throws SerializerException
591      */
592     protected abstract void processExport(String name, XMLBinding binding)
593             throws SerializerException; 
594 
595     /***
596      * The workhorse for importing data
597      * 
598      * @param binding
599      *            established XML binding
600      * @return
601      * @throws SerializerException
602      */
603     protected abstract  void processImport() throws SerializerException;
604 
605     /***
606      * Setup the binding for the different classes, mapping each extracted class
607      * to a unique tag name in the XML
608      * 
609      * @param binding
610      */
611     protected abstract void setupAliases(XMLBinding binding);
612 
613     
614 	/***
615 	 * return the class for the serializer data , for example JSSeedData.class)
616 	 * 
617 	 * @return
618 	 */    
619     protected abstract Class getSerializerDataClass();
620 
621 
622 	/***
623 	 * return the XML tag for the serializer data , for example "JSSnapShot")
624 	 * 
625 	 * @return
626 	 */    
627     protected abstract String getSerializerDataTag();
628 
629 	public JSSnapshot getSnapshot()
630 	{
631 		return snapshot;
632 	}
633 
634 
635 
636 	public void setSnapshot(JSSnapshot snapshot)
637 	{
638 		this.snapshot = snapshot;
639 	}
640 
641 }