Anda di halaman 1dari 9

12/6/2015

Chapter19.WritingyourownGuacamoleapplication

Chapter19.WritingyourownGuacamole
application
AsGuacamoleisanAPI,oneofthebestwaystoputGuacamoletouseisbybuildingyourownGuacamole
drivenwebapplication,integratingHTML5remotedesktopintowhateveryouthinkneedsit.
TheGuacamoleprojectprovidesanexampleofdoingthiscalled"guacamoleexample",butthisexampleis
alreadycompletedforyou,andfromaquickglanceatthisexample,itmaynotbeobviousjusthoweasyitis
to integrate remote access into a web application. This tutorial will walk you through the basic steps of
buildinganHTML5remotedesktopapplicationusingtheGuacamoleAPIandMaven.

Thebasics
Guacamole'sarchitectureismadeupofmanycomponents,butit'sactuallystraightforward,especiallyfrom
theperspectiveofthewebapplication.
Guacamole has a proxy daemon, guacd, which handles communication using remote desktop protocols,
exposingthosetowhateverconnectstoit(inthiscase,thewebapplication)usingtheGuacamoleprotocol.
From where the web application is standing, it doesn't really matter that guacd dynamically loads protocol
pluginsorthatitsharesacommonlibraryallowingthisallthatmattersisthatthewebapplicationjusthasto
connecttoport4822(whereguacdlistensbydefault)andusetheGuacamoleprotocol.Thearchitecturewill
takecareoftherest.
Thankfully, the Java side of the Guacamole API provides simple classes which already implement the
Guacamole protocol with the intent of tunneling it between guacd and the JavaScript half of your web
application.Atypicalwebapplicationleveragingtheseclassesneedsonlythefollowing:
1. AclasswhichextendsGuacamoleHTTPTunnelServlet,providing the tunnel between the JavaScript
client(presumablyusingguacamolecommonjs)andguacd.
GuacamoleHTTPTunnelServlet is an abstract class which is provided by the Guacamole API and
alreadyimplementsafullyfunctional,HTTPbasedtunnelwhichthetunnelingobjectsalreadypartof
guacamolecommonjs are written to connect to. This class exists to make it easy for you to use
Guacamole'sexistingandrobustHTTPtunnelimplementation.
Ifyouwanttonotusethisclassandinsteaduseyourowntunnelingmechanism,perhapsWebSocket,
thisisfinetheJavaScriptobjectmentionedaboveimplementsacommoninterfacewhichyoucanalso
implement, and the Guacamole JavaScript client which is also part of guacamolecommonjs will
happilyuseyourimplementationaslongasitprovidesthatinterface.
2. AwebpagewhichincludesJavaScriptfilesfromguacamolecommonjsandusestheclientandtunnel
objectstoconnectbacktothewebapplication.
The JavaScript API provided by the Guacamole project includes a full implementation of the
Guacamole protocol as a client, implementations of HTTP and WebSocketbased tunnels, and
mouse/keyboard/touch input abstraction. Again, as the Guacamole protocol and all parts of the
architecturearedocumentedhere,youdon'tabsolutelyneedtousetheseobjects,butitwillmakeyour
life easier. Mouse and keyboard support in JavaScript is finicky business, and the Guacamole client
providediswellknowntoworkwithothercomponentsintheAPI,beingtheofficialclientoftheproject.
That'sreallyallthereistoit.
If you want authentication, the place to implement that would be in your extended version of
GuacamoleHTTPTunnelServlet this is what the Guacamole web application does. Besides authentication,
therearemanyotherthingsyoucouldwraparoundyourremotedesktopapplication,butultimatelythebase
ofallthisissimple:youhaveatunnelwhichallowstheJavaScriptclienttocommunicatewithguacd,andyou
havetheJavaScriptclientitself,withthehardpartalreadyprovidedwithinguacamolecommonjs.
http://guacdev.org/doc/gug/writingyouownguacamoleapp.html

1/9

12/6/2015

Chapter19.WritingyourownGuacamoleapplication

