diff --git a/gatling-recorder/src/main/scala/com/excilys/ebi/gatling/recorder/http/channel/BootstrapFactory.scala b/gatling-recorder/src/main/scala/com/excilys/ebi/gatling/recorder/http/channel/BootstrapFactory.scala index 8e172f552e..289995b8b4 100644 --- a/gatling-recorder/src/main/scala/com/excilys/ebi/gatling/recorder/http/channel/BootstrapFactory.scala +++ b/gatling-recorder/src/main/scala/com/excilys/ebi/gatling/recorder/http/channel/BootstrapFactory.scala @@ -17,7 +17,7 @@ package com.excilys.ebi.gatling.recorder.http.channel import org.jboss.netty.bootstrap.{ ServerBootstrap, ClientBootstrap } import org.jboss.netty.channel.{ ChannelPipelineFactory, ChannelPipeline, ChannelHandlerContext } -import org.jboss.netty.channel.Channels.pipeline +import org.jboss.netty.channel.Channels import org.jboss.netty.channel.socket.nio.{ NioServerSocketChannelFactory, NioClientSocketChannelFactory } import org.jboss.netty.handler.codec.http.{ HttpResponseEncoder, HttpRequestDecoder, HttpRequest, HttpContentDecompressor, HttpContentCompressor, HttpClientCodec, HttpChunkAggregator } import org.jboss.netty.handler.ssl.SslHandler @@ -29,26 +29,28 @@ import com.excilys.ebi.gatling.recorder.http.ssl.{ SSLEngineFactory, FirstEventI object BootstrapFactory { + val SSL_HANDLER_NAME = "ssl" + private val CHUNK_MAX_SIZE = 100 * 1024 * 1024; // 100Mo private val clientChannelFactory = new NioClientSocketChannelFactory private val serverChannelFactory = new NioServerSocketChannelFactory - def newClientBootstrap(controller: RecorderController, browserCtx: ChannelHandlerContext, browserRequest: HttpRequest, ssl: Boolean): ClientBootstrap = { + def newClientBootstrap(controller: RecorderController, requestContext: ChannelHandlerContext, browserRequest: HttpRequest, ssl: Boolean): ClientBootstrap = { val bootstrap = new ClientBootstrap(clientChannelFactory) bootstrap.setPipelineFactory(new ChannelPipelineFactory() { def getPipeline: ChannelPipeline = { - val tmpPipeline = pipeline() + val pipeline = Channels.pipeline if (ssl) - tmpPipeline.addLast("ssl", new SslHandler(SSLEngineFactory.newClientSSLEngine)) - tmpPipeline.addLast("codec", new HttpClientCodec) - tmpPipeline.addLast("inflater", new HttpContentDecompressor) - tmpPipeline.addLast("aggregator", new HttpChunkAggregator(CHUNK_MAX_SIZE)) - tmpPipeline.addLast("gatling", new ServerHttpResponseHandler(controller, browserCtx, browserRequest)) + pipeline.addLast(SSL_HANDLER_NAME, new SslHandler(SSLEngineFactory.newClientSSLEngine)) + pipeline.addLast("codec", new HttpClientCodec) + pipeline.addLast("inflater", new HttpContentDecompressor) + pipeline.addLast("aggregator", new HttpChunkAggregator(CHUNK_MAX_SIZE)) + pipeline.addLast("gatling", new ServerHttpResponseHandler(controller, requestContext, browserRequest)) - tmpPipeline + pipeline } }) @@ -64,19 +66,19 @@ object BootstrapFactory { bootstrap.setPipelineFactory(new ChannelPipelineFactory() { def getPipeline: ChannelPipeline = { - val tmpPipeline = pipeline() + val pipeline = Channels.pipeline if (ssl) - tmpPipeline.addLast("ssl", new FirstEventIsUnsecuredConnectSslHandler(SSLEngineFactory.newServerSSLEngine)) - tmpPipeline.addLast("decoder", new HttpRequestDecoder) - tmpPipeline.addLast("aggregator", new HttpChunkAggregator(CHUNK_MAX_SIZE)) - tmpPipeline.addLast("encoder", new HttpResponseEncoder) - tmpPipeline.addLast("deflater", new HttpContentCompressor) + pipeline.addLast(SSL_HANDLER_NAME, new FirstEventIsUnsecuredConnectSslHandler(SSLEngineFactory.newServerSSLEngine)) + pipeline.addLast("decoder", new HttpRequestDecoder) + pipeline.addLast("aggregator", new HttpChunkAggregator(CHUNK_MAX_SIZE)) + pipeline.addLast("encoder", new HttpResponseEncoder) + pipeline.addLast("deflater", new HttpContentCompressor) if (ssl) - tmpPipeline.addLast("gatling", new BrowserHttpsRequestHandler(controller, proxyConfig)) + pipeline.addLast("gatling", new BrowserHttpsRequestHandler(controller, proxyConfig)) else - tmpPipeline.addLast("gatling", new BrowserHttpRequestHandler(controller, proxyConfig)) + pipeline.addLast("gatling", new BrowserHttpRequestHandler(controller, proxyConfig)) - tmpPipeline + pipeline } }) diff --git a/gatling-recorder/src/main/scala/com/excilys/ebi/gatling/recorder/http/handler/AbstractBrowserRequestHandler.scala b/gatling-recorder/src/main/scala/com/excilys/ebi/gatling/recorder/http/handler/AbstractBrowserRequestHandler.scala index ebec200fbf..3469f6e19c 100644 --- a/gatling-recorder/src/main/scala/com/excilys/ebi/gatling/recorder/http/handler/AbstractBrowserRequestHandler.scala +++ b/gatling-recorder/src/main/scala/com/excilys/ebi/gatling/recorder/http/handler/AbstractBrowserRequestHandler.scala @@ -31,6 +31,10 @@ import grizzled.slf4j.Logging abstract class AbstractBrowserRequestHandler(controller: RecorderController, proxyConfig: ProxyConfig) extends SimpleChannelHandler with Logging { + implicit def function2ChannelFutureListener(thunk: ChannelFuture => Any) = new ChannelFutureListener { + def operationComplete(future: ChannelFuture) { thunk(future) } + } + override def messageReceived(ctx: ChannelHandlerContext, event: MessageEvent) { event.getMessage match { @@ -45,39 +49,26 @@ abstract class AbstractBrowserRequestHandler(controller: RecorderController, pro } }.getOrElse(request.removeHeader("Proxy-Connection")) // remove Proxy-Connection header if it's not significant - val future = connectToServerOnBrowserRequestReceived(ctx, request) + propagateRequest(ctx, request) controller.receiveRequest(request) - sendRequestToServerAfterConnection(future, request); - case unknown => warn("Received unknown message: " + unknown) } } - def connectToServerOnBrowserRequestReceived(ctx: ChannelHandlerContext, request: HttpRequest): ChannelFuture + def propagateRequest(requestContext: ChannelHandlerContext, request: HttpRequest) override def exceptionCaught(ctx: ChannelHandlerContext, e: ExceptionEvent) { error("Exception caught", e.getCause) // Properly closing val future = ctx.getChannel.getCloseFuture - future.addListener(new ChannelFutureListener { - def operationComplete(future: ChannelFuture) = future.getChannel.close - }) + future.addListener(ChannelFutureListener.CLOSE) ctx.sendUpstream(e) } - private def sendRequestToServerAfterConnection(future: ChannelFuture, request: HttpRequest) { - - Option(future).map { future => - future.addListener(new ChannelFutureListener { - def operationComplete(future: ChannelFuture) = future.getChannel.write(buildRequestWithRelativeURI(request)) - }) - } - } - - private def buildRequestWithRelativeURI(request: HttpRequest) = { + def buildRequestWithRelativeURI(request: HttpRequest) = { val uri = new URI(request.getUri) val newUri = new URI(null, null, null, -1, uri.getPath, uri.getQuery, uri.getFragment).toString val newRequest = new DefaultHttpRequest(request.getProtocolVersion, request.getMethod, newUri) diff --git a/gatling-recorder/src/main/scala/com/excilys/ebi/gatling/recorder/http/handler/BrowserHttpRequestHandler.scala b/gatling-recorder/src/main/scala/com/excilys/ebi/gatling/recorder/http/handler/BrowserHttpRequestHandler.scala index 83fb2b18fd..de0685cd7f 100644 --- a/gatling-recorder/src/main/scala/com/excilys/ebi/gatling/recorder/http/handler/BrowserHttpRequestHandler.scala +++ b/gatling-recorder/src/main/scala/com/excilys/ebi/gatling/recorder/http/handler/BrowserHttpRequestHandler.scala @@ -26,9 +26,9 @@ import com.excilys.ebi.gatling.recorder.http.channel.BootstrapFactory.newClientB class BrowserHttpRequestHandler(controller: RecorderController, proxyConfig: ProxyConfig) extends AbstractBrowserRequestHandler(controller, proxyConfig) { - def connectToServerOnBrowserRequestReceived(ctx: ChannelHandlerContext, request: HttpRequest): ChannelFuture = { + def propagateRequest(requestContext: ChannelHandlerContext, request: HttpRequest) { - val bootstrap = newClientBootstrap(controller, ctx, request, false) + val bootstrap = newClientBootstrap(controller, requestContext, request, false) val (proxyHost, proxyPort) = (for { host <- proxyConfig.host @@ -40,6 +40,8 @@ class BrowserHttpRequestHandler(controller: RecorderController, proxyConfig: Pro (uri.getHost, port) } - bootstrap.connect(new InetSocketAddress(proxyHost, proxyPort)) + bootstrap + .connect(new InetSocketAddress(proxyHost, proxyPort)) + .addListener { future: ChannelFuture => future.getChannel.write(buildRequestWithRelativeURI(request)) } } } diff --git a/gatling-recorder/src/main/scala/com/excilys/ebi/gatling/recorder/http/handler/BrowserHttpsRequestHandler.scala b/gatling-recorder/src/main/scala/com/excilys/ebi/gatling/recorder/http/handler/BrowserHttpsRequestHandler.scala index 91cd2ea401..8db5e7e3b1 100644 --- a/gatling-recorder/src/main/scala/com/excilys/ebi/gatling/recorder/http/handler/BrowserHttpsRequestHandler.scala +++ b/gatling-recorder/src/main/scala/com/excilys/ebi/gatling/recorder/http/handler/BrowserHttpsRequestHandler.scala @@ -19,9 +19,11 @@ import java.net.{ InetSocketAddress, URI } import org.jboss.netty.channel.{ ChannelFuture, ChannelHandlerContext } import org.jboss.netty.handler.codec.http.{ DefaultHttpResponse, HttpMethod, HttpRequest, HttpResponseStatus, HttpVersion } +import org.jboss.netty.handler.ssl.SslHandler import com.excilys.ebi.gatling.recorder.config.ProxyConfig import com.excilys.ebi.gatling.recorder.controller.RecorderController +import com.excilys.ebi.gatling.recorder.http.channel.BootstrapFactory import com.excilys.ebi.gatling.recorder.http.channel.BootstrapFactory.newClientBootstrap import grizzled.slf4j.Logging @@ -30,34 +32,37 @@ class BrowserHttpsRequestHandler(controller: RecorderController, proxyConfig: Pr @volatile var targetHostURI: URI = _ - def connectToServerOnBrowserRequestReceived(ctx: ChannelHandlerContext, request: HttpRequest): ChannelFuture = { - - info("Received " + request.getMethod + " on " + request.getUri) - - if (request.getMethod == HttpMethod.CONNECT) { - - targetHostURI = new URI("https://" + request.getUri()); + def propagateRequest(requestContext: ChannelHandlerContext, request: HttpRequest) { + def handleConnect { + targetHostURI = new URI("https://" + request.getUri) warn("Trying to connect to " + targetHostURI + ", make sure you've accepted the recorder certificate for this site") - controller.secureConnection(targetHostURI) + requestContext.getChannel.write(new DefaultHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK)) + } - ctx.getChannel.write(new DefaultHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK)) - - null - - } else { - // set full uri so that it's correctly recorded + def handlePropagatableRequest { + // set full uri so that it's correctly recorded FIXME ugly request.setUri(targetHostURI + request.getUri) - val bootstrap = newClientBootstrap(controller, ctx, request, true) + val bootstrap = newClientBootstrap(controller, requestContext, request, true) val (host, port) = (for { host <- proxyConfig.host port <- proxyConfig.port } yield (host, port)).getOrElse(targetHostURI.getHost, targetHostURI.getPort) - bootstrap.connect(new InetSocketAddress(host, port)) + bootstrap + .connect(new InetSocketAddress(host, port)) + .addListener { connectFuture: ChannelFuture => + connectFuture.getChannel.getPipeline.get(BootstrapFactory.SSL_HANDLER_NAME).asInstanceOf[SslHandler].handshake.addListener { handshakeFuture: ChannelFuture => + handshakeFuture.getChannel.write(buildRequestWithRelativeURI(request)) + } + } } + + info("Received " + request.getMethod + " on " + request.getUri) + if (request.getMethod == HttpMethod.CONNECT) handleConnect + else handlePropagatableRequest } } diff --git a/gatling-recorder/src/main/scala/com/excilys/ebi/gatling/recorder/ui/frame/ConfigurationFrame.scala b/gatling-recorder/src/main/scala/com/excilys/ebi/gatling/recorder/ui/frame/ConfigurationFrame.scala index c7b7f78f51..ba1018b3dd 100644 --- a/gatling-recorder/src/main/scala/com/excilys/ebi/gatling/recorder/ui/frame/ConfigurationFrame.scala +++ b/gatling-recorder/src/main/scala/com/excilys/ebi/gatling/recorder/ui/frame/ConfigurationFrame.scala @@ -36,318 +36,318 @@ import javax.swing._ class ConfigurationFrame(controller: RecorderController) extends JFrame with ScalaSwing with Logging { - private val IS_MAC_OSX = System.getProperty("os.name").startsWith("Mac"); - - val txtPort = new JTextField(null, 4) - val txtSslPort = new JTextField(null, 4) - - val txtProxyHost = new JTextField(null, 15) - val txtProxyPort = new JTextField(null, 4) - txtProxyPort.setEnabled(false) - val txtProxySslPort = new JTextField(null, 4) - txtProxySslPort.setEnabled(false) - val txtProxyUsername = new JTextField(null, 12) - txtProxyUsername.setEnabled(false) - val txtProxyPassword = new JTextField(null, 12) - txtProxyPassword.setEnabled(false) - - val cbFilterStrategies = new JComboBox - val chkSavePref = new JCheckBox("Save preferences") - val chkFollowRedirect = new JCheckBox("Follow Redirects?") - val chkAutomaticReferer = new JCheckBox("Automatic Referers?") - val txtOutputFolder = new JTextField(66) - val tblFilters = new FilterTable - val cbOutputEncoding = new JComboBox - val txtSimulationPackage = new JTextField(30) - val txtSimulationClassName = new JTextField(30) - - private val btnFiltersAdd = new JButton("+") - private val btnFiltersDel = new JButton("-") - private val btnOutputFolder = new JButton("Browse") - private val btnClear = new JButton("Clear") - val btnStart = new JButton("Start !") - - private var pnlTop: JPanel = null - private var pnlCenter: JPanel = null - private var pnlBottom: JPanel = null - - private var fileDialog: FileDialog = null - private var fileChooser: JFileChooser = null - - /** Initialization of the frame **/ - - setTitle("Gatling Recorder - Configuration") - setLayout(new BorderLayout) - setMinimumSize(new Dimension(1024, 768)) - setResizable(true) - setLocationRelativeTo(null) - setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE) - setIconImages(iconList) - - /** Initialization of components **/ - initTopPanel - initCenterPanel - initBottomPanel - initOutputDirectoryChooser - - setListeners - - setValidationListeners - - populateItemsFromConfiguration(configuration) - - private def initOutputDirectoryChooser { - - if (IS_MAC_OSX) { - // on mac, use native dialog because JFileChooser is buggy - System.setProperty("apple.awt.fileDialogForDirectories", "true") - fileDialog = new FileDialog(ConfigurationFrame.this) - - } else { - fileChooser = new JFileChooser - fileChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY) - } - } - - private def initTopPanel { - /***** Creating Top Panel (Network) *****/ - pnlTop = new JPanel(new BorderLayout) - - /* Gatling Image */ - val pnlImage = new JPanel - pnlImage.add(new JLabel(Commons.logoSmall)) - - /* Network Panel */ - val pnlNetwork = new JPanel(new BorderLayout) - pnlNetwork.setBorder(BorderFactory.createTitledBorder("Network")) - pnlNetwork.setLayout(new BorderLayout) - - /* Local proxy host panel */ - val localProxyHostPanel = new JPanel(new FlowLayout(FlowLayout.LEFT)) - localProxyHostPanel.add(new JLabel("Listening port* : ")) - localProxyHostPanel.add(new JLabel(" localhost")) - - /* Local proxy ports panel */ - val localProxyPortsPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT)) - localProxyPortsPanel.add(new JLabel("HTTP")) - localProxyPortsPanel.add(txtPort) - localProxyPortsPanel.add(new JLabel("HTTPS")) - localProxyPortsPanel.add(txtSslPort) - - /* Local proxy panel */ - val localProxyPanel = new JPanel(new FlowLayout) - localProxyPanel.add(localProxyHostPanel) - localProxyPanel.add(localProxyPortsPanel) - - /* Outgoing proxy host panel */ - val outgoingProxyHostPanel = new JPanel(new FlowLayout(FlowLayout.LEFT)) - outgoingProxyHostPanel.add(new JLabel("Outgoing proxy : ")) - outgoingProxyHostPanel.add(new JLabel("host:")) - outgoingProxyHostPanel.add(txtProxyHost) - outgoingProxyHostPanel.add(new JLabel("HTTP")) - outgoingProxyHostPanel.add(txtProxyPort) - outgoingProxyHostPanel.add(new JLabel("HTTPS")) - outgoingProxyHostPanel.add(txtProxySslPort) - - /* Outgoing proxy ports panel */ - val outgoingProxyCredentialsPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT)) - outgoingProxyCredentialsPanel.add(new JLabel("Username")) - outgoingProxyCredentialsPanel.add(txtProxyUsername) - outgoingProxyCredentialsPanel.add(new JLabel("Password")) - outgoingProxyCredentialsPanel.add(txtProxyPassword) - - /* Outgoing proxy panel */ - val outgoingProxyPanel = new JPanel(new BorderLayout) - outgoingProxyPanel.add(outgoingProxyHostPanel, BorderLayout.NORTH) - outgoingProxyPanel.add(outgoingProxyCredentialsPanel, BorderLayout.SOUTH) - - /* Adding panels to newtworkPanel */ - pnlNetwork.add(localProxyPanel, BorderLayout.NORTH) - pnlNetwork.add(outgoingProxyPanel, BorderLayout.SOUTH) - - /* Adding Image and network panel to top panel */ - pnlTop.add(pnlImage, BorderLayout.WEST) - pnlTop.add(pnlNetwork, BorderLayout.EAST) - - /* Adding panel to Frame */ - add(pnlTop, BorderLayout.NORTH) - } - - private def initCenterPanel { - /***** Creating Center Panel (Output + Start) *****/ - pnlCenter = new JPanel - pnlCenter.setLayout(new BorderLayout) - - /* Output Folder Panel */ - val outputFolderPanel = new JPanel(new FlowLayout(FlowLayout.LEFT)) - outputFolderPanel.add(new JLabel("Output folder* : ")) - outputFolderPanel.add(txtOutputFolder) - outputFolderPanel.add(btnOutputFolder) - - for (c <- Charset.availableCharsets.values) - cbOutputEncoding.addItem(c) - - /* Output Panel */ - val outputPanel = new JPanel(new BorderLayout) - outputPanel.setBorder(BorderFactory.createTitledBorder("Output")) - - val outputFormatPanel = new JPanel(new FlowLayout(FlowLayout.LEFT)) - outputFormatPanel.add(new JLabel("Encoding: ")) - outputFormatPanel.add(cbOutputEncoding) - - outputPanel.add(outputFolderPanel, BorderLayout.NORTH) - outputPanel.add(outputFormatPanel, BorderLayout.CENTER) - - /* Simulation information panel */ - val simulationInfoPanel = new JPanel(new BorderLayout) - - val packageNamePanel = new JPanel(new FlowLayout(FlowLayout.LEFT)) - packageNamePanel.add(new JLabel("Package: ")) - packageNamePanel.add(txtSimulationPackage) - - val simulationNamePanel = new JPanel(new FlowLayout(FlowLayout.LEFT)) - simulationNamePanel.add(new JLabel("Class Name*: ")) - simulationNamePanel.add(txtSimulationClassName) - - simulationInfoPanel.add(packageNamePanel, BorderLayout.WEST) - simulationInfoPanel.add(simulationNamePanel, BorderLayout.EAST) - - val simulationConfigPanel = new JPanel(new BorderLayout) - simulationConfigPanel.setBorder(BorderFactory.createTitledBorder("Simulation Information")) - - simulationConfigPanel.add(simulationInfoPanel, BorderLayout.NORTH) - simulationConfigPanel.add(chkFollowRedirect, BorderLayout.WEST) - simulationConfigPanel.add(chkAutomaticReferer, BorderLayout.EAST) - - /* Filters Panel */ - val filtersPanel = new JPanel(new BorderLayout); - filtersPanel.setBorder(BorderFactory.createTitledBorder("Filters")) - - // Fill Combo Box for Strategies - for (ft <- FilterStrategy.values) - cbFilterStrategies.addItem(ft) - - /* Filter Actions panel */ - val filterActionsPanel = new JPanel - filterActionsPanel.add(new JLabel("Strategy")) - filterActionsPanel.add(cbFilterStrategies) - filterActionsPanel.add(btnFiltersAdd) - filterActionsPanel.add(btnFiltersDel) - filterActionsPanel.add(btnClear) - - /* Adding panels to filterPanel */ - filtersPanel.add(tblFilters, BorderLayout.CENTER) - filtersPanel.add(filterActionsPanel, BorderLayout.SOUTH) - - /* Adding panels to bottomPanel */ - pnlCenter.add(simulationConfigPanel, BorderLayout.NORTH) - pnlCenter.add(outputPanel, BorderLayout.CENTER) - pnlCenter.add(filtersPanel, BorderLayout.SOUTH) - - /* Adding panel to Frame */ - add(pnlCenter, BorderLayout.CENTER) - } - - private def initBottomPanel { - /***** Creating Bottom Panel (Filters) *****/ - pnlBottom = new JPanel - pnlBottom.setLayout(new BorderLayout) - - /* Start Action Panel */ - val startActionPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT)) - startActionPanel.add(chkSavePref) - startActionPanel.add(btnStart) - - chkSavePref.setHorizontalTextPosition(SwingConstants.LEFT); - - pnlBottom.add(startActionPanel, BorderLayout.SOUTH); - - /* Adding panel to Frame */ - add(pnlBottom, BorderLayout.SOUTH) - } - - private def setListeners { - // Enables or disables filter edition depending on the selected strategy - cbFilterStrategies.addItemListener((e: ItemEvent) => { - if (e.getStateChange == ItemEvent.SELECTED && e.getItem == FilterStrategy.NONE) { - tblFilters.setEnabled(false) - tblFilters.setFocusable(false) - } else { - tblFilters.setEnabled(true) - tblFilters.setFocusable(true) - } - }) - - // Adds a filter row when + button clicked - btnFiltersAdd.addActionListener((e: ActionEvent) => tblFilters.addRow) - - // Removes selected filter when - button clicked - btnFiltersDel.addActionListener((e: ActionEvent) => tblFilters.removeSelectedRow) - - // Removes all filters when clear button clicked - btnClear.addActionListener((e: ActionEvent) => tblFilters.removeAllElements) - - // Opens a save dialog when Browse button clicked - btnOutputFolder.addActionListener((e: ActionEvent) => { - - var chosenDirPath: String = null - - if (IS_MAC_OSX) { - fileDialog.setVisible(true) - - if (fileDialog.getDirectory == null) - return - - chosenDirPath = fileDialog.getDirectory + fileDialog.getFile - - } else { - if (fileChooser.showSaveDialog(null) != JFileChooser.APPROVE_OPTION) - return - - chosenDirPath = fileChooser.getSelectedFile.getPath - } - - txtOutputFolder.setText(chosenDirPath) - }) - - // Validates form when Start button clicked - btnStart.addActionListener(new SaveConfigurationListener(controller, this)) - } - - private def setValidationListeners { - txtPort.addKeyListener(intValidator(this, "port")) - txtSslPort.addKeyListener(intValidator(this, "sslPort")) - txtProxyHost.addKeyListener(proxyHostValidator(this)) - txtProxyPort.addKeyListener(intValidator(this, "proxyPort")) - txtProxySslPort.addKeyListener(intValidator(this, "proxySslPort")) - txtOutputFolder.addKeyListener(nonEmptyValidator(this, "outputFolder")) - txtSimulationClassName.addKeyListener(nonEmptyValidator(this, "simulationClassName")) - } - - def populateItemsFromConfiguration(configuration: Configuration) { - txtPort.setText(configuration.port.toString) - txtSslPort.setText(configuration.sslPort.toString) - - configuration.proxy.host.map { proxyHost => - txtProxyHost.setText(proxyHost) - txtProxyPort.setText(configuration.proxy.port.getOrElse(0).toString) - txtProxySslPort.setText(configuration.proxy.sslPort.getOrElse(0).toString) - txtProxyUsername.setText(configuration.proxy.getUsername.getOrElse(null)) - txtProxyPassword.setText(configuration.proxy.getPassword.getOrElse(null)) - txtProxyPort.setEnabled(true) - txtProxySslPort.setEnabled(true) - txtProxyUsername.setEnabled(true) - txtProxyPassword.setEnabled(true) - } - configuration.simulationPackage.map(txtSimulationPackage.setText) - txtSimulationClassName.setText(configuration.simulationClassName) - cbFilterStrategies.setSelectedItem(configuration.filterStrategy) - chkFollowRedirect.setSelected(configuration.followRedirect) - chkAutomaticReferer.setSelected(configuration.automaticReferer) - for (pattern <- configuration.patterns) - tblFilters.addRow(pattern) - txtOutputFolder.setText(configuration.outputFolder) - chkSavePref.setSelected(configuration.saveConfiguration) - cbOutputEncoding.setSelectedItem(Charset.forName(configuration.encoding)) - } + private val IS_MAC_OSX = System.getProperty("os.name").startsWith("Mac"); + + val txtPort = new JTextField(null, 4) + val txtSslPort = new JTextField(null, 4) + + val txtProxyHost = new JTextField(null, 15) + val txtProxyPort = new JTextField(null, 4) + txtProxyPort.setEnabled(false) + val txtProxySslPort = new JTextField(null, 4) + txtProxySslPort.setEnabled(false) + val txtProxyUsername = new JTextField(null, 12) + txtProxyUsername.setEnabled(false) + val txtProxyPassword = new JTextField(null, 12) + txtProxyPassword.setEnabled(false) + + val cbFilterStrategies = new JComboBox + val chkSavePref = new JCheckBox("Save preferences") + val chkFollowRedirect = new JCheckBox("Follow Redirects?") + val chkAutomaticReferer = new JCheckBox("Automatic Referers?") + val txtOutputFolder = new JTextField(66) + val tblFilters = new FilterTable + val cbOutputEncoding = new JComboBox + val txtSimulationPackage = new JTextField(30) + val txtSimulationClassName = new JTextField(30) + + private val btnFiltersAdd = new JButton("+") + private val btnFiltersDel = new JButton("-") + private val btnOutputFolder = new JButton("Browse") + private val btnClear = new JButton("Clear") + val btnStart = new JButton("Start !") + + private var pnlTop: JPanel = null + private var pnlCenter: JPanel = null + private var pnlBottom: JPanel = null + + private var fileDialog: FileDialog = null + private var fileChooser: JFileChooser = null + + /** Initialization of the frame **/ + + setTitle("Gatling Recorder - Configuration") + setLayout(new BorderLayout) + setMinimumSize(new Dimension(1024, 768)) + setResizable(true) + setLocationRelativeTo(null) + setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE) + setIconImages(iconList) + + /** Initialization of components **/ + initTopPanel + initCenterPanel + initBottomPanel + initOutputDirectoryChooser + + setListeners + + setValidationListeners + + populateItemsFromConfiguration(configuration) + + private def initOutputDirectoryChooser { + + if (IS_MAC_OSX) { + // on mac, use native dialog because JFileChooser is buggy + System.setProperty("apple.awt.fileDialogForDirectories", "true") + fileDialog = new FileDialog(ConfigurationFrame.this) + + } else { + fileChooser = new JFileChooser + fileChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY) + } + } + + private def initTopPanel { + /***** Creating Top Panel (Network) *****/ + pnlTop = new JPanel(new BorderLayout) + + /* Gatling Image */ + val pnlImage = new JPanel + pnlImage.add(new JLabel(Commons.logoSmall)) + + /* Network Panel */ + val pnlNetwork = new JPanel(new BorderLayout) + pnlNetwork.setBorder(BorderFactory.createTitledBorder("Network")) + pnlNetwork.setLayout(new BorderLayout) + + /* Local proxy host panel */ + val localProxyHostPanel = new JPanel(new FlowLayout(FlowLayout.LEFT)) + localProxyHostPanel.add(new JLabel("Listening port* : ")) + localProxyHostPanel.add(new JLabel(" localhost")) + + /* Local proxy ports panel */ + val localProxyPortsPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT)) + localProxyPortsPanel.add(new JLabel("HTTP")) + localProxyPortsPanel.add(txtPort) + localProxyPortsPanel.add(new JLabel("HTTPS")) + localProxyPortsPanel.add(txtSslPort) + + /* Local proxy panel */ + val localProxyPanel = new JPanel(new FlowLayout) + localProxyPanel.add(localProxyHostPanel) + localProxyPanel.add(localProxyPortsPanel) + + /* Outgoing proxy host panel */ + val outgoingProxyHostPanel = new JPanel(new FlowLayout(FlowLayout.LEFT)) + outgoingProxyHostPanel.add(new JLabel("Outgoing proxy : ")) + outgoingProxyHostPanel.add(new JLabel("host:")) + outgoingProxyHostPanel.add(txtProxyHost) + outgoingProxyHostPanel.add(new JLabel("HTTP")) + outgoingProxyHostPanel.add(txtProxyPort) + outgoingProxyHostPanel.add(new JLabel("HTTPS")) + outgoingProxyHostPanel.add(txtProxySslPort) + + /* Outgoing proxy ports panel */ + val outgoingProxyCredentialsPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT)) + outgoingProxyCredentialsPanel.add(new JLabel("Username")) + outgoingProxyCredentialsPanel.add(txtProxyUsername) + outgoingProxyCredentialsPanel.add(new JLabel("Password")) + outgoingProxyCredentialsPanel.add(txtProxyPassword) + + /* Outgoing proxy panel */ + val outgoingProxyPanel = new JPanel(new BorderLayout) + outgoingProxyPanel.add(outgoingProxyHostPanel, BorderLayout.NORTH) + outgoingProxyPanel.add(outgoingProxyCredentialsPanel, BorderLayout.SOUTH) + + /* Adding panels to newtworkPanel */ + pnlNetwork.add(localProxyPanel, BorderLayout.NORTH) + pnlNetwork.add(outgoingProxyPanel, BorderLayout.SOUTH) + + /* Adding Image and network panel to top panel */ + pnlTop.add(pnlImage, BorderLayout.WEST) + pnlTop.add(pnlNetwork, BorderLayout.EAST) + + /* Adding panel to Frame */ + add(pnlTop, BorderLayout.NORTH) + } + + private def initCenterPanel { + /***** Creating Center Panel (Output + Start) *****/ + pnlCenter = new JPanel + pnlCenter.setLayout(new BorderLayout) + + /* Output Folder Panel */ + val outputFolderPanel = new JPanel(new FlowLayout(FlowLayout.LEFT)) + outputFolderPanel.add(new JLabel("Output folder* : ")) + outputFolderPanel.add(txtOutputFolder) + outputFolderPanel.add(btnOutputFolder) + + for (c <- Charset.availableCharsets.values) + cbOutputEncoding.addItem(c) + + /* Output Panel */ + val outputPanel = new JPanel(new BorderLayout) + outputPanel.setBorder(BorderFactory.createTitledBorder("Output")) + + val outputFormatPanel = new JPanel(new FlowLayout(FlowLayout.LEFT)) + outputFormatPanel.add(new JLabel("Encoding: ")) + outputFormatPanel.add(cbOutputEncoding) + + outputPanel.add(outputFolderPanel, BorderLayout.NORTH) + outputPanel.add(outputFormatPanel, BorderLayout.CENTER) + + /* Simulation information panel */ + val simulationInfoPanel = new JPanel(new BorderLayout) + + val packageNamePanel = new JPanel(new FlowLayout(FlowLayout.LEFT)) + packageNamePanel.add(new JLabel("Package: ")) + packageNamePanel.add(txtSimulationPackage) + + val simulationNamePanel = new JPanel(new FlowLayout(FlowLayout.LEFT)) + simulationNamePanel.add(new JLabel("Class Name*: ")) + simulationNamePanel.add(txtSimulationClassName) + + simulationInfoPanel.add(packageNamePanel, BorderLayout.WEST) + simulationInfoPanel.add(simulationNamePanel, BorderLayout.EAST) + + val simulationConfigPanel = new JPanel(new BorderLayout) + simulationConfigPanel.setBorder(BorderFactory.createTitledBorder("Simulation Information")) + + simulationConfigPanel.add(simulationInfoPanel, BorderLayout.NORTH) + simulationConfigPanel.add(chkFollowRedirect, BorderLayout.WEST) + simulationConfigPanel.add(chkAutomaticReferer, BorderLayout.EAST) + + /* Filters Panel */ + val filtersPanel = new JPanel(new BorderLayout); + filtersPanel.setBorder(BorderFactory.createTitledBorder("Filters")) + + // Fill Combo Box for Strategies + for (ft <- FilterStrategy.values) + cbFilterStrategies.addItem(ft) + + /* Filter Actions panel */ + val filterActionsPanel = new JPanel + filterActionsPanel.add(new JLabel("Strategy")) + filterActionsPanel.add(cbFilterStrategies) + filterActionsPanel.add(btnFiltersAdd) + filterActionsPanel.add(btnFiltersDel) + filterActionsPanel.add(btnClear) + + /* Adding panels to filterPanel */ + filtersPanel.add(tblFilters, BorderLayout.CENTER) + filtersPanel.add(filterActionsPanel, BorderLayout.SOUTH) + + /* Adding panels to bottomPanel */ + pnlCenter.add(simulationConfigPanel, BorderLayout.NORTH) + pnlCenter.add(outputPanel, BorderLayout.CENTER) + pnlCenter.add(filtersPanel, BorderLayout.SOUTH) + + /* Adding panel to Frame */ + add(pnlCenter, BorderLayout.CENTER) + } + + private def initBottomPanel { + /***** Creating Bottom Panel (Filters) *****/ + pnlBottom = new JPanel + pnlBottom.setLayout(new BorderLayout) + + /* Start Action Panel */ + val startActionPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT)) + startActionPanel.add(chkSavePref) + startActionPanel.add(btnStart) + + chkSavePref.setHorizontalTextPosition(SwingConstants.LEFT); + + pnlBottom.add(startActionPanel, BorderLayout.SOUTH); + + /* Adding panel to Frame */ + add(pnlBottom, BorderLayout.SOUTH) + } + + private def setListeners { + // Enables or disables filter edition depending on the selected strategy + cbFilterStrategies.addItemListener { e: ItemEvent => + if (e.getStateChange == ItemEvent.SELECTED && e.getItem == FilterStrategy.NONE) { + tblFilters.setEnabled(false) + tblFilters.setFocusable(false) + } else { + tblFilters.setEnabled(true) + tblFilters.setFocusable(true) + } + } + + // Adds a filter row when + button clicked + btnFiltersAdd.addActionListener { e: ActionEvent => tblFilters.addRow } + + // Removes selected filter when - button clicked + btnFiltersDel.addActionListener { e: ActionEvent => tblFilters.removeSelectedRow } + + // Removes all filters when clear button clicked + btnClear.addActionListener { e: ActionEvent => tblFilters.removeAllElements } + + // Opens a save dialog when Browse button clicked + btnOutputFolder.addActionListener { e: ActionEvent => + + var chosenDirPath: String = null + + if (IS_MAC_OSX) { + fileDialog.setVisible(true) + + if (fileDialog.getDirectory == null) + return + + chosenDirPath = fileDialog.getDirectory + fileDialog.getFile + + } else { + if (fileChooser.showSaveDialog(null) != JFileChooser.APPROVE_OPTION) + return + + chosenDirPath = fileChooser.getSelectedFile.getPath + } + + txtOutputFolder.setText(chosenDirPath) + } + + // Validates form when Start button clicked + btnStart.addActionListener(new SaveConfigurationListener(controller, this)) + } + + private def setValidationListeners { + txtPort.addKeyListener(intValidator(this, "port")) + txtSslPort.addKeyListener(intValidator(this, "sslPort")) + txtProxyHost.addKeyListener(proxyHostValidator(this)) + txtProxyPort.addKeyListener(intValidator(this, "proxyPort")) + txtProxySslPort.addKeyListener(intValidator(this, "proxySslPort")) + txtOutputFolder.addKeyListener(nonEmptyValidator(this, "outputFolder")) + txtSimulationClassName.addKeyListener(nonEmptyValidator(this, "simulationClassName")) + } + + def populateItemsFromConfiguration(configuration: Configuration) { + txtPort.setText(configuration.port.toString) + txtSslPort.setText(configuration.sslPort.toString) + + configuration.proxy.host.map { proxyHost => + txtProxyHost.setText(proxyHost) + txtProxyPort.setText(configuration.proxy.port.getOrElse(0).toString) + txtProxySslPort.setText(configuration.proxy.sslPort.getOrElse(0).toString) + txtProxyUsername.setText(configuration.proxy.getUsername.getOrElse(null)) + txtProxyPassword.setText(configuration.proxy.getPassword.getOrElse(null)) + txtProxyPort.setEnabled(true) + txtProxySslPort.setEnabled(true) + txtProxyUsername.setEnabled(true) + txtProxyPassword.setEnabled(true) + } + configuration.simulationPackage.map(txtSimulationPackage.setText) + txtSimulationClassName.setText(configuration.simulationClassName) + cbFilterStrategies.setSelectedItem(configuration.filterStrategy) + chkFollowRedirect.setSelected(configuration.followRedirect) + chkAutomaticReferer.setSelected(configuration.automaticReferer) + for (pattern <- configuration.patterns) + tblFilters.addRow(pattern) + txtOutputFolder.setText(configuration.outputFolder) + chkSavePref.setSelected(configuration.saveConfiguration) + cbOutputEncoding.setSelectedItem(Charset.forName(configuration.encoding)) + } } \ No newline at end of file diff --git a/gatling-recorder/src/main/scala/com/excilys/ebi/gatling/recorder/ui/frame/RunningFrame.scala b/gatling-recorder/src/main/scala/com/excilys/ebi/gatling/recorder/ui/frame/RunningFrame.scala index 065ba7ad06..52cad7cd1a 100644 --- a/gatling-recorder/src/main/scala/com/excilys/ebi/gatling/recorder/ui/frame/RunningFrame.scala +++ b/gatling-recorder/src/main/scala/com/excilys/ebi/gatling/recorder/ui/frame/RunningFrame.scala @@ -123,7 +123,7 @@ class RunningFrame(controller: RecorderController) extends JFrame with ScalaSwin private def setListeners { /* Listeners */ - btnTag.addActionListener((e: ActionEvent) => { + btnTag.addActionListener { e: ActionEvent => if (!txtTag.getText.isEmpty) { val tag = new TagInfo(txtTag.getText) eventsInfo.addElement(tag) @@ -131,9 +131,9 @@ class RunningFrame(controller: RecorderController) extends JFrame with ScalaSwin eventsInfoJList.ensureIndexIsVisible(eventsInfo.getSize() - 1) txtTag.clear } - }) + } - eventsInfoJList.addListSelectionListener((e: ListSelectionEvent) => { + eventsInfoJList.addListSelectionListener { e: ListSelectionEvent => if (eventsInfoJList.getSelectedIndex() >= 0) { val obj = eventsInfo.get(eventsInfoJList.getSelectedIndex()); if (obj.isInstanceOf[RequestInfo]) { @@ -158,16 +158,16 @@ class RunningFrame(controller: RecorderController) extends JFrame with ScalaSwin responseBodyInfo.clear } } - }) + } - btnClear.addActionListener((e: ActionEvent) => controller.clearRecorderState) + btnClear.addActionListener { e: ActionEvent => controller.clearRecorderState } - btnCancel.addActionListener((e: ActionEvent) => { + btnCancel.addActionListener { e: ActionEvent => controller.clearRecorderState controller.stopRecording - }) + } - btnStop.addActionListener((e: ActionEvent) => controller.stopRecording) + btnStop.addActionListener { e: ActionEvent => controller.stopRecording } } def clearState {