View Javadoc

1   /*
2    * Copyright (c) 2005 Regents of the University of California (Regents). Created
3    * by TELS, Graduate School of Education, University of California at Berkeley.
4    *
5    * This software is distributed under the GNU Lesser General Public License, v2.
6    *
7    * Permission is hereby granted, without written agreement and without license
8    * or royalty fees, to use, copy, modify, and distribute this software and its
9    * documentation for any purpose, provided that the above copyright notice and
10   * the following two paragraphs appear in all copies of this software.
11   *
12   * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
13   * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
14   * PURPOSE. THE SOFTWAREAND ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED
15   * HEREUNDER IS PROVIDED "AS IS". REGENTS HAS NO OBLIGATION TO PROVIDE
16   * MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
17   *
18   * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
19   * SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS,
20   * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
21   * REGENTS HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
22   */
23  package net.sf.sail.core.util;
24  
25  import java.io.BufferedOutputStream;
26  import java.io.ByteArrayInputStream;
27  import java.io.File;
28  import java.io.FileNotFoundException;
29  import java.io.FileOutputStream;
30  import java.io.IOException;
31  import java.io.InputStream;
32  import java.io.OutputStream;
33  import java.net.JarURLConnection;
34  import java.net.MalformedURLException;
35  import java.net.URL;
36  import java.text.DecimalFormat;
37  import java.util.Date;
38  import java.util.Enumeration;
39  import java.util.jar.JarEntry;
40  import java.util.jar.JarFile;
41  import java.util.jar.JarOutputStream;
42  import java.util.logging.Logger;
43  import java.util.zip.ZipEntry;
44  import java.util.zip.ZipOutputStream;
45  
46  import net.sf.sail.common.apps.PreviewCurnitFile;
47  import net.sf.sail.core.beans.Pod;
48  import net.sf.sail.core.beans.UnknownPodException;
49  import net.sf.sail.core.curnit.Curnit;
50  import net.sf.sail.core.curnit.CurnitArchive;
51  import net.sf.sail.core.curnit.CurnitArchiveResolver;
52  import net.sf.sail.core.curnit.CurnitFile;
53  import net.sf.sail.core.curnit.PodArchiveResolver;
54  import net.sf.sail.core.uuid.CurnitUuid;
55  import net.sf.sail.core.uuid.PodUuid;
56  
57  import org.apache.commons.io.IOUtils;
58  
59  /**
60   * 
61   * @author turadg
62   * AUDIT07-
63   */
64  public class BinaryUtils {
65  	/**
66  	 * Logger for this class
67  	 */
68  	private static final Logger logger = Logger.getLogger(BinaryUtils.class
69  			.getName());
70  
71  	/**
72  	 * Takes a URL that points to a resource within a JAR, unzips it onto the
73  	 * filesystem, and returns a file: url to it
74  	 * 
75  	 * @param location
76  	 *            points to a resource within a JAR
77  	 * @return file: URL to the specified jar: URL resource
78  	 * @throws IOException
79  	 */
80  	public static URL toFileUrl(URL location) throws IOException {
81  		String protocol = location.getProtocol().intern();
82  		if (protocol != "jar")
83  			throw new IOException("cannot explode " + location);
84  
85  		JarURLConnection juc = (JarURLConnection) location.openConnection();
86  
87  		String path = juc.getEntryName();
88  
89  		String parentPath = parentPathOf(path);
90  
91  		File tempDir = createTempDir("jartemp");
92  
93  		JarFile jarFile = juc.getJarFile();
94  		for (Enumeration<JarEntry> en = jarFile.entries(); en.hasMoreElements();) {
95  			ZipEntry entry = en.nextElement();
96  			if (entry.isDirectory())
97  				continue;
98  			String entryPath = entry.getName();
99  			if (entryPath.startsWith(parentPath)) {
100 				File dest = new File(tempDir, entryPath);
101 				dest.getParentFile().mkdirs();
102 				InputStream in = jarFile.getInputStream(entry);
103 				OutputStream out = new FileOutputStream(dest);
104 				IOUtils.copy(in, out);
105 				// Tell JVM to delete these files on exit,
106 				// we don't want to slowly be building up files on the local
107 				// machine
108 				dest.deleteOnExit();
109 			}
110 		}
111 
112 		File realFile = new File(tempDir, path);
113 		return realFile.toURL();
114 	}
115 
116 	/**
117 	 * @param path
118 	 * @return
119 	 */
120 	private static String parentPathOf(String path) {
121 		int from = 0;
122 		int to = path.indexOf("/");
123 		if (to < 0)
124 			return "";
125 		String parentPath = path.substring(from, to);
126 		return parentPath;
127 	}
128 
129 	/**
130 	 * @param tempDirName
131 	 *            TODO
132 	 * @throws IOException
133 	 */
134 	public static File createTempDir(String tempDirName) throws IOException {
135 		File tempDir = File.createTempFile("sail-" + tempDirName, "dir");
136 		boolean success = tempDir.delete();
137 		if (!success || tempDir.exists()) {
138 			throw new IOException(
139 					"Failed to delete file to be converted to dir");
140 		}
141 
142 		success = tempDir.mkdirs();
143 		if (!success || !tempDir.isDirectory()) {
144 			throw new IOException("failed to create temp dir");
145 		}
146 
147 		// Tell JVM to clean this up when we are done
148 		tempDir.deleteOnExit();
149 		return tempDir;
150 	}
151 
152 	public static URL makeJarUrl(URL jarUrl, String pathInJar) {
153 		try {
154 			return new URL("jar:" + jarUrl + "!/" + pathInJar);
155 		} catch (MalformedURLException e) {
156 			// this shouldn't be possible
157 			throw new RuntimeException(e);
158 		}
159 	}
160 
161 	/**
162 	 * @param externalForm
163 	 * @return
164 	 * @throws IOException
165 	 */
166 	public static File tempFileForUrl(String externalForm) throws IOException {
167 		URL url = new URL(externalForm);
168 		return tempFileForUrl(url);
169 	}
170 
171 	/**
172 	 * @param curnitArchiveUrl
173 	 * @param deleteOnExit
174 	 * @return
175 	 * @throws IOException
176 	 */
177 	public static File tempFileForUrl(URL url, boolean deleteOnExit) throws IOException {
178 		File tempFile = File.createTempFile("tempFileForUrl-", ".jar");
179 		// delete the temp files on exit
180 		// might need to be overridden
181 		if (deleteOnExit) {
182 			tempFile.deleteOnExit();
183 		}
184 		org.apache.commons.io.FileUtils.copyURLToFile(url, tempFile);
185 		return tempFile;
186 	}
187 	
188 	/**
189 	 * @param curnitArchiveUrl
190 	 * @return
191 	 * @throws IOException
192 	 */
193 	public static File tempFileForUrl(URL url) throws IOException {
194 		return tempFileForUrl(url, true);
195 	}
196 
197 	/**
198 	 * @param path
199 	 * @return
200 	 * @throws IOException
201 	 */
202 	public static File fileForCommandArgument(String path) throws IOException {
203 		if (path.startsWith("http://")) {
204 			logger.info("opening url " + path); //$NON-NLS-1$
205 			return tempFileForUrl(path);
206 		}
207 
208 		logger.info("opening file " + path); //$NON-NLS-1$
209 		return new File(path);
210 	}
211 
212 	/**
213 	 * @param path
214 	 * @return
215 	 * @throws IOException
216 	 */
217 	public static URL urlForCommandArgument(String path) throws IOException {
218 		if (path.startsWith("http://")) {
219 			logger.info("opening url " + path); //$NON-NLS-1$
220 			return new URL(path);
221 		}
222 
223 		logger.info("opening file " + path); //$NON-NLS-1$
224 		return new File(path).toURL();
225 	}
226 
227 	public static URL addToArchive(Pod pod,
228 			ZipOutputStream podArchiveOutputStream, String filename,
229 			InputStream source) throws IOException {
230 		ZipEntry entry = new ZipEntry(filename);
231 		podArchiveOutputStream.putNextEntry(entry);
232 		IOUtils.copy(source, podArchiveOutputStream);
233 		podArchiveOutputStream.closeEntry();
234 		return PodArchiveResolver.withinPodArchive(pod, filename);
235 	}
236 
237 	/**
238 	 * Note: ignores the previous archive associated with the pod
239 	 * 
240 	 * @param pod
241 	 * @return a new JarOutputStream to which to write to the new archive
242 	 * @throws IOException
243 	 */
244 	public static JarOutputStream newPodArchiveFor(Pod pod) throws IOException {
245 		File podArchiveFile = File.createTempFile("podarchive", ".jar");
246 		PodArchiveResolver.getSystemResolver().put(pod.getPodId(),
247 				podArchiveFile.toURL());
248 		JarOutputStream podArchiveOut = new JarOutputStream(
249 				new FileOutputStream(podArchiveFile));
250 		return podArchiveOut;
251 	}
252 
253 	/**
254 	 * TODO think of way to avoid this hack
255 	 * 
256 	 * @param pod
257 	 * @param podToArchive
258 	 * @throws IOException
259 	 */
260 	public static void cleanClosePodArchive(Pod pod, JarOutputStream podArchive)
261 			throws IOException {
262 		// every archive needs at least one entry
263 		ByteArrayInputStream inputStream = new ByteArrayInputStream(pod
264 				.getPodId().toByteArray());
265 		BinaryUtils.addToArchive(pod, podArchive, "POD-ID.TXT", inputStream);
266 		podArchive.close();
267 	}
268 
269 	/**
270 	 * @param args
271 	 * @return
272 	 * @throws IOException
273 	 */
274 	public static CurnitFile curnitFileForArgs(String[] args)
275 			throws IOException {
276 		URL curnitUrl = PreviewCurnitFile.getCurnitArchiveUrl(args);
277 		File localfile = tempFileForUrl(curnitUrl);
278 		CurnitFile curnitFile = new CurnitFile(localfile);
279 		return curnitFile;
280 	}
281 
282 	/**
283 	 * Write to the output stream a curnit archive of a curnit with the
284 	 * specified curnit id, title and root pod
285 	 * 
286 	 * @return
287 	 * @throws Exception
288 	 */
289 	public static void writeCurnit(CurnitUuid curnitId, String curnitTitle,
290 			Pod rootPod, OutputStream out) throws Exception {
291 		Curnit curnit = new Curnit();
292 		curnit.setCurnitId(curnitId);
293 		curnit.setTitle(curnitTitle);
294 		curnit.setRootPodId(rootPod.getPodId());
295 		CurnitArchive.writeArchive(curnit, out);
296 	}
297 
298 	/**
299 	 * Transform integer id into a valid curnit uuid
300 	 * 
301 	 * @param someInt
302 	 * @return uuid of curnit for given serial id
303 	 */
304 	public static CurnitUuid curnitIdFromInt(int someInt) {
305 		String PRE = "cccccccc-";
306 		String POST = "-0000-0000-000000000000";
307 		DecimalFormat df = new DecimalFormat("0000");
308 		String middle = df.format(someInt % 1000);
309 		String idStr = PRE + middle + POST;
310 		return new CurnitUuid(idStr);
311 	}
312 
313 	/**
314 	 * loads a curnit from a file, returns the curnit object
315 	 * 
316 	 * @param file - curnit archive file
317 	 * @return
318 	 * @throws IOException
319 	 * @throws UnknownPodException 
320 	 */
321 	public static Curnit loadCurnit(File file) throws IOException, UnknownPodException {
322 		CurnitFile curnitFile = new CurnitFile(file);
323 		Curnit curnit = curnitFile.getCurnit();
324 		// register curnit archive with resolver
325 		CurnitUuid curnitId = curnit.getCurnitId();
326 		CurnitArchiveResolver.getSystemResolver().put(curnitId, file.toURL());
327 		curnit.assemble();
328 		return curnit;
329 	}
330 
331 	/**
332 	 * @param rootPodId
333 	 * @return
334 	 * @throws IOException
335 	 * @throws FileNotFoundException
336 	 * @throws MalformedURLException
337 	 */
338 	public static File tempCurnitArchive(PodUuid rootPodId)
339 			throws IOException, FileNotFoundException, MalformedURLException {
340 		File tempFile = File.createTempFile("tempCurnit", ".jar");
341 		Curnit curnit = new Curnit();
342 		curnit.setCurnitId(curnitIdFromInt((int) Math.random()));
343 		curnit.setTitle("PREVIEW" + new Date());
344 		try {
345 			curnit.setRootPodId(rootPodId);
346 		} catch (UnknownPodException e) {
347 			// TODO Auto-generated catch block
348 			e.printStackTrace();
349 			// shouldn't ever happen
350 			throw new RuntimeException(e);
351 		}
352 		OutputStream out = new BufferedOutputStream(new FileOutputStream(
353 				tempFile));
354 		CurnitArchive.writeArchive(curnit, out);
355 		return tempFile;
356 	}
357 	
358 }