Webapplicationskeleton
Aswithmosttutorials,thistutorialbeginswithcreatingaprojectskeletonthatestablishesaminimalbasefor
thetutorialtoenhanceinsubsequentsteps.
ThistutorialwilluseMaven,whichisthesamebuildsystemusedbytheupstreamGuacamoleproject.Asthe
Guacamole project has a Maven repository for both the Java and JavaScript APIs, writing a Guacamole
based application using Maven is much easier Maven will download and use the Guacamole API
automatically.

pom.xml
AllMavenprojectsmusthaveaprojectdescriptor,thepom.xmlfile,intherootdirectoryoftheproject.This
filedescribesprojectdependenciesandspecificbuildrequirements.UnlikeotherbuildtoolslikeApacheAnt
orGNUAutotools,Mavenchoosesconventionoverconfiguration: files within the project must be placed in
specificlocations,andtheprojectdependenciesmustbefullydescribedinthepom.xml.Ifthisisdone,the
buildwillbehandledautomatically.
ThebasisofthisGuacamoledrivenwebapplicationwillbeasimpleHTMLfilewhichwillultimatelybecome
theclient.WhilethefinishedproductwillhaveanHTTPtunnelwritteninJava,wedon'tneedthisyetforour
skeleton. We will create a very basic, barebones Maven project containing only index.html and a web
applicationdescriptorfile,web.xml.Oncethesefilesareinplace,theprojectcanbepackagedintoa.warfile
whichcanbedeployedtoyourservletcontainerofchoice(suchasApacheTomcat).
As this skeleton will contain no Java code, it has no dependencies, and no build requirements beyond the
metadatacommontoanyMavenproject.Thepom.xmlisthusverysimpleforthetimebeing:
<projectxmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchemainstance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/mavenv4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.glyptodon.guacamole</groupId>
<artifactId>guacamoletutorial</artifactId>
<packaging>war</packaging>
<version>0.9.7</version>
<name>guacamoletutorial</name>
<url>http://guacdev.org/</url>
<properties>
<project.build.sourceEncoding>UTF8</project.build.sourceEncoding>
</properties>
</project>

WEBINF/web.xml
Beforetheprojectwillbuild,thereneedstobeawebapplicationdeploymentdescriptor,web.xml.Thisfileis
requiredbytheJavaEEstandardforbuildingthe.warfilewhichwillcontainthewebapplication,andwillbe
read by the servlet container when the application is actually deployed. For Maven to find and use this file
whenbuildingthe.war,itmustbeplacedinthesrc/main/webapp/WEBINF/directory.
<?xmlversion="1.0"encoding="UTF8"?>
<webappversion="2.5"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchemainstance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://guacdev.org/doc/gug/writingyouownguacamoleapp.html

2/9

12/6/2015

Chapter19.WritingyourownGuacamoleapplication

http://java.sun.com/xml/ns/javaee/webapp_2_5.xsd">
<!Basicconfig>
<welcomefilelist>
<welcomefile>index.html</welcomefile>
</welcomefilelist>
</webapp>

index.html
With the web.xml file in place and the skeleton pom.xml written, the web application will now build
successfully. However, as the web.xml refers to a "welcome file" called index.html (which will ultimately
containourclient),weneedtoputthisinplacesotheservletcontainerwillhavesomethingtoserve.Fornow,
thiscanbeanythingwewillreplaceitlater:
<!DOCTYPEHTML>
<html>
<head>
<title>GuacamoleTutorial</title>
</head>
<body>
<p>HelloWorld</p>
</body>
</html>

Buildingtheskeleton
Onceallthreeoftheabovefilesareinplace,thewebapplicationwillbuild,andcanevenbedeployedtoyour
servlet container. It won't do anything yet other than serve the index.html file, but it's good to at least try
building the web application to make sure nothing is missing and all steps were followed correctly before
proceeding:
$mvnpackage
[INFO]Scanningforprojects...
[INFO]
[INFO]Buildingguacamoletutorial
[INFO]tasksegment:[package]
[INFO]
...
[INFO]
[INFO]BUILDSUCCESSFUL
[INFO]
[INFO]Totaltime:4seconds
[INFO]Finishedat:FriJan1113:04:11PST2013
[INFO]FinalMemory:18M/128M
[INFO]
$
Assuming you see the "BUILDSUCCESSFUL" message when you build the web application, there will be a
new file, target/guacamoletutorial0.7.0.war, which can be deployed to your servlet container and
http://guacdev.org/doc/gug/writingyouownguacamoleapp.html

