blob: e710de311e8fa50d21ebd9b686431d5d2726f6f0 [file] [log] [blame]
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Apache TomEE</title>
<meta name="description"
content="Apache TomEE is a lightweight, yet powerful, JavaEE Application server with feature rich tooling." />
<meta name="keywords" content="tomee,asf,apache,javaee,jee,shade,embedded,test,junit,applicationcomposer,maven,arquillian" />
<meta name="author" content="Luka Cvetinovic for Codrops" />
<link rel="icon" href="../favicon.ico">
<link rel="icon" type="image/png" href="../favicon.png">
<meta name="msapplication-TileColor" content="#80287a">
<meta name="theme-color" content="#80287a">
<link rel="stylesheet" type="text/css" href="../css/normalize.css">
<link rel="stylesheet" type="text/css" href="../css/bootstrap.css">
<link rel="stylesheet" type="text/css" href="../css/owl.css">
<link rel="stylesheet" type="text/css" href="../css/animate.css">
<link rel="stylesheet" type="text/css" href="../fonts/font-awesome-4.1.0/css/font-awesome.min.css">
<link rel="stylesheet" type="text/css" href="../fonts/eleganticons/et-icons.css">
<link rel="stylesheet" type="text/css" href="../css/jqtree.css">
<link rel="stylesheet" type="text/css" href="../css/idea.css">
<link rel="stylesheet" type="text/css" href="../css/cardio.css">
<script type="text/javascript">
<!-- Matomo -->
var _paq = window._paq = window._paq || [];
/* tracker methods like "setCustomDimension" should be called before "trackPageView" */
/* We explicitly disable cookie tracking to avoid privacy issues */
_paq.push(['disableCookies']);
_paq.push(['trackPageView']);
_paq.push(['enableLinkTracking']);
(function () {
var u = "//matomo.privacy.apache.org/";
_paq.push(['setTrackerUrl', u + 'matomo.php']);
_paq.push(['setSiteId', '5']);
var d = document, g = d.createElement('script'), s = d.getElementsByTagName('script')[0];
g.async = true;
g.src = u + 'matomo.js';
s.parentNode.insertBefore(g, s);
})();
<!-- End Matomo Code -->
</script>
</head>
<body>
<div class="preloader">
<img src="../img/loader.gif" alt="Preloader image">
</div>
<nav class="navbar">
<div class="container">
<div class="row"> <div class="col-md-12">
<!-- Brand and toggle get grouped for better mobile display -->
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="/" title="Apache TomEE">
<span>
<img
src="../img/apache_tomee-logo.svg"
onerror="this.src='../img/apache_tomee-logo.jpg'"
height="50"
>
</span>
</a>
</div>
<!-- Collect the nav links, forms, and other content for toggling -->
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
<ul class="nav navbar-nav navbar-right main-nav">
<li><a href="../docs.html">Documentation</a></li>
<li><a href="../community/index.html">Community</a></li>
<li><a href="../security/security.html">Security</a></li>
<li><a class="btn btn-accent accent-orange no-shadow" href="../download.html">Downloads</a></li>
</ul>
</div>
<!-- /.navbar-collapse -->
</div></div>
</div>
<!-- /.container-fluid -->
</nav>
<div id="main-block" class="container main-block">
<div class="row title">
<div class="col-md-12">
<div class='page-header'>
<h1>xbean-finder</h1>
</div>
</div>
</div>
<div class="row">
<div class="col-md-12">
<div class="sect1">
<h2 id="_annotationfinder">AnnotationFinder</h2>
<div class="sectionbody">
<div class="paragraph">
<p>It uses ASM create an index of annotations and classes in a specific archive.
Reason for using ASM are:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>Security: Loading classes involves executing static initializers.
Imagine doing this for every class in every jar.</p>
</li>
<li>
<p>Speed: Loading all those classes is slow</p>
</li>
<li>
<p>Memory: Chews up permgen space quickly and needlessly.
Additional note, see above, some static initializers may hook themselves into the system and make the entire classloader (and the thousands of classes loaded) impossible to GC.</p>
</li>
</ul>
</div>
<div class="sect2">
<h3 id="_usage">Usage</h3>
<div class="paragraph">
<p>Say you had an <code>@Plugin</code> annotation you used, you could do as follows and skip the whole <code>META-INF</code> business:</p>
</div>
<div class="literalblock">
<div class="content">
<pre>AnnotationFinder finder = new AnnotationFinder(new JarArchive(classloader, jarUrl));
List&lt;Class&lt;?&gt;&gt; plugins = finder.findAnnotatedClasses(Plugin.class);</pre>
</div>
</div>
<div class="paragraph">
<p>That&#8217;s the basics.</p>
</div>
<div class="literalblock">
<div class="content">
<pre>public class AnnotationFinder {
boolean isAnnotationPresent(Class&lt;? extends Annotation&gt; annotation);
List&lt;String&gt; getClassesNotLoaded();
List&lt;Package&gt; findAnnotatedPackages(Class&lt;? extends Annotation&gt; annotation);
List&lt;Class&lt;?&gt;&gt; findAnnotatedClasses(Class&lt;? extends Annotation&gt; annotation);
List&lt;Class&lt;?&gt;&gt; findInheritedAnnotatedClasses(Class&lt;? extends Annotation&gt; annotation);
List&lt;Method&gt; findAnnotatedMethods(Class&lt;? extends Annotation&gt; annotation);
List&lt;Constructor&gt; findAnnotatedConstructors(Class&lt;? extends Annotation&gt; annotation);
List&lt;Field&gt; findAnnotatedFields(Class&lt;? extends Annotation&gt; annotation);
List&lt;Class&lt;?&gt;&gt; findClassesInPackage(String packageName, boolean recursive);
&lt;T&gt; List&lt;Class&lt;? extends T&gt;&gt; findSubclasses(Class&lt;T&gt; clazz);
&lt;T&gt; List&lt;Class&lt;? extends T&gt;&gt; findImplementations(Class&lt;T&gt; clazz);
List&lt;Annotated&lt;Method&gt;&gt; findMetaAnnotatedMethods(Class&lt;? extends Annotation&gt; annotation);
List&lt;Annotated&lt;Field&gt;&gt; findMetaAnnotatedFields(Class&lt;? extends Annotation&gt; annotation);
List&lt;Annotated&lt;Class&lt;?&gt;&gt;&gt; findMetaAnnotatedClasses(Class&lt;? extends Annotation&gt; annotation);
List&lt;String&gt; getAnnotatedClassNames();
}</pre>
</div>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_archive">Archive</h2>
<div class="sectionbody">
<div class="paragraph">
<p>So what we have now is a composable system.
You create your finder and feed it an archive, like so:</p>
</div>
<div class="literalblock">
<div class="content">
<pre>Archive archive = new JarArchive(classloader, jarURL);
AnnotationFinder finder = new AnnotationFinder( archive );
List&lt;Class&lt;?&gt;&gt; plugins = finder.findAnnotatedClasses(PluginAnnotation.class)</pre>
</div>
</div>
<div class="paragraph">
<p>If you want some filtering, you add that in:</p>
</div>
<div class="literalblock">
<div class="content">
<pre>Archive archive = new JarArchive(classloader, jarURL);
archive = new FilteredArchive(archive, new Filter {
@Override
public boolean accept(String name) {
return name.startsWith("org.foo.");
}
});
AnnotationFinder finder = new AnnotationFinder( archive );
List&lt;Class&lt;?&gt;&gt; plugins = finder.findAnnotatedClasses(PluginAnnotation.class)</pre>
</div>
</div>
<div class="paragraph">
<p>Several archives can be composed together via <code>CompositeArchive</code></p>
</div>
<div class="literalblock">
<div class="content">
<pre>Archive archive = new CompositeArchive(
new JarArchive(classloader, jarURL),
new FileArchive(classloader, new File("target/classes/")),
new ClassesArchive(Foo.class, Bar.class)
);</pre>
</div>
</div>
<div class="paragraph">
<p>Sky is the limit.</p>
</div>
<div class="paragraph">
<p>We have the following <code>Archive</code> implementations</p>
</div>
<div class="ulist">
<ul>
<li>
<p>ClassesArchive(Class&lt;?&gt;&#8230;&#8203;
classes)</p>
</li>
<li>
<p>ClassesArchive(Iterable&lt;Class&lt;?&gt;&gt; classes)</p>
</li>
<li>
<p>FileArchive(ClassLoader loader, URL url)</p>
</li>
<li>
<p>FileArchive(ClassLoader loader, File dir)</p>
</li>
<li>
<p>JarArchive(ClassLoader loader, URL url)</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>For creating combinations of the above we have:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>CompositeArchive(Archive&#8230;&#8203;
archives)</p>
</li>
<li>
<p>CompositeArchive(Iterable<Archive>archives)</Archive></p>
</li>
</ul>
</div>
<div class="paragraph">
<p>For filtering classes out of archvies:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>FilteredArchive(Archive archive, Filter filter)</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>And a convenience class to quickly get an Archive from a set of urls</p>
</div>
<div class="ulist">
<ul>
<li>
<p>ClasspathArchive(ClassLoader loader, URL&#8230;&#8203;
urls)</p>
</li>
<li>
<p>ClasspathArchive(ClassLoader loader, Iterable<URL>urls)</URL></p>
</li>
</ul>
</div>
<div class="paragraph">
<p>The above currently only supports <code>jar:</code> and <code>file:</code> urls</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_filters">Filters</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Several built in filters exist for convenience</p>
</div>
<div class="ulist">
<ul>
<li>
<p>ClassFilter(String name)</p>
</li>
<li>
<p>ContainsFilter(String token)</p>
</li>
<li>
<p>PackageFilter(String packageName)</p>
</li>
<li>
<p>PatternFilter(String expression)</p>
</li>
<li>
<p>PatternFilter(Pattern pattern)</p>
</li>
<li>
<p>PrefixFilter(String prefix)</p>
</li>
<li>
<p>SuffixFilter(String suffix)</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>As well as some filter implementations that allow all of the above to be composed together</p>
</div>
<div class="ulist">
<ul>
<li>
<p>ExcludeIncludeFilter(Filter include, Filter exclude)</p>
</li>
<li>
<p>FilterList(Filter&#8230;&#8203;
filters)</p>
</li>
<li>
<p>FilterList(Iterable<Filter>filters)</Filter></p>
</li>
<li>
<p>IncludeExcludeFilter(Filter include, Filter exclude)</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>And the following convenience class for quickly creating any of the above</p>
</div>
<div class="literalblock">
<div class="content">
<pre>public class Filters {
public static Filter packages(String... packages) {
public static Filter classes(String... classes) {
public static Filter prefixes(String... prefixes) {
public static Filter tokens(String... tokens) {
public static Filter suffixes(String... suffixes) {
public static Filter patterns(String... patterns) {
public static Filter optimize(Filter... filters) {
public static Filter optimize(List&lt;Filter&gt;... filterss) {
public static Filter invert(Filter filter) {
}</pre>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_resourcefinder">ResourceFinder</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Something similar to Java 6 ServiceLoader, except doesn&#8217;t do the instantiations, but you could add that for yourself very easily.</p>
</div>
<div class="paragraph">
<p>Using the same <code>META-INF</code> layout and files as you posted, you can do like:</p>
</div>
<div class="literalblock">
<div class="content">
<pre>ResourceFinder finder = new ResourceFinder("META-INF/services/");
List plugins = finder.findAllImplementations(Plugin.class);</pre>
</div>
</div>
<div class="paragraph">
<p>A little neater if you adjusted your META-INF layout as follows</p>
</div>
<div class="literalblock">
<div class="content">
<pre>META-INF/com.example.plugins.Plugins/red
META-INF/com.example.plugins.Plugins/blue</pre>
</div>
</div>
<div class="paragraph">
<p>&#8230;&#8203;where the "red" file contained the text "com.example.plugins.RedPlugin" and the "blue" file contained the text "com.example.plugins.BluePlugin", you could then get them in a map like so:
Map plugins = finder.mapAvailableImplementations(Plugin.class);
Class red = plugins.get("red");
Class blue = plugins.get("blue");</p>
</div>
<div class="paragraph">
<p>Now say you want to do something similar, but the "red" and "blue" files are properties files which contain the name of the implementation class and other configurable properties for your red and blue plugins.</p>
</div>
<div class="literalblock">
<div class="content">
<pre>ResourceFinder finder = new ResourceFinder("META-INF/services/");
Map pluginConfigs = finder.mapAllProperties(Plugin.class.getName());
Properties redConfig = pluginConfigs.get("red");
Properties blueConfig = pluginConfigs.get("blue");</pre>
</div>
</div>
<div class="paragraph">
<p>Object instantiation was never written into any of those libraries because we&#8217;re big fans of xbean-reflect package, which is a real "don&#8217;t tell me what to do" library for when you just want to create a simple object and would like to get real basic field/setter/constructor injection without choking down a whole "i control everything" framework.</p>
</div>
<div class="paragraph">
<p>You just:</p>
</div>
<div class="literalblock">
<div class="content">
<pre>ObjectRecipe recpie = new ObjectRecipe("com.example.plugins.RedPlugin");
recpie.setProperty("myDateField","2008-04-17"); recpie.setProperty("myIntField","100");
recpie.setProperty("myBooleanField","true");
recpie.setProperty("myUrlField","http://www.theserverside.com");
Plugin red = (Plugin) recpie.create();
red.start();</pre>
</div>
</div>
<div class="paragraph">
<p>Obviously, the above style to object creation couples really well to the <code>ResourceFinder</code> method that gives you Properties objects back.
You put the class name and config for your plugin in the properties files and pass the properties right into the ObjectRecipe and more or less get a little do-it-yourself IoC plugin system.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="_openejbtomee">OpenEJB/TomEE</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Here is a grep of some of the calls made to <code>AnnotationFinder</code>.
Most of this code is in an OpenEJB class called <code>AnnotationDeployer</code> whose primary job is to merge the @annotation and <xml>metadata into one tree.</xml></p>
</div>
<div class="literalblock">
<div class="content">
<pre> for (Annotated&lt;Class&lt;?&gt;&gt; clazz : finder.findMetaAnnotatedClasses(LocalClient.class)) {
for (Annotated&lt;Class&lt;?&gt;&gt; clazz : finder.findMetaAnnotatedClasses(RemoteClient.class)) {
List&lt;Class&lt;?&gt;&gt; connectorClasses = finder.findAnnotatedClasses(Connector.class);
List&lt;Class&lt;?&gt;&gt; classes = finder.findAnnotatedClasses(ConnectionDefinitions.class);
classes = finder.findAnnotatedClasses(ConnectionDefinition.class);
classes = finder.findAnnotatedClasses(Activation.class);
classes = finder.findAnnotatedClasses(AdministeredObject.class);
classes.addAll(finder.findAnnotatedClasses(WebService.class));
classes.addAll(finder.findAnnotatedClasses(WebServiceProvider.class));
for (Annotated&lt;Class&lt;?&gt;&gt; beanClass : finder.findMetaAnnotatedClasses(Singleton.class)) {
for (Annotated&lt;Class&lt;?&gt;&gt; beanClass : finder.findMetaAnnotatedClasses(Stateless.class)) {
for (Annotated&lt;Class&lt;?&gt;&gt; beanClass : finder.findMetaAnnotatedClasses(Stateful.class)) {
for (Annotated&lt;Class&lt;?&gt;&gt; beanClass : finder.findMetaAnnotatedClasses(ManagedBean.class)) {
for (Annotated&lt;Class&lt;?&gt;&gt; beanClass : finder.findMetaAnnotatedClasses(MessageDriven.class)) {
List&lt;Class&lt;?&gt;&gt; appExceptions = finder.findAnnotatedClasses(ApplicationException.class);
List&lt;Class&lt;?&gt;&gt; list = finder.findAnnotatedClasses(annotation);
final List&lt;Annotated&lt;Class&lt;?&gt;&gt;&gt; annotatedClasses = sortClasses(annotationFinder.findMetaAnnotatedClasses(Interceptors.class));
final List&lt;Annotated&lt;Method&gt;&gt; annotatedMethods = sortMethods(annotationFinder.findMetaAnnotatedMethods(Interceptors.class));
for (Annotated&lt;Method&gt; method : annotationFinder.findMetaAnnotatedMethods(ExcludeDefaultInterceptors.class)) {
for (Annotated&lt;Method&gt; method : sortMethods(annotationFinder.findMetaAnnotatedMethods(ExcludeClassInterceptors.class))) {
if (annotationFinder.isAnnotationPresent(Path.class) || !annotationFinder.findAnnotatedMethods(Path.class).isEmpty()) {
for (Annotated&lt;Method&gt; method : annotationFinder.findMetaAnnotatedMethods(Asynchronous.class)) {
for (Annotated&lt;Class&lt;?&gt;&gt; clazz : annotationFinder.findMetaAnnotatedClasses(Asynchronous.class)) {
for (Annotated&lt;Method&gt; method : annotationFinder.findMetaAnnotatedMethods(RolesAllowed.class)) {
for (Annotated&lt;Method&gt; method : annotationFinder.findMetaAnnotatedMethods(PermitAll.class)) {
for (Annotated&lt;Method&gt; method : annotationFinder.findMetaAnnotatedMethods(DenyAll.class)) {
scheduleMethods.addAll(annotationFinder.findMetaAnnotatedMethods(javax.ejb.Schedules.class));
scheduleMethods.addAll(annotationFinder.findMetaAnnotatedMethods(javax.ejb.Schedule.class));
for (Annotated&lt;Method&gt; method : sortMethods(annotationFinder.findMetaAnnotatedMethods(PostConstruct.class))) {
for (Annotated&lt;Method&gt; method : sortMethods(annotationFinder.findMetaAnnotatedMethods(PreDestroy.class))) {
for (Annotated&lt;Method&gt; method : sortMethods(annotationFinder.findMetaAnnotatedMethods(javax.interceptor.AroundInvoke.class))) {
for (Annotated&lt;Method&gt; method : sortMethods((annotationFinder.findMetaAnnotatedMethods(javax.interceptor.AroundTimeout.class)))) {
List&lt;Annotated&lt;Method&gt;&gt; timeoutMethods = sortMethods(annotationFinder.findMetaAnnotatedMethods(javax.ejb.Timeout.class));
for (Annotated&lt;Method&gt; method : sortMethods(annotationFinder.findMetaAnnotatedMethods(AfterBegin.class))) {
for (Annotated&lt;Method&gt; method : sortMethods(annotationFinder.findMetaAnnotatedMethods(BeforeCompletion.class))) {
for (Annotated&lt;Method&gt; method : sortMethods(annotationFinder.findMetaAnnotatedMethods(AfterCompletion.class))) {
for (Annotated&lt;Method&gt; method : sortMethods(annotationFinder.findMetaAnnotatedMethods(PostActivate.class))) {
for (Annotated&lt;Method&gt; method : sortMethods(annotationFinder.findMetaAnnotatedMethods(PrePassivate.class))) {
for (Annotated&lt;Method&gt; method : sortMethods(annotationFinder.findMetaAnnotatedMethods(Init.class))) {
List&lt;Annotated&lt;Method&gt;&gt; removeMethods = sortMethods(annotationFinder.findMetaAnnotatedMethods(Remove.class));
for (Annotated&lt;Class&lt;?&gt;&gt; clazz : annotationFinder.findMetaAnnotatedClasses(EJBs.class)) {
for (Annotated&lt;Class&lt;?&gt;&gt; clazz : annotationFinder.findMetaAnnotatedClasses(EJB.class)) {
for (Annotated&lt;Field&gt; field : annotationFinder.findMetaAnnotatedFields(EJB.class)) {
for (Annotated&lt;Method&gt; method : annotationFinder.findMetaAnnotatedMethods(EJB.class)) {
for (Annotated&lt;Class&lt;?&gt;&gt; clazz : annotationFinder.findMetaAnnotatedClasses(Resources.class)) {
for (Annotated&lt;Class&lt;?&gt;&gt; clazz : annotationFinder.findMetaAnnotatedClasses(Resource.class)) {
for (Annotated&lt;Field&gt; field : annotationFinder.findMetaAnnotatedFields(Resource.class)) {
for (Annotated&lt;Method&gt; method : annotationFinder.findMetaAnnotatedMethods(Resource.class)) {
for (Annotated&lt;Class&lt;?&gt;&gt; clazz : annotationFinder.findMetaAnnotatedClasses(WebServiceRefs.class)) {
for (Annotated&lt;Class&lt;?&gt;&gt; clazz : annotationFinder.findMetaAnnotatedClasses(WebServiceRef.class)) {
for (Annotated&lt;Field&gt; field : annotationFinder.findMetaAnnotatedFields(WebServiceRef.class)) {
for (Annotated&lt;Method&gt; method : annotationFinder.findMetaAnnotatedMethods(WebServiceRef.class)) {
for (Annotated&lt;Class&lt;?&gt;&gt; clazz : annotationFinder.findMetaAnnotatedClasses(PersistenceUnits.class)) {
for (Annotated&lt;Class&lt;?&gt;&gt; clazz : annotationFinder.findMetaAnnotatedClasses(PersistenceUnit.class)) {
for (Annotated&lt;Field&gt; field : annotationFinder.findMetaAnnotatedFields(PersistenceUnit.class)) {
for (Annotated&lt;Method&gt; method : annotationFinder.findMetaAnnotatedMethods(PersistenceUnit.class)) {
for (Annotated&lt;Class&lt;?&gt;&gt; clazz : annotationFinder.findMetaAnnotatedClasses(PersistenceContexts.class)) {
for (Annotated&lt;Class&lt;?&gt;&gt; clazz : annotationFinder.findMetaAnnotatedClasses(PersistenceContext.class)) {
for (Annotated&lt;Field&gt; field : annotationFinder.findMetaAnnotatedFields(PersistenceContext.class)) {
for (Annotated&lt;Method&gt; method : annotationFinder.findMetaAnnotatedMethods(PersistenceContext.class)) {
int ann = annotationFinder.findAnnotatedClasses(handler.getAnnotationClass()).size();
ann += annotationFinder.findAnnotatedMethods(handler.getAnnotationClass()).size();
List&lt;Annotated&lt;Class&lt;?&gt;&gt;&gt; types = sortClasses(annotationFinder.findMetaAnnotatedClasses(annotationClass));
List&lt;Annotated&lt;Method&gt;&gt; methods = annotationFinder.findMetaAnnotatedMethods(annotationClass);
List&lt;Class&lt;?&gt;&gt; annotatedClasses = finder.findAnnotatedClasses(Path.class);
methods.addAll(finder.findAnnotatedMethods(Path.class));</pre>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div style="margin-bottom: 30px;"></div>
<footer>
<div class="container">
<div class="row">
<div class="col-sm-6 text-center-mobile">
<h3 class="white">Be simple. Be certified. Be Tomcat.</h3>
<h5 class="light regular light-white">"A good application in a good server"</h5>
<ul class="social-footer">
<li><a href="https://www.facebook.com/ApacheTomEE/"><i class="fa fa-facebook"></i></a></li>
<li><a href="https://twitter.com/apachetomee"><i class="fa fa-twitter"></i></a></li>
</ul>
<h5 class="light regular light-white">
<a href="../privacy-policy.html" class="white">Privacy Policy</a>
</h5>
</div>
<div class="col-sm-6 text-center-mobile">
<div class="row opening-hours">
<div class="col-sm-3 text-center-mobile">
<h5><a href="../latest/docs/" class="white">Documentation</a></h5>
<ul class="list-unstyled">
<li><a href="../latest/docs/admin/configuration/index.html" class="regular light-white">How to configure</a></li>
<li><a href="../latest/docs/admin/file-layout.html" class="regular light-white">Dir. Structure</a></li>
<li><a href="../latest/docs/developer/testing/index.html" class="regular light-white">Testing</a></li>
<li><a href="../latest/docs/admin/cluster/index.html" class="regular light-white">Clustering</a></li>
</ul>
</div>
<div class="col-sm-3 text-center-mobile">
<h5><a href="../latest/examples/" class="white">Examples</a></h5>
<ul class="list-unstyled">
<li><a href="../latest/examples/simple-cdi-interceptor.html" class="regular light-white">CDI Interceptor</a></li>
<li><a href="../latest/examples/rest-cdi.html" class="regular light-white">REST with CDI</a></li>
<li><a href="../latest/examples/ejb-examples.html" class="regular light-white">EJB</a></li>
<li><a href="../latest/examples/jsf-managedBean-and-ejb.html" class="regular light-white">JSF</a></li>
</ul>
</div>
<div class="col-sm-3 text-center-mobile">
<h5><a href="../community/index.html" class="white">Community</a></h5>
<ul class="list-unstyled">
<li><a href="../community/contributors.html" class="regular light-white">Contributors</a></li>
<li><a href="../community/social.html" class="regular light-white">Social</a></li>
<li><a href="../community/sources.html" class="regular light-white">Sources</a></li>
</ul>
</div>
<div class="col-sm-3 text-center-mobile">
<h5><a href="../security/index.html" class="white">Security</a></h5>
<ul class="list-unstyled">
<li><a href="https://apache.org/security" target="_blank" class="regular light-white">Apache Security</a></li>
<li><a href="https://apache.org/security/projects.html" target="_blank" class="regular light-white">Security Projects</a></li>
<li><a href="https://cve.mitre.org" target="_blank" class="regular light-white">CVE</a></li>
</ul>
</div>
</div>
</div>
</div>
<div class="row bottom-footer text-center-mobile">
<div class="col-sm-12 light-white">
<p>Copyright &copy; 1999-2022 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>
</div>
</div>
</div>
</footer>
<!-- Holder for mobile navigation -->
<div class="mobile-nav">
<ul>
<li><a hef="../latest/docs/admin/index.html">Administrators</a>
<li><a hef="../latest/docs/developer/index.html">Developers</a>
<li><a hef="../latest/docs/advanced/index.html">Advanced</a>
<li><a hef="../community/index.html">Community</a>
</ul>
<a href="#" class="close-link"><i class="arrow_up"></i></a>
</div>
<!-- Scripts -->
<script src="../js/jquery-1.11.1.min.js"></script>
<script src="../js/owl.carousel.min.js"></script>
<script src="../js/bootstrap.min.js"></script>
<script src="../js/wow.min.js"></script>
<script src="../js/typewriter.js"></script>
<script src="../js/jquery.onepagenav.js"></script>
<script src="../js/tree.jquery.js"></script>
<script src="../js/highlight.pack.js"></script>
<script src="../js/main.js"></script>
</body>
</html>