001: package org.andromda.core.common;
002:
003: import java.io.BufferedInputStream;
004: import java.io.BufferedOutputStream;
005: import java.io.ByteArrayInputStream;
006: import java.io.File;
007: import java.io.FileOutputStream;
008: import java.io.IOException;
009: import java.io.InputStream;
010: import java.io.OutputStream;
011: import java.net.URL;
012:
013: import org.apache.commons.lang.StringUtils;
014:
015: /**
016: * Used for writing resources for the framework. Also keeps histories of
017: * previous resources generated so that we can avoid regenerating if the
018: * generated resources are current.
019: *
020: * @author Chad Brandon
021: */
022: public class ResourceWriter {
023: /**
024: * The shared instance
025: */
026: private static final ResourceWriter instance = new ResourceWriter();
027:
028: /**
029: * Gets the shared ResourceWriter instance. Normally you'll want to retrieve
030: * the instance through this method.
031: *
032: * @return the shared instance.
033: */
034: public static ResourceWriter instance() {
035: return instance;
036: }
037:
038: /**
039: * Writes the string to the file specified by the fileLocation argument.
040: *
041: * @param string the string to write to the file
042: * @param file the file to which to write.
043: * @param namespace the current namespace for which this resource is being
044: * written.
045: * @throws IOException
046: */
047: public void writeStringToFile(final String string, final File file,
048: final String namespace) throws IOException {
049: ExceptionUtils.checkNull("file", file);
050: this
051: .writeStringToFile(string, file.toString(), namespace,
052: true);
053: }
054:
055: /**
056: * Writes the string to the file specified by the fileLocation argument.
057: *
058: * @param string the string to write to the file
059: * @param fileLocation the location of the file which to write.
060: */
061: public void writeStringToFile(final String string,
062: final String fileLocation) throws IOException {
063: this .writeStringToFile(string, fileLocation, true);
064: }
065:
066: /**
067: * Writes the string to the file specified by the fileLocation argument.
068: *
069: * @param string the string to write to the file
070: * @param file the file which to write.
071: */
072: public void writeStringToFile(final String string, final File file)
073: throws IOException {
074: this .writeStringToFile(string, file != null ? file.toString()
075: : null, true);
076: }
077:
078: /**
079: * Writes the string to the file specified by the fileLocation argument.
080: *
081: * @param string the string to write to the file
082: * @param fileLocation the location of the file which to write.
083: * @param recordHistory whether or not the history of the file should be
084: * recorded.
085: */
086: private void writeStringToFile(final String string,
087: final String fileLocation, final boolean recordHistory)
088: throws IOException {
089: this .writeStringToFile(string, fileLocation, null,
090: recordHistory);
091: }
092:
093: /**
094: * Writes the string to the file specified by the fileLocation argument.
095: *
096: * @param string the string to write to the file
097: * @param fileLocation the location of the file which to write.
098: * @param namespace the current namespace for which this resource is being
099: * written.
100: * @throws IOException
101: */
102: public void writeStringToFile(final String string,
103: final String fileLocation, final String namespace)
104: throws IOException {
105: this .writeStringToFile(string, fileLocation, namespace, true);
106: }
107:
108: /**
109: * Writes the string to the file specified by the fileLocation argument.
110: *
111: * @param string the string to write to the file
112: * @param fileLocation the location of the file which to write.
113: * @param namespace the current namespace for which this resource is being
114: * written.
115: * @param recordHistory whether or not the history of this file should be
116: * recorded.
117: * @throws IOException
118: */
119: private void writeStringToFile(String string,
120: final String fileLocation, final String namespace,
121: final boolean recordHistory) throws IOException {
122: if (string == null) {
123: string = "";
124: }
125: ExceptionUtils.checkEmpty("fileLocation", fileLocation);
126: final File file = new File(fileLocation);
127: ResourceUtils.makeDirectories(fileLocation);
128: final Merger merger = Merger.instance();
129: if (merger.requiresMerge(namespace)) {
130: string = Merger.instance().getMergedString(string,
131: namespace);
132: }
133: final OutputStream stream = new BufferedOutputStream(
134: new FileOutputStream(file));
135: byte[] output;
136: if (StringUtils.isNotBlank(this .encoding)) {
137: output = string.getBytes(this .encoding);
138: } else {
139: output = string.getBytes();
140: }
141: final InputStream inputStream = new BufferedInputStream(
142: new ByteArrayInputStream(output));
143: for (int ctr = inputStream.read(); ctr != -1; ctr = inputStream
144: .read()) {
145: stream.write(ctr);
146: }
147: inputStream.close();
148: stream.flush();
149: stream.close();
150: if (recordHistory) {
151: this .recordHistory(file);
152: }
153: }
154:
155: /**
156: * Writes the URL contents to a file specified by the fileLocation argument.
157: *
158: * @param url the URL to read
159: * @param fileLocation the location which to write.
160: */
161: public void writeUrlToFile(final URL url, final String fileLocation)
162: throws IOException {
163: ResourceUtils.writeUrlToFile(url, fileLocation, this .encoding);
164: this .recordHistory(new File(fileLocation));
165: }
166:
167: /**
168: * Stores the encoding to be used for output.
169: */
170: private String encoding = null;
171:
172: /**
173: * Sets the encoding to which all output written from this class will be
174: * written.
175: *
176: * @param encoding the encoding type (UTF-8, ISO-8859-1, etc).
177: */
178: public void setEncoding(String encoding) {
179: this .encoding = encoding;
180: }
181:
182: private StringBuffer history = new StringBuffer();
183:
184: /**
185: * Resets the a history file, to write the history {@link #writeHistory()} must be called.
186: *
187: * @param modelUri used to construct the file name from the modelUri where the history is stored
188: */
189: public void resetHistory(final String modelUri) {
190: String modelFile = modelUri.replace('\\', '/');
191: int lastSlash = modelFile.lastIndexOf('/');
192: if (lastSlash != -1) {
193: modelFile = modelFile.substring(lastSlash + 1, modelFile
194: .length());
195: }
196: this .modelFile = modelFile;
197: this .history = new StringBuffer();
198: this .writtenCount = 0;
199: }
200:
201: private String modelFile = null;
202:
203: /**
204: * Stores the count of the resources written over this instance's history.
205: */
206: private long writtenCount = 0;
207:
208: /**
209: * Gets the number of currently written resources over the course of this instance's history.
210: *
211: * @return the number of written resources.
212: */
213: public long getWrittenCount() {
214: return this .writtenCount;
215: }
216:
217: /**
218: * The location to which history is written.
219: */
220: private static final String HISTORY_LOCATION = Constants.TEMPORARY_DIRECTORY
221: + "history/";
222:
223: /**
224: * Stores the file history.
225: */
226: private String getHistoryStorage() {
227: return HISTORY_LOCATION + this .modelFile;
228: }
229:
230: /**
231: * Writes the output history to disk.
232: *
233: * @throws IOException
234: */
235: public void writeHistory() throws IOException {
236: writeStringToFile(history.toString(), getHistoryStorage(),
237: false);
238: }
239:
240: /**
241: * Writes the string to the file specified by the fileLocation argument.
242: *
243: * @param file the file to which to record the history to
244: */
245: private void recordHistory(File file) {
246: if (this .history != null) {
247: this .history.append(file).append(',');
248: }
249: this .writtenCount++;
250: }
251:
252: /**
253: * Checks to see if the history is before the given <code>time</code>.
254: *
255: * @param time the time in milliseconds to check against.
256: * @return true/false
257: */
258: public boolean isHistoryBefore(long time) {
259: boolean before = true;
260: try {
261: final File historyFile = new File(getHistoryStorage());
262: if (historyFile.exists()
263: && historyFile.lastModified() >= time) {
264: final String history = ResourceUtils
265: .getContents(new File(getHistoryStorage())
266: .toURL());
267: final String[] files = history.split(",");
268: long lastModified = 0;
269: for (int ctr = 0; ctr < files.length; ctr++) {
270: final String fileString = StringUtils
271: .trimToEmpty(files[ctr]);
272: if (StringUtils.isNotEmpty(fileString)) {
273: File file = new File(fileString);
274:
275: // if we find one file that doesn't exist then
276: // before is automatically false
277: if (!file.exists()) {
278: lastModified = 0;
279: break;
280: }
281: if (file.lastModified() > lastModified) {
282: lastModified = file.lastModified();
283: }
284: }
285: }
286: before = time > lastModified;
287: }
288: } catch (IOException ex) {
289: before = true;
290: }
291: return before;
292: }
293: }
|