blob: 374b4c366dbe8b13d234a6276267debb91a0b8db [file] [log] [blame]
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Webadmin</title>
<meta name="description" content="Apache TomEE">
<meta name="author" content="Apache TomEE">
<meta name="google-translate-customization" content="f36a520c08f4c9-0a04e86a9c075ce9-g265f3196f697cf8f-10">
<meta http-equiv="Pragma" content="no-cache">
<meta http-equiv="Expires" content="0">
<meta http-equiv="Cache-Control" content="no-store, no-cache, must-revalidate, max-age=0">
<!-- Le HTML5 shim, for IE6-8 support of HTML elements -->
<!--[if lt IE 9]>
<script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->
<!-- Le styles -->
<link href="./resources/css/bootstrap.css" rel="stylesheet">
<link href="./resources/css/prettify.css" rel="stylesheet">
<!--link href="./resources/css/bootstrap-mods.css" rel="stylesheet"-->
<link href="./resources/css/main.css" rel="stylesheet">
<link href="./resources/font-awesome-4.6.3/css/font-awesome.min.css" rel="stylesheet">
<script type="text/javascript">
var t = encodeURIComponent(document.title.replace(/^\s+|\s+$/g,""));
var u = encodeURIComponent(""+document.URL);
function fbshare () {
window.open(
"http://www.facebook.com/sharer/sharer.php?u="+u,
'Share on Facebook',
'width=640,height=426');
};
function gpshare () {
window.open(
"https://plus.google.com/share?url="+u,
'Share on Google+',
'width=584,height=385');
};
function twshare () {
window.open(
"https://twitter.com/intent/tweet?url="+u+"&text="+t,
'Share on Twitter',
'width=800,height=526');
};
function pinshare () {
window.open("//www.pinterest.com/pin/create/button/?url="+u+"&media=http%3A%2F%2Ftomee.apache.org%2Fresources%2Fimages%2Ffeather-logo.png&description="+t,
'Share on Pinterest',
'width=800,height=526');
};
</script>
<!-- Le fav and touch icons -->
<link rel="shortcut icon" href="./favicon.ico">
<link rel="apple-touch-icon" href="./resources/images/apple-touch-icon.png">
<link rel="apple-touch-icon" sizes="72x72" href="./resources/images/apple-touch-icon-72x72.png">
<link rel="apple-touch-icon" sizes="114x114" href="./resources/images/apple-touch-icon-114x114.png">
<script src="./resources/js/prettify.js" type="text/javascript"></script>
<script src="./resources/js/jquery-latest.js"></script>
<script src="http://platform.twitter.com/widgets.js" type="text/javascript"></script>
<script src="./resources/js/common.js"></script>
<script src="./resources/js/prettyprint.js"></script>
<!--script src="//assets.pinterest.com/js/pinit.js" type="text/javascript" async></script//-->
<script type="text/javascript">
var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-2717626-1']);
_gaq.push(['_setDomainName', 'apache.org']);
_gaq.push(['_trackPageview']);
(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();
</script>
</head>
<body>
<div class="topbar" data-dropdown="dropdown">
<div class="fill">
<div class="container">
<a class="brand" href="./index.html">Apache TomEE</a>
<ul class="nav">
<li class="dropdown">
<a class="dropdown-toggle" data-toggle="dropdown" href="#">
Apache
<b class="caret"></b>
</a>
<ul class="dropdown-menu">
<!-- <li><a href="./misc/whoweare.html">Who we are?</a></li> -->
<!-- <li><a href="./misc/heritage.html">Heritage</a></li> -->
<li><a href="http://www.apache.org">Apache Home</a></li>
<!-- <li><a href="./misc/resources.html">Resources</a></li> -->
<li><a href="./misc/contact.html">Contact</a></li>
<li><a href="./misc/legal.html">Legal</a></li>
<li><a href="http://www.apache.org/foundation/sponsorship.html">Sponsorship</a></li>
<li><a href="http://www.apache.org/foundation/thanks.html">Thanks</a></li>
<li class="divider"/>
<li><a href="http://www.apache.org/security">Security</a></li>
</ul>
</li>
<li><a href="./index.html">Home</a></li>
<li><a href="./downloads.html">Downloads</a></li>
<li><a href="./documentation.html">Documentation</a></li>
<li><a href="./examples-trunk/index.html">Examples</a></li>
<li><a href="./support.html">Support</a></li>
<li><a href="./contribute.html">Contribute</a></li>
<li><a href="./security/index.html">Security</a></li>
</ul>
<!-- Google CSE Search Box Begins -->
<FORM class="pull-right" id="searchbox_010475492895890475512:_t4iqjrgx90" action="http://www.google.com/cse">
<INPUT type="hidden" name="cx" value="010475492895890475512:_t4iqjrgx90">
<INPUT type="hidden" name="cof" value="FORID:0">
<INPUT size="18" width="130" style="width:130px" name="q" type="text" placeholder="Search">
</FORM>
<!--<SCRIPT type="text/javascript" src="http://www.google.com/coop/cse/brand?form=searchbox_010475492895890475512:_t4iqjrgx90"></SCRIPT>-->
<!-- Google CSE Search Box Ends -->
</div>
</div>
</div>
<div class="container">
<div class="page-header">
<small><a href="./index.html">Home</a></small><br>
<h1>Webadmin
<div style="float: right; position: relative; bottom: -10px; ">
<a onclick="javascript:gpshare()" class="gp-share sprite" title="Share on Google+">share [gp]</a>
<a onclick="javascript:fbshare()" class="fb-share sprite" title="Share on Facebook">share [fb]</a>
<a onclick="javascript:twshare()" class="tw-share sprite" title="Share on Twitter">share [tw]</a>
<a onclick="javascript:pinshare()" class="pin-share sprite" title="Share on Pinterest">share [pin]</a>
<a data-toggle="modal" href="#edit" class="edit-page" title="Contribute to this Page">contribute</a>
</div>
</h1>
</div>
<p>The Webadmin is a new addition to OpenEJB 1.0 and very innovative in that
it lets you plug-in your own admin beans. Here are some screenshots:</p>
<ul>
<li><a href="http://tomee.apache.org/images/webadmin-main.png">Main</a></li>
<li><a href="http://tomee.apache.org/images/webadmin-ejbdetails.png">EJB Details</a></li>
<li><a href="http://tomee.apache.org/images/webadmin-listlogs.png">List Logs</a></li>
<li><a href="http://tomee.apache.org/images/webadmin-properties.png">System Properties</a></li>
<li><a href="http://tomee.apache.org/images/webadmin-viewjndi.png">JNDI Viewer</a></li>
<li><a href="http://tomee.apache.org/images/webadmin-ejbviewer.png">EJB Viewer</a></li>
<li><a href="http://tomee.apache.org/images/webadmin-objectinvoker.png">Object and EJB Invoker</a></li>
</ul>
<p><a name="Webadmin-EnablingtheWebadminin1.0beta1"></a></p>
<h2>Enabling the Webadmin in 1.0 beta 1</h2>
<p>The Webadmin console is in the 1.0 beta 1 release. To enable it, simply
move into the openejb.home directory and <em>copy</em> the
openejb-webadmin-main.jar from the <em>beans</em> directory into the <em>lib</em>
directory. Then start the server.</p>
<pre><code>mingus:~/
$ cd /usr/local/openejb-1.0-beta1
mingus:/usr/local/openejb-1.0-beta1 03:37:33
$ cp beans/openejb-webadmin-main.jar lib/
mingus:/usr/local/openejb-1.0-beta1 03:37:52
$ ./bin/openejb start
OPENEJB_HOME = /usr/local/openejb-1.0-beta1
OpenEJB 1.0-beta1 build: 20050829-2233
http://www.openejb.org
resources 1
OpenEJB ready.
[init]
</code></pre>
<p>OpenEJB Remote Server
<em>* Starting Services *</em>
NAME IP PORT <br />
admin thread 127.0.0.1 4200 <br />
ejbd 127.0.0.1 4201 <br />
telnet 127.0.0.1 4202 <br />
webadmin 127.0.0.1 4203 <br />
-------
Ready!</p>
<p>Now you can open your browser to go to http://localhost:4203/</p>
<p><a name="Webadmin-WebAdminBeans"></a></p>
<h1>WebAdmin Beans</h1>
<p>To create an EJB and have it included as part of the WebAdmin, simply
subclass from WebAdminBean and include it in your ejb-jar.xml file as such:</p>
<pre><code>&lt;session&gt;
&lt;description&gt;A JNDI viewer&lt;/description&gt;
&lt;ejb-name&gt;webadmin/ViewJndi&lt;/ejb-name&gt;
&lt;home&gt;org.openejb.webadmin.HttpHome&lt;/home&gt;
&lt;remote&gt;org.openejb.webadmin.HttpObject&lt;/remote&gt;
&lt;ejb-class&gt;org.openejb.webadmin.clienttools.ViewJndiBean&lt;/ejb-class&gt;
&lt;session-type&gt;Stateless&lt;/session-type&gt;
&lt;transaction-type&gt;Bean&lt;/transaction-type&gt;
&lt;/session&gt;
</code></pre>
<p>The ejb-name is used to create the menus and should follow the format of
'menu-section/menu-item'. WebAdminBeans are grouped together by the
'menu-section' portion of their ejb-name. The 'menu-item' is the clickable
link that causes the EJB code to be execute. Very simple and makes it
possible to package administrative components with your EJB applications.</p>
<h1>WebAdmin Plugins</h1>
<p>Here is a project that already takes advantage of the new feature. [BeanGen|http://beangen.sourceforge.net]</p>
<h1>Developers guide</h1>
<p>Below is David Blevins' email on how webadmin worked. Please have a look at
the text below before you start working on porting the existing WebAdmin to
version 3.</p>
<p>Plain old stateless beans were used as the "servlets". To make a bean that
would show up in the Webadmin Console you simply had to implement the
HttpBean interface (i think it's now called HttpListener) and give your
bean a deploymentId following this format "webadmin/{section}/{page}".
Anyone could add to the Webadmin console by doing both of these things,
which is really cool as people developing EJB apps can also deploy beans
for administering those apps right in the exact same jar. This is not only
easy for packaging but means new sections can be added/removed on the fly.</p>
<p>Using the described "webadmin/{section}/{page}" deploymentId format,
things end up automagically grouped in the JNDI tree. There's a 'webadmin'
context we grab which will contain any number of "section" contexts
("ClientTools", "EJBGenerator", etc.). Each of those section subcontexts
will contain several beans which we will use to make the pages. Making the
menu is pretty easy as we just iterate over the webadmin section of the
global jndi tree.</p>
<p>When an http request came in we just took the path part of the GET or POST
request, prepended "webadmin/" and then went looking for a bean with that
deployment id and invoked it via it's HttpBean (now called HttpListener)
interface passing in a HttpRequest and HttpResponse objects which are
trimmed down versions of similar servlet classes.
There'll be some changes to this as now we support our plain ejb protocol
over our http implementation, so the two will have to find a way to share
the URL space. See the openejb-http module.</p>
<p>To implement session state, we had a stateful session bean implementing an
HttpSession interface (again, similar to the servlet equivalent) and simply
wrote the internal ID of the bean instance into a Cookie sent to the
browser. For some reason we would write the javax.ejb.Handle of the
stateful bean's EJBObject to disk and
read it back out on subsequent requests then used it to get a reference to
the EJBObject again. I'm not sure why we didn't just keep a static hashmap
and put the EJBObject right in it using an ID we could just make up like
UUID (that would have been way simpler).</p>
<p>We had a standard superclass we favored for beans that implemented the
HttpBean (HttpListener) interface that did templating and the
aforementioned menu construction. The templating was perhaps too tricky
as we used a non-printable character to determine where to insert data.
Now we could just use swizzle-stream for some pretty decent templating
ability or even velocity. I'd be hesitant to endorse velocity as we
already have a dep on swizzle-stream and wouldn't want to see us add
another meg to our distro size if we can avoid it -- we have like 3 times
as many deps as 1.0 did and we should probably start tightening the belt.</p>
<p>To serve static things like images, we had a "default" HttpBean which
searched for the items in the classpath and wrote them into the response
setting the mime type, etc. correctly. One thing that we never did which
still needs to happen is that the bean didn't have the logic to set the
modification information into the response so the "If modified since"
header which would allow the browser to rely on it's cache instead of
requesting the same images over and over again.</p>
<p>That pretty much covers the way it was put together.</p>
<ul>
<li>The Jndi Viewer, Class Viewer, Ejb Viewer, and Object Invoker were written by yours truly</li>
<li>The EJB Generator was written by Jeremy Whitlock</li>
<li>Everything else was written by Tim Urberg. Tim was "WebAdmin guy" for
a good long while. Before Tim came along the webadmin was just some
experimental code I had in a branch, he did more than he realizes by putting his energy
into it -- active people attract/ create more active people. Maybe we can
convince him to come back and work on it ;)</li>
</ul>
<p>And of course I have to mention our own Paulo Lopes who wrote a really cool
project out in SF.net (http://beangen.sourceforge.net/) which was the first
plugin for the OpenEJB Webadmin. He wrote it before we even had shipped a
release containing the Webadmin or had any docs at all on it, which in my
mind shows just how neat the idea of using ejb's and simple conventions to
do the console really is.</p>
<p>Some notes going forward is that we have a truck load of meta-data now
available via SystemInstance.get().get (OpenEjbConfiguration.class).
Certainly JSR-77 is one option, but we could do far better with plain old
java code. That tree is the primary source of meta-data for OpenEJB, it's
what was used to construct every container, bean, resource adapter,
database connector and <em>everything</em> in the system (well, sans the
protocols). Someone new to the project can look at it and understand it
without having to read any abstract specs. Something to consider. The
tree is read only in it's function, however it is possible to copy then
edit and make new containers, etc. based on existing definitions.</p>
<p>Additionally, using this same data structure it's possible to show the
potential services available via the service-jar.xml files in the classpath
that detail containers, resource adapters, database connectors, etc. which
can be configured/created at runtime. So we could also display a sort of
catalogue of components (aka. services) that someone could click and deploy
via the console.</p>
<div id="edit" class="modal hide fade in" style="display: none; ">
<div class="modal-header">
<a class="close" data-dismiss="modal">x</a>
<h3>Thank you for contributing to the documentation!</h3>
</div>
<div class="modal-body">
<h4>Any help with the documentation is greatly appreciated.</h4>
<p>All edits are reviewed before going live, so feel free to do much more than fix typos or links. If you see a page that could benefit from an entire rewrite, we'd be thrilled to review it. Don't be surprised if we like it so much we ask you for help with other pages :)</p>
<small>NOTICE: unless indicated otherwise on the pages in question, all editable content available from apache.org is presumed to be licensed under the Apache License (AL) version 2.0 and hence all submissions to apache.org treated as formal Contributions under the license terms.</small>
<!--[if gt IE 6]>
<h4>Internet Explorer Users</h4>
<p>If you are not an Apache committer, click the Yes link and enter a <i>anonymous</i> for the username and leave the password empty</p>
<![endif]-->
</div>
<div class="modal-footer">
Do you have an Apache ID?
<a href="javascript:void(location.href='https://cms.apache.org/redirect?uri='+escape(location.href))" class="btn">Yes</a>
<a href="javascript:void(location.href='https://anonymous:@cms.apache.org/redirect?uri='+escape(location.href))" class="btn">No</a>
</div>
</div>
<script src="./resources/js/bootstrap-modal.js"></script>
<footer>
<p>Copyright &copy; 1999-2016 The Apache Software Foundation, Licensed under the Apache License, Version 2.0.
Apache TomEE, TomEE, Apache, the Apache feather logo, and the Apache TomEE project logo are trademarks of The Apache Software Foundation.
All other marks mentioned may be trademarks or registered trademarks of their respective owners.</p>
</footer>
</div> <!-- /container -->
<!-- Javascript
================================================== -->
<!-- Placed at the end of the document so the pages load faster -->
<script src="./resources/js/bootstrap-dropdown.js"></script>
</body>
</html>