3/9

12/6/2015

Chapter19.WritingyourownGuacamoleapplication

tested.Ifyouchangedthenameorversionoftheprojectinthepom.xmlfile,thenameofthisnew.warfile
willbedifferent,butitcanstillbefoundwithintarget/.

AddingGuacamole
Once we have a functional web application built, the next step is to actually add the references to the
GuacamoleAPIandintegrateaGuacamoleclientintotheapplication.

Updatingpom.xml
Nowthatwe'readdingGuacamolecomponentstoourproject,weneedtomodifypom.xmltospecifywhich
components are being used, and where they can be obtained. With this information in place, Maven will
automaticallyresolvedependenciesanddownloadthemasnecessaryduringthebuild.
Regardingthebuildprocessitself,therearetwomainchanges:wearenowgoingtobeusingJava,andwe
needtheJavaScriptfilesfromguacamolecommonjsincludedautomaticallyinsidethe.war.
GuacamolerequiresatleastJava1.6,thuswemustaddasectiontothepom.xmlwhichdescribesthesource
andtargetJavaversions:
...
<build>
<plugins>
<!CompileusingJava1.6>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>mavencompilerplugin</artifactId>
<configuration>
<source>1.6</source>
<target>1.6</target>
</configuration>
</plugin>
</plugins>
</build>
...
IncludingtheJavaScriptfilesfromanexternalprojectlikeguacamolecommonjsrequiresusingafeatureof
themavenwarplugincalledoverlays.Toaddanoverlaycontainingguacamolecommonjs,weaddasection
describingtheconfigurationoftheMavenwarplugin,listingguacamolecommonjsasanoverlay:
...
<build>
<plugins>
...
<!Overlayguacamolecommonjs(zip)>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>mavenwarplugin</artifactId>
<configuration>
<overlays>
<overlay>
http://guacdev.org/doc/gug/writingyouownguacamoleapp.html

4/9

12/6/2015

Chapter19.WritingyourownGuacamoleapplication

<groupId>org.glyptodon.guacamole</groupId>
<artifactId>guacamolecommonjs</artifactId>
<type>zip</type>
</overlay>
</overlays>
</configuration>
</plugin>
</plugins>
</build>
...
With the build now configured, we still need to add dependencies and list the repositories those
dependenciescanbedownloadedfrom.
As this is a web application which will use the Java Servlet API, we must explicitly include this as a
dependency,aswellastheGuacamoleJavaandJavaScriptAPIs:
...
<dependencies>
<!ServletAPI>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servletapi</artifactId>
<version>2.5</version>
<scope>provided</scope>
</dependency>
<!MainGuacamolelibrary>
<dependency>
<groupId>org.glyptodon.guacamole</groupId>
<artifactId>guacamolecommon</artifactId>
<version>0.9.7</version>
<scope>compile</scope>
</dependency>
<!GuacamoleJavaScriptlibrary>
<dependency>
<groupId>org.glyptodon.guacamole</groupId>
<artifactId>guacamolecommonjs</artifactId>
<version>0.9.7</version>
<type>zip</type>
<scope>runtime</scope>
</dependency>
</dependencies>
...
The Java Servlet API will be provided by your servlet container, so Maven does not need to download it
duringthebuild,anditneednotexistinanyMavenrepository.
With these changes, the web application will still build at this point, even though no Java code has been
writtenyet.Youmaywishtoverifythateverythingstillworks.
http://guacdev.org/doc/gug/writingyouownguacamoleapp.html

5/9

12/6/2015

Chapter19.WritingyourownGuacamoleapplication

Ifthepom.xmlwasupdatedproperlyasdescribedabove,thewebapplicationshouldbuildsuccessfully,and
theGuacamoleJavaScriptAPIshouldbeaccessibleintheguacamolecommonjs/subdirectoryofyourweb
application after it is deployed. A quick check that you can access /guacamoletutorial
0.8.0/guacamolecommonjs/guacamole.jsisprobablyworththeeffort.

