Grails http://danielhalima.com/grails Development Sun, 28 Feb 2016 10:57:38 +0000 pt-BR hourly 1 http://wordpress.org/?v=3.4.1 Nova jornada http://danielhalima.com/grails/2011/10/07/nova-jornada/ http://danielhalima.com/grails/2011/10/07/nova-jornada/#comments Fri, 07 Oct 2011 16:25:32 +0000 daniel http://techdm.com/grails/?p=1062 Após tantos anos trabalhando diretamente com análise e desenvolvimento de software, decidi por mudar de foco. Caso queiram acompanhar a nova jornada:

http://inconvencional.com.br/

Infelizmente, está disponível somente em português.

Informações para contato (ainda em atualização):

LinkedIn
Facebook
Twitter

Obrigado.

]]>
http://danielhalima.com/grails/2011/10/07/nova-jornada/feed/ 0
Novo plugin para Grails: hibernate-spatial http://danielhalima.com/grails/2011/10/01/novo-plugin-para-grails-hibernate-spatial/ http://danielhalima.com/grails/2011/10/01/novo-plugin-para-grails-hibernate-spatial/#comments Sat, 01 Oct 2011 15:32:10 +0000 daniel http://techdm.com/grails/?p=1039 http://www.grails.org/plugin/hibernate-spatial
http://www.grails.org/plugin/hibernate-spatial-hdb
http://www.grails.org/plugin/hibernate-spatial-postgresql

