/* * Copyright 2013 original Randori IntelliJ Plugin authors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package randori.plugin.runner; import com.intellij.ide.BrowserUtil; import com.intellij.openapi.components.ProjectComponent; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.Project; import org.eclipse.jetty.server.Handler; import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.handler.DefaultHandler; import org.eclipse.jetty.server.handler.HandlerList; import org.eclipse.jetty.server.handler.ResourceHandler; import org.eclipse.jetty.server.nio.NetworkTrafficSelectChannelConnector; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import randori.plugin.configuration.RandoriCompilerModel; import randori.plugin.util.LogUtils; import randori.plugin.util.ProjectUtils; import java.net.ServerSocket; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; /** * @author Michael Schmalle */ public class RandoriServerComponent implements ProjectComponent { private static final Logger log = Logger.getInstance(RandoriServerComponent.class); private static final String DEFAULT_INDEX_HTML = "index.html"; private Server server; private ExecutorService execService; private final Project project; private final RandoriCompilerModel component; public RandoriServerComponent(Project project, RandoriCompilerModel component) { this.project = project; this.component = component; } private static int findFreePort() { int port = -1; ServerSocket server = null; try { server = new ServerSocket(0); port = server.getLocalPort(); } catch (Exception e) { e.printStackTrace(); log.error("Error finding free port:"); log.error(LogUtils.dumpStackTrace(e.getStackTrace())); } finally { if (server != null) { try { server.close(); } catch (Exception e) { e.printStackTrace(); log.error("Error closing socket:"); log.error(LogUtils.dumpStackTrace(e.getStackTrace())); } } } return port; } @Override public void initComponent() { } @Override public void disposeComponent() { server = null; execService = null; } @Override public void projectOpened() { // XXX temp if (!ProjectUtils.hasRandoriModuleType(project)) return; server = new Server(); NetworkTrafficSelectChannelConnector connector = new NetworkTrafficSelectChannelConnector(); connector.setServer(server); int portNr = component.getState().getPort(); if (portNr < 0) { portNr = findFreePort(); if (portNr < 0) { //For now do nothing, but if this fails something //is terribly wrong, we need some kind of global //state that indicates that the entire system is //unstable and that the user cannot proceed further. (Or something) return; } component.getState().setPort(portNr); } connector.setPort(portNr); server.addConnector(connector); startServer(component.getState()); } @Override public void projectClosed() { // XXX temp if (!ProjectUtils.hasRandoriModuleType(project)) return; stopServer(); } // not used yet void restartServer() { // no idea if I am doing this right at the moment stopServer(); startServer(component.getState()); } void startServer(RandoriCompilerModel model) { // we call this here since the webroot might have changed updateHandlers(); execService = Executors.newFixedThreadPool(1); execService.submit(new Runnable() { @Override public void run() { try { server.start(); server.join(); } catch (Exception e) { e.printStackTrace(); log.error("Error starting server:"); log.error(LogUtils.dumpStackTrace(e.getStackTrace())); } } }); } void stopServer() { try { server.stop(); execService.shutdown(); } catch (Exception e) { e.printStackTrace(); log.error("Error stopping server:"); log.error(LogUtils.dumpStackTrace(e.getStackTrace())); } } @NonNls @NotNull @Override public String getComponentName() { return "RandoriServerComponent"; } public void openURL(String relativeURL, String explicitWebRoot) { // still new to this, figuring out if this is the right way to do this. String url = getURL(relativeURL, explicitWebRoot); // temp, will hook up properly, can create a config that says // something like preview in browser checkbox BrowserUtil.launchBrowser(url); } String getURL(String index, String explicitWebRoot) { String url = explicitWebRoot; if (url.length() == 0) { int port = component.getState().getPort(); url = "http://localhost:" + port + "/" + index; } else { if (!url.endsWith("/")) { url = url + "/"; } url = url + index; } return url; } private void updateHandlers() { ResourceHandler resourceHandler = new ResourceHandler(); resourceHandler.setDirectoriesListed(true); resourceHandler.setWelcomeFiles(new String[] { DEFAULT_INDEX_HTML }); String root = component.getState().getWebRoot(); if (root == null || root.equals("")) root = project.getBasePath(); resourceHandler.setResourceBase(root); HandlerList handlers = new HandlerList(); handlers.setHandlers(new Handler[] { resourceHandler, new DefaultHandler() }); server.setHandler(handlers); } }