Speed Up Your Development:GroovyServ & Grails Improx Plugin@nobeansYasuharu NAKANO
GroovyServ
In case ofDevelopinga Groovy Script
Write RunCommon Strategy:“Trial and Error”
$	  time	  groovy	  -­‐e	  “println	  ‘Hello,	  Groovy’”Hello,	  Groovyreal	  	  	  	  0m0.823suser	  	  	  	  0m1.016ssys...
N timesTrial and Errortakes N sec.
“Many a little makesa mickle”
Waiting timemakes meForget nextaction
Why so slow?• JVM initialization• Loading Many Many Classes• .... from Diskhttp://en.wikipedia.org/wiki/Java_performance#S...
Doom of JVMLanguages?
Any solutions?
$	  groovyConsole
DemogroovyConsole
groovyConsole• Handy for trying Java/Groovy APIs, etc.• But features as editor aren’t so rich:• No code completion• No syn...
Other solutions?
GroovyServ“GroovyServ makes Groovy’s startup time muchfaster, by pre-invoking Groovy as a server.”http://kobo.github.io/gr...
DemoGroovy and GroovyServ
$	  time	  groovyclient	  -­‐e	  “println	  ‘Hello,	  GroovyServ’”Hello,	  GroovyServreal	  	  	  	  0m0.031suser	  	  	  ...
NormalGroovy User GroovyScriptShell Environment JavaVMFile SystemCLASSPATHcmdlineargsstdinstdoutstderrCtrl-CotherENVsexits...
Shell EnvironmentJavaVMFile SystemUser GroovyScriptCLASSPATHcmdlineargsstdinstdoutstderrCtrl-CotherENVs≪file≫Authtokenexits...
In case ofDevelopinga Groovy Script
GroovyServ Way• Write code with your favorite IDE/editor• Run the code by using GroovyServ asExternal Tool• You can also s...
DemoGroovyServ way
Available Editors/IDEs• IntelliJ IDEA• Eclipse/STS/GGTS• Sublime Text 2• Vim + QuickRun.vim• and more...
GroovyServ“GroovyServ makes Groovy’s startup time muchfaster, by pre-invoking Groovy as a server.”http://kobo.github.io/gr...
How to Install
How to Install• Downloadable Binaries for• Mac OS X (built at Mac OS X 10.8 (x86_64))• Windows• bundled in Groovy Windows ...
No setting required• If there is a binary set, you can use it:• $	  /xxx/groovyserv/bin/groovyclient• Adding to PATH, you ...
How to Use
Commands• groovyclient• groovyserver
groovyclient• Invokes a groovy file or one-liner code, bysending a request to server• Also invokes groovyserver processauto...
groovyserver• Invokes a JVM process as a server.• Should be used only when you want tospecify special options.• e.g.• -­‐v...
Available for OtherJVM Languageshttp://nobeans-en.blogspot.jp/2011/07/high-speed-start-up-jythonclojure-by.html
Jython$	  alias	  gythonserver="env	  CLASSPATH=/your/jython.jar	  groovyserver"$	  alias	  gython="groovyclient	  -­‐e	  ...
Clojure$	  alias	  glojureserver="env	  CLASSPATH=/your/clojure.jar	  groovyserver"$	  alias	  glojure="groovyclient	  -­‐...
• A script to get schedule data fromgroupware• As editor’s macro• As mail filter• etc.Using at Runtime
Other Features• Access Control• Propagation of CLASSPATH• Propagation of Environment Variables• Handling System#exit()• Dy...
Improx Plugincodenamed:GrailsServ
In case ofDevelopingGrails Application
Grails’ Test supportsis Great.
How to run tests• All tests• grails	  test-­‐app
While I’m writing a test,I want to run only it.
I want to run the testas fast as possible.
How to run a specified test fast• Run only a unit test• test-­‐app	  unit:	  <FQCN	  of	  TestClass>• Run only a integrati...
Why does it needa test phase?
If test phase not specified when run unit test,integration phase is also run.$	  cat	  test/unit/test/app/sample/FooTests....
 Integration
 phase
 running!?
$	  time	  grails	  test-­‐app	  unit:	  FooTests|	  Completed	  1	  unit	  test,	  0	  failed	  in	  546ms|	  Tests	  PAS...
 than
 a
 half
 of
 previous
 sample!Specifying a phase can avoidrunning an extra phaseWithout	  a	  phase:real	  	  	  	  0m15.375suser	  	  	  	  0m3...
Required to run test-app• FQCN of target test class• Test phase of target test class
By the way
How do you run a test while writing it?• (A) By IDE support (GGTS, IntelliJ, etc.)• (B) By “grails test-app” as standalone...
Interactive Mode• Very very useful• Makes command execution faster becausethe JVM doesnt have to be restarted foreach comm...
DEMOInteractiveMode/Pros
But still there is trouble• It needs frequent switching of windowsfor use while writing code in IDE/editor• To run a test,...
DEMOInteractiveMode/Cons
I’m too tired fromsuch Switching,Copy  Paste, etc...
Improx PluginProvides the way of using interactive modefrom other process via TCP.http://grails.org/plugin/improx
DEMOImprox Plugin
Improx Plugin• You can run a test• Faster than general IDE supportsbecause using interactive mode• Directly from IDE/edito...
Available Editors/IDEs• IntelliJ IDEA• Eclipse/STS/GGTS• Sublime Text 2• Vim + QuickRun.vim• and more...
InteractiveModePROXy
GrailsImproxShell Environment≪script≫improxClientTCP/IP≪script≫improxSmartInvoker≪class≫InteractiveMode≪class≫GrailsConsol...
• As same as interactive mode• install-­‐plugin• uninstall-­‐plugin• Special built-in commands• create-­‐app• quit• stop-­...
How to Install
BuildConfig.groovy:plugins	  {//...	  	  	  	  compile	  :improx:0.2//...}Install Plugin
Install Client Scripts$	  grails	  improx-­‐install-­‐resources|	  Improx	  resources	  installed	  successfully:	  /xxx/i...
 once
 you
 store
 them
 to
 global
 path,
 
 you
 dont
 need
 the
 preparation
 for
 other
 projects.
How to Use
Grails Commands• improx-­‐start• improx-­‐stop• improx-­‐install-­‐resources
improx-­‐start	  /	  improx-­‐stop• improx-­‐start• Starts an interactive mode proxy server• improx-­‐stop• Stops the inte...
improx-­‐install-­‐resources• Installs “improx-resources” directory whichhas some client scripts into yourapplication proj...
Client Scripts• improxClient.sh• improxClient.groovy• improxSmartInvoker.sh• improxSmartInvoker.groovy
improxClient.(sh|groovy)	  Command• Runs a command in interactive mode viaTCP port of improx server• Very simple
$	  improxClient.sh	  helpExecuting	  help	  via	  interactive	  mode	  proxy.........Usage	  (optionals	  marked	  with	 ...
improxSmartInvoker.(sh|groovy)	  FILE_PATH• Invokes any *.groovy file in an appropriateway• Very useful for IDE/editor
How SMART is it?
grails	  test-­‐app	  unit:	  sample.SampleUnitTests$	  improxSmartInvoker.sh	  /path/to/yourApp/test/unit/sample/SampleUn...
grails	  test-­‐app	  integration:	  sample.SampleIntegTests$	  improxSmartInvoker.sh	  /path/to/yourApp/test/integration/...
$	  improxSmartInvoker.sh	  /path/to/yourApp/test/functional/sample/SampleFuncTests.groovygrails	  test-­‐app	  functional...
 functional
 test
 doesn’t
 work
 well
 on
 interactive
 mode
 at
 present.Runs the following commandas new standalone Grails process:
$	  improxSmartInvoker.sh	  /path/to/scriptDir/myTribialScript.groovygroovy	  /path/to/scriptDir/myTribialScript.groovyIf
 youve
 installed
 GroovyServ,
 the
 groovyclient
 is
 automatically
 used
 instead
 of
 groovy
 command.Runs the following commandas a normal Groovy script:
All you have to do isto setimproxSmartInvokeras External Toolof IDE/editorhttp://kobo.github.io/grails-improx/guide/integr...
SimpleProtocol
TCP• Request:COMMAND• Whole response is result of the command• You can also use as client• e.g. telnet, nc
$	  telnet	  localhost	  8096Trying	  ::1...Connected	  to	  localhost.Escape	  character	  is	  ^].help......Usage	  (opt...
HTTP• RequestGET	  /COMMAND	  HTTP/[0-­‐9.]+• Whole response is result of the command• You can also use as client• e.g. We...
• GroovyServ• http://kobo.github.io/groovyserv/index.html• https://github.com/kobo/groovyserv• Improx - Interactive Mode P...
Appendix
GroovyServUnder the hood
Under the hood• Client-Server Communication• Access Control• Propagation of CLASSPATH• Propagation of Environment Variable...
Client-ServerCommunication
Transfer of StandardIn/Out/Err Stream
$	  groovyclient	  -­‐e	  println	  ‘Hello,	  GroovyServ’
groovyclientClientConnectionOutputStream≪script≫println “Hello, GroovyServ!”≪System.out≫DynamicDelegatedPrintStreamwrites ...
$	  groovyclient	  -­‐e	  System.in.eachLine{	  println	  it*5	  }
ClientConnectionPipedOutputStreamPipedInputStreamgroovyclient ≪thread≫StreamRequestHandler≪script≫System.in.eachLine { ......
Protocol over TCP
InvocationRequestCwd: cwd LFArg: arg1 LFArg: arg2 LF:Env: env1=value1 LFEnv: env2=value2 LF:Cp: classpath LFAuthToken: aut...
StreamRequestSize: size LFLFbody from STDINwhere:size is the size of body to send to server. size==-1 meansclient exited.b...
InvocationResponseStatus: status LFwhere:status is exit status of invoked groovy script.
StreamResponseChannel: id LFSize: size LFLFbody for STDERR/STDOUTwhere:id is out or err, where out means standard output o...
Access Control
AgainstEvil RequestFrom Evil Client
Client Address Checking / Authtoken• Request only from loopback address isallowed.• Authtoken is generated and stored into...
-­‐-­‐allow-­‐from• By default, A request only from loop-backaddress is available.• You can allow specified addresses.$	  g...
-­‐-­‐authtoken• By default, authtoken is generatedautomatically.• You can specify any string.SECURITY RISK: Be careful wh...
At your own risk
Propagation ofCLASSPATH
Client and Serverare DifferentProcess
≪process≫groovyserver≪process≫groovyclientCLASSPATH=/my/classpath/xxx.jarCLASSPATH=/my/classpath/zzz.jarIndividual Env for...
If GroovyServ weretoo simple, ...
≪process≫groovyserver≪process≫groovyclientCLASSPATH=/my/classpath/foo.jar
≪process≫groovyserver≪process≫groovyclientPlease execute this!new foo.Foo().execute()CLASSPATH=/my/classpath/foo.jar
≪process≫groovyserver≪process≫groovyclientCLASSPATH=/my/classpath/foo.jarI don’t know its class!Please execute this!new fo...
≪process≫groovyserver≪process≫groovyclientCLASSPATH=/my/classpath/foo.jarI don’t know its class!org.codehaus.groovy.contro...
Upcoming SlideShare
Loading in …5
×

Gr8conf EU 2013 Speed up your development: GroovyServ and Grails Improx Plugin

3,627 views

Published on

Published in: Technology

Gr8conf EU 2013 Speed up your development: GroovyServ and Grails Improx Plugin

  1. 1. Speed Up Your Development:GroovyServ & Grails Improx Plugin@nobeansYasuharu NAKANO
  2. 2. GroovyServ
  3. 3. In case ofDevelopinga Groovy Script
  4. 4. Write RunCommon Strategy:“Trial and Error”
  5. 5. $  time  groovy  -­‐e  “println  ‘Hello,  Groovy’”Hello,  Groovyreal        0m0.823suser        0m1.016ssys          0m0.096sBut, It takes 1 sec!
  6. 6. N timesTrial and Errortakes N sec.
  7. 7. “Many a little makesa mickle”
  8. 8. Waiting timemakes meForget nextaction
  9. 9. Why so slow?• JVM initialization• Loading Many Many Classes• .... from Diskhttp://en.wikipedia.org/wiki/Java_performance#Startup_time“ It seems that much of the startup time is due to IO-bound operations rather than JVM initialization orclass loading (the rt.jar class data file alone is 40 MBand the JVM must seek a lot of data in this huge file).
  10. 10. Doom of JVMLanguages?
  11. 11. Any solutions?
  12. 12. $  groovyConsole
  13. 13. DemogroovyConsole
  14. 14. groovyConsole• Handy for trying Java/Groovy APIs, etc.• But features as editor aren’t so rich:• No code completion• No syntax checking• No auto import• etc.• I want to use my favorite IDE/editor!
  15. 15. Other solutions?
  16. 16. GroovyServ“GroovyServ makes Groovy’s startup time muchfaster, by pre-invoking Groovy as a server.”http://kobo.github.io/groovyserv/
  17. 17. DemoGroovy and GroovyServ
  18. 18. $  time  groovyclient  -­‐e  “println  ‘Hello,  GroovyServ’”Hello,  GroovyServreal        0m0.031suser        0m0.001ssys          0m0.002sNormal  Groovy:real        0m0.823suser        0m1.016ssys          0m0.096s
  19. 19. NormalGroovy User GroovyScriptShell Environment JavaVMFile SystemCLASSPATHcmdlineargsstdinstdoutstderrCtrl-CotherENVsexitstatusSystem.inSystem.outSystem.errgroovyUser GroovyScript
  20. 20. Shell EnvironmentJavaVMFile SystemUser GroovyScriptCLASSPATHcmdlineargsstdinstdoutstderrCtrl-CotherENVs≪file≫AuthtokenexitstatusTCP/IPSystem.inSystem.outSystem.errgroovyservergroovyclientGroovyServ
  21. 21. In case ofDevelopinga Groovy Script
  22. 22. GroovyServ Way• Write code with your favorite IDE/editor• Run the code by using GroovyServ asExternal Tool• You can also see the result on a consoleof IDE
  23. 23. DemoGroovyServ way
  24. 24. Available Editors/IDEs• IntelliJ IDEA• Eclipse/STS/GGTS• Sublime Text 2• Vim + QuickRun.vim• and more...
  25. 25. GroovyServ“GroovyServ makes Groovy’s startup time muchfaster, by pre-invoking Groovy as a server.”http://kobo.github.io/groovyserv/
  26. 26. How to Install
  27. 27. How to Install• Downloadable Binaries for• Mac OS X (built at Mac OS X 10.8 (x86_64))• Windows• bundled in Groovy Windows Installer• (built at WindowsXP (32bit) (x86))• (built at Windows7 (64bit) (AMD64))• Linux (i386) (linked with glibc 2.9)• Self-build (required Gradle)• Homebrew (only Mac)• $  brew  install  groovyserv• http://kobo.github.io/groovyserv/howtoinstall.html
  28. 28. No setting required• If there is a binary set, you can use it:• $  /xxx/groovyserv/bin/groovyclient• Adding to PATH, you can easily use it:• $  groovyclient
  29. 29. How to Use
  30. 30. Commands• groovyclient• groovyserver
  31. 31. groovyclient• Invokes a groovy file or one-liner code, bysending a request to server• Also invokes groovyserver processautomatically if not exists
  32. 32. groovyserver• Invokes a JVM process as a server.• Should be used only when you want tospecify special options.• e.g.• -­‐v                        verbose  option• -­‐-­‐allow-­‐from    for  remote  feature
  33. 33. Available for OtherJVM Languageshttp://nobeans-en.blogspot.jp/2011/07/high-speed-start-up-jythonclojure-by.html
  34. 34. Jython$  alias  gythonserver="env  CLASSPATH=/your/jython.jar  groovyserver"$  alias  gython="groovyclient  -­‐e  import  org.python.util.jython;  jython.main(args)  -­‐-­‐"$  gythonserver  -­‐r...$  time  gython  -­‐c  "print(Hello)"Helloreal        0m0.057suser        0m0.001ssys          0m0.004s
  35. 35. Clojure$  alias  glojureserver="env  CLASSPATH=/your/clojure.jar  groovyserver"$  alias  glojure="groovyclient  -­‐e  import  clojure.main;main.main(args)  -­‐-­‐"$  glojureserver  -­‐r...$  time  glojure  -­‐e  "(println  Hello)"Helloreal        0m0.053suser        0m0.001ssys          0m0.004smain  method  ofclosure.main  class
  36. 36. • A script to get schedule data fromgroupware• As editor’s macro• As mail filter• etc.Using at Runtime
  37. 37. Other Features• Access Control• Propagation of CLASSPATH• Propagation of Environment Variables• Handling System#exit()• Dynamic CWD
  38. 38. Improx Plugincodenamed:GrailsServ
  39. 39. In case ofDevelopingGrails Application
  40. 40. Grails’ Test supportsis Great.
  41. 41. How to run tests• All tests• grails  test-­‐app
  42. 42. While I’m writing a test,I want to run only it.
  43. 43. I want to run the testas fast as possible.
  44. 44. How to run a specified test fast• Run only a unit test• test-­‐app  unit:  <FQCN  of  TestClass>• Run only a integration test• test-­‐app  integration:  <FQCN  of  TestClass>• Run only a functional test• test-­‐app  functional:  <FQCN  of  TestClass>
  45. 45. Why does it needa test phase?
  46. 46. If test phase not specified when run unit test,integration phase is also run.$  cat  test/unit/test/app/sample/FooTests.groovy....class  FooTests  {        void  testSomething()  {                //  do  nothing        }}$  time  grails  test-­‐app  FooTests|  Packaging  Grails  application.....|  Tests  PASSED  -­‐  view  reports  in  /xxx/test-­‐reportsreal        0m15.375suser        0m35.119ssys          0m1.858sOops!
  47. 47.  Integration
  48. 48.  phase
  49. 49.  running!?
  50. 50. $  time  grails  test-­‐app  unit:  FooTests|  Completed  1  unit  test,  0  failed  in  546ms|  Tests  PASSED  -­‐  view  reports  in  /xxx/test-­‐reportsreal        0m7.303suser        0m18.068ssys          0m0.909sLess
  51. 51.  than
  52. 52.  a
  53. 53.  half
  54. 54.  of
  55. 55.  previous
  56. 56.  sample!Specifying a phase can avoidrunning an extra phaseWithout  a  phase:real        0m15.375suser        0m35.119ssys          0m1.858s
  57. 57. Required to run test-app• FQCN of target test class• Test phase of target test class
  58. 58. By the way
  59. 59. How do you run a test while writing it?• (A) By IDE support (GGTS, IntelliJ, etc.)• (B) By “grails test-app” as standalone• (C) By “grails test-app” via InteractiveMode• (D) Others
  60. 60. Interactive Mode• Very very useful• Makes command execution faster becausethe JVM doesnt have to be restarted foreach command• $  grails• TAB completion is available• Since Grails 2.0
  61. 61. DEMOInteractiveMode/Pros
  62. 62. But still there is trouble• It needs frequent switching of windowsfor use while writing code in IDE/editor• To run a test, you must prepare:• FQCN of target test class• Test phase of target test class
  63. 63. DEMOInteractiveMode/Cons
  64. 64. I’m too tired fromsuch Switching,Copy Paste, etc...
  65. 65. Improx PluginProvides the way of using interactive modefrom other process via TCP.http://grails.org/plugin/improx
  66. 66. DEMOImprox Plugin
  67. 67. Improx Plugin• You can run a test• Faster than general IDE supportsbecause using interactive mode• Directly from IDE/editor withoutcomplicated operations
  68. 68. Available Editors/IDEs• IntelliJ IDEA• Eclipse/STS/GGTS• Sublime Text 2• Vim + QuickRun.vim• and more...
  69. 69. InteractiveModePROXy
  70. 70. GrailsImproxShell Environment≪script≫improxClientTCP/IP≪script≫improxSmartInvoker≪class≫InteractiveMode≪class≫GrailsConsole≪command≫improx-start≪command≫improx-stop≪command≫improx-install-resourcesother clients≪class≫GrailsScriptRunnerechoback delegaterun scriptstartstopgrails commandexpand client scriptsuse
  71. 71. • As same as interactive mode• install-­‐plugin• uninstall-­‐plugin• Special built-in commands• create-­‐app• quit• stop-­‐app• exit• !(shell  command)• Using threads complexly• run-­‐appUnsupported Commands
  72. 72. How to Install
  73. 73. BuildConfig.groovy:plugins  {//...        compile  :improx:0.2//...}Install Plugin
  74. 74. Install Client Scripts$  grails  improx-­‐install-­‐resources|  Improx  resources  installed  successfully:  /xxx/improx-­‐resources$  chmod  +x  improx-­‐resources/scripts/*.sh$  mv  improx-­‐resources  $HOME/.improx-­‐resourcesIf
  75. 75.  once
  76. 76.  you
  77. 77.  store
  78. 78.  them
  79. 79.  to
  80. 80.  global
  81. 81.  path,
  82. 82.  
  83. 83.  you
  84. 84.  dont
  85. 85.  need
  86. 86.  the
  87. 87.  preparation
  88. 88.  for
  89. 89.  other
  90. 90.  projects.
  91. 91. How to Use
  92. 92. Grails Commands• improx-­‐start• improx-­‐stop• improx-­‐install-­‐resources
  93. 93. improx-­‐start  /  improx-­‐stop• improx-­‐start• Starts an interactive mode proxy server• improx-­‐stop• Stops the interactive mode proxy serverwhich is running
  94. 94. improx-­‐install-­‐resources• Installs “improx-resources” directory whichhas some client scripts into yourapplication projectimprox-­‐resources/  !  scripts            #  improxClient.groovy            #  improxClient.sh            #  improxSmartInvoker.groovy            !  improxSmartInvoker.sh
  95. 95. Client Scripts• improxClient.sh• improxClient.groovy• improxSmartInvoker.sh• improxSmartInvoker.groovy
  96. 96. improxClient.(sh|groovy)  Command• Runs a command in interactive mode viaTCP port of improx server• Very simple
  97. 97. $  improxClient.sh  helpExecuting  help  via  interactive  mode  proxy.........Usage  (optionals  marked  with  *):grails  [environment]*  [options]*  [target]  [arguments]*...(snipped)...test-­‐apptomcatuninstall-­‐pluginupgradewarwrapper$
  98. 98. improxSmartInvoker.(sh|groovy)  FILE_PATH• Invokes any *.groovy file in an appropriateway• Very useful for IDE/editor
  99. 99. How SMART is it?
  100. 100. grails  test-­‐app  unit:  sample.SampleUnitTests$  improxSmartInvoker.sh  /path/to/yourApp/test/unit/sample/SampleUnitTests.groovyRuns the following commandon the interactive mode:
  101. 101. grails  test-­‐app  integration:  sample.SampleIntegTests$  improxSmartInvoker.sh  /path/to/yourApp/test/integration/sample/SampleIntegTests.groovyRuns the following commandon the interactive mode:
  102. 102. $  improxSmartInvoker.sh  /path/to/yourApp/test/functional/sample/SampleFuncTests.groovygrails  test-­‐app  functional:  sample.SampleFuncTestsBecause
  103. 103.  functional
  104. 104.  test
  105. 105.  doesn’t
  106. 106.  work
  107. 107.  well
  108. 108.  on
  109. 109.  interactive
  110. 110.  mode
  111. 111.  at
  112. 112.  present.Runs the following commandas new standalone Grails process:
  113. 113. $  improxSmartInvoker.sh  /path/to/scriptDir/myTribialScript.groovygroovy  /path/to/scriptDir/myTribialScript.groovyIf
  114. 114.  youve
  115. 115.  installed
  116. 116.  GroovyServ,
  117. 117.  the
  118. 118.  groovyclient
  119. 119.  is
  120. 120.  automatically
  121. 121.  used
  122. 122.  instead
  123. 123.  of
  124. 124.  groovy
  125. 125.  command.Runs the following commandas a normal Groovy script:
  126. 126. All you have to do isto setimproxSmartInvokeras External Toolof IDE/editorhttp://kobo.github.io/grails-improx/guide/integrationWithEditors.html
  127. 127. SimpleProtocol
  128. 128. TCP• Request:COMMAND• Whole response is result of the command• You can also use as client• e.g. telnet, nc
  129. 129. $  telnet  localhost  8096Trying  ::1...Connected  to  localhost.Escape  character  is  ^].help......Usage  (optionals  marked  with  *):grails  [environment]*  [options]*  [target]  [arguments]*...(snipped)...uninstall-­‐pluginupgradewarwrapper$
  130. 130. HTTP• RequestGET  /COMMAND  HTTP/[0-­‐9.]+• Whole response is result of the command• You can also use as client• e.g. Web browser, wget, curl
  131. 131. • GroovyServ• http://kobo.github.io/groovyserv/index.html• https://github.com/kobo/groovyserv• Improx - Interactive Mode Proxy• http://kobo.github.io/grails-improx/guide/• http://grails.org/plugin/improx• https://github.com/kobo/grails-improx• Demo code• https://github.com/nobeans/gr8confeu2013-demo
  132. 132. Appendix
  133. 133. GroovyServUnder the hood
  134. 134. Under the hood• Client-Server Communication• Access Control• Propagation of CLASSPATH• Propagation of Environment Variables• Handling System#exit()• Dynamic CWD
  135. 135. Client-ServerCommunication
  136. 136. Transfer of StandardIn/Out/Err Stream
  137. 137. $  groovyclient  -­‐e  println  ‘Hello,  GroovyServ’
  138. 138. groovyclientClientConnectionOutputStream≪script≫println “Hello, GroovyServ!”≪System.out≫DynamicDelegatedPrintStreamwrites data convertedbased on a protocolinto output stream ofsocketHello, GroovyServ!if Channel header == ”err”To STDERRif Channel header == ”out”To STDOUTClient console
  139. 139. $  groovyclient  -­‐e  System.in.eachLine{  println  it*5  }
  140. 140. ClientConnectionPipedOutputStreamPipedInputStreamgroovyclient ≪thread≫StreamRequestHandler≪script≫System.in.eachLine { ... }ConnectedrawData = Socket.inputStream.read()bodyData = convert(rawData)pipedOutputStream.write(bodyData)≪System.in≫DynamicDelegatedInputStream
  141. 141. Protocol over TCP
  142. 142. InvocationRequestCwd: cwd LFArg: arg1 LFArg: arg2 LF:Env: env1=value1 LFEnv: env2=value2 LF:Cp: classpath LFAuthToken: authToken LFLFwhere:cwd is current working directory.arg1,arg2.. are commandline arguments which must be encoded by Base64. (optional)env1,env2.. are environment variable names which sent to the server. (optional)value1,valeu2.. are environment variable values which sent to the server. (optional)classpath is the value of environment variable CLASSPATH. (optional)authToken is authentication value which certify client is the user who invoked theserver.LF is line feed (0x0a, n).
  143. 143. StreamRequestSize: size LFLFbody from STDINwhere:size is the size of body to send to server. size==-1 meansclient exited.body from STDIN is byte sequence from standard input.
  144. 144. InvocationResponseStatus: status LFwhere:status is exit status of invoked groovy script.
  145. 145. StreamResponseChannel: id LFSize: size LFLFbody for STDERR/STDOUTwhere:id is out or err, where out means standard output of the program.err means standard error of the program.size is the size of chunk.body from STDERR/STDOUT is byte sequence from standard output/error.
  146. 146. Access Control
  147. 147. AgainstEvil RequestFrom Evil Client
  148. 148. Client Address Checking / Authtoken• Request only from loopback address isallowed.• Authtoken is generated and stored into afile when server process starts.• $HOME/.groovy/groovyserver/authtoken-­‐PORT• Authtoken always is used for checkingthat the request is from valid owner user.
  149. 149. -­‐-­‐allow-­‐from• By default, A request only from loop-backaddress is available.• You can allow specified addresses.$  groovyserver  -­‐-­‐allow-­‐from  192.168.1.1SECURITY RISK: Be careful when using this option
  150. 150. -­‐-­‐authtoken• By default, authtoken is generatedautomatically.• You can specify any string.SECURITY RISK: Be careful when using this option$  groovyserver  -­‐-­‐authtoken  MY_AUTHTOKEN
  151. 151. At your own risk
  152. 152. Propagation ofCLASSPATH
  153. 153. Client and Serverare DifferentProcess
  154. 154. ≪process≫groovyserver≪process≫groovyclientCLASSPATH=/my/classpath/xxx.jarCLASSPATH=/my/classpath/zzz.jarIndividual Env for each
  155. 155. If GroovyServ weretoo simple, ...
  156. 156. ≪process≫groovyserver≪process≫groovyclientCLASSPATH=/my/classpath/foo.jar
  157. 157. ≪process≫groovyserver≪process≫groovyclientPlease execute this!new foo.Foo().execute()CLASSPATH=/my/classpath/foo.jar
  158. 158. ≪process≫groovyserver≪process≫groovyclientCLASSPATH=/my/classpath/foo.jarI don’t know its class!Please execute this!new foo.Foo().execute()
  159. 159. ≪process≫groovyserver≪process≫groovyclientCLASSPATH=/my/classpath/foo.jarI don’t know its class!org.codehaus.groovy.control.MultipleCompilationErrorsException: startup failed:script_from_command_line: 1: unable to resolve class foo.Foo@ line 1, column 1.new foo.Foo().execute()^1 errorPlease execute this!new foo.Foo().execute()
  160. 160. But GroovyServ isenough smart
  161. 161. ≪process≫groovyserver≪process≫groovyclientPlease execute this!new foo.Foo().execute()CLASSPATH=/my/classpath/foo.jar
  162. 162. ≪process≫groovyserver≪process≫groovyclientCLASSPATH=/my/classpath/foo.jarPlease execute this!new foo.Foo().execute()CLASSPATH=/my/classpath/foo.jarnew foo.Foo().execute()
  163. 163. ≪process≫groovyserver≪process≫groovyclientCLASSPATH=/my/classpath/foo.jarYou got it!Please execute this!new foo.Foo().execute()CLASSPATH=/my/classpath/foo.jar
  164. 164. CLASSPATHwhich is propagatedfrom client isVolatile
  165. 165. ≪process≫groovyserver
  166. 166. ≪process≫groovyserver≪process≫groovyclientCLASSPATH=/my/classpath/foo.jarOKPlease execute this!new foo.Foo().execute()CLASSPATH=/my/classpath/foo.jar
  167. 167. ≪process≫groovyserverDone
  168. 168. ≪process≫groovyserver≪process≫groovyclientCLASSPATH=/my/classpath/bar.jarPlease execute this!new bar.Bar().execute()CLASSPATH=/my/classpath/bar.jarOK
  169. 169. ≪process≫groovyserverDone
  170. 170. How to specifyCLASSPATH fromClient
  171. 171. -classpath / -cp / --classpath$  groovyclient          -­‐cp  /my/classpath/foo.jar            -­‐e  “new  foo.Foo().execute()”
  172. 172. CLASSPATH env$  export  CLASSPATH=/my/classpath/foo.jar$  groovyclient  -­‐e  “new  foo.Foo().execute()”
  173. 173. Default CLASSPATHon Server
  174. 174. CLASSPATH env$  export  CLASSPATH=/my/classpath/foo.jar$  groovyserver
  175. 175. ≪process≫groovyserverI feel some power...CLASSPATH=/my/classpath/foo.jar
  176. 176. ≪process≫groovyserver≪process≫groovyclientCLASSPATH=/my/classpath/foo.jarPlease execute this!new foo.Foo().execute()CLASSPATH=/my/classpath/foo.jarI already know foo.jar!
  177. 177. ≪process≫groovyserverDoneCLASSPATH=/my/classpath/foo.jar
  178. 178. ≪process≫groovyserver≪process≫groovyclientCLASSPATH=/my/classpath/bar.jarPlease execute this!new bar.Bar().execute()CLASSPATH=/my/classpath/bar.jarOKCLASSPATH=/my/classpath/foo.jar
  179. 179. ≪process≫groovyserverDoneCLASSPATH=/my/classpath/foo.jar
  180. 180. Propagation ofEnvironmentVariables
  181. 181. Handywith IDE/editor
  182. 182. ≪process≫groovyserver≪process≫groovyclientCLASSPATH=/my/classpath/xxx.jarHow to propagate envKEY_A_1=VALUE_A_1KEY_A_2=VALUE_A_2KEY_B=VALUE_BKEY_A_1=VALUE_A_1KEY_B=VALUE_BKEY_A_2=VALUE_A_2
  183. 183. groovyclient options• -­‐Cenv  substr• Passes environment variables of which aname includes specified substr• -­‐Cenv-­‐all• pass all environment variables• -­‐Cenv-­‐exclude  substr• dont pass environment variables ofwhich a name includes specified substr
  184. 184. ≪process≫groovyserver≪process≫groovyclientCLASSPATH=/my/classpath/xxx.jar-­‐Cenv  _A_KEY_A_1=VALUE_A_1KEY_A_2=VALUE_A_2KEY_B=VALUE_BKEY_A_1=VALUE_A_1KEY_B=VALUE_BKEY_A_2=VALUE_A_2
  185. 185. ≪process≫groovyserver≪process≫groovyclientCLASSPATH=/my/classpath/xxx.jar-­‐Cenv-­‐allKEY_A_1=VALUE_A_1KEY_A_2=VALUE_A_2KEY_B=VALUE_BKEY_A_1=VALUE_A_1KEY_B=VALUE_BKEY_A_2=VALUE_A_2
  186. 186. ≪process≫groovyserver≪process≫groovyclientCLASSPATH=/my/classpath/xxx.jar-­‐Cenv-­‐all  -­‐Cenv-­‐exclude  _2KEY_A_1=VALUE_A_1KEY_A_2=VALUE_A_2KEY_B=VALUE_BKEY_A_1=VALUE_A_1KEY_B=VALUE_BKEY_A_2=VALUE_A_2
  187. 187. Caution:ENV on server isn’tcleared after eachinvocation
  188. 188. ≪process≫groovyserver≪process≫groovyclientCLASSPATH=/my/classpath/xxx.jar-­‐Cenv  KEY_A_1KEY_A_1=VALUE_A_1KEY_A_2=VALUE_A_2KEY_B=VALUE_BKEY_A_1=VALUE_A_1
  189. 189. ≪process≫groovyserver≪process≫groovyclientCLASSPATH=/my/classpath/xxx.jar-­‐Cenv  KEY_A_2KEY_A_1=VALUE_A_1KEY_A_2=VALUE_A_2KEY_B=VALUE_BKEY_A_1=VALUE_A_1KEY_A_2=VALUE_A_2
  190. 190. ≪process≫groovyserver≪process≫groovyclientCLASSPATH=/my/classpath/xxx.jar-­‐Cenv  KEY_BKEY_A_1=VALUE_A_1KEY_A_2=VALUE_A_2KEY_B=VALUE_BKEY_A_1=VALUE_A_1KEY_A_2=VALUE_A_2KEY_B=VALUE_B
  191. 191. HandlingSystem#exit()
  192. 192. Server processmust not be terminated,even if a scriptexecutes System.exit()
  193. 193. SecurityManagerpublic  class  NoExitSecurityManager2  extends  NoExitSecurityManager  {        public  void  checkExit(final  int  code)  {                throw  new  SystemExitException(code,                                            called  System.exit(  +  code  +  ));        }}
  194. 194. GroovyMainprivate  boolean  run()  {        try  {                //...                processArgs(...)                //...        }  catch  (SystemExitException  e)                throw  e;        }  catch  (Throwable  e)  {                //...        }}static  void  processArgs(...)  {        //...        if  (!process(cmd,  classpath))  {                //  Disabled  because  this  causes  a  secondary  disaster                //System.exit(1);        }        //...}
  195. 195. Dynamic CWD
  196. 196. CWD =Current WorkingDirectory
  197. 197. $ cd /tmp$ groovyserver -r$ cd /home/nobeans$ cat test.txtCan you read me?$ groovyclient -e ‘println(new File(“test.txt”).text)’Caught: java.io.FileNotFoundException: test.txt (No suchfile or directory)...SNIP...≪process≫groovyserverCWD=/tmpI wanna use “test.txt”of current directory.Is it “/tmp/test.txt” ?Hmm, such a file not found.
  198. 198. CWD of client should beset to serverfor each invocation.But, ...
  199. 199. In Java,CWD is thoroughlyhidden
  200. 200. Solution• Setting to “user.dir” system property• It affects File#getAbsolutePath()• Changing CWD of native JVM process• Many classes don’t use “user.dir” tocomplete an absolute path.• But, JNI is troublesome...
  201. 201. JNA is easy way to use native APIUnixLibC.groovy:interface  UnixLibC  extends  com.sun.jna.Library.Library  {        int  chdir(String  dir)        int  setenv(String  envVarName,  String  envVarValue,  int  overwrite)}pom.xml:        dependency            groupIdnet.java.dev.jna/groupId            artifactIdjna/artifactId            version3.2.2/version        /dependencyUsage:def  libc  =  com.sun.jna.Native.loadLibrary(c,  UnixLibC.class)libc.chdir(“/tmp/foo/bar”)
  202. 202. $ cd /tmp$ groovyserver -r$ cd /home/nobeans$ cat test.txtCan you read me?$ groovyclient -e ‘println(new File(“test.txt”).text)’Can you read me?≪process≫groovyserverCWD=/tmpI wanna use “test.txt”of current directory.≪process≫groovyserverCWD=/home/nobeansIs it “/home/nobeans/test.txt” ?OK, I got it.Yes!

×