View Javadoc

1   /*
2    * $Id$
3    *
4    * The contents of this file are subject to the Mozilla Public License 
5    * Version 1.1 (the "License"); you may not use this file except in 
6    * compliance with the License. You may obtain a copy of the License at 
7    * http://www.mozilla.org/MPL/ 
8    *
9    * Software distributed under the License is distributed on an "AS IS" basis, 
10   * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License 
11   * for the specific language governing rights and limitations under the License.
12   *
13   * The Original Code is XML Hammer code. (org.xmlhammer.*)
14   *
15   * The Initial Developer of the Original Code is Edwin Dankert. Portions created 
16   * by the Initial Developer are Copyright (C) 2005 - 2006 the Initial Developer. 
17   * All Rights Reserved.
18   *
19   * Contributor(s): Edwin Dankert <edankert@gmail.com>
20   */
21  package org.xmlhammer.gui.util;
22  
23  import java.io.BufferedReader;
24  import java.io.File;
25  import java.io.IOException;
26  import java.io.InputStream;
27  import java.io.InputStreamReader;
28  import java.io.PrintStream;
29  import java.net.MalformedURLException;
30  import java.net.URI;
31  import java.util.StringTokenizer;
32  import java.util.regex.Matcher;
33  import java.util.regex.Pattern;
34  
35  import org.apache.log4j.Logger;
36  import org.bounce.util.URIUtils;
37  
38  import edu.stanford.ejalbert.BrowserLauncher;
39  import edu.stanford.ejalbert.BrowserLauncherRunner;
40  import edu.stanford.ejalbert.exception.BrowserLaunchingInitializingException;
41  import edu.stanford.ejalbert.exception.UnsupportedOperatingSystemException;
42  
43  public class ExternalApplicationLauncher {
44      public static String FILE_PATTERN = "${file}";
45      public static String LINE_PATTERN = "${line}";
46      public static String COLUMN_PATTERN = "${column}";
47      
48      private static ExternalApplicationLauncher instance = null;
49      private String extensions = null;
50      private String defaultCommand = null;
51      private String editorCommand = null;
52  
53      private ExternalApplicationLauncher() {
54          super();
55      }
56      
57      public static ExternalApplicationLauncher getInstance() {
58          if (instance == null) {
59              instance = new ExternalApplicationLauncher();
60          }
61          
62          return instance;
63      }
64  
65      public void setBrowserExtensions(String extensions) {
66          this.extensions = extensions;
67      }
68  
69      public void setDefaultCommand(String command) {
70          defaultCommand = command;
71      }
72  
73      public void setEditorCommand(String command) {
74          editorCommand = command;
75      }
76  
77      public void open(URI uri, int line, int column) {
78          File file = getFile(uri);
79  
80          if (isBrowserExtension(uri) || file == null || defaultCommand == null || defaultCommand.trim().length() == 0) {
81              browse(uri);
82          } else {
83              run(defaultCommand, file, line, column);
84          }
85      }
86  
87      public void edit(URI uri, int line, int column) {
88          File file = getFile(uri);
89  
90          if (file != null) {
91              if (editorCommand != null && editorCommand.trim().length() > 0) {
92                  run(editorCommand, file, line, column);
93              } else {
94                  open(uri, line, column);
95              }
96          } else {
97              browse(uri);
98          }
99      }
100     
101     public File getFile(URI uri) {
102         File result = null;
103         
104         try {
105             result = new File(uri);
106         } catch (Exception e) {
107         }
108         
109         return result;
110     }
111 
112     public void browse(URI uri) {
113         if (uri != null) {
114             try {
115                 BrowserLauncher launcher = new BrowserLauncher(null);
116                 BrowserLauncherRunner runner = new BrowserLauncherRunner(launcher, URIUtils.toString(uri), null);
117                 Thread launcherThread = new Thread(runner);
118                 launcherThread.start();
119             } catch (BrowserLaunchingInitializingException e) {
120                 Logger.getLogger("org.xmlhammer.gui.util.ExternalApplicationLauncher").debug(e);
121             } catch (UnsupportedOperatingSystemException e) {
122                 Logger.getLogger("org.xmlhammer.gui.util.ExternalApplicationLauncher").debug(e);
123             }
124         }
125     }
126     
127     public void run(String command, File file, int line, int column) {
128         String resolvedCommand = replace(command, LINE_PATTERN, ""+Math.max(0,line));;
129         resolvedCommand = replace(resolvedCommand, COLUMN_PATTERN, ""+Math.max(0,column));
130         
131         if (resolvedCommand.indexOf(FILE_PATTERN) != -1) {
132             resolvedCommand = replace(resolvedCommand, FILE_PATTERN, file.toString());
133         } else {
134             resolvedCommand = resolvedCommand+" \""+file+"\"";
135         }
136         
137         try {
138             Process process = Runtime.getRuntime().exec(resolvedCommand);
139 
140             StreamReader errorReader = new StreamReader(process.getErrorStream(), System.err);            
141             StreamReader outputReader = new StreamReader(process.getInputStream(), System.out);
142                 
143             // kick them off
144             errorReader.start();
145             outputReader.start();
146         } catch (MalformedURLException e) {
147             Logger.getLogger("org.xmlhammer.gui.util.ExternalApplicationLauncher").debug(e);
148         } catch (IOException e) {
149             Logger.getLogger("org.xmlhammer.gui.util.ExternalApplicationLauncher").debug(e);
150         }
151     }
152     
153     private boolean isBrowserExtension(URI uri) {
154         StringTokenizer tokenizer = new StringTokenizer(extensions, " \t\n\r\f,;|");
155         
156         while (tokenizer.hasMoreTokens()) {
157             String extension = tokenizer.nextToken();
158             if (uri.getPath().endsWith(extension)) {
159                 return true;
160             }
161         }
162 
163         return false;
164     }
165 
166     class StreamReader extends Thread {
167         InputStream input = null;
168         PrintStream printer = null;
169 
170         public StreamReader(InputStream input, PrintStream printer) {
171             this.input = input;
172             this.printer = printer;
173         }
174 
175         public void run() {
176             try {
177                 BufferedReader reader = new BufferedReader(
178                         new InputStreamReader(input));
179                 String line = reader.readLine();
180 
181                 while (line != null) {
182                     printer.println(line);
183                     line = reader.readLine();
184                 }
185             } catch (IOException e) {
186                 Logger.getLogger("org.xmlhammer.gui.util.ExternalApplicationLauncher").debug(e);
187             }
188         }
189     }
190     
191     private static String replace(String source, String search, String replacement) {
192         String result = null;
193         
194         search = "//Q"+prepareNonRegularExpression(search)+"//E";
195         replacement = prepareNonRegularExpressionReplacement(replacement);
196 
197         Pattern pattern = Pattern.compile(search, Pattern.CASE_INSENSITIVE);
198 
199         try {
200             Matcher matcher = pattern.matcher(source);
201             result = matcher.replaceAll(replacement);
202         } catch( Exception e) {
203             Logger.getLogger("org.xmlhammer.gui.util.ExternalApplicationLauncher").debug(e);
204         }
205         
206         return result;
207     }
208     
209     private static String prepareNonRegularExpressionReplacement( String regexp) {
210         StringBuffer result = new StringBuffer( regexp);
211         
212         int index = result.indexOf( "//");
213         
214         while ( index != -1) {
215             result.replace( index, index+1, "////");
216             index = result.indexOf( "//", index+2);
217         }
218         
219         index = result.indexOf( "$");
220         
221         while ( index != -1) {
222             result.replace( index, index+1, "//$");
223             index = result.indexOf( "$", index+2);
224         }
225 
226         return result.toString();
227     }
228 
229     private static String prepareNonRegularExpression( String regexp) {
230         StringBuffer result = new StringBuffer( regexp);
231         
232         int index = result.indexOf( "//E");
233         
234         while ( index != -1) {
235             result.replace( index, index+2, "//E////E//Q");
236             index = result.indexOf( "//E", index+7);
237         }
238         
239         // Last character is a '\', make sure to escape otherwise it will escape 
240         // the \E and we don't see the end of the non-regular expression.
241         if ( result.charAt( result.length()-1) == '//') {
242             result.append( "E//////Q");
243         }
244 
245         return result.toString();
246     }
247 }