Java tutorial
/******************************************************************************* * CPF Pipeline * ------------ * * File : UploadApplet.java * Author : D Trudgian * Created : 2009-10-6 * * Description * ----------- * Main JApplet derived class for CPFP UploadApplet * * ******************************************************************************/ /**** LICENCE TEXT **** * * The Application is entitled "Central Proteomics Facilities Pipeline (CPFP)" * and is a web based user interface and necessary pipeline infrastructure * for the automated analysis of proteomic mass spectrometry datasets in the * context of peptide and protein identification and quantification. The * Application provides a simple user interface for pre-existing open source * analysis tools from the ISB Trans Proteomic Pipline (TPP). The Application has * three main elements: a relational database model, a web application written in * the Perl language and a number of scripts implementing the analysis pipeline. * * The Current Date is 11th September 2009. * * The Developers means Dr David Trudgian. * * The Licence is the Common Development and Distribution Licence (CDDL) * Version 1.0, available at the Current Date from the following website: * http://www.opensource.org/licenses. * * The Licensor is the Chancellor, Masters and Scholars of the University of * Oxford, having an administrative office at Wellington Square, Oxford OX1 2JD, * United Kingdom. * * The Software means intellectual property rights in the Application owned by * the Licensor and resulting from work by the Developers. * * The Licensor grants to you, the party wishing to obtain and use copies of the * Software, a licence to the Software under the terms of the Licence. This * licence is subject to English Law and to the jurisdiction of the English * Courts. No licence to use any intellectual property rights is granted or * implied by this statement except the rights expressly granted in this * statement. * **** END LICENCE TEXT ****/ package uk.ac.ox.cbrg.cpfp.uploadapp; // java.awt import java.awt.*; // java.beans import java.beans.*; // java.io import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.File; //java.net import java.net.URL; import java.net.MalformedURLException; //java.util import java.util.List; import java.util.Vector; //java.security import java.security.cert.X509Certificate; import java.security.cert.CertificateException; //javax.net import javax.net.ssl.SSLContext; import javax.net.ssl.TrustManager; import javax.net.ssl.X509TrustManager; //javax.swing import javax.swing.table.*; import javax.swing.*; import javax.swing.UIManager.LookAndFeelInfo; // browser plugin javascript support import netscape.javascript.*; // apache httpclient import org.apache.http.params.CoreProtocolPNames; import org.apache.http.HttpResponse; import org.apache.http.entity.mime.MultipartEntity; import org.apache.http.entity.mime.HttpMultipartMode; import org.apache.http.entity.mime.content.StringBody; import org.apache.http.entity.mime.content.FileBody; import org.apache.http.client.HttpClient; import org.apache.http.client.methods.HttpPost; import org.apache.http.impl.client.DefaultHttpClient; import org.apache.http.impl.conn.ProxySelectorRoutePlanner; import java.net.ProxySelector; import org.apache.http.conn.ssl.SSLSocketFactory; import org.apache.http.conn.scheme.Scheme; // UploadApplet // Main applet class // public class UploadApplet extends javax.swing.JApplet implements PropertyChangeListener { private UploadTask task; private Vector<UploadFile> uploadFiles; private String uploadURL; private long chunkSize; private String browserCookie; private String fileExtensions; private JSObject jso; private boolean errorFlag; //-------------------------------------------------------------------------- // UploadTask // Inner SwingWorker class // Uses SwingWorker to implement upload in background thread class UploadTask extends SwingWorker<Void, String> { private Vector<UploadFile> uploadFiles; // Constructor // public UploadTask(Vector<UploadFile> uploadFiles) { this.uploadFiles = uploadFiles; } // doInBackground // Upload is performed here // public Void doInBackground() { setProgress(0); // Upload files sequentially for (int i = 0; i < uploadFiles.size(); i++) { String filePath = uploadFiles.elementAt(i).getFilePath(); String fileName = uploadFiles.elementAt(i).getFileName(); String fileMsg = "Uploading file " + (i + 1) + "/" + uploadFiles.size() + "\n"; this.publish(fileMsg); try { File inFile = new File(filePath); FileInputStream in = new FileInputStream(inFile); byte[] inBytes = new byte[(int) chunkSize]; // File will split into maxCount chunks of chunkSize bytes int count = 1; // Highest chunk number is... // Number of times buffer fits to file, -1 for 0 index int maxCount = (int) (inFile.length() / chunkSize); // If there is a remainder than add another chunk if (inFile.length() % chunkSize > 0) { maxCount++; } int readCount = 0; readCount = in.read(inBytes); // readCount > 0 if data was successfully read from file while (readCount > 0) { File splitFile = File.createTempFile("upl", null, null); String splitName = splitFile.getPath(); FileOutputStream out = new FileOutputStream(splitFile); out.write(inBytes, 0, readCount); out.close(); // Is this the final chunk? boolean chunkFinal = (count == maxCount); fileMsg = " - Sending chunk " + count + "/" + maxCount + ": "; this.publish(fileMsg); boolean uploadSuccess = false; int uploadTries = 0; while (!uploadSuccess && uploadTries <= 5) { uploadTries++; // Perform the upload for this chunk boolean uploadStatus = upload(splitName, fileName, count, chunkFinal); // If some problem with upload then try again, else done if (uploadStatus) { fileMsg = "OK\n"; this.publish(fileMsg); uploadSuccess = true; } else { fileMsg = "ERROR\n"; this.publish(fileMsg); uploadSuccess = false; } } // If we failed then warn user and give up if (!uploadSuccess) { fileMsg = "There was an error uploading your files. Please let the pipeline administrator know about this problem. Cut and paste the messages in this box, and supply them.\n"; this.publish(fileMsg); // Set the errorFlag so we don't redirect to file processing errorFlag = true; return null; } // Progress on this file in % float thisProgress = (count * 100) / (maxCount); // Progress on complete files in % float completeProgress = (i * (100 / uploadFiles.size())); // Combined progress float totalProgress = completeProgress + (thisProgress / uploadFiles.size()); setProgress((int) totalProgress); splitFile.delete(); readCount = in.read(inBytes); count++; } } catch (Exception e) { this.publish(e.toString()); } } return null; } // done // Performed in event-dispatch thread when uploads complete // @Override protected void done() { // Un-set busy cursor setCursor(null); // If there was an error during the upload then stop! if (errorFlag) { return; } // Upload finished, display message whilst redirect is processed // on server jPanel1.setVisible(false); JLabel lbl = new JLabel("Processing Files. Please Wait.", JLabel.CENTER); lbl.setFont(new Font("Sans-Serif", Font.BOLD, 24)); UploadApplet.this.getContentPane().setLayout(new FlowLayout()); UploadApplet.this.getContentPane().add(lbl); lbl = new JLabel("Do not navigate away from this page.", JLabel.CENTER); UploadApplet.this.getContentPane().add(lbl); // Redirect browser using JS callback to upl_complete method try { jso.call("upl_complete", new String[] {}); } catch (Exception e) { } } // process // Called on event-dispatch thread to process messages from publish // @Override protected void process(List<String> messages) { // Add all messages to text box on form for (int i = 0; i < messages.size(); i++) { txtMessages.append(messages.get(i)); } } // upload // Perform upload of file using apache httpclient // private boolean upload(String filePath, String fileName, int chunkNum, boolean chunkFinal) throws Exception { // TrustManager to accept self-signed SSL certificates TrustManager easyTrustManager = new X509TrustManager() { @Override public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException { // Oh, I am easy! } @Override public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException { // Oh, I am easy! } @Override public X509Certificate[] getAcceptedIssuers() { return null; } }; // Create SSL socket factory to use the trust manager SSLContext sslcontext = SSLContext.getInstance("TLS"); sslcontext.init(null, new TrustManager[] { easyTrustManager }, null); SSLSocketFactory sf = new SSLSocketFactory(sslcontext); // Do not perform any hostname verification sf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER); // Create httpclient and replace default https scheme with // scheme that accepts self-signed certificates as above Scheme https = new Scheme("https", sf, 443); DefaultHttpClient httpclient = new DefaultHttpClient(); httpclient.getConnectionManager().getSchemeRegistry().register(https); ProxySelectorRoutePlanner routePlanner = new ProxySelectorRoutePlanner( httpclient.getConnectionManager().getSchemeRegistry(), ProxySelector.getDefault()); httpclient.setRoutePlanner(routePlanner); HttpPost httppost = new HttpPost(uploadURL); // Copy browser cookies into post so session is same as browser httppost.addHeader("Cookie", browserCookie); // Some servers do not support HTTP expect, so turn off httppost.getParams().setBooleanParameter(CoreProtocolPNames.USE_EXPECT_CONTINUE, false); // Setup POST request MultipartEntity reqEntity = new MultipartEntity(HttpMultipartMode.BROWSER_COMPATIBLE); reqEntity.addPart("chunk_num", new StringBody(Integer.toString(chunkNum))); if (chunkFinal) { reqEntity.addPart("chunk_final", new StringBody("1")); } FileBody uplFile = new FileBody(new File(filePath)); reqEntity.addPart("file", uplFile); reqEntity.addPart("filename", new StringBody(fileName)); httppost.setEntity(reqEntity); // Perform upload HttpResponse response = httpclient.execute(httppost); // HTTP status code 200 = OK // Return true if code 200, false otherwise if (response.getStatusLine().getStatusCode() != 200) { return false; } return true; } } //-------------------------------------------------------------------------- // init // Fetch applet parameters, setup drag-and-drop @Override public void init() { // Set errorFlag to false - no errors yet ;-) errorFlag = false; // <PARAM> tag handling uploadFiles = new Vector<UploadFile>(); uploadURL = getParameter("UPLOADURL"); if (uploadURL == null) { uploadURL = ""; } fileExtensions = getParameter("EXTENSIONS"); if (fileExtensions == null) { fileExtensions = ""; } chunkSize = Long.parseLong(getParameter("CHUNKSIZE")); if (chunkSize == 0) { chunkSize = 10485760; // 10MB } // Get cookies from browser so session can be used for uploads try { JSObject myBrowser = (JSObject) JSObject.getWindow(this); JSObject myDocument = (JSObject) myBrowser.getMember("document"); browserCookie = (String) myDocument.getMember("cookie"); jso = JSObject.getWindow(this); } catch (Exception e) { e.printStackTrace(); } // Use Nimbus look and feel rather than default try { for (LookAndFeelInfo info : UIManager.getInstalledLookAndFeels()) { if ("Nimbus".equals(info.getName())) { UIManager.setLookAndFeel(info.getClassName()); break; } } } catch (UnsupportedLookAndFeelException e) { } catch (ClassNotFoundException e) { } catch (InstantiationException e) { } catch (IllegalAccessException e) { } // Invoke Applet try { java.awt.EventQueue.invokeAndWait(new Runnable() { public void run() { initComponents(); } }); } catch (Exception ex) { ex.printStackTrace(); } } /** This method is called from within the init() method to * initialize the form. * WARNING: Do NOT modify this code. The content of this method is * always regenerated by the Form Editor. */ @SuppressWarnings("unchecked") // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents private void initComponents() { jPanel1 = new javax.swing.JPanel(); jScrollPane1 = new javax.swing.JScrollPane(); fileTable = new javax.swing.JTable(); btnAdd = new javax.swing.JButton(); btnDel = new javax.swing.JButton(); btnUpload = new javax.swing.JButton(); prgUploadProgress = new javax.swing.JProgressBar(); lblProgress = new javax.swing.JLabel(); lblMessages = new javax.swing.JLabel(); jScrollPane2 = new javax.swing.JScrollPane(); txtMessages = new javax.swing.JTextArea(); jLabel1 = new javax.swing.JLabel(); jLabel2 = new javax.swing.JLabel(); fileTable.setModel(new javax.swing.table.DefaultTableModel(new Object[][] { }, new String[] { "Filename", "Size" }) { Class[] types = new Class[] { java.lang.String.class, java.lang.String.class }; boolean[] canEdit = new boolean[] { false, false }; public Class getColumnClass(int columnIndex) { return types[columnIndex]; } public boolean isCellEditable(int rowIndex, int columnIndex) { return canEdit[columnIndex]; } }); fileTable.setColumnSelectionAllowed(true); fileTable.getTableHeader().setReorderingAllowed(false); jScrollPane1.setViewportView(fileTable); fileTable.getColumnModel().getSelectionModel() .setSelectionMode(javax.swing.ListSelectionModel.MULTIPLE_INTERVAL_SELECTION); btnAdd.setIcon( new javax.swing.ImageIcon(getClass().getResource("/uk/ac/ox/cbrg/cpfp/uploadapp/12-em-plus.png"))); // NOI18N btnAdd.setText("Add File(s)"); btnAdd.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { btnAddActionPerformed(evt); } }); btnDel.setIcon( new javax.swing.ImageIcon(getClass().getResource("/uk/ac/ox/cbrg/cpfp/uploadapp/12-em-cross.png"))); // NOI18N btnDel.setText("Remove File(s)"); btnDel.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { btnDelActionPerformed(evt); } }); btnUpload.setIcon( new javax.swing.ImageIcon(getClass().getResource("/uk/ac/ox/cbrg/cpfp/uploadapp/12-em-up.png"))); // NOI18N btnUpload.setText("Upload Files"); btnUpload.setEnabled(false); btnUpload.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { btnUploadActionPerformed(evt); } }); prgUploadProgress.setStringPainted(true); lblProgress.setText("Progress:"); lblMessages.setText("Messages:"); txtMessages.setColumns(20); txtMessages.setRows(5); jScrollPane2.setViewportView(txtMessages); jLabel1.setFont(jLabel1.getFont().deriveFont(jLabel1.getFont().getStyle() | java.awt.Font.BOLD, jLabel1.getFont().getSize() + 3)); jLabel1.setForeground(javax.swing.UIManager.getDefaults().getColor("textText")); jLabel1.setHorizontalAlignment(javax.swing.SwingConstants.CENTER); jLabel1.setText("CPFP File Uploader"); jLabel2.setText("2011.10.04"); javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1); jPanel1.setLayout(jPanel1Layout); jPanel1Layout.setHorizontalGroup(jPanel1Layout .createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(jPanel1Layout.createSequentialGroup().addContainerGap().addGroup(jPanel1Layout .createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addComponent(jScrollPane2, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 609, Short.MAX_VALUE) .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 609, Short.MAX_VALUE) .addComponent(prgUploadProgress, javax.swing.GroupLayout.DEFAULT_SIZE, 609, Short.MAX_VALUE) .addComponent(lblProgress) .addGroup(jPanel1Layout.createSequentialGroup().addGroup( jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(jPanel1Layout.createSequentialGroup().addComponent(btnAdd) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(btnDel)) .addComponent(lblMessages)) .addGroup(jPanel1Layout .createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(jPanel1Layout.createSequentialGroup() .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(jLabel1, javax.swing.GroupLayout.DEFAULT_SIZE, 257, Short.MAX_VALUE)) .addGroup(jPanel1Layout.createSequentialGroup().addGap(103, 103, 103) .addComponent(jLabel2))) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(btnUpload))) .addContainerGap())); jPanel1Layout.setVerticalGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(jPanel1Layout.createSequentialGroup().addContainerGap() .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(jPanel1Layout.createSequentialGroup() .addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 244, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addGroup(jPanel1Layout .createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addComponent(btnAdd).addComponent(btnDel).addComponent(btnUpload) .addComponent(jLabel1)) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(lblMessages) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(jScrollPane2, javax.swing.GroupLayout.DEFAULT_SIZE, 87, Short.MAX_VALUE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(lblProgress) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(prgUploadProgress, javax.swing.GroupLayout.PREFERRED_SIZE, 26, javax.swing.GroupLayout.PREFERRED_SIZE) .addGap(35, 35, 35)) .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel1Layout .createSequentialGroup().addComponent(jLabel2).addGap(195, 195, 195))))); javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane()); getContentPane().setLayout(layout); layout.setHorizontalGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup().addContainerGap().addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addContainerGap())); layout.setVerticalGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING).addGroup( javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup().addContainerGap().addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addContainerGap())); }// </editor-fold>//GEN-END:initComponents private void btnUploadActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnUploadActionPerformed // Set busy cursor during upload setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); // Disable all buttons btnUpload.setEnabled(false); btnAdd.setEnabled(false); btnDel.setEnabled(false); // Upload in SwingWorker background thread task = new UploadTask(uploadFiles); task.addPropertyChangeListener(this); task.execute(); return; }//GEN-LAST:event_btnUploadActionPerformed private void btnDelActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnDelActionPerformed int selRows[] = fileTable.getSelectedRows(); DefaultTableModel fileModel = (DefaultTableModel) fileTable.getModel(); // Delete all selected files from the table AND file list int numRows = fileTable.getSelectedRows().length; for (int i = 0; i < numRows; i++) { int delRow = fileTable.getSelectedRow(); String fileName = (String) fileModel.getValueAt(delRow, 0); uploadFiles.remove(delRow); fileModel.removeRow(delRow); } // if not files left disable upload if (uploadFiles.isEmpty()) { btnUpload.setEnabled(false); } }//GEN-LAST:event_btnDelActionPerformed private void btnAddActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnAddActionPerformed // Create & show file chooser with extension filter as per applet param JFileChooser fc = new JFileChooser(); fc.setFileFilter(new CustomFileFilter(fileExtensions)); fc.setMultiSelectionEnabled(true); fc.showOpenDialog(UploadApplet.this); // Add selected files to upload queue File[] selFiles = fc.getSelectedFiles(); addFiles(selFiles); } // addFiles // Add array of File objects to upload queue // private void addFiles(File[] files) { DefaultTableModel fileModel = (DefaultTableModel) fileTable.getModel(); for (int i = 0; i < files.length; i++) { String filePath = files[i].getAbsolutePath(); String fileName = files[i].getName(); long fileSize = files[i].length(); txtMessages.append("Selected file: " + fileName + "\n"); UploadFile uf = new UploadFile(filePath, fileName, fileSize, "Not Uploaded"); // Check if file already exists if (uploadFiles.contains(uf)) { JOptionPane.showMessageDialog(this, "File already in list:\n" + fileName); } else { // Add to upload queue list uploadFiles.add(uf); // Add to table fileModel.addRow(uf.getTableRow()); // Allow upload once a file has been selected btnUpload.setEnabled(true); } } }//GEN-LAST:event_btnAddActionPerformed // btnAddActionPerformed // Event handler for add button click // // btnDelActionPerformed // Event handler for delete button click // // btnUploadActionPerformed // Event handler for upload button click // // propertyChange // Handle SwingWorker progress property changes to update progress bar // public void propertyChange(PropertyChangeEvent evt) { if (evt.getPropertyName().equals("progress")) { int progress = (Integer) evt.getNewValue(); prgUploadProgress.setValue(progress); } } // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JButton btnAdd; private javax.swing.JButton btnDel; private javax.swing.JButton btnUpload; private javax.swing.JTable fileTable; private javax.swing.JLabel jLabel1; private javax.swing.JLabel jLabel2; private javax.swing.JPanel jPanel1; private javax.swing.JScrollPane jScrollPane1; private javax.swing.JScrollPane jScrollPane2; private javax.swing.JLabel lblMessages; private javax.swing.JLabel lblProgress; private javax.swing.JProgressBar prgUploadProgress; private javax.swing.JTextArea txtMessages; // End of variables declaration//GEN-END:variables }