Jetty 9.4.x 3755 annotation/jndi example cleanup (#3763)

* Issue #3755 Annotation example cleanup

+ Created JettyDistribution class as common utility to locate a jetty distribution for examples.
+ Fixed ServerWithAnnotations to correctly use the test-spec-webapp
+ Added AttributeContainerMap as a better way to treat attribute values as beans. This avoids them appearing twice in a dump and always associates them with their key.
+ Added NamingDump and use it in EnvConfiguration and jetty-plus.xml so that a server dump will contain dumps of the server local tree and each contexts java:comp/env tree
+ Improved the dump format of NamingContext and WebAppContext
+ Improved the toString format of several associated classes

Signed-off-by: Greg Wilkins <gregw@webtide.com>
This commit is contained in:
Greg Wilkins 2019-06-18 09:50:18 +02:00 committed by GitHub
parent 275f83c1d0
commit 862e6d008e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
22 changed files with 520 additions and 212 deletions

View File

@ -0,0 +1,109 @@
//
// ========================================================================
// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
//
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
//
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
//
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
//
package org.eclipse.jetty.embedded;
import java.io.File;
import java.nio.file.Path;
import org.eclipse.jetty.util.StringUtil;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
/**
* A utility test class to locate a Jetty Distribution for testing purposes by searching:
* <ul>
* <li>The <code>jetty.home</code> system property</li>
* <li>The <code>JETTY_HOME</code> environment variable</li>
* <li>The working directory hierarchy with subdirectory <code>jetty-distribution/target/home</code></li>
* </ul>
*/
public class JettyDistribution
{
private final static Logger LOG = Log.getLogger(JettyDistribution.class);
public final static Path DISTRIBUTION;
static
{
Path distro = asJettyDistribution(System.getProperty("jetty.home"));
if (distro==null)
distro = asJettyDistribution(System.getenv().get("JETTY_HOME"));
if (distro==null)
{
try
{
Path working = new File(".").getAbsoluteFile().getCanonicalFile().toPath();
while(distro == null && working !=null )
{
distro = asJettyDistribution(working.resolve("jetty-distribution/target/distribution").toString());
working = working.getParent();
}
}
catch(Throwable th)
{
LOG.warn(th);
}
}
DISTRIBUTION = distro;
}
private static Path asJettyDistribution(String test)
{
try
{
if (StringUtil.isBlank(test))
{
LOG.info("asJettyDistribution {} is blank", test);
return null;
}
File dir = new File(test);
if (!dir.exists() || !dir.isDirectory())
{
LOG.info("asJettyDistribution {} is not a directory", test);
return null;
}
File demoBase = new File(dir,"demo-base");
if (!demoBase.exists() || !demoBase.isDirectory())
{
LOG.info("asJettyDistribution {} has no demo-base", test);
return null;
}
LOG.info("asJettyDistribution {}", dir);
return dir.getAbsoluteFile().getCanonicalFile().toPath();
}
catch(Exception e)
{
LOG.ignore(e);
}
return null;
}
public static Path resolve(String path)
{
return DISTRIBUTION.resolve(path);
}
public static void main(String... arg)
{
System.err.println("Jetty Distribution is " + DISTRIBUTION);
}
}

View File

@ -19,7 +19,6 @@
package org.eclipse.jetty.embedded;
import java.io.File;
import java.io.FileNotFoundException;
import java.lang.management.ManagementFactory;
import org.eclipse.jetty.deploy.DeploymentManager;
@ -60,27 +59,14 @@ public class LikeJettyXml
public static void main( String[] args ) throws Exception
{
// Path to as-built jetty-distribution directory
String jettyHomeBuild = "jetty-distribution/target/distribution";
String jettyHomeBuild = JettyDistribution.DISTRIBUTION.toString();
// Find jetty home and base directories
String homePath = System.getProperty("jetty.home", jettyHomeBuild);
File start_jar = new File(homePath,"start.jar");
if (!start_jar.exists())
{
homePath = jettyHomeBuild = "jetty-distribution/target/distribution";
start_jar = new File(homePath,"start.jar");
if (!start_jar.exists())
throw new FileNotFoundException(start_jar.toString());
}
File homeDir = new File(homePath);
String basePath = System.getProperty("jetty.base", homeDir + "/demo-base");
File baseDir = new File(basePath);
if(!baseDir.exists())
{
throw new FileNotFoundException(baseDir.getAbsolutePath());
}
// Configure jetty.home and jetty.base system properties
String jetty_home = homeDir.getAbsolutePath();
@ -88,7 +74,6 @@ public class LikeJettyXml
System.setProperty("jetty.home", jetty_home);
System.setProperty("jetty.base", jetty_base);
// === jetty.xml ===
// Setup Threadpool
QueuedThreadPool threadPool = new QueuedThreadPool();
@ -219,7 +204,6 @@ public class LikeJettyXml
lowResourcesMonitor.setPeriod(1000);
lowResourcesMonitor.setLowResourcesIdleTimeout(200);
lowResourcesMonitor.setMonitorThreads(true);
lowResourcesMonitor.setMaxConnections(0);
lowResourcesMonitor.setMaxMemory(0);
lowResourcesMonitor.setMaxLowResourcesTime(5000);
server.addBean(lowResourcesMonitor);

View File

@ -49,8 +49,7 @@ public class OneWebApp
// PlusConfiguration) to choosing where the webapp will unpack itself.
WebAppContext webapp = new WebAppContext();
webapp.setContextPath("/");
File warFile = new File(
"../../tests/test-jmx/jmx-webapp/target/jmx-webapp");
File warFile = JettyDistribution.resolve("demo-base/webapps/async-rest.war").toFile();
webapp.setWar(warFile.getAbsolutePath());
// A WebAppContext is a ContextHandler as well so it needs to be set to

View File

@ -21,6 +21,7 @@ package org.eclipse.jetty.embedded;
import java.io.File;
import org.eclipse.jetty.plus.jndi.EnvEntry;
import org.eclipse.jetty.plus.jndi.NamingDump;
import org.eclipse.jetty.plus.jndi.Resource;
import org.eclipse.jetty.plus.jndi.Transaction;
import org.eclipse.jetty.security.HashLoginService;
@ -47,16 +48,14 @@ public class ServerWithAnnotations
classlist.addBefore(
"org.eclipse.jetty.webapp.JettyWebXmlConfiguration",
"org.eclipse.jetty.annotations.AnnotationConfiguration");
// Create a WebApp
WebAppContext webapp = new WebAppContext();
webapp.setContextPath("/");
File warFile = new File(
"jetty-distribution/target/distribution/demo-base/webapps/test.war");
File warFile = JettyDistribution.resolve("demo-base/webapps/test-spec.war").toFile();
webapp.setWar(warFile.getAbsolutePath());
webapp.setAttribute(
"org.eclipse.jetty.server.webapp.ContainerIncludeJarPattern",
".*/javax.servlet-[^/]*\\.jar$|.*/servlet-api-[^/]*\\.jar$");
"org.eclipse.jetty.server.webapp.ContainerIncludeJarPattern",
".*/javax.servlet-[^/]*\\.jar$|.*/servlet-api-[^/]*\\.jar$");
server.setHandler(webapp);
// Register new transaction manager in JNDI
@ -64,10 +63,14 @@ public class ServerWithAnnotations
new Transaction(new com.acme.MockUserTransaction());
// Define an env entry with webapp scope.
new EnvEntry(webapp, "maxAmount", new Double(100), true);
// THIS ENTRY IS OVERRIDEN BY THE ENTRY IN jetty-env.xml
new EnvEntry(webapp, "maxAmount", 100d, true);
// Register a mock DataSource scoped to the webapp
new Resource(webapp, "jdbc/mydatasource", new com.acme.MockDataSource());
new Resource(server, "jdbc/mydatasource", new com.acme.MockDataSource());
// Add JNDI context to server for dump
server.addBean(new NamingDump());
// Configure a LoginService
HashLoginService loginService = new HashLoginService();
@ -75,6 +78,7 @@ public class ServerWithAnnotations
loginService.setConfig("examples/embedded/src/test/resources/realm.properties");
server.addBean(loginService);
server.start();
server.dumpStdErr();
server.join();

View File

@ -22,8 +22,10 @@ import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import javax.naming.Binding;
@ -126,7 +128,7 @@ public class NamingContext implements Context, Dumpable
this(env, name, parent, parser, null);
}
private NamingContext(Hashtable<String,Object> env,
protected NamingContext(Hashtable<String,Object> env,
String name,
NamingContext parent,
NameParser parser,
@ -143,14 +145,13 @@ public class NamingContext implements Context, Dumpable
}
/**
* @return A shallow copy of the Context with the same bindings, but a copy of the Env
* @return A shallow copy of the Context with the same bindings, but with the passed environment
*/
public NamingContext shallowCopy()
public Context shallowCopy(Hashtable<String, Object> env)
{
return new NamingContext(_env, _name, _parent, _parser, _bindings);
return new NamingContext(env, _name, _parent, _parser, _bindings);
}
public boolean isDeepBindingSupported()
{
// look for deep binding support in _env
@ -457,7 +458,7 @@ public class NamingContext implements Context, Dumpable
{
if(LOG.isDebugEnabled())
LOG.debug("Null or empty name, returning shallowCopy of this context");
return shallowCopy();
return shallowCopy(_env);
}
if (cname.size() == 1)
@ -541,7 +542,7 @@ public class NamingContext implements Context, Dumpable
if (cname == null || name.isEmpty())
{
return shallowCopy();
return shallowCopy(_env);
}
if (cname.size() == 0)
@ -1118,7 +1119,17 @@ public class NamingContext implements Context, Dumpable
@Override
public void dump(Appendable out,String indent) throws IOException
{
Dumpable.dumpObjects(out,indent,this, _bindings);
Map<String, Object> bindings = new HashMap<>();
for (Map.Entry<String,Binding> binding : _bindings.entrySet())
bindings.put(binding.getKey(), binding.getValue().getObject());
Dumpable.dumpObject(out, this);
Dumpable.dumpMapEntries(out, indent, bindings, _env.isEmpty());
if (!_env.isEmpty())
{
out.append(indent).append("+> environment\n");
Dumpable.dumpMapEntries(out, indent + " ", _env, true);
}
}
private Collection<Listener> findListeners()

View File

@ -270,7 +270,7 @@ public class localContextRoot implements Context
if (cname == null || cname.isEmpty())
{
//If no name create copy of this context with same bindings, but with copy of the environment so it can be modified
return __root.shallowCopy();
return __root.shallowCopy(_env);
}
if (cname.size() == 0)
@ -339,7 +339,7 @@ public class localContextRoot implements Context
if ((cname == null) || cname.isEmpty())
{
return __root.shallowCopy();
return __root.shallowCopy(_env);
}
if (cname.size() == 1)

View File

@ -56,4 +56,10 @@ public class EnvEntry extends NamingEntry
{
return this.overrideWebXml;
}
@Override
protected String toStringMetaData()
{
return "OverrideWebXml=" + overrideWebXml;
}
}

View File

@ -52,4 +52,10 @@ public class Link extends NamingEntry
{
return _link;
}
@Override
protected String toStringMetaData()
{
return _link;
}
}

View File

@ -0,0 +1,71 @@
//
// ========================================================================
// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
//
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
//
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
//
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
//
package org.eclipse.jetty.plus.jndi;
import javax.naming.InitialContext;
import org.eclipse.jetty.util.StringUtil;
import org.eclipse.jetty.util.component.Dumpable;
/**
* A utility Dumpable to dump a JNDI naming context tree.
*/
public class NamingDump implements Dumpable
{
private final ClassLoader _loader;
private final String _name;
public NamingDump()
{
this(null,"");
}
public NamingDump(ClassLoader loader, String name)
{
_loader = loader;
_name = name;
}
@Override
public void dump(Appendable out, String indent)
{
ClassLoader loader = Thread.currentThread().getContextClassLoader();
try
{
if (!StringUtil.isBlank(_name))
out.append(_name).append(" ");
if (_loader!=null)
Thread.currentThread().setContextClassLoader(_loader);
Object context = new InitialContext().lookup(_name);
if (context instanceof Dumpable)
((Dumpable)context).dump(out, indent);
else
Dumpable.dumpObjects(out, indent, context);
}
catch(Throwable th)
{
throw new RuntimeException(th);
}
finally
{
if (_loader!=null)
Thread.currentThread().setContextClassLoader(loader);
}
}
}

View File

@ -49,14 +49,7 @@ public abstract class NamingEntry
protected String _namingEntryNameString; //the name of the NamingEntry relative to the context it is stored in
protected String _objectNameString; //the name of the object relative to the context it is stored in
@Override
public String toString()
{
return _jndiName;
}
/**
* Create a naming entry.
*
@ -173,21 +166,21 @@ public abstract class NamingEntry
/**
* Save the NamingEntry for later use.
* <p>
* Saving is done by binding the NamingEntry
* Saving is done by binding both the NamingEntry
* itself, and the value it represents into
* JNDI. In this way, we can link to the
* value it represents later, but also
* still retrieve the NamingEntry itself too.
* <p>
* The object is bound at the jndiName passed in.
* This NamingEntry is bound at __/jndiName.
* The object is bound at scope/jndiName and
* the NamingEntry is bound at scope/__/jndiName.
* <p>
* eg
* <pre>
* jdbc/foo : DataSource
* __/jdbc/foo : NamingEntry
* </pre>
*
* @see NamingEntryUtil#getNameForScope(Object)
* @param object the object to save
* @throws NamingException if unable to save
*/
@ -212,5 +205,18 @@ public abstract class NamingEntry
_objectNameString = objectName.toString();
NamingUtil.bind(ic, _objectNameString, object);
}
protected String toStringMetaData()
{
return null;
}
@Override
public String toString()
{
String metadata = toStringMetaData();
if (metadata == null)
return String.format("%s@%x{name=%s}", this.getClass().getName(), hashCode(), getJndiName());
return String.format("%s@%x{name=%s,%s}", this.getClass().getName(), hashCode(), getJndiName(), metadata);
}
}

View File

@ -118,7 +118,7 @@ public class NamingEntryUtil
* @return all NameEntries of a certain type in the given naming environment scope (server-wide names or context-specific names)
* @throws NamingException if unable to lookup the naming entries
*/
public static List<Object> lookupNamingEntries (Object scope, Class<?> clazz)
public static <T> List<? extends T> lookupNamingEntries (Object scope, Class<T> clazz)
throws NamingException
{
try
@ -127,7 +127,7 @@ public class NamingEntryUtil
Context namingEntriesContext = (Context)scopeContext.lookup(NamingEntry.__contextName);
ArrayList<Object> list = new ArrayList<Object>();
lookupNamingEntries(list, namingEntriesContext, clazz);
return list;
return (List<T>)list;
}
catch (NameNotFoundException e)
{

View File

@ -21,9 +21,7 @@ package org.eclipse.jetty.plus.webapp;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import javax.naming.Binding;
import javax.naming.Context;
import javax.naming.InitialContext;
@ -36,6 +34,7 @@ import org.eclipse.jetty.jndi.NamingContext;
import org.eclipse.jetty.jndi.NamingUtil;
import org.eclipse.jetty.jndi.local.localContextRoot;
import org.eclipse.jetty.plus.jndi.EnvEntry;
import org.eclipse.jetty.plus.jndi.NamingDump;
import org.eclipse.jetty.plus.jndi.NamingEntryUtil;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
@ -54,6 +53,7 @@ public class EnvConfiguration extends AbstractConfiguration
private static final String JETTY_ENV_BINDINGS = "org.eclipse.jetty.jndi.EnvConfiguration";
private URL jettyEnvXmlUrl;
private NamingDump _dumper;
public void setJettyEnvXml (URL url)
{
@ -128,6 +128,9 @@ public class EnvConfiguration extends AbstractConfiguration
//add java:comp/env entries for any EnvEntries that have been defined so far
bindEnvEntries(context);
_dumper = new NamingDump(context.getClassLoader(),"java:comp");
context.addBean(_dumper);
}
@ -138,6 +141,9 @@ public class EnvConfiguration extends AbstractConfiguration
@Override
public void deconfigure (WebAppContext context) throws Exception
{
context.removeBean(_dumper);
_dumper = null;
//get rid of any bindings for comp/env for webapp
ClassLoader oldLoader = Thread.currentThread().getContextClassLoader();
Thread.currentThread().setContextClassLoader(context.getClassLoader());
@ -206,40 +212,23 @@ public class EnvConfiguration extends AbstractConfiguration
public void bindEnvEntries (WebAppContext context)
throws NamingException
{
LOG.debug("Binding env entries from the jvm scope");
InitialContext ic = new InitialContext();
Context envCtx = (Context)ic.lookup("java:comp/env");
Object scope = null;
List<Object> list = NamingEntryUtil.lookupNamingEntries(scope, EnvEntry.class);
Iterator<Object> itor = list.iterator();
while (itor.hasNext())
{
EnvEntry ee = (EnvEntry)itor.next();
ee.bindToENC(ee.getJndiName());
Name namingEntryName = NamingEntryUtil.makeNamingEntryName(null, ee);
NamingUtil.bind(envCtx, namingEntryName.toString(), ee);//also save the EnvEntry in the context so we can check it later
}
LOG.debug("Binding env entries from the jvm scope");
doBindings(envCtx, null);
LOG.debug("Binding env entries from the server scope");
scope = context.getServer();
list = NamingEntryUtil.lookupNamingEntries(scope, EnvEntry.class);
itor = list.iterator();
while (itor.hasNext())
{
EnvEntry ee = (EnvEntry)itor.next();
ee.bindToENC(ee.getJndiName());
Name namingEntryName = NamingEntryUtil.makeNamingEntryName(null, ee);
NamingUtil.bind(envCtx, namingEntryName.toString(), ee);//also save the EnvEntry in the context so we can check it later
}
doBindings(envCtx, context.getServer());
LOG.debug("Binding env entries from the context scope");
scope = context;
list = NamingEntryUtil.lookupNamingEntries(scope, EnvEntry.class);
itor = list.iterator();
while (itor.hasNext())
doBindings(envCtx, context);
}
private void doBindings(Context envCtx, Object scope) throws NamingException
{
for (EnvEntry ee : NamingEntryUtil.lookupNamingEntries(scope, EnvEntry.class))
{
EnvEntry ee = (EnvEntry)itor.next();
ee.bindToENC(ee.getJndiName());
Name namingEntryName = NamingEntryUtil.makeNamingEntryName(null, ee);
NamingUtil.bind(envCtx, namingEntryName.toString(), ee);//also save the EnvEntry in the context so we can check it later

View File

@ -22,5 +22,9 @@
</Call>
</Call>
<Call name="addBean">
<Arg><New class="org.eclipse.jetty.plus.jndi.NamingDump"/></Arg>
</Call>
</Configure>

View File

@ -18,6 +18,15 @@
package org.eclipse.jetty.plus.jndi;
import java.util.List;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.Name;
import javax.naming.NameNotFoundException;
import javax.naming.NamingException;
import org.junit.jupiter.api.Test;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.containsInAnyOrder;
import static org.hamcrest.Matchers.empty;
@ -27,16 +36,6 @@ import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.fail;
import java.util.List;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.Name;
import javax.naming.NameNotFoundException;
import javax.naming.NamingException;
import org.junit.jupiter.api.Test;
public class TestNamingEntryUtil
{
public class MyNamingEntry extends NamingEntry
@ -122,7 +121,7 @@ public class TestNamingEntryUtil
public void testLookupNamingEntries() throws Exception
{
ScopeA scope = new ScopeA();
List<?> list = NamingEntryUtil.lookupNamingEntries(scope, MyNamingEntry.class);
List<? extends MyNamingEntry> list = NamingEntryUtil.lookupNamingEntries(scope, MyNamingEntry.class);
assertThat(list, is(empty()));
MyNamingEntry mne1 = new MyNamingEntry(scope, "a/b", 1);

View File

@ -18,6 +18,15 @@
package org.eclipse.jetty.server;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.Executor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import org.eclipse.jetty.io.EndPoint;
import org.eclipse.jetty.util.annotation.ManagedAttribute;
import org.eclipse.jetty.util.annotation.ManagedObject;
@ -29,15 +38,6 @@ import org.eclipse.jetty.util.thread.ScheduledExecutorScheduler;
import org.eclipse.jetty.util.thread.Scheduler;
import org.eclipse.jetty.util.thread.ThreadPool;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.Executor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
/**
*
@ -135,7 +135,7 @@ public class LowResourceMonitor extends ContainerLifeCycle
/**
* @param maxConnections The maximum connections before low resources state is triggered
* @deprecated Replaced by ConnectionLimit
* @deprecated Replaced by {@link ConnectionLimit}
*/
@Deprecated
public void setMaxConnections(int maxConnections)

View File

@ -28,7 +28,6 @@ import java.util.Enumeration;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.Future;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
@ -47,7 +46,6 @@ import org.eclipse.jetty.server.handler.ErrorHandler;
import org.eclipse.jetty.server.handler.HandlerWrapper;
import org.eclipse.jetty.server.handler.StatisticsHandler;
import org.eclipse.jetty.util.Attributes;
import org.eclipse.jetty.util.AttributesMap;
import org.eclipse.jetty.util.Jetty;
import org.eclipse.jetty.util.MultiException;
import org.eclipse.jetty.util.URIUtil;
@ -55,6 +53,7 @@ import org.eclipse.jetty.util.Uptime;
import org.eclipse.jetty.util.annotation.ManagedAttribute;
import org.eclipse.jetty.util.annotation.ManagedObject;
import org.eclipse.jetty.util.annotation.Name;
import org.eclipse.jetty.util.component.AttributeContainerMap;
import org.eclipse.jetty.util.component.LifeCycle;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
@ -75,7 +74,7 @@ public class Server extends HandlerWrapper implements Attributes
{
private static final Logger LOG = Log.getLogger(Server.class);
private final AttributesMap _attributes = new AttributesMap();
private final AttributeContainerMap _attributes = new AttributeContainerMap();
private final ThreadPool _threadPool;
private final List<Connector> _connectors = new CopyOnWriteArrayList<>();
private SessionIdManager _sessionIdManager;
@ -107,6 +106,7 @@ public class Server extends HandlerWrapper implements Attributes
ServerConnector connector=new ServerConnector(this);
connector.setPort(port);
setConnectors(new Connector[]{connector});
addBean(_attributes);
}
/* ------------------------------------------------------------ */
@ -584,9 +584,6 @@ public class Server extends HandlerWrapper implements Attributes
@Override
public void clearAttributes()
{
Enumeration<String> names = _attributes.getAttributeNames();
while (names.hasMoreElements())
removeBean(_attributes.getAttribute(names.nextElement()));
_attributes.clearAttributes();
}
@ -607,7 +604,7 @@ public class Server extends HandlerWrapper implements Attributes
@Override
public Enumeration<String> getAttributeNames()
{
return AttributesMap.getAttributeNamesCopy(_attributes);
return _attributes.getAttributeNames();
}
/* ------------------------------------------------------------ */
@ -617,9 +614,6 @@ public class Server extends HandlerWrapper implements Attributes
@Override
public void removeAttribute(String name)
{
Object bean=_attributes.getAttribute(name);
if (bean!=null)
removeBean(bean);
_attributes.removeAttribute(name);
}
@ -630,9 +624,6 @@ public class Server extends HandlerWrapper implements Attributes
@Override
public void setAttribute(String name, Object attribute)
{
// TODO this is a crude way to get attribute values managed by JMX.
Object old=_attributes.getAttribute(name);
updateBean(old,attribute);
_attributes.setAttribute(name, attribute);
}
@ -693,7 +684,7 @@ public class Server extends HandlerWrapper implements Attributes
@Override
public void dump(Appendable out,String indent) throws IOException
{
dumpObjects(out,indent,new ClassLoaderDump(this.getClass().getClassLoader()),_attributes);
dumpObjects(out,indent,new ClassLoaderDump(this.getClass().getClassLoader()));
}
/* ------------------------------------------------------------ */
@ -714,6 +705,5 @@ public class Server extends HandlerWrapper implements Attributes
_seconds = seconds;
_dateField = dateField;
}
}
}

View File

@ -0,0 +1,82 @@
//
// ========================================================================
// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
//
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
//
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
//
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
//
package org.eclipse.jetty.util.component;
import java.io.IOException;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import org.eclipse.jetty.util.Attributes;
/**
* An Attributes implementation that holds it's values in an immutable {@link ContainerLifeCycle}
*/
public class AttributeContainerMap extends ContainerLifeCycle implements Attributes
{
private final Map<String, Object> _map = new HashMap<>();
@Override
public synchronized void setAttribute(String name, Object attribute)
{
Object old = _map.put(name, attribute);
updateBean(old, attribute);
}
@Override
public synchronized void removeAttribute(String name)
{
Object removed = _map.remove(name);
if (removed != null)
removeBean(removed);
}
@Override
public synchronized Object getAttribute(String name)
{
return _map.get(name);
}
@Override
public synchronized Enumeration<String> getAttributeNames()
{
return Collections.enumeration(_map.keySet());
}
@Override
public synchronized void clearAttributes()
{
_map.clear();
this.removeBeans();
}
@Override
public void dump(Appendable out, String indent) throws IOException
{
Dumpable.dumpObject(out, this);
Dumpable.dumpMapEntries(out, indent, _map, true);
}
@Override
public String toString()
{
return String.format("%s@%x{size=%d}",this.getClass().getSimpleName(),hashCode(),_map.size());
}
}

View File

@ -132,7 +132,7 @@ public interface Container
/**
* @param clazz the class of the beans
* @return the list of beans of the given class from the entire managed hierarchy
* @return the list of beans of the given class from the entire Container hierarchy
* @param <T> the Bean type
*/
public <T> Collection<T> getContainedBeans(Class<T> clazz);

View File

@ -550,13 +550,17 @@ public class ContainerLifeCycle extends AbstractLifeCycle implements Container,
@Override
public <T> Collection<T> getBeans(Class<T> clazz)
{
ArrayList<T> beans = new ArrayList<>();
ArrayList<T> beans = null;
for (Bean b : _beans)
{
if (clazz.isInstance(b._bean))
{
if (beans == null)
beans = new ArrayList<>();
beans.add(clazz.cast(b._bean));
}
}
return beans;
return beans == null ? Collections.emptyList() : beans;
}
@Override
@ -879,7 +883,7 @@ public class ContainerLifeCycle extends AbstractLifeCycle implements Container,
/**
* @param clazz the class of the beans
* @return the list of beans of the given class from the entire managed hierarchy
* @return the list of beans of the given class from the entire Container hierarchy
* @param <T> the Bean type
*/
@Override
@ -893,7 +897,7 @@ public class ContainerLifeCycle extends AbstractLifeCycle implements Container,
/**
* @param clazz the class of the beans
* @param <T> the Bean type
* @param beans the collection to add beans of the given class from the entire managed hierarchy
* @param beans the collection to add beans of the given class from the entire Container hierarchy
*/
protected <T> void getContainedBeans(Class<T> clazz, Collection<T> beans)
{

View File

@ -93,18 +93,19 @@ public interface Dumpable
String s;
if (o==null)
s = "null";
else if (o instanceof Collection)
s = String.format("%s@%x(size=%d)",o.getClass().getName(),o.hashCode(),((Collection)o).size());
else if (o.getClass().isArray())
s = String.format("%s@%x[size=%d]",o.getClass().getComponentType(),o.hashCode(), Array.getLength(o));
else if (o instanceof Map)
s = String.format("%s@%x{size=%d}",o.getClass().getName(),o.hashCode(),((Map<?,?>)o).size());
else if (o instanceof Dumpable)
{
s = ((Dumpable)o).dumpSelf();
s = StringUtil.replace(s, "\r\n", "|");
s = StringUtil.replace(s, '\n', '|');
}
else if (o instanceof Collection)
s = String.format("%s@%x(size=%d)",o.getClass().getName(),o.hashCode(),((Collection)o).size());
else if (o.getClass().isArray())
s = String.format("%s@%x[size=%d]",o.getClass().getComponentType(),o.hashCode(), Array.getLength(o));
else if (o instanceof Map)
s = String.format("%s@%x{size=%d}",o.getClass().getName(),o.hashCode(),((Map<?,?>)o).size());
else
{
s = String.valueOf(o);
@ -139,7 +140,7 @@ public interface Dumpable
{
dumpObject(out,object);
int size = extraChildren==null?0:extraChildren.length;
int extras = extraChildren==null?0:extraChildren.length;
if (object instanceof Stream)
object = ((Stream)object).toArray();
@ -148,87 +149,25 @@ public interface Dumpable
if (object instanceof Container)
{
Container container = (Container)object;
ContainerLifeCycle containerLifeCycle = container instanceof ContainerLifeCycle ? (ContainerLifeCycle)container : null;
for (Iterator<Object> i = container.getBeans().iterator(); i.hasNext();)
{
Object bean = i.next();
String nextIndent = indent + ((i.hasNext() || size>0) ? "| " : " ");
if (bean instanceof LifeCycle)
{
if (container.isManaged(bean))
{
out.append(indent).append("+= ");
if (bean instanceof Dumpable)
((Dumpable)bean).dump(out,nextIndent);
else
dumpObjects(out, nextIndent, bean);
}
else if (containerLifeCycle != null && containerLifeCycle.isAuto(bean))
{
out.append(indent).append("+? ");
if (bean instanceof Dumpable)
((Dumpable)bean).dump(out,nextIndent);
else
dumpObjects(out, nextIndent, bean);
}
else
{
out.append(indent).append("+~ ");
dumpObject(out, bean);
}
}
else if (containerLifeCycle != null && containerLifeCycle.isUnmanaged(bean))
{
out.append(indent).append("+~ ");
dumpObject(out, bean);
}
else
{
out.append(indent).append("+- ");
if (bean instanceof Dumpable)
((Dumpable)bean).dump(out,nextIndent);
else
dumpObjects(out, nextIndent, bean);
}
}
dumpContainer(out, indent, (Container)object, extras==0);
}
if (object instanceof Iterable)
{
for (Iterator i = ((Iterable<?>)object).iterator(); i.hasNext();)
{
Object item = i.next();
String nextIndent = indent + ((i.hasNext() || size>0) ? "| " : " ");
out.append(indent).append("+: ");
if (item instanceof Dumpable)
((Dumpable)item).dump(out,nextIndent);
else
dumpObjects(out,nextIndent, item);
}
dumpIterable(out, indent, (Iterable<?>)object, extras==0);
}
else if (object instanceof Map)
{
for (Iterator<? extends Map.Entry<?, ?>> i = ((Map<?,?>)object).entrySet().iterator(); i.hasNext();)
{
Map.Entry entry = i.next();
String nextIndent = indent + ((i.hasNext() || size>0) ? "| " : " ");
out.append(indent).append("+@ ").append(String.valueOf(entry.getKey())).append('=');
Object item = entry.getValue();
if (item instanceof Dumpable)
((Dumpable)item).dump(out,nextIndent);
else
dumpObjects(out,nextIndent, item);
}
dumpMapEntries(out, indent, (Map<?,?>)object, extras==0);
}
if (size==0)
if (extras==0)
return;
int i = 0;
for (Object item : extraChildren)
{
i++;
String nextIndent = indent + (i<size ? "| " : " ");
String nextIndent = indent + (i<extras ? "| " : " ");
out.append(indent).append("+> ");
if (item instanceof Dumpable)
((Dumpable)item).dump(out,nextIndent);
@ -236,4 +175,91 @@ public interface Dumpable
dumpObjects(out, nextIndent, item);
}
}
static void dumpContainer(Appendable out, String indent, Container object, boolean last) throws IOException
{
Container container = object;
ContainerLifeCycle containerLifeCycle = container instanceof ContainerLifeCycle ? (ContainerLifeCycle)container : null;
for (Iterator<Object> i = container.getBeans().iterator(); i.hasNext();)
{
Object bean = i.next();
String nextIndent = indent + ((i.hasNext() || !last) ? "| " : " ");
if (bean instanceof LifeCycle)
{
if (container.isManaged(bean))
{
out.append(indent).append("+= ");
if (bean instanceof Dumpable)
((Dumpable)bean).dump(out,nextIndent);
else
dumpObjects(out, nextIndent, bean);
}
else if (containerLifeCycle != null && containerLifeCycle.isAuto(bean))
{
out.append(indent).append("+? ");
if (bean instanceof Dumpable)
((Dumpable)bean).dump(out,nextIndent);
else
dumpObjects(out, nextIndent, bean);
}
else
{
out.append(indent).append("+~ ");
dumpObject(out, bean);
}
}
else if (containerLifeCycle != null && containerLifeCycle.isUnmanaged(bean))
{
out.append(indent).append("+~ ");
dumpObject(out, bean);
}
else
{
out.append(indent).append("+- ");
if (bean instanceof Dumpable)
((Dumpable)bean).dump(out,nextIndent);
else
dumpObjects(out, nextIndent, bean);
}
}
}
static void dumpIterable(Appendable out, String indent, Iterable<?> iterable, boolean last) throws IOException
{
for (Iterator i = iterable.iterator(); i.hasNext();)
{
Object item = i.next();
String nextIndent = indent + ((i.hasNext() || !last) ? "| " : " ");
out.append(indent).append("+: ");
if (item instanceof Dumpable)
((Dumpable)item).dump(out,nextIndent);
else
dumpObjects(out,nextIndent, item);
}
}
static void dumpMapEntries(Appendable out, String indent, Map<?,?> map, boolean last) throws IOException
{
for (Iterator<? extends Map.Entry<?, ?>> i = map.entrySet().iterator(); i.hasNext();)
{
Map.Entry entry = i.next();
String nextIndent = indent + ((i.hasNext() || !last) ? "| " : " ");
out.append(indent).append("+@ ").append(String.valueOf(entry.getKey())).append(" = ");
Object item = entry.getValue();
if (item instanceof Dumpable)
((Dumpable)item).dump(out,nextIndent);
else
dumpObjects(out,nextIndent, item);
}
}
static Dumpable named(String name, Object object)
{
return (out, indent) ->
{
out.append(name).append(": ");
Dumpable.dumpObjects(out, indent, object);
};
}
}

View File

@ -724,7 +724,7 @@ public class WebAppClassLoader extends URLClassLoader implements ClassVisibility
@Override
public String toString()
{
return "WebAppClassLoader=" + _name+"@"+Long.toHexString(hashCode());
return String.format("%s{%s}@%x", this.getClass().getSimpleName(), _name, hashCode());
}
@Override

View File

@ -34,7 +34,6 @@ import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.servlet.ServletContext;
import javax.servlet.ServletRegistration.Dynamic;
import javax.servlet.ServletSecurityElement;
@ -1040,15 +1039,10 @@ public class WebAppContext extends ServletContextHandler implements WebAppClassL
public String toString()
{
if (_war!=null)
{
String war=_war;
if (war.indexOf("/webapps/")>=0)
war=war.substring(war.indexOf("/webapps/")+8);
return super.toString()+"{"+war+"}";
}
return super.toString()+"{"+_war+"}";
return super.toString();
}
/* ------------------------------------------------------------ */
@Override
public void dump(Appendable out, String indent) throws IOException
@ -1066,15 +1060,39 @@ public class WebAppContext extends ServletContextHandler implements WebAppClassL
server_classes=new ArrayList<>(_serverClasses);
Collections.sort(server_classes);
}
String name = getDisplayName();
if (name == null)
{
if (_war != null)
{
if (_war.indexOf("/webapps/") >= 0)
name = _war.substring(_war.indexOf("/webapps/") + 8);
else
name = _war;
}
else if (getResourceBase() != null)
{
name = getResourceBase();
if (name.indexOf("/webapps/") >= 0)
name = name.substring(name.indexOf("/webapps/") + 8);
}
else
{
name = this.getClass().getSimpleName();
}
}
name = String.format("%s@%x", name, hashCode());
dumpObjects(out,indent,
new ClassLoaderDump(getClassLoader()),
new DumpableCollection("Systemclasses "+this,system_classes),
new DumpableCollection("Serverclasses "+this,server_classes),
new DumpableCollection("Configurations "+this,_configurations),
new DumpableCollection("Handler attributes "+this,((AttributesMap)getAttributes()).getAttributeEntrySet()),
new DumpableCollection("Context attributes "+this,((Context)getServletContext()).getAttributeEntrySet()),
new DumpableCollection("Initparams "+this,getInitParams().entrySet())
new DumpableCollection("Systemclasses " + name, system_classes),
new DumpableCollection("Serverclasses " + name, server_classes),
new DumpableCollection("Configurations " + name, _configurations),
new DumpableCollection("Handler attributes " + name, ((AttributesMap)getAttributes()).getAttributeEntrySet()),
new DumpableCollection("Context attributes " + name, ((Context)getServletContext()).getAttributeEntrySet()),
new DumpableCollection("Initparams " + name, getInitParams().entrySet())
);
}