O anúncio foi feito aqui.

]]>
http://danielhalima.com/grails/2011/10/01/novo-plugin-para-grails-hibernate-spatial/feed/ 0
Material do mini-curso de Groovy e Grails na Semcomp 14 da USP/São Carlos http://danielhalima.com/grails/2011/09/21/material-do-mini-curso-de-groovy-e-grails-na-semcomp14-da-uspsao-carlos-nota-rapida-2/ http://danielhalima.com/grails/2011/09/21/material-do-mini-curso-de-groovy-e-grails-na-semcomp14-da-uspsao-carlos-nota-rapida-2/#comments Wed, 21 Sep 2011 05:13:20 +0000 daniel http://techdm.com/grails/?p=1032 Groovy & Grails – Semcomp 14

]]>
http://danielhalima.com/grails/2011/09/21/material-do-mini-curso-de-groovy-e-grails-na-semcomp14-da-uspsao-carlos-nota-rapida-2/feed/ 0
Dicas de scripts Gant em Grails http://danielhalima.com/grails/2011/08/08/dicas-de-scripts-gant-em-grails-nota-rapida/ http://danielhalima.com/grails/2011/08/08/dicas-de-scripts-gant-em-grails-nota-rapida/#comments Mon, 08 Aug 2011 18:55:02 +0000 daniel http://techdm.com/grails/?p=585
  • Enquanto GRAILS-7274 não for corrigido, use try-catch ao escrever build event handlers;
        eventCreateWarEnd = {warName, stagingDir ->
             try {
                 // Script logic goes here...
             } catch (Exception e) {
                 e.printStackTrace()
                 throw e
             }
        }
    
  • Adicione “verbosidade” ao log do Gant, sempre que necessário:
    import org.codehaus.gant.GantState
    // (...)
    GantState.verbosity = GantState.VERBOSE
    ant.logger.setMessageOutputLevel(GantState.verbosity)
    
  • Prefira AntBuilder.path à utilização de elementos aninhados de classpath:
            ant.path(id: 'myClasspath', { pathelement(location: 'somewhere') })
            ant.java(classname: 'aClass', dir: 'anyDir', fork: true, 
                        classpathref:'myClasspath') {}
    
  • O “prêmio” por ter lido até aqui é trecho de código necessário à execução do weblogic.appc (entre outras atividades, ele pré-compilará os JSPs) após a criação do arquivo .war do seu projeto:

    // _Events.groovy
    import org.codehaus.gant.GantState
    
    eventCreateWarEnd = {warName, stagingDir ->
    
        def beaHome = System.getenv('BEA_HOME')?: 'C:/bea'
        try {
            println "Executing weblogic.appc ${beaHome} ${warName}"
    
            //GantState.dryRun = true
            GantState.verbosity = GantState.VERBOSE
            ant.logger.setMessageOutputLevel(GantState.verbosity)
    
            File warFile = new File(warName)
            File tmpFile = new File(warFile.parentFile, "${warFile.name.tokenize('.')[0]}_tmp.war")
            ant.move(file: warFile, tofile: tmpFile)
    
            ant.path(id: 'appcClasspath', { pathelement(location: "${beaHome}/wlserver_10.3/server/lib/weblogic.jar") })
    
            ant.java(classname: 'weblogic.appc', dir: warFile.parentFile, fork: true, classpathref:'appcClasspath') {
                arg(line: "-output ${warFile.name} -lineNumbers -g -O -keepgenerated ${tmpFile.name}")
            }
        } catch (Throwable e) {
            e.printStackTrace()
            throw e
        }
    }
    

    Referências adicionais:

    ]]>
    http://danielhalima.com/grails/2011/08/08/dicas-de-scripts-gant-em-grails-nota-rapida/feed/ 0
    Código-fonte buscável e navegável http://danielhalima.com/grails/2011/07/25/codigo-fonte-buscavel-e-navegavel-nota-rapida/ http://danielhalima.com/grails/2011/07/25/codigo-fonte-buscavel-e-navegavel-nota-rapida/#comments Mon, 25 Jul 2011 23:21:33 +0000 daniel http://techdm.com/grails/?p=563 Para código-fonte público e escrito em Java, GrepCode pode ser útil.

    Para código-fonte privado e/ou escrito em outras linguagens (ou armazenado usando inusitados softwares de controle de versão), vale a pena conhecer o OpenGrok.

    Referências adicionais:

    ]]>
    http://danielhalima.com/grails/2011/07/25/codigo-fonte-buscavel-e-navegavel-nota-rapida/feed/ 0
    Melhoria de desempenho do freemarker-tags http://danielhalima.com/grails/2011/07/17/melhoria-de-desempenho-do-freemarker-tags-nota-rapida/ http://danielhalima.com/grails/2011/07/17/melhoria-de-desempenho-do-freemarker-tags-nota-rapida/#comments Sun, 17 Jul 2011 16:18:46 +0000 daniel http://techdm.com/grails/?p=532 Para a maioria das aplicações o tempo gasto na geração das saídas das views é pequeno e, portanto, qualquer melhoria nesse aspecto será desprezível.
    Para as aplicações sensíveis a esse tempo, freemarker-tags foi redesenhado, melhorando seu desempenho. Na versão 0.7.0 do plugin, a velocidade de renderização das Grails Tag Libraries, em um template FTL, estará muito próxima à de uma página GSP compilada:

    A) Aplicação quick_start iniciada usando ‘grails prod run-war’ e testada usando ‘ab -n 3000 -c 30 url’

    #request/second (mean)

    freemarker-tags-0.6.1

    list: 165.99 #/sec, 403.29 #/sec, 448.74 #/sec, 421.15 #/sec
    create: 201.49 #/sec, 407.45 #/sec, 449.79 #/sec, 436.02 #/sec
    show: 231.39 #/sec, 428.36 #/sec, 496.63 #/sec, 468.14 #/sec
    edit: 186.29 #/sec, 348.25 #/sec, 388.07 #/sec, 372.15 #/sec

    gsp

    list: 248.94 #/sec, 714.39 #/sec, 777.56 #/sec, 688.66 #/sec
    create: 251.24 #/sec, 712.82 #/sec, 891.65 #/sec, 813.68 #/sec
    show: 250.04 #/sec, 742.08 #/sec, 990.49 #/sec, 918.49 #/sec
    edit: 230.59 #/sec, 720.73 #/sec, 903.11 #/sec, 783.17 #/sec

    freemarker-tags-0.7.0

    list: 222.27 #/sec, 670.82 #/sec, 720.34 #/sec, 627.70 #/sec
    create: 218.92 #/sec, 618.93 #/sec, 750.98 #/sec, 695.02 #/sec
    show: 250.08 #/sec, 786.39 #/sec, 1040.83 #/sec, 878.74 #/sec
    edit: 211.43 #/sec, 636.35 #/sec, 823.98 #/sec, 757.29 #/sec

    Em situações particulares, o desempenho do template FTL será ainda melhor do que o de uma página GSP, graças ao próprio FreeMarker:

    B) Aplicação dynamic_rendering iniciada usando ‘grails run-app’ e testada usando ‘ab -n 3000 -c 30 url’

    freemarker-tags-0.6.1

    Template Creation: 9687ms, 8652ms, 8142ms, 8056ms, 8068ms
    Rendering: 14188ms, 9820ms, 9184ms, 8944ms, 8913ms
    Both: 17489ms, 17655ms, 17698ms, 17575ms, 17629ms

    gsp

    Template Creation: java.lang.OutOfMemoryError: PermGen space
    Rendering: 12492ms, 8571ms, 7680ms, 7293ms, 7280ms
    Both: ?

    freemarker-tags-0.7.0

    Template Creation: 9630ms, 8640ms, 8182ms, 8204ms, 8216ms
    Rendering: 8740ms, 5861ms, 5156ms, 4933ms, 4941ms
    Both: 13377ms, 13327ms, 13374ms, 13273ms, 13240ms

    C) Aplicação dynamic_rendering iniciada usando ‘grails run-app’ e testada usando ‘ab -n 3000 -c 30 url’
    freemarker-tags-0.6.1


    freemarker-tags-0.6.1
    Template Creation: 9924ms, 8725ms, 8027ms, 7969ms, 7950ms
    Rendering: 13098ms, 8682ms, 8035ms, 7827ms, 7860ms
    Both: 16271ms, 16271ms, 16194ms, 16178ms, 16176ms

    gsp

    Template Creation: java.lang.OutOfMemoryError: PermGen space
    Rendering: 10687ms, 7084ms, 6311ms, 5941ms, 5867ms
    Both: java.lang.OutOfMemoryError: PermGen space at gspTemplate415:63

    freemarker-tags-0.7.0

    Template Creation: 9941ms, 8556ms, 8028ms, 7868ms, 7864ms
    Rendering: 8900ms, 5646ms, 4855ms, 4747ms, 4748ms
    Both: 13014ms, 13034ms, 13001ms, 13018ms, 12953ms

    O tempo de “dynamic rendering” é o mesmo percebido pelo desenvolvedor, durante o ciclo alteração <-> atualização da view. Para uma referência, abra as URLs http://localhost:8080/dynamic_rendering/benchmark/freemarkerPage e http://localhost:8080/dynamic_rendering/benchmark/gspPage em abas distintas do seu navegador e, para cada uma delas, clique algumas vezes no botão “atualizar”.

    Projeto no GitHub.
    Download do código-fonte e dos resultados completos.

    ]]>
    http://danielhalima.com/grails/2011/07/17/melhoria-de-desempenho-do-freemarker-tags-nota-rapida/feed/ 0
    Gerenciamento programático de transações em Grails http://danielhalima.com/grails/2011/07/02/gerenciamento-programatico-de-transacoes-em-grails-nota-rapida/ http://danielhalima.com/grails/2011/07/02/gerenciamento-programatico-de-transacoes-em-grails-nota-rapida/#comments Sat, 02 Jul 2011 16:22:10 +0000 daniel http://techdm.com/grails/?p=515 Até que GRAILS-7093 faça parte do core, a funcionalidade permanecerá disponível na forma de um plugin para Grails: transaction-handling.

    Exemplos de utilização:

            User.withTransaction {
            }
    
            User.withTransaction(isolation: 'readUncommitted') {
            }
    
            User.withTransaction(readOnly: true, timeout: 'default') {
            }
    
            User.withTransaction(propagationBehaviorName: 'PROPAGATION_MANDATORY', timeout: 765) {
            }
    
            User.withTransaction(propagation: "mandatory") {
            }
    
            User.withNewTransaction {
            }
    
            User.withNewTransaction(isolationLevel: TransactionDefinition.ISOLATION_SERIALIZABLE) {
            }
    
            User.withNewTransaction(propagation: 'supports', readOnly: true, timeout: 612) {
            }
    
            User.withNewTransaction(isolationLevelName: 'ISOLATION_REPEATABLE_READ') {
            } 
    

    Referências adicionais

    ]]>
    http://danielhalima.com/grails/2011/07/02/gerenciamento-programatico-de-transacoes-em-grails-nota-rapida/feed/ 0
    GSP x FTL (microbenchmark) http://danielhalima.com/grails/2011/06/10/gsp-x-ftl-microbenchmark/ http://danielhalima.com/grails/2011/06/10/gsp-x-ftl-microbenchmark/#comments Fri, 10 Jun 2011 01:35:10 +0000 daniel http://techdm.com/grails/?p=445 Groovy Server Pages x FreeMarker Templates. Ambas são boas ferramentas, são mantidas por equipes extremamente qualificadas e estão disponíveis para Grails (FreeMarker através dos plugins freemarker e freemarker-tags).

    Conforme já mencionado anteriormente, microbenchmarks são apenas microbenchmarks. Os testes a seguir foram motivados por uma antiga discussão sobre a renderização de templates dinâmicos e pelo recente tópico sobre o desempenho de renderização de vários frameworks web.

    Seguem-se os resultados obtidos, para o cenário particular do tópico em questão:

    Apache HTTP server benchmarking tool (ab)

    • GSP

      Document Path: /grailsapp/products
      Document Length: 1037698 bytes

      Concurrency Level: 30
      Time taken for tests: 383.757685 seconds
      Complete requests: 3000
      Failed requests: 0
      Write errors: 0
      Total transferred: 3113592000 bytes
      HTML transferred: 3113094000 bytes
      Requests per second: 7.82 [#/sec] (mean)
      Time per request: 3837.577 [ms] (mean)
      Time per request: 127.919 [ms] (mean, across all concurrent requests)
      Transfer rate: 7923.27 [Kbytes/sec] received

      Connection Times (ms)
      min mean[+/-sd] median max
      Connect: 0 0 1.1 0 14
      Processing: 2105 3829 380.8 3831 5122
      Waiting: 2097 3824 381.0 3825 5120
      Total: 2105 3829 380.9 3831 5122

      Percentage of the requests served within a certain time (ms)
      50% 3831
      66% 3987
      75% 4092

    • FTL

      Document Path: /grailsapp-fm/products
      Document Length: 1026697 bytes

      Concurrency Level: 30
      Time taken for tests: 103.94286 seconds
      Complete requests: 3000
      Failed requests: 0
      Write errors: 0
      Total transferred: 3080604000 bytes
      HTML transferred: 3080091000 bytes
      Requests per second: 29.10 [#/sec] (mean)
      Time per request: 1030.943 [ms] (mean)
      Time per request: 34.365 [ms] (mean, across all concurrent requests)
      Transfer rate: 29181.07 [Kbytes/sec] received

      Connection Times (ms)
      min mean[+/-sd] median max
      Connect: 0 0 0.0 0 0
      Processing: 74 1027 646.1 962 4373
      Waiting: 71 988 643.3 915 4006
      Total: 74 1027 646.1 962 4373

      Percentage of the requests served within a certain time (ms)
      50% 962
      66% 1212
      75% 1376

    JMeter

    • GSP

    • FTL

    Informações relevantes:

    • As aplicações foram iniciadas usando-se ‘grails prod run-war’;
    • Para a execução do Apache benchmarking foi usado o comando ‘ab -n 3000 -c 30 URL’;
    • O arquivo de configuração do JMeter pode ser encontrado aqui;
    • Os resultados completos encontram-se aqui;
    • O desempenho de renderização dos GSPs foi melhorado na versão 1.4 de Grails: GRAILS-7582.

    Projeto no github.

    Referências adicionais:

    ]]>
    http://danielhalima.com/grails/2011/06/10/gsp-x-ftl-microbenchmark/feed/ 11
    Usando Grails para construir um sistema batch simples http://danielhalima.com/grails/2011/06/06/usando-grails-para-construir-um-sistema-batch-simples/ http://danielhalima.com/grails/2011/06/06/usando-grails-para-construir-um-sistema-batch-simples/#comments Mon, 06 Jun 2011 00:22:31 +0000 daniel http://techdm.com/grails/?p=371 Inspirado pela discussão sobre ‘Como eu carregaria um job Quartz a partir de um script’ e baseando-me na postagem sobre o ‘Tiny GroovyServ’, resolvi implementar um sistema batch simples usando Grails e os plugins quartz, spring-security-core e batch-launcher.

    O batch-launcher foi adotado porque, na empresa na qual trabalho, os ambientes para aplicações online (web) e batch são segregados. Dessa forma, no ambiente exclusivo a aplicações batch não há Tomcat, WebLogic ou qualquer Web Container ou Application Server. Nesse contexto, as aplicações batch são responsáveis por todo processamento massivo e assíncrono, principalmente aquele necessário à integração de dois ou mais sistemas.

    Basicamente foi criada uma aplicação composta por serviços e tarefas agendadas cuja invocação síncrona ou assíncrona pode ser feita através de um cliente de SSH. O passo-a-passo para teste:

    1. Efetuar download do arquivo simple_batch_system-0.1.zip (o arquivo possui, aproximadamente, 25 MBytes e contém todas as dependências necessárias à execução da aplicação)
    2. Descompactar o arquivo em um diretório qualquer
    3. Iniciar a aplicação (o único pré-requisito para esse passo é ter uma JRE instalada e o java estar disponível no PATH)

      [daniel@techdm simple_batch_system-0.1]$ ./simple_batch_system.sh

      ou

      simple_batch_system.bat

    4. Disparar a execução de serviços ou tarefas agendadas, como admin0 (a senha é admin):

      ssh -p 8123 admin0@localhost task1Job,task3Service

    Algumas observações importantes:

    • Para os casos onde não há segregação dos ambientes online (web) e batch, uma abordagem semelhante pode ser adotada na implementação de aplicações Grails “comuns” (web). O código-fonte, para a execução dos comandos ssh, pode ser encontrado aqui;
    • O plugin spring-security-core é opcional e foi utilizado somente para a criação de um modelo de domínio conhecido de usuários e perfis;
    • O mecanismo de chaves públicas e privadas pode ser adotado como alternativa de autenticação. Isso combinado a um ssh-agent eliminaria a necessidade da troca de senhas, sem reduzir a segurança da solução;
    • É possível implementar uma sessão SSH interativa, para a execução dos comandos;
    • Durante qualquer desenvolvimento usando batch-launcher, os comandos de maior destaque são ‘grails batch-run-app’, ‘grails interactive’ (combinado com ‘batch-reload-app’) e ‘grails batch-war’.

    Projeto no gitbub.
    Download do código-fonte.

    ]]>
    http://danielhalima.com/grails/2011/06/06/usando-grails-para-construir-um-sistema-batch-simples/feed/ 3
    Tiny GroovyServ http://danielhalima.com/grails/2011/06/03/tiny-groovyserv/ http://danielhalima.com/grails/2011/06/03/tiny-groovyserv/#comments Fri, 03 Jun 2011 04:35:54 +0000 daniel http://techdm.com/grails/?p=323 GroovyServ é uma solução interessante para a execução de múltiplos scripts Groovy em uma JVM compartilhada. Infelizmente, conforme citado nesse tópico, a limitação em relação aos sistemas operacionais suportados pode se tornar um problema.

    Como abordagem alternativa, foi escrito um pequeno servidor SSH usando Groovy. Dessa maneira, qualquer cliente SSH nativo estaria apto a enviar comandos de execução de script ao servidor. A idéia segue a mesma linha de raciocínio da combinação ‘groovy -l’ e telnet. Para todo o tratamento do protocolo SSH, foi utilizado o Apache Mina SSHD.

    Vale ressaltar que o servidor desenvolvido é apenas um primo distante, não otimizado, inseguro e funcionalmente limitado do GroovyServ, não tendo a pretensão de substituí-lo. Para a execução em ambientes não controlados, aconselha-se a utilização de um SecurityManager devidamente configurado, bem como a adoção de mecanismo de autenticação adequado.

    Passo-a-passo para a utilização:

    1. Efetuar download do código-fonte do servidor

    2. Descompactar o conteúdo do arquivo em um diretório

    3. Iniciar o servidor

    [user@techdm tiny-groovyserv]$ groovy tgserv.groovy

    ou

    [user@techdm tiny-groovyserv]$ groovy tgserv.groovy 8123

    4. Escrever alguns scripts no mesmo computador

    5. Iniciar mais de prompt de comando ou shell e executar, simultaneamente, os scripts criados

    [user@techdm test]$ ssh -p 8123 localhost /tmp/test/a.groovy abc 123

    [user@techdm dir1]$ ssh -p 8123 localhost /tmp/test/dir1/b.groovy

    [user@techdm dir2]$ ssh -p 8123 localhost /tmp/test/dir2/c.groovy

    ou usando plink:

    C:\tmp\test> plink -P 8123 -ssh -l x localhost c:/tmp/test/a.groovy abc 123

    C:\tmp\test\dir1> plink -P 8123 -ssh -l x localhost c:/tmp/test/dir1/b.groovy

    C:\tmp\test\dir2> plink -P 8123 -ssh -l x localhost c:/tmp/test/dir2/c.groovy

    Projeto no github.

    Referências adicionais:

    /*
     * http://www.apache.org/licenses/LICENSE-2.0
     */
    
    /**
     * @author Daniel Henrique Alves Lima
     */
    import java.io.IOException;
    
    import groovy.lang.GroovyClassLoader
    import org.codehaus.groovy.runtime.StackTraceUtils
    
    import org.apache.sshd.SshServer
    import org.apache.sshd.server.auth.UserAuthNone
    import org.apache.sshd.server.Command
    import org.apache.sshd.server.CommandFactory
    import org.apache.sshd.server.command.ScpCommandFactory
    import org.apache.sshd.server.Environment
    import org.apache.sshd.server.ExitCallback
    import org.apache.sshd.server.keyprovider.SimpleGeneratorHostKeyProvider
    
    //import org.apache.sshd.server.PasswordAuthenticator
    //import org.apache.sshd.server.PublickeyAuthenticator
    
    SshServer sshd = SshServer.setUpDefaultServer()
    sshd.port = args && args.length > 0? args[0] as int : 8123
    sshd.keyPairProvider = new SimpleGeneratorHostKeyProvider('hostkey.ser')
    
    def sysOut = System.out
    
    def findMyClassLoader = {ClassLoader cl = Thread.currentThread().contextClassLoader ->
        while (cl != null && !(cl instanceof MyGroovyClassLoader)) {
            cl = cl.parent
        }
        return cl
    }
    
    sshd.commandFactory = new ScpCommandFactory(
        {command ->
    
            command = command.tokenize(' ')
            def cmd
            cmd = [
                input: null, output: null, error:null, callback: null,
                setExitCallback: {cb -> cmd.callback = cb},
                setInputStream: {is -> cmd.input = is as InputStream},
                setOutputStream: {out -> cmd.output = new PrintStream(out)},
                setErrorStream: {err -> cmd.error = new PrintStream(err)},
                destroy: {},
                start: {env ->
                    Thread currentThread = Thread.currentThread()
                    sysOut.println "${currentThread} begin"
                    def oldThreadCl = currentThread.contextClassLoader
                    def cl = new MyGroovyClassLoader(oldThreadCl? oldThreadCl : this.class.classLoader)
                    cl.errorStream = cmd.error; cl.inputStream = cmd.input; cl.outputStream = cmd.output
    				
                    def scriptName = command.size() > 0?"${command[0]}":''
                    def scriptArgs = (command.size() > 1? command.subList(1, command.size()): []) as String[]
                    ThreadGroup tg = new ThreadGroup(currentThread.threadGroup, 
                                                     "${currentThread.threadGroup.name}:${scriptName}")
                    Thread t = new Thread(tg,
                                          {
                                              long time = -1; int result = -1
                                              try {							
                                                  def scriptFile = new File(scriptName)
                                                  if (scriptFile.parentFile) {cl.addURL(scriptFile.parentFile.toURI().toURL())}
                                                  def script = cl.parseClass(scriptFile)
                                                  assert cl.equals(findMyClassLoader(script.classLoader))
                                                  time = System.currentTimeMillis()
                                                  script = script.newInstance()
                                                  script.args = scriptArgs; script.run()
                                                  result = 0
                                              } catch (Exception e) {
                                                  e =  StackTraceUtils.deepSanitize(e)
                                                  sshd.log.error("Error running script ${scriptName}", e)
                                                  e.printStackTrace()
                                                  throw e
                                              } finally {
                                                  try {
                                                      while (tg.activeCount() > 1 || tg.activeGroupCount() > 1) {Thread.sleep 100}
                                                      System.err.flush(); System.out.flush()
                                                      cl.release()
                                                  } finally {
                                                      if (time > 0) {time = System.currentTimeMillis() - time; sysOut.println "${Thread.currentThread()} ${time} (ms)"}
                                                      sysOut.println "${Thread.currentThread()} end"
                                                      cmd.callback.onExit(result)
                                                  }
                                              }
                                          }
                                          as Runnable
                                         )
                    t.contextClassLoader = cl
                    t.start()	
                }
            ]
            
            return cmd as Command
    
        } as CommandFactory
    )
    
    /*sshd.publickeyAuthenticator = {username, key, session ->
        return true
        } as PublickeyAuthenticator*/
    
    
    /*sshd.passwordAuthenticator = {username, password, session ->
        return true
        } as PasswordAuthenticator*/
    
    
    def userAuthFactories = sshd.userAuthFactories
    if (!userAuthFactories) {userAuthFactories = []}
    userAuthFactories << new UserAuthNone.Factory()
    sshd.userAuthFactories = userAuthFactories
    
    
    System.err = new PrintStream(new MyOutputStream(System.err, findMyClassLoader))
    System.out = new PrintStream(new MyOutputStream(System.out, findMyClassLoader))
    System.in = new MyInputStream(System.in, findMyClassLoader)
    
    sshd.start()
    
    
    class MyGroovyClassLoader extends GroovyClassLoader {
    
        def inputStream
        def outputStream
        def errorStream
        
        public MyGroovyClassLoader() {
            super()
        }
    
        public MyGroovyClassLoader(ClassLoader loader) {
            super(loader)
        }
    
        public MyGroovyClassLoader(GroovyClassLoader parent) {
            super(parent)
        }
        
        public void release() {
            errorStream?.flush(); outputStream?.flush()
            errorStream?.close(); outputStream?.close(); inputStream?.close()
        }
        
    }
    
    class MyInputStream extends InputStream {
        
        private InputStream input
        private Closure selectCl
        
        public MyInputStream(InputStream input, Closure selectCl) {this.input = input; this.selectCl = selectCl}
    
        @Override
        public int read() throws IOException {
            def cl = selectCl()
            return (cl? cl.inputStream : input).read()
        }
    
        @Override
        public int read(byte[] b, int off, int len) throws IOException {
            def cl = selectCl()
            return (cl? cl.inputStream : input).read(b, off, len)
        }
              
    }
    
    class MyOutputStream extends OutputStream {
        
        private OutputStream output
        private Closure selectCl
        
        public MyOutputStream(OutputStream output, Closure selectCl) {this.output = output; this.selectCl = selectCl}
    
        @Override
        public void write(int b) throws IOException {
            def cl = selectCl()
            (cl? cl.outputStream : output).write(b)
        }
        
        @Override
        public void write(byte[] b, int off, int len) throws IOException {
            def cl = selectCl()
            (cl? cl.outputStream : output).write(b, off, len)
            flush() //
        }
    
        @Override
        public void flush() throws IOException {
            def cl = selectCl()
            (cl? cl.outputStream : output).flush()
        }
        
    }
    
    ]]>
    http://danielhalima.com/grails/2011/06/03/tiny-groovyserv/feed/ 0