1 19 package org.netbeans.modules.ruby.railsprojects.server; 20 21 import java.awt.Dialog ; 22 import java.awt.event.ActionEvent ; 23 import java.io.BufferedReader ; 24 import java.io.File ; 25 import java.io.IOException ; 26 import java.io.InputStreamReader ; 27 import java.io.PrintWriter ; 28 import java.net.InetSocketAddress ; 29 import java.net.MalformedURLException ; 30 import java.net.Socket ; 31 import java.net.URL ; 32 import java.util.ArrayList ; 33 import java.util.List ; 34 import javax.swing.AbstractAction ; 35 import org.netbeans.modules.ruby.rubyproject.api.RubyExecution; 36 import org.netbeans.modules.ruby.rubyproject.execution.DirectoryFileLocator; 37 import org.netbeans.modules.ruby.rubyproject.execution.ExecutionService; 38 import org.netbeans.modules.ruby.rubyproject.api.RubyInstallation; 39 import org.netbeans.api.progress.ProgressHandle; 40 import org.netbeans.api.progress.ProgressHandleFactory; 41 import org.netbeans.modules.ruby.rubyproject.execution.ExecutionDescriptor; 42 import org.netbeans.modules.ruby.rubyproject.execution.OutputRecognizer; 43 import org.netbeans.modules.ruby.rubyproject.execution.OutputRecognizer.RecognizedOutput; 44 import org.openide.DialogDescriptor; 45 import org.openide.DialogDisplayer; 46 import org.openide.awt.HtmlBrowser; 47 import org.openide.awt.StatusDisplayer; 48 import org.openide.filesystems.FileUtil; 49 import org.openide.util.Cancellable; 50 import org.openide.util.NbBundle; 51 import org.openide.util.RequestProcessor; 52 import org.netbeans.api.project.Project; 53 import org.netbeans.api.project.ProjectInformation; 54 import org.openide.ErrorManager; 55 56 57 66 public class WebrickServer { 67 private ServerStatus status = ServerStatus.NOT_STARTED; 68 private boolean cancelled; 69 private boolean portConflict; 70 private int port = -1; 71 private Project project; 72 File dir; 73 74 public WebrickServer(Project project) { 75 this.project = project; 76 dir = FileUtil.toFile(project.getProjectDirectory()); 77 } 78 79 public void ensureRunning() { 80 synchronized (WebrickServer.this) { 81 if (status == ServerStatus.STARTING) { 82 return; 83 } else if (status == ServerStatus.RUNNING) { 84 if (isPortInUse(port)) { 85 return; 87 } 88 } 89 } 90 91 Runnable finishedAction = 93 new Runnable () { 94 public void run() { 95 synchronized (WebrickServer.this) { 96 status = ServerStatus.NOT_STARTED; 97 if (portConflict) { 98 updatePort(); 100 } 101 } 102 } 103 }; 104 105 synchronized (WebrickServer.this) { 107 status = ServerStatus.STARTING; 108 } 109 110 portConflict = false; 111 if (port == -1) { 112 port = RubyInstallation.getInstance().getRailsPort(); 113 } 114 while(isPortInUse(port)) { 115 port++; 116 } 117 String name = project.getLookup().lookup(ProjectInformation.class).getDisplayName(); 118 new ExecutionService(new ExecutionDescriptor(NbBundle.getMessage(WebrickServer.class, "WEBrickTab", name, Integer.toString(port)), dir, 119 "script" + File.separator + "server", "--port", Integer.toString(port)).postBuild(finishedAction) .addOutputRecognizer(RubyExecution.RUBY_COMPILER) 121 .addOutputRecognizer(new WebrickMessageListener()) 122 .fileLocator(new DirectoryFileLocator(FileUtil.toFileObject(dir))) 123 .showProgress(false)) 124 .run(); 125 } 126 127 private void updatePort() { 128 final PortConflictPanel panel = new PortConflictPanel(RubyInstallation.getInstance().getRailsPort()); 129 Object [] options = new Object [] { 131 DialogDescriptor.OK_OPTION, 133 DialogDescriptor.CANCEL_OPTION 134 }; 135 DialogDescriptor desc = new DialogDescriptor ( 147 panel, 148 NbBundle.getMessage (WebrickServer.class, "LBL_PortTitle" ), 149 true, 150 options, 151 options[0], 152 DialogDescriptor.BOTTOM_ALIGN, 153 null, 154 null); 155 Dialog dlg = DialogDisplayer.getDefault ().createDialog (desc); 157 dlg.setVisible (true); 158 if (desc.getValue() == options[0]) { 159 RubyInstallation.getInstance().setRailsPort(panel.getPort()); 160 ensureRunning(); 162 } 163 dlg.dispose(); 164 } 165 166 169 public synchronized void showUrl(final String relativeUrl) { 170 synchronized (WebrickServer.this) { 171 if (status == ServerStatus.RUNNING && isPortInUse(port)) { 172 try { 173 URL url = new URL ("http://localhost:" + port + "/" + relativeUrl); HtmlBrowser.URLDisplayer.getDefault().showURL(url); 175 } catch (MalformedURLException ex) { 176 ErrorManager.getDefault().notify(ex); 177 } 178 return; 179 } 180 181 ensureRunning(); 182 } 183 184 cancelled = false; 185 186 String displayName = NbBundle.getMessage(WebrickServer.class, "ServerStartup"); 187 final ProgressHandle handle = 188 ProgressHandleFactory.createHandle(displayName, 189 new Cancellable() { 190 public boolean cancel() { 191 synchronized (WebrickServer.this) { 192 cancelled = true; 193 } 194 195 return true; 196 } 197 }, 198 new AbstractAction () { 199 public void actionPerformed(ActionEvent e) { 200 } 202 }); 203 204 handle.start(); 205 handle.switchToIndeterminate(); 206 207 RequestProcessor.getDefault().post(new Runnable () { 208 public void run() { 209 try { 210 for (int i = 0; i < 20; i++) { 212 try { 213 Thread.currentThread().sleep(1000); 214 } catch (InterruptedException ie) { 215 ; } 217 218 synchronized (WebrickServer.this) { 219 if (status == ServerStatus.RUNNING) { 220 try { 221 URL url = new URL ("http://localhost:" + port + "/" + relativeUrl); HtmlBrowser.URLDisplayer.getDefault().showURL(url); 223 } catch (MalformedURLException ex) { 224 ErrorManager.getDefault().notify(ex); 225 } 226 227 return; 228 } 229 230 if (status == ServerStatus.NOT_STARTED) { 231 break; 233 } 234 } 235 236 290 } 291 292 StatusDisplayer.getDefault() 293 .setStatusText(NbBundle.getMessage(WebrickServer.class, 294 "NoServerFound", "http://localhost:" + port + "/" + relativeUrl)); 295 296 } finally { 299 handle.finish(); 300 } 301 } 302 }); 303 } 304 305 308 public static boolean isPortInUse(int port) { 309 int timeout = 3000; 310 Socket socket = new Socket (); 311 try { 312 try { 313 socket.connect(new InetSocketAddress ("localhost", port), timeout); socket.setSoTimeout(timeout); 315 PrintWriter out = new PrintWriter (socket.getOutputStream(), true); 316 try { 317 BufferedReader in = new BufferedReader (new InputStreamReader (socket.getInputStream())); 318 try { 319 out.println("GET /\n"); 322 String text = in.readLine(); 324 if (text == null || !text.startsWith("<!DOCTYPE")) { return false; } 327 return true; 328 } finally { 329 in.close(); 330 } 331 } finally { 332 out.close(); 333 } 334 } finally { 335 socket.close(); 336 } 337 } catch (IOException ioe) { 338 return false; 339 } 340 } 341 342 private class WebrickMessageListener extends OutputRecognizer { 343 public RecognizedOutput processLine(String line) { 344 if (line.contains("Rails application started on")) { 349 synchronized (WebrickServer.this) { 350 status = ServerStatus.RUNNING; 351 } 352 } else if (line.contains("in `new': Address in use (Errno::EADDRINUSE)")) { 353 portConflict = true; 354 } 355 356 return null; 357 } 358 } 359 enum ServerStatus {NOT_STARTED, STARTING, RUNNING; 360 } 361 } 362 | Popular Tags |