Thesimplesttunnelpossible
Aswiththeothertutorialsinthisbook,wewillkeepthissimpleforthesakeofdemonstrating the principles
behind a Guacamolebased web application, and to give developers a good idea of where to start looking
whenit'stimetoconsulttheAPIdocumentation.
It is the duty of the class extending GuacamoleHTTPTunnelServlet to implement a function called
doConnect().Thisistheonlyfunctionrequiredtobeimplemented,andingeneralitistheonlyfunctionyou
shouldimplementtheotherfunctionsinvolvedarealreadyoptimizedfortunnelingtheGuacamoleprotocol.
ThedoConnect()functionreturnsaGuacamoleTunnel,whichprovidesapersistentcommunicationchannel
for GuacamoleHTTPTunnelServlet to use when talking with guacd and initiating a connection with some
arbitrary remote desktop using some arbitrary remote desktop protocol. In our simple tunnel, this
configuration will be hardcoded, and no authentication will be attempted. Any user accessing this web
applicationwillbeimmediatelygivenafunctionalremotedesktop,noquestionsasked.
Create a new file, TutorialGuacamoleTunnelServlet.java, defining a basic implementation of a tunnel
servletclass:
packageorg.glyptodon.guacamole.net.example;
importjavax.servlet.http.HttpServletRequest;
importjavax.servlet.http.HttpSession;
importorg.glyptodon.guacamole.GuacamoleException;
importorg.glyptodon.guacamole.net.GuacamoleSocket;
importorg.glyptodon.guacamole.net.GuacamoleTunnel;
importorg.glyptodon.guacamole.net.InetGuacamoleSocket;
importorg.glyptodon.guacamole.protocol.ConfiguredGuacamoleSocket;
importorg.glyptodon.guacamole.protocol.GuacamoleConfiguration;
importorg.glyptodon.guacamole.servlet.GuacamoleHTTPTunnelServlet;
importorg.glyptodon.guacamole.servlet.GuacamoleSession;
publicclassTutorialGuacamoleTunnelServlet
extendsGuacamoleHTTPTunnelServlet{
@Override
protectedGuacamoleTunneldoConnect(HttpServletRequestrequest)
throwsGuacamoleException{
//Createourconfiguration
GuacamoleConfigurationconfig=newGuacamoleConfiguration();
config.setProtocol("vnc");
config.setParameter("hostname","localhost");
config.setParameter("port","5901");
config.setParameter("password","potato");
//Connecttoguacdeverythingishardcodedhere.
GuacamoleSocketsocket=newConfiguredGuacamoleSocket(
newInetGuacamoleSocket("localhost",4822),
config
);
//Establishthetunnelusingtheconnectedsocket
GuacamoleTunneltunnel=newGuacamoleTunnel(socket);
//Attachtunneltosession
http://guacdev.org/doc/gug/writingyouownguacamoleapp.html

6/9

12/6/2015

Chapter19.WritingyourownGuacamoleapplication

HttpSessionhttpSession=request.getSession(true);
GuacamoleSessionsession=newGuacamoleSession(httpSession);
session.attachTunnel(tunnel);
//Returnpreattachedtunnel
returntunnel;
}
}
Place this file in the src/main/java/net/sourceforge/guacamole/net/example subdirectory of the
project.Theinitialpartofthissubdirectory,src/main/java,isthepathrequiredbyMaven,whiletherestis
thedirectoryrequiredbyJavabasedonthepackageassociatedwiththeclass.
Oncetheclassdefiningourtunneliscreated,itmustbeaddedtotheweb.xmlsuchthattheservletcontainer
knowswhichURLmapstoit.ThisURLwilllaterbegiventotheJavaScriptclienttoestablishtheconnection
backtotheGuacamoleserver:
...
<!GuacamoleTunnelServlet>
<servlet>
<description>Tunnelservlet.</description>
<servletname>Tunnel</servletname>
<servletclass>
org.glyptodon.guacamole.net.example.TutorialGuacamoleTunnelServlet
</servletclass>
</servlet>
<servletmapping>
<servletname>Tunnel</servletname>
<urlpattern>/tunnel</urlpattern>
</servletmapping>
...
Thefirstsectionassignsauniquename,"Tunnel",totheservletclasswejustdefined. The second section
mapstheservletclassbyit'sservletname("Tunnel")totheURLwewishtousewhenmakingHTTPrequests
totheservlet:/tunnel.ThisURLisrelativetothecontextrootofthewebapplication.Inthecaseofthisweb
application,thefinalabsoluteURLwillbe/guacamoletutorial0.8.0/tunnel.

Addingtheclient
AstheGuacamoleJavaScriptAPIalreadyprovidesfunctionalclientandtunnelimplementations,aswellas
mouse and keyboard input objects, the coding required for the "web" side of the web application is very
minimal.
WemustcreateaGuacamole.HTTPTunnel,connectittoourpreviouslyimplementedtunnelservlet,andpass
that tunnel to a new Guacamole.Client. Once that is done, and the connect() function of the client is
called,communicationwillimmediatelyensue,andyourremotedesktopwillbevisible:
...
<body>
<!Guacamole>
<scripttype="text/javascript"
src="guacamolecommonjs/all.min.js"></script>
http://guacdev.org/doc/gug/writingyouownguacamoleapp.html

7/9

12/6/2015

Chapter19.WritingyourownGuacamoleapplication

<!Display>
<divid="display"></div>
<!Init>
<scripttype="text/javascript">/*<![CDATA[*/
//Getdisplaydivfromdocument
vardisplay=document.getElementById("display");
//Instantiateclient,usinganHTTPtunnelforcommunications.
varguac=newGuacamole.Client(
newGuacamole.HTTPTunnel("tunnel")
);
//Addclienttodisplaydiv
display.appendChild(guac.getDisplay().getElement());

//Errorhandler
guac.onerror=function(error){
alert(error);
};
//Connect
guac.connect();
//Disconnectonclose
window.onunload=function(){
guac.disconnect();
}
/*]]>*/</script>
</body>
...
Ifyoubuildanddeploythewebapplicationnow,itwillwork,butmouseandkeyboardinputwillnot.Thisis
because input is not implemented by the client directly. The Guacamole.Client object only decodes the
Guacamoleprotocolandhandlesthedisplay,providinganelementwhichyoucanaddmanuallytotheDOM.
While it will also send keyboard and mouse events for you, you need to call the respective functions
manually.TheGuacamoleAPIprovideskeyboardandmouseabstractionobjectswhichmakethiseasy.
WeneedonlycreateaGuacamole.MouseandGuacamole.Keyboard,andaddeventhandlerstohandletheir
corresponding input events, calling whichever function of the Guacamole client is appropriate to send the
inputeventthroughthetunneltoguacd:

...
<!Init>
<scripttype="text/javascript">/*<![CDATA[*/
...
//Mouse
varmouse=newGuacamole.Mouse(guac.getDisplay().getElement());
mouse.onmousedown=
mouse.onmouseup=
mouse.onmousemove=function(mouseState){
http://guacdev.org/doc/gug/writingyouownguacamoleapp.html

8/9

12/6/2015

Chapter19.WritingyourownGuacamoleapplication

guac.sendMouseState(mouseState);
};
//Keyboard
varkeyboard=newGuacamole.Keyboard(document);
keyboard.onkeydown=function(keysym){
guac.sendKeyEvent(1,keysym);
};
keyboard.onkeyup=function(keysym){
guac.sendKeyEvent(0,keysym);
};
/*]]>*/</script>

Wheretogofromhere
Atthispoint,wenowhaveafullyfunctionalGuacamolebasedwebapplication.Thiswebapplicationinherits
allthecorefunctionalitypresentintheofficialGuacamolewebapplication,includingsoundandvideo,without
verymuchcoding.
Extendingthisapplicationtoprovideauthentication,multipleconnectionsperuser,oraspiffyinterfacewhich
iscompatiblewithmobileisnottoomuchofastretch.ThisisexactlyhowtheGuacamolewebapplicationis
written.IntegratingGuacamoleintoanexistingapplicationwouldbesimilar.

http://guacdev.org/doc/gug/writingyouownguacamoleapp.html

9/9