http://git-wip-us.apache.org/repos/asf/struts-site/blob/124e36c4/content/docs/getting-started.html ---------------------------------------------------------------------- diff --git a/content/docs/getting-started.html b/content/docs/getting-started.html new file mode 100644 index 0000000..172a83d --- /dev/null +++ b/content/docs/getting-started.html @@ -0,0 +1,189 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> +<!-- +Licensed to the Apache Software Foundation (ASF) under one +or more contributor license agreements. See the NOTICE file +distributed with this work for additional information +regarding copyright ownership. The ASF licenses this file +to you under the Apache License, Version 2.0 (the +"License"); you may not use this file except in compliance +with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, +software distributed under the License is distributed on an +"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +KIND, either express or implied. See the License for the +specific language governing permissions and limitations +under the License. +--> +<html> +<head> + <link type="text/css" rel="stylesheet" href="https://struts.apache.org/css/default.css"> + <style type="text/css"> + .dp-highlighter { + width:95% !important; + } + </style> + <style type="text/css"> + .footer { + background-image: url('https://cwiki.apache.org/confluence/images/border/border_bottom.gif'); + background-repeat: repeat-x; + background-position: left top; + padding-top: 4px; + color: #666; + } + </style> + <script type="text/javascript" language="javascript"> + var hide = null; + var show = null; + var children = null; + + function init() { + /* Search form initialization */ + var form = document.forms['search']; + if (form != null) { + form.elements['domains'].value = location.hostname; + form.elements['sitesearch'].value = location.hostname; + } + + /* Children initialization */ + hide = document.getElementById('hide'); + show = document.getElementById('show'); + children = document.all != null ? + document.all['children'] : + document.getElementById('children'); + if (children != null) { + children.style.display = 'none'; + show.style.display = 'inline'; + hide.style.display = 'none'; + } + } + + function showChildren() { + children.style.display = 'block'; + show.style.display = 'none'; + hide.style.display = 'inline'; + } + + function hideChildren() { + children.style.display = 'none'; + show.style.display = 'inline'; + hide.style.display = 'none'; + } + </script> + <title>Getting Started</title> +</head> +<body onload="init()"> +<table border="0" cellpadding="2" cellspacing="0" width="100%"> + <tr class="topBar"> + <td align="left" valign="middle" class="topBarDiv" align="left" nowrap> + <a href="home.html">Home</a> > <a href="tutorials.html">Tutorials</a> > <a href="getting-started.html">Getting Started</a> + </td> + <td align="right" valign="middle" nowrap> + <form name="search" action="https://www.google.com/search" method="get"> + <input type="hidden" name="ie" value="UTF-8" /> + <input type="hidden" name="oe" value="UTF-8" /> + <input type="hidden" name="domains" value="" /> + <input type="hidden" name="sitesearch" value="" /> + <input type="text" name="q" maxlength="255" value="" /> + <input type="submit" name="btnG" value="Google Search" /> + </form> + </td> + </tr> +</table> + +<div id="PageContent"> + <div class="pageheader" style="padding: 6px 0px 0px 0px;"> + <!-- We'll enable this once we figure out how to access (and save) the logo resource --> + <!--img src="/wiki/images/confluence_logo.gif" style="float: left; margin: 4px 4px 4px 10px;" border="0"--> + <div style="margin: 0px 10px 0px 10px" class="smalltext">Apache Struts 2 Documentation</div> + <div style="margin: 0px 10px 8px 10px" class="pagetitle">Getting Started</div> + + <div class="greynavbar" align="right" style="padding: 2px 10px; margin: 0px;"> + <a href="https://cwiki.apache.org/confluence/pages/editpage.action?pageId=14811855"> + <img src="https://cwiki.apache.org/confluence/images/icons/notep_16.gif" + height="16" width="16" border="0" align="absmiddle" title="Edit Page"></a> + <a href="https://cwiki.apache.org/confluence/pages/editpage.action?pageId=14811855">Edit Page</a> + + <a href="https://cwiki.apache.org/confluence/pages/listpages.action?key=WW"> + <img src="https://cwiki.apache.org/confluence/images/icons/browse_space.gif" + height="16" width="16" border="0" align="absmiddle" title="Browse Space"></a> + <a href="https://cwiki.apache.org/confluence/pages/listpages.action?key=WW">Browse Space</a> + + <a href="https://cwiki.apache.org/confluence/pages/createpage.action?spaceKey=WW&fromPageId=14811855"> + <img src="https://cwiki.apache.org/confluence/images/icons/add_page_16.gif" + height="16" width="16" border="0" align="absmiddle" title="Add Page"></a> + <a href="https://cwiki.apache.org/confluence/pages/createpage.action?spaceKey=WW&fromPageId=14811855">Add Page</a> + + <a href="https://cwiki.apache.org/confluence/pages/createblogpost.action?spaceKey=WW&fromPageId=14811855"> + <img src="https://cwiki.apache.org/confluence/images/icons/add_blogentry_16.gif" + height="16" width="16" border="0" align="absmiddle" title="Add News"></a> + <a href="https://cwiki.apache.org/confluence/pages/createblogpost.action?spaceKey=WW&fromPageId=14811855">Add News</a> + </div> + </div> + + <div class="pagecontent"> + <div class="wiki-content"> + <div id="ConfluenceContent"><div class="confluence-information-macro confluence-information-macro-warning"><span class="aui-icon aui-icon-small aui-iconfont-error confluence-information-macro-icon"></span><div class="confluence-information-macro-body"><p>THIS PAGE IS DEPRECATED, PLEASE FOLLOW THE LINK TO THE NEW GETTING STARTED GUIDE!</p><p><a shape="rect" class="external-link" href="http://struts.apache.org/getting-started/">http://struts.apache.org/getting-started/</a></p></div></div><div class="confluence-information-macro confluence-information-macro-information"><span class="aui-icon aui-icon-small aui-iconfont-info confluence-information-macro-icon"></span><div class="confluence-information-macro-body"><p>The framework documentation is written for active web developers and assumes a working knowledge about how Java web applications are built. For more about the underlying nuts and bolts, see the <a shape="rect" class="external-link" href="http://struts.apache.org/p rimer.html">Key Technologies Primer</a>.</p></div></div><p>Follow along with these tutorials to get started using Struts 2. The example code for the tutorialsis available for checkout from the <br clear="none"> Struts 2 GitHub repository at <a shape="rect" class="external-link" href="https://github.com/apache/struts-examples" rel="nofollow">https://github.com/apache/struts-examples</a>. The example projects use Maven<br clear="none"> to manage the artifact dependencies and to build the .war files.</p><div class="confluence-information-macro confluence-information-macro-tip"><span class="aui-icon aui-icon-small aui-iconfont-approve confluence-information-macro-icon"></span><div class="confluence-information-macro-body"><p>The <a shape="rect" class="external-link" href="http://struts.apache.org/mail.html">Struts 2 user mailing list</a> is an excellent place to get help. If you are having a problem getting the tutorial example applications to work search the Struts 2 mailing list. If y ou don't find an answer to your problem, post a question on the mailing list.</p></div></div><h3 id="GettingStarted-GettingStarted">Getting Started</h3><p><a shape="rect" href="how-to-create-a-struts-2-web-application.html">How To Create A Struts 2 Web Application</a></p><p><a shape="rect" href="hello-world-using-struts-2.html">Hello World Using Struts 2</a></p><p><a shape="rect" href="using-struts-2-tags.html">Using Struts 2 Tags</a></p><p><a shape="rect" href="coding-struts-2-actions.html">Coding Struts 2 Actions</a></p><p><a shape="rect" href="processing-forms.html">Processing Forms</a></p><p><a shape="rect" href="form-validation.html">Form Validation</a></p><p><a shape="rect" href="message-resource-files.html">Message Resource Files</a></p><p><a shape="rect" href="exception-handling.html">Exception Handling</a></p><p><a shape="rect" href="debugging-struts.html">Debugging Struts</a></p><p><a shape="rect" href="struts-2-form-tags.html">Struts 2 Form Tags</a></p><p><a shape="rect" href="form-validation-using-xml.html">Form Validation Using XML</a></p><p><a shape="rect" href="struts-control-tags.html">Control Tags</a></p><p><a shape="rect" href="wildcard-method-selection.html">Wildcard Method Selection</a></p><p><a shape="rect" href="struts-2-themes.html">Struts 2 Themes</a></p><p><a shape="rect" href="spring-and-struts-2.html">Spring and Struts 2</a></p><p><a shape="rect" href="struts-2-annotations.html">Struts 2 Annotations</a></p><p><a shape="rect" href="introducing-interceptors.html">Introducing Interceptors</a></p><p><a shape="rect" href="unit-testing.html">Unit Testing</a></p><p><a shape="rect" href="http-session.html">HTTP Session</a></p><p><a shape="rect" href="preparable-interface.html">Preparable Interface</a></p><p><a shape="rect" href="exclude-parameters.html">Exclude Parameters</a></p><div class="confluence-information-macro confluence-information-macro-information"><span class="aui-icon aui-icon-small aui-iconfont-info confluence-information-macr o-icon"></span><div class="confluence-information-macro-body"><p>Looking for the old <a shape="rect" href="bootstrap.html">Bootstrap tutorials</a>?</p></div></div></div> + </div> + + <div class="tabletitle"> + Children + <span class="smalltext" id="show" style="display: inline;"> + <a href="javascript:showChildren()">Show Children</a></span> + <span class="smalltext" id="hide" style="display: none;"> + <a href="javascript:hideChildren()">Hide Children</a></span> + </div> + <div class="greybox" id="children" style="display: none;"> + $page.link($child) + <span class="smalltext">(Apache Struts 2 Documentation)</span> + <br> + $page.link($child) + <span class="smalltext">(Apache Struts 2 Documentation)</span> + <br> + $page.link($child) + <span class="smalltext">(Apache Struts 2 Documentation)</span> + <br> + $page.link($child) + <span class="smalltext">(Apache Struts 2 Documentation)</span> + <br> + $page.link($child) + <span class="smalltext">(Apache Struts 2 Documentation)</span> + <br> + $page.link($child) + <span class="smalltext">(Apache Struts 2 Documentation)</span> + <br> + $page.link($child) + <span class="smalltext">(Apache Struts 2 Documentation)</span> + <br> + $page.link($child) + <span class="smalltext">(Apache Struts 2 Documentation)</span> + <br> + $page.link($child) + <span class="smalltext">(Apache Struts 2 Documentation)</span> + <br> + $page.link($child) + <span class="smalltext">(Apache Struts 2 Documentation)</span> + <br> + $page.link($child) + <span class="smalltext">(Apache Struts 2 Documentation)</span> + <br> + $page.link($child) + <span class="smalltext">(Apache Struts 2 Documentation)</span> + <br> + $page.link($child) + <span class="smalltext">(Apache Struts 2 Documentation)</span> + <br> + $page.link($child) + <span class="smalltext">(Apache Struts 2 Documentation)</span> + <br> + </div> + + </div> +</div> +<div class="footer"> + Generated by CXF SiteExporter +</div> +</body> +</html>
http://git-wip-us.apache.org/repos/asf/struts-site/blob/124e36c4/content/docs/glassfish-2x.html ---------------------------------------------------------------------- diff --git a/content/docs/glassfish-2x.html b/content/docs/glassfish-2x.html new file mode 100644 index 0000000..ef4f306 --- /dev/null +++ b/content/docs/glassfish-2x.html @@ -0,0 +1,155 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> +<!-- +Licensed to the Apache Software Foundation (ASF) under one +or more contributor license agreements. See the NOTICE file +distributed with this work for additional information +regarding copyright ownership. The ASF licenses this file +to you under the Apache License, Version 2.0 (the +"License"); you may not use this file except in compliance +with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, +software distributed under the License is distributed on an +"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +KIND, either express or implied. See the License for the +specific language governing permissions and limitations +under the License. +--> +<html> +<head> + <link type="text/css" rel="stylesheet" href="https://struts.apache.org/css/default.css"> + <style type="text/css"> + .dp-highlighter { + width:95% !important; + } + </style> + <style type="text/css"> + .footer { + background-image: url('https://cwiki.apache.org/confluence/images/border/border_bottom.gif'); + background-repeat: repeat-x; + background-position: left top; + padding-top: 4px; + color: #666; + } + </style> + <link href='https://struts.apache.org/highlighter/style/shCoreStruts.css' rel='stylesheet' type='text/css' /> + <link href='https://struts.apache.org/highlighter/style/shThemeStruts.css' rel='stylesheet' type='text/css' /> + <script src='https://struts.apache.org/highlighter/js/shCore.js' type='text/javascript'></script> + <script src='https://struts.apache.org/highlighter/js/shBrushPlain.js' type='text/javascript'></script> + <script src='https://struts.apache.org/highlighter/js/shBrushXml.js' type='text/javascript'></script> + <script src='https://struts.apache.org/highlighter/js/shBrushJava.js' type='text/javascript'></script> + <script src='https://struts.apache.org/highlighter/js/shBrushJScript.js' type='text/javascript'></script> + <script src='https://struts.apache.org/highlighter/js/shBrushGroovy.js' type='text/javascript'></script> + <script src='https://struts.apache.org/highlighter/js/shBrushBash.js' type='text/javascript'></script> + <script src='https://struts.apache.org/highlighter/js/shBrushCss.js' type='text/javascript'></script> + <script type="text/javascript"> + SyntaxHighlighter.defaults['toolbar'] = false; + SyntaxHighlighter.all(); + </script> + <script type="text/javascript" language="javascript"> + var hide = null; + var show = null; + var children = null; + + function init() { + /* Search form initialization */ + var form = document.forms['search']; + if (form != null) { + form.elements['domains'].value = location.hostname; + form.elements['sitesearch'].value = location.hostname; + } + + /* Children initialization */ + hide = document.getElementById('hide'); + show = document.getElementById('show'); + children = document.all != null ? + document.all['children'] : + document.getElementById('children'); + if (children != null) { + children.style.display = 'none'; + show.style.display = 'inline'; + hide.style.display = 'none'; + } + } + + function showChildren() { + children.style.display = 'block'; + show.style.display = 'none'; + hide.style.display = 'inline'; + } + + function hideChildren() { + children.style.display = 'none'; + show.style.display = 'inline'; + hide.style.display = 'none'; + } + </script> + <title>Glassfish 2.x</title> +</head> +<body onload="init()"> +<table border="0" cellpadding="2" cellspacing="0" width="100%"> + <tr class="topBar"> + <td align="left" valign="middle" class="topBarDiv" align="left" nowrap> + <a href="home.html">Home</a> > <a href="guides.html">Guides</a> > <a href="core-developers-guide.html">Core Developers Guide</a> > <a href="application-servers.html">Application Servers</a> > <a href="glassfish-2x.html">Glassfish 2.x</a> + </td> + <td align="right" valign="middle" nowrap> + <form name="search" action="https://www.google.com/search" method="get"> + <input type="hidden" name="ie" value="UTF-8" /> + <input type="hidden" name="oe" value="UTF-8" /> + <input type="hidden" name="domains" value="" /> + <input type="hidden" name="sitesearch" value="" /> + <input type="text" name="q" maxlength="255" value="" /> + <input type="submit" name="btnG" value="Google Search" /> + </form> + </td> + </tr> +</table> + +<div id="PageContent"> + <div class="pageheader" style="padding: 6px 0px 0px 0px;"> + <!-- We'll enable this once we figure out how to access (and save) the logo resource --> + <!--img src="/wiki/images/confluence_logo.gif" style="float: left; margin: 4px 4px 4px 10px;" border="0"--> + <div style="margin: 0px 10px 0px 10px" class="smalltext">Apache Struts 2 Documentation</div> + <div style="margin: 0px 10px 8px 10px" class="pagetitle">Glassfish 2.x</div> + + <div class="greynavbar" align="right" style="padding: 2px 10px; margin: 0px;"> + <a href="https://cwiki.apache.org/confluence/pages/editpage.action?pageId=40505336"> + <img src="https://cwiki.apache.org/confluence/images/icons/notep_16.gif" + height="16" width="16" border="0" align="absmiddle" title="Edit Page"></a> + <a href="https://cwiki.apache.org/confluence/pages/editpage.action?pageId=40505336">Edit Page</a> + + <a href="https://cwiki.apache.org/confluence/pages/listpages.action?key=WW"> + <img src="https://cwiki.apache.org/confluence/images/icons/browse_space.gif" + height="16" width="16" border="0" align="absmiddle" title="Browse Space"></a> + <a href="https://cwiki.apache.org/confluence/pages/listpages.action?key=WW">Browse Space</a> + + <a href="https://cwiki.apache.org/confluence/pages/createpage.action?spaceKey=WW&fromPageId=40505336"> + <img src="https://cwiki.apache.org/confluence/images/icons/add_page_16.gif" + height="16" width="16" border="0" align="absmiddle" title="Add Page"></a> + <a href="https://cwiki.apache.org/confluence/pages/createpage.action?spaceKey=WW&fromPageId=40505336">Add Page</a> + + <a href="https://cwiki.apache.org/confluence/pages/createblogpost.action?spaceKey=WW&fromPageId=40505336"> + <img src="https://cwiki.apache.org/confluence/images/icons/add_blogentry_16.gif" + height="16" width="16" border="0" align="absmiddle" title="Add News"></a> + <a href="https://cwiki.apache.org/confluence/pages/createblogpost.action?spaceKey=WW&fromPageId=40505336">Add News</a> + </div> + </div> + + <div class="pagecontent"> + <div class="wiki-content"> + <div id="ConfluenceContent"><h3 id="Glassfish2.x-Conventionpluginsupport">Convention plugin support</h3><p>To have proper support of the <a shape="rect" href="convention-plugin.html">Convention Plugin</a> in Glassfish 2.x when packed as EAR archive add the following constant to <code>struts.xml</code></p><div class="code panel pdl" style="border-width: 1px;"><div class="codeContent panelContent pdl"> +<pre class="brush: java; gutter: false; theme: Default" style="font-size:12px;"><constant name="struts.convention.exclude.parentClassLoader" value="false" /> +</pre> +</div></div><p>Thanks to <a shape="rect" class="external-link" href="http://stackoverflow.com/a/22490925/1805267" rel="nofollow">pavpal</a>!</p></div> + </div> + + + </div> +</div> +<div class="footer"> + Generated by CXF SiteExporter +</div> +</body> +</html> http://git-wip-us.apache.org/repos/asf/struts-site/blob/124e36c4/content/docs/google-app-engine-gae.html ---------------------------------------------------------------------- diff --git a/content/docs/google-app-engine-gae.html b/content/docs/google-app-engine-gae.html new file mode 100644 index 0000000..accd085 --- /dev/null +++ b/content/docs/google-app-engine-gae.html @@ -0,0 +1,355 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> +<!-- +Licensed to the Apache Software Foundation (ASF) under one +or more contributor license agreements. See the NOTICE file +distributed with this work for additional information +regarding copyright ownership. The ASF licenses this file +to you under the Apache License, Version 2.0 (the +"License"); you may not use this file except in compliance +with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, +software distributed under the License is distributed on an +"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +KIND, either express or implied. See the License for the +specific language governing permissions and limitations +under the License. +--> +<html> +<head> + <link type="text/css" rel="stylesheet" href="https://struts.apache.org/css/default.css"> + <style type="text/css"> + .dp-highlighter { + width:95% !important; + } + </style> + <style type="text/css"> + .footer { + background-image: url('https://cwiki.apache.org/confluence/images/border/border_bottom.gif'); + background-repeat: repeat-x; + background-position: left top; + padding-top: 4px; + color: #666; + } + </style> + <link href='https://struts.apache.org/highlighter/style/shCoreStruts.css' rel='stylesheet' type='text/css' /> + <link href='https://struts.apache.org/highlighter/style/shThemeStruts.css' rel='stylesheet' type='text/css' /> + <script src='https://struts.apache.org/highlighter/js/shCore.js' type='text/javascript'></script> + <script src='https://struts.apache.org/highlighter/js/shBrushPlain.js' type='text/javascript'></script> + <script src='https://struts.apache.org/highlighter/js/shBrushXml.js' type='text/javascript'></script> + <script src='https://struts.apache.org/highlighter/js/shBrushJava.js' type='text/javascript'></script> + <script src='https://struts.apache.org/highlighter/js/shBrushJScript.js' type='text/javascript'></script> + <script src='https://struts.apache.org/highlighter/js/shBrushGroovy.js' type='text/javascript'></script> + <script src='https://struts.apache.org/highlighter/js/shBrushBash.js' type='text/javascript'></script> + <script src='https://struts.apache.org/highlighter/js/shBrushCss.js' type='text/javascript'></script> + <script type="text/javascript"> + SyntaxHighlighter.defaults['toolbar'] = false; + SyntaxHighlighter.all(); + </script> + <script type="text/javascript" language="javascript"> + var hide = null; + var show = null; + var children = null; + + function init() { + /* Search form initialization */ + var form = document.forms['search']; + if (form != null) { + form.elements['domains'].value = location.hostname; + form.elements['sitesearch'].value = location.hostname; + } + + /* Children initialization */ + hide = document.getElementById('hide'); + show = document.getElementById('show'); + children = document.all != null ? + document.all['children'] : + document.getElementById('children'); + if (children != null) { + children.style.display = 'none'; + show.style.display = 'inline'; + hide.style.display = 'none'; + } + } + + function showChildren() { + children.style.display = 'block'; + show.style.display = 'none'; + hide.style.display = 'inline'; + } + + function hideChildren() { + children.style.display = 'none'; + show.style.display = 'inline'; + hide.style.display = 'none'; + } + </script> + <title>Google App Engine (GAE)</title> +</head> +<body onload="init()"> +<table border="0" cellpadding="2" cellspacing="0" width="100%"> + <tr class="topBar"> + <td align="left" valign="middle" class="topBarDiv" align="left" nowrap> + <a href="home.html">Home</a> > <a href="faqs.html">FAQs</a> > <a href="google-app-engine-gae.html">Google App Engine (GAE)</a> + </td> + <td align="right" valign="middle" nowrap> + <form name="search" action="https://www.google.com/search" method="get"> + <input type="hidden" name="ie" value="UTF-8" /> + <input type="hidden" name="oe" value="UTF-8" /> + <input type="hidden" name="domains" value="" /> + <input type="hidden" name="sitesearch" value="" /> + <input type="text" name="q" maxlength="255" value="" /> + <input type="submit" name="btnG" value="Google Search" /> + </form> + </td> + </tr> +</table> + +<div id="PageContent"> + <div class="pageheader" style="padding: 6px 0px 0px 0px;"> + <!-- We'll enable this once we figure out how to access (and save) the logo resource --> + <!--img src="/wiki/images/confluence_logo.gif" style="float: left; margin: 4px 4px 4px 10px;" border="0"--> + <div style="margin: 0px 10px 0px 10px" class="smalltext">Apache Struts 2 Documentation</div> + <div style="margin: 0px 10px 8px 10px" class="pagetitle">Google App Engine (GAE)</div> + + <div class="greynavbar" align="right" style="padding: 2px 10px; margin: 0px;"> + <a href="https://cwiki.apache.org/confluence/pages/editpage.action?pageId=114612"> + <img src="https://cwiki.apache.org/confluence/images/icons/notep_16.gif" + height="16" width="16" border="0" align="absmiddle" title="Edit Page"></a> + <a href="https://cwiki.apache.org/confluence/pages/editpage.action?pageId=114612">Edit Page</a> + + <a href="https://cwiki.apache.org/confluence/pages/listpages.action?key=WW"> + <img src="https://cwiki.apache.org/confluence/images/icons/browse_space.gif" + height="16" width="16" border="0" align="absmiddle" title="Browse Space"></a> + <a href="https://cwiki.apache.org/confluence/pages/listpages.action?key=WW">Browse Space</a> + + <a href="https://cwiki.apache.org/confluence/pages/createpage.action?spaceKey=WW&fromPageId=114612"> + <img src="https://cwiki.apache.org/confluence/images/icons/add_page_16.gif" + height="16" width="16" border="0" align="absmiddle" title="Add Page"></a> + <a href="https://cwiki.apache.org/confluence/pages/createpage.action?spaceKey=WW&fromPageId=114612">Add Page</a> + + <a href="https://cwiki.apache.org/confluence/pages/createblogpost.action?spaceKey=WW&fromPageId=114612"> + <img src="https://cwiki.apache.org/confluence/images/icons/add_blogentry_16.gif" + height="16" width="16" border="0" align="absmiddle" title="Add News"></a> + <a href="https://cwiki.apache.org/confluence/pages/createblogpost.action?spaceKey=WW&fromPageId=114612">Add News</a> + </div> + </div> + + <div class="pagecontent"> + <div class="wiki-content"> + <div id="ConfluenceContent"><p>It is possible to run, at least, a simple Struts 2 application on GAE with a little work. Namely, you need to tell OGNL to not do security manager permission checks, which will fail since GAE has a security manager and you don't have the ability to add the OGNL-specific permissions. Therefore, somewhere in your initialization code, add this:</p> + +<div class="code panel pdl" style="border-width: 1px;"><div class="codeContent panelContent pdl"> +<pre class="brush: java; gutter: false; theme: Default" style="font-size:12px;"> +OgnlRuntime.setSecurityManager(null); +</pre> +</div></div> + +<p>The easiest place for this is in a Servlet context listener, executing when the context is initialized.</p> + +<p>For Struts 2.1.8, Jeromy Evans did some work to get things running on GAE. The following post on the mailing list reports both the issues and the workarounds.</p> + +<h3 id="GoogleAppEngine(GAE)-IssueswhendeployingonGAE">Issues when deploying on GAE</h3> + +<p>Jeromy Evans: I've put in some more effort to get Struts 2.1.8 snapshot running in live GAE environment. I made progress moving to Sitemesh 2.4.2, disabling OgnlRuntime SecurityManager and moving to convention-2.1.8-SNAPSHOT (WW-3114)</p> + +<p>The next issue is that XWorks XMLConfigurationProvider throws a SecurityException on the following line (211):</p> + +<p>// Force loading of class to detect no class def found exceptions<br clear="none"> +cimpl.getDeclaredConstructors();</p> + +<p>SecurityException: Unable to get members for o.a.s.c.PackageBasedActionConfigBuilder</p> + +<p>cimpl is the Class of the ActionConfigBuilder bean specified in struts-plugin.xml and loaded by ClassLoaderTools. I believe this is a technique to eagerly load the class.</p> + +<p>I'm not sure why that's access is not permitted in the sandbox. It's not documented anywhere I can see and It only occurs in the live environment.</p> + +<p>As a work-around (guess), I changed it to cimpl.getDeclaredClasses() instead which is permitted (I don't know if this has the same effect on the ClassLoader). That got me past the issue above, but the same SecurityException occurs in XWork's ContainerImpl$ConstructorInjector.findConstructorIn():<br clear="none"> +SecurityException: Unable to get members for Class o.a.s.v.v.VelocityManager</p> + +<p>which seems to be a fundamental problem with XWork's constructor injection in GAE.</p> + +<p>As a side note, Guice 2's constructor injection works okay in GAE. I imagine the Guice 2 codebase is now very different beast than XWork's IOC though.</p> + +<p>I guess I need to approach the GAE forum now. Has anyone got any ideas about what to attempt next on the S2/Xwork side? Stack traces for the two cases are below.</p> + +<div class="preformatted panel" style="border-width: 1px;"><div class="preformattedContent panelContent"> +<pre> +Failed startup of context com.google.apphosting.utils.jetty.RuntimeAppEngineWebAppContext@67fe80{/,/base/data/home/apps/{appname}/1.335834217966711427} +Unable to load configuration. - bean - jar:file:/base/data/home/apps/{appname}/1.335834217966711427/WEB-INF/lib/struts2-convention-plugin-2.1.8-SNAPSHOT.jar!/struts-plugin.xml:32:155 + at org.apache.struts2.dispatcher.Dispatcher.init(Dispatcher.java:431) + at org.apache.struts2.dispatcher.ng.InitOperations.initDispatcher(InitOperations.java:69) + at org.apache.struts2.dispatcher.ng.filter.StrutsPrepareFilter.init(StrutsPrepareFilter.java:50) + at com.google.inject.servlet.FilterDefinition.init(FilterDefinition.java:81) + at com.google.inject.servlet.ManagedFilterPipeline.initPipeline(ManagedFilterPipeline.java:102) + at com.google.inject.servlet.GuiceFilter.init(GuiceFilter.java:168) + at org.mortbay.jetty.servlet.FilterHolder.doStart(FilterHolder.java:99) + at org.mortbay.component.AbstractLifeCycle.start(AbstractLifeCycle.java:40) + at org.mortbay.jetty.servlet.ServletHandler.initialize(ServletHandler.java:589) + at org.mortbay.jetty.servlet.Context.startContext(Context.java:139) + at org.mortbay.jetty.webapp.WebAppContext.startContext(WebAppContext.java:1218) + at org.mortbay.jetty.handler.ContextHandler.doStart(ContextHandler.java:500) + at org.mortbay.jetty.webapp.WebAppContext.doStart(WebAppContext.java:448) + at org.mortbay.component.AbstractLifeCycle.start(AbstractLifeCycle.java:40) + at com.google.apphosting.runtime.jetty.AppVersionHandlerMap.createHandler(AppVersionHandlerMap.java:190) + at com.google.apphosting.runtime.jetty.AppVersionHandlerMap.getHandler(AppVersionHandlerMap.java:167) + at com.google.apphosting.runtime.jetty.JettyServletEngineAdapter.serviceRequest(JettyServletEngineAdapter.java:127) + at com.google.apphosting.runtime.JavaRuntime.handleRequest(JavaRuntime.java:235) + at com.google.apphosting.base.RuntimePb$EvaluationRuntime$6.handleBlockingRequest(RuntimePb.java:4823) + at com.google.apphosting.base.RuntimePb$EvaluationRuntime$6.handleBlockingRequest(RuntimePb.java:4821) + at com.google.net.rpc.impl.BlockingApplicationHandler.handleRequest(BlockingApplicationHandler.java:24) + at com.google.net.rpc.impl.RpcUtil.runRpcInApplication(RpcUtil.java:359) + at com.google.net.rpc.impl.Server$2.run(Server.java:820) + at com.google.tracing.LocalTraceSpanRunnable.run(LocalTraceSpanRunnable.java:56) + at com.google.tracing.LocalTraceSpanBuilder.internalContinueSpan(LocalTraceSpanBuilder.java:516) + at com.google.net.rpc.impl.Server.startRpc(Server.java:775) + at com.google.net.rpc.impl.Server.processRequest(Server.java:348) + at com.google.net.rpc.impl.ServerConnection.messageReceived(ServerConnection.java:436) + at com.google.net.rpc.impl.RpcConnection.parseMessages(RpcConnection.java:319) + at com.google.net.rpc.impl.RpcConnection.dataReceived(RpcConnection.java:290) + at com.google.net.async.Connection.handleReadEvent(Connection.java:428) + at com.google.net.async.EventDispatcher.processNetworkEvents(EventDispatcher.java:762) + at com.google.net.async.EventDispatcher.internalLoop(EventDispatcher.java:207) + at com.google.net.async.EventDispatcher.loop(EventDispatcher.java:101) + at com.google.net.rpc.RpcService.runUntilServerShutdown(RpcService.java:251) + at com.google.apphosting.runtime.JavaRuntime$RpcRunnable.run(JavaRuntime.java:374) + at java.lang.Thread.run(Unknown Source) +Caused by: Unable to load configuration. - bean - jar:file:/base/data/home/apps/{appname}/1.335834217966711427/WEB-INF/lib/struts2-convention-plugin-2.1.8-SNAPSHOT.jar!/struts-plugin.xml:32:155 + at com.opensymphony.xwork2.config.ConfigurationManager.getConfiguration(ConfigurationManager.java:58) + at org.apache.struts2.dispatcher.Dispatcher.init_PreloadConfiguration(Dispatcher.java:374) + at org.apache.struts2.dispatcher.Dispatcher.init(Dispatcher.java:418) + ... 36 more +Caused by: Unable to load bean: type:org.apache.struts2.convention.ActionConfigBuilder class:org.apache.struts2.convention.PackageBasedActionConfigBuilder - bean - jar:file:/base/data/home/apps/{appname}/1.335834217966711427/WEB-INF/lib/struts2-convention-plugin-2.1.8-SNAPSHOT.jar!/struts-plugin.xml:32:155 + at com.opensymphony.xwork2.config.providers.XmlConfigurationProvider.register(XmlConfigurationProvider.java:222) + at org.apache.struts2.config.StrutsXmlConfigurationProvider.register(StrutsXmlConfigurationProvider.java:101) + at com.opensymphony.xwork2.config.impl.DefaultConfiguration.reloadContainer(DefaultConfiguration.java:165) + at com.opensymphony.xwork2.config.ConfigurationManager.getConfiguration(ConfigurationManager.java:55) + ... 38 more +Caused by: java.lang.SecurityException: Unable to get members for class org.apache.struts2.convention.PackageBasedActionConfigBuilder + at com.google.apphosting.runtime.security.shared.intercept.java.lang.Class_$10.run(Class_.java:357) + at com.google.apphosting.runtime.security.shared.intercept.java.lang.Class_$10.run(Class_.java:347) + at java.security.AccessController.doPrivileged(Native Method) + at com.google.apphosting.runtime.security.shared.intercept.java.lang.Class_.getMembers(Class_.java:347) + at com.google.apphosting.runtime.security.shared.intercept.java.lang.Class_.getDeclaredConstructors(Class_.java:192) + at com.opensymphony.xwork2.config.providers.XmlConfigurationProvider.register(XmlConfigurationProvider.java:212) + ... 41 more +</pre> +</div></div> + +<p>— case two —</p> +<div class="preformatted panel" style="border-width: 1px;"><div class="preformattedContent panelContent"> +<pre> +{ +[{appname}/1.335835094531171610].<stdout>: 642 [Runtime Network Thread] ERROR org.apache.struts2.dispatcher.Dispatcher - Dispatcher initialization failed +java.lang.RuntimeException: java.lang.RuntimeException: java.lang.RuntimeException: java.lang.SecurityException: Unable to get members for class org.apache.struts2.views.velocity.VelocityManager + at com.opensymphony.xwork2.inject.ContainerImpl$MethodInjector.inject(ContainerImpl.java:295) + at com.opensymphony.xwork2.inject.ContainerImpl$2.call(ContainerImpl.java:104) + at com.opensymphony.xwork2.inject.ContainerImpl$2.call(ContainerImpl.java:102) + at com.opensymphony.xwork2.inject.ContainerImpl.callInContext(ContainerImpl.java:574) + at com.opensymphony.xwork2.inject.ContainerImpl.injectStatics(ContainerImpl.java:101) + at com.opensymphony.xwork2.inject.ContainerBuilder.create(ContainerBuilder.java:493) + at com.opensymphony.xwork2.config.impl.DefaultConfiguration.reloadContainer(DefaultConfiguration.java:184) + at com.opensymphony.xwork2.config.ConfigurationManager.getConfiguration(ConfigurationManager.java:55) + at org.apache.struts2.dispatcher.Dispatcher.init_PreloadConfiguration(Dispatcher.java:374) + at org.apache.struts2.dispatcher.Dispatcher.init(Dispatcher.java:418) + at org.apache.struts2.dispatcher.ng.InitOperations.initDispatcher(InitOperations.java:69) + at org.apache.struts2.dispatcher.ng.filter.StrutsPrepareFilter.init(StrutsPrepareFilter.java:50) + at com.google.inject.servlet.FilterDefinition.init(FilterDefinition.java:81) + at com.google.inject.servlet.ManagedFilterPipeline.initPipeline(ManagedFilterPipeline.java:102) + at com.google.inject.servlet.GuiceFilter.init(GuiceFilter.java:168) + at org.mortbay.jetty.servlet.FilterHolder.doStart(FilterHolder.java:99) + at org.mortbay.component.AbstractLifeCycle.start(AbstractLifeCycle.java:40) + at org.mortbay.jetty.servlet.ServletHandler.initialize(ServletHandler.java:589) + at org.mortbay.jetty.servlet.Context.startContext(Context.java:139) + at org.mortbay.jetty.webapp.WebAppContext.startContext(WebAppContext.java:1218) + at org.mortbay.jetty.handler.ContextHandler.doStart(ContextHandler.java:500) + at org.mortbay.jetty.webapp.WebAppContext.doStart(WebAppContext.java:448) + at org.mortbay.component.AbstractLifeCycle.start(AbstractLifeCycle.java:40) + at com.google.apphosting.runtime.jetty.AppVersionHandlerMap.createHandler(AppVersionHandlerMap.java:190) + at com.google.apphosting.runtime.jetty.AppVersionHandlerMap.getHandler(AppVersionHandlerMap.java:167) + at com.google.apphosting.runtime.jetty.JettyServletEngineAdapter.serviceRequest(JettyServletEngineAdapter.java:127) + at com.google.apphosting.runtime.JavaRuntime.handleRequest(JavaRuntime.java:235) + at com.google.apphosting.base.RuntimePb$EvaluationRuntime$6.handleBlockingRequest(RuntimePb.java:4823) + at com.google.apphosting.base.RuntimePb$EvaluationRuntime$6.handleBlockingRequest(RuntimePb.java:4821) + at com.google.net.rpc.impl.BlockingApplicationHandler.handleRequest(BlockingApplicationHandler.java:24) + at com.google.net.rpc.impl.RpcUtil.runRpcInApplication(RpcUtil.java:359) + at com.google.net.rpc.impl.Server$2.run(Server.java:820) + at com.google.tracing.LocalTraceSpanRunnable.run(LocalTraceSpanRunnable.java:56) + at com.google.tracing.LocalTraceSpanBuilder.internalContinueSpan(LocalTraceSpanBuilder.java:516) + at com.google.net.rpc.impl.Server.startRpc(Server.java:775) + at com.google.net.rpc.impl.Server.processRequest(Server.java:348) + at com.google.net.rpc.impl.ServerConnection.messageReceived(ServerConnection.java:436) + at com.google.net.rpc.impl.RpcConnection.parseMessages(RpcConnection.java:319) + at com.google.net.rpc.impl.RpcConnection.dataReceived(RpcConnection.java:290) + at com.google.net.async.Connection.handleReadEvent(Connection.java:428) + at com.google.net.async.EventDispatcher.processNetworkEvents(EventDispatcher.java:762) + at com.google.net.async.EventDispatcher.internalLoop(EventDispatcher.java:207) + at com.google.net.async.EventDispatcher.loop(EventDispatcher.java:101) + at com.google.net.rpc.RpcService.runUntilServerShutdown(RpcService.java:251) + at com.google.apphosting.runtime.JavaRuntime$RpcRunnable.run(JavaRuntime.java:374) + at java.lang.Thread.run(Unknown Source) +Caused by: java.lang.RuntimeException: java.lang.RuntimeException: java.lang.SecurityException: Unable to get members for class org.apache.struts2.views.velocity.VelocityManager + at com.opensymphony.xwork2.inject.ContainerBuilder$4.create(ContainerBuilder.java:132) + at com.opensymphony.xwork2.inject.Scope$2$1.create(Scope.java:51) + at com.opensymphony.xwork2.inject.ContainerImpl$ParameterInjector.inject(ContainerImpl.java:462) + at com.opensymphony.xwork2.inject.ContainerImpl.getParameters(ContainerImpl.java:477) + at com.opensymphony.xwork2.inject.ContainerImpl.access$000(ContainerImpl.java:34) + at com.opensymphony.xwork2.inject.ContainerImpl$MethodInjector.inject(ContainerImpl.java:293) + ... 45 more +Caused by: java.lang.RuntimeException: java.lang.SecurityException: Unable to get members for class org.apache.struts2.views.velocity.VelocityManager + at com.opensymphony.xwork2.inject.ContainerImpl.inject(ContainerImpl.java:495) + at com.opensymphony.xwork2.inject.ContainerImpl$7.call(ContainerImpl.java:532) + at com.opensymphony.xwork2.inject.ContainerImpl.callInContext(ContainerImpl.java:581) + at com.opensymphony.xwork2.inject.ContainerImpl.inject(ContainerImpl.java:530) + at com.opensymphony.xwork2.config.impl.LocatableFactory.create(LocatableFactory.java:32) + at com.opensymphony.xwork2.inject.ContainerBuilder$4.create(ContainerBuilder.java:130) + ... 50 more +Caused by: java.lang.SecurityException: Unable to get members for class org.apache.struts2.views.velocity.VelocityManager + at com.google.apphosting.runtime.security.shared.intercept.java.lang.Class_$10.run(Class_.java:357) + at com.google.apphosting.runtime.security.shared.intercept.java.lang.Class_$10.run(Class_.java:347) + at java.security.AccessController.doPrivileged(Native Method) + at com.google.apphosting.runtime.security.shared.intercept.java.lang.Class_.getMembers(Class_.java:347) + at com.google.apphosting.runtime.security.shared.intercept.java.lang.Class_.getDeclaredConstructors(Class_.java:192) + at com.opensymphony.xwork2.inject.ContainerImpl$ConstructorInjector.findConstructorIn(ContainerImpl.java:366) + at com.opensymphony.xwork2.inject.ContainerImpl$ConstructorInjector.<init>(ContainerImpl.java:319) + at com.opensymphony.xwork2.inject.ContainerImpl$5.create(ContainerImpl.java:305) + at com.opensymphony.xwork2.inject.ContainerImpl$5.create(ContainerImpl.java:304) + at com.opensymphony.xwork2.inject.util.ReferenceCache$CallableCreate.call(ReferenceCache.java:150) + at java.util.concurrent.FutureTask$Sync.innerRun(Unknown Source) + at java.util.concurrent.FutureTask.run(Unknown Source) + at com.opensymphony.xwork2.inject.util.ReferenceCache.internalCreate(ReferenceCache.java:76) + at com.opensymphony.xwork2.inject.util.ReferenceCache.get(ReferenceCache.java:116) + at com.opensymphony.xwork2.inject.ContainerImpl.getConstructor(ContainerImpl.java:594) + at com.opensymphony.xwork2.inject.ContainerImpl.inject(ContainerImpl.java:491) + ... 55 more +</pre> +</div></div> + +<h3 id="GoogleAppEngine(GAE)-Workarounds">Workarounds</h3> + +<blockquote><p>As a work-around (guess), I changed it to cimpl.getDeclaredClasses() instead which is permitted (I don't know if this has the same effect on the ClassLoader). That got me past the issue above, but the same SecurityException occurs in XWork's ContainerImpl$ConstructorInjector.findConstructorIn():</p></blockquote> +<p> SecurityException: Unable to get members for Class o.a.s.v.v.VelocityManager</p> + + +<p>This exception occurs within Google App Engine because XWork eagerly loads the VelocityManager Class for the bean struts-default.xml. VelocityManager uses the VelocityToolbox optional dependency (in velocity-tools) which is not deployed with the application by default. I presume the GAE ClassLoader checks all imported classes against the whitelist and fails if the class is not found.<br clear="none"> +It's overcome by deploying the application velocity.</p> + +<p>I now have Struts 2.1.8-snapshot with Convention, Sitemesh and JSON, within a Guice2 servlet filter for IOC, running within GAE.</p> + +<p>The mandatory work-around are:</p> +<ul class="alternate"><li>to still use a ServletContextListener to disable the OgnlRuntime security manager. If not done, an IllegalAccessException occurs in OgnlUtil.setProperty(String) at run-time. This exception is swallowed, but it typically results in an NPE in ServletRedirectResult.isPathUrl(String) because location cannot be set.</li><li>the velocity dependencies need to be deployed with the application even if not in use. If not done, a security exception occurs while getting the members of VelocityManager because VelocityManager imports VelocityToolbox and VelocityEngine.</li></ul> + + +<p>I don't think any S2 code changes are required at this time.</p></div> + </div> + + + </div> +</div> +<div class="footer"> + Generated by CXF SiteExporter +</div> +</body> +</html> http://git-wip-us.apache.org/repos/asf/struts-site/blob/124e36c4/content/docs/groovyresult.html ---------------------------------------------------------------------- diff --git a/content/docs/groovyresult.html b/content/docs/groovyresult.html new file mode 100644 index 0000000..d3259b6 --- /dev/null +++ b/content/docs/groovyresult.html @@ -0,0 +1,386 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> +<!-- +Licensed to the Apache Software Foundation (ASF) under one +or more contributor license agreements. See the NOTICE file +distributed with this work for additional information +regarding copyright ownership. The ASF licenses this file +to you under the Apache License, Version 2.0 (the +"License"); you may not use this file except in compliance +with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, +software distributed under the License is distributed on an +"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +KIND, either express or implied. See the License for the +specific language governing permissions and limitations +under the License. +--> +<html> +<head> + <link type="text/css" rel="stylesheet" href="https://struts.apache.org/css/default.css"> + <style type="text/css"> + .dp-highlighter { + width:95% !important; + } + </style> + <style type="text/css"> + .footer { + background-image: url('https://cwiki.apache.org/confluence/images/border/border_bottom.gif'); + background-repeat: repeat-x; + background-position: left top; + padding-top: 4px; + color: #666; + } + </style> + <link href='https://struts.apache.org/highlighter/style/shCoreStruts.css' rel='stylesheet' type='text/css' /> + <link href='https://struts.apache.org/highlighter/style/shThemeStruts.css' rel='stylesheet' type='text/css' /> + <script src='https://struts.apache.org/highlighter/js/shCore.js' type='text/javascript'></script> + <script src='https://struts.apache.org/highlighter/js/shBrushPlain.js' type='text/javascript'></script> + <script src='https://struts.apache.org/highlighter/js/shBrushXml.js' type='text/javascript'></script> + <script src='https://struts.apache.org/highlighter/js/shBrushJava.js' type='text/javascript'></script> + <script src='https://struts.apache.org/highlighter/js/shBrushJScript.js' type='text/javascript'></script> + <script src='https://struts.apache.org/highlighter/js/shBrushGroovy.js' type='text/javascript'></script> + <script src='https://struts.apache.org/highlighter/js/shBrushBash.js' type='text/javascript'></script> + <script src='https://struts.apache.org/highlighter/js/shBrushCss.js' type='text/javascript'></script> + <script type="text/javascript"> + SyntaxHighlighter.defaults['toolbar'] = false; + SyntaxHighlighter.all(); + </script> + <script type="text/javascript" language="javascript"> + var hide = null; + var show = null; + var children = null; + + function init() { + /* Search form initialization */ + var form = document.forms['search']; + if (form != null) { + form.elements['domains'].value = location.hostname; + form.elements['sitesearch'].value = location.hostname; + } + + /* Children initialization */ + hide = document.getElementById('hide'); + show = document.getElementById('show'); + children = document.all != null ? + document.all['children'] : + document.getElementById('children'); + if (children != null) { + children.style.display = 'none'; + show.style.display = 'inline'; + hide.style.display = 'none'; + } + } + + function showChildren() { + children.style.display = 'block'; + show.style.display = 'none'; + hide.style.display = 'inline'; + } + + function hideChildren() { + children.style.display = 'none'; + show.style.display = 'inline'; + hide.style.display = 'none'; + } + </script> + <title>GroovyResult</title> +</head> +<body onload="init()"> +<table border="0" cellpadding="2" cellspacing="0" width="100%"> + <tr class="topBar"> + <td align="left" valign="middle" class="topBarDiv" align="left" nowrap> + <a href="home.html">Home</a> > <a href="faqs.html">FAQs</a> > <a href="cookbook.html">Cookbook</a> > <a href="groovyresult.html">GroovyResult</a> + </td> + <td align="right" valign="middle" nowrap> + <form name="search" action="https://www.google.com/search" method="get"> + <input type="hidden" name="ie" value="UTF-8" /> + <input type="hidden" name="oe" value="UTF-8" /> + <input type="hidden" name="domains" value="" /> + <input type="hidden" name="sitesearch" value="" /> + <input type="text" name="q" maxlength="255" value="" /> + <input type="submit" name="btnG" value="Google Search" /> + </form> + </td> + </tr> +</table> + +<div id="PageContent"> + <div class="pageheader" style="padding: 6px 0px 0px 0px;"> + <!-- We'll enable this once we figure out how to access (and save) the logo resource --> + <!--img src="/wiki/images/confluence_logo.gif" style="float: left; margin: 4px 4px 4px 10px;" border="0"--> + <div style="margin: 0px 10px 0px 10px" class="smalltext">Apache Struts 2 Documentation</div> + <div style="margin: 0px 10px 8px 10px" class="pagetitle">GroovyResult</div> + + <div class="greynavbar" align="right" style="padding: 2px 10px; margin: 0px;"> + <a href="https://cwiki.apache.org/confluence/pages/editpage.action?pageId=13865"> + <img src="https://cwiki.apache.org/confluence/images/icons/notep_16.gif" + height="16" width="16" border="0" align="absmiddle" title="Edit Page"></a> + <a href="https://cwiki.apache.org/confluence/pages/editpage.action?pageId=13865">Edit Page</a> + + <a href="https://cwiki.apache.org/confluence/pages/listpages.action?key=WW"> + <img src="https://cwiki.apache.org/confluence/images/icons/browse_space.gif" + height="16" width="16" border="0" align="absmiddle" title="Browse Space"></a> + <a href="https://cwiki.apache.org/confluence/pages/listpages.action?key=WW">Browse Space</a> + + <a href="https://cwiki.apache.org/confluence/pages/createpage.action?spaceKey=WW&fromPageId=13865"> + <img src="https://cwiki.apache.org/confluence/images/icons/add_page_16.gif" + height="16" width="16" border="0" align="absmiddle" title="Add Page"></a> + <a href="https://cwiki.apache.org/confluence/pages/createpage.action?spaceKey=WW&fromPageId=13865">Add Page</a> + + <a href="https://cwiki.apache.org/confluence/pages/createblogpost.action?spaceKey=WW&fromPageId=13865"> + <img src="https://cwiki.apache.org/confluence/images/icons/add_blogentry_16.gif" + height="16" width="16" border="0" align="absmiddle" title="Add News"></a> + <a href="https://cwiki.apache.org/confluence/pages/createblogpost.action?spaceKey=WW&fromPageId=13865">Add News</a> + </div> + </div> + + <div class="pagecontent"> + <div class="wiki-content"> + <div id="ConfluenceContent"><div class="confluence-information-macro confluence-information-macro-information"><p class="title">Groovy Plugin Available</p><span class="aui-icon aui-icon-small aui-iconfont-info confluence-information-macro-icon"></span><div class="confluence-information-macro-body"> +<p>There is now a Struts 2 Groovy plugin that largely superceded this page: <a shape="rect" class="external-link" href="http://cwiki.apache.org/S2PLUGINS/groovy-plugin.html">http://cwiki.apache.org/S2PLUGINS/groovy-plugin.html</a></p></div></div> +<h2 id="GroovyResult-GroovyResult-Groovyscriptsasaview">GroovyResult - Groovy scripts as a view</h2> + +<p>This is an attempt to create a Result type that uses Groovy (<a shape="rect" class="external-link" href="http://groovy.codehaus.org" rel="nofollow">http://groovy.codehaus.org</a>) files as a view. It exposes the current ActionContext to a groovy script. This doesn't really have much practical use, but it's fun nonetheless and shows how easy it is to create a Result. There is another Result (JFreeChartResult) in the <a shape="rect" href="https://cwiki.apache.org/confluence/pages/viewpage.action?pageId=117058">Cookbook</a></p> + +<h2 id="GroovyResult-Installation">Installation</h2> + +<p>Not much - just make sure you have Groovy in your classpath, and the antlr, asm-* and groovy jars available to your webapp.</p> + +<h2 id="GroovyResult-Configuration">Configuration</h2> + +<div class="code panel pdl" style="border-width: 1px;"><div class="codeHeader panelHeader pdl" style="border-bottom-width: 1px;"><b>acdtion.xml</b></div><div class="codeContent panelContent pdl"> +<pre class="brush: xml; gutter: false; theme: Default" style="font-size:12px;"> +<result-types> + <result-type name="groovy" class="myapp.action2.extensions.GroovyResult"/> +</result-types> +</pre> +</div></div> +<p>xwork.xml - action definitions</p> +<div class="code panel pdl" style="border-width: 1px;"><div class="codeContent panelContent pdl"> +<pre class="brush: java; gutter: false; theme: Default" style="font-size:12px;"> +<action name="MyAction" class="myapp.action2.actions.MyAction"> + <result name="success" type="groovy"> + <param name="file">test.groovy</param> + </result> +</action> +</pre> +</div></div> +<p>The result type takes one parameter (for now), namely 'file', which contains the name of the groovy script in our script directory.</p> + +<h2 id="GroovyResult-Showmethecode!">Show me the code !</h2> + +<p>Here's the code of the actual GroovyResult. This is a verbose version, with a lot of error checking.</p> +<ul class="alternate"><li>source code +<div class="code panel pdl" style="border-width: 1px;"><div class="codeHeader panelHeader pdl" style="border-bottom-width: 1px;"><b>GroovyResult.java</b></div><div class="codeContent panelContent pdl"> +<pre class="brush: java; gutter: false; theme: Default" style="font-size:12px;"> +public class GroovyResult implements Result { + + public final static String GROOVY_DIR_NAME = "groovy"; + + private final static Logger logger = Logger.getLogger(GroovyResult.class); + //our groovy source file name + private String file; + //a groovy shell + private GroovyShell shell; + //our parsed script + private Script script; + //the outputstream that will replace the 'out' in our groovy stream + private OutputStream out; + //directory containing groovy scripts + private String scriptDirectory; + /* + * (non-Javadoc) + * + * @see com.opensymphony.xwork.Result#execute(com.opensymphony.xwork.ActionInvocation) + */ + public void execute(ActionInvocation inv) { + + //check the scriptDirectory - if it doesn't exists, use the default one + //WEBAPP + Groovy files directory + if (scriptDirectory == null) { + //not pretty, but this allows us to get the app root directory + String base = ServletActionContext.getServletContext().getRealPath( + "/"); + //if for some reason (.war, apache connector, ..) we can't get the + // base path + if (base == null) { + logger + .warn("Could not translate the virtual path \"/\" to set the default groovy script directory"); + return; + } + scriptDirectory = base + GROOVY_DIR_NAME; + //issue a warning that this directory should NOT be world readable + // !! + logger + .warn("Please make sure your script directory is NOT world readable !"); + } + + // first of all, make sure our groovy file exists, is readable, and is + // an actual file + + File groovyFile = new File(scriptDirectory, file); + if (!groovyFile.exists()) { + //log an error and return + logger.warn("Could not find destination groovy file: " + + groovyFile.getAbsolutePath()); + return; + } + if (!groovyFile.isFile()) { + //log an error and return + logger.warn("Destination is not a file: " + + groovyFile.getAbsolutePath()); + return; + } + if (!groovyFile.canRead()) { + //log an error and return + logger.warn("Can not read file: " + groovyFile.getAbsolutePath()); + return; + } + + if (logger.isDebugEnabled()) + logger.debug("File " + groovyFile.getPath() + + " found, going to parse it .."); + + /* + * Here we create a Binding object which we populate with the webwork + * stack + */ + Binding binding = new Binding(); + + binding.setVariable("context", ActionContext.getContext()); + + /* + * We replace the standard OutputStream with our own, in this case the + * OutputStream from our httpResponse + */ + try { + //the out will be stored in an OutputStream + out = ServletActionContext.getResponse().getOutputStream(); + } catch (IOException e1) { + logger.error("Could not open outputstream", e1); + } + if (out != null){ + binding.setVariable("out", out); + } + else { + logger + .warn("OutputStream not available, using default System.out instead"); + binding.setVariable("out", System.out); + } + + //create a new shell to parse and run our groovy file + shell = new GroovyShell(binding); + try { + //try to parse the script - the returned script could be cached for + //performance improvent + script = shell.parse(groovyFile); + } catch (CompilationFailedException e) { + logger.error("Could not parse groovy script", e); + return; + } catch (IOException e) { + logger.error("Error reading groovy script", e); + return; + } + //the binding is set, now run the script + Object result = script.run(); + + if (logger.isDebugEnabled()) { + logger.debug("Script " + groovyFile.getName() + + " executed, and returned: " + result); + } + try { + out.flush(); + } catch (IOException e2) { + logger.error("Could not flush the outputstream", e2); + } + } + + /** + * @return Returns the script. + */ + public Script getScript() { + return script; + } + /** + * @param file + * The file to set. + */ + public void setFile(String file) { + this.file = file; + } + /** + * @param out + * The out to set. + */ + public void setOut(OutputStream out) { + this.out = out; + } +</pre> +</div></div></li></ul> + + +<h2 id="GroovyResult-Explanation">Explanation</h2> + +<p>The first part of the result is little more than:</p> +<ul class="alternate"><li>determining the script directory - defaults to <code>MYWEBAPP/groovy/</code></li><li>checking the file - make sure it exists, is readable, .. +<div class="confluence-information-macro confluence-information-macro-note"><span class="aui-icon aui-icon-small aui-iconfont-warning confluence-information-macro-icon"></span><div class="confluence-information-macro-body"><p>Make sure the groovy scripts directory is not world readable !</p></div></div></li></ul> + + +<div class="code panel pdl" style="border-width: 1px;"><div class="codeHeader panelHeader pdl" style="border-bottom-width: 1px;"><b>The groovy part</b></div><div class="codeContent panelContent pdl"> +<pre class="brush: java; gutter: false; theme: Default" style="font-size:12px;"> +Binding binding = new Binding(); +binding.setVariable("context", ActionContext.getContext()); +</pre> +</div></div> +<p>A Binding object allows us to 'bind' objects to a groovy script, so they can be used as variables. In this case, I took the ActionContext and exposed it as 'context'.</p> +<div class="code panel pdl" style="border-width: 1px;"><div class="codeContent panelContent pdl"> +<pre class="brush: java; gutter: false; theme: Default" style="font-size:12px;"> +out = ServletActionContext.getResponse().getOutputStream(); +... +binding.setVariable("out", out); +</pre> +</div></div> +<p>We also bind an OutputStream to the groovy script (as 'out') - it simply serves as a replacement for the standard System.out, so any printing goes directly to the http response outputstream.</p> +<div class="code panel pdl" style="border-width: 1px;"><div class="codeContent panelContent pdl"> +<pre class="brush: java; gutter: false; theme: Default" style="font-size:12px;"> +shell = new GroovyShell(binding); +</pre> +</div></div> +<p>Next step; we create a GroovyShell, and pass our populated Binding to the constructor. Any script ran by this shell will have access to the passed variables (ActionContext and OutputStream).</p> +<div class="code panel pdl" style="border-width: 1px;"><div class="codeContent panelContent pdl"> +<pre class="brush: java; gutter: false; theme: Default" style="font-size:12px;"> +script = shell.parse(groovyFile); +</pre> +</div></div> +<p>Before you can run a groovyFile, you need to parse it. Any syntax errors will be reported here - I also suggest adding a better error reporting in this case if you actually want to use this Result.<br clear="none"> +Upon successful parsing, a Script is returned (which could be cached if you want to increase performance) which will be run by our Shell.</p> +<div class="code panel pdl" style="border-width: 1px;"><div class="codeContent panelContent pdl"> +<pre class="brush: java; gutter: false; theme: Default" style="font-size:12px;"> +Object result = script.run(); +</pre> +</div></div> +<p>As a test, you might want to create a little 'groovy' script to test our Result.<br clear="none"> +test.groovy - a simple groovy script</p> +<div class="code panel pdl" style="border-width: 1px;"><div class="codeContent panelContent pdl"> +<pre class="brush: java; gutter: false; theme: Default" style="font-size:12px;"> +for (item in context.contextMap){ + println "item: ${item}" +} +</pre> +</div></div> +<p>Place the test.groovy file in your groovy scripts directory. You should now see the result when you invoke MyAction.action in your browser.</p> + +<p>Possible improvements are binding all objects on the stack so they become available to the groovy script, refactoring to an InputStream instead of a File, etc .. Comments welcome !</p></div> + </div> + + + </div> +</div> +<div class="footer"> + Generated by CXF SiteExporter +</div> +</body> +</html>