| <!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’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 |
| <SPDE0048I> Processing 'CREATED' event for file 'formtags-war-3.0.0.RELEASE.war'. |
| [2009-07-01 14:54:45.797] fs-watcher |
| <SPDE0010I> Deployment of 'formtags-war-3.0.0.RELEASE.war' version '0' completed. |
| [2009-07-01 14:54:45.797] Thread-20 |
| <SPWE0000I> Starting web bundle '/formtags-war-3.0.0.RELEASE'. |
| [2009-07-01 14:54:46.380] Thread-20 |
| <SPWE0001I> 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’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’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’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’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 |
| <SPDE0048I> Processing 'CREATED' event for file 'formtags-shared-libs-3.0.0.RELEASE.war'. |
| [2009-07-01 15:00:15.363] fs-watcher |
| <SPDE0010I> Deployment of 'org.springframework.showcase.formtags_shared_libs' version '2' completed. |
| [2009-07-01 15:00:15.364] Thread-20 |
| <SPWE0000I> Starting web bundle '/formtags-shared-libs-3.0.0.RELEASE'. |
| [2009-07-01 15:00:15.816] Thread-20 |
| <SPWE0001I> 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’ll see that |
| names are almost always indicative of the contents of the bundle. |
| For this example, however, we have also appended |
| “-shared-services” |
| 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’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"><?xml version="1.0" encoding="UTF-8"?> |
| |
| <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"> |
| |
| <bean id="userManager" |
| class="org.springframework.showcase.formtags.service.internal.StubUserManager"/> |
| |
| </beans></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"><?xml version="1.0" encoding="UTF-8"?> |
| <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"> |
| |
| <service ref="userManager" |
| interface="org.springframework.showcase.formtags.service.UserManager"/> |
| |
| </beans:beans></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’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 |
| <SPDE0048I> Processing 'CREATED' event for file 'formtags-shared-services-service-2.0.0.RELEASE.jar'. |
| [2009-07-01 15:05:03.688] fs-watcher |
| <SPDE0010I> 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’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’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’s <code><reference …​ /></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"><context-param> |
| <param-name>contextClass</param-name> |
| <param-value>org.eclipse.virgo.web.dm.ServerOsgiBundleXmlWebApplicationContext</param-value> |
| </context-param> |
| |
| <listener> |
| <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> |
| </listener></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’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’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’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"><?xml version="1.0" encoding="UTF-8"?> |
| <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"> |
| |
| <reference id="userManager" |
| interface="org.springframework.showcase.formtags.service.UserManager"/> |
| |
| </beans:beans></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’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’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 |
| <SPDE0048I> Processing 'CREATED' event for file 'formtags-shared-services-war-3.0.0.RELEASE.war'. |
| [2009-07-01 15:09:20.167] fs-watcher |
| <SPDE0010I> Deployment of 'org.springframework.showcase.formtags.web_shared_services' version '3' completed. |
| [2009-07-01 15:09:20.168] Thread-20 |
| <SPWE0000I> Starting web bundle '/formtags-shared-services-war-3.0.0.RELEASE'. |
| [2009-07-01 15:09:20.647] Thread-20 |
| <SPWE0001I> 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 “.par” |
| 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’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’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’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’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 |
| <SPDE0048I> Processing 'CREATED' event for file 'formtags-par-2.0.0.RELEASE.par'. |
| [2009-07-01 15:13:44.060] fs-watcher |
| <SPDE0010I> Deployment of 'formtags-par' version '2.0.0.RELEASE' completed. |
| [2009-07-01 15:13:44.068] Thread-20 |
| <SPWE0000I> Starting web bundle '/formtags-par'. |
| [2009-07-01 15:13:45.212] Thread-20 |
| <SPWE0001I> 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’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"><?xml version="1.0" encoding="UTF-8"?> |
| <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"> |
| |
| <artifact type="bundle" name="org.springframework.showcase.formtags.domain_par" version="[3.0,3.1)"/> |
| <artifact type="bundle" name="org.springframework.showcase.formtags.service_par" version="[3.0,3.1)"/> |
| <artifact type="bundle" name="org.springframework.showcase.formtags.web_par" version="[3.0,3.1)"/> |
| |
| </plan></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> |