001: /*
002: * All content copyright (c) 2003-2006 Terracotta, Inc., except as may otherwise be noted in a separate copyright notice. All rights reserved.
003: */
004: package com.tc.object.tools;
005:
006: import org.apache.commons.io.FileUtils;
007:
008: import java.io.File;
009: import java.io.FileInputStream;
010: import java.io.FileOutputStream;
011: import java.io.IOException;
012: import java.io.InputStream;
013: import java.io.OutputStream;
014: import java.util.jar.JarEntry;
015: import java.util.jar.JarInputStream;
016: import java.util.jar.JarOutputStream;
017: import java.util.jar.Manifest;
018:
019: public class BootJarHandler {
020: private final boolean write_out_temp_file;
021: private final File outputFile;
022: private final File tempOutputFile;
023: private final String tempOutputFileAbsPath;
024: private final String outputFileAbsPath;
025:
026: public BootJarHandler(boolean write_out_temp_file, File outputFile) {
027: this .write_out_temp_file = write_out_temp_file;
028: this .outputFile = outputFile;
029: outputFileAbsPath = this .outputFile.getAbsolutePath();
030: if (this .write_out_temp_file) {
031: try {
032: tempOutputFile = File
033: .createTempFile("tc-bootjar", null);
034: tempOutputFileAbsPath = tempOutputFile
035: .getAbsolutePath();
036: tempOutputFile.deleteOnExit();
037: } catch (IOException e) {
038: throw new RuntimeException(e);
039: }
040: } else {
041: tempOutputFile = null;
042: tempOutputFileAbsPath = "";
043: }
044: }
045:
046: public void validateDirectoryExists()
047: throws BootJarHandlerException {
048: try {
049: FileUtils.forceMkdir(outputFile.getAbsoluteFile()
050: .getParentFile());
051: } catch (IOException ioe) {
052: throw new BootJarHandlerException("Failed to create path:"
053: + outputFile.getParentFile().getAbsolutePath(), ioe);
054: }
055:
056: if (write_out_temp_file) {
057: try {
058: FileUtils.forceMkdir(tempOutputFile.getAbsoluteFile()
059: .getParentFile());
060: } catch (IOException ioe) {
061: throw new BootJarHandlerException(
062: "Failed to create path:"
063: + tempOutputFile.getParentFile()
064: .getAbsolutePath(), ioe);
065: }
066: }
067: }
068:
069: public void announceCreationStart() {
070: announce("Creating boot JAR at '" + outputFileAbsPath + "...");
071: }
072:
073: public BootJar getBootJar() throws UnsupportedVMException {
074: if (write_out_temp_file) {
075: return BootJar.getBootJarForWriting(this .tempOutputFile);
076: } else {
077: return BootJar.getBootJarForWriting(this .outputFile);
078: }
079: }
080:
081: public String getCreationErrorMessage() {
082: if (write_out_temp_file) {
083: return "ERROR creating temp boot jar";
084: }
085: return "ERROR creating boot jar";
086: }
087:
088: public String getCloseErrorMessage() {
089: if (write_out_temp_file) {
090: return "Failed to create temp jar file:"
091: + tempOutputFileAbsPath;
092: }
093: return "Failed to create jar file:" + outputFileAbsPath;
094: }
095:
096: public void announceCreationEnd() throws BootJarHandlerException {
097: if (write_out_temp_file) {
098: createFinalBootJar();
099: }
100: announce("Successfully created boot JAR file at '"
101: + outputFileAbsPath + "'.");
102: }
103:
104: private void createFinalBootJar() throws BootJarHandlerException {
105: announceCreationStart();
106: try {
107: JarInputStream jarIn = new JarInputStream(
108: new FileInputStream(tempOutputFile
109: .getAbsolutePath()));
110: Manifest manifest = jarIn.getManifest();
111: if (manifest == null) {
112: manifest = new Manifest();
113: }
114:
115: File tempFile = File.createTempFile("tc-bootjar", null);
116: tempFile.deleteOnExit();
117:
118: JarOutputStream jarOut = new JarOutputStream(
119: new FileOutputStream(tempFile.getAbsolutePath()),
120: manifest);
121: byte[] buffer = new byte[4096];
122: JarEntry entry;
123: while ((entry = jarIn.getNextJarEntry()) != null) {
124: if ("META-INF/MANIFEST.MF".equals(entry.getName())) {
125: continue;
126: }
127: jarOut.putNextEntry(entry);
128: int read;
129: while ((read = jarIn.read(buffer)) != -1) {
130: jarOut.write(buffer, 0, read);
131: }
132: jarOut.closeEntry();
133: }
134: jarOut.flush();
135: jarOut.close();
136: jarIn.close();
137:
138: copyFile(tempFile, outputFile);
139: } catch (Exception e) {
140: throw new BootJarHandlerException(
141: "ERROR creating boot jar", e);
142: }
143: if (!tempOutputFile.delete()) {
144: announce("Warning: Unsuccessful deletion of temp boot JAR file at '"
145: + tempOutputFileAbsPath + "'.");
146: }
147: }
148:
149: private void announce(String msg) {
150: System.out.println(msg);
151: }
152:
153: private void copyFile(File src, File dest) throws IOException {
154: if (dest.isDirectory()) {
155: dest = new File(dest, src.getName());
156: }
157:
158: File tmplck = null;
159: InputStream in = null;
160: OutputStream out = null;
161: try {
162: // wait until it's okay to copy over the bootjar
163: tmplck = new File(dest.getParentFile(), "tc-bootjar.lck");
164: while (tmplck.exists()) {
165: try {
166: Thread.sleep(1000);
167: } catch (InterruptedException e) {
168: //throw e;
169: }
170: }
171:
172: // block everyone else from copying over their bootjar
173: tmplck.createNewFile();
174: tmplck.deleteOnExit();
175:
176: // copy our new bootjar file over into a temporary file
177: File tmpdest = File.createTempFile("tc-bootjar", null, dest
178: .getParentFile());
179: out = new FileOutputStream(tmpdest);
180: in = new FileInputStream(src);
181:
182: byte[] buffer = new byte[4096];
183: int bytesRead;
184:
185: while ((bytesRead = in.read(buffer)) >= 0) {
186: out.write(buffer, 0, bytesRead);
187: }
188:
189: in.close();
190: in = null;
191:
192: out.close();
193: out = null;
194:
195: // remove any existing bootjar...
196: if (dest.exists() && !dest.delete()) {
197: throw new IOException("Unable to delete '" + dest + "'");
198: }
199:
200: // ... and replace it with the one that we just copied over
201: if (!tmpdest.renameTo(dest)) {
202: throw new IOException("Unable to rename '" + tmpdest
203: + "' to '" + dest + "'");
204: }
205: } finally {
206: // house keeping
207: if (in != null)
208: in.close();
209: if (out != null)
210: out.close();
211:
212: // now signal that it's okay for the other clients to copy over their bootjar
213: tmplck.delete();
214: }
215: }
216: }
|