You are on page 1of 16

University of Victoria

Faculty of Engineering
Fall 2006 Work Term Report
Deploying a J2EE pplication Using Java We!"tart
Department of #$ysics an% stronomy
University of Victoria
Victoria& 'ritis$ (olum!ia
"ergey #opov
0)2)*00
Work Term +
(omputer "cience,-at$ematics
spopov.uvic/ca
Decem!er )0& 2006
1n partial fulfillment of t$e re2uirements of t$e
'ac$elor of "cience Degree
"upervisor3s pproval4 To !e complete% !y (o5op Employer
I approve the release of this report to the University of Victoria for evaluation purposes only.
The report is to be considered (select one): NOT CONFI!NTI"# CONFI!NTI"#

$i%nature: &osition: ' ate:


Na(e (print): !)*ail: Fa+ ,:

If a report is dee(ed CONFI!NTI"#- a non)disclosure for( si%ned by an evaluator .ill be fa+ed to the
e(ployer. The report .ill be destroyed follo.in% evaluation. If the report is NOT CONFI!NTI"#- it
.ill be returned to the student follo.in% evaluation.
Report Specification
Audience
This report is intended to be read by anyone ta/in% over (y position .ith the epart(ent
of &hysics and "strono(y- as .ell as anyone .ishin% to fa(iliari0e the(selves .ith
deploy(ent of 12!! applications usin% 1ava 3eb$tart.
Prerequisites
Fa(iliarity .ith 1ava Virtual *achine (1V*)- 12!! applications- 4*# and .eb services is
assu(ed on the part of the reader. $o(e sa(ple 1ava code and an 4*# 3eb$tart
descriptor file is included in this report.
Purpose
"fter readin% this paper- the reader .ill %ain insi%ht into deploy(ent of 12!! applications
over the .eb usin% 1ava 3eb$tart. Further(ore- detailed infor(ation on the inner
.or/in%s of the 1V*- especially .ith respect to the syste( class loader and security
(an%er co(ponents- is provided in this report.
Introduction
The follo.in% report describes a (a5or pro5ect underta/en by (e durin% (y 6 (onth Coop
place(ent .ith the epart(ent of &hysics and "strono(y at UVic- na(ely the deploy(ent
of an e+istin% 12!! application over the .eb usin% 1ava 3eb$tart technolo%y.
The application in 7uestion is called the 1ob $ub(ission Client- or 1$C for short- and is
used by users to sub(it 5obs to the co(putational %rid setup by UVic and National
8esearch Council (N8C). The application is .ritten entirely in 1ava .ith a $.in% 9UI and
consists of a handful of 1ar files in a .tar.gz archive. *y tas/ .as to deploy the application
over the .eb usin% the 9rid *onitor .ebsite on .hich I .as also .or/in%.
3hat follo.s is (y account of the process I e(ployed to achieve the stated ob5ectives-
ran%in% fro( 8e7uire(ent 9atherin% to the I(ple(entation sta%es. "dditionally- so(e
sa(ple code is provided to better illustrate the final product- althou%h its understandin% is
not re7uired due to the analysis provided in this report.
Requirements Gathering
The first sta%e of (y pro5ect involved %atherin% re7uire(ents for the final product. The
basic 7uestion that needed to be ans.ered .as :3hat e+actly do I need to build;< This
7uestion can only be ans.ered by first addressin% the re7uired functionality of the final
product. *y spec .as very si(ple and open)ended- na(ely deploy an e+istin% 12!!
application over the .eb.
The application in 7uestion re7uires a very specific environ(ent in order to run- includin%
the client (achine havin% both 1ava and 9T6 installed. 9lobus- or 9T6 for short- is the
%rid (iddle.are used by the UVic %rid and is itself a shorthand .ay to refer to the 9lobus
Tool/it version 6. 9T6 is the de facto standard for %rid (iddle.are and is used to handle
co((unication- security- data and user (ana%e(ent bet.een the different parts of the %rid.
Currently- 9lobus supports only the #inu+ platfor(. 3hile it is technically possible to use
1ava 3eb$tart or si(ilar technolo%y to deploy all of the supportin% applications as .ell- it
.as dee(ed to be too ris/y for both ti(e and resources available. Thus- I .as to continue
under the assu(ption that the supportin% applications .ould already be installed and
confi%ured on the client (achines.
#astly- there .as a sin%le functional re7uire(ent- na(ely that- %iven the environ(ent
specified above- the only thin% the user .ould need to do to deploy 1$C is to clic/ a lin/ on
a .eb pa%e and accept the security certificate. The do.nloadin%- installation and lin/in% of
the 1$C .ith the supportin% application .ould all be done auto(atically usin% 1ava
3eb$tart. 3eb$tart .ould also be used to launch the application once confi%ured and then
pass the control to 1$C itself.
9iven such usability and functionality %oals- it .as up to (e to (a/e it happen. I started
by loo/in% at the available technolo%ies and seein% if I could so(eho. piece the( to%ether
to achieve the desired result.
Technology Exploration
"fter finali0in% .hat it is that needed to be built- (y ne+t tas/ .as to find a .ay to build it.
This section .ill tal/ about the different concepts and technolo%ies that I considered and
eventually used to achieve said %oal.
The J2EE Application
First- I had to (a/e sure that it .ould be feasible to deploy the tar%et 12!! application
usin% 1ava 3eb$tart. #uc/ily for (e- the 1ob $ub(ission Client .as an in)house create
app in the later sta%es of the develop(ent cycle and- (ost i(portantly- I had access to the
lead developer. Thus it .as fairly easy to %et all of the re7uired environ(ent variables and
co((and line options that I .ould need in order to launch the application properly.
The bi%%est ris/ ite( .as the application=s need to have .rite access to the user=s
filesyste( in order to persist 5ob infor(ation. >o.ever- I could not find any infor(ation
about .hether or not this .as possible- other than a cryptic note about the security attribute
in the 3eb$tart descriptor file.
Webstart Descriptor File
1ava 3eb$tart is bundled .ith each distribution of the 18! and is auto(atically installed
on the client=s (achine .ith the 18!. >o.ever- before 3eb$tart can launch a re(ote
application- it needs to /no. so(e thin%s about the pro%ra(. This is .here the 3eb$tart
descriptor file is used.
The descriptor file specifies the location of the application 1ars on the re(ote (achine- the
(ini(al version of the 18! that has to be installed on the client (achine in order to run the
application- as .ell as the entry point or (ain class and any security re7uire(ents of the
app. This file is the only piece of infor(ation needed by 3eb$tart to auto(atically
do.nload the 1ars- confi%ure the environ(ent and launch the application in the default
console.
The 3eb$tart descriptor file that I constructed is provided in "ppendi+ I as jsc.jnlp.
Apache Support
In order to deploy usin% 3eb$tart- there is an additional confi%uration step that needs to be
done to the "pache server such that "pache .ill associate 3eb$tart descriptor files .ith
1ava 3eb$tart. It involves addin% one line to the "pache confi%uration file mime.types as
the follo.in%:
Self-Signed Jars
3eb$tart provides the ability to run potentially any code via the .eb and- in fact- .ill %o so
far as to launch the application in the default 1V*. Conse7uently- so(e security
(echanis( needs to be in place to prevent da(a%e to unscrupulous users= (achines by
havin% the( si(ply clic/ a 1ava 3eb$tart lin/. The current i(ple(entation of 3eb$tart
re7uires that all 5ar files specified in the 3eb$tart escriptor file be si%ned .ith the sa(e
security certificate that the client has to accept as valid before the pro%ra( can run.
Ideally- these certificates .ould co(e fro( a trusted and central authority li/e Veri$i%n or
9rid Canada? ho.ever- for develop(ent)only purposes I decided to use a self)si%ned
application@+)5ava)5nlp)file 5nlp
certificate that I created usin% 1ava=s pac/a%ed jarsigner application. $ince the use of the
jarsigner utility is outside the scope of this essay- the reader is encoura%ed to e+plore this
topic on their o.n.
Prototyping ith !elloWorld
ue to the lar%e nu(ber of ne. and poorly understood technolo%ies involved- I decided to
construct a prototype 3eb$tart application to test (y understandin% of the various
co(ponents and their interactions. "s a startin% point- I .ent to the 1ava tutorial section of
$un=s .ebsite and copy)pasted the 1ava $.in% Hello World tutorial code. I then co(piled
the code- created a HelloWorld.jar 1ar file- si%ned it usin% the above procedure- created a
ne. 3eb$tart descriptor file that .ould call the (ain (ethod in the ne. 1ar and copied
both of the( over to the develop(ent "pache environ(ent.
To verify that everythin% .or/s as I e+pected- I si(ply pointed (y bro.ser to the .jnlp file-
clic/ed [Accept] on the security .arnin% pro(pt and .atched Hello World in all its %lory.
The success of the prototype su%%ested that it is indeed possible to deploy a 12!! 9UI
application over the .eb. One of the fallouts fro( the prototypin% sta%e is (y discovery
that 3eb$tart uses its o.n classpath and 1V* options that are different fro( the
correspondin% client (achine variables. Thus- (y ne+t step .as to create a .rapper that
.ould initiali0e the 1ava environ(ent for the 1ob $ub(ission Client.
WebStart Wrapper
"fter the re7uire(ents %atherin% and prototypin% sta%es- it .as no. ti(e to start the actual
i(ple(entation. In this case- the WebstartWrapper class that .ill be called by 1ava
3eb$tart to setup the environ(ent and load the 9lobus 5ars before handin% the control over
to the 1$C. This .as an i(portant and re7uired step since deployin% .ith 3eb$tart is not
the sa(e thin% as launchin% the app fro( a shell script due to 3eb$tart=s use of its o.n
1ava classpath .ith its o.n 1V* options.
Ja"a En"iron#ent $ariables
Fro( the 8e7uire(ents 9atherin% phase- I /ne. that there .ere t.o environ(ent variables
needed by the 1$C and not included in the 1V* as launched by 3eb$tart. These .ere
GLOBU!LO"A#$O%- a shell variable that points to the root installation directory of 9T6-
and a&is."lient"onfig'ile- a .eb services definition file stored .ith a specific offset fro(
GLOBU!LO"A#$O%.
Initially- I tried usin% the ystem.geten()* call to read the GLOBU!LO"A#$O% shell
variable- but it .as inconsistently thro.in% security e+ceptions. To %et the shell variable- I
created a ne. subprocess that ran the en( shell co((and and parsed the output. The .eb
services definition file offset .as deter(ined to be constant for all installations of 9T6 and
can be si(ply concatenated to the GLOBU!LO"A#$O%.
Finally- I used the ystem.set+roperty)* call to add these t.o variables to the 1V*.
Ja"a %lasspath
The re7uire(ents %atherin% phase revealed that the 1$C needs to have access to the 9T6
libraries in order to function properly. >o.ever- since 9lobus can be installed in an
arbitrary location- it is not possible to use a 3eb$tart descriptor file to specify a static
location li/e one (i%ht do .ith a shell launch file. The classpath needed to be chan%ed at
runti(e.
Unfortunately- 1ava A.B does not provide a natural .ay to dyna(ically chan%e the library
path pro%ra(atically. Instead- the assu(ption is that you .ill use the ,cp co((and line
s.itch .hen startin% the 1V*. >ence- (y initial atte(pt at solvin% this proble( consisted
of creatin% a subprocess C in (uch the sa(e .ay as readin% shell variables C and launchin%
a ne. 1V* instance usin% the co((and line ar%u(ents to set the classpath to loo/ in the
9T6 install directory.
This did not turn out to be a %ood solution because of the .ay subprocesses are created in
1ava. 1ava subprocesses created .ith -.ntime.e&ec)* do not share the parent process=
console or ter(inal session. In fact- the child process creates a ne. instance of both
$np.ttream and O.tp.ttream ob5ects that are co(pletely separate fro( ystem.o.t and
ystem.in strea(s. !ffectively- this (eans that a substantial a(ount of strea( redirect code
.ould need to be .ritten in order to satisfy the user interaction co(ponent of the 1$C UI.
#uc/ily for (e- a 9oo%le search revealed the follo.in% pa%e:
http:@@foru(.5ava.sun.co(@thread.5spa;threadIDEFFBBG. In this postin%- a very clever
person has fi%ured out the .ay to access and (odify the syste( class loader to load a sin%le
e+ternal .5ar file usin% the 1ava 8eflections "&I. The bi% advanta%e of usin% the syste(
class loader (over creatin% a custo( and separate instance of the %eneric "lassLoader) is
that libraries loaded .ith the syste( loader can be accessed as if they .ere included in the
classpath co((and line ar%u(ent. In other .ords- the code provided is able to
dyna(ically load a sin%le 1ava 5ar file as if it has been specified in the ori%inal co((and
line ar%u(ent to start the 1V* .ithout the need to constantly reference "lassLoader
ob5ects for each library call. This approach provided a bi% advanta%e in that the 1$C code
could be left as is and a separate branch .ould not need to be (aintained for 3eb$tart
deploy(ents.
One last proble( re(ained- na(ely that 9T6 contains no fe.er than AFA separate 5ar files
and (ost- if not all- of the( are used by 1$C. Huildin% on the above code provided in the
1ava foru(s on $un=s .ebsite- I .as able to (a/e a trivial chan%e in scope to create a
"lass+at/Updater class that could load an arbitrary nu(ber of individual 1ar files usin% the
syste( class loader at runti(e.
Ja"a Security%onte&t'anager %lass
The last hoop that needed to be 5u(ped throu%h .as .ith respect to the 1V* per(issions
(ana%e(ent. 1ava 3eb$tart launched 1V*s use a default ec.rity"onte&t0anager class
to verify that the application has appropriate per(issions to access certain syste( resources.
This chec/ is in addition to security certificates and si%ned 5ar files- and is i(ple(ented by
artificially issuin% a ec.rity0anager.c/ec1+ermission)* call .ith the correspondin%
syste( resource and action re7uest before each syste( call. If the specified access to the
na(ed resource .as allo.ed- the (ethod .ould si(ply return. Other.ise it .ould thro. a
security e+ception and halt e+ecution.
"s sho.n earlier- in the 1ava !nviron(ent Variables section- for so(e un/no.n reason this
c/ec1+ermission)* call disallo.s access to syste( properties- includin% those properties
needed by 1$C and e+plicitly set in the earlier steps.
$ince ti(e pressure .as be%innin% to be (ore and (ore of a factor in decision (a/in%- I
decided to create a du((y class that .ould bypass the security chec/ by si(ply returnin%
on any input to the c/ec1+ermission)* (ethod. I then used the ystem.setec.rity0anager
)* call to over.rite the default security (ana%er.
Threat Analysis
" rou%h and ready threat analysis failed to reveal an attac/ vector to the potential security
hole opened by bypassin% the syste( security (ana%er since the e+ecutin% code still runs
.ithin the 1V* (e(ory sandbo+- thus (iti%atin% a%ainst any buffer overflo. attac/s.
Further(ore- local per(ission elevation attac/s .ill still need to circu(vent the 9lobus
"&I re7uire(ent for a valid %rid pro+y certificate in order to penetrate the 1$C on any ports
it (ay have opened.
Packaging
Once the .rapper .as built and tested- a pac/a%in% decision needed to be (ade .ith
respect to the location in the repository that .ill house the ne. code. The issue at hand is
that .hile there .ere separate locations for the 1$C and .eb portal code bases- the
WebstartWrapper code (ore of less spanned the %ap bet.een the(. #o%ically- the .rapper
.as part of the 1$C application in the sense that it added ne. functionality to the
application by allo.in% it to be .eb)deployable. On the other hand- the .rapper code .as
e+tra to the core 1$C code and specification and acted as a :%lue< to bind the 1$C and the
.eb portal.
In the end- the deploy(ent decisions dictated that the .rapper code be part of the 9rid
*onitor pro5ect and .as chec/ed into the portal repository.
eployment
eploy(ent decisions centered around the need for (aintainin% a :one clic/ build and
deploy< environ(ent in the 9rid *onitor pro5ect. $ince the scope of said policy is tan%ent
to the scope of this essay- I .ill only %o so far as to state that "nt and !clipse .ere used to
enable this functionality .hile the functionality itself proved to shorten both the
develop(ent and the release cycles.
Thus- the pro5ect build script needed to be (odified to allo. for the si(ultaneous build and
deploy(ent of the WebstartWrapper code .ith the rest of the 9rid *onitor .eb portal.
The build part re7uired not only the co(pilation of the various class files- but also the
creation and security certificate si%nin% of the WebstartWrapper 5ar file. 3hile the
deploy(ent section needed only a sin%le (odification to include the ne. .ebstart directory
that housed the 3eb$tart descriptor file and all of the si%ned 5ars needed by 3eb$tart. "n
additional anchor ta% .as added to the portal >T*# to lin/ the 3eb$tart descriptor file for
online deploy(ent of the 1ob $ub(ission Client.
Hecause the .rapper code .as tested and verified as .or/in% before it .as added to the
pro5ect build- no issues .ere e+perienced due to the above chan%es. Those developers that
did not need to .or/ .ith the ne. code .ere able to easily e+clude the 3eb$tart tar%et
fro( their build scripts.
Summary!"onclusion
In conclusion- deployin% a 12!! application over the .eb is very possible- but not trivial.
In (y e+perience- the co(ple+ity of the tar%et application has a lot to do .ith the
co(ple+ity of the deploy(ent. In the case of the 1ob $ub(ission Client- a nu(ber of
chan%es to the 1ava Virtual *achine had to be (ade at runti(e in order to properly
bootstrap the 1$C to the client=s environ(ent.
First- all of the application 5ars needed to be si%ned .ith a security certificate. $econd- the
1ava classpath needed to be chan%ed at runti(e in order to load needed syste( libraries
.hose location .as un/no.n until the pro%ra( actually ran. #astly- 1ava security (odel
needed to be altered to allo. the application access to the client=s filesyste( such that the
application could overco(e une+pected ter(ination and potential data loss by persistin% its
state to dis/.
"fter co(pletin% this pro5ect- I have ac7uired additional /no.led%e of the inner .or/in%s
of the 1ava Virtual *achine. $pecifically .ith respect to the class loader processes and the
syste( security (odel. I have also %ained first hand e+perience .ith deploy(ent of 12!!
applications over the .eb usin% 1ava 3eb$tart.
#ppendix I
This appendi+ contains so(e sa(ple code and confi%uration files that .ere used in this
pro5ect.
(sc)(nlp
I;+(l versionDJA.FJ encodin%DJutf)KJ;L
IM)) 1$C 3eb $tart eploy(ent Te(plate ))L
I5nlp specDJA.FNJ
codebaseDJhttp:@@u%devFE.phys.uvic.ca@$er%ey$andbo+@.ebstartJ
hrefDJ5sc.5nlpJL
Iinfor(ationL
ItitleL9rid4A 1ob $ub(ission ClientI@titleL
IvendorLphys.uvic.caI@vendorL
Iho(epa%e hrefDJhttp:@@....%rid.phys.uvic.ca@inde+.ht(lJ@L
IdescriptionL1ob $ub(ission ClientI@descriptionL
Idescription /indDJshortJL
$ub(it %rid 5obs via the .eb.
I@descriptionL
Iicon .idthDJAOFJ hei%htDJPOJ hrefDJ..@i(a%es@%rid)b%)color.5p%J@L
Iicon /indDJsplashJ hrefDJ..@i(a%es@banner'left.%ifJ@L
Ioffline)allo.ed@L
I@infor(ationL
IsecurityL
Iall)per(issions@L
I@securityL
IresourcesL
I52se hrefDJhttp:@@5ava.sun.co(@products@autodl@52seJ onclic/DJ5avascript:(ytrac/er(this.href)?J
versionDJA.BNJ @L
I5ar hrefDJ.ebstart.5arJ@L
I5ar hrefDJ1ob$ub(issionClient.5arJ@L
I5ar hrefDJco((ons)io)A.2.5arJ@L
I5ar hrefDJco((ons)lan%)2.2.5arJ@L
I5ar hrefDJ5hall.5arJ@L
I5ar hrefDJderby.5arJ@L
I5ar hrefDJderbytools.5arJ@L
I5ar hrefDJ5lf%r)A'F.5arJ@L
I5ar hrefDJ5sa(lib.5arJ@L
I@resourceL
Iapplication)desc (ain)classDJca.%rid+2..ebstart.3ebstart3rapperJL
I@application)descL
I@5nlpL
WebstartWrapper)(a"a
@QQ
Q 3ebstart3apper.5ava
Q Created Nov 2G- 2FFO
Q
Q This is a .rapper class used to launch the 1ob $ub(ission client usin%
Q 1ava .ebstart. It reads in all of the re7uired shell variables and passes
Q the( off to the 1V* before launchin% the (ain (ethod of the 1ob$ub(issionClient
Q class- because .ebstart does not appear to propo%ate shell variables.
QQ@
pac/a%e ca.%rid+2..ebstart?
i(port 5ava.io.Q?
i(port 5ava.util.Q?
i(port 5ava.net.Q?
public class 3ebstart3rapper R

public static void (ain($trin%ST ar%s) thro.s IO!+ceptionR
@@%et 9lobus infor(ation
$trin% %lobus>o(e D %et!nv(J9#OHU$'>O*!J)?
if(%lobus>o(e.e7uals(JJ))
%lobus>o(e D %et!nv(J9#OHU$'#OC"TIONJ)?
@@(un%e the classpath
load9lobus1ars(%lobus>o(e NJ@libJ)?
@@set 1$C specific properties
$yste(.set&roperty(J9#OHU$'#OC"TIONJ- %lobus>o(e)?
$yste(.set&roperty(Ja+is.ClientConfi%FileJ- %lobus>o(e NJ@client)confi%..sddJ)?
@@launch the (ain app
$trin%ST toss D ne. $trin%SAT?
tossSFT D J)%uiJ?
tryR
$yste(.set$ecurity*ana%er(ne. 3ebstart$ecurity*ana%er())?
ca.%rid+A.sp.1ob$ub(issionClient.1ob$ub(issionClient.(ain(toss)?
Ucatch(Thro.able t)R
$yste(.err.println(JUnable to run app because of: J Nt.to$trin%())?
t.print$tac/Trace($yste(.err)?
thro. ne. IO!+ception(JFatal !rrorM J Nt.to$trin%())?
U
U@@end (ethod
@@ .or/around for security violations bein% thro.n .hen accessin%
@@ $yste(.%etenv()
private static $trin% %et!nv($trin% na(e) thro.s IO!+ceptionR
&rocess p D null?
tryR
p D 8unti(e.%et8unti(e().e+ec(JenvJ)?
Ucatch (IO!+ception e)R
thro. ne. IO!+ception(J%et!nv returned .ith an error: J Ne.to$trin%())?
U
Huffered8eader br D ne. Huffered8eader(
ne. Input$trea(8eader( p.%etInput$trea(() )
)?
$trin% toss D br.read#ine()?
.hile( toss MD null )R
int id+ D toss.inde+Of(=D=)?
$trin% /ey D toss.substrin%(F- id+)?
@@$yste(.out.println(JCo(parin%: J N/ey NJ to J Nna(e)?
if( /ey.e7uals(na(e) )
return toss.substrin%(id+NA)?
toss D br.read#ine()?
U@@end .hile
return JJ?
U@@end (ethod
private static void load9lobus1ars($trin% lib&ath) thro.s IO!+ceptionR
File dir D ne. File(lib&ath)?
FileST allFiles D dir.listFiles()?
for(int iDF? iIallFiles.len%th? iNN)R
if( allFilesSiT.%etNa(e().ends3ith(J.5arJ))
Class&athUpdater.addFile(allFilesSiT)?
U@@end for
U@@end (ethod
U
%lassPath*pdater)(a"a
@@(ost of the code borro.ed fro(:
@@Jhttp:@@foru(.5ava.sun.co(@thread.5spa;threadIDEFFBBGJ
pac/a%e ca.%rid+2..ebstart?
i(port 5ava.io.Q?
i(port 5ava.net.Q?
i(port 5ava.lan%.reflect.Q?
public class Class&athUpdater R
public static void addFile($trin% s) thro.s IO!+ception R
File f D ne. File(s)?
addFile(f)?
U@@end (ethod
public static void addFile(File f) thro.s IO!+ception R
addU8#(f.toU8#())?
U@@end (ethod
public static void addU8#(U8# u) thro.s IO!+ception R
@@local scope so that .e can load (ultiple files at once
final ClassST para(eters D ne. ClassSTRU8#.classU?

U8#Class#oader sysloader D (U8#Class#oader)Class#oader.%et$yste(Class#oader()?
Class sysclass D U8#Class#oader.class?
try R
*ethod (ethod D sysclass.%eteclared*ethod(JaddU8#J-para(eters)?
(ethod.set"ccessible(true)?
(ethod.invo/e(sysloader-ne. Ob5ectSTR u U)?
U catch (Thro.able t) R
t.print$tac/Trace()?
thro. ne. IO!+ception(J!rror- could not add U8# to syste( classloaderJ)?
U@@end try catch
U@@end (ethod
U@@end class

You might also like