C:\nb_all\scripting\ruby>cls C:\nb_all\scripting\ruby>cvs -q diff -u ? diff.txt Index: railsprojects/src/org/netbeans/modules/ruby/railsprojects/RailsActionProvider.java =================================================================== RCS file: /cvs/scripting/ruby/railsprojects/src/org/netbeans/modules/ruby/railsprojects/RailsActionProvider.java,v retrieving revision 1.5 diff -u -r1.5 RailsActionProvider.java --- railsprojects/src/org/netbeans/modules/ruby/railsprojects/RailsActionProvider.java 8 Mar 2007 22:44:11 -0000 1.5 +++ railsprojects/src/org/netbeans/modules/ruby/railsprojects/RailsActionProvider.java 9 Mar 2007 16:21:58 -0000 @@ -121,20 +121,10 @@ // Save all files first LifecycleManager.getDefault().saveAll(); - // Start the server, if necessary - //WebrickServer.getInstance().ensureRunning(FileUtil.toFile(project.getProjectDirectory())); - - try { - RubyInstallation installation = RubyInstallation.getInstance(); - URL url = new URL("http://localhost:" + installation.getRailsPort() + "/"); // NOI18N - //URL url = new URL("http://localhost:" + installation.getRailsPort()); // NOI18N - - //HtmlBrowser.URLDisplayer.getDefault().showURL(url); - WebrickServer.getInstance().showUrl(FileUtil.toFile(project.getProjectDirectory()), url); + WebrickServer server = project.getLookup().lookup(WebrickServer.class); + if (server != null) { + server.showUrl(""); //NOI18N } - catch (MalformedURLException ex) { - ErrorManager.getDefault().notify(ex); - }; return; } else if (COMMAND_RUN_SINGLE.equals(command)) { @@ -181,19 +171,10 @@ return; } - // Start the server, if necessary - //WebrickServer.getInstance().ensureRunning(FileUtil.toFile(project.getProjectDirectory())); - - try { - RubyInstallation installation = RubyInstallation.getInstance(); - URL url = new URL("http://localhost:" + installation.getRailsPort() + "/" + path); // NOI18N - - //HtmlBrowser.URLDisplayer.getDefault().showURL(url); - WebrickServer.getInstance().showUrl(FileUtil.toFile(project.getProjectDirectory()), url); + WebrickServer server = project.getLookup().lookup(WebrickServer.class); + if (server != null) { + server.showUrl(path); } - catch (MalformedURLException ex) { - ErrorManager.getDefault().notify(ex); - }; return; } else if (COMMAND_BUILD.equals(command)) { Index: railsprojects/src/org/netbeans/modules/ruby/railsprojects/RailsProject.java =================================================================== RCS file: /cvs/scripting/ruby/railsprojects/src/org/netbeans/modules/ruby/railsprojects/RailsProject.java,v retrieving revision 1.1 diff -u -r1.1 RailsProject.java --- railsprojects/src/org/netbeans/modules/ruby/railsprojects/RailsProject.java 30 Jan 2007 01:06:44 -0000 1.1 +++ railsprojects/src/org/netbeans/modules/ruby/railsprojects/RailsProject.java 9 Mar 2007 16:21:58 -0000 @@ -34,6 +34,7 @@ import org.netbeans.api.project.ProjectManager; import org.netbeans.modules.ruby.railsprojects.SourceRoots; import org.netbeans.modules.ruby.railsprojects.classpath.ClassPathProviderImpl; +import org.netbeans.modules.ruby.railsprojects.server.WebrickServer; import org.netbeans.modules.ruby.railsprojects.ui.RailsLogicalViewProvider; import org.netbeans.modules.ruby.railsprojects.ui.customizer.CustomizerProviderImpl; import org.netbeans.modules.ruby.railsprojects.ui.customizer.RailsProjectProperties; @@ -203,7 +204,8 @@ new RailsConfigurationProvider(this), UILookupMergerSupport.createPrivilegedTemplatesMerger(), UILookupMergerSupport.createRecommendedTemplatesMerger(), - LookupProviderSupport.createSourcesMerger() + LookupProviderSupport.createSourcesMerger(), + new WebrickServer(this), }); return LookupProviderSupport.createCompositeLookup(base, "Projects/org-netbeans-modules-ruby-railsprojects/Lookup"); //NOI18N } Index: railsprojects/src/org/netbeans/modules/ruby/railsprojects/RailsProjectGenerator.java =================================================================== RCS file: /cvs/scripting/ruby/railsprojects/src/org/netbeans/modules/ruby/railsprojects/RailsProjectGenerator.java,v retrieving revision 1.3 diff -u -r1.3 RailsProjectGenerator.java --- railsprojects/src/org/netbeans/modules/ruby/railsprojects/RailsProjectGenerator.java 8 Mar 2007 22:44:11 -0000 1.3 +++ railsprojects/src/org/netbeans/modules/ruby/railsprojects/RailsProjectGenerator.java 9 Mar 2007 16:21:59 -0000 @@ -77,9 +77,6 @@ dirFO.getFileSystem().refresh(true); } - // Start the server - WebrickServer.getInstance().ensureRunning(dir); - // TODO - open database.yml and edit in JDBC stuff? RakeProjectHelper h = createProject(dirFO, name/*, "app", "test", mainClass, manifestFile, false*/); //NOI18N @@ -91,6 +88,12 @@ // createMainClass( mainClass, srcFolder, "Templates/Ruby/main.rb" ); // } // createMainClass( "Rakefile.rb", srcFolder, "Templates/Ruby/rakefile.rb" ); + + // Start the server + WebrickServer server = p.getLookup().lookup(WebrickServer.class); + if (server != null) { + server.ensureRunning(); + } return h; } Index: railsprojects/src/org/netbeans/modules/ruby/railsprojects/server/Bundle.properties =================================================================== RCS file: /cvs/scripting/ruby/railsprojects/src/org/netbeans/modules/ruby/railsprojects/server/Bundle.properties,v retrieving revision 1.2 diff -u -r1.2 Bundle.properties --- railsprojects/src/org/netbeans/modules/ruby/railsprojects/server/Bundle.properties 27 Feb 2007 05:11:16 -0000 1.2 +++ railsprojects/src/org/netbeans/modules/ruby/railsprojects/server/Bundle.properties 9 Mar 2007 16:21:59 -0000 @@ -15,6 +15,8 @@ # Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun # Microsystems, Inc. All Rights Reserved. +# 0..project 1..port +WEBrickTab=WEBrick for {0} on {1} WEBrick=WEBrick Web Server ServerStartup=Server Startup NoServerFound=Could not connect to the web server - cannot show {0} Index: railsprojects/src/org/netbeans/modules/ruby/railsprojects/server/WebrickServer.java =================================================================== RCS file: /cvs/scripting/ruby/railsprojects/src/org/netbeans/modules/ruby/railsprojects/server/WebrickServer.java,v retrieving revision 1.5 diff -u -r1.5 WebrickServer.java --- railsprojects/src/org/netbeans/modules/ruby/railsprojects/server/WebrickServer.java 8 Mar 2007 22:44:15 -0000 1.5 +++ railsprojects/src/org/netbeans/modules/ruby/railsprojects/server/WebrickServer.java 9 Mar 2007 16:21:59 -0000 @@ -20,8 +20,17 @@ import java.awt.Dialog; import java.awt.event.ActionEvent; +import java.io.BufferedReader; import java.io.File; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.PrintWriter; +import java.net.InetSocketAddress; +import java.net.MalformedURLException; +import java.net.Socket; import java.net.URL; +import java.util.ArrayList; +import java.util.List; import javax.swing.AbstractAction; import org.netbeans.modules.ruby.rubyproject.api.RubyExecution; import org.netbeans.modules.ruby.rubyproject.execution.DirectoryFileLocator; @@ -40,6 +49,9 @@ import org.openide.util.Cancellable; import org.openide.util.NbBundle; import org.openide.util.RequestProcessor; +import org.netbeans.api.project.Project; +import org.netbeans.api.project.ProjectInformation; +import org.openide.ErrorManager; /** @@ -49,30 +61,34 @@ * write Java web server plugins and take some pointers. Perhaps it can * even implement some of their APIs such that logging, runtime nodes etc. * all begin to work. - * @todo These servers are per-project, I can't have an instance. Attach them - * to projects or cache them per project directory. - * @author Tor Norbye + * @author Tor Norbye, Pavel Buzek */ public class WebrickServer { - static WebrickServer INSTANCE = new WebrickServer(); private ServerStatus status = ServerStatus.NOT_STARTED; private boolean cancelled; private boolean portConflict; - - private WebrickServer() { - } - - public static WebrickServer getInstance() { - return INSTANCE; + private int port = -1; + private Project project; + File dir; + + public WebrickServer(Project project) { + this.project = project; + dir = FileUtil.toFile(project.getProjectDirectory()); } - public void ensureRunning(final File dir) { + public void ensureRunning() { synchronized (WebrickServer.this) { - if (status != ServerStatus.NOT_STARTED) { + if (status == ServerStatus.STARTING) { return; + } else if (status == ServerStatus.RUNNING) { + if (isPortInUse(port)) { + // Simply assume it is still the same server running + return; + } } } + // Server was not started or was killed externally Runnable finishedAction = new Runnable() { public void run() { @@ -80,7 +96,7 @@ status = ServerStatus.NOT_STARTED; if (portConflict) { // Port conflict - notify user. - updatePort(dir); + updatePort(); } } } @@ -92,8 +108,14 @@ } portConflict = false; - int port = RubyInstallation.getInstance().getRailsPort(); - new ExecutionService(new ExecutionDescriptor(NbBundle.getMessage(WebrickServer.class, "WEBrick"), dir, + if (port == -1) { + port = RubyInstallation.getInstance().getRailsPort(); + } + while(isPortInUse(port)) { + port++; + } + String name = project.getLookup().lookup(ProjectInformation.class).getDisplayName(); + new ExecutionService(new ExecutionDescriptor(NbBundle.getMessage(WebrickServer.class, "WEBrickTab", name, Integer.toString(port)), dir, "script" + File.separator + "server", "--port", Integer.toString(port)).postBuild(finishedAction) // NOI18N .addOutputRecognizer(RubyExecution.RUBY_COMPILER) .addOutputRecognizer(new WebrickMessageListener()) @@ -102,7 +124,7 @@ .run(); } - private void updatePort(File dir) { + private void updatePort() { final PortConflictPanel panel = new PortConflictPanel(RubyInstallation.getInstance().getRailsPort()); //final JButton okButton = new JButton (NbBundle.getMessage (WebrickServer.class, "Ok")); Object[] options = new Object[] { @@ -136,22 +158,27 @@ if (desc.getValue() == options[0]) { RubyInstallation.getInstance().setRailsPort(panel.getPort()); // Restart server - ensureRunning(dir); + ensureRunning(); } dlg.dispose(); } - public synchronized void showUrl(final File dir, final URL url) { + /** Starts the server if not running and shows url. + * @param relativeUrl the resulting url will be for example: http://localhost:3001/{relativeUrl} + */ + public synchronized void showUrl(final String relativeUrl) { synchronized (WebrickServer.this) { - if (status == ServerStatus.RUNNING) { - HtmlBrowser.URLDisplayer.getDefault().showURL(url); - + if (status == ServerStatus.RUNNING && isPortInUse(port)) { + try { + URL url = new URL("http://localhost:" + port + "/" + relativeUrl); // NOI18N + HtmlBrowser.URLDisplayer.getDefault().showURL(url); + } catch (MalformedURLException ex) { + ErrorManager.getDefault().notify(ex); + } return; } - if (status == ServerStatus.NOT_STARTED) { - ensureRunning(dir); - } + ensureRunning(); } cancelled = false; @@ -190,7 +217,12 @@ synchronized (WebrickServer.this) { if (status == ServerStatus.RUNNING) { - HtmlBrowser.URLDisplayer.getDefault().showURL(url); + try { + URL url = new URL("http://localhost:" + port + "/" + relativeUrl); // NOI18N + HtmlBrowser.URLDisplayer.getDefault().showURL(url); + } catch (MalformedURLException ex) { + ErrorManager.getDefault().notify(ex); + } return; } @@ -259,7 +291,7 @@ StatusDisplayer.getDefault() .setStatusText(NbBundle.getMessage(WebrickServer.class, - "NoServerFound", url.toExternalForm())); + "NoServerFound", "http://localhost:" + port + "/" + relativeUrl)); //} catch (IOException ioe) { // ErrorManager.getDefault().notify(ioe); @@ -270,6 +302,43 @@ }); } + /** Return true if there is an HTTP response from the port on localhost. + * Based on tomcatint\tomcat5\src\org.netbeans.modules.tomcat5.util.Utils.java. + */ + public static boolean isPortInUse(int port) { + int timeout = 3000; + Socket socket = new Socket(); + try { + try { + socket.connect(new InetSocketAddress("localhost", port), timeout); // NOI18N + socket.setSoTimeout(timeout); + PrintWriter out = new PrintWriter(socket.getOutputStream(), true); + try { + BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream())); + try { + // request + out.println("GET /\n"); // NOI18N + + // response + String text = in.readLine(); + if (text == null || !text.startsWith("