incubator-sling-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From conflue...@apache.org
Subject [CONF] Apache Sling: Documentation (page edited)
Date Wed, 09 Jul 2008 09:32:00 GMT
<html>
<head>
    <base href="http://cwiki.apache.org/confluence" />
    <style type="text/css">
    <!--
    body, p, td, table, tr, .bodytext, .stepfield {
	font-family: Verdana, arial, sans-serif;
	font-size: 11px;
	line-height: 16px;
	color: #000000;
	font-weight: normal;
}
#PageContent {
	text-align: left;
	background-color: #fff;
	padding: 0px;
	margin: 0px;
    padding-bottom:20px;
}
/*
** when this stylesheet is used for the Tiny MCE Wysiwyg editor's edit area, we can't
** use an id=PageContent or class=wiki-content, so we must
** set the body style to that used for PageContent, and p to that used for wiki-content.
*/

body {
	margin: 0px;
	padding: 0px;
	text-align: center;
    background-color: #f0f0f0;
}

@media print {

body {
    background-color: #fff;
}

}

.monospaceInput {
    font:12px monospace
}

.wiki-content p, .commentblock p {
    margin: 16px 0px 16px 0px;
    padding: 0px;
}

.wiki-content-preview {
    padding: 5px;
    border-left: 1px solid #3c78b5;
    border-right: 1px solid #3c78b5;
}

ul, ol {
    margin-top: 2px;
    margin-bottom: 2px;
    padding-top: 0px;
    padding-bottom: 0px;
}

pre {
    padding: 0px;
    margin-top: 5px;
    margin-left: 15px;
    margin-bottom: 5px;
    margin-right: 5px;
    text-align: left;
}

.helpheading {
    font-weight: bold;
    background-color: #D0D9BD;
        border-bottom: 1px solid #3c78b5;
        padding: 4px 4px 4px 4px;
        margin: 0px;
        margin-top: 10px;
}
.helpcontent {
        padding: 4px 4px 20px 4px;
    background-color: #f5f7f1;
}

.code {
 	border: 1px dashed #3c78b5;
    font-size: 11px;
	font-family: Courier;
    margin: 10px;
	line-height: 13px;
}

.focusedComment {
    background: #ffffce;
}

.commentBox, .focusedComment {
    padding: 10px;
    margin: 5px 0 5px 0;
    border: 1px #bbb solid;
}

.codeHeader {
    background-color: #f0f0f0;
 	border-bottom: 1px dashed #3c78b5;
    padding: 3px;
	text-align: center;
}

.codeContent {
    text-align: left;
    background-color: #f0f0f0;
    padding: 3px;
}

.preformatted {
 	border: 1px dashed #3c78b5;
    font-size: 11px;
	font-family: Courier;
    margin: 10px;
	line-height: 13px;
}

.preformattedHeader {
    background-color: #f0f0f0;
 	border-bottom: 1px dashed #3c78b5;
    padding: 3px;
	text-align: center;
}

.preformattedContent {
    background-color: #f0f0f0;
    padding: 3px;
}

.panel {
 	border: 1px dashed #3c78b5;
    margin: 10px;
    margin-top: 0px;
}

.panelHeader {
    background-color: #f0f0f0;
 	border-bottom: 1px dashed #3c78b5;
    padding: 3px;
	text-align: center;
}

.panelContent {
    background-color: #f0f0f0;
    padding: 5px;
}

.anonymousAlert {
    background-color: #f0f0f0;
 	border: 1px dashed red;
    font-size: 11px;
    padding: 10px 5px 10px 5px;
    margin: 4px;
	line-height: 13px;
}

.lockAlert {
    background-color: #f0f0f0;
    width: 50%;
 	border: 1px dashed red;
    font-size: 11px;
    padding: 10px 5px 10px 5px;
    margin: 4px;
	line-height: 13px;
}


.code-keyword {
  color: #000091;
  background-color: inherit;
}

.code-object {
  color: #910091;
  background-color: inherit;
}

.code-quote {
  color: #009100;
  background-color: inherit;
}

.code-comment {
  color: #808080;
  background-color: inherit;
}


.code-xml .code-keyword {
  color: inherit;
  font-weight: bold;
}

.code-tag {
  color: #000091;
  background-color: inherit;
}

.breadcrumbs {
    background-color: #f0f0f0;
 	border-color: #3c78b5;
	border-width: 1px 0px 1px 0px;
	border-style: solid;
    font-size: 11px;
    padding: 3px 0px 3px 0px;
}

.navmenu {
    border: 1px solid #ccc;
}

.menuheading {
    font-weight: bold;
    background-color: #f0f0f0;
 	border-bottom: 1px solid #3c78b5;
	padding: 4px 4px 2px 4px;
}

.menuitems {
	padding: 4px 4px 20px 4px;
}

.rightpanel {
    border-left: 1px solid #ccc;
    border-bottom: 1px solid #ccc;
}

#helpheading {
    text-align: left;
    font-weight: bold;
    background-color: #D0D9BD;
 	border-bottom: 1px solid #3c78b5;
	padding: 4px 4px 4px 4px;
	margin: 0px;
}
#helpcontent {
	padding: 4px 4px 4px 4px;
    background-color: #f5f7f1;
}
.helptab-unselected {
    font-weight: bold;
	padding: 5px;
    background-color: #f5f7f1;
}
.helptab-selected {
    font-weight: bold;
    background-color: #D0D9BD;
	padding: 5px;
}
.helptabs {
    margin: 0px;
    background-color: #f5f7f1;
	padding: 5px;
}
.infopanel-heading {
    font-weight: bold;
	padding: 4px 0px 2px 0px;
}

.pagebody {
}

.pageheader {
	padding: 5px 5px 5px 0px;
 	border-bottom: 1px solid #3c78b5;
}

.pagetitle {
	font-size: 22px;
	font-weight: bold;
	font-family: Arial, sans-serif;
	color: #003366;
}

.newpagetitle {
    color: #ccc !important;
}

.steptitle {
	font-size: 18px;
	font-weight: bold;
	font-family: Arial, sans-serif;
	color: #003366;
	margin-bottom: 7px;
}

.substeptitle {
    font-size: 12px;
    font-weight: bold;
    font-family: Arial, sans-serif;
    color: #003366;
    margin: 2px 4px 4px 4px;
    padding: 2px 4px 1px 4px;
}

.stepdesc {
    font-family: Verdana, arial, sans-serif;
	font-size: 11px;
	line-height: 16px;
	font-weight: normal;
    color: #666666;
    margin-top: 7px;
    margin-bottom: 7px;
}

.steplabel {
    font-weight: bold;
    margin-right: 4px;
    color: black;
    float: left;
    width: 15%;
    text-align: right;
}

.stepfield {
    background: #f0f0f0;
    padding: 5px;
}

.submitButtons{
    margin-top:5px;
    text-align:right;
}

.formtitle {
	font-size: 12px;
	font-weight: bold;
	font-family: Arial, sans-serif;
	color: #003366;
}

.sectionbottom {
    border-bottom: 1px solid #3c78b5;
}

.topRow {
    border-top: 2px solid #3c78b5;
}

.tabletitle {
	font-size: 14px;
	font-weight: bold;
	font-family: Arial, sans-serif;
    padding: 3px 0px 2px 0px;
    margin: 8px 4px 2px 0px;
	color: #003366;
	border-bottom: 2px solid #3c78b5;
}
.pagesubheading {
    color: #666666;
    font-size: 10px;
    padding: 0px 0px 5px 0px;
}

HR {
	color: 3c78b5;
	height: 1;
}

A:link, A:visited, A:active, A:hover {
	color: #003366;
}

h1 A:link, h1 A:visited, h1 A:active {
	text-decoration: none;
}

h1 A:hover {
    border-bottom: 1px dotted #003366;
}

.wiki-content > :first-child, .commentblock > :first-child {
    margin-top: 3px;
}

.logocell {
    padding: 10px;
}

input {
	font-family: verdana, geneva, arial, sans-serif;
	font-size: 11px;
	color: #000000;
}

textarea, textarea.editor {
	font-family: verdana, geneva, arial, sans-serif;
	font-size: 11px;
	color: #333333;
}

/* use logoSpaceLink instead.
.spacenametitle {
	font: 21px/31px Impact, Arial, Helvetica;
    font-weight: 100;
    color: #999999;
	margin: 0px;
}
.spacenametitle img {
  margin: 0 0 -4px 0;
}
.spacenametitle a {
    text-decoration: none;
    color: #999999;
}
.spacenametitle a:visited {
    text-decoration: none;
    color: #999999;
}*/

.spacenametitle-printable {
	font: 20px/25px Impact, Arial, Helvetica;
    font-weight: 100;
    color: #999999;
	margin: 0px;
}
.spacenametitle-printable a {
    text-decoration: none;
    color: #999999;
}
.spacenametitle-printable a:visited {
    text-decoration: none;
    color: #999999;
}

.blogDate {
	font-weight: bold;
	text-decoration: none;
	color: black;
}

.blogSurtitle {
    background: #f0f0f0;
 	border: 1px solid #ddd;
	padding: 3px;
	margin: 1px 1px 10px 1px;
}

.blogHeading {
    font-size: 20px;
    line-height: normal;
    font-weight: bold;
    padding: 0px;
    margin: 0px;
}

.blogHeading a {
   text-decoration: none;
   color: black;
}

.endsection {
	align: right;
	color: #666666;
	margin-top: 10px;
}
.endsectionleftnav {
	align: right;
	color: #666666;
	margin-top: 10px;
}

h1 {
	font-size: 24px;
	line-height: normal;
	font-weight: bold;
	background-color: #f0f0f0;
	color: #003366;
 	border-bottom: 1px solid #3c78b5;
	padding: 2px;
	margin: 36px 0px 4px 0px;
}

h2 {
	font-size: 18px;
	line-height: normal;
	font-weight: bold;
	background-color: #f0f0f0;
 	border-bottom: 1px solid #3c78b5;
	padding: 2px;
	margin: 27px 0px 4px 0px;
}

h3 {
	font-size: 14px;
	line-height: normal;
	font-weight: bold;
	background-color: #f0f0f0;
	padding: 2px;
	margin: 21px 0px 4px 0px;
}

h4 {
	font-size: 12px;
	line-height: normal;
	font-weight: bold;
	background-color: #f0f0f0;
	padding: 2px;
	margin: 18px 0px 4px 0px;
}

h4.search {
	font-size: 12px;
	line-height: normal;
	font-weight: normal;
	background-color: #f0f0f0;
	padding: 4px;
	margin: 18px 0px 4px 0px;
}

h5 {
	font-size: 10px;
	line-height: normal;
	font-weight: bold;
	background-color: #f0f0f0;
	padding: 2px;
	margin: 14px 0px 4px 0px;
}

h6 {
	font-size: 8px;
	line-height: normal;
	font-weight: bold;
	background-color: #f0f0f0;
	padding: 2px;
	margin: 14px 0px 4px 0px;
}

.smallfont {
    font-size: 10px;
}
.descfont {
    font-size: 10px;
    color: #666666;
}
.smallerfont {
    font-size: 9px;
}
.smalltext {
    color: #666666;
    font-size: 10px;
}
.smalltext a {
    color: #666666;
}
.smalltext-blue {
    color: #3c78b5;
    font-size: 10px;
}
.surtitle {
    margin-left: 1px;
    margin-bottom: 5px;
    font-size: 14px;
    color: #666666;
}

/* css hack found here:  http://www.fo3nix.pwp.blueyonder.co.uk/tutorials/css/hacks/ */
.navItemOver { font-size: 10px; font-weight: bold; color: #ffffff; background-color: #003366; cursor: hand; voice-family: '\'}\''; voice-family:inherit; cursor: pointer;}
.navItemOver a { color: #ffffff; background-color:#003366; text-decoration: none; }
.navItemOver a:visited { color: #ffffff; background-color:#003366; text-decoration: none; }
.navItemOver a:hover { color: #ffffff; background-color:#003366; text-decoration: none; }
.navItem { font-size: 10px; font-weight: bold; color: #ffffff; background-color: #3c78b5; }
.navItem a { color: #ffffff; text-decoration: none; }
.navItem a:hover { color: #ffffff; text-decoration: none; }
.navItem a:visited { color: #ffffff; text-decoration: none; }

div.padded { padding: 4px; }
div.thickPadded { padding: 10px; }
h3.macrolibrariestitle {
    margin: 0px 0px 0px 0px;
}

div.centered { text-align: center; margin: 10px; }
div.centered table {margin: 0px auto; text-align: left; }

.tableview table {
    margin: 0;
}

.tableview th {
    text-align: left;
    color: #003366;
    font-size: 12px;
    padding: 5px 0px 0px 5px;
    border-bottom: 2px solid #3c78b5;
}
.tableview td {
    text-align: left;
    border-color: #ccc;
    border-width: 0px 0px 1px 0px;
    border-style: solid;
    margin: 0;
    padding: 4px 10px 4px 5px;
}

.grid {
    margin: 2px 0px 5px 0px;
    border-collapse: collapse;
}
.grid th  {
    border: 1px solid #ccc;
    padding: 2px 4px 2px 4px;
    background: #f0f0f0;
    text-align: center;
}
.grid td  {
    border: 1px solid #ccc;
    padding: 3px 4px 3px 4px;
}
.gridHover {
	background-color: #f9f9f9;
}

td.infocell {
    background-color: #f0f0f0;
}
.label {
	font-weight: bold;
	color: #003366;
}

label {
	font-weight: bold;
	color: #003366;
}

.error {
	background-color: #fcc;
}

.errorBox {
	background-color: #fcc;
    border: 1px solid #c00;
    padding: 5px;
    margin: 5px;
}

.errorMessage {
	color: #c00;
}

.success {
	background-color: #dfd;
}

.successBox {
	background-color: #dfd;
    border: 1px solid #090;
    padding: 5px;
    margin-top:5px;
    margin-bottom:5px;
}

blockquote {
	padding-left: 10px;
	padding-right: 10px;
	margin-left: 5px;
	margin-right: 0px;
	border-left: 1px solid #3c78b5;
}

table.confluenceTable
{
    margin: 5px;
    border-collapse: collapse;
}

/* Added as a temporary fix for CONF-4223. The table elements appear to be inheriting the border: none attribute from the sectionMacro class */
table.confluenceTable td.confluenceTd
{
    border-width: 1px;
    border-style: solid;
    border-color: #ccc;
    padding: 3px 4px 3px 4px;
}

/* Added as a temporary fix for CONF-4223. The table elements appear to be inheriting the border: none attribute from the sectionMacro class */
table.confluenceTable th.confluenceTh
{
    border-width: 1px;
    border-style: solid;
    border-color: #ccc;
    padding: 3px 4px 3px 4px;
    background-color: #f0f0f0;
    text-align: center;
}

td.confluenceTd
{
    border-width: 1px;
    border-style: solid;
    border-color: #ccc;
    padding: 3px 4px 3px 4px;
}

th.confluenceTh
{
    border-width: 1px;
    border-style: solid;
    border-color: #ccc;
    padding: 3px 4px 3px 4px;
    background-color: #f0f0f0;
    text-align: center;
}

DIV.small {
	font-size: 9px;
}

H1.pagename {
	margin-top: 0px;
}

IMG.inline  {}

.loginform {
    margin: 5px;
    border: 1px solid #ccc;
}

/* The text how the "This is a preview" comment should be shown. */
.previewnote { text-align: center;
                font-size: 11px;
                    color: red; }

/* How the preview content should be shown */
.previewcontent { background: #E0E0E0; }

/* How the system messages should be shown (DisplayMessage.jsp) */
.messagecontent { background: #E0E0E0; }

/* How the "This page has been modified..." -comment should be shown. */
.conflictnote { }

.createlink {
    color: maroon;
}
a.createlink {
    color: maroon;
}
.templateparameter {
    font-size: 9px;
    color: darkblue;
}

.diffadded {
    background: #ddffdd;
    padding: 1px 1px 1px 4px;
	border-left: 4px solid darkgreen;
}
.diffdeleted {
    color: #999;
    background: #ffdddd;
    padding: 1px 1px 1px 4px;
	border-left: 4px solid darkred;
}
.diffnochange {
    padding: 1px 1px 1px 4px;
	border-left: 4px solid lightgrey;
}
.differror {
    background: brown;
}
.diff {
    font-family: lucida console, courier new, fixed-width;
	font-size: 12px;
	line-height: 14px;
}
.diffaddedchars {
    background-color:#99ff99;
    font-weight:bolder;
}
.diffremovedchars {
    background-color:#ff9999;
    text-decoration: line-through;
    font-weight:bolder;
}

.greybackground {
    background: #f0f0f0
}

.greybox {
 	border: 1px solid #ddd;
	padding: 3px;
	margin: 1px 1px 10px 1px;
}

.borderedGreyBox {
    border: 1px solid #cccccc;
    background-color: #f0f0f0;
    padding: 10px;
}

.greyboxfilled {
 	border: 1px solid #ddd;
    background: #f0f0f0;
    padding: 3px;
	margin: 1px 1px 10px 1px;
}

.navBackgroundBox {
    padding: 5px 5px 5px 5px;
    font-size: 22px;
	font-weight: bold;
	font-family: Arial, sans-serif;
	color: white;
    background: #3c78b5;
    text-decoration: none;
}

.previewBoxTop {
	background-color: #f0f0f0;
    border-width: 1px 1px 0px 1px;
    border-style: solid;
    border-color: #3c78b5;
    padding: 5px;
    margin: 5px 0px 0px 0px;
    text-align: center;
}
.previewContent {
    background-color: #fff;
 	border-color: #3c78b5;
	border-width: 0px 1px 0px 1px;
	border-style: solid;
	padding: 10px;
	margin: 0px;
}
.previewBoxBottom {
	background-color: #f0f0f0;
    border-width: 0px 1px 1px 1px;
    border-style: solid;
    border-color: #3c78b5;
    padding: 5px;
    margin: 0px 0px 5px 0px;
    text-align: center;
}

.functionbox {
    background-color: #f0f0f0;
 	border: 1px solid #3c78b5;
	padding: 3px;
	margin: 1px 1px 10px 1px;
}

.functionbox-greyborder {
    background-color: #f0f0f0;
 	border: 1px solid #ddd;
	padding: 3px;
	margin: 1px 1px 10px 1px;
}

.search-highlight {
    background-color: #ffffcc;
}

/* normal (white) background */
.rowNormal {
    background-color: #ffffff;
 }

/* alternate (pale yellow) background */
.rowAlternate {
    background-color: #f7f7f7;
}

/* used in the list attachments table */
.rowAlternateNoBottomColor {
    background-color: #f7f7f7;
}

.rowAlternateNoBottomNoColor {
}

.rowAlternateNoBottomColor td {
    border-bottom: 0px;
}

.rowAlternateNoBottomNoColor td {
    border-bottom: 0px;
}

/* row highlight (grey) background */
.rowHighlight {
    background-color: #f0f0f0;

}

TD.greenbar {FONT-SIZE: 2px; BACKGROUND: #00df00; BORDER: 1px solid #9c9c9c; PADDING: 0px; }
TD.redbar {FONT-SIZE: 2px; BACKGROUND: #df0000; BORDER: 1px solid #9c9c9c; PADDING: 0px; }
TD.darkredbar {FONT-SIZE: 2px; BACKGROUND: #af0000; BORDER: 1px solid #9c9c9c; PADDING: 0px; }

TR.testpassed {FONT-SIZE: 2px; BACKGROUND: #ddffdd; PADDING: 0px; }
TR.testfailed {FONT-SIZE: 2px; BACKGROUND: #ffdddd; PADDING: 0px; }

.toolbar  {
    margin: 0px;
    border-collapse: collapse;
}

.toolbar td  {
    border: 1px solid #ccc;
    padding: 2px 2px 2px 2px;
    color: #ccc;
}

td.noformatting {
    border-width: 0px;
    border-style: none;
    text-align: center;
	padding: 0px;
}

.commentblock {
    margin: 12px 0 12px 0;
}

/*
 * Divs displaying the license information, if necessary.
 */
.license-eval, .license-none, .license-nonprofit {
    border-top: 1px solid #bbbbbb;
    text-align: center;
    font-size: 10px;
    font-family: Verdana, Arial, Helvetica, sans-serif;
}

.license-eval, .license-none {
    background-color: #ffcccc;
}

.license-eval b, .license-none b {
    color: #990000
}

.license-nonprofit {
    background-color: #ffffff;
}

/*
 * The shadow at the bottom of the page between the main content and the
 * "powered by" section.
 */
.bottomshadow {
    height: 12px;
    background-image: url("$req.contextPath/images/border/border_bottom.gif");
    background-repeat: repeat-x;
}

/*
 * Styling of the operations box
 */
.navmenu .operations li, .navmenu .operations ul {
    list-style: none;
    margin-left: 0;
    padding-left: 0;
}

.navmenu .operations ul {
    margin-bottom: 9px;
}

.navmenu .label {
    font-weight: inherit;
}

/*
 * Styling of ops as a toolbar
 */
.toolbar div {
    display: none;
}

.toolbar .label {
    display: none;
}

.toolbar .operations {
    display: block;
}

.toolbar .operations ul {
    display: inline;
    list-style: none;
    margin-left: 10px;
    padding-left: 0;
}

.toolbar .operations li {
    list-style: none;
    display: inline;
}

/* list page navigational tabs */
#foldertab {
padding: 3px 0px 3px 8px;
margin-left: 0;
border-bottom: 1px solid #3c78b5;
font: bold 11px Verdana, sans-serif;
}

#foldertab li {
list-style: none;
margin: 0;
display: inline;
}

#foldertab li a {
padding: 3px 0.5em;
margin-left: 3px;
border: 1px solid #3c78b5;
border-bottom: none;
background: #3c78b5;
text-decoration: none;
}

#foldertab li a:link { color: #ffffff; }
#foldertab li a:visited { color: #ffffff; }

#foldertab li a:hover {
color: #ffffff;
background: #003366;
border-color: #003366;
}

#foldertab li a.current {
background: white;
border-bottom: 1px solid white;
color: black;
}

#foldertab li a.current:link { color: black; }
#foldertab li a.current:visited { color: black; }
#foldertab li a.current:hover {
background: white;
border-bottom: 1px solid white;
color: black;
}

/* alphabet list */
ul#squaretab {
margin-left: 0;
padding-left: 0;
white-space: nowrap;
font: bold 8px Verdana, sans-serif;
}

#squaretab li {
display: inline;
list-style-type: none;
}

#squaretab a {
padding: 2px 6px;
border: 1px solid #3c78b5;
}

#squaretab a:link, #squaretab a:visited {
color: #fff;
background-color: #3c78b5;
text-decoration: none;
}

#squaretab a:hover {
color: #ffffff;
background-color: #003366;
border-color: #003366;
text-decoration: none;
}

#squaretab li a#current {
background: white;
color: black;
}

.blogcalendar * {
    font-family:verdana, arial, sans-serif;
    font-size:x-small;
    font-weight:normal;
    line-height:140%;
    padding:2px;
}


table.blogcalendar {
    border: 1px solid #3c78b5;
}

.blogcalendar th.calendarhead, a.calendarhead {
    font-size:x-small;
    font-weight:bold;
    padding:2px;
    text-transform:uppercase;
    background-color: #3c78b5;
    color: #ffffff;
    letter-spacing: .3em;
    text-transform: uppercase;
}

.calendarhead:visited {color: white;}
.calendarhead:active {color: white;}
.calendarhead:hover {color: white;}

.blogcalendar th {
    font-size:x-small;
    font-weight:bold;
    padding:2px;
    background-color:#f0f0f0;
}

.blogcalendar td {
    font-size:x-small;
    font-weight:normal;
}

.searchGroup { padding: 0 0 10px 0; background: #f0f0f0; }
.searchGroupHeading { font-size: 10px; font-weight: bold; color: #ffffff; background-color: #3c78b5; padding: 2px 4px 1px 4px; }
.searchItem { padding: 1px 4px 1px 4px; }
.searchItemSelected { padding: 1px 4px 1px 4px; font-weight: bold; background: #ddd; }

/* permissions page styles */
.permissionHeading {
    border-bottom: #bbb; border-width: 0 0 1px 0; border-style: solid; font-size: 16px; text-align: left;
}
.permissionTab {
    border-width: 0 0 0 1px; border-style: solid; background: #3c78b5; color: #ffffff; font-size: 10px;
}
.permissionSuperTab {
    border-width: 0 0 0 1px; border-style: solid; background: #003366; color: #ffffff;
}
.permissionCell {
    border-left: #bbb; border-width: 0 0 0 1px; border-style: solid;
}

/* warning panel */
.warningPanel { background: #FFFFCE; border:#F0C000 1px solid; padding: 8px; margin: 10px; }
/* alert panel */
.alertPanel { background: #FFCCCC; border:#C00 1px solid; padding: 8px; margin: 10px; }
/* info panel */
.infoPanel { background: #D8E4F1; border:#3c78b5 1px solid; padding: 8px; margin: 10px; }

/* side menu highlighting (e.g. space content screen) */
.optionPadded { padding: 2px; }
.optionSelected { background-color: #ffffcc; padding: 2px; border: 1px solid #ddd; margin: -1px; }
.optionSelected a { font-weight: bold; text-decoration: none; color: black; }

/* information macros */
.noteMacro { border-style: solid; border-width: 1px; border-color: #F0C000; background-color: #FFFFCE; text-align:left; margin-top: 5px; margin-bottom: 5px}
.warningMacro { border-style: solid; border-width: 1px; border-color: #c00; background-color: #fcc; text-align:left; margin-top: 5px; margin-bottom: 5px}
.infoMacro { border-style: solid; border-width: 1px; border-color: #3c78b5; background-color: #D8E4F1; text-align:left; margin-top: 5px; margin-bottom: 5px}
.tipMacro { border-style: solid; border-width: 1px; border-color: #090; background-color: #dfd; text-align:left; margin-top: 5px; margin-bottom: 5px}
.informationMacroPadding { padding: 5px 0 0 5px; }

table.infoMacro td, table.warningMacro td, table.tipMacro td, table.noteMacro td, table.sectionMacro td {
    border: none;
}

table.sectionMacroWithBorder td.columnMacro { border-style: dashed; border-width: 1px; border-color: #cccccc;}

.pagecontent
{
    padding: 10px;
    text-align: left;
}

/* styles for links in the top bar */
.topBarDiv a:link {color: #ffffff;}
.topBarDiv a:visited {color: #ffffff;}
.topBarDiv a:active {color: #ffffff;}
.topBarDiv a:hover {color: #ffffff;}
.topBarDiv {color: #ffffff;}

.topBar {
    background-color: #003366;
}


/* styles for extended operations */
.greyLinks a:link {color: #666666; text-decoration:underline;}
.greyLinks a:visited {color: #666666; text-decoration:underline;}
.greyLinks a:active {color: #666666; text-decoration:underline;}
.greyLinks a:hover {color: #666666; text-decoration:underline;}
.greyLinks {color: #666666; display:block; padding: 10px}

.logoSpaceLink {color: #999999; text-decoration: none}
.logoSpaceLink a:link {color: #999999; text-decoration: none}
.logoSpaceLink a:visited {color: #999999; text-decoration: none}
.logoSpaceLink a:active {color: #999999; text-decoration: none}
.logoSpaceLink a:hover {color: #003366; text-decoration: none}

/* basic panel (basicpanel.vmd) style */
.basicPanelContainer {border: 1px solid #3c78b5; margin-top: 2px; margin-bottom: 8px; width: 100%}
.basicPanelTitle {padding: 5px; margin: 0px; background-color: #f0f0f0; color: black; font-weight: bold;}
.basicPanelBody {padding: 5px; margin: 0px}

.separatorLinks a:link {color: white}
.separatorLinks a:visited {color: white}
.separatorLinks a:active {color: white}

.greynavbar {background-color: #f0f0f0; border-top: 1px solid #3c78b5; margin-top: 2px}

div.headerField {
    float: left;
    width: auto;
    height: 100%;
}

.headerFloat {
    margin-left: auto;
    width: 50%;
}

.headerFloatLeft {
    float: left;
    margin-right: 20px;
    margin-bottom: 10px;
}

#headerRow {
    padding: 10px;
}

div.license-personal {
   background-color: #003366;
   color: #ffffff;
}

div.license-personal a {
   color: #ffffff;
}

.greyFormBox {
    border: 1px solid #cccccc;
    padding: 5px;
}

/* IE automatically adds a margin before and after form tags. Use this style to remove that */
.marginlessForm {
    margin: 0px;
}

.openPageHighlight {
    background-color: #ffffcc;
    padding: 2px;
    border: 1px solid #ddd;
}

.editPageInsertLinks, .editPageInsertLinks a
{
    color: #666666;
    font-weight: bold;
    font-size: 10px;
}

/* Style for label heatmap. */
.top10 a {
    font-weight: bold;
    font-size: 2em;
    color: #003366;
}
.top25 a {
    font-weight: bold;
    font-size: 1.6em;
    color: #003366;
}
.top50 a {
    font-size: 1.4em;
    color: #003366;
}
.top100 a {
    font-size: 1.2em;
    color: #003366;
}

.heatmap {
    list-style:none;
    width: 95%;
    margin: 0px auto;
}

.heatmap a {
    text-decoration:none;
}

.heatmap a:hover {
    text-decoration:underline;
}

.heatmap li {
    display: inline;
}

.minitab {
padding: 3px 0px 3px 8px;
margin-left: 0;
margin-top: 1px;
margin-bottom: 0px;
border-bottom: 1px solid #3c78b5;
font: bold 9px Verdana, sans-serif;
text-decoration: none;
float:none;
}
.selectedminitab {
padding: 3px 0.5em;
margin-left: 3px;
margin-top: 1px;
border: 1px solid #3c78b5;
background: white;
border-bottom: 1px solid white;
color: #000000;
text-decoration: none;
}
.unselectedminitab {
padding: 3px 0.5em;
margin-left: 3px;
margin-top: 1px;
border: 1px solid #3c78b5;
border-bottom: none;
background: #3c78b5;
color: #ffffff;
text-decoration: none;
}

a.unselectedminitab:hover {
color: #ffffff;
background: #003366;
border-color: #003366;
}

a.unselectedminitab:link { color: white; }
a.unselectedminitab:visited { color: white; }

a.selectedminitab:link { color: black; }
a.selectedminitab:visited { color: black; }

.linkerror { background-color: #fcc;}

a.labelOperationLink:link {text-decoration: underline}
a.labelOperationLink:active {text-decoration: underline}
a.labelOperationLink:visited {text-decoration: underline}
a.labelOperationLink:hover {text-decoration: underline}

a.newLabel:link {background-color: #ddffdd}
a.newLabel:active {background-color: #ddffdd}
a.newLabel:visited {background-color: #ddffdd}
a.newLabel:hover {background-color: #ddffdd}

ul.square {list-style-type: square}

.inline-control-link {
    background: #ffc;
    font-size: 9px;
    color: #666;
    padding: 2px;
    text-transform: uppercase;
    text-decoration: none;
}


.inline-control-link a:link {text-decoration: none}
.inline-control-link a:active {text-decoration: none}
.inline-control-link a:visited {text-decoration: none}
.inline-control-link a:hover {text-decoration: none}

.inline-control-link {
    background: #ffc;
    font-size: 9px;
    color: #666;
    padding: 2px;
    text-transform: uppercase;
    text-decoration: none;
    cursor: pointer;
}

div.auto_complete {
    width: 350px;
    background: #fff;
}
div.auto_complete ul {
    border: 1px solid #888;
    margin: 0;
    padding: 0;
    width: 100%;
    list-style-type: none;
}
div.auto_complete ul li {
    margin: 0;
    padding: 3px;
}
div.auto_complete ul li.selected {
    background-color: #ffb;
}
div.auto_complete ul strong.highlight {
    color: #800;
    margin: 0;
    padding: 0;
}

/******* Edit Page Styles *******/
.toogleFormDiv{
    border:1px solid #A7A6AA;
    background-color:white;
    padding:5px;
    margin-top: 5px;
}

.toogleInfoDiv{
    border:1px solid #A7A6AA;
    background-color:white;
    display:none;
    padding:5px;
    margin-top: 10px;
}

.inputSection{
    margin-bottom:20px;
}

#editBox{
   border:1px solid lightgray;
   background-color:#F0F0F0;
}

/******* Left Navigation Theme Styles ********/
.leftnav li a {
    text-decoration:none;
    color:white;
    margin:0px;
    display:block;
    padding:2px;
    padding-left:5px;
    background-color: #3c78b5;
    border-top:1px solid #3c78b5;
}

.leftnav li a:active {color:white;}
.leftnav li a:visited {color:white;}
.leftnav li a:hover {background-color: #003366; color:white;}

/* Added by Shaun during i18n */
.replaced
{
    background-color: #33CC66;
}

.topPadding
{
    margin-top: 20px;
}

/* new form style */
.form-block {
    padding: 6px;
}
.form-error-block {
    padding: 6px;
    background: #fcc;
    border-top: #f0f0f0 1px solid;
    border-bottom: #f0f0f0 1px solid;
    margin-bottom: 6px;
    padding: 0 12px 0 12px;
}
.form-element-large {
    font-size: 16px;
    font-weight: bold;
    font-family: Arial, sans-serif;
    color: #003366;
}

.form-element-small {
    font-size: 12px;
    font-weight: bold;
    font-family: Arial, sans-serif;
    color: #003366;
}

.form-header {
    background: lightyellow;
    border-top: #f0f0f0 1px solid;
    border-bottom: #f0f0f0 1px solid;
    margin-bottom: 6px;
    padding: 0 12px 0 12px;
}
.form-header p, .form-block p, .form-error-block p {
    line-height: normal;
    margin: 12px 0 12px 0;
}
.form-example {
    color: #888;
    font-size: 11px;
}
.form-divider {
    border-bottom: #ccc 1px solid;
    margin-bottom: 6px;
}
.form-buttons {
    margin-top: 6px;
    border-top: #ccc 1px solid;
    border-bottom: #ccc 1px solid;
    background: #f0f0f0;
    padding: 10px;
    text-align: center;
}
.form-buttons input {
    width: 100px;
}
.form-block .error {
    padding: 6px;
    margin-bottom: 6px;
}
    -->
    </style>
</head>
<body>

<div id="PageContent">
<table class="pagecontent" border="0" cellpadding="0" cellspacing="0" width="100%"><tr>
<td valign="top" class="pagebody">

    <div class="pageheader">
        <span class="pagetitle">
            Page Edited :
            <a href="http://cwiki.apache.org/confluence/display/SLING">SLING</a> :
            <a href="http://cwiki.apache.org/confluence/display/SLING/Documentation">Documentation</a>
        </span>
    </div>

     <p>
        <a href="http://cwiki.apache.org/confluence/display/SLING/Documentation">Documentation</a>
        has been edited by             <a href="http://cwiki.apache.org/confluence/display/~alexander.klimetschek@googlemail.com">Alexander Klimetschek</a>
            <span class="smallfont">(May 09, 2008)</span>.
     </p>
    
     <p>
                 <a href="http://cwiki.apache.org/confluence/pages/diffpagesbyversion.action?pageId=76423&originalVersion=3&revisedVersion=4">(View changes)</a>
     </p>

    <span class="label">Content:</span><br/>
    <div class="greybox wiki-content"><p>= Testing the Confluence snippet macro =<br/>
See <span class="nobr"><a href="http://confluence.atlassian.com/display/CONFEXT/Snippet+Plugin" title="Visit page outside Confluence" rel="nofollow">http://confluence.atlassian.com/display/CONFEXT/Snippet+Plugin<sup><img class="rendericon" src="/confluence/images/icons/linkext7.gif" height="7" width="7" align="absmiddle" alt="" border="0"/></sup></a></span> for more info.</p>

<p>== Here's Sling.java straight from our svn repository ==</p>
<div class="code"><div class="codeContent">
<pre class="code-java">/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * <span class="code-keyword">this</span> work <span class="code-keyword">for</span> additional information regarding copyright ownership.
 * The ASF licenses <span class="code-keyword">this</span> file to You under the Apache License, Version 2.0
 * (the <span class="code-quote">"License"</span>); you may not use <span class="code-keyword">this</span> file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *      http:<span class="code-comment">//www.apache.org/licenses/LICENSE-2.0
</span> *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an <span class="code-quote">"AS IS"</span> BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License <span class="code-keyword">for</span> the specific language governing permissions and
 * limitations under the License.
 */
<span class="code-keyword">package</span> org.apache.sling.launcher.app;

<span class="code-keyword">import</span> <span class="code-keyword">static</span> org.apache.felix.framework.util.FelixConstants.EMBEDDED_EXECUTION_PROP;

<span class="code-keyword">import</span> java.io.File;
<span class="code-keyword">import</span> java.io.FileInputStream;
<span class="code-keyword">import</span> java.io.FileOutputStream;
<span class="code-keyword">import</span> java.io.IOException;
<span class="code-keyword">import</span> java.io.InputStream;
<span class="code-keyword">import</span> java.io.OutputStream;
<span class="code-keyword">import</span> java.util.ArrayList;
<span class="code-keyword">import</span> java.util.HashMap;
<span class="code-keyword">import</span> java.util.Hashtable;
<span class="code-keyword">import</span> java.util.Iterator;
<span class="code-keyword">import</span> java.util.List;
<span class="code-keyword">import</span> java.util.Map;
<span class="code-keyword">import</span> java.util.Properties;
<span class="code-keyword">import</span> java.util.Set;
<span class="code-keyword">import</span> java.util.SortedMap;
<span class="code-keyword">import</span> java.util.StringTokenizer;
<span class="code-keyword">import</span> java.util.TreeMap;
<span class="code-keyword">import</span> java.util.TreeSet;
<span class="code-keyword">import</span> java.util.Map.Entry;

<span class="code-keyword">import</span> org.apache.felix.framework.Felix;
<span class="code-keyword">import</span> org.apache.felix.framework.Logger;
<span class="code-keyword">import</span> org.osgi.framework.BundleActivator;
<span class="code-keyword">import</span> org.osgi.framework.BundleContext;
<span class="code-keyword">import</span> org.osgi.framework.BundleException;
<span class="code-keyword">import</span> org.osgi.framework.Constants;
<span class="code-keyword">import</span> org.osgi.framework.Version;
<span class="code-keyword">import</span> org.osgi.service.url.URLConstants;
<span class="code-keyword">import</span> org.osgi.service.url.URLStreamHandlerService;

/**
 * The &lt;code&gt;Sling&lt;/code&gt; serves as the starting point <span class="code-keyword">for</span> Sling.
 * &lt;ul&gt;
 * &lt;li&gt;The {@link #Sling(Logger, ResourceProvider, Map)} method launches
 * Apache &lt;code&gt;Felix&lt;/code&gt; as the OSGi framework implementation we use.
 * &lt;/ul&gt;
 * &lt;p&gt;
 * &lt;b&gt;Launch Configuration&lt;/b&gt;
 * &lt;p&gt;
 * The Apache &lt;code&gt;Felix&lt;/code&gt; framework requires configuration parameters
 * to be specified <span class="code-keyword">for</span> startup. This servlet builds the list of parameters from
 * three locations:
 * &lt;ol&gt;
 * &lt;li&gt;The &lt;code&gt;com/day/osgi/servlet/Sling.properties&lt;/code&gt; is read from
 * the servlet class path. This properties file contains <span class="code-keyword">default</span> settings.&lt;/li&gt;
 * &lt;li&gt;Extensions of <span class="code-keyword">this</span> servlet may provide additional properties to be
 * loaded overwriting the {@link #loadPropertiesOverride(Map)} method.
 * &lt;li&gt;Finally, web application init parameters are added to the properties and
 * may overwrite existing properties of the same name(s).
 * &lt;/ol&gt;
 * &lt;p&gt;
 * After loading all properties, variable substitution takes place on the
 * property values. A variable is indicated as &lt;code&gt;${&amp;lt;prop-name&amp;gt;}&lt;/code&gt;
 * where &lt;code&gt;&amp;lt;prop-name&amp;gt;&lt;/code&gt; is the name of a system or
 * configuration property (configuration properties override system properties).
 * Variables may be nested and are resolved from <span class="code-keyword">inner</span>-most to <span class="code-keyword">outer</span>-most. For
 * example, the property value &lt;code&gt;${<span class="code-keyword">outer</span>-${<span class="code-keyword">inner</span>}}&lt;/code&gt; is resolved by
 * first resolving &lt;code&gt;${<span class="code-keyword">inner</span>}&lt;/code&gt; and then resolving the property whose
 * name is the catenation of &lt;code&gt;<span class="code-keyword">outer</span>-&lt;/code&gt; and the result of resolving
 * &lt;code&gt;${<span class="code-keyword">inner</span>}&lt;/code&gt;.
 * &lt;p&gt;
 */
<span class="code-keyword">public</span> class Sling <span class="code-keyword">implements</span> BundleActivator {

    /** Pseduo class version ID to keep the IDE quite. */
    <span class="code-keyword">private</span> <span class="code-keyword">static</span> <span class="code-keyword">final</span> <span class="code-object">long</span> serialVersionUID = 1L;

    /**
     * The name of the configuration property defining the Sling home directory
     * (value is <span class="code-quote">"sling.home"</span>). This is a Platform file system directory below
     * which all runtime data, such as the Felix bundle archives, logfiles, CRX
     * repository, etc., is located.
     * &lt;p&gt;
     * The value of <span class="code-keyword">this</span> property, <span class="code-keyword">if</span> not set as a system property defaults to
     * the &lt;i&gt;sling&lt;/i&gt; directory in the current working directory.
     *
     * @see #SLING_HOME_URL
     */
    <span class="code-keyword">public</span> <span class="code-keyword">static</span> <span class="code-keyword">final</span> <span class="code-object">String</span> SLING_HOME = <span class="code-quote">"sling.home"</span>;

    /**
     * The name of the configuration property defining the Sling home directory
     * as an URL (value is <span class="code-quote">"sling.home.url"</span>).
     * &lt;p&gt;
     * The value of <span class="code-keyword">this</span> property is assigned the value of
     * &lt;code&gt;<span class="code-keyword">new</span> File(${sling.home}).toURI().toString()&lt;/code&gt; before
     * resolving the property variables.
     *
     * @see #SLING_HOME
     */
    <span class="code-keyword">public</span> <span class="code-keyword">static</span> <span class="code-keyword">final</span> <span class="code-object">String</span> SLING_HOME_URL = <span class="code-quote">"sling.home.url"</span>;

    /**
     * The name of the configuration property defining a properties file
     * defining a list of bundles, which are installed into the framework when
     * it has been launched (value is <span class="code-quote">"org.apache.osgi.bundles"</span>).
     * &lt;p&gt;
     * This configuration property is generally set in the web application
     * configuration and may be referenced in all property files (<span class="code-keyword">default</span>, user
     * supplied and web application parameters) used to build the framework
     * configuration.
     */
    <span class="code-keyword">public</span> <span class="code-keyword">static</span> <span class="code-keyword">final</span> <span class="code-object">String</span> OSGI_FRAMEWORK_BUNDLES = <span class="code-quote">"org.apache.osgi.bundles"</span>;

    /**
     * The property to be set to ignore the system properties when building the
     * Felix framework properties (value is <span class="code-quote">"sling.ignoreSystemProperties"</span>). If
     * <span class="code-keyword">this</span> is property is set to &lt;code&gt;<span class="code-keyword">true</span>&lt;/code&gt; (<span class="code-keyword">case</span> does not matter),
     * the system properties will not be used by
     * {@link #loadConfigProperties(Map)}.
     */
    <span class="code-keyword">public</span> <span class="code-keyword">static</span> <span class="code-keyword">final</span> <span class="code-object">String</span> SLING_IGNORE_SYSTEM_PROPERTIES = <span class="code-quote">"sling.ignoreSystemProperties"</span>;

    /**
     * The name of the <span class="code-keyword">default</span> launcher properties file to setup the environment
     * <span class="code-keyword">for</span> the &lt;code&gt;Felix&lt;/code&gt; framework (value is <span class="code-quote">"sling.properties"</span>).
     * &lt;p&gt;
     * Extensions of <span class="code-keyword">this</span> class may overwrite some or all properties in <span class="code-keyword">this</span>
     * file through Web Application parameters or other properties files.
     */
    <span class="code-keyword">public</span> <span class="code-keyword">static</span> <span class="code-keyword">final</span> <span class="code-object">String</span> CONFIG_PROPERTIES = <span class="code-quote">"sling.properties"</span>;

    <span class="code-keyword">public</span> <span class="code-keyword">static</span> <span class="code-keyword">final</span> <span class="code-object">String</span> PROP_SYSTEM_PACKAGES = <span class="code-quote">"org.apache.sling.launcher.system.packages"</span>;

    /**
     * The simple logger to log messages during startup and shutdown to
     */
    <span class="code-keyword">protected</span> <span class="code-keyword">final</span> Logger logger;

    <span class="code-keyword">private</span> ResourceProvider resourceProvider;

    /**
     * The &lt;code&gt;Felix&lt;/code&gt; instance loaded on {@link #init()} and stopped
     * on {@link #destroy()}.
     */
    <span class="code-keyword">private</span> Felix felix;

    /**
     * The &lt;code&gt;BundleContext&lt;/code&gt; of the OSGi framework system bundle.
     * This is used <span class="code-keyword">for</span> service registration and service access to get at the
     * delegatee servlet.
     */
    <span class="code-keyword">private</span> BundleContext bundleContext;

    /**
     * Initializes <span class="code-keyword">this</span> servlet by loading the framework configuration
     * properties, starting the OSGi framework (Apache Felix) and exposing the
     * system bundle context and the &lt;code&gt;Felix&lt;/code&gt; instance as servlet
     * context attributes.
     *
     * @<span class="code-keyword">throws</span> BundleException <span class="code-keyword">if</span> the framework cannot be initialized.
     */
    <span class="code-keyword">public</span> Sling(Logger logger, ResourceProvider resourceProvider,
            Map&lt;<span class="code-object">String</span>, <span class="code-object">String</span>&gt; propOverwrite) <span class="code-keyword">throws</span> BundleException {

        <span class="code-keyword">this</span>.logger = logger;
        <span class="code-keyword">this</span>.resourceProvider = resourceProvider;

        <span class="code-keyword">this</span>.logger.log(Logger.LOG_INFO, <span class="code-quote">"Starting Sling"</span>);

        <span class="code-comment">// read the <span class="code-keyword">default</span> parameters
</span>        Map&lt;<span class="code-object">String</span>, <span class="code-object">String</span>&gt; props = <span class="code-keyword">this</span>.loadConfigProperties(propOverwrite);

        <span class="code-comment">// check <span class="code-keyword">for</span> auto-start bundles
</span>        <span class="code-keyword">this</span>.setInstallBundles(props);

        <span class="code-comment">// ensure execution environment
</span>        <span class="code-keyword">this</span>.setExecutionEnvironment(props);

        <span class="code-comment">// make sure Felix does not exit the VM when terminating ...
</span>        props.put(EMBEDDED_EXECUTION_PROP, <span class="code-quote">"<span class="code-keyword">true</span>"</span>);

        <span class="code-comment">// the custom activator list just contains <span class="code-keyword">this</span> servlet
</span>        List&lt;BundleActivator&gt; activators = <span class="code-keyword">new</span> ArrayList&lt;BundleActivator&gt;();
        activators.add(<span class="code-keyword">this</span>);
        activators.add(<span class="code-keyword">new</span> BootstrapInstaller(logger, resourceProvider));

        <span class="code-comment">// create the framework and start it
</span>        Felix tmpFelix = <span class="code-keyword">new</span> Felix(logger, props, activators);
        tmpFelix.start();

        <span class="code-comment">// only assign field <span class="code-keyword">if</span> start succeeds
</span>        <span class="code-keyword">this</span>.felix = tmpFelix;

        <span class="code-comment">// log sucess message
</span>        <span class="code-keyword">this</span>.logger.log(Logger.LOG_INFO, <span class="code-quote">"Sling started"</span>);
    }

    /**
     * Destroys <span class="code-keyword">this</span> servlet by shutting down the OSGi framework and hence the
     * delegatee servlet <span class="code-keyword">if</span> one is set at all.
     */
    <span class="code-keyword">public</span> <span class="code-keyword">final</span> void destroy() {
        <span class="code-comment">// shutdown the Felix container
</span>        <span class="code-keyword">if</span> (felix != <span class="code-keyword">null</span>) {
            logger.log(Logger.LOG_INFO, <span class="code-quote">"Shutting down Sling"</span>);
            felix.stopAndWait();
            logger.log(Logger.LOG_INFO, <span class="code-quote">"Sling stopped"</span>);
            felix = <span class="code-keyword">null</span>;
        }
    }

    <span class="code-comment">// ---------- BundleActivator ----------------------------------------------
</span>
    /**
     * Called when the OSGi framework is being started. This implementation
     * registers as a service listener <span class="code-keyword">for</span> the
     * &lt;code&gt;javax.servlet.Servlet&lt;/code&gt; class and calls the
     * {@link #doStartBundle()} method <span class="code-keyword">for</span> implementations to execute more
     * startup tasks. Additionally the &lt;code&gt;context&lt;/code&gt; URL protocol
     * handler is registered.
     *
     * @param bundleContext The &lt;code&gt;BundleContext&lt;/code&gt; of the system
     *            bundle of the OSGi framework.
     * @<span class="code-keyword">throws</span> Exception May be thrown <span class="code-keyword">if</span> the {@link #doStartBundle()} <span class="code-keyword">throws</span>.
     */
    <span class="code-keyword">public</span> <span class="code-keyword">final</span> void start(BundleContext bundleContext) <span class="code-keyword">throws</span> Exception {
        <span class="code-keyword">this</span>.bundleContext = bundleContext;

        <span class="code-comment">// register the context URL handler
</span>        Hashtable&lt;<span class="code-object">String</span>, <span class="code-object">Object</span>&gt; props = <span class="code-keyword">new</span> Hashtable&lt;<span class="code-object">String</span>, <span class="code-object">Object</span>&gt;();
        props.put(URLConstants.URL_HANDLER_PROTOCOL, <span class="code-keyword">new</span> <span class="code-object">String</span>[] { <span class="code-quote">"context"</span> });
        ContextProtocolHandler contextHandler = <span class="code-keyword">new</span> ContextProtocolHandler(
            <span class="code-keyword">this</span>.resourceProvider);
        bundleContext.registerService(URLStreamHandlerService.class.getName(),
            contextHandler, props);

        <span class="code-comment">// execute optional bundle startup tasks of an extension
</span>        <span class="code-keyword">this</span>.doStartBundle();
    }

    /**
     * Called when the OSGi framework is being shut down. This implementation
     * first calls the {@link #doStopBundle()} method method before
     * unregistering as a service listener and ungetting an servlet delegatee <span class="code-keyword">if</span>
     * one has been acquired.
     *
     * @param bundleContext The &lt;code&gt;BundleContext&lt;/code&gt; of the system
     *            bundle of the OSGi framework.
     */
    <span class="code-keyword">public</span> <span class="code-keyword">final</span> void stop(BundleContext bundleContext) {
        <span class="code-comment">// execute optional bundle stop tasks of an extension
</span>        <span class="code-keyword">try</span> {
            <span class="code-keyword">this</span>.doStopBundle();
        } <span class="code-keyword">catch</span> (Exception e) {
            <span class="code-keyword">this</span>.logger.log(Logger.LOG_ERROR, <span class="code-quote">"Unexpected exception caught"</span>, e);
        }

        <span class="code-comment">// drop bundle context reference
</span>        <span class="code-keyword">this</span>.bundleContext = <span class="code-keyword">null</span>;
    }

    <span class="code-comment">// ---------- Configuration Loading ----------------------------------------
</span>
    /**
     * Loads the configuration properties in the configuration property file
     * associated with the framework installation; these properties are
     * accessible to the framework and to bundles and are intended <span class="code-keyword">for</span>
     * configuration purposes. By <span class="code-keyword">default</span>, the configuration property file is
     * located in the &lt;tt&gt;conf/&lt;/tt&gt; directory of the Felix installation
     * directory and is called <span class="code-quote">"&lt;tt&gt;config.properties&lt;/tt&gt;"</span>. The
     * installation directory of Felix is assumed to be the parent directory of
     * the &lt;tt&gt;felix.jar&lt;/tt&gt; file as found on the system class path property.
     * The precise file from which to load configuration properties can be set
     * by initializing the <span class="code-quote">"&lt;tt&gt;felix.config.properties&lt;/tt&gt;"</span> system
     * property to an arbitrary URL.
     *
     * @<span class="code-keyword">return</span> A &lt;tt&gt;Properties&lt;/tt&gt; instance or &lt;tt&gt;<span class="code-keyword">null</span>&lt;/tt&gt; <span class="code-keyword">if</span> there was
     *         an error.
     */
    <span class="code-keyword">private</span> Map&lt;<span class="code-object">String</span>, <span class="code-object">String</span>&gt; loadConfigProperties(
            Map&lt;<span class="code-object">String</span>, <span class="code-object">String</span>&gt; propOverwrite) <span class="code-keyword">throws</span> BundleException {
        <span class="code-comment">// The config properties file is either specified by a system
</span>        <span class="code-comment">// property or it is in the same directory as the Felix JAR file.
</span>        <span class="code-comment">// Try to load it from one of these places.
</span>        Map&lt;<span class="code-object">String</span>, <span class="code-object">String</span>&gt; props = <span class="code-keyword">new</span> HashMap&lt;<span class="code-object">String</span>, <span class="code-object">String</span>&gt;();

        <span class="code-comment">// Read the properties file.
</span>        <span class="code-keyword">this</span>.load(props, CONFIG_PROPERTIES);

        <span class="code-comment">// resolve inclusions (and remove property)
</span>        <span class="code-keyword">this</span>.loadIncludes(props, <span class="code-keyword">null</span>);

        <span class="code-comment">// overwrite <span class="code-keyword">default</span> properties with initial overwrites
</span>        <span class="code-keyword">if</span> (propOverwrite != <span class="code-keyword">null</span>) {
            props.putAll(propOverwrite);
        }

        <span class="code-comment">// check whether sling.home is overwritten by system property
</span>        <span class="code-object">String</span> slingHome = <span class="code-object">System</span>.getProperty(SLING_HOME);
        <span class="code-keyword">if</span> (slingHome == <span class="code-keyword">null</span> || slingHome.length() == 0) {

            <span class="code-comment">// no system property, ensure <span class="code-keyword">default</span> setting
</span>            slingHome = props.get(SLING_HOME);
            <span class="code-keyword">if</span> (slingHome == <span class="code-keyword">null</span> || slingHome.length() == 0) {
                slingHome = <span class="code-quote">"sling"</span>;
                <span class="code-keyword">this</span>.logger.log(Logger.LOG_INFO,
                    <span class="code-quote">"sling.home is not defined. Using '"</span> + slingHome + <span class="code-quote">"'"</span>);
            }
        }

        <span class="code-comment">// resolve variables and ensure sling.home is an absolute path
</span>        slingHome = substVars(slingHome, SLING_HOME, <span class="code-keyword">null</span>, props);
        File slingHomeFile = <span class="code-keyword">new</span> File(slingHome).getAbsoluteFile();
        slingHome = slingHomeFile.getAbsolutePath();

        <span class="code-comment">// overlay with ${sling.home}/sling.properties
</span>        <span class="code-keyword">this</span>.logger.log(Logger.LOG_INFO, <span class="code-quote">"Starting sling in "</span> + slingHome);
        File propFile = <span class="code-keyword">new</span> File(slingHome, CONFIG_PROPERTIES);
        <span class="code-keyword">this</span>.load(props, propFile);

        <span class="code-comment">// create a copy of the properties to perform variable substitution
</span>        Map&lt;<span class="code-object">String</span>, <span class="code-object">String</span>&gt; origProps = props;
        props = <span class="code-keyword">new</span> HashMap&lt;<span class="code-object">String</span>, <span class="code-object">String</span>&gt;();
        props.putAll(origProps);

        <span class="code-comment">// check system properties <span class="code-keyword">for</span> any overrides (except sling.home !)
</span>        <span class="code-object">String</span> ignoreSystemProperties = props.get(SLING_IGNORE_SYSTEM_PROPERTIES);
        <span class="code-keyword">if</span> (!<span class="code-quote">"<span class="code-keyword">true</span>"</span>.equalsIgnoreCase(ignoreSystemProperties)) {
            <span class="code-keyword">for</span> (<span class="code-object">String</span> name : props.keySet()) {
                <span class="code-object">String</span> sysProp = <span class="code-object">System</span>.getProperty(name);
                <span class="code-keyword">if</span> (sysProp != <span class="code-keyword">null</span>) {
                    props.put(name, sysProp);
                }
            }
        }

        <span class="code-comment">// resolve inclusions again
</span>        <span class="code-keyword">this</span>.loadIncludes(props, slingHome);

        <span class="code-comment">// overwrite properties, <span class="code-keyword">this</span> is not persisted as such
</span>        <span class="code-keyword">this</span>.loadPropertiesOverride(props);

        <span class="code-comment">// resolve boot delegation and system packages
</span>        <span class="code-keyword">this</span>.resolve(props, <span class="code-quote">"org.osgi.framework.bootdelegation"</span>,
            <span class="code-quote">"sling.bootdelegation."</span>);
        <span class="code-keyword">this</span>.resolve(props, <span class="code-quote">"org.osgi.framework.system.packages"</span>,
            <span class="code-quote">"sling.system.packages."</span>);

        <span class="code-comment">// reset back the sling home property
</span>        <span class="code-comment">// might have been overwritten by system properties, included
</span>        <span class="code-comment">// files or the sling.properties file
</span>        origProps.put(SLING_HOME, slingHome);
        props.put(SLING_HOME, slingHome);
        props.put(SLING_HOME_URL, slingHomeFile.toURI().toString());

        <span class="code-comment">// Perform variable substitution <span class="code-keyword">for</span> system properties.
</span>        <span class="code-keyword">for</span> (Entry&lt;<span class="code-object">String</span>, <span class="code-object">String</span>&gt; entry : props.entrySet()) {
            entry.setValue(substVars(entry.getValue(), entry.getKey(), <span class="code-keyword">null</span>,
                props));
        }

        <span class="code-comment">// look <span class="code-keyword">for</span> context:/ URLs to substitute
</span>        <span class="code-keyword">for</span> (Entry&lt;<span class="code-object">String</span>, <span class="code-object">String</span>&gt; entry : props.entrySet()) {
            <span class="code-object">String</span> name = entry.getKey();
            <span class="code-object">String</span> value = entry.getValue();
            <span class="code-keyword">if</span> (value != <span class="code-keyword">null</span> &amp;&amp; value.startsWith(<span class="code-quote">"context:/"</span>)) {
                <span class="code-object">String</span> path = value.substring(<span class="code-quote">"context:/"</span>.length() - 1);

                InputStream src = <span class="code-keyword">this</span>.resourceProvider.getResourceAsStream(path);
                <span class="code-keyword">if</span> (src != <span class="code-keyword">null</span>) {
                    File target = <span class="code-keyword">new</span> File(slingHome, path);
                    OutputStream dest = <span class="code-keyword">null</span>;
                    <span class="code-keyword">try</span> {
                        <span class="code-comment">// only copy file <span class="code-keyword">if</span> not existing
</span>                        <span class="code-keyword">if</span> (!target.exists()) {
                            target.getParentFile().mkdirs();
                            dest = <span class="code-keyword">new</span> FileOutputStream(target);
                            <span class="code-object">byte</span>[] buf = <span class="code-keyword">new</span> <span class="code-object">byte</span>[2048];
                            <span class="code-object">int</span> rd;
                            <span class="code-keyword">while</span> ((rd = src.read(buf)) &gt;= 0) {
                                dest.write(buf, 0, rd);
                            }
                        }

                        <span class="code-comment">// after copying replace property and add url property
</span>                        entry.setValue(target.getAbsolutePath());

                        <span class="code-comment">// also set the <span class="code-keyword">new</span> property on the unsubstituted props
</span>                        origProps.put(name, <span class="code-quote">"${sling.home}"</span> + path);

                    } <span class="code-keyword">catch</span> (IOException ioe) {
                        <span class="code-keyword">this</span>.logger.log(Logger.LOG_ERROR, <span class="code-quote">"Cannot copy file "</span>
                            + value + <span class="code-quote">" to "</span> + target, ioe);
                    } <span class="code-keyword">finally</span> {
                        <span class="code-keyword">if</span> (dest != <span class="code-keyword">null</span>) {
                            <span class="code-keyword">try</span> {
                                dest.close();
                            } <span class="code-keyword">catch</span> (IOException ignore) {
                            }
                        }
                        <span class="code-keyword">try</span> {
                            src.close();
                        } <span class="code-keyword">catch</span> (IOException ignore) {
                        }
                    }
                }
            }
        }

        <span class="code-comment">// write the unsubstituted properties back to the overlay file
</span>        OutputStream os = <span class="code-keyword">null</span>;
        <span class="code-keyword">try</span> {
            <span class="code-comment">// ensure parent folder(s)
</span>            propFile.getParentFile().mkdirs();

            os = <span class="code-keyword">new</span> FileOutputStream(propFile);

            <span class="code-comment">// copy the values into a temporary properties structure to store
</span>            Properties tmp = <span class="code-keyword">new</span> Properties();
            tmp.putAll(origProps);
            tmp.store(os, <span class="code-quote">"Overlay properties <span class="code-keyword">for</span> configuration"</span>);
        } <span class="code-keyword">catch</span> (Exception ex) {
            <span class="code-keyword">this</span>.logger.log(Logger.LOG_ERROR,
                <span class="code-quote">"Error loading overlay properties from "</span> + propFile, ex);
        } <span class="code-keyword">finally</span> {
            <span class="code-keyword">if</span> (os != <span class="code-keyword">null</span>) {
                <span class="code-keyword">try</span> {
                    os.close();
                } <span class="code-keyword">catch</span> (IOException ex2) {
                    <span class="code-comment">// Nothing we can <span class="code-keyword">do</span>.
</span>                }
            }
        }

        <span class="code-keyword">return</span> props;
    }

    /**
     * Scans the properties <span class="code-keyword">for</span> any properties starting with the given
     * &lt;code&gt;prefix&lt;/code&gt; (e.g. &lt;code&gt;sling.bootdelegation.&lt;/code&gt;).
     * &lt;ol&gt;
     * &lt;li&gt;Each such property is checked, whether it actually starts with
     * &lt;code&gt;prefix&lt;b&gt;class.&lt;/b&gt;&lt;/code&gt;. If so, the <span class="code-keyword">rest</span> of the property
     * name is assumed to be a fully qualified class name which is check,
     * whether it is visible. If so, the value of the property is appended to
     * the value of the &lt;code&gt;osgiProp&lt;/code&gt;. If the class cannot be loaded,
     * the property is ignored.
     * &lt;li&gt;Otherwise, <span class="code-keyword">if</span> the property does not contain a fully qualified class
     * name, the value of the property is simply appended to the
     * &lt;code&gt;osgiProp&lt;/code&gt;.
     * &lt;/ol&gt;
     *
     * @param props The &lt;code&gt;Properties&lt;/code&gt; to be scanned.
     * @param osgiProp The name of the property in &lt;code&gt;props&lt;/code&gt; to which
     *            any matching property values are appended.
     * @param prefix The prefix of properties to handle.
     */
    <span class="code-keyword">private</span> void resolve(Map&lt;<span class="code-object">String</span>, <span class="code-object">String</span>&gt; props, <span class="code-object">String</span> osgiProp,
            <span class="code-object">String</span> prefix) {
        <span class="code-keyword">final</span> <span class="code-object">String</span> propVal = props.get(osgiProp);
        <span class="code-object">StringBuffer</span> prop = <span class="code-keyword">new</span> <span class="code-object">StringBuffer</span>(propVal == <span class="code-keyword">null</span> ? "" : propVal);
        <span class="code-object">boolean</span> mod = <span class="code-keyword">false</span>;
        <span class="code-keyword">for</span> (Entry&lt;<span class="code-object">String</span>, <span class="code-object">String</span>&gt; pEntry : props.entrySet()) {
            <span class="code-object">String</span> key = pEntry.getKey();
            <span class="code-keyword">if</span> (key.startsWith(prefix)) {
                <span class="code-keyword">if</span> (key.indexOf(<span class="code-quote">"class."</span>) == prefix.length()) {
                    <span class="code-comment">// prefix is followed by checker class name
</span>                    <span class="code-object">String</span> className = key.substring(prefix.length()
                        + <span class="code-quote">"class."</span>.length());
                    <span class="code-keyword">try</span> {
                        <span class="code-object">Class</span>.forName(className, <span class="code-keyword">true</span>,
                            <span class="code-keyword">this</span>.getClass().getClassLoader());
                    } <span class="code-keyword">catch</span> (Throwable t) {
                        <span class="code-comment">// don't really care, but class checking failed, so we
</span>                        <span class="code-comment">// <span class="code-keyword">do</span> not add
</span>                        <span class="code-keyword">this</span>.logger.log(Logger.LOG_DEBUG, <span class="code-quote">"<span class="code-object">Class</span> "</span> + className
                            + <span class="code-quote">" not found. Ignoring '"</span> + pEntry.getValue()
                            + <span class="code-quote">"' <span class="code-keyword">for</span> property "</span> + osgiProp);
                        <span class="code-keyword">continue</span>;
                    }
                }

                <span class="code-comment">// get here <span class="code-keyword">if</span> class is known or no checker class
</span>                <span class="code-keyword">this</span>.logger.log(Logger.LOG_DEBUG, <span class="code-quote">"Adding '"</span>
                    + pEntry.getValue() + <span class="code-quote">"' to property "</span> + osgiProp);
                <span class="code-keyword">if</span> (prop.length() &gt; 0) {
                    prop.append(',');
                }
                prop.append(pEntry.getValue());
                mod = <span class="code-keyword">true</span>;
            }
        }

        <span class="code-comment">// replace the property with the modified property
</span>        <span class="code-keyword">if</span> (mod) {
            <span class="code-keyword">this</span>.logger.log(Logger.LOG_DEBUG, <span class="code-quote">"Setting property "</span> + osgiProp
                + <span class="code-quote">" to "</span> + prop.toString());
            props.put(osgiProp, prop.toString());
        }
    }

    <span class="code-keyword">private</span> void setInstallBundles(Map&lt;<span class="code-object">String</span>, <span class="code-object">String</span>&gt; props) {
        <span class="code-object">String</span> prefix = <span class="code-quote">"sling.install."</span>;
        Set&lt;<span class="code-object">String</span>&gt; levels = <span class="code-keyword">new</span> TreeSet&lt;<span class="code-object">String</span>&gt;();
        <span class="code-keyword">for</span> (<span class="code-object">String</span> key : props.keySet()) {
            <span class="code-keyword">if</span> (key.startsWith(prefix)) {
                levels.add(key.substring(prefix.length()));
            }
        }

        <span class="code-object">StringBuffer</span> buf = <span class="code-keyword">new</span> <span class="code-object">StringBuffer</span>();
        <span class="code-keyword">for</span> (<span class="code-object">String</span> level : levels) {
            <span class="code-keyword">if</span> (buf.length() &gt; 0) {
                buf.append(',');
            }
            buf.append(level);
        }

        props.put(prefix + <span class="code-quote">"bundles"</span>, buf.toString());
    }

    /**
     * Ensures sensible Execution Environment setting. If the
     * &lt;code&gt;org.osgi.framework.executionenvironment&lt;/code&gt; property is set in
     * the configured properties or the system properties, we ensure that older
     * settings <span class="code-keyword">for</span> J2SE-1.2, J2SE-1.3 and J2SE-1.4 are included. If the
     * property is neither set in the configuration properties nor in the system
     * properties, the property is not set.
     *
     * @param props The configuration properties to check and optionally ammend.
     */
    <span class="code-keyword">private</span> void setExecutionEnvironment(Map&lt;<span class="code-object">String</span>, <span class="code-object">String</span>&gt; props) {
        <span class="code-comment">// get the current Execution Environment setting
</span>        <span class="code-object">String</span> ee = props.get(Constants.FRAMEWORK_EXECUTIONENVIRONMENT);
        <span class="code-keyword">if</span> (ee == <span class="code-keyword">null</span>) {
            ee = <span class="code-object">System</span>.getProperty(Constants.FRAMEWORK_EXECUTIONENVIRONMENT);
        }

        <span class="code-comment">// <span class="code-keyword">if</span> there is a setting, ensure J2SE-1.2/3/4/5 is included in the list
</span>        <span class="code-keyword">if</span> (ee != <span class="code-keyword">null</span>) {
            <span class="code-object">int</span> javaMinor;
            <span class="code-keyword">try</span> {
                <span class="code-object">String</span> specVString = <span class="code-object">System</span>.getProperty(<span class="code-quote">"java.specification.version"</span>);
                javaMinor = Version.parseVersion(specVString).getMinor();
            } <span class="code-keyword">catch</span> (IllegalArgumentException iae) {
                <span class="code-comment">// don't care, assume minimal sling version (1.5)
</span>                javaMinor = 5;
            }

            <span class="code-keyword">for</span> (<span class="code-object">int</span> i = 2; i &lt;= javaMinor; i++) {
                <span class="code-object">String</span> exEnv = <span class="code-quote">"J2SE-1."</span> + i;
                <span class="code-keyword">if</span> (ee.indexOf(exEnv) &lt; 0) {
                    ee += <span class="code-quote">","</span> + exEnv;
                }
            }

            <span class="code-keyword">this</span>.logger.log(Logger.LOG_INFO,
                <span class="code-quote">"Using Execution Environment setting: "</span> + ee);
            props.put(Constants.FRAMEWORK_EXECUTIONENVIRONMENT, ee);
        } <span class="code-keyword">else</span> {
            <span class="code-keyword">this</span>.logger.log(Logger.LOG_INFO,
                <span class="code-quote">"Not using Execution Environment setting"</span>);
        }
    }

    <span class="code-comment">// ---------- Extension support --------------------------------------------
</span>
    /**
     * Loads additional properties into the &lt;code&gt;properties&lt;/code&gt; object.
     * &lt;p&gt;
     * This implementation does nothing and may be overwritten by extensions
     * requiring additional properties to be set.
     * &lt;p&gt;
     * This method is called when the servlet is initialized to prepare the
     * configuration <span class="code-keyword">for</span> &lt;code&gt;Felix&lt;/code&gt;. Implementations may add
     * properties from implementation specific sources. Properties added here
     * overwrite properties loaded from the <span class="code-keyword">default</span> properties file and may be
     * overwritten by parameters set in the web application.
     * &lt;p&gt;
     * The &lt;code&gt;properties&lt;/code&gt; object has not undergone variable
     * substition and properties added by <span class="code-keyword">this</span> method may also contain values
     * refererring to other properties.
     * &lt;p&gt;
     * The properties added in <span class="code-keyword">this</span> method will not be persisted in the
     * &lt;code&gt;sling.properties&lt;/code&gt; file in the &lt;code&gt;sling.home&lt;/code&gt;
     * directory.
     *
     * @param properties The &lt;code&gt;Properties&lt;/code&gt; object to which custom
     *            properties may be added.
     */
    <span class="code-keyword">protected</span> void loadPropertiesOverride(Map&lt;<span class="code-object">String</span>, <span class="code-object">String</span>&gt; properties) {
    }

    /**
     * Returns the &lt;code&gt;BundleContext&lt;/code&gt; of the system bundle of the OSGi
     * framework launched by <span class="code-keyword">this</span> servlet. This method only returns a non-&lt;code&gt;<span class="code-keyword">null</span>&lt;/code&gt;
     * object after the system bundle of the framework has been started and
     * before it is being stopped.
     */
    <span class="code-keyword">protected</span> <span class="code-keyword">final</span> BundleContext getBundleContext() {
        <span class="code-keyword">return</span> <span class="code-keyword">this</span>.bundleContext;
    }

    /**
     * Executes additional startup tasks and is called by the
     * {@link #start(BundleContext)} method.
     * &lt;p&gt;
     * This implementation does nothing and may be overwritten by extensions
     * requiring additional startup tasks.
     *
     * @<span class="code-keyword">throws</span> Exception May be thrown in <span class="code-keyword">case</span> of problems.
     */
    <span class="code-keyword">protected</span> void doStartBundle() <span class="code-keyword">throws</span> Exception {
    }

    /**
     * Executes additional shutdown tasks and is called by the
     * {@link #stop(BundleContext)} method.
     * &lt;p&gt;
     * This implementation does nothing and may be overwritten by extensions
     * requiring additional shutdown tasks.
     * &lt;p&gt;
     * When overwriting <span class="code-keyword">this</span> method, it must be made sure, that no exception may
     * be thrown, otherwise unexpected behaviour may result.
     */
    <span class="code-keyword">protected</span> void doStopBundle() {
    }

    <span class="code-comment">// ---------- Property file support ----------------------------------------
</span>
    /**
     * Looks <span class="code-keyword">for</span> &lt;code&gt;sling.include&lt;/code&gt; and &lt;code&gt;sling.include.*&lt;/code&gt;
     * properties in the &lt;code&gt;props&lt;/code&gt; and loads properties form the
     * respective locations.
     * &lt;p&gt;
     * Each &lt;code&gt;sling.include&lt;/code&gt; (or &lt;code&gt;sling.include.*&lt;/code&gt;)
     * property may contain a comma-separated list of resource and/or file names
     * to be loaded from. The includes are loaded in alphabetical order of the
     * property names.
     * &lt;p&gt;
     * Each reasource path is first tried to be loaded through the
     * {@link #resourceProvider}. If that fails, the resource path is tested as
     * a file. If relative &lt;code&gt;slingHome&lt;/code&gt; is used as the parent <span class="code-keyword">if</span> not
     * &lt;code&gt;<span class="code-keyword">null</span>&lt;/code&gt;, otherwise the current working directory is used as
     * the parent.
     * &lt;p&gt;
     * Any non-existing resource is silently ignored.
     * &lt;p&gt;
     * When the method returns, the &lt;code&gt;sling.include&lt;/code&gt; and
     * &lt;code&gt;sling.include.*&lt;/code&gt; properties are not contained in the
     * &lt;code&gt;props&lt;/code&gt; any more.
     *
     * @param props The &lt;code&gt;Properties&lt;/code&gt; containing the
     *            &lt;code&gt;sling.include&lt;/code&gt; and &lt;code&gt;sling.include.*&lt;/code&gt;
     *            properties. This is also the destination <span class="code-keyword">for</span> the <span class="code-keyword">new</span>
     *            properties loaded.
     * @param slingHome The parent directory used to resolve relative path names
     *            <span class="code-keyword">if</span> loading from a file. This may be &lt;code&gt;<span class="code-keyword">null</span>&lt;/code&gt; in
     *            which <span class="code-keyword">case</span> the current working directory is used as the
     *            parent.
     */
    <span class="code-keyword">private</span> void loadIncludes(Map&lt;<span class="code-object">String</span>, <span class="code-object">String</span>&gt; props, <span class="code-object">String</span> slingHome) {
        <span class="code-comment">// Build the sort map of include properties first
</span>        <span class="code-comment">// and remove include elements from the properties
</span>        SortedMap&lt;<span class="code-object">String</span>, <span class="code-object">String</span>&gt; includes = <span class="code-keyword">new</span> TreeMap&lt;<span class="code-object">String</span>, <span class="code-object">String</span>&gt;();
        <span class="code-keyword">for</span> (Iterator&lt;Entry&lt;<span class="code-object">String</span>, <span class="code-object">String</span>&gt;&gt; pi = props.entrySet().iterator(); pi.hasNext();) {
            Entry&lt;<span class="code-object">String</span>, <span class="code-object">String</span>&gt; entry = pi.next();
            <span class="code-keyword">if</span> (entry.getKey().startsWith(<span class="code-quote">"sling.include."</span>)
                || entry.getKey().equals(<span class="code-quote">"sling.include"</span>)) {
                includes.put(entry.getKey(), entry.getValue());
                pi.remove();
            }
        }

        <span class="code-keyword">for</span> (Iterator&lt;Entry&lt;<span class="code-object">String</span>, <span class="code-object">String</span>&gt;&gt; ii = includes.entrySet().iterator(); ii.hasNext();) {
            Map.Entry&lt;<span class="code-object">String</span>, <span class="code-object">String</span>&gt; entry = ii.next();
            <span class="code-object">String</span> key = entry.getKey();
            <span class="code-object">String</span> include = entry.getValue();

            <span class="code-comment">// ensure variable resolution on <span class="code-keyword">this</span> property
</span>            include = substVars(include, key, <span class="code-keyword">null</span>, props);

            StringTokenizer tokener = <span class="code-keyword">new</span> StringTokenizer(include, <span class="code-quote">","</span>);
            <span class="code-keyword">while</span> (tokener.hasMoreTokens()) {
                <span class="code-object">String</span> file = tokener.nextToken().trim();
                InputStream is = <span class="code-keyword">this</span>.resourceProvider.getResourceAsStream(file);
                <span class="code-keyword">try</span> {
                    <span class="code-keyword">if</span> (is == <span class="code-keyword">null</span> &amp;&amp; slingHome != <span class="code-keyword">null</span>) {
                        File resFile = <span class="code-keyword">new</span> File(file);
                        <span class="code-keyword">if</span> (!resFile.isAbsolute()) {
                            resFile = <span class="code-keyword">new</span> File(slingHome, file);
                        }
                        <span class="code-keyword">if</span> (resFile.canRead()) {
                            is = <span class="code-keyword">new</span> FileInputStream(resFile);
                            file = resFile.getAbsolutePath(); <span class="code-comment">// <span class="code-keyword">for</span> logging
</span>                        }
                    }

                    <span class="code-keyword">if</span> (is != <span class="code-keyword">null</span>) {
                        <span class="code-keyword">this</span>.load(props, is);
                    }
                } <span class="code-keyword">catch</span> (IOException ioe) {
                    <span class="code-keyword">this</span>.logger.log(Logger.LOG_ERROR,
                        <span class="code-quote">"Error loading config properties from "</span> + file, ioe);
                }
            }
        }
    }

    /**
     * Load properties from the given resource file, which is accessed through
     * the {@link #resourceProvider}. If the resource does not exist, nothing
     * is loaded.
     *
     * @param props The &lt;code&gt;Properties&lt;/code&gt; into which the loaded
     *            properties are loaded
     * @param resource The resource from which to load the resources
     */
    <span class="code-keyword">private</span> void load(Map&lt;<span class="code-object">String</span>, <span class="code-object">String</span>&gt; props, <span class="code-object">String</span> resource) {
        InputStream is = <span class="code-keyword">this</span>.resourceProvider.getResourceAsStream(resource);
        <span class="code-keyword">if</span> (is != <span class="code-keyword">null</span>) {
            <span class="code-keyword">try</span> {
                <span class="code-keyword">this</span>.load(props, is);
            } <span class="code-keyword">catch</span> (IOException ioe) {
                <span class="code-keyword">this</span>.logger.log(Logger.LOG_ERROR,
                    <span class="code-quote">"Error loading config properties from "</span> + resource, ioe);
            }
        }
    }

    /**
     * Load properties from the given file. If the resource cannot be read from
     * (e.g. because it does not exist), nothing is loaded.
     *
     * @param props The &lt;code&gt;Properties&lt;/code&gt; into which the loaded
     *            properties are loaded
     * @param file The &lt;code&gt;File&lt;/code&gt; to load the properties from
     */
    <span class="code-keyword">private</span> void load(Map&lt;<span class="code-object">String</span>, <span class="code-object">String</span>&gt; props, File file) {
        <span class="code-keyword">if</span> (file != <span class="code-keyword">null</span> &amp;&amp; file.canRead()) {
            <span class="code-keyword">try</span> {
                <span class="code-keyword">this</span>.load(props, <span class="code-keyword">new</span> FileInputStream(file));
            } <span class="code-keyword">catch</span> (IOException ioe) {
                <span class="code-keyword">this</span>.logger.log(Logger.LOG_ERROR,
                    <span class="code-quote">"Error loading config properties from "</span>
                        + file.getAbsolutePath(), ioe);
            }
        }
    }

    <span class="code-keyword">private</span> void load(Map&lt;<span class="code-object">String</span>, <span class="code-object">String</span>&gt; props, InputStream ins)
            <span class="code-keyword">throws</span> IOException {
        <span class="code-keyword">try</span> {
            Properties tmp = <span class="code-keyword">new</span> Properties();
            tmp.load(ins);

            <span class="code-keyword">for</span> (Map.Entry&lt;<span class="code-object">Object</span>, <span class="code-object">Object</span>&gt; entry : tmp.entrySet()) {
                props.put((<span class="code-object">String</span>) entry.getKey(), (<span class="code-object">String</span>) entry.getValue());
            }
        } <span class="code-keyword">finally</span> {
            <span class="code-keyword">try</span> {
                ins.close();
            } <span class="code-keyword">catch</span> (IOException ioe2) {
                <span class="code-comment">// ignore
</span>            }
        }
    }

    <span class="code-comment">// ---------- Property file variable substition support --------------------
</span>
    /**
     * The starting delimiter of variable names (value is <span class="code-quote">"${"</span>).
     */
    <span class="code-keyword">private</span> <span class="code-keyword">static</span> <span class="code-keyword">final</span> <span class="code-object">String</span> DELIM_START = <span class="code-quote">"${"</span>;

    /**
     * The ending delimiter of variable names (value is <span class="code-quote">"}"</span>).
     */
    <span class="code-keyword">private</span> <span class="code-keyword">static</span> <span class="code-keyword">final</span> <span class="code-object">String</span> DELIM_STOP = <span class="code-quote">"}"</span>;

    /**
     * This method performs property variable substitution on the specified
     * value. If the specified value contains the syntax
     * &lt;tt&gt;${&amp;lt;prop-name&amp;gt;}&lt;/tt&gt;, where &lt;tt&gt;&amp;lt;prop-name&amp;gt;&lt;/tt&gt;
     * refers to either a configuration property or a system property, then the
     * corresponding property value is substituted <span class="code-keyword">for</span> the variable placeholder.
     * Multiple variable placeholders may exist in the specified value as well
     * as nested variable placeholders, which are substituted from <span class="code-keyword">inner</span> most to
     * <span class="code-keyword">outer</span> most. Configuration properties override system properties.
     *
     * @param val The string on which to perform property substitution.
     * @param currentKey The key of the property being evaluated used to detect
     *            cycles.
     * @param cycleMap Map of variable references used to detect nested cycles.
     * @param configProps Set of configuration properties.
     * @<span class="code-keyword">return</span> The value of the specified string after system property
     *         substitution.
     * @<span class="code-keyword">throws</span> IllegalArgumentException If there was a syntax error in the
     *             property placeholder syntax or a recursive variable
     *             reference.
     */
    <span class="code-keyword">private</span> <span class="code-keyword">static</span> <span class="code-object">String</span> substVars(<span class="code-object">String</span> val, <span class="code-object">String</span> currentKey,
            Map&lt;<span class="code-object">String</span>, <span class="code-object">String</span>&gt; cycleMap, Map&lt;<span class="code-object">String</span>, <span class="code-object">String</span>&gt; configProps)
            <span class="code-keyword">throws</span> IllegalArgumentException {
        <span class="code-comment">// If there is currently no cycle map, then create
</span>        <span class="code-comment">// one <span class="code-keyword">for</span> detecting cycles <span class="code-keyword">for</span> <span class="code-keyword">this</span> invocation.
</span>        <span class="code-keyword">if</span> (cycleMap == <span class="code-keyword">null</span>) {
            cycleMap = <span class="code-keyword">new</span> HashMap&lt;<span class="code-object">String</span>, <span class="code-object">String</span>&gt;();
        }

        <span class="code-comment">// Put the current key in the cycle map.
</span>        cycleMap.put(currentKey, currentKey);

        <span class="code-comment">// Assume we have a value that is something like:
</span>        <span class="code-comment">// <span class="code-quote">"leading ${foo.${bar}} middle ${baz} trailing"</span>
</span>
        <span class="code-comment">// Find the first ending '}' variable delimiter, which
</span>        <span class="code-comment">// will correspond to the first deepest nested variable
</span>        <span class="code-comment">// placeholder.
</span>        <span class="code-object">int</span> stopDelim = val.indexOf(DELIM_STOP);

        <span class="code-comment">// Find the matching starting <span class="code-quote">"${"</span> variable delimiter
</span>        <span class="code-comment">// by looping until we find a start delimiter that is
</span>        <span class="code-comment">// greater than the stop delimiter we have found.
</span>        <span class="code-object">int</span> startDelim = val.indexOf(DELIM_START);
        <span class="code-keyword">while</span> (stopDelim &gt;= 0) {
            <span class="code-object">int</span> idx = val.indexOf(DELIM_START, startDelim
                + DELIM_START.length());
            <span class="code-keyword">if</span> ((idx &lt; 0) || (idx &gt; stopDelim)) {
                <span class="code-keyword">break</span>;
            } <span class="code-keyword">else</span> <span class="code-keyword">if</span> (idx &lt; stopDelim) {
                startDelim = idx;
            }
        }

        <span class="code-comment">// If we <span class="code-keyword">do</span> not have a start or stop delimiter, then just
</span>        <span class="code-comment">// <span class="code-keyword">return</span> the existing value.
</span>        <span class="code-keyword">if</span> ((startDelim &lt; 0) &amp;&amp; (stopDelim &lt; 0)) {
            <span class="code-keyword">return</span> val;
        }
        <span class="code-comment">// At <span class="code-keyword">this</span> point, we found a stop delimiter without a start,
</span>        <span class="code-comment">// so <span class="code-keyword">throw</span> an exception.
</span>        <span class="code-keyword">else</span> <span class="code-keyword">if</span> (((startDelim &lt; 0) || (startDelim &gt; stopDelim))
            &amp;&amp; (stopDelim &gt;= 0)) {
            <span class="code-keyword">throw</span> <span class="code-keyword">new</span> IllegalArgumentException(
                <span class="code-quote">"stop delimiter with no start delimiter: "</span> + val);
        }

        <span class="code-comment">// At <span class="code-keyword">this</span> point, we have found a variable placeholder so
</span>        <span class="code-comment">// we must perform a variable substitution on it.
</span>        <span class="code-comment">// Using the start and stop delimiter indices, extract
</span>        <span class="code-comment">// the first, deepest nested variable placeholder.
</span>        <span class="code-object">String</span> variable = val.substring(startDelim + DELIM_START.length(),
            stopDelim);

        <span class="code-comment">// Verify that <span class="code-keyword">this</span> is not a recursive variable reference.
</span>        <span class="code-keyword">if</span> (cycleMap.get(variable) != <span class="code-keyword">null</span>) {
            <span class="code-keyword">throw</span> <span class="code-keyword">new</span> IllegalArgumentException(<span class="code-quote">"recursive variable reference: "</span>
                + variable);
        }

        <span class="code-comment">// Get the value of the deepest nested variable placeholder.
</span>        <span class="code-comment">// Try to configuration properties first.
</span>        <span class="code-object">String</span> substValue = (configProps != <span class="code-keyword">null</span>)
                ? configProps.get(variable)
                : <span class="code-keyword">null</span>;
        <span class="code-keyword">if</span> (substValue == <span class="code-keyword">null</span>) {
            <span class="code-comment">// Ignore unknown property values.
</span>            substValue = <span class="code-object">System</span>.getProperty(variable, "");
        }

        <span class="code-comment">// Remove the found variable from the cycle map, since
</span>        <span class="code-comment">// it may appear more than once in the value and we don't
</span>        <span class="code-comment">// want such situations to appear as a recursive reference.
</span>        cycleMap.remove(variable);

        <span class="code-comment">// Append the leading characters, the substituted value of
</span>        <span class="code-comment">// the variable, and the trailing characters to get the <span class="code-keyword">new</span>
</span>        <span class="code-comment">// value.
</span>        val = val.substring(0, startDelim) + substValue
            + val.substring(stopDelim + DELIM_STOP.length(), val.length());

        <span class="code-comment">// Now perform substitution again, since there could still
</span>        <span class="code-comment">// be substitutions to make.
</span>        val = substVars(val, currentKey, cycleMap, configProps);

        <span class="code-comment">// Return the value.
</span>        <span class="code-keyword">return</span> val;
    }
}</pre>
</div></div></div>


</td></tr></table></div>
<p>
<table border="0" cellpadding="0" cellspacing="0" width="100%">
    <tr>
        <td height="12" background="http://cwiki.apache.org/confluence/images/border/border_bottom.gif"><img src="http://cwiki.apache.org/confluence/images/border/spacer.gif" width="1" height="1" border="0"/></td>
    </tr>
</table>

<div class="smalltext">
    Powered by
    <a href="http://www.atlassian.com/software/confluence/default.jsp?clicked=footer" class="smalltext">Atlassian Confluence</a>
    (Version: 2.2.9 Build:#527 Sep 07, 2006)
    -
    <a href="http://jira.atlassian.com/secure/BrowseProject.jspa?id=10470" class="smalltext">Bug/feature request</a><br/>
    <br>
    <a href="http://cwiki.apache.org/confluence/users/viewnotifications.action">Unsubscribe or edit your notifications preferences</a>

</div>

</body>
</html>


Mime
View raw message