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