source: josm/trunk/src/org/openstreetmap/josm/io/MirroredInputStream.java@ 4067

Last change on this file since 4067 was 4022, checked in by stoecker, 13 years ago

fix prefs key for mirrored input stream, use pref collection instead of own code

  • Property svn:eol-style set to native
File size: 9.7 KB
Line 
1// License: GPL. Copyright 2007 by Immanuel Scholz and others
2package org.openstreetmap.josm.io;
3
4import static org.openstreetmap.josm.tools.I18n.tr;
5
6import java.io.BufferedInputStream;
7import java.io.BufferedOutputStream;
8import java.io.File;
9import java.io.FileInputStream;
10import java.io.FileOutputStream;
11import java.io.IOException;
12import java.io.InputStream;
13import java.net.URL;
14import java.net.URLConnection;
15import java.util.Arrays;
16import java.util.Collection;
17import java.util.Enumeration;
18import java.util.zip.ZipEntry;
19import java.util.zip.ZipFile;
20
21import org.openstreetmap.josm.Main;
22
23/**
24 * Mirrors a file to a local file.
25 * <p>
26 * The file mirrored is only downloaded if it has been more than 7 days since last download
27 */
28public class MirroredInputStream extends InputStream {
29 InputStream fs = null;
30 File file = null;
31
32 public MirroredInputStream(String name) throws IOException {
33 this(name, null, -1L);
34 }
35
36 public MirroredInputStream(String name, long maxTime) throws IOException {
37 this(name, null, maxTime);
38 }
39
40 public MirroredInputStream(String name, String destDir) throws IOException {
41 this(name, destDir, -1L);
42 }
43
44 /**
45 * Get an inputstream from a given filename, url or internal resource.
46 * @param name can be
47 * - relative or absolute file name
48 * - file:///SOME/FILE the same as above
49 * - resource://SOME/FILE file from the classpath (usually in the current *.jar)
50 * - http://... a url. It will be cached on disk.
51 * @param destDir the destination directory for the cache file. only applies for urls.
52 * @param maxTime the maximum age of the cache file (in seconds)
53 * @throws IOException when the resource with the given name could not be retrieved
54 */
55 public MirroredInputStream(String name, String destDir, long maxTime) throws IOException {
56 URL url;
57 try {
58 url = new URL(name);
59 if (url.getProtocol().equals("file")) {
60 file = new File(name.substring("file:/".length()));
61 if (!file.exists()) {
62 file = new File(name.substring("file://".length()));
63 }
64 } else {
65 if(Main.applet) {
66 URLConnection conn = url.openConnection();
67 conn.setConnectTimeout(5000);
68 conn.setReadTimeout(5000);
69 fs = new BufferedInputStream(conn.getInputStream());
70 file = new File(url.getFile());
71 } else {
72 file = checkLocal(url, destDir, maxTime);
73 }
74 }
75 } catch (java.net.MalformedURLException e) {
76 if(name.startsWith("resource://")) {
77 fs = getClass().getResourceAsStream(
78 name.substring("resource:/".length()));
79 if (fs == null)
80 throw new IOException(tr("Failed to open input stream for resource ''{0}''", name));
81 return;
82 }
83 file = new File(name);
84 }
85 if (file == null)
86 throw new IOException();
87 fs = new FileInputStream(file);
88 }
89
90 /**
91 * Replies an input stream for a file in a ZIP-file. Replies a file in the top
92 * level directory of the ZIP file which has an extension <code>extension</code>. If more
93 * than one files have this extension, the last file whose name includes <code>namepart</code>
94 * is opened.
95 *
96 * @param extension the extension of the file we're looking for
97 * @param namepart the name part
98 * @return an input stream. Null if this mirrored input stream doesn't represent a zip file or if
99 * there was no matching file in the ZIP file
100 */
101 public InputStream getZipEntry(String extension, String namepart) {
102 if (file == null)
103 return null;
104 InputStream res = null;
105 try {
106 ZipFile zipFile = new ZipFile(file);
107 ZipEntry resentry = null;
108 Enumeration<? extends ZipEntry> entries = zipFile.entries();
109 while (entries.hasMoreElements()) {
110 ZipEntry entry = entries.nextElement();
111 if (entry.getName().endsWith("." + extension)) {
112 /* choose any file with correct extension. When more than
113 one file, prefer the one which matches namepart */
114 if (resentry == null || entry.getName().indexOf(namepart) >= 0) {
115 resentry = entry;
116 }
117 }
118 }
119 if (resentry != null) {
120 res = zipFile.getInputStream(resentry);
121 } else {
122 zipFile.close();
123 }
124 } catch (Exception e) {
125 if(file.getName().endsWith(".zip")) {
126 System.err.println(tr("Warning: failed to open file with extension ''{2}'' and namepart ''{3}'' in zip file ''{0}''. Exception was: {1}",
127 file.getName(), e.toString(), extension, namepart));
128 }
129 }
130 return res;
131 }
132
133 public File getFile()
134 {
135 return file;
136 }
137
138 static public void cleanup(String name)
139 {
140 cleanup(name, null);
141 }
142 static public void cleanup(String name, String destDir)
143 {
144 URL url;
145 try {
146 url = new URL(name);
147 if (!url.getProtocol().equals("file"))
148 {
149 String prefKey = getPrefKey(url, destDir);
150 // FIXME: replace with normal getCollection after july 2011
151 Collection<String> localPath = Main.pref.getCollectionOld(prefKey, ";");
152 if(localPath.size() == 2) {
153 String[] lp = (String[]) localPath.toArray();
154 File lfile = new File(lp[1]);
155 if(lfile.exists()) {
156 lfile.delete();
157 }
158 }
159 Main.pref.put(prefKey, null);
160 }
161 } catch (java.net.MalformedURLException e) {}
162 }
163
164 /**
165 * get preference key to store the location and age of the cached file.
166 * 2 resources that point to the same url, but that are to be stored in different
167 * directories will not share a cache file.
168 */
169 private static String getPrefKey(URL url, String destDir) {
170 StringBuilder prefKey = new StringBuilder("mirror.");
171 if (destDir != null) {
172 String prefDir = Main.pref.getPreferencesDir();
173 if (destDir.startsWith(prefDir)) {
174 destDir = destDir.substring(prefDir.length());
175 }
176 prefKey.append(destDir);
177 prefKey.append(".");
178 }
179 prefKey.append(url.toString());
180 return prefKey.toString().replaceAll("=","_");
181 }
182
183 private File checkLocal(URL url, String destDir, long maxTime) throws IOException {
184 String prefKey = getPrefKey(url, destDir);
185 File file = null;
186 // FIXME: replace with normal getCollection after july 2011
187 Collection<String> localPathEntry = Main.pref.getCollectionOld(prefKey, ";");
188 if(localPathEntry.size() == 2) {
189 String[] lp = (String[]) localPathEntry.toArray();
190 file = new File(lp[1]);
191 if(!file.exists())
192 file = null;
193 else {
194 if (maxTime <= 0) {
195 maxTime = Main.pref.getInteger("mirror.maxtime", 7*24*60*60);
196 }
197 if (System.currentTimeMillis() - Long.parseLong(lp[0]) < maxTime*1000) {
198 return file;
199 }
200 }
201 }
202 if(destDir == null) {
203 destDir = Main.pref.getPreferencesDir();
204 }
205
206 File destDirFile = new File(destDir);
207 if (!destDirFile.exists()) {
208 destDirFile.mkdirs();
209 }
210
211 String a = url.toString().replaceAll("[^A-Za-z0-9_.-]", "_");
212 String localPath = "mirror_" + a;
213 destDirFile = new File(destDir, localPath + ".tmp");
214 BufferedOutputStream bos = null;
215 BufferedInputStream bis = null;
216 try {
217 URLConnection conn = url.openConnection();
218 conn.setConnectTimeout(5000);
219 conn.setReadTimeout(5000);
220 bis = new BufferedInputStream(conn.getInputStream());
221 bos = new BufferedOutputStream( new FileOutputStream(destDirFile));
222 byte[] buffer = new byte[4096];
223 int length;
224 while ((length = bis.read(buffer)) > -1) {
225 bos.write(buffer, 0, length);
226 }
227 bos.close();
228 bos = null;
229 file = new File(destDir, localPath);
230 destDirFile.renameTo(file);
231 Main.pref.putCollection(prefKey, Arrays.asList(new String[]
232 {Long.toString(System.currentTimeMillis()), file.toString()}));
233 } finally {
234 if (bis != null) {
235 try {
236 bis.close();
237 } catch (IOException e) {
238 e.printStackTrace();
239 }
240 }
241 if (bos != null) {
242 try {
243 bos.close();
244 } catch (IOException e) {
245 e.printStackTrace();
246 }
247 }
248 }
249
250 return file;
251 }
252 @Override
253 public int available() throws IOException
254 { return fs.available(); }
255 @Override
256 public void close() throws IOException
257 { fs.close(); }
258 @Override
259 public int read() throws IOException
260 { return fs.read(); }
261 @Override
262 public int read(byte[] b) throws IOException
263 { return fs.read(b); }
264 @Override
265 public int read(byte[] b, int off, int len) throws IOException
266 { return fs.read(b,off, len); }
267 @Override
268 public long skip(long n) throws IOException
269 { return fs.skip(n); }
270}
Note: See TracBrowser for help on using the repository browser.