Java tutorial
/* Copyright (C) 2009 Rachel Engel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /* * To change this template, choose Tools | Templates * and open the template in the editor. */ /* * ThirdIdea.java * * Created on May 14, 2009, 3:30:45 PM */ package com.isecpartners.gizmo; import java.awt.event.ActionEvent; import java.awt.event.KeyEvent; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.PrintWriter; import java.io.UnsupportedEncodingException; import java.util.LinkedList; import java.util.List; import java.util.logging.Level; import java.util.logging.Logger; import java.util.Map; import java.util.Properties; import java.util.StringTokenizer; import java.util.Vector; import java.util.regex.Matcher; import java.util.regex.Pattern; import javax.swing.AbstractAction; import javax.swing.JComponent; import javax.swing.KeyStroke; import javax.swing.event.CaretEvent; import javax.swing.event.CaretListener; import org.apache.commons.codec.binary.Base64; import org.jdesktop.application.Action; /** * * @author rachel */ public class FourthIdea extends javax.swing.JFrame implements CaretListener { private Properties command_translation; private BlobScroller scroller; private String reqText; private List<String> temp_files_to_clean_up = new LinkedList<String>(); private File buffer_file; private static final String command_map_file_name = "command_map.properties"; /* * I think the way to keep text selected after the user's clicked on the command area is to * re-highlight any text when the command line gets focus. If we can't detect when the command * line gets focus, we re-highlight it when we execute the command. Once the command is finished, * we re-highlight the new text and start waiting for a click or a keypress. Either a click or a * keypress de-selects the text. I think. */ public FourthIdea(final BlobScroller scroller, final HTTPMessage msg, final boolean request) { try { this.buffer_file = File.createTempFile("tmp", "end"); } catch (IOException ex) { Logger.getLogger(FourthIdea.class.getName()).log(Level.SEVERE, null, ex); } initComponents(); init(scroller, msg.contents(), new AbstractAction() { public void actionPerformed(ActionEvent e) { if (request) { scroller.setCommand(jTextPane1.getText(), request, (HttpRequest) msg); } FourthIdea.this.dispose(); } }); } public FourthIdea(final BlobScroller scroller, String str) { initComponents(); init(scroller, str, new AbstractAction() { public void actionPerformed(ActionEvent e) { FourthIdea.this.dispose(); } }); } private String apply_macros(String command_string) { if (command_translation == null) return command_string; for (Object obj : command_translation.keySet()) { String key = (String) obj; String value = (String) command_translation.get(key); String regex = "^([\\s]*\\" + key + ").*"; // so the goal here is to substitute the pattern *only* if it shows up first // and ignore trailing spaces. i want to take the first group, remove that // and then prepend the replacement string to what's left. Matcher match = Pattern.compile(regex).matcher(command_string); if (match.matches()) { if (match.groupCount() != 1) break; String found_str = match.group(1); int end_of_match = command_string.indexOf(found_str) + found_str.length(); command_string = value + " " + command_string.substring(end_of_match + 1); } command_string = Pattern.compile(key).matcher(command_string).replaceAll(value); } return command_string; } private void init(final BlobScroller scroller, String str, final AbstractAction action) { this.scroller = scroller; this.reqText = str; if (System.getProperty("os.name").toUpperCase().contains("WINDOWS")) { defaultShellField.setText("cmd.exe /c"); } else { defaultShellField.setText("sh -c"); } this.addWindowListener(new WindowAdapter() { @Override public void windowClosing(WindowEvent e) { action.actionPerformed(null); } }); command_translation = new Properties(); try { command_translation.load(new FileInputStream(command_map_file_name)); } catch (IOException ex) { try { FileOutputStream fout = new FileOutputStream(command_map_file_name); fout.write("".getBytes()); fout.close(); } catch (IOException ex1) { } GizmoView.log("couldn't find " + command_map_file_name + ".. turning off macro translation"); } jTextPane1.setText(str); jTextPane1.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), "esc"); jTextPane1.getActionMap().put("esc", action); } // Turn an environment map into an environment vector. // Get an environment into a vector. Save the first n slots for use. private String[] getenv(int n) { Map<String, String> m = System.getenv(); String ret[] = new String[n + m.size()]; for (Map.Entry<String, String> e : m.entrySet()) { if (e.getKey().toUpperCase().trim().equals("PATH")) { ret[n++] = e.getKey() + "=" + e.getValue() + System.getProperty("path.separator") + "scripts"; } else { ret[n++] = e.getKey() + "=" + e.getValue(); } } return ret; } private void cleanup_temp_files() { for (String str : temp_files_to_clean_up) { new File(str).delete(); } } private void executeCommand(final String text) { final InputStream procInput; new Thread(new Runnable() { public void run() { String newRequestText = ""; try { temp_files_to_clean_up.add(buffer_file.getCanonicalPath()); PrintWriter out = new PrintWriter(new FileOutputStream(buffer_file)); byte[] requestBuf = null; if (jTextPane1.getSelectedText() != null && jTextPane1.getSelectedText().length() > 0) { out.write(jTextPane1.getSelectedText()); requestBuf = jTextPane1.getSelectedText().getBytes(); } else { out.write(jTextPane1.getText()); requestBuf = jTextPane1.getText().getBytes(); } out.close(); String env[] = getenv(1); env[0] = "BUF=" + buffer_file.getCanonicalPath(); String cmd = ""; if (System.getProperty("os.name").toUpperCase().contains("WINDOWS")) { cmd = "type " + buffer_file + "|" + text; } else { cmd = "cat " + buffer_file + "|" + text; } newRequestText = exec(cmd, env, requestBuf); } catch (IOException ex) { Logger.getLogger(FourthIdea.class.getName()).log(Level.SEVERE, null, ex); } finally { if (jTextPane1.getSelectedText() != null && jTextPane1.getSelectedText().length() > 0) { jTextPane1.replaceSelection(newRequestText); } else { FourthIdea.this.jTextPane1.setText(newRequestText); } } } private String readWholeFile(File file) { InputStream in = null; String ret = ""; try { in = new FileInputStream(file); int file_size = Integer.MAX_VALUE; if (file.length() < Integer.MAX_VALUE) { file_size = (int) file.length(); } byte[] buf = new byte[file_size]; // truncated because for some reason, a byte array is initialized with an int instead of a long // so this's a bit awful, but if you're editing a request bigger than 2G in size, then don't in.read(buf); ret = new String(buf); } catch (IOException ex) { Logger.getLogger(FourthIdea.class.getName()).log(Level.SEVERE, null, ex); } finally { try { in.close(); } catch (IOException ex) { Logger.getLogger(FourthIdea.class.getName()).log(Level.SEVERE, null, ex); } } return ret; } }).start(); } /** This method is called from within the constructor 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() { jLabel1 = new javax.swing.JLabel(); defaultShellField = new javax.swing.JTextField(); jScrollPane1 = new javax.swing.JScrollPane(); jTextPane1 = new javax.swing.JTextPane(); jTextField1 = new javax.swing.JTextField(); jPanel1 = new javax.swing.JPanel(); jPanel2 = new javax.swing.JPanel(); jScrollPane2 = new javax.swing.JScrollPane(); shell_output_area = new javax.swing.JTextArea(); setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE); setName("Form"); // NOI18N org.jdesktop.application.ResourceMap resourceMap = org.jdesktop.application.Application.getInstance() .getContext().getResourceMap(FourthIdea.class); jLabel1.setText(resourceMap.getString("jLabel1.text")); // NOI18N jLabel1.setName("jLabel1"); // NOI18N defaultShellField.setText(resourceMap.getString("defaultShellField.text")); // NOI18N defaultShellField.setName("defaultShellField"); // NOI18N jScrollPane1.setName("jScrollPane1"); // NOI18N jTextPane1.setName("jTextPane1"); // NOI18N jScrollPane1.setViewportView(jTextPane1); jTextField1.setText(resourceMap.getString("jTextField1.text")); // NOI18N jTextField1.setName("jTextField1"); // NOI18N jTextField1.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { jTextField1ActionPerformed(evt); } }); jPanel1.setName("jPanel1"); // NOI18N jPanel2.setName("jPanel2"); // NOI18N jScrollPane2.setName("jScrollPane2"); // NOI18N shell_output_area.setBackground(resourceMap.getColor("shell_output_area.background")); // NOI18N shell_output_area.setColumns(20); shell_output_area.setEditable(false); shell_output_area.setRows(5); shell_output_area.setName("shell_output_area"); // NOI18N jScrollPane2.setViewportView(shell_output_area); javax.swing.GroupLayout jPanel2Layout = new javax.swing.GroupLayout(jPanel2); jPanel2.setLayout(jPanel2Layout); jPanel2Layout .setHorizontalGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addComponent(jScrollPane2, javax.swing.GroupLayout.DEFAULT_SIZE, 775, Short.MAX_VALUE)); jPanel2Layout.setVerticalGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addComponent(jScrollPane2, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 295, Short.MAX_VALUE)); javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1); jPanel1.setLayout(jPanel1Layout); jPanel1Layout.setHorizontalGroup( jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING).addComponent(jPanel2, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)); jPanel1Layout.setVerticalGroup( jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING).addComponent(jPanel2, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)); javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane()); getContentPane().setLayout(layout); layout.setHorizontalGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup().addComponent(jLabel1) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(defaultShellField, javax.swing.GroupLayout.PREFERRED_SIZE, 81, javax.swing.GroupLayout.PREFERRED_SIZE) .addGap(628, 628, 628)) .addComponent(jTextField1, javax.swing.GroupLayout.DEFAULT_SIZE, 775, Short.MAX_VALUE) .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 775, Short.MAX_VALUE) .addComponent(jPanel1, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)); layout.setVerticalGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addComponent(jLabel1, javax.swing.GroupLayout.DEFAULT_SIZE, 19, Short.MAX_VALUE) .addComponent(defaultShellField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 305, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(jTextField1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED).addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))); pack(); }// </editor-fold>//GEN-END:initComponents private void jTextField1ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jTextField1ActionPerformed executeCommand(jTextField1.getText()); }//GEN-LAST:event_jTextField1ActionPerformed // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JTextField defaultShellField; private javax.swing.JLabel jLabel1; private javax.swing.JPanel jPanel1; private javax.swing.JPanel jPanel2; private javax.swing.JScrollPane jScrollPane1; private javax.swing.JScrollPane jScrollPane2; private javax.swing.JTextField jTextField1; private javax.swing.JTextPane jTextPane1; private javax.swing.JTextArea shell_output_area; // End of variables declaration//GEN-END:variables public String exec(String command_string, String[] env, byte[] requestBuf) { StringBuffer display_text = new StringBuffer(); String out = ""; try { String shell = defaultShellField.getText(); Process proc = null; command_string = apply_macros(command_string); if (System.getProperty("os.name").toUpperCase().contains("WINDOWS")) { String[] args = translateCommandline(shell + " " + command_string); proc = Runtime.getRuntime().exec(args, env); } else { String[] shell_pieces = shell.split("\\s+"); String args[] = new String[shell_pieces.length + 1]; System.arraycopy(shell_pieces, 0, args, 0, shell_pieces.length); args[args.length - 1] = command_string; proc = Runtime.getRuntime().exec(args, env); } out = readOutput(proc); String err = readError(proc); proc.waitFor(); proc.destroy(); display_text.append("\n\n" + out + err); appendToOutputArea(display_text.toString()); } catch (InterruptedException ex) { Logger.getLogger(FourthIdea.class.getName()).log(Level.SEVERE, null, ex); } catch (IOException ex) { Logger.getLogger(FourthIdea.class.getName()).log(Level.SEVERE, null, ex); } catch (Exception e) { GizmoView.log(e.toString()); } return out; } private void appendToOutputArea(String output) { shell_output_area.setText(shell_output_area.getText() + output); shell_output_area.getCaret().setVisible(true); shell_output_area.setCaretPosition(shell_output_area.getText().length() - 1); } private void pipe(String command_string) { command_string = command_string.trim().replaceFirst("|", ""); } private String readError(Process proc) { return readStream(proc, proc.getErrorStream()); } private String readOutput(Process proc) { return readStream(proc, proc.getInputStream()); } private static String[] translateCommandline(final String toProcess) { if (toProcess == null || toProcess.length() == 0) { // no command? no string return new String[0]; } // parse with a simple finite state machine final int normal = 0; final int inQuote = 1; final int inDoubleQuote = 2; int state = normal; StringTokenizer tok = new StringTokenizer(toProcess, "\"\' ", true); Vector v = new Vector(); StringBuffer current = new StringBuffer(); boolean lastTokenHasBeenQuoted = false; while (tok.hasMoreTokens()) { String nextTok = tok.nextToken(); switch (state) { case inQuote: if ("\'".equals(nextTok)) { lastTokenHasBeenQuoted = true; state = normal; } else { current.append(nextTok); } break; case inDoubleQuote: if ("\"".equals(nextTok)) { lastTokenHasBeenQuoted = true; state = normal; } else { current.append(nextTok); } break; default: if ("\'".equals(nextTok)) { state = inQuote; } else if ("\"".equals(nextTok)) { state = inDoubleQuote; } else if (" ".equals(nextTok)) { if (lastTokenHasBeenQuoted || current.length() != 0) { v.addElement(current.toString()); current = new StringBuffer(); } } else { current.append(nextTok); } lastTokenHasBeenQuoted = false; break; } } if (lastTokenHasBeenQuoted || current.length() != 0) { v.addElement(current.toString()); } if (state == inQuote || state == inDoubleQuote) { throw new IllegalArgumentException("Unbalanced quotes in " + toProcess); } String[] args = new String[v.size()]; v.copyInto(args); return args; } private String readStream(Process proc, InputStream in) { StringBuffer ret = new StringBuffer(); try { int n = in.read(); while (n != -1) { ret.append((char) n); n = in.read(); } } catch (IOException ex) { Logger.getLogger(FourthIdea.class.getName()).log(Level.SEVERE, null, ex); } return ret.toString(); } private String readWholeFile(String filename) { InputStream in = null; String ret = ""; try { File f = new File(filename); in = new FileInputStream(f); int file_size = Integer.MAX_VALUE; if (f.length() < Integer.MAX_VALUE) { file_size = (int) f.length(); } byte[] buf = new byte[file_size]; // truncated because for some reason, a byte array is initialized with an int instead of a long // so this's a bit awful, but if you're editing a request bigger than 2G in size, then don't in.read(buf); ret = new String(buf); } catch (IOException ex) { Logger.getLogger(FourthIdea.class.getName()).log(Level.SEVERE, null, ex); } finally { try { in.close(); } catch (IOException ex) { Logger.getLogger(FourthIdea.class.getName()).log(Level.SEVERE, null, ex); } } return ret; } private String process_req_variable(String text) { PrintWriter out = null; String ret = text; try { File tmp2 = File.createTempFile("tmp", "end"); temp_files_to_clean_up.add(tmp2.getCanonicalPath()); out = new PrintWriter(new FileOutputStream(tmp2)); out.write(reqText); out.close(); ret = ret.replace("$REQ", "\"" + tmp2.getCanonicalPath() + "\""); } catch (IOException ex) { Logger.getLogger(FourthIdea.class.getName()).log(Level.SEVERE, null, ex); } finally { out.close(); } return ret; } @Action public void b64encode() { String original_text = jTextPane1.getSelectedText(); String new_text = new String(Base64.encodeBase64(original_text.getBytes())); jTextPane1.replaceSelection(new_text); } @Action public void b64decode() { String original_text = jTextPane1.getSelectedText(); String new_text = new String(Base64.decodeBase64(original_text.getBytes())); jTextPane1.replaceSelection(new_text); } @Action public void urlencode() { try { String original_text = jTextPane1.getSelectedText(); String new_text = java.net.URLEncoder.encode(original_text, "UTF-8"); jTextPane1.replaceSelection(new_text); } catch (UnsupportedEncodingException ex) { Logger.getLogger(FourthIdea.class.getName()).log(Level.SEVERE, null, ex); } } @Action public void urldecode() { try { String original_text = jTextPane1.getSelectedText(); String new_text = java.net.URLDecoder.decode(original_text, "UTF-8"); jTextPane1.replaceSelection(new_text); } catch (UnsupportedEncodingException ex) { Logger.getLogger(FourthIdea.class.getName()).log(Level.SEVERE, null, ex); } } public void caretUpdate(CaretEvent e) { throw new UnsupportedOperationException("Not supported yet."); } private void writeToProcess(Process proc, byte[] buf) { try { proc.getOutputStream().write(buf, 0, buf.length); } catch (IOException ex) { Logger.getLogger(FourthIdea.class.getName()).log(Level.SEVERE, null, ex); } } }