blob: f5d5ea813af8650d5212222f64e10ba2de12a537 [file] [log] [blame]
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<!--[if IE]><meta http-equiv="X-UA-Compatible" content="IE=edge"><![endif]-->
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="generator" content="Asciidoctor 1.5.3">
<title>Case Study: Migrating the Form Tags Sample Application</title>
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Open+Sans:300,300italic,400,400italic,600,600italic%7CNoto+Serif:400,400italic,700,700italic%7CDroid+Sans+Mono:400,700">
<style>
/* Asciidoctor default stylesheet | MIT License | http://asciidoctor.org */
/* Remove comment around @import statement below when using as a custom stylesheet */
/*@import "https://fonts.googleapis.com/css?family=Open+Sans:300,300italic,400,400italic,600,600italic%7CNoto+Serif:400,400italic,700,700italic%7CDroid+Sans+Mono:400,700";*/
article,aside,details,figcaption,figure,footer,header,hgroup,main,nav,section,summary{display:block}
audio,canvas,video{display:inline-block}
audio:not([controls]){display:none;height:0}
[hidden],template{display:none}
script{display:none!important}
html{font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}
body{margin:0}
a{background:transparent}
a:focus{outline:thin dotted}
a:active,a:hover{outline:0}
h1{font-size:2em;margin:.67em 0}
abbr[title]{border-bottom:1px dotted}
b,strong{font-weight:bold}
dfn{font-style:italic}
hr{-moz-box-sizing:content-box;box-sizing:content-box;height:0}
mark{background:#ff0;color:#000}
code,kbd,pre,samp{font-family:monospace;font-size:1em}
pre{white-space:pre-wrap}
q{quotes:"\201C" "\201D" "\2018" "\2019"}
small{font-size:80%}
sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}
sup{top:-.5em}
sub{bottom:-.25em}
img{border:0}
svg:not(:root){overflow:hidden}
figure{margin:0}
fieldset{border:1px solid silver;margin:0 2px;padding:.35em .625em .75em}
legend{border:0;padding:0}
button,input,select,textarea{font-family:inherit;font-size:100%;margin:0}
button,input{line-height:normal}
button,select{text-transform:none}
button,html input[type="button"],input[type="reset"],input[type="submit"]{-webkit-appearance:button;cursor:pointer}
button[disabled],html input[disabled]{cursor:default}
input[type="checkbox"],input[type="radio"]{box-sizing:border-box;padding:0}
input[type="search"]{-webkit-appearance:textfield;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box}
input[type="search"]::-webkit-search-cancel-button,input[type="search"]::-webkit-search-decoration{-webkit-appearance:none}
button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}
textarea{overflow:auto;vertical-align:top}
table{border-collapse:collapse;border-spacing:0}
*,*:before,*:after{-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box}
html,body{font-size:100%}
body{background:#fff;color:rgba(0,0,0,.8);padding:0;margin:0;font-family:"Noto Serif","DejaVu Serif",serif;font-weight:400;font-style:normal;line-height:1;position:relative;cursor:auto}
a:hover{cursor:pointer}
img,object,embed{max-width:100%;height:auto}
object,embed{height:100%}
img{-ms-interpolation-mode:bicubic}
.left{float:left!important}
.right{float:right!important}
.text-left{text-align:left!important}
.text-right{text-align:right!important}
.text-center{text-align:center!important}
.text-justify{text-align:justify!important}
.hide{display:none}
body{-webkit-font-smoothing:antialiased}
img,object,svg{display:inline-block;vertical-align:middle}
textarea{height:auto;min-height:50px}
select{width:100%}
.center{margin-left:auto;margin-right:auto}
.spread{width:100%}
p.lead,.paragraph.lead>p,#preamble>.sectionbody>.paragraph:first-of-type p{font-size:1.21875em;line-height:1.6}
.subheader,.admonitionblock td.content>.title,.audioblock>.title,.exampleblock>.title,.imageblock>.title,.listingblock>.title,.literalblock>.title,.stemblock>.title,.openblock>.title,.paragraph>.title,.quoteblock>.title,table.tableblock>.title,.verseblock>.title,.videoblock>.title,.dlist>.title,.olist>.title,.ulist>.title,.qlist>.title,.hdlist>.title{line-height:1.45;color:#7a2518;font-weight:400;margin-top:0;margin-bottom:.25em}
div,dl,dt,dd,ul,ol,li,h1,h2,h3,#toctitle,.sidebarblock>.content>.title,h4,h5,h6,pre,form,p,blockquote,th,td{margin:0;padding:0;direction:ltr}
a{color:#2156a5;text-decoration:underline;line-height:inherit}
a:hover,a:focus{color:#1d4b8f}
a img{border:none}
p{font-family:inherit;font-weight:400;font-size:1em;line-height:1.6;margin-bottom:1.25em;text-rendering:optimizeLegibility}
p aside{font-size:.875em;line-height:1.35;font-style:italic}
h1,h2,h3,#toctitle,.sidebarblock>.content>.title,h4,h5,h6{font-family:"Open Sans","DejaVu Sans",sans-serif;font-weight:300;font-style:normal;color:#ba3925;text-rendering:optimizeLegibility;margin-top:1em;margin-bottom:.5em;line-height:1.0125em}
h1 small,h2 small,h3 small,#toctitle small,.sidebarblock>.content>.title small,h4 small,h5 small,h6 small{font-size:60%;color:#e99b8f;line-height:0}
h1{font-size:2.125em}
h2{font-size:1.6875em}
h3,#toctitle,.sidebarblock>.content>.title{font-size:1.375em}
h4,h5{font-size:1.125em}
h6{font-size:1em}
hr{border:solid #ddddd8;border-width:1px 0 0;clear:both;margin:1.25em 0 1.1875em;height:0}
em,i{font-style:italic;line-height:inherit}
strong,b{font-weight:bold;line-height:inherit}
small{font-size:60%;line-height:inherit}
code{font-family:"Droid Sans Mono","DejaVu Sans Mono",monospace;font-weight:400;color:rgba(0,0,0,.9)}
ul,ol,dl{font-size:1em;line-height:1.6;margin-bottom:1.25em;list-style-position:outside;font-family:inherit}
ul,ol,ul.no-bullet,ol.no-bullet{margin-left:1.5em}
ul li ul,ul li ol{margin-left:1.25em;margin-bottom:0;font-size:1em}
ul.square li ul,ul.circle li ul,ul.disc li ul{list-style:inherit}
ul.square{list-style-type:square}
ul.circle{list-style-type:circle}
ul.disc{list-style-type:disc}
ul.no-bullet{list-style:none}
ol li ul,ol li ol{margin-left:1.25em;margin-bottom:0}
dl dt{margin-bottom:.3125em;font-weight:bold}
dl dd{margin-bottom:1.25em}
abbr,acronym{text-transform:uppercase;font-size:90%;color:rgba(0,0,0,.8);border-bottom:1px dotted #ddd;cursor:help}
abbr{text-transform:none}
blockquote{margin:0 0 1.25em;padding:.5625em 1.25em 0 1.1875em;border-left:1px solid #ddd}
blockquote cite{display:block;font-size:.9375em;color:rgba(0,0,0,.6)}
blockquote cite:before{content:"\2014 \0020"}
blockquote cite a,blockquote cite a:visited{color:rgba(0,0,0,.6)}
blockquote,blockquote p{line-height:1.6;color:rgba(0,0,0,.85)}
@media only screen and (min-width:768px){h1,h2,h3,#toctitle,.sidebarblock>.content>.title,h4,h5,h6{line-height:1.2}
h1{font-size:2.75em}
h2{font-size:2.3125em}
h3,#toctitle,.sidebarblock>.content>.title{font-size:1.6875em}
h4{font-size:1.4375em}}
table{background:#fff;margin-bottom:1.25em;border:solid 1px #dedede}
table thead,table tfoot{background:#f7f8f7;font-weight:bold}
table thead tr th,table thead tr td,table tfoot tr th,table tfoot tr td{padding:.5em .625em .625em;font-size:inherit;color:rgba(0,0,0,.8);text-align:left}
table tr th,table tr td{padding:.5625em .625em;font-size:inherit;color:rgba(0,0,0,.8)}
table tr.even,table tr.alt,table tr:nth-of-type(even){background:#f8f8f7}
table thead tr th,table tfoot tr th,table tbody tr td,table tr td,table tfoot tr td{display:table-cell;line-height:1.6}
body{tab-size:4}
h1,h2,h3,#toctitle,.sidebarblock>.content>.title,h4,h5,h6{line-height:1.2;word-spacing:-.05em}
h1 strong,h2 strong,h3 strong,#toctitle strong,.sidebarblock>.content>.title strong,h4 strong,h5 strong,h6 strong{font-weight:400}
.clearfix:before,.clearfix:after,.float-group:before,.float-group:after{content:" ";display:table}
.clearfix:after,.float-group:after{clear:both}
*:not(pre)>code{font-size:.9375em;font-style:normal!important;letter-spacing:0;padding:.1em .5ex;word-spacing:-.15em;background-color:#f7f7f8;-webkit-border-radius:4px;border-radius:4px;line-height:1.45;text-rendering:optimizeSpeed}
pre,pre>code{line-height:1.45;color:rgba(0,0,0,.9);font-family:"Droid Sans Mono","DejaVu Sans Mono",monospace;font-weight:400;text-rendering:optimizeSpeed}
.keyseq{color:rgba(51,51,51,.8)}
kbd{font-family:"Droid Sans Mono","DejaVu Sans Mono",monospace;display:inline-block;color:rgba(0,0,0,.8);font-size:.65em;line-height:1.45;background-color:#f7f7f7;border:1px solid #ccc;-webkit-border-radius:3px;border-radius:3px;-webkit-box-shadow:0 1px 0 rgba(0,0,0,.2),0 0 0 .1em white inset;box-shadow:0 1px 0 rgba(0,0,0,.2),0 0 0 .1em #fff inset;margin:0 .15em;padding:.2em .5em;vertical-align:middle;position:relative;top:-.1em;white-space:nowrap}
.keyseq kbd:first-child{margin-left:0}
.keyseq kbd:last-child{margin-right:0}
.menuseq,.menu{color:rgba(0,0,0,.8)}
b.button:before,b.button:after{position:relative;top:-1px;font-weight:400}
b.button:before{content:"[";padding:0 3px 0 2px}
b.button:after{content:"]";padding:0 2px 0 3px}
p a>code:hover{color:rgba(0,0,0,.9)}
#header,#content,#footnotes,#footer{width:100%;margin-left:auto;margin-right:auto;margin-top:0;margin-bottom:0;max-width:62.5em;*zoom:1;position:relative;padding-left:.9375em;padding-right:.9375em}
#header:before,#header:after,#content:before,#content:after,#footnotes:before,#footnotes:after,#footer:before,#footer:after{content:" ";display:table}
#header:after,#content:after,#footnotes:after,#footer:after{clear:both}
#content{margin-top:1.25em}
#content:before{content:none}
#header>h1:first-child{color:rgba(0,0,0,.85);margin-top:2.25rem;margin-bottom:0}
#header>h1:first-child+#toc{margin-top:8px;border-top:1px solid #ddddd8}
#header>h1:only-child,body.toc2 #header>h1:nth-last-child(2){border-bottom:1px solid #ddddd8;padding-bottom:8px}
#header .details{border-bottom:1px solid #ddddd8;line-height:1.45;padding-top:.25em;padding-bottom:.25em;padding-left:.25em;color:rgba(0,0,0,.6);display:-ms-flexbox;display:-webkit-flex;display:flex;-ms-flex-flow:row wrap;-webkit-flex-flow:row wrap;flex-flow:row wrap}
#header .details span:first-child{margin-left:-.125em}
#header .details span.email a{color:rgba(0,0,0,.85)}
#header .details br{display:none}
#header .details br+span:before{content:"\00a0\2013\00a0"}
#header .details br+span.author:before{content:"\00a0\22c5\00a0";color:rgba(0,0,0,.85)}
#header .details br+span#revremark:before{content:"\00a0|\00a0"}
#header #revnumber{text-transform:capitalize}
#header #revnumber:after{content:"\00a0"}
#content>h1:first-child:not([class]){color:rgba(0,0,0,.85);border-bottom:1px solid #ddddd8;padding-bottom:8px;margin-top:0;padding-top:1rem;margin-bottom:1.25rem}
#toc{border-bottom:1px solid #efefed;padding-bottom:.5em}
#toc>ul{margin-left:.125em}
#toc ul.sectlevel0>li>a{font-style:italic}
#toc ul.sectlevel0 ul.sectlevel1{margin:.5em 0}
#toc ul{font-family:"Open Sans","DejaVu Sans",sans-serif;list-style-type:none}
#toc li{line-height:1.3334;margin-top:.3334em}
#toc a{text-decoration:none}
#toc a:active{text-decoration:underline}
#toctitle{color:#7a2518;font-size:1.2em}
@media only screen and (min-width:768px){#toctitle{font-size:1.375em}
body.toc2{padding-left:15em;padding-right:0}
#toc.toc2{margin-top:0!important;background-color:#f8f8f7;position:fixed;width:15em;left:0;top:0;border-right:1px solid #efefed;border-top-width:0!important;border-bottom-width:0!important;z-index:1000;padding:1.25em 1em;height:100%;overflow:auto}
#toc.toc2 #toctitle{margin-top:0;margin-bottom:.8rem;font-size:1.2em}
#toc.toc2>ul{font-size:.9em;margin-bottom:0}
#toc.toc2 ul ul{margin-left:0;padding-left:1em}
#toc.toc2 ul.sectlevel0 ul.sectlevel1{padding-left:0;margin-top:.5em;margin-bottom:.5em}
body.toc2.toc-right{padding-left:0;padding-right:15em}
body.toc2.toc-right #toc.toc2{border-right-width:0;border-left:1px solid #efefed;left:auto;right:0}}
@media only screen and (min-width:1280px){body.toc2{padding-left:20em;padding-right:0}
#toc.toc2{width:20em}
#toc.toc2 #toctitle{font-size:1.375em}
#toc.toc2>ul{font-size:.95em}
#toc.toc2 ul ul{padding-left:1.25em}
body.toc2.toc-right{padding-left:0;padding-right:20em}}
#content #toc{border-style:solid;border-width:1px;border-color:#e0e0dc;margin-bottom:1.25em;padding:1.25em;background:#f8f8f7;-webkit-border-radius:4px;border-radius:4px}
#content #toc>:first-child{margin-top:0}
#content #toc>:last-child{margin-bottom:0}
#footer{max-width:100%;background-color:rgba(0,0,0,.8);padding:1.25em}
#footer-text{color:rgba(255,255,255,.8);line-height:1.44}
.sect1{padding-bottom:.625em}
@media only screen and (min-width:768px){.sect1{padding-bottom:1.25em}}
.sect1+.sect1{border-top:1px solid #efefed}
#content h1>a.anchor,h2>a.anchor,h3>a.anchor,#toctitle>a.anchor,.sidebarblock>.content>.title>a.anchor,h4>a.anchor,h5>a.anchor,h6>a.anchor{position:absolute;z-index:1001;width:1.5ex;margin-left:-1.5ex;display:block;text-decoration:none!important;visibility:hidden;text-align:center;font-weight:400}
#content h1>a.anchor:before,h2>a.anchor:before,h3>a.anchor:before,#toctitle>a.anchor:before,.sidebarblock>.content>.title>a.anchor:before,h4>a.anchor:before,h5>a.anchor:before,h6>a.anchor:before{content:"\00A7";font-size:.85em;display:block;padding-top:.1em}
#content h1:hover>a.anchor,#content h1>a.anchor:hover,h2:hover>a.anchor,h2>a.anchor:hover,h3:hover>a.anchor,#toctitle:hover>a.anchor,.sidebarblock>.content>.title:hover>a.anchor,h3>a.anchor:hover,#toctitle>a.anchor:hover,.sidebarblock>.content>.title>a.anchor:hover,h4:hover>a.anchor,h4>a.anchor:hover,h5:hover>a.anchor,h5>a.anchor:hover,h6:hover>a.anchor,h6>a.anchor:hover{visibility:visible}
#content h1>a.link,h2>a.link,h3>a.link,#toctitle>a.link,.sidebarblock>.content>.title>a.link,h4>a.link,h5>a.link,h6>a.link{color:#ba3925;text-decoration:none}
#content h1>a.link:hover,h2>a.link:hover,h3>a.link:hover,#toctitle>a.link:hover,.sidebarblock>.content>.title>a.link:hover,h4>a.link:hover,h5>a.link:hover,h6>a.link:hover{color:#a53221}
.audioblock,.imageblock,.literalblock,.listingblock,.stemblock,.videoblock{margin-bottom:1.25em}
.admonitionblock td.content>.title,.audioblock>.title,.exampleblock>.title,.imageblock>.title,.listingblock>.title,.literalblock>.title,.stemblock>.title,.openblock>.title,.paragraph>.title,.quoteblock>.title,table.tableblock>.title,.verseblock>.title,.videoblock>.title,.dlist>.title,.olist>.title,.ulist>.title,.qlist>.title,.hdlist>.title{text-rendering:optimizeLegibility;text-align:left;font-family:"Noto Serif","DejaVu Serif",serif;font-size:1rem;font-style:italic}
table.tableblock>caption.title{white-space:nowrap;overflow:visible;max-width:0}
.paragraph.lead>p,#preamble>.sectionbody>.paragraph:first-of-type p{color:rgba(0,0,0,.85)}
table.tableblock #preamble>.sectionbody>.paragraph:first-of-type p{font-size:inherit}
.admonitionblock>table{border-collapse:separate;border:0;background:none;width:100%}
.admonitionblock>table td.icon{text-align:center;width:80px}
.admonitionblock>table td.icon img{max-width:none}
.admonitionblock>table td.icon .title{font-weight:bold;font-family:"Open Sans","DejaVu Sans",sans-serif;text-transform:uppercase}
.admonitionblock>table td.content{padding-left:1.125em;padding-right:1.25em;border-left:1px solid #ddddd8;color:rgba(0,0,0,.6)}
.admonitionblock>table td.content>:last-child>:last-child{margin-bottom:0}
.exampleblock>.content{border-style:solid;border-width:1px;border-color:#e6e6e6;margin-bottom:1.25em;padding:1.25em;background:#fff;-webkit-border-radius:4px;border-radius:4px}
.exampleblock>.content>:first-child{margin-top:0}
.exampleblock>.content>:last-child{margin-bottom:0}
.sidebarblock{border-style:solid;border-width:1px;border-color:#e0e0dc;margin-bottom:1.25em;padding:1.25em;background:#f8f8f7;-webkit-border-radius:4px;border-radius:4px}
.sidebarblock>:first-child{margin-top:0}
.sidebarblock>:last-child{margin-bottom:0}
.sidebarblock>.content>.title{color:#7a2518;margin-top:0;text-align:center}
.exampleblock>.content>:last-child>:last-child,.exampleblock>.content .olist>ol>li:last-child>:last-child,.exampleblock>.content .ulist>ul>li:last-child>:last-child,.exampleblock>.content .qlist>ol>li:last-child>:last-child,.sidebarblock>.content>:last-child>:last-child,.sidebarblock>.content .olist>ol>li:last-child>:last-child,.sidebarblock>.content .ulist>ul>li:last-child>:last-child,.sidebarblock>.content .qlist>ol>li:last-child>:last-child{margin-bottom:0}
.literalblock pre,.listingblock pre:not(.highlight),.listingblock pre[class="highlight"],.listingblock pre[class^="highlight "],.listingblock pre.CodeRay,.listingblock pre.prettyprint{background:#f7f7f8}
.sidebarblock .literalblock pre,.sidebarblock .listingblock pre:not(.highlight),.sidebarblock .listingblock pre[class="highlight"],.sidebarblock .listingblock pre[class^="highlight "],.sidebarblock .listingblock pre.CodeRay,.sidebarblock .listingblock pre.prettyprint{background:#f2f1f1}
.literalblock pre,.literalblock pre[class],.listingblock pre,.listingblock pre[class]{-webkit-border-radius:4px;border-radius:4px;word-wrap:break-word;padding:1em;font-size:.8125em}
.literalblock pre.nowrap,.literalblock pre[class].nowrap,.listingblock pre.nowrap,.listingblock pre[class].nowrap{overflow-x:auto;white-space:pre;word-wrap:normal}
@media only screen and (min-width:768px){.literalblock pre,.literalblock pre[class],.listingblock pre,.listingblock pre[class]{font-size:.90625em}}
@media only screen and (min-width:1280px){.literalblock pre,.literalblock pre[class],.listingblock pre,.listingblock pre[class]{font-size:1em}}
.literalblock.output pre{color:#f7f7f8;background-color:rgba(0,0,0,.9)}
.listingblock pre.highlightjs{padding:0}
.listingblock pre.highlightjs>code{padding:1em;-webkit-border-radius:4px;border-radius:4px}
.listingblock pre.prettyprint{border-width:0}
.listingblock>.content{position:relative}
.listingblock code[data-lang]:before{display:none;content:attr(data-lang);position:absolute;font-size:.75em;top:.425rem;right:.5rem;line-height:1;text-transform:uppercase;color:#999}
.listingblock:hover code[data-lang]:before{display:block}
.listingblock.terminal pre .command:before{content:attr(data-prompt);padding-right:.5em;color:#999}
.listingblock.terminal pre .command:not([data-prompt]):before{content:"$"}
table.pyhltable{border-collapse:separate;border:0;margin-bottom:0;background:none}
table.pyhltable td{vertical-align:top;padding-top:0;padding-bottom:0;line-height:1.45}
table.pyhltable td.code{padding-left:.75em;padding-right:0}
pre.pygments .lineno,table.pyhltable td:not(.code){color:#999;padding-left:0;padding-right:.5em;border-right:1px solid #ddddd8}
pre.pygments .lineno{display:inline-block;margin-right:.25em}
table.pyhltable .linenodiv{background:none!important;padding-right:0!important}
.quoteblock{margin:0 1em 1.25em 1.5em;display:table}
.quoteblock>.title{margin-left:-1.5em;margin-bottom:.75em}
.quoteblock blockquote,.quoteblock blockquote p{color:rgba(0,0,0,.85);font-size:1.15rem;line-height:1.75;word-spacing:.1em;letter-spacing:0;font-style:italic;text-align:justify}
.quoteblock blockquote{margin:0;padding:0;border:0}
.quoteblock blockquote:before{content:"\201c";float:left;font-size:2.75em;font-weight:bold;line-height:.6em;margin-left:-.6em;color:#7a2518;text-shadow:0 1px 2px rgba(0,0,0,.1)}
.quoteblock blockquote>.paragraph:last-child p{margin-bottom:0}
.quoteblock .attribution{margin-top:.5em;margin-right:.5ex;text-align:right}
.quoteblock .quoteblock{margin-left:0;margin-right:0;padding:.5em 0;border-left:3px solid rgba(0,0,0,.6)}
.quoteblock .quoteblock blockquote{padding:0 0 0 .75em}
.quoteblock .quoteblock blockquote:before{display:none}
.verseblock{margin:0 1em 1.25em 1em}
.verseblock pre{font-family:"Open Sans","DejaVu Sans",sans;font-size:1.15rem;color:rgba(0,0,0,.85);font-weight:300;text-rendering:optimizeLegibility}
.verseblock pre strong{font-weight:400}
.verseblock .attribution{margin-top:1.25rem;margin-left:.5ex}
.quoteblock .attribution,.verseblock .attribution{font-size:.9375em;line-height:1.45;font-style:italic}
.quoteblock .attribution br,.verseblock .attribution br{display:none}
.quoteblock .attribution cite,.verseblock .attribution cite{display:block;letter-spacing:-.025em;color:rgba(0,0,0,.6)}
.quoteblock.abstract{margin:0 0 1.25em 0;display:block}
.quoteblock.abstract blockquote,.quoteblock.abstract blockquote p{text-align:left;word-spacing:0}
.quoteblock.abstract blockquote:before,.quoteblock.abstract blockquote p:first-of-type:before{display:none}
table.tableblock{max-width:100%;border-collapse:separate}
table.tableblock td>.paragraph:last-child p>p:last-child,table.tableblock th>p:last-child,table.tableblock td>p:last-child{margin-bottom:0}
table.tableblock,th.tableblock,td.tableblock{border:0 solid #dedede}
table.grid-all th.tableblock,table.grid-all td.tableblock{border-width:0 1px 1px 0}
table.grid-all tfoot>tr>th.tableblock,table.grid-all tfoot>tr>td.tableblock{border-width:1px 1px 0 0}
table.grid-cols th.tableblock,table.grid-cols td.tableblock{border-width:0 1px 0 0}
table.grid-all *>tr>.tableblock:last-child,table.grid-cols *>tr>.tableblock:last-child{border-right-width:0}
table.grid-rows th.tableblock,table.grid-rows td.tableblock{border-width:0 0 1px 0}
table.grid-all tbody>tr:last-child>th.tableblock,table.grid-all tbody>tr:last-child>td.tableblock,table.grid-all thead:last-child>tr>th.tableblock,table.grid-rows tbody>tr:last-child>th.tableblock,table.grid-rows tbody>tr:last-child>td.tableblock,table.grid-rows thead:last-child>tr>th.tableblock{border-bottom-width:0}
table.grid-rows tfoot>tr>th.tableblock,table.grid-rows tfoot>tr>td.tableblock{border-width:1px 0 0 0}
table.frame-all{border-width:1px}
table.frame-sides{border-width:0 1px}
table.frame-topbot{border-width:1px 0}
th.halign-left,td.halign-left{text-align:left}
th.halign-right,td.halign-right{text-align:right}
th.halign-center,td.halign-center{text-align:center}
th.valign-top,td.valign-top{vertical-align:top}
th.valign-bottom,td.valign-bottom{vertical-align:bottom}
th.valign-middle,td.valign-middle{vertical-align:middle}
table thead th,table tfoot th{font-weight:bold}
tbody tr th{display:table-cell;line-height:1.6;background:#f7f8f7}
tbody tr th,tbody tr th p,tfoot tr th,tfoot tr th p{color:rgba(0,0,0,.8);font-weight:bold}
p.tableblock>code:only-child{background:none;padding:0}
p.tableblock{font-size:1em}
td>div.verse{white-space:pre}
ol{margin-left:1.75em}
ul li ol{margin-left:1.5em}
dl dd{margin-left:1.125em}
dl dd:last-child,dl dd:last-child>:last-child{margin-bottom:0}
ol>li p,ul>li p,ul dd,ol dd,.olist .olist,.ulist .ulist,.ulist .olist,.olist .ulist{margin-bottom:.625em}
ul.unstyled,ol.unnumbered,ul.checklist,ul.none{list-style-type:none}
ul.unstyled,ol.unnumbered,ul.checklist{margin-left:.625em}
ul.checklist li>p:first-child>.fa-square-o:first-child,ul.checklist li>p:first-child>.fa-check-square-o:first-child{width:1em;font-size:.85em}
ul.checklist li>p:first-child>input[type="checkbox"]:first-child{width:1em;position:relative;top:1px}
ul.inline{margin:0 auto .625em auto;margin-left:-1.375em;margin-right:0;padding:0;list-style:none;overflow:hidden}
ul.inline>li{list-style:none;float:left;margin-left:1.375em;display:block}
ul.inline>li>*{display:block}
.unstyled dl dt{font-weight:400;font-style:normal}
ol.arabic{list-style-type:decimal}
ol.decimal{list-style-type:decimal-leading-zero}
ol.loweralpha{list-style-type:lower-alpha}
ol.upperalpha{list-style-type:upper-alpha}
ol.lowerroman{list-style-type:lower-roman}
ol.upperroman{list-style-type:upper-roman}
ol.lowergreek{list-style-type:lower-greek}
.hdlist>table,.colist>table{border:0;background:none}
.hdlist>table>tbody>tr,.colist>table>tbody>tr{background:none}
td.hdlist1,td.hdlist2{vertical-align:top;padding:0 .625em}
td.hdlist1{font-weight:bold;padding-bottom:1.25em}
.literalblock+.colist,.listingblock+.colist{margin-top:-.5em}
.colist>table tr>td:first-of-type{padding:0 .75em;line-height:1}
.colist>table tr>td:last-of-type{padding:.25em 0}
.thumb,.th{line-height:0;display:inline-block;border:solid 4px #fff;-webkit-box-shadow:0 0 0 1px #ddd;box-shadow:0 0 0 1px #ddd}
.imageblock.left,.imageblock[style*="float: left"]{margin:.25em .625em 1.25em 0}
.imageblock.right,.imageblock[style*="float: right"]{margin:.25em 0 1.25em .625em}
.imageblock>.title{margin-bottom:0}
.imageblock.thumb,.imageblock.th{border-width:6px}
.imageblock.thumb>.title,.imageblock.th>.title{padding:0 .125em}
.image.left,.image.right{margin-top:.25em;margin-bottom:.25em;display:inline-block;line-height:0}
.image.left{margin-right:.625em}
.image.right{margin-left:.625em}
a.image{text-decoration:none;display:inline-block}
a.image object{pointer-events:none}
sup.footnote,sup.footnoteref{font-size:.875em;position:static;vertical-align:super}
sup.footnote a,sup.footnoteref a{text-decoration:none}
sup.footnote a:active,sup.footnoteref a:active{text-decoration:underline}
#footnotes{padding-top:.75em;padding-bottom:.75em;margin-bottom:.625em}
#footnotes hr{width:20%;min-width:6.25em;margin:-.25em 0 .75em 0;border-width:1px 0 0 0}
#footnotes .footnote{padding:0 .375em 0 .225em;line-height:1.3334;font-size:.875em;margin-left:1.2em;text-indent:-1.05em;margin-bottom:.2em}
#footnotes .footnote a:first-of-type{font-weight:bold;text-decoration:none}
#footnotes .footnote:last-of-type{margin-bottom:0}
#content #footnotes{margin-top:-.625em;margin-bottom:0;padding:.75em 0}
.gist .file-data>table{border:0;background:#fff;width:100%;margin-bottom:0}
.gist .file-data>table td.line-data{width:99%}
div.unbreakable{page-break-inside:avoid}
.big{font-size:larger}
.small{font-size:smaller}
.underline{text-decoration:underline}
.overline{text-decoration:overline}
.line-through{text-decoration:line-through}
.aqua{color:#00bfbf}
.aqua-background{background-color:#00fafa}
.black{color:#000}
.black-background{background-color:#000}
.blue{color:#0000bf}
.blue-background{background-color:#0000fa}
.fuchsia{color:#bf00bf}
.fuchsia-background{background-color:#fa00fa}
.gray{color:#606060}
.gray-background{background-color:#7d7d7d}
.green{color:#006000}
.green-background{background-color:#007d00}
.lime{color:#00bf00}
.lime-background{background-color:#00fa00}
.maroon{color:#600000}
.maroon-background{background-color:#7d0000}
.navy{color:#000060}
.navy-background{background-color:#00007d}
.olive{color:#606000}
.olive-background{background-color:#7d7d00}
.purple{color:#600060}
.purple-background{background-color:#7d007d}
.red{color:#bf0000}
.red-background{background-color:#fa0000}
.silver{color:#909090}
.silver-background{background-color:#bcbcbc}
.teal{color:#006060}
.teal-background{background-color:#007d7d}
.white{color:#bfbfbf}
.white-background{background-color:#fafafa}
.yellow{color:#bfbf00}
.yellow-background{background-color:#fafa00}
span.icon>.fa{cursor:default}
.admonitionblock td.icon [class^="fa icon-"]{font-size:2.5em;text-shadow:1px 1px 2px rgba(0,0,0,.5);cursor:default}
.admonitionblock td.icon .icon-note:before{content:"\f05a";color:#19407c}
.admonitionblock td.icon .icon-tip:before{content:"\f0eb";text-shadow:1px 1px 2px rgba(155,155,0,.8);color:#111}
.admonitionblock td.icon .icon-warning:before{content:"\f071";color:#bf6900}
.admonitionblock td.icon .icon-caution:before{content:"\f06d";color:#bf3400}
.admonitionblock td.icon .icon-important:before{content:"\f06a";color:#bf0000}
.conum[data-value]{display:inline-block;color:#fff!important;background-color:rgba(0,0,0,.8);-webkit-border-radius:100px;border-radius:100px;text-align:center;font-size:.75em;width:1.67em;height:1.67em;line-height:1.67em;font-family:"Open Sans","DejaVu Sans",sans-serif;font-style:normal;font-weight:bold}
.conum[data-value] *{color:#fff!important}
.conum[data-value]+b{display:none}
.conum[data-value]:after{content:attr(data-value)}
pre .conum[data-value]{position:relative;top:-.125em}
b.conum *{color:inherit!important}
.conum:not([data-value]):empty{display:none}
dt,th.tableblock,td.content,div.footnote{text-rendering:optimizeLegibility}
h1,h2,p,td.content,span.alt{letter-spacing:-.01em}
p strong,td.content strong,div.footnote strong{letter-spacing:-.005em}
p,blockquote,dt,td.content,span.alt{font-size:1.0625rem}
p{margin-bottom:1.25rem}
.sidebarblock p,.sidebarblock dt,.sidebarblock td.content,p.tableblock{font-size:1em}
.exampleblock>.content{background-color:#fffef7;border-color:#e0e0dc;-webkit-box-shadow:0 1px 4px #e0e0dc;box-shadow:0 1px 4px #e0e0dc}
.print-only{display:none!important}
@media print{@page{margin:1.25cm .75cm}
*{-webkit-box-shadow:none!important;box-shadow:none!important;text-shadow:none!important}
a{color:inherit!important;text-decoration:underline!important}
a.bare,a[href^="#"],a[href^="mailto:"]{text-decoration:none!important}
a[href^="http:"]:not(.bare):after,a[href^="https:"]:not(.bare):after{content:"(" attr(href) ")";display:inline-block;font-size:.875em;padding-left:.25em}
abbr[title]:after{content:" (" attr(title) ")"}
pre,blockquote,tr,img,object,svg{page-break-inside:avoid}
thead{display:table-header-group}
svg{max-width:100%}
p,blockquote,dt,td.content{font-size:1em;orphans:3;widows:3}
h2,h3,#toctitle,.sidebarblock>.content>.title{page-break-after:avoid}
#toc,.sidebarblock,.exampleblock>.content{background:none!important}
#toc{border-bottom:1px solid #ddddd8!important;padding-bottom:0!important}
.sect1{padding-bottom:0!important}
.sect1+.sect1{border:0!important}
#header>h1:first-child{margin-top:1.25rem}
body.book #header{text-align:center}
body.book #header>h1:first-child{border:0!important;margin:2.5em 0 1em 0}
body.book #header .details{border:0!important;display:block;padding:0!important}
body.book #header .details span:first-child{margin-left:0!important}
body.book #header .details br{display:block}
body.book #header .details br+span:before{content:none!important}
body.book #toc{border:0!important;text-align:left!important;padding:0!important;margin:0!important}
body.book #toc,body.book #preamble,body.book h1.sect0,body.book .sect1>h2{page-break-before:always}
.listingblock code[data-lang]:before{display:block}
#footer{background:none!important;padding:0 .9375em}
#footer-text{color:rgba(0,0,0,.6)!important;font-size:.9em}
.hide-on-print{display:none!important}
.print-only{display:block!important}
.hide-for-print{display:none!important}
.show-for-print{display:inherit!important}}
</style>
</head>
<body class="article">
<div id="header">
</div>
<div id="content">
<div class="paragraph">
<p><a id="formtags-case-study"></a></p>
</div>
<div class="sect1">
<h2 id="_case_study_migrating_the_form_tags_sample_application">Case Study: Migrating the Form Tags Sample Application</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Migrating Form Tags</p>
</div>
<div class="paragraph">
<p>In this chapter we will walk through the steps needed to migrate the
Form Tags sample application from a standard Java EE WAR to a fully
OSGi compliant <strong>Shared Services WAR</strong> within a PAR.
The migration involves four packaging and deployment formats:</p>
</div>
<div class="olist arabic">
<ol class="arabic">
<li>
<p><a href="#formtags-case-study-war">Standard WAR</a></p>
</li>
<li>
<p><a href="#formtags-case-study-war-shared-libs">Shared Libraries WAR</a></p>
</li>
<li>
<p><a href="#formtags-case-study-war-shared-services">Shared Services WAR</a></p>
</li>
<li>
<p><a href="#formtags-case-study-par">PAR with a shared services WAR</a></p>
</li>
</ol>
</div>
<div class="paragraph">
<p>Each of these migration steps will produce a web application
that can be deployed and run on the VTS.</p>
</div>
<div class="paragraph">
<p>After summarising the process, an example <code>plan</code>
is shown which is another way of packaging and deploying the application.</p>
</div>
<div class="paragraph">
<p>The following image displays the directory structure you should have
after installing the Form Tags sample. Note however that the release
tag will typically resemble <code>3.0.0.RELEASE</code>.</p>
</div>
<div class="paragraph">
<p><span class="image"><img src="assets/images/formtags-case-study-sample-layout.png" alt="formtags case study sample layout"></span></p>
</div>
<div class="paragraph">
<p>The <code>dist</code> directory contains the distributables,
and the <code>projects</code> directory contains the source code and build scripts.</p>
</div>
<div class="paragraph">
<p>For simplicity, this chapter will focus on the distributables—which
are built using Virgo-Build rather than on configuring a project in an IDE.</p>
</div>
<div class="admonitionblock tip">
<table>
<tr>
<td class="icon">
<div class="title">Tip</div>
</td>
<td class="content">
<div class="paragraph">
<p>Pre-packaged distributables are made available in the <code>dist</code> directory;
however, if you would like to modify the samples or build
them from scratch, you may do so using Virgo-Build. Take a look at
the <code>README.TXT</code> file in each of the folders under the <code>projects</code>
directory in the Form Tags sample for instructions.</p>
</div>
</td>
</tr>
</table>
</div>
<div class="paragraph">
<p><a id="formtags-case-study-introduction"></a></p>
</div>
<div class="sect2">
<h3 id="_overview_of_the_form_tags_sample_application">Overview of the Form Tags Sample Application</h3>
<div class="paragraph">
<p>The sample that we will be using is the Form Tags show case
sample
which was provided with Spring 2.0. The Form Tags application
has
been removed from the official Spring 2.5.x distributions;
however,
since it is relatively simple but still contains enough
ingredients
to demonstrate the various considerations required during
a migration,
we have chosen to use it for these examples.</p>
</div>
<div class="paragraph">
<p>The purpose of the Form Tags show case sample was to demonstrate how
the Spring specific
<code>form:</code>
tags, released
in Spring 2.0, make view development with JSPs and tag
libraries easier.
The Form Tags application consists of a single
<code>UserService</code>
which returns a list
of
<code>Users</code>
. Furthermore, the application demonstrates how to list, view,
and
edit
<code>Users</code>
in a simple Spring MVC based web application using JSP
and JSTL.</p>
</div>
<div class="paragraph">
<p><a id="formtags-case-study-war"></a></p>
</div>
</div>
<div class="sect2">
<h3 id="_form_tags_war">Form Tags WAR</h3>
<div class="paragraph">
<p>We begin with a standard WAR deployment.</p>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<div class="title">Note</div>
</td>
<td class="content">
<div class="paragraph">
<p>The VTS supports the standard Java EE WAR
packaging
and deployment format as a first-class citizen, and there
are many
benefits to deploying a standard WAR file on the
VTS including,
but not limited to: tooling
support, runtime error diagnostics, FFDC
(first failure data
capture), etc.
In addition, support for standard WAR deployment
provides an easy on-ramp
for trying out the
VTS with existing web applications.</p>
</div>
</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>The following screen shot displays the directory structure of the
Form Tags application using the standard WAR format. As you can see,
there is no deviation from the standard structure and layout, and as
you would expect, all of the web application&#8217;s third-party
dependencies
(for example: Spring, Commons Logging) are packaged as
JARs in
<code>WEB-INF/lib</code>
.</p>
</div>
<div class="paragraph">
<p><span class="image"><img src="assets/images/formtags-case-study-exploded-war.png" alt="formtags case study exploded war"></span></p>
</div>
<div class="paragraph">
<p>To deploy this application, simply copy
<code>dist/formtags-war-3.0.0.*.war</code>
to
the
<code>SERVER_HOME/pickup</code>
directory for hot deployment.</p>
</div>
<div class="paragraph">
<p>You should then see the VTS produce
console output similar to the following:</p>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<div class="title">Note</div>
</td>
<td class="content">
<div class="paragraph">
<p>The console output has been reformatted to fit this document.</p>
</div>
</td>
</tr>
</table>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-txt" data-lang="txt">[2009-07-01 14:54:45.135] fs-watcher
&lt;SPDE0048I&gt; Processing 'CREATED' event for file 'formtags-war-3.0.0.RELEASE.war'.
[2009-07-01 14:54:45.797] fs-watcher
&lt;SPDE0010I&gt; Deployment of 'formtags-war-3.0.0.RELEASE.war' version '0' completed.
[2009-07-01 14:54:45.797] Thread-20
&lt;SPWE0000I&gt; Starting web bundle '/formtags-war-3.0.0.RELEASE'.
[2009-07-01 14:54:46.380] Thread-20
&lt;SPWE0001I&gt; Started web bundle '/formtags-war-3.0.0.RELEASE'.</code></pre>
</div>
</div>
<div class="paragraph">
<p>Navigate to
<code><a href="http://localhost:8080/" class="bare">http://localhost:8080/</a></code>
plus the web application context path,
which in the above case is
<code>formtags-war-3.0.0.RELEASE</code>
. Thus navigating to
<code><a href="http://localhost:8080/formtags-war-3.0.0.RELEASE" class="bare">http://localhost:8080/formtags-war-3.0.0.RELEASE</a></code>
should render the sample application&#8217;s welcome page, as
displayed in the screen
shot below.</p>
</div>
<div class="admonitionblock tip">
<table>
<tr>
<td class="icon">
<div class="title">Tip</div>
</td>
<td class="content">
<div class="paragraph">
<p>For WARs, the default web context path is the name of the WAR file
without the
<code>.war</code>
extension. You can optionally
specify a context path using the
<code>Web-ContextPath</code>
bundle
manifest header, which will be described in further detail
later.</p>
</div>
</td>
</tr>
</table>
</div>
<div class="paragraph">
<p><span class="image"><img src="assets/images/formtags-case-study-war-webpage.png" alt="formtags case study war webpage"></span></p>
</div>
<div class="paragraph">
<p><a id="formtags-case-study-war-shared-libs"></a></p>
</div>
</div>
<div class="sect2">
<h3 id="_form_tags_shared_libraries_war">Form Tags Shared Libraries WAR</h3>
<div class="paragraph">
<p>As mentioned above, a standard WAR file typically packages of all its
required
dependencies in
<code>WEB-INF/lib</code>
. The servlet container will
then add all of the JARs in
<code>WEB-INF/lib</code>
to the application&#8217;s
classpath.</p>
</div>
<div class="paragraph">
<p>The first step of the migration towards benefiting from an OSGi
container is to retrieve the dependencies from the
VTS&#8217;s bundle
repository at runtime. This
can significantly reduce the time it takes to build
and deploy the
application. It also enables the enforcement of policies
regarding the
use of third-party libraries.</p>
</div>
<div class="paragraph">
<p>The way in which dependencies are declared in an OSGi environment is
via manifest headers in a bundle&#8217;s
<code>/META-INF/MANIFEST.MF</code>
.
As mentioned in <a href="#developing-applications">[developing-applications]</a>, there are
three ways of expressing dependencies:
<code>Import-Package</code>,
<code>Import-Bundle</code> and
<code>Import-Library</code>.</p>
</div>
<div class="paragraph">
<p>The Form Tags application uses JSTL standard tag libraries.
Thus, you
need to choose a JSTL provider, for example the
Apache implementation
which comes with the VTS. To use the
Apache
implementation of JSTL, you need to express your dependency
as
outlined in the following manifest listing.
Because it is a single
bundle,
<code>Import-Bundle</code>
is
the simplest and therefore preferred manifest header to use.</p>
</div>
<div class="paragraph">
<p>The Form Tags application requires commons-logging and Spring.
It
would be very painful to have to list all the Spring packages one by
one.
Equally, considering the number of bundles that make up the
Spring framework, it would be verbose to list each bundle. Therefore
<code>Import-Library</code>
is the preferred approach
for expressing the dependency on the Spring
framework.</p>
</div>
<div class="admonitionblock tip">
<table>
<tr>
<td class="icon">
<div class="title">Tip</div>
</td>
<td class="content">
<div class="paragraph">
<p>How do you determine the name of a library definition provided
by the Virgo for Apache Tomcat? Use the <a href="http://www.eclipse.org/ebr">EBR</a>.</p>
</div>
</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>Examine the
<code>/META-INF/MANIFEST.MF</code>
in
<code>/dist/formtags-shared-libs-*.war</code>:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-txt" data-lang="txt">Manifest-Version: 1.0
Ant-Version: Apache Ant 1.7.0
Created-By: 1.5.0_13-119 (Apple Inc.)
Bundle-ManifestVersion: 2
Bundle-SymbolicName: org.springframework.showcase.formtags-shared-libs
Import-Library: org.springframework.spring;version="[3.0.0,4.0.0)"
Import-Bundle: com.springsource.org.apache.taglibs.standard;version="1
.1.2"</code></pre>
</div>
</div>
<div class="paragraph">
<p>You can see the
<code>Import-Library</code>
and
<code>Import-Bundle</code>
directives that instruct the VTS to add the
appropriate package imports to the bundle
classpath used by this WAR file.</p>
</div>
<div class="paragraph">
<p>Deploying the shared libraries WAR onto the
VTS should result
in console output similar to
the following:</p>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<div class="title">Note</div>
</td>
<td class="content">
<div class="paragraph">
<p>The console output has been reformatted to fit this document.</p>
</div>
</td>
</tr>
</table>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-txt" data-lang="txt">[2009-07-01 15:00:14.953] fs-watcher
&lt;SPDE0048I&gt; Processing 'CREATED' event for file 'formtags-shared-libs-3.0.0.RELEASE.war'.
[2009-07-01 15:00:15.363] fs-watcher
&lt;SPDE0010I&gt; Deployment of 'org.springframework.showcase.formtags_shared_libs' version '2' completed.
[2009-07-01 15:00:15.364] Thread-20
&lt;SPWE0000I&gt; Starting web bundle '/formtags-shared-libs-3.0.0.RELEASE'.
[2009-07-01 15:00:15.816] Thread-20
&lt;SPWE0001I&gt; Started web bundle '/formtags-shared-libs-3.0.0.RELEASE'.</code></pre>
</div>
</div>
<div class="paragraph">
<p>Navigating to
<code><a href="http://localhost:8080/formtags-shared-libs-BUILDTAG" class="bare">http://localhost:8080/formtags-shared-libs-BUILDTAG</a>
`
should render the welcome page. Note that for the pre-packaged
distributable,
the
`BUILDTAG</code>
should be similar to
<code>3.0.0.RELEASE</code>
;
whereas, for a local build the
<code>-BUILDTAG</code>
may be completely
omitted. Please consult the console output,
web-based admin console, or log
to determine the exact context path
under which the web application has been deployed.</p>
</div>
<div class="paragraph">
<p><a id="formtags-case-study-war-shared-services"></a></p>
</div>
</div>
<div class="sect2">
<h3 id="_form_tags_shared_services_war">Form Tags Shared Services WAR</h3>
<div class="paragraph">
<p>The next step in the migration is to deploy the services as a
separate
OSGi bundle which the WAR then references.
The Form Tags
sample has a single service
<code>UserManager</code>.</p>
</div>
<div class="paragraph">
<p>This scenario has two separate deployables, the
<code>service</code>
bundle and the WAR file.
The following image shows the two separate
source trees:</p>
</div>
<div class="paragraph">
<p><span class="image"><img src="assets/images/formtags-case-study-shared-services-eclipse.png" alt="formtags case study shared services eclipse"></span></p>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<div class="title">Note</div>
</td>
<td class="content">
<div class="paragraph">
<p>Note that the WAR does not contain the
<code>.domain</code>
or
<code>.service</code>
packages as these will be imported from the separate service bundle.</p>
</div>
</td>
</tr>
</table>
</div>
<div class="paragraph">
<p><a id="formtags-case-study-war-shared-services-service"></a></p>
</div>
<div class="sect3">
<h4 id="_the_service_bundle">The Service Bundle</h4>
<div class="paragraph">
<p>The responsibility of the first bundle (
<code>formtags-shared-services-service</code>
)
is to provide the API of the formtags service. This includes both
the
domain and the service API. In the same way that imports are
defined
in the
<code>/META-INF/MANIFEST.MF</code>
, so are exports.
The following is the
<code>/META-INF/MANIFEST.MF</code>
listing from the service bundle.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-txt" data-lang="txt">Manifest-Version: 1.0
Ant-Version: Apache Ant 1.7.0
Created-By: 1.5.0_13-119 (Apple Inc.)
Bundle-ManifestVersion: 2
Bundle-Name: FormTags Service (and implementation)
Bundle-SymbolicName: org.springframework.showcase.formtags.service-shared-services
Export-Package: org.springframework.showcase.formtags.service,org.spri
ngframework.showcase.formtags.domain
Import-Library: org.springframework.spring;version="[3.0.0,4.0.0)"</code></pre>
</div>
</div>
<div class="paragraph">
<p>The symbolic name of this bundle is
<code>org.springframework.showcase.formtags.service-shared-services</code>.
Note that the name of the bundle typically describes the package that the bundle primarily exports.
If you take a look at the <code>repository/bundles/ext</code> in the VTS
directory, you&#8217;ll see that
names are almost always indicative of the contents of the bundle.
For this example, however, we have also appended
&#8220;-shared-services&#8221;
in order to avoid possible clashes with other bundle symbolic
names.
You will see later that the PAR also contains a service
bundle.</p>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<div class="title">Note</div>
</td>
<td class="content">
<div class="paragraph">
<p>In OSGi, the combination of
<code>Bundle-SymbolicName</code>
and
<code>Bundle-Version</code>
is used to uniquely identify
a bundle within the OSGi container.
Furthermore, when you deploy
a bundle to the Virgo for Apache Tomcat,
for example via the
<code>pickup</code>
directory, a bundle&#8217;s filename is also used to uniquely
identify it for
the purpose of supporting
<strong>hot deployment</strong>
via
the file system.</p>
</div>
</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>As well as exporting types (i.e. the domain classes and service
API), the service bundle also publishes an implementation of the
<code>UserManager</code>
. The actual implementation is
<code>StubUserManager</code>
; however, that should remain an
implementation detail of this
bundle.</p>
</div>
<div class="paragraph">
<p>The fact that this bundle publishes a service is not captured in
the
<code>/META-INF/MANIFEST.MF</code>
, as it is a Gemini Blueprint concept.
The following image is of
<code>src/main/resources/spring</code>.</p>
</div>
<div class="paragraph">
<p><span class="image"><img src="assets/images/formtags-case-study-shared-services-service-resources.png" alt="formtags case study shared services service resources"></span></p>
</div>
<div class="paragraph">
<p>As you can see there are two Spring configuration files:
<code>module-context.xml</code>
and
<code>osgi-context.xml</code>.</p>
</div>
<div class="admonitionblock tip">
<table>
<tr>
<td class="icon">
<div class="title">Tip</div>
</td>
<td class="content">
<div class="paragraph">
<p>These names are abitrary; however, they follow an informal
convention:
<code>module-context.xml</code>
typically bootstraps the Spring context
(usually delegating to
smaller fine grained context files inside another directory),
whilst
<code>osgi-context.xml</code>
contains all the OSGi service exports and references.</p>
</div>
</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>The following is a listing of
<code>module-context.xml</code>
.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-xml" data-lang="xml">&lt;?xml version="1.0" encoding="UTF-8"?&gt;
&lt;beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd"&gt;
&lt;bean id="userManager"
class="org.springframework.showcase.formtags.service.internal.StubUserManager"/&gt;
&lt;/beans&gt;</code></pre>
</div>
</div>
<div class="paragraph">
<p>As you can see, this simply defines a bean called
<code>userManager</code>
.
The following is a listing of
<code>osgi-context.xml</code>.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-xml" data-lang="xml">&lt;?xml version="1.0" encoding="UTF-8"?&gt;
&lt;beans:beans
xmlns="http://www.springframework.org/schema/osgi"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:beans="http://www.springframework.org/schema/beans"
xsi:schemaLocation="http://www.springframework.org/schema/osgi
http://www.springframework.org/schema/osgi/spring-osgi.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd"&gt;
&lt;service ref="userManager"
interface="org.springframework.showcase.formtags.service.UserManager"/&gt;
&lt;/beans:beans&gt;</code></pre>
</div>
</div>
<div class="paragraph">
<p>This single bean definition exports the
<code>userManager</code>
defined in
<code>module-context.xml</code>
to the
OSGi service registry and makes it available under the public
`org.springframework.showcase.formtags.service.UserManager
`
API.</p>
</div>
<div class="paragraph">
<p>The service bundle should now be ready to deploy on the
VTS.
So copy
<code>/dist/formtags-shared-services-services*</code>
to the
<code>SERVER_HOME/pickup</code>
directory.
Output similar to the following should appear in the
VTS&#8217;s console:</p>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<div class="title">Note</div>
</td>
<td class="content">
<div class="paragraph">
<p>The console output has been reformatted to fit this document.</p>
</div>
</td>
</tr>
</table>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-txt" data-lang="txt">[2009-07-01 15:05:03.511] fs-watcher
&lt;SPDE0048I&gt; Processing 'CREATED' event for file 'formtags-shared-services-service-2.0.0.RELEASE.jar'.
[2009-07-01 15:05:03.688] fs-watcher
&lt;SPDE0010I&gt; Deployment of 'org.springframework.showcase.formtags.service_shared_services' version '2.0.0.RELEASE' completed.</code></pre>
</div>
</div>
<div class="paragraph">
<p><a id="formtags-case-study-war-shared-services-war"></a></p>
</div>
</div>
<div class="sect3">
<h4 id="_accessing_the_service_and_types_from_the_war">Accessing the Service and Types from the WAR</h4>
<div class="paragraph">
<p>The WAR file now needs to access the types and service exported
by
the service bundle. The following listing is the WAR&#8217;s
<code>/META-INF/MANIFEST.MF</code>
which imports the types
exported by the service bundle. The
<code>Import-Bundle</code>
statement has also been extended to import
<code>org.springframework.osgi.core</code>
,
which is necessary in order to load an OSGi-enabled
<code>WebApplicationContext</code>
.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-txt" data-lang="txt">Manifest-Version: 1.0
Ant-Version: Apache Ant 1.7.0
Created-By: 1.5.0_13-119 (Apple Inc.)
Bundle-ManifestVersion: 2
Bundle-SymbolicName: org.springframework.showcase.formtags.web-shared-
services
Import-Package: org.springframework.showcase.formtags.domain,org.sprin
gframework.showcase.formtags.service, org.eclipse.virgo.web.dm;version="[1.0,2.1)"
Import-Library: org.springframework.spring;version="[2.5.4,3.1.0)"
Import-Bundle: com.springsource.org.apache.taglibs.standard;version="1
.1.2",org.springframework.osgi.core</code></pre>
</div>
</div>
<div class="paragraph">
<p>In addition to importing the exported types of the service bundle,
the WAR must also obtain a reference to the
<code>UserManager</code>
published by the service bundle. The following image shows the
directory
structure of the Shared Services WAR.</p>
</div>
<div class="paragraph">
<p><span class="image"><img src="assets/images/formtags-case-study-shared-services-war-resources.png" alt="formtags case study shared services war resources"></span></p>
</div>
<div class="paragraph">
<p>As you can see in the above image, the Form Tags Shared Services
WAR&#8217;s
<code>/WEB-INF/web.xml</code>
directory contains a standard
<code>web.xml</code>
deployment descriptor,
<code>applicationContext.xml</code>
which defines the configuration
for the
<strong>root</strong>
<code>WebApplicationContext</code>
, and
<code>formtags-servlet.xml</code>
which defines the configuration specific to the
configured
<strong>formtags</strong>
<code>DispatcherServlet</code>
.</p>
</div>
<div class="paragraph">
<p>As is typical for Spring MVC based web applications, you configure a
<code>ContextLoaderListener</code>
in
<code>web.xml</code>
to load your root
<code>WebApplicationContext</code>
; however, to enable your
<code>WebApplicationContext</code>
to be able to reference services from the OSGi Service Registry,
you
must explicitly set the
<code>contextClass</code>
Servlet context parameter to the fully qualified
class name of a
<code>ConfigurableWebApplicationContext</code>
which is OSGi-enabled. When deploying
Shared Services WARs to the
Virgo for Apache Tomcat, you should use
<code>org.eclipse.virgo.web.dm.ServerOsgiBundleXmlWebApplicationContext</code>.
This will then enable the use of Gemini Blueprint&#8217;s <code>&lt;reference &#8230;&#8203; /&gt;</code>
within your root <code>WebApplicationContext</code> (i.e., in <code>applicationContext.xml</code>).
The following listing is an excerpt from <code>/WEB-INF/web.xml</code>.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-xml" data-lang="xml">&lt;context-param&gt;
&lt;param-name&gt;contextClass&lt;/param-name&gt;
&lt;param-value&gt;org.eclipse.virgo.web.dm.ServerOsgiBundleXmlWebApplicationContext&lt;/param-value&gt;
&lt;/context-param&gt;
&lt;listener&gt;
&lt;listener-class&gt;org.springframework.web.context.ContextLoaderListener&lt;/listener-class&gt;
&lt;/listener&gt;</code></pre>
</div>
</div>
<div class="paragraph">
<p>The Form Tags Shared Services WAR contains a
<code>/WEB-INF/applicationContext.xml</code>
file which is the default configuration location used to create the
<strong>root</strong>
<code>WebApplicationContext</code>
for Spring MVC&#8217;s
<code>ContextLoaderListener</code>.</p>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<div class="title">Note</div>
</td>
<td class="content">
<div class="paragraph">
<p>As already mentioned, in the OSGi world, bundle configuration
takes
place in the root
<code>/META-INF/</code>
directory.
Typically Gemini Blueprint powered configuration files will live
there as well (e.g., in
<code>/META-INF/spring/*.xml</code>
).
In a WAR, however, the root
<code>WebApplicationContext</code>
loaded by
<code>ContextLoaderListener</code>
and the
<code>DispatcherServlet&#8217;s</code>
application context typically live in
<code>/WEB-INF/</code>.</p>
</div>
</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>The following is the listing of the WAR&#8217;s
<code>/WEB-INF/applicationContext.xml</code>.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-xml" data-lang="xml">&lt;?xml version="1.0" encoding="UTF-8"?&gt;
&lt;beans:beans
xmlns="http://www.springframework.org/schema/osgi"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:beans="http://www.springframework.org/schema/beans"
xsi:schemaLocation="http://www.springframework.org/schema/osgi
http://www.springframework.org/schema/osgi/spring-osgi.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd"&gt;
&lt;reference id="userManager"
interface="org.springframework.showcase.formtags.service.UserManager"/&gt;
&lt;/beans:beans&gt;</code></pre>
</div>
</div>
<div class="paragraph">
<p>The single bean declaration is retrieving a service that implements
the
`org.springframework.showcase.formtags.service.UserManager
`
API from the OSGi Service Registry.</p>
</div>
<div class="admonitionblock tip">
<table>
<tr>
<td class="icon">
<div class="title">Tip</div>
</td>
<td class="content">
<div class="paragraph">
<p>You might have been expecting a reference to the service bundle,
but that isn&#8217;t how OSGi works. OSGi provides a service
registry, and this bean definition is accessing a service in that
registry that meets the specified restriction (i.e. implements
the
specified interface). This leads to a very loosely coupled
programming model: the WAR really doesn&#8217;t care where the
implementation
comes from.</p>
</div>
</td>
</tr>
</table>
</div>
<div class="admonitionblock tip">
<table>
<tr>
<td class="icon">
<div class="title">Tip</div>
</td>
<td class="content">
<div class="paragraph">
<p>What happens if there is no service at runtime?
What if there are
multiple services that match the criteria?
Gemini Blueprint provides a lot
of configuration options, including
whether or not the reference is
<strong>mandatory</strong>
,
how long to wait for a service reference, etc. Please consult the
<a href="https://www.eclipse.org/gemini/blueprint/documentation/reference/2.0.0.RELEASE/html/index.html">Eclipse Gemini Blueprint Reference Guide</a> for further information.</p>
</div>
</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>One of the benefits of programming to interfaces is that you
are
decoupled from the actual implementation; Gemini Blueprint provides a
proxy. This
has enormous benefits including the ability to
dynamically refresh individual bundles without
cascading that
refresh to unrelated bundles.</p>
</div>
<div class="paragraph">
<p>To deploy the WAR, copy
<code>/dist/formtags-shared-services-war*</code>
to the
<code>SERVER_HOME/pickup</code>
directory.
You should then see console output similar to the
following:</p>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<div class="title">Note</div>
</td>
<td class="content">
<div class="paragraph">
<p>The console output has been reformatted to fit this document.</p>
</div>
</td>
</tr>
</table>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-txt" data-lang="txt">[2009-07-01 15:09:19.819] fs-watcher
&lt;SPDE0048I&gt; Processing 'CREATED' event for file 'formtags-shared-services-war-3.0.0.RELEASE.war'.
[2009-07-01 15:09:20.167] fs-watcher
&lt;SPDE0010I&gt; Deployment of 'org.springframework.showcase.formtags.web_shared_services' version '3' completed.
[2009-07-01 15:09:20.168] Thread-20
&lt;SPWE0000I&gt; Starting web bundle '/formtags-shared-services-war-3.0.0.RELEASE'.
[2009-07-01 15:09:20.647] Thread-20
&lt;SPWE0001I&gt; Started web bundle '/formtags-shared-services-war-3.0.0.RELEASE'.
----</code></pre>
</div>
</div>
<div class="paragraph">
<p>Navigating to the appropriate link should render the welcome page.</p>
</div>
<div class="paragraph">
<p><a id="formtags-case-study-par"></a></p>
</div>
</div>
</div>
<div class="sect2">
<h3 id="_form_tags_par">Form Tags PAR</h3>
<div class="paragraph">
<p>The final step in the migration is that of a full blown
OSGi
application with web support. The Virgo for Apache Tomcat introduces a
new packaging and deployment format: the PAR.</p>
</div>
<div class="paragraph">
<p>A PAR is a standard JAR with a &#8220;.par&#8221;
file extension which contains all of the modules of your
application (e.g., service, domain, and infrastructure bundles
as well
as a WAR for web applications) in a single deployment unit.
Moreover,
a PAR defines both a physical and logical application boundary.</p>
</div>
<div class="paragraph">
<p>The PAR sample is comprised of four directories, as shown below.</p>
</div>
<div class="paragraph">
<p><span class="image"><img src="assets/images/formtags-case-study-par-sample.png" alt="formtags case study par sample"></span></p>
</div>
<div class="paragraph">
<p>The
<code>formtags-par</code>
directory is a build project that
understands how to create the PAR
from its constituent bundles.</p>
</div>
<div class="paragraph">
<p><a id="formtags-case-study-par-granularity"></a></p>
</div>
<div class="sect3">
<h4 id="_granularity_of_the_par">Granularity of the PAR</h4>
<div class="paragraph">
<p>Achieving the appropriate level of granularity for your OSGi
application is more of an art than a science. It helps to look
at the
different requirements:</p>
</div>
<table class="tableblock frame-all grid-all spread">
<caption class="title">Table 1. Granularity drivers</caption>
<colgroup>
<col style="width: 40%;">
<col style="width: 60%;">
</colgroup>
<thead>
<tr>
<th class="tableblock halign-left valign-top">Requirement</th>
<th class="tableblock halign-left valign-top">Description</th>
</tr>
</thead>
<tbody>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">Domain/Technical Layering</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Applications can be split either by domain (i.e.,
by use case or
<strong>vertically</strong>
) or
by their technical layers (i.e.,
<strong>horizontally</strong>
).
Since the Form Tags application essentially has only
a single
use case, the bundles are split by technical layering
(i.e.,
domain, service, and web).</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">Refreshability</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">A major benefit of OSGi is that of refreshability: if one
bundle
is changed, only bundles that have a dependency upon
the
exported types need to be refreshed. This has a high impact
on
development time costs as well as production
costs. However,
this can lead to lots of smaller, fine grained
bundles. An
example of this granularity would be to
separate out the service
API and implementation into two different
bundles. This means
that a change in the implementation
wouldn&#8217;t require any
other bundles to be refreshed.</p></td>
</tr>
</tbody>
</table>
<div class="paragraph">
<p>Ultimately the right level of granularity will depend upon your
particular application and team.</p>
</div>
<div class="paragraph">
<p><a id="formtags-case-study-par-domain-and-service"></a></p>
</div>
</div>
<div class="sect3">
<h4 id="_domain_and_service_bundles">Domain and Service Bundles</h4>
<div class="paragraph">
<p>The service bundle is identical (except for the
<code>Bundle-SymbolicName</code>
) to that
in the shared-services variation of the sample.
The PAR has
also separated out the domain classes into their own bundle.
When
layering by technical considerations, it is again
somewhat of an
unofficial convention to have a
<code>.domain</code>
bundle.</p>
</div>
<div class="paragraph">
<p><a id="formtags-case-study-par-par"></a></p>
</div>
</div>
</div>
<div class="sect2">
<h3 id="_constructing_the_par">Constructing the PAR</h3>
<div class="paragraph">
<p>Finally we need to construct the PAR itself.
The following are
the contents of the exploded PAR.</p>
</div>
<div class="paragraph">
<p><span class="image"><img src="assets/images/formtags-case-study-par-exploded.png" alt="formtags case study par exploded"></span></p>
</div>
<div class="paragraph">
<p>You can see that the PAR itself doesn&#8217;t contain any
resources or
Java classes: it simply packages together a related set
of bundles
as a single, logical unit.</p>
</div>
<div class="paragraph">
<p>The PAR does however, contain its own
<code>/META-INF/MANIFEST.MF</code>.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-txt" data-lang="txt">Manifest-Version: 1.0
Application-SymbolicName: org.springframework.showcase.formtags-par
Application-Version: 3.0.0
Application-Name: FormTags Showcase Application (PAR)</code></pre>
</div>
</div>
<div class="paragraph">
<p>For more information on the contents of the PAR&#8217;s
<code>/META-INF/MANIFEST.MF</code>
, please consult <a href="#developing-applications">[developing-applications]</a>.</p>
</div>
<div class="paragraph">
<p>You can now deploy the PAR on the VTS, for
example by copying
<code>/dist/formtags-par*.par</code>
to the VTS&#8217;s
<code>pickup</code>
directory.
You should then see console output similar to the
following:</p>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<div class="title">Note</div>
</td>
<td class="content">
<div class="paragraph">
<p>The console output has been reformatted to fit this document.</p>
</div>
</td>
</tr>
</table>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-txt" data-lang="txt">[2009-07-01 15:13:43.306] fs-watcher
&lt;SPDE0048I&gt; Processing 'CREATED' event for file 'formtags-par-2.0.0.RELEASE.par'.
[2009-07-01 15:13:44.060] fs-watcher
&lt;SPDE0010I&gt; Deployment of 'formtags-par' version '2.0.0.RELEASE' completed.
[2009-07-01 15:13:44.068] Thread-20
&lt;SPWE0000I&gt; Starting web bundle '/formtags-par'.
[2009-07-01 15:13:45.212] Thread-20
&lt;SPWE0001I&gt; Started web bundle '/formtags-par'.</code></pre>
</div>
</div>
<div class="paragraph">
<p>Navigate to <a href="http://localhost:8080/formtags-par" class="bare">http://localhost:8080/formtags-par</a> to see the welcome page.</p>
</div>
<div class="admonitionblock tip">
<table>
<tr>
<td class="icon">
<div class="title">Tip</div>
</td>
<td class="content">
<div class="paragraph">
<p>Note that the web application&#8217;s context path is explicitly
defined via the
<code>Web-ContextPath</code>
manifest header in
<code>/META-INF/MANIFEST.MF</code>
of the Web application bundle within the PAR.</p>
</div>
</td>
</tr>
</table>
</div>
<div class="paragraph">
<p><a id="formtags-case-study-summary"></a></p>
</div>
</div>
<div class="sect2">
<h3 id="_summary_of_the_form_tags_migration">Summary of the Form Tags Migration</h3>
<div class="paragraph">
<p>The Virgo for Apache Tomcat provides out-of-the-box support for
deploying
standard Java EE WAR files. In addition support for
<strong>Shared Libraries</strong>
and
<strong>Shared Services</strong>
WAR formats provides a logical migration path away from standard,
monolithic WARs toward OSGi-enable Web applications. The PAR
packaging
and deployment format enables truly fine-grained,
loosely-coupled, and
efficient application development. In general,
the migration steps
presented in this chapter are fairly
straightforward, but developers
should set aside time for some
up-front design of the bundles themselves.</p>
</div>
<div class="paragraph">
<p>It is recommended that you take another sample application or
indeed your own small application and go through this migration
process yourself. This will help you better understand the concepts
and
principles at work. In addition, it is highly recommended that you
familiarize yourself with the extensive Eclipse IDE support provided
by the Virgo Tools. See the Virgo Tools Guide for more on that.</p>
</div>
<div class="paragraph">
<p><a id="formtags-case-study-as-plan"></a></p>
</div>
</div>
<div class="sect2">
<h3 id="_form_tags_as_a_plan">Form Tags as a Plan</h3>
<div class="paragraph">
<p>Plans (see <a href="#developing-applications-plans">[developing-applications-plans]</a>)
allow us to package and deploy the Form Tags application in a more
flexible way.
Instead of packaging all the bundles of the application
into a single PAR file, each bundle can be placed in the repository
and referred to in a <strong>plan</strong>.</p>
</div>
<div class="paragraph">
<p>The bundles to be placed in a repository in the chain (for example,
<code>repository/usr</code>) are:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-txt" data-lang="txt">org.springframework.showcase.formtags.domain-2.0.0.RELEASE.jar
org.springframework.showcase.formtags.service-2.0.0.RELEASE.jar
org.springframework.showcase.formtags.web-2.0.0.RELEASE.war</code></pre>
</div>
</div>
<div class="paragraph">
<p>which are just those files which were part of the PAR.</p>
</div>
<div class="paragraph">
<p>Here is the contents of a suitable plan file for the Form Tags
example:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlight"><code class="language-xml" data-lang="xml">&lt;?xml version="1.0" encoding="UTF-8"?&gt;
&lt;plan name="formtags.plan" version="2.0.0" scoped="true" atomic="true"
xmlns="http://www.eclipse.org/virgo/schema/plan"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.eclipse.org/virgo/schema/plan
http://www.eclipse.org/virgo/schema/plan/eclipse-virgo-plan.xsd"&gt;
&lt;artifact type="bundle" name="org.springframework.showcase.formtags.domain_par" version="[3.0,3.1)"/&gt;
&lt;artifact type="bundle" name="org.springframework.showcase.formtags.service_par" version="[3.0,3.1)"/&gt;
&lt;artifact type="bundle" name="org.springframework.showcase.formtags.web_par" version="[3.0,3.1)"/&gt;
&lt;/plan&gt;</code></pre>
</div>
</div>
<div class="paragraph">
<p>where we have chosen to use any of the artifacts in the version range [2.0,2.1).
This plan (as a file called, for example, <code>formtags.plan</code>)
can be deployed in any of the normal ways (for example, dropped in the <code>pickup</code> directory).</p>
</div>
<div class="paragraph">
<p>When the plan is deployed, the artifacts it references are
installed from the repository and deployed in the order given in the
plan file.
Because this plan is scoped and atomic, the collection is
given an application scope and is started and stopped as a single
unit.</p>
</div>
</div>
</div>
</div>
</div>
<div id="footer">
<div id="footer-text">
Last updated 2017-02-23 21:06:55 +01:00
</div>
</div>
</body>
</html>