View Javadoc
1   package org.andromda.core.common;
2   
3   import java.io.File;
4   import java.io.IOException;
5   import java.net.URL;
6   import org.apache.commons.io.FileUtils;
7   import org.apache.commons.lang.StringUtils;
8   
9   /**
10   * Used for writing resources for the framework. Also keeps histories of
11   * previous resources generated so that we can avoid regenerating if the
12   * generated resources are current.
13   *
14   * @author Chad Brandon
15   * @author Bob Fields
16   */
17  public class ResourceWriter
18  {
19      /**
20       * The shared instance
21       */
22      private static final ResourceWriter instance = new ResourceWriter();
23  
24      /**
25       * Gets the shared ResourceWriter instance. Normally you'll want to retrieve
26       * the instance through this method.
27       *
28       * @return the shared instance.
29       */
30      public static ResourceWriter instance()
31      {
32          return instance;
33      }
34  
35      /**
36       * Writes the string to the file specified by the fileLocation argument.
37       *
38       * @param string the string to write to the file
39       * @param file the file to which to write.
40       * @param namespace the current namespace for which this resource is being
41       *        written.
42       * @throws IOException
43       */
44      public void writeStringToFile(
45          final String string,
46          final File file,
47          final String namespace)
48          throws IOException
49      {
50          ExceptionUtils.checkNull(
51              "file",
52              file);
53          this.writeStringToFile(
54              string,
55              file.toString(),
56              namespace,
57              true);
58      }
59  
60      /**
61       * Writes the string to the file specified by the fileLocation argument.
62       *
63       * @param string the string to write to the file
64       * @param fileLocation the location of the file which to write.
65       * @throws IOException
66       */
67      public void writeStringToFile(
68          final String string,
69          final String fileLocation)
70          throws IOException
71      {
72          this.writeStringToFile(
73              string,
74              fileLocation,
75              true);
76      }
77  
78      /**
79       * Writes the string to the file specified by the fileLocation argument.
80       *
81       * @param string the string to write to the file
82       * @param file the file which to write.
83       * @throws IOException
84       */
85      public void writeStringToFile(
86          final String string,
87          final File file)
88          throws IOException
89      {
90          this.writeStringToFile(
91              string,
92              file != null ? file.toString() : null,
93              true);
94      }
95  
96      /**
97       * Writes the string to the file specified by the fileLocation argument.
98       *
99       * @param string the string to write to the file
100      * @param fileLocation the location of the file which to write.
101      * @param recordHistory whether or not the history of the file should be
102      *        recorded.
103      */
104     private void writeStringToFile(
105         final String string,
106         final String fileLocation,
107         final boolean recordHistory)
108         throws IOException
109     {
110         this.writeStringToFile(
111             string,
112             fileLocation,
113             null,
114             recordHistory);
115     }
116 
117     /**
118      * Writes the string to the file specified by the fileLocation argument.
119      *
120      * @param string the string to write to the file
121      * @param fileLocation the location of the file which to write.
122      * @param namespace the current namespace for which this resource is being
123      *        written.
124      * @throws IOException
125      */
126     public void writeStringToFile(
127         final String string,
128         final String fileLocation,
129         final String namespace)
130         throws IOException
131     {
132         this.writeStringToFile(
133             string,
134             fileLocation,
135             namespace,
136             true);
137     }
138 
139     /**
140      * Writes the string to the file specified by the fileLocation argument.
141      *
142      * @param string the string to write to the file
143      * @param fileLocation the location of the file which to write.
144      * @param namespace the current namespace for which this resource is being
145      *        written.
146      * @param recordHistory whether or not the history of this file should be
147      *        recorded.
148      * @throws IOException
149      */
150     private void writeStringToFile(
151         String string,
152         final String fileLocation,
153         final String namespace,
154         final boolean recordHistory)
155         throws IOException
156     {
157         if (string == null)
158         {
159             string = "";
160         }
161         ExceptionUtils.checkEmpty(
162             "fileLocation",
163             fileLocation);
164 
165         ResourceUtils.makeDirectories(fileLocation);
166         final Merger merger = Merger.instance();
167         if (merger.requiresMerge(namespace))
168         {
169             string = Merger.instance().getMergedString(
170                     string,
171                     namespace);
172         }
173 
174         final File file = new File(fileLocation);
175         FileUtils.writeStringToFile(file, string, this.encoding);
176 
177         if (recordHistory)
178         {
179             this.recordHistory(file);
180         }
181     }
182 
183     /**
184      * Writes the URL contents to a file specified by the fileLocation argument.
185      *
186      * @param url the URL to read
187      * @param fileLocation the location which to write.
188      * @throws IOException
189      */
190     public void writeUrlToFile(
191         final URL url,
192         final String fileLocation)
193         throws IOException
194     {
195         ResourceUtils.writeUrlToFile(url, fileLocation);
196         this.recordHistory(new File(fileLocation));
197     }
198 
199     /**
200      * Stores the encoding to be used for output.
201      */
202     private String encoding = null;
203 
204     /**
205      * Sets the encoding to which all output written from this class will be
206      * written.
207      *
208      * @param encoding the encoding type (UTF-8, ISO-8859-1, etc).
209      */
210     public void setEncoding(String encoding)
211     {
212         this.encoding = StringUtils.trimToNull(encoding);
213     }
214 
215     private StringBuffer history = new StringBuffer();
216 
217     /**
218      * Resets the a history file, to write the history {@link #writeHistory()} must be called.
219      *
220      * @param modelUri used to construct the file name from the modelUri where the history is stored
221      */
222     public void resetHistory(final String modelUri)
223     {
224         String modelFile = modelUri.replace(
225                 '\\',
226                 '/');
227         int lastSlash = modelFile.lastIndexOf('/');
228         if (lastSlash != -1)
229         {
230             modelFile = modelFile.substring(
231                     lastSlash + 1,
232                     modelFile.length());
233         }
234         this.modelFile = modelFile;
235         this.history = new StringBuffer();
236         this.writtenCount = 0;
237     }
238 
239     private String modelFile = null;
240 
241     /**
242      * Stores the count of the resources written over this instance's history.
243      */
244     private long writtenCount = 0;
245 
246     /**
247      * Gets the number of currently written resources over the course of this instance's history.
248      *
249      * @return the number of written resources.
250      */
251     public long getWrittenCount()
252     {
253         return this.writtenCount;
254     }
255 
256     /**
257      * The location to which history is written.
258      */
259     //private static final String HISTORY_LOCATION = Constants.TEMPORARY_DIRECTORY + "history/";
260     private String historyDir = null;
261 
262     /**
263      * Gets the file history storage location.
264      * @return model generation history storage location
265      */
266     public String getHistoryStorage()
267     {
268         return this.historyDir + '/' + this.modelFile;
269     }
270 
271     /**
272      * Sets the file history storage location.
273      * @param historyDirIn the history file storage location
274      */
275     public void setHistoryStorage(String historyDirIn)
276     {
277         this.historyDir = historyDirIn;
278     }
279 
280     /**
281      * Writes the output history to disk.
282      *
283      * @throws IOException
284      */
285     public void writeHistory()
286         throws IOException
287     {
288         writeStringToFile(
289             history.toString(),
290             getHistoryStorage(),
291             false);
292     }
293 
294     /**
295      * Writes the string to the file specified by the fileLocation argument.
296      *
297      * @param file the file to which to record the history to
298      */
299     private void recordHistory(File file)
300     {
301         // Resource files may be merged multiple times to the temp directory, before the final output file is written
302         if (this.history != null && !file.getName().endsWith(".vsl"))
303         {
304             this.history.append(file).append(',');
305         }
306         this.writtenCount++;
307     }
308 
309     /**
310      * Checks to see if the history is before the given <code>time</code>.
311      *
312      * @param time the time in milliseconds to check against.
313      * @return true/false
314      */
315     public boolean isHistoryBefore(long time)
316     {
317         boolean before = true;
318         try
319         {
320             final File historyFile = new File(getHistoryStorage());
321             if (historyFile.exists() && historyFile.lastModified() >= time)
322             {
323                 final String history = ResourceUtils.getContents(new File(getHistoryStorage()).toURI().toURL());
324                 final String[] fileNames = history.split(",");
325                 long lastModified = 0;
326                 for (String fileName : fileNames)
327                 {
328                     if (StringUtils.isNotBlank(fileName))
329                     {
330                         File file = new File(fileName.trim());
331 
332                         // if we find one file that doesn't exist then
333                         // before is automatically false
334                         if (!file.exists())
335                         {
336                             lastModified = 0;
337                             break;
338                         }
339                         if (file.lastModified() > lastModified)
340                         {
341                             lastModified = file.lastModified();
342                         }
343                     }
344                 }
345                 before = time > lastModified;
346             }
347         }
348         catch (IOException ex)
349         {
350             before = true;
351         }
352         return before;
353     }
354 }