001: package com.xoetrope.resource;
002:
003: import java.io.File;
004: import java.io.FileOutputStream;
005: import java.io.InputStream;
006: import java.io.OutputStream;
007: import java.net.URL;
008: import java.net.URLClassLoader;
009: import java.text.SimpleDateFormat;
010: import java.util.Date;
011: import java.util.concurrent.Callable;
012: import java.util.concurrent.CompletionService;
013: import java.util.concurrent.ExecutionException;
014: import java.util.concurrent.ExecutorCompletionService;
015: import java.util.concurrent.ExecutorService;
016: import java.util.concurrent.Executors;
017: import java.util.concurrent.Future;
018:
019: import com.xoetrope.task.LaunderThrowable;
020:
021: import net.xoetrope.debug.DebugLogger;
022: import net.xoetrope.xui.XProject;
023: import net.xoetrope.xui.data.XBaseModel;
024: import net.xoetrope.xui.data.XModel;
025: import net.xoetrope.xui.helper.SwingWorker;
026:
027: /**
028: * A dynamic loader of resources from a URL.
029: * <p> Copyright (c) Xoetrope Ltd., 2001-2006, This software is licensed under
030: * the GNU Public License (GPL), please see license.txt for more details. If
031: * you make commercial use of this software you must purchase a commercial
032: * license from Xoetrope.</p>
033: */
034: public class XResourceLoader {
035: public static final int DOWNLOAD_FILENAME = 0;
036: public static final int DOWNLOAD_ID = 1;
037: public static final int DOCUMENT_FILESIZE = 2;
038: public static final int DOWNLOAD_FILEDATE = 3;
039: public static final int DOWNLOAD_PROGRESS = 4;
040:
041: private XProject currentProject;
042: private XModel rootModel;
043:
044: private XBaseModel downloadList;
045:
046: private String serverURL;
047: private File targetFolder;
048:
049: private SimpleDateFormat sdf;
050:
051: private final ExecutorService threadPool;
052:
053: private XResourceClassLoader urlClassLoader;
054:
055: /** Creates a new instance of DocumentManager */
056: protected XResourceLoader(XProject project) {
057: currentProject = project;
058: rootModel = currentProject.getModel();
059:
060: sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.S");
061:
062: threadPool = Executors.newFixedThreadPool(3);
063: urlClassLoader = new XResourceClassLoader(new URL[0],
064: getClass().getClassLoader());
065: project.addCustomClassLoader(urlClassLoader);
066: }
067:
068: public static XResourceLoader getInstance(XProject project) {
069: XResourceLoader resourceLoader = (XResourceLoader) project
070: .getObject("ResourceLoader");
071: if (resourceLoader == null) {
072: resourceLoader = new XResourceLoader(project);
073: project.setObject("ResourceLoader", resourceLoader);
074: }
075:
076: return resourceLoader;
077: }
078:
079: public ClassLoader getClassloader() {
080: return urlClassLoader;
081: }
082:
083: /**
084: * Start the download service
085: */
086: public void startCacheCheck(XBaseModel fileList, File outputFolder) {
087: downloadList = fileList;
088:
089: if (outputFolder != null)
090: setTargetFolder(outputFolder);
091:
092: SwingWorker worker = new SwingWorker() {
093: public Object construct() {
094: try {
095: checkCache();
096: } finally {
097: }
098: return null;
099: }
100:
101: public void finished() {
102: }
103: };
104: worker.start();
105: }
106:
107: /**
108: * Start the download service
109: */
110: public void startDownload(XBaseModel fileList,
111: final String downloadServer, File outputFolder,
112: final XResourceLoaderStatus status) {
113: downloadList = fileList;
114:
115: setServerURL(downloadServer);
116: if (outputFolder != null)
117: setTargetFolder(outputFolder);
118:
119: SwingWorker worker = new SwingWorker() {
120: public Object construct() {
121: try {
122: doDownload(status);
123: } finally {
124: }
125: return null;
126: }
127:
128: public void finished() {
129: status.setProgress(100);
130: }
131: };
132: worker.start();
133: }
134:
135: /**
136: * Iterate the downloada list and download all the files
137: */
138: private void checkCache() {
139: CompletionService<XBaseModel> completionService = new ExecutorCompletionService<XBaseModel>(
140: threadPool);
141:
142: int numEntries = downloadList.getNumChildren();
143: for (int j = 0; j < numEntries; j++) {
144: final XBaseModel documentModel = ((XBaseModel) downloadList
145: .get(j));
146: // Setup the download jobs
147: completionService.submit(new Callable<XBaseModel>() {
148: public XBaseModel call() {
149: checkFile(documentModel);
150: return documentModel;
151: }
152: });
153: }
154:
155: // Wait for the downloads to complete
156: try {
157: for (int i = 0; i < numEntries; i++) {
158: Future<XBaseModel> f = completionService.take();
159: XBaseModel documentModel = f.get();
160: }
161: } catch (InterruptedException e) {
162: Thread.currentThread().interrupt();
163: } catch (ExecutionException e) {
164: throw LaunderThrowable.launderThrowable(e.getCause());
165: }
166: }
167:
168: /**
169: * Iterate the downloada list and download all the files
170: */
171: private void doDownload(final XResourceLoaderStatus status) {
172: CompletionService<XBaseModel> completionService = new ExecutorCompletionService<XBaseModel>(
173: threadPool);
174:
175: int numEntries = downloadList.getNumChildren();
176: for (int j = 0; j < numEntries; j++) {
177: final XBaseModel documentModel = ((XBaseModel) downloadList
178: .get(j));
179: // Setup the download jobs
180: completionService.submit(new Callable<XBaseModel>() {
181: public XBaseModel call() {
182: downloadFile(status, documentModel);
183: return documentModel;
184: }
185: });
186: }
187:
188: // Wait for the downloads to complete
189: try {
190: for (int i = 0; i < numEntries; i++) {
191: Future<XBaseModel> f = completionService.take();
192: XBaseModel documentModel = f.get();
193: status.setProgress(i * 100 / numEntries);
194: }
195: } catch (InterruptedException e) {
196: Thread.currentThread().interrupt();
197: } catch (ExecutionException e) {
198: throw LaunderThrowable.launderThrowable(e.getCause());
199: }
200: }
201:
202: /**
203: * Download an individual file
204: */
205: private void downloadFile(final XResourceLoaderStatus status,
206: XBaseModel documentModel) {
207: String fileName = (String) documentModel
208: .getAttribValue(DOWNLOAD_FILENAME);
209: String fileDate = (String) documentModel
210: .getAttribValue(DOWNLOAD_FILEDATE);
211:
212: long lastModified = Long.MAX_VALUE;
213: if ((fileDate != null) && (fileDate.trim().length() > 0)) {
214: try {
215: Date date = sdf.parse(fileDate.trim());
216: lastModified = date.getTime();
217: } catch (Exception ex) {
218: System.out.println(fileDate);
219: ex.printStackTrace();
220: }
221: }
222:
223: String srcFileName = getSourceFileName(fileName);
224: File targetFile = getTargetFile(fileName, true);
225:
226: int fileSize = 0;
227: try {
228: fileSize = Integer.parseInt((String) documentModel
229: .getAttribValue(DOCUMENT_FILESIZE));
230: } catch (Exception ex) {
231: }
232:
233: // Read the document
234: int bytesSofar = 0;
235: try {
236: if (!targetFile.exists()
237: || (targetFile.lastModified() < lastModified)) {
238: // Create channel on the source
239: DebugLogger.trace("Downloading file: " + srcFileName);
240: URL url = new URL(srcFileName);
241: InputStream in = url.openStream();
242: OutputStream out = new FileOutputStream(targetFile);
243:
244: // Transfer bytes from in to out
245: byte[] buf = new byte[4096];
246: int len;
247: while ((len = in.read(buf)) > 0) {
248: out.write(buf, 0, len);
249: bytesSofar += len;
250: documentModel.setAttribValue(DOWNLOAD_PROGRESS,
251: Integer.toString(bytesSofar * 100
252: / fileSize));
253: status.updateFileProgress();
254: }
255:
256: out.flush();
257: in.close();
258: out.close();
259: } else
260: documentModel.setAttribValue(DOWNLOAD_PROGRESS, "100");
261:
262: urlClassLoader.addURL(targetFile.toURL());
263: } catch (Exception e) {
264: if (bytesSofar == 0)
265: documentModel.setAttribValue(DOWNLOAD_PROGRESS,
266: "-10000");
267: else
268: documentModel.setAttribValue(DOWNLOAD_PROGRESS, Integer
269: .toString(-bytesSofar * 100 / fileSize));
270: status.updateFileProgress();
271: e.printStackTrace();
272: }
273: }
274:
275: /**
276: * Check the cache for an individual file
277: */
278: private void checkFile(XBaseModel documentModel) {
279: String fileName = (String) documentModel
280: .getAttribValue(DOWNLOAD_FILENAME);
281: String fileDate = (String) documentModel
282: .getAttribValue(DOWNLOAD_FILEDATE);
283:
284: long lastModified = Long.MAX_VALUE;
285: if ((fileDate != null) && (fileDate.length() > 0)) {
286: try {
287: Date date = sdf.parse(fileDate.trim());
288: lastModified = date.getTime();
289: } catch (Exception ex) {
290: System.out.println(fileDate);
291: ex.printStackTrace();
292: }
293: }
294:
295: File targetFile = getTargetFile(fileName, true);
296:
297: int fileSize = 0;
298: try {
299: fileSize = Integer.parseInt((String) documentModel
300: .getAttribValue(DOCUMENT_FILESIZE));
301: } catch (Exception ex) {
302: }
303:
304: // Read the document
305: int bytesSofar = 0;
306: try {
307: if (!targetFile.exists()
308: || (targetFile.lastModified() < lastModified)) {
309: } else
310: documentModel.setAttribValue(DOWNLOAD_PROGRESS, "100");
311:
312: if (targetFile.exists())
313: urlClassLoader.addURL(targetFile.toURL());
314: } catch (Exception e) {
315: if (bytesSofar == 0)
316: documentModel.setAttribValue(DOWNLOAD_PROGRESS,
317: "-10000");
318: else
319: documentModel.setAttribValue(DOWNLOAD_PROGRESS, Integer
320: .toString(-bytesSofar * 100 / fileSize));
321: e.printStackTrace();
322: }
323: }
324:
325: public void stopDownload() {
326:
327: }
328:
329: public void pauseDownload() {
330:
331: }
332:
333: /**
334: * Get the complete server URL of the file
335: */
336: public String getSourceFileName(String fileName) {
337: String srcFileName = "";
338: if (serverURL != null)
339: srcFileName += serverURL;
340: else
341: srcFileName += "<server>";
342:
343: if (!(srcFileName.endsWith("/") || srcFileName.endsWith("\\")))
344: srcFileName += "/";
345: srcFileName += fileName;
346:
347: return srcFileName;
348: }
349:
350: /**
351: * Get the complete target filename
352: */
353: public File getTargetFile(String fileName, boolean makeDirs) {
354: File targetFile = new File(targetFolder, fileName);
355: if (makeDirs && !targetFile.exists())
356: targetFile.getParentFile().mkdirs();
357:
358: return targetFile;
359: }
360:
361: /**
362: * Fixup the server URL
363: */
364: public void setServerURL(String url) {
365: serverURL = url.trim();
366: if (!serverURL.endsWith("/"))
367: serverURL += "/";
368: }
369:
370: /**
371: * Fixup the target folder
372: */
373: public void setTargetFolder(File folder) {
374: targetFolder = folder;
375: }
376:
377: class XResourceClassLoader extends URLClassLoader {
378: public XResourceClassLoader(URL[] urls) {
379: super (urls);
380: }
381:
382: public XResourceClassLoader(URL[] urls, ClassLoader cl) {
383: super (urls, cl);
384: }
385:
386: public void addURL(URL url) {
387: super.addURL(url);
388: }
389: }
390: }
|