Start browser when not in logging to console
Start browser when not in logging to console

/*
* Copyright 2014 John Ahlroos
*
* 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 fi.jasoft.plugin

import org.gradle.api.Project
import org.gradle.api.file.FileCollection
import org.gradle.api.plugins.WarPluginConvention

import java.nio.file.FileSystems
import java.nio.file.FileVisitResult
import java.nio.file.Files
import java.nio.file.Path
import java.nio.file.Paths
import java.nio.file.SimpleFileVisitor
import java.nio.file.StandardWatchEventKinds
import java.nio.file.WatchEvent
import java.nio.file.attribute.BasicFileAttributes

class ApplicationServer {

    def Process process;

    def final project;

    def List browserParameters

    def ApplicationServer(project, browserParameters = []) {
        this.project = project
        this.browserParameters = browserParameters
    }

    def boolean start(restarting=false) {

        if (process != null) {
            project.logger.error('Server is already running.')
            return false
        }

        File webAppDir = project.convention.getPlugin(WarPluginConvention).webAppDir
        FileCollection cp = project.configurations[DependencyListener.Configuration.JETTY9.caption] + Util.getClassPath(project)

        def appServerProcess = ['java']

        // Debug
        if (project.vaadin.debug) {
            appServerProcess.add('-Xdebug')
            appServerProcess.add("-Xrunjdwp:transport=dt_socket,address=${project.vaadin.debugPort},server=y,suspend=n")
        }

        // Jrebel
        if (project.vaadin.jrebel.enabled && project.vaadin.debug) {
            if (project.vaadin.jrebel.location != null && new File(project.vaadin.jrebel.location).exists()) {
                appServerProcess.add('-noverify')
                appServerProcess.add("-javaagent:${project.vaadin.jrebel.location}")
            } else {
                project.logger.warn('jrebel.jar not found, running without jrebel')
            }
        }

        // JVM options
        if (project.vaadin.debug) {
            appServerProcess.add('-ea')
        }

        appServerProcess.add('-cp')
        appServerProcess.add(cp.getAsPath())

        if (project.vaadin.jvmArgs != null) {
            appServerProcess.addAll(project.vaadin.jvmArgs)
        }

        // Program args
        appServerProcess.add('fi.jasoft.plugin.ApplicationServerRunner')

        appServerProcess.add(project.vaadin.serverPort)

        appServerProcess.add(webAppDir.canonicalPath + '/')

        File classesDir = project.file("build/classes")
        appServerProcess.add(classesDir.canonicalPath + '/')

        // Execute server
        process = appServerProcess.execute()

        if(!process.alive) {
            project.logger.error("Could not start server,  server terminated with error code ${process.exitValue()}. Please look at jetty.log for reason.")
            return
        }

        // Watch for changes in classes
        if(project.vaadin.plugin.jettyAutoRefresh) {
            def self = this
            Thread.start 'Directory Watcher', {
                watchDirectoryForChanges(self)
            }
        }

        // Build browser GET parameters
        def paramString = ''
        if (project.vaadin.debug) {
            paramString += '?debug'
            paramString += '&' + browserParameters.join('&')
        } else if(!browserParameters.isEmpty()){
            paramString += '?' + browserParameters.join('&')
        }
        paramString = paramString.replaceAll('\\?$|&$', '')

        // Capture log output
        Util.logProcess(project, process, 'jetty.log', { line ->
            if(line.contains('Server:main: Started')) {
                def resultStr = "Application running on http://localhost:${project.vaadin.serverPort} "
                if (project.vaadin.jrebel.enabled) {
                    resultStr += "(debugger on ${project.vaadin.debugPort}, JRebel active)"
                } else if (project.vaadin.debug) {
                    resultStr += "(debugger on ${project.vaadin.debugPort})"
                }
                project.logger.lifecycle(resultStr)
                project.logger.lifecycle('Press [Ctrl+C] to terminate server...')

                // Open browser
                if(!restarting) {
                    Util.openBrowser((Project)project, "http://localhost:${(Integer)project.vaadin.serverPort}/${paramString}")
                }
            }
        })

        project.logger.info 'Server running'
    }

    def restart = false

    def startAndBlock() {
        while(true){
            // Keep main loop running so task does not end

            // Reset values
            def restarting = restart
            restart = false
            process = null

            // Start server
            start(restarting)

            // Wait until server process calls destroy()
            process.waitFor()

            // In no restart is requested, terminate task
            if(!restart) {
                break;
            }
        }
    }

    def terminate() {
        if(process){
            process.destroy()
            project.logger.lifecycle("Application server terminated.")
        }
    }

    def restart() {
        restart = true
        terminate()
    }

    def watchDirectoryForChanges(task) {

        File classesDir = null
        if (project.vaadin.plugin.eclipseOutputDir == null) {
            classesDir = project.sourceSets.main.output.classesDir
        } else {
            classesDir = project.file(project.vaadin.plugin.eclipseOutputDir)
        }

        def classesPath = Paths.get(classesDir.canonicalPath)
        def watchService = FileSystems.getDefault().newWatchService()

        Files.walkFileTree classesPath, new SimpleFileVisitor<Path>() {

            @Override
            public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs){
                dir.register(watchService,
                        StandardWatchEventKinds.ENTRY_CREATE,
                        StandardWatchEventKinds.ENTRY_DELETE,
                        StandardWatchEventKinds.ENTRY_MODIFY)
                FileVisitResult.CONTINUE
            }
        }

        project.logger.info "Watching directory $classesDir for changes..."

        def restart = false
        while(true) {
            def key = watchService.take()
            key.pollEvents().each { WatchEvent event ->
                restart = true
            }
            if(!key.reset() || restart) break
        }

        project.logger.info "Stopped watching directory"

        if(restart) {
            task.restart()
        } else {
            project.logger.info 'Stopped watching directory (no restart)'
        }
    }
}

/*
* Copyright 2014 John Ahlroos
*
* 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 fi.jasoft.plugin

import org.gradle.api.Project
import org.gradle.api.file.FileCollection
import org.gradle.api.plugins.WarPluginConvention

import java.nio.file.FileSystems
import java.nio.file.FileVisitResult
import java.nio.file.Files
import java.nio.file.Path
import java.nio.file.Paths
import java.nio.file.SimpleFileVisitor
import java.nio.file.StandardWatchEventKinds
import java.nio.file.WatchEvent
import java.nio.file.attribute.BasicFileAttributes

class ApplicationServer {

    def Process process;

    def final project;

    def List browserParameters

    def ApplicationServer(project, browserParameters = []) {
        this.project = project
        this.browserParameters = browserParameters
    }

    def boolean start(restarting=false) {

        if (process != null) {
            project.logger.error('Server is already running.')
            return false
        }

        File webAppDir = project.convention.getPlugin(WarPluginConvention).webAppDir
        FileCollection cp = project.configurations[DependencyListener.Configuration.JETTY9.caption] + Util.getClassPath(project)

        def appServerProcess = ['java']

        // Debug
        if (project.vaadin.debug) {
            appServerProcess.add('-Xdebug')
            appServerProcess.add("-Xrunjdwp:transport=dt_socket,address=${project.vaadin.debugPort},server=y,suspend=n")
        }

        // Jrebel
        if (project.vaadin.jrebel.enabled && project.vaadin.debug) {
            if (project.vaadin.jrebel.location != null && new File(project.vaadin.jrebel.location).exists()) {
                appServerProcess.add('-noverify')
                appServerProcess.add("-javaagent:${project.vaadin.jrebel.location}")
            } else {
                project.logger.warn('jrebel.jar not found, running without jrebel')
            }
        }

        // JVM options
        if (project.vaadin.debug) {
            appServerProcess.add('-ea')
        }

        appServerProcess.add('-cp')
        appServerProcess.add(cp.getAsPath())

        if (project.vaadin.jvmArgs != null) {
            appServerProcess.addAll(project.vaadin.jvmArgs)
        }

        // Program args
        appServerProcess.add('fi.jasoft.plugin.ApplicationServerRunner')

        appServerProcess.add(project.vaadin.serverPort)

        appServerProcess.add(webAppDir.canonicalPath + '/')

        File classesDir = project.file("build/classes")
        appServerProcess.add(classesDir.canonicalPath + '/')

        // Execute server
        process = appServerProcess.execute()

        if(!process.alive) {
            project.logger.error("Could not start server,  server terminated with error code ${process.exitValue()}. Please look at jetty.log for reason.")
            return
        }

        // Watch for changes in classes
        if(project.vaadin.plugin.jettyAutoRefresh) {
            def self = this
            Thread.start 'Directory Watcher', {
                watchDirectoryForChanges(self)
            }
        }

        // Build browser GET parameters
        def paramString = ''
        if (project.vaadin.debug) {
            paramString += '?debug'
            paramString += '&' + browserParameters.join('&')
        } else if(!browserParameters.isEmpty()){
            paramString += '?' + browserParameters.join('&')
        }
        paramString = paramString.replaceAll('\\?$|&$', '')

        // Capture log output
        Util.logProcess(project, process, 'jetty.log', { line ->
            if(line.contains('Server:main: Started')) {
                def resultStr = "Application running on http://localhost:${project.vaadin.serverPort} "
                if (project.vaadin.jrebel.enabled) {
                    resultStr += "(debugger on ${project.vaadin.debugPort}, JRebel active)"
                } else if (project.vaadin.debug) {
                    resultStr += "(debugger on ${project.vaadin.debugPort})"
                }
                project.logger.lifecycle(resultStr)
                project.logger.lifecycle('Press [Ctrl+C] to terminate server...')

                // Open browser
                if(project.vaadin.plugin.logToConsole && !restarting) {
                    Util.openBrowser((Project)project, "http://localhost:${(Integer)project.vaadin.serverPort}/${paramString}")
                }
            }
        })

        project.logger.info 'Server running'
    }

    def restart = false

    def startAndBlock() {
        while(true){
            // Keep main loop running so task does not end

            // Reset values
            def restarting = restart
            restart = false
            process = null

            // Start server
            start(restarting)

            // Wait until server process calls destroy()
            process.waitFor()

            // In no restart is requested, terminate task
            if(!restart) {
                break;
            }
        }
    }

    def terminate() {
        if(process){
            process.destroy()
            project.logger.lifecycle("Application server terminated.")
        }
    }

    def restart() {
        restart = true
        terminate()
    }

    def watchDirectoryForChanges(task) {

        File classesDir = null
        if (project.vaadin.plugin.eclipseOutputDir == null) {
            classesDir = project.sourceSets.main.output.classesDir
        } else {
            classesDir = project.file(project.vaadin.plugin.eclipseOutputDir)
        }

        def classesPath = Paths.get(classesDir.canonicalPath)
        def watchService = FileSystems.getDefault().newWatchService()

        Files.walkFileTree classesPath, new SimpleFileVisitor<Path>() {

            @Override
            public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs){
                dir.register(watchService,
                        StandardWatchEventKinds.ENTRY_CREATE,
                        StandardWatchEventKinds.ENTRY_DELETE,
                        StandardWatchEventKinds.ENTRY_MODIFY)
                FileVisitResult.CONTINUE
            }
        }

        project.logger.info "Watching directory $classesDir for changes..."

        def restart = false
        while(true) {
            def key = watchService.take()
            key.pollEvents().each { WatchEvent event ->
                restart = true
            }
            if(!key.reset() || restart) break
        }

        project.logger.info "Stopped watching directory"

        if(restart) {
            task.restart()
        } else {
            project.logger.info 'Stopped watching directory (no restart)'
        }
    }
}
