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