1 package com.hammurapi.jcapture;
2 
3 import java.awt.Component;
4 import java.io.Closeable;
5 import java.io.File;
6 import java.io.FileInputStream;
7 import java.io.FileOutputStream;
8 import java.io.InputStream;
9 import java.io.OutputStream;
10 import java.net.ProxySelector;
11 import java.text.MessageFormat;
12 import java.util.ArrayList;
13 import java.util.Collection;
14 import java.util.Iterator;
15 import java.util.Properties;
16 import java.util.StringTokenizer;
17 import java.util.concurrent.ExecutorService;
18 import java.util.concurrent.Executors;
19 import java.util.concurrent.ThreadFactory;
20 
21 import javax.swing.JApplet;
22 import javax.swing.JOptionPane;
23 import javax.swing.ProgressMonitorInputStream;
24 import javax.swing.SwingUtilities;
25 
26 import org.apache.commons.codec.DecoderException;
27 import org.apache.commons.codec.binary.Hex;
28 import org.apache.commons.codec.net.URLCodec;
29 import org.apache.http.HttpResponse;
30 import org.apache.http.client.methods.HttpUriRequest;
31 import org.apache.http.entity.mime.content.InputStreamBody;
32 import org.apache.http.impl.client.DefaultHttpClient;
33 import org.apache.http.impl.conn.ProxySelectorRoutePlanner;
34 
35 /**
36  * Base class for capture applets.
37  * @author Pavel
38  *
39  */
40 public abstract class AbstractCaptureApplet extends JApplet {
41 
42 	private static final String OUTPUT_DIR_PARAMETER = "outputDir";
43 
44 	private CaptureFrame captureFrame;
45 
46 	@Override
stop()47 	public void stop() {
48 		if (captureFrame!=null) {
49 			captureFrame.dispose();
50 			captureFrame = null;
51 		}
52 		backgroundProcessor.shutdown();
53 		synchronized (closeables) {
54 			Iterator<Closeable> cit = closeables.iterator();
55 			while (cit.hasNext()) {
56 				try {
57 					cit.next().close();
58 				} catch (Exception e) {
59 					e.printStackTrace();
60 				}
61 				cit.remove();
62 			}
63 		}
64 		super.stop();
65 	}
66 
67 	/**
68 	 * Adds closeable to close in applet stop() method.
69 	 * @param closeable
70 	 */
addCloseable(Closeable closeable)71 	public void addCloseable(Closeable closeable) {
72 		synchronized (closeables) {
73 			closeables.add(closeable);
74 		}
75 	}
76 
77 	private Collection<Closeable> closeables = new ArrayList<Closeable>();
78 
showCaptureFrame()79 	public void showCaptureFrame() {
80 		if (captureFrame==null) {
81 			createCaptureFrame();
82 		}
83 		captureFrame.setVisible(true);
84 	}
85 
86 	private ExecutorService backgroundProcessor;
87 
88 	@Override
start()89 	public void start() {
90 		super.start();
91 
92 		ThreadFactory threadFactory =  new ThreadFactory() {
93 
94 			@Override
95 			public Thread newThread(Runnable r) {
96 				Thread th=new Thread(r, "Background processor");
97 				th.setPriority(Thread.NORM_PRIORITY);
98 				return th;
99 			}
100 		};
101 		backgroundProcessor = Executors.newSingleThreadExecutor(threadFactory);
102 
103 		SwingUtilities.invokeLater(new Runnable() {
104 
105 			public void run() {
106 				createCaptureFrame();
107 			}
108 		});
109 
110 		try {
111 			// Proxy configuration - requires java.net.NetPermission getProxySelector
112 			proxySelector = ProxySelector.getDefault();
113 		} catch (Exception e) {
114 			System.err.println("Can't obtain proxy information: "+e);
115 			e.printStackTrace();
116 		}
117 	}
118 
getBackgroundProcessor()119 	public ExecutorService getBackgroundProcessor() {
120 		return backgroundProcessor;
121 	}
122 
createCaptureFrame()123 	protected void createCaptureFrame() {
124 		try {
125 			captureFrame = new CaptureFrame(this);
126 			captureFrame.setVisible(true);
127 		} catch (Exception e) {
128 			JOptionPane.showMessageDialog(
129 					null,
130 					"Error: "+e,
131 					"Cannot create capture window",
132 					JOptionPane.ERROR_MESSAGE);
133 			e.printStackTrace();
134 		}
135 	}
136 
formatByteSize(long bytes)137 	public static String formatByteSize(long bytes) {
138 		if (bytes<1024) {
139 			return bytes + "bytes";
140 		}
141 		if (bytes<1024*1024) {
142 			return MessageFormat.format("{0,number,0.0} Kb", new Object[] {(double) bytes/1024.0});
143 		}
144 		if (bytes<1024*1024*1024) {
145 			return MessageFormat.format("{0,number,0.00} Mb", new Object[] {(double) bytes/(double) (1024.0*1024.0)});
146 		}
147 		return MessageFormat.format("{0,number,0.00} Gb", new Object[] {(double) bytes/(double) (1024.0*1024.0*1024.0)});
148 	}
149 
150 
151 	protected File preferencesFile = new File(System.getProperty("user.home")+File.separator+"."+getClass().getName()+".properties");
152 
loadConfig()153 	public Properties loadConfig() {
154 		try {
155 			if (preferencesFile.isFile()) {
156 				InputStream configStream = new FileInputStream(preferencesFile);
157 				Properties ret = new Properties();
158 				ret.load(configStream);
159 				configStream.close();
160 				return ret;
161 			}
162 		} catch (Exception e) {
163 			e.printStackTrace();
164 		}
165 		return null;
166 	}
167 
storeConfig(Properties properties)168 	public void storeConfig(Properties properties) {
169 		try {
170 			FileOutputStream out = new FileOutputStream(preferencesFile);
171 			properties.store(out, "Config");
172 			out.close();
173 		} catch (Exception e) {
174 			e.printStackTrace();
175 		}
176 	}
177 
getCookies()178 	protected String getCookies() throws DecoderException {
179 		String cookiesStr = getParameter("cookies");
180 		if (cookiesStr==null) {
181 			return null;
182 		}
183 
184 		StringBuilder ret = new StringBuilder();
185 		StringTokenizer st = new StringTokenizer(cookiesStr, ";");
186 		while (st.hasMoreTokens()) {
187 			String tok = st.nextToken();
188 			int idx = tok.indexOf("=");
189 			ret.append(hex2urlEncoded(tok.substring(0, idx)));
190 			ret.append("=");
191 			ret.append(hex2urlEncoded(tok.substring(idx+1)));
192 			if (st.hasMoreElements()) {
193 				ret.append(";");
194 			}
195 		}
196 
197 		return ret.toString();
198 	}
199 
hex2urlEncoded(String hexStr)200 	private String hex2urlEncoded(String hexStr) throws DecoderException {
201 		return new String(URLCodec.encodeUrl(null, Hex.decodeHex(hexStr.toCharArray())));
202 	}
203 
204 	protected ProxySelector proxySelector;
205 
206 	/**
207 	 * Posts capture/recording to the web site.
208 	 * @param parentComponent Parent component for the progress bar.
209 	 * @param content Content - file or byte array.
210 	 * @param fileName File name.
211 	 * @param mimeType Mime type.
212 	 * @return
213 	 * @throws Exception
214 	 */
post( Component parentComponent, final InputStream content, final long contentLength, String fileName, String mimeType)215 	public HttpResponse post(
216 			Component parentComponent,
217 			final InputStream content,
218 			final long contentLength,
219 			String fileName,
220 			String mimeType) throws Exception {
221 
222 
223 		System.out.println("jCapture applet, build @@@time@@@");
224 
225 		/**
226 		 * Debugging - save to file.
227 		 */
228 		if (getParameter(OUTPUT_DIR_PARAMETER)!=null) {
229 			OutputStream out = new FileOutputStream(new File(getParameter(OUTPUT_DIR_PARAMETER)+File.separator+fileName));
230 			byte[] buf=new byte[4096];
231 			int l;
232 			while ((l=content.read(buf))!=-1) {
233 				out.write(buf, 0, l);
234 			}
235 			out.close();
236 			content.close();
237 			return null;
238 		}
239 
240 	    ProgressMonitorInputStream pmis = new ProgressMonitorInputStream(parentComponent, "Uploading "+ fileName + " ("+formatByteSize(contentLength)+")", content);
241 		InputStreamBody bin = new InputStreamBody(pmis, mimeType, bodyName(fileName)) {
242 
243 	    	@Override
244 	    	public long getContentLength() {
245 	    		return contentLength;
246 	    	}
247 	    };
248 
249 		DefaultHttpClient httpClient = new DefaultHttpClient();
250 	    if (proxySelector!=null) {
251 	    	ProxySelectorRoutePlanner routePlanner = new ProxySelectorRoutePlanner(
252 		        httpClient.getConnectionManager().getSchemeRegistry(),
253 		        proxySelector);
254 	    	httpClient.setRoutePlanner(routePlanner);
255 	    }
256 		return httpClient.execute(createRequest(fileName, bin));
257 	}
258 
createRequest(String fileName, InputStreamBody bin)259 	protected abstract HttpUriRequest createRequest(String fileName, InputStreamBody bin) throws Exception;
260 
bodyName(String fileName)261 	protected abstract String bodyName(String fileName);
262 }
263