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

Last change on this file since 3775 was 3695, checked in by bastiK, 13 years ago

fixed #5692 - users of imagery plugin don't see bing menu entry, because it uses old cache file from wms plugin
(Now the preference key to store the age and location of cache file contains not only the url, but the destination directory as well. Previously it could happen, that 2 plugins access the same url and try to cache it in their private plugin folder, but both plugins will share a single cache file. This used to be ok, but in this case it is no good, simply because we want a fresh download when the new plugin is installed. On top of that, in case both plugins had different caching times, the sharing wouldn't respect that either.)

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