001: package snow.utils;
002:
003: import java.text.DecimalFormat;
004: import java.io.*;
005: import java.net.*;
006: import java.util.*;
007: import snow.utils.storage.FileUtils;
008: import snow.utils.gui.ProgressModalDialog; //import sun.net.ftp.*; // not supported don't even address, let it be used in background by the URL !
009: //import sun.net.www.ParseUtil;
010:
011: import javax.swing.*;
012:
013: /** TODO: create ftp folder(s) if needed
014: * TODO: list ftp folder contents
015: */
016: public final class NetUtils {
017: private NetUtils() {
018: }
019:
020: public static void publishFTP(File source, String host,
021: String user, String pass, ProgressModalDialog pmd,
022: long alreadySend, long totalSizeToSend) throws Exception //sun.net.ftp.FtpLoginException, Exception
023: {
024: publishFTP_(source, host, user, pass,
025: guessTypeIsBinary(source), pmd, alreadySend,
026: totalSizeToSend);
027: }
028:
029: /** Publish the file source on an ftp site.
030: * Limitation: the destination folder must already exist !
031: * Limitation: uses the embedded sun.net.ftp that is NOT supported...
032: *
033: * @param binary can be always true, so we are sure we transfer the same bytes, without some linefeed conversions.
034: * @param host contains the destination, including file name. The directory must exist !!!
035: */
036: public static void publishFTP_(File source, String host,
037: final String user, String pass, boolean binary,
038: ProgressModalDialog pmd, long alreadySend0,
039: long totalSizeToSend) throws Exception
040: //, sun.net.ftp.FtpLoginException
041: {
042: // [Feb2008]: subtle, when pass contains "@" chars
043: String s = user + ":" + pass;
044: String encs = encode(s, true); //"Basic "+new sun.misc.BASE64Encoder().encode(s.getBytes());
045:
046: if (host.toLowerCase().startsWith("ftp://")) {
047: host = host.substring(6); // subtle: remove it because it is prepended, below:
048: }
049:
050: String urlString = encs
051: //user+":"+pass
052: + "@" + host + (binary ? ";type=i" : ";type=a");
053: if (!urlString.toLowerCase().startsWith("ftp://")) {
054: urlString = "ftp://" + urlString;
055: }
056:
057: int p0 = (pmd != null ? pmd.getValue() : 0);
058:
059: URL url = new URL(urlString);
060: URLConnection connection = url.openConnection();
061:
062: connection.setDoOutput(true);
063: connection.connect();
064: BufferedOutputStream bos = new BufferedOutputStream(connection
065: .getOutputStream());
066: FileInputStream fis = null;
067: try {
068: fis = new FileInputStream(source);
069: BufferedInputStream bis = new BufferedInputStream(fis);
070: long alreadySent = alreadySend0;
071: int length;
072: byte[] buf = new byte[128];
073: long lastUpdate = -1;
074: while ((length = bis.read(buf)) != -1) {
075: bos.write(buf, 0, length);
076: alreadySent += length;
077:
078: if (pmd != null) {
079: if (System.currentTimeMillis() - lastUpdate > 500) {
080: lastUpdate = System.currentTimeMillis();
081: pmd
082: .setProgressValue(
083: (int) (alreadySent * 1000.0 / totalSizeToSend),
084: null);
085: }
086: }
087: }
088: bis.close();
089: bos.flush();
090: } catch (Exception e) {
091: throw e;
092: } finally {
093: FileUtils.closeIgnoringExceptions(bos);
094: FileUtils.closeIgnoringExceptions(fis);
095: }
096: }
097:
098: /** To encode the password to be able to pass it in the ftp url as ftp://user:pass@url .
099: * Because often, "@" is part of the password on anonymous logon that requires a login with a valid mail adress.
100: */
101: public static String encode(String s, boolean flag) {
102: s = s.replace("@", "%40");
103: s = s.replace("#", "%23");
104: s = s.replace(" ", "%20");
105: s = s.replace("!", "%21");
106: s = s.replace("$", "%24");
107: s = s.replace("%", "%25");
108: s = s.replace("&", "%26"); // not all present...
109: return s;
110:
111: /* discovered with
112: for(int i=10; i<128; i++)
113: {
114: URL url = new URL("ftp://sth:hello %"+i+" abc@ftp://ftp.test.com/;type=i");
115: System.out.println("UI="+ url.getUserInfo()+" "+ParseUtil.decode(url.getUserInfo()));
116: }
117: */
118:
119: }
120:
121: /** @return true except for well known ascii types.
122: */
123: public static boolean guessTypeIsBinary(File f) {
124: String nameLow = f.getName().toLowerCase(Locale.ENGLISH);
125: if (nameLow.endsWith(".txt"))
126: return false;
127: if (nameLow.endsWith(".text"))
128: return false;
129: if (nameLow.endsWith(".htm"))
130: return false;
131: if (nameLow.endsWith(".html"))
132: return false;
133: if (nameLow.endsWith(".jnlp"))
134: return false;
135: if (nameLow.endsWith(".css"))
136: return false;
137: if (nameLow.endsWith(".xml"))
138: return false;
139: if (nameLow.endsWith(".xsl"))
140: return false;
141: if (nameLow.endsWith(".xslt"))
142: return false;
143: if (nameLow.endsWith(".java"))
144: return false;
145:
146: return true;
147: }
148:
149: /** Can be used for ftp, http, ...
150: */
151: public static void download(URL url, File dest) throws Exception {
152: URLConnection connection = url.openConnection();
153: connection.setDoOutput(false);
154: connection.connect();
155: BufferedInputStream bis = new BufferedInputStream(connection
156: .getInputStream());
157: BufferedOutputStream bos = new BufferedOutputStream(
158: new FileOutputStream(dest));
159: try {
160: int length = -1;
161: byte[] buf = new byte[128];
162: while ((length = bis.read(buf)) != -1) {
163: bos.write(buf, 0, length);
164: }
165: } finally {
166: FileUtils.closeIgnoringExceptions(bos);
167: FileUtils.closeIgnoringExceptions(bis);
168: }
169: }
170:
171: public static void downloadFileFromServer(URL url, File dest,
172: String fileNameForUI, ProgressModalDialog pmd)
173: throws Exception {
174: long start = System.currentTimeMillis();
175: long size = 0;
176: if (url.getProtocol().equalsIgnoreCase("file")) {
177: File f = new File(("" + url).substring(7)); // DON'T WORK ON ANOTHER DISK: .getPath());
178: if (!f.exists()) {
179: throw new Exception("File not existing: " + f);
180: }
181:
182: long date = f.lastModified();
183: size = f.length();
184: FileInputStream fis = new FileInputStream(f);
185: BufferedInputStream bis = new BufferedInputStream(fis);
186: pmd.setProgressComment("Downloading " + fileNameForUI
187: + " (" + FileUtils.formatSize(size) + ")");
188: writeToFile(bis, dest, pmd, size);
189: if (date > 0) {
190: dest.setLastModified(date);
191: System.out.println("set date " + new Date(date)
192: + " for " + dest);
193: }
194: } else if (url.getProtocol().equalsIgnoreCase("http")) {
195: HttpURLConnection con = (HttpURLConnection) url
196: .openConnection();
197: con.setDoOutput(false);
198: long date = con.getLastModified();
199: size = con.getContentLength();
200: // the size may be null,specified by some crazy proxies.
201:
202: pmd.setProgressComment("Downloading " + fileNameForUI
203: + " (" + FileUtils.formatSize(size) + ")");
204: pmd.start();
205: writeToFile(con.getInputStream(), dest, pmd, size);
206: if (date > 0) {
207: dest.setLastModified(date);
208: System.out.println("set date " + new Date(date)
209: + " for " + dest);
210: }
211:
212: con.disconnect();
213: } else {
214: // TODO: ftp...?
215: throw new Exception("bad proto: " + url);
216: }
217: System.out.println("Downloaded "
218: + fileNameForUI
219: + " at "
220: + NetUtils.formatNetSpeed(size, System
221: .currentTimeMillis()
222: - start));
223: }
224:
225: /** @param is is closed in all situations.
226: * @param totSize is only used for progress estimation.
227: */
228: public static void writeToFile(final InputStream is, File file,
229: final ProgressModalDialog pmd, long totSize)
230: throws Exception {
231: if (totSize <= 0)
232: totSize = 1000000; //1MB
233:
234: File parent = file.getParentFile();
235: if (parent != null && !parent.exists()) {
236: parent.mkdirs();
237: }
238:
239: FileOutputStream fos = null;
240: try {
241: fos = new FileOutputStream(file);
242: byte[] buf = new byte[256];
243: long totRead = 0;
244: int read = -1;
245: while ((read = is.read(buf)) != -1) {
246: if (pmd.getWasCancelled())
247: throw new Exception("Download cancelled");
248:
249: fos.write(buf, 0, read);
250: totRead += read;
251:
252: pmd.setProgressValue((int) (totRead * 90.0 / totSize),
253: "");
254:
255: }
256: } catch (Exception e) {
257: throw e;
258: } finally {
259: FileUtils.closeIgnoringExceptions(fos);
260: FileUtils.closeIgnoringExceptions(is);
261: }
262: }
263:
264: /** {date, size}. Don't look too much at the size, it can be zero behind some proxies.
265: */
266: public static long[] getDateAndSizeOnServer(URL url)
267: throws Exception {
268: //System.out.println("proto="+ url.getProtocol());
269: if (url.getProtocol().equalsIgnoreCase("file")) {
270: File f = new File(("" + url).substring(7)); // getpath DOESN'T WORK If the file is on another disk !
271: return new long[] { f.lastModified(), f.length() };
272: } else if (url.getProtocol().equalsIgnoreCase("http")
273: || url.getProtocol().equalsIgnoreCase("https")) {
274: URLConnection con0 = url.openConnection();
275: if (!(con0 instanceof HttpURLConnection)) {
276: System.out.println("URLConnection of class "
277: + con0.getClass().getName());
278: }
279: HttpURLConnection con = (HttpURLConnection) con0;
280: long date = con.getLastModified();
281: long size = con.getContentLength();
282: con.disconnect();
283: if (date < 1)
284: throw new Exception("No connection to " + url);
285: // Mike K. suggests: behind crazy proxies, size is zero and only date is reasonable.
286: return new long[] { date, size };
287: } else {
288: throw new Exception("Unknown protocol " + url.getProtocol()
289: + ". Only file:// and http:// are supported.");
290: }
291: }
292:
293: /**
294: * head examples:
295: * {Expires=[Thu, 01 Jan 1970 00:00:00 GMT], Set-Cookie=[JSESSIONID=aMOvePdy_cY5; path=/], null=[HTTP/1.1 200 OK], Date=[Wed, 03 Jan 2007 15:13:51 GMT], Pragma=[no-cache], Server=[Resin/2.1.9], Content-Type=[text/html], Transfer-Encoding=[chunked], Cache-Control=[no-store]}
296: * {Content-Length=[55024], Connection=[keep-alive], Expires=[Wed, 03 Jan 2007 16:34:17 GMT], ETag=["ef80e5db-01010001"], Date=[Wed, 03 Jan 2007 16:19:17 GMT], Server=[Apache], Content-Type=[text/html; charset=ISO-8859-1], X-Cache=[HIT from www.sunrise.ch], Last-Modified=[Wed, 03 Jan 2007 13:03:12 GMT], Age=[366], null=[HTTP/1.0 200 OK]}
297: */
298: public static void analyseFile(URL url) throws Exception {
299: HttpURLConnection connection = (HttpURLConnection) url
300: .openConnection();
301: connection.setDoOutput(false);
302: System.out.println("" + connection.getHeaderFields());
303: System.out.println("content-length="
304: + connection.getContentLength());
305: System.out.println("date=" + new Date(connection.getDate()));
306: System.out.println("lastModified="
307: + new Date(connection.getLastModified()));
308: }
309:
310: private final static DecimalFormat df0 = new DecimalFormat("0.0");
311:
312: /** Using the bits/s standard network unit.
313: */
314: public static String formatNetSpeed(long sizeInByte, long timeMillis) {
315: if (timeMillis == 0)
316: timeMillis = 1; // avoid div. by zero.
317: double speed = 8.0 * sizeInByte / timeMillis; // byte/ms = kBit/s
318: if (speed > 1e6) {
319: return df0.format(speed * 1e-6) + " GBit/s";
320: }
321: if (speed > 1e3) {
322: return df0.format(speed * 1e-3) + " MBit/s";
323: }
324: // let kBps even if small...
325: return df0.format(speed) + " kBit/s";
326: }
327:
328: /** NOT WORKING !!
329: * Please use apache commons for this.
330: * there are up to 8 various LIST syntax . horrible...
331: */
332: public static String listFTP(String address, String user,
333: String pass) {
334: return null;
335: }
336:
337: /*test*
338: public static void main(String[] arguments) throws Exception
339: {
340: URL u = new URL("File://h:/sth");
341: System.out.println(""+u.getPath()); // /sth
342: System.out.println(""+u.getAuthority()); // h:
343: System.out.println(""+u.getFile()); // /sth
344: System.out.println(""+u.getQuery()); // null
345: //System.out.println(""+u.getRef());
346: //System.out.println(""+u.getContent());
347: System.out.println(""+u.getUserInfo());
348: URL url = new URL("http://www.freesurf.ch/index.html");
349:
350: //download(url, new File("c:/temp/abc.zip"));
351: analyseFile(url);
352: }*/
353:
354: }
|