Merged branch 'jetty-9.4.x' into 'jetty-9.4.x-2868-spnego_client'

This commit is contained in:
Simone Bordet 2018-09-28 08:59:46 +02:00
commit eb00e6c7c6
63 changed files with 1876 additions and 1437 deletions

4
Jenkinsfile vendored
View File

@ -82,7 +82,7 @@ def getFullBuild(jdk, os) {
//options: [invokerPublisher(disabled: false)],
mavenOpts: mavenOpts,
mavenLocalRepo: localRepo) {
sh "mvn -V -B install -Dmaven.test.failure.ignore=true -e -Pmongodb -T3 -Dunix.socket.tmp="+env.JENKINS_HOME
sh "mvn -V -B install -Dmaven.test.failure.ignore=true -e -Pmongodb -T3 -Djetty.testtracker.log=true -Dunix.socket.tmp="+env.JENKINS_HOME
}
// withMaven doesn't label..
// Report failures in the jenkins UI
@ -137,7 +137,7 @@ def getFullBuild(jdk, os) {
globalMavenSettingsConfig: settingsName,
mavenOpts: mavenOpts,
mavenLocalRepo: localRepo) {
sh "mvn -f aggregates/jetty-all-compact3 -V -B -Pcompact3 clean install -T5"
sh "mvn -f aggregates/jetty-all-compact3 -V -B -Pcompact3 clean install -T6"
}
}
} catch(Exception e) {

View File

@ -9,3 +9,4 @@
#org.eclipse.jetty.server.LEVEL=DEBUG
#org.eclipse.jetty.servlets.LEVEL=DEBUG
#org.eclipse.jetty.alpn.LEVEL=DEBUG
#org.eclipse.jetty.jmx.LEVEL=DEBUG

View File

@ -81,12 +81,10 @@ public class WebListenerAnnotation extends DiscoveredAnnotation
{
MetaData metaData = _context.getMetaData();
if (metaData.getOrigin(clazz.getName()+".listener") == Origin.NotSet)
{
java.util.EventListener listener = (java.util.EventListener)_context.getServletContext().createInstance(clazz);
{
ListenerHolder h = _context.getServletHandler().newListenerHolder(new Source(Source.Origin.ANNOTATION, clazz.getName()));
h.setListener(listener);
h.setHeldClass(clazz);
_context.getServletHandler().addListener(h);
_context.addEventListener(listener);
}
}
else

View File

@ -108,7 +108,7 @@ public class HttpRequest implements Request
headers.put(userAgentField);
}
protected HttpConversation getConversation()
public HttpConversation getConversation()
{
return conversation;
}

View File

@ -110,16 +110,16 @@ public class HttpChannelOverHTTP extends HttpChannel
// Upgrade Response
HttpRequest request = exchange.getRequest();
if (request instanceof HttpConnectionUpgrader)
HttpConnectionUpgrader upgrader = (HttpConnectionUpgrader) request.getConversation().getAttribute(HttpConnectionUpgrader.class.getName());
if (upgrader != null)
{
HttpConnectionUpgrader listener = (HttpConnectionUpgrader)request;
try
{
listener.upgrade(response,getHttpConnection());
upgrader.upgrade(response, getHttpConnection());
}
catch (Throwable x)
{
return new Result(result,x);
return new Result(result, x);
}
}
}

View File

@ -47,6 +47,7 @@
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
<!--
@ -73,73 +74,6 @@
<excludes>META-INF/**</excludes>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId>
<executions>
<execution>
<id>populate distribution from home</id>
<phase>prepare-package</phase>
<goals>
<goal>run</goal>
</goals>
<configuration>
<tasks>
<copy todir="${assembly-directory}">
<fileset dir="${home-directory}/jetty-home-${project.version}/" />
</copy>
</tasks>
</configuration>
</execution>
<execution>
<id>set jetty.sh</id>
<phase>prepare-package</phase>
<goals>
<goal>run</goal>
</goals>
<configuration>
<tasks>
<chmod dir="${assembly-directory}/bin" perm="755" includes="**/*.sh" />
</tasks>
</configuration>
</execution>
<execution>
<id>removeKeystore</id>
<phase>prepare-package</phase>
<goals>
<goal>run</goal>
</goals>
<configuration>
<tasks>
<delete file="${assembly-directory}/etc/keystore" />
</tasks>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-remote-resources-plugin</artifactId>
<executions>
<execution>
<phase>prepare-package</phase>
<goals>
<goal>process</goal>
</goals>
<configuration>
<resourceBundles>
<resourceBundle>org.eclipse.jetty.toolchain:jetty-distribution-remote-resources:1.2</resourceBundle>
</resourceBundles>
<outputDirectory>${assembly-directory}</outputDirectory>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
<execution>
<id>copy</id>
<phase>prepare-package</phase>
@ -222,7 +156,7 @@
<artifactItems>
<artifactItem>
<groupId>org.eclipse.jetty</groupId>
<artifactId>test-jetty-webapp</artifactId>
<artifactId>test-jetty-webapp</artifactId>
<version>${project.version}</version>
<classifier>config</classifier>
<type>jar</type>
@ -321,6 +255,68 @@
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId>
<executions>
<execution>
<id>populate distribution from home</id>
<phase>prepare-package</phase>
<goals>
<goal>run</goal>
</goals>
<configuration>
<tasks>
<copy todir="${assembly-directory}">
<fileset dir="${home-directory}/jetty-home-${project.version}/" />
</copy>
</tasks>
</configuration>
</execution>
<execution>
<id>set jetty.sh</id>
<phase>prepare-package</phase>
<goals>
<goal>run</goal>
</goals>
<configuration>
<tasks>
<chmod dir="${assembly-directory}/bin" perm="755" includes="**/*.sh" />
</tasks>
</configuration>
</execution>
<execution>
<id>removeKeystore</id>
<phase>prepare-package</phase>
<goals>
<goal>run</goal>
</goals>
<configuration>
<tasks>
<delete file="${assembly-directory}/etc/keystore" />
</tasks>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-remote-resources-plugin</artifactId>
<executions>
<execution>
<phase>prepare-package</phase>
<goals>
<goal>process</goal>
</goals>
<configuration>
<resourceBundles>
<resourceBundle>org.eclipse.jetty.toolchain:jetty-distribution-remote-resources:1.2</resourceBundle>
</resourceBundles>
<outputDirectory>${assembly-directory}</outputDirectory>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>

View File

@ -88,7 +88,7 @@ Instead, you could redefine the DefaultServlet in your web.xml file, making sure
<web-app ...>
...
<servlet>
<servlet-name>Default</servlet-name>
<servlet-name>default</servlet-name>
<servlet-class>org.eclipse.jetty.servlet.DefaultServlet</servlet-class>
<init-param>
<param-name>useFileMappedBuffer</param-name>
@ -97,9 +97,7 @@ Instead, you could redefine the DefaultServlet in your web.xml file, making sure
<load-on-startup>0</load-on-startup>
</servlet>
...
</web-app>
</web-app>
----
==== Alternate Remedy
@ -117,7 +115,6 @@ Configure this in an xml file like so:
.
.
</New>
----
____

View File

@ -19,18 +19,27 @@
package org.eclipse.jetty.jmx;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;
import javax.management.InstanceNotFoundException;
import javax.management.MBeanInfo;
import javax.management.MBeanRegistrationException;
import javax.management.MBeanServer;
import javax.management.ObjectName;
import javax.management.modelmbean.ModelMBean;
import org.eclipse.jetty.util.Loader;
import org.eclipse.jetty.util.annotation.ManagedAttribute;
import org.eclipse.jetty.util.annotation.ManagedObject;
import org.eclipse.jetty.util.component.Container;
import org.eclipse.jetty.util.component.ContainerLifeCycle;
@ -45,15 +54,190 @@ import org.eclipse.jetty.util.log.Logger;
@ManagedObject("The component that registers beans as MBeans")
public class MBeanContainer implements Container.InheritedListener, Dumpable, Destroyable
{
private final static Logger LOG = Log.getLogger(MBeanContainer.class.getName());
private final static ConcurrentMap<String, AtomicInteger> __unique = new ConcurrentHashMap<>();
private static final Logger LOG = Log.getLogger(MBeanContainer.class.getName());
private static final ConcurrentMap<String, AtomicInteger> __unique = new ConcurrentHashMap<>();
private static final Container ROOT = new ContainerLifeCycle();
private final MBeanServer _mbeanServer;
private final boolean _useCacheForOtherClassLoaders;
private final ConcurrentMap<Class, MetaData> _metaData = new ConcurrentHashMap<>();
private final ConcurrentMap<Object, Container> _beans = new ConcurrentHashMap<>();
private final ConcurrentMap<Object, ObjectName> _mbeans = new ConcurrentHashMap<>();
private String _domain = null;
/**
* Constructs MBeanContainer
*
* @param server instance of MBeanServer for use by container
*/
public MBeanContainer(MBeanServer server)
{
this(server, true);
}
/**
* Constructs MBeanContainer
*
* @param server instance of MBeanServer for use by container
* @param cacheOtherClassLoaders If true, MBeans from other classloaders (eg WebAppClassLoader) will be cached.
* The cache is never flushed, so this should be false if some classloaders do not live forever.
*/
public MBeanContainer(MBeanServer server, boolean cacheOtherClassLoaders)
{
_mbeanServer = server;
_useCacheForOtherClassLoaders = cacheOtherClassLoaders;
}
/**
* Retrieve instance of MBeanServer used by container
*
* @return instance of MBeanServer
*/
public MBeanServer getMBeanServer()
{
return _mbeanServer;
}
@ManagedAttribute(value = "Whether to use the cache for MBeans loaded by other ClassLoaders", readonly = true)
public boolean isUseCacheForOtherClassLoaders()
{
return _useCacheForOtherClassLoaders;
}
/**
* Set domain to be used to add MBeans
*
* @param domain domain name
*/
public void setDomain(String domain)
{
_domain = domain;
}
/**
* Retrieve domain name used to add MBeans
*
* @return domain name
*/
@ManagedAttribute("The default ObjectName domain")
public String getDomain()
{
return _domain;
}
/**
* <p>Creates an ObjectMBean for the given object.</p>
* <p>Attempts to create an ObjectMBean for the object by searching the package
* and class name space. For example an object of the type:</p>
* <pre>
* class com.acme.MyClass extends com.acme.util.BaseClass implements com.acme.Iface
* </pre>
* <p>then this method would look for the following classes:</p>
* <ul>
* <li>com.acme.jmx.MyClassMBean</li>
* <li>com.acme.util.jmx.BaseClassMBean</li>
* <li>org.eclipse.jetty.jmx.ObjectMBean</li>
* </ul>
*
* @param o The object
* @return A new instance of an MBean for the object or null.
*/
public Object mbeanFor(Object o)
{
return mbeanFor(this, o);
}
static Object mbeanFor(MBeanContainer container, Object o)
{
if (o == null)
return null;
Object mbean = findMetaData(container, o.getClass()).newInstance(o);
if (mbean instanceof ObjectMBean)
((ObjectMBean)mbean).setMBeanContainer(container);
if (LOG.isDebugEnabled())
{
LOG.debug("MBean for {} is {}", o, mbean);
if (mbean instanceof ObjectMBean)
{
MBeanInfo info = ((ObjectMBean)mbean).getMBeanInfo();
for (Object a : info.getAttributes())
LOG.debug(" {}", a);
for (Object a : info.getOperations())
LOG.debug(" {}", a);
}
}
return mbean;
}
static MetaData findMetaData(MBeanContainer container, Class<?> klass)
{
if (klass == null)
return null;
MetaData metaData = getMetaData(container, klass);
if (metaData != null)
{
if (LOG.isDebugEnabled())
LOG.debug("Found cached {}", metaData);
return metaData;
}
return newMetaData(container, klass);
}
private static MetaData getMetaData(MBeanContainer container, Class<?> klass)
{
return container == null ? null : container._metaData.get(klass);
}
private static MetaData newMetaData(MBeanContainer container, Class<?> klass)
{
if (klass == null)
return null;
if (klass == Object.class)
return new MetaData(klass, null, null, Collections.emptyList());
List<MetaData> interfaces = Arrays.stream(klass.getInterfaces())
.map(intf -> findMetaData(container, intf))
.collect(Collectors.toList());
MetaData metaData = new MetaData(klass, findConstructor(klass), findMetaData(container, klass.getSuperclass()), interfaces);
if (container != null)
{
if (container.isUseCacheForOtherClassLoaders() || klass.getClassLoader() == container.getClass().getClassLoader())
{
MetaData existing = container._metaData.putIfAbsent(klass, metaData);
if (existing != null)
metaData = existing;
if (LOG.isDebugEnabled())
LOG.debug("Cached {}", metaData);
}
}
return metaData;
}
private static Constructor<?> findConstructor(Class<?> klass)
{
String pName = klass.getPackage().getName();
String cName = klass.getName().substring(pName.length() + 1);
String mName = pName + ".jmx." + cName + "MBean";
try
{
Class<?> mbeanClass = Loader.loadClass(mName);
Constructor<?> constructor = ModelMBean.class.isAssignableFrom(mbeanClass)
? mbeanClass.getConstructor()
: mbeanClass.getConstructor(Object.class);
if (LOG.isDebugEnabled())
LOG.debug("Found MBean wrapper: {} for {}", mName, klass.getName());
return constructor;
}
catch (Throwable x)
{
if (LOG.isDebugEnabled())
LOG.debug("MBean wrapper not found: {} for {}", mName, klass.getName());
return null;
}
}
/**
* Lookup an object name by instance
*
@ -81,47 +265,6 @@ public class MBeanContainer implements Container.InheritedListener, Dumpable, De
return null;
}
/**
* Constructs MBeanContainer
*
* @param server instance of MBeanServer for use by container
*/
public MBeanContainer(MBeanServer server)
{
_mbeanServer = server;
}
/**
* Retrieve instance of MBeanServer used by container
*
* @return instance of MBeanServer
*/
public MBeanServer getMBeanServer()
{
return _mbeanServer;
}
/**
* Set domain to be used to add MBeans
*
* @param domain domain name
*/
public void setDomain(String domain)
{
_domain = domain;
}
/**
* Retrieve domain name used to add MBeans
*
* @return domain name
*/
public String getDomain()
{
return _domain;
}
@Override
public void beanAdded(Container parent, Object obj)
{
@ -154,14 +297,13 @@ public class MBeanContainer implements Container.InheritedListener, Dumpable, De
try
{
// Create an MBean for the object.
Object mbean = ObjectMBean.mbeanFor(obj);
Object mbean = mbeanFor(obj);
if (mbean == null)
return;
ObjectName objectName = null;
if (mbean instanceof ObjectMBean)
{
((ObjectMBean)mbean).setMBeanContainer(this);
objectName = ((ObjectMBean)mbean).getObjectName();
}
@ -256,7 +398,7 @@ public class MBeanContainer implements Container.InheritedListener, Dumpable, De
@Override
public void dump(Appendable out, String indent) throws IOException
{
ContainerLifeCycle.dumpObject(out,this);
ContainerLifeCycle.dumpObject(out, this);
ContainerLifeCycle.dump(out, indent, _mbeans.entrySet());
}
@ -269,6 +411,7 @@ public class MBeanContainer implements Container.InheritedListener, Dumpable, De
@Override
public void destroy()
{
_metaData.clear();
_mbeans.values().stream()
.filter(Objects::nonNull)
.forEach(this::unregister);

View File

@ -0,0 +1,566 @@
//
// ========================================================================
// Copyright (c) 1995-2018 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.jmx;
import java.lang.annotation.Annotation;
import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.stream.Collectors;
import javax.management.Attribute;
import javax.management.AttributeNotFoundException;
import javax.management.MBeanAttributeInfo;
import javax.management.MBeanConstructorInfo;
import javax.management.MBeanException;
import javax.management.MBeanInfo;
import javax.management.MBeanNotificationInfo;
import javax.management.MBeanOperationInfo;
import javax.management.MBeanParameterInfo;
import javax.management.ObjectName;
import javax.management.ReflectionException;
import javax.management.modelmbean.ModelMBean;
import org.eclipse.jetty.util.annotation.ManagedAttribute;
import org.eclipse.jetty.util.annotation.ManagedObject;
import org.eclipse.jetty.util.annotation.ManagedOperation;
import org.eclipse.jetty.util.annotation.Name;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
class MetaData
{
private static final Logger LOG = Log.getLogger(MetaData.class);
private static final MBeanAttributeInfo[] NO_ATTRIBUTES = new MBeanAttributeInfo[0];
private static final MBeanConstructorInfo[] NO_CONSTRUCTORS = new MBeanConstructorInfo[0];
private static final MBeanOperationInfo[] NO_OPERATIONS = new MBeanOperationInfo[0];
private static final MBeanNotificationInfo[] NO_NOTIFICATIONS = new MBeanNotificationInfo[0];
private final Map<String, AttributeInfo> _attributes = new HashMap<>();
private final Map<String, OperationInfo> _operations = new HashMap<>();
private final Class<?> _klass;
private final MetaData _parent;
private final List<MetaData> _interfaces;
private final Constructor<?> _constructor;
private final MBeanInfo _info;
MetaData(Class<?> klass, Constructor<?> constructor, MetaData parent, List<MetaData> interfaces)
{
_klass = klass;
_parent = parent;
_interfaces = interfaces;
_constructor = constructor;
if (_constructor != null)
parseMethods(klass, _constructor.getDeclaringClass());
else
parseMethods(klass);
_info = buildMBeanInfo(klass);
}
Object newInstance(Object bean)
{
Object mbean;
if (_constructor != null)
mbean = newInstance(_constructor, bean);
else if (_parent != null)
mbean = _parent.newInstance(bean);
else
mbean = new ObjectMBean(bean);
return mbean;
}
MBeanInfo getMBeanInfo()
{
return _info;
}
Object getAttribute(String name, ObjectMBean mbean) throws AttributeNotFoundException, ReflectionException, MBeanException
{
AttributeInfo info = findAttribute(name);
if (info == null)
throw new AttributeNotFoundException(name);
return info.getAttribute(mbean);
}
void setAttribute(Attribute attribute, ObjectMBean mbean) throws AttributeNotFoundException, ReflectionException, MBeanException
{
if (attribute == null)
return;
String name = attribute.getName();
AttributeInfo info = findAttribute(name);
if (info == null)
throw new AttributeNotFoundException(name);
info.setAttribute(attribute.getValue(), mbean);
}
private AttributeInfo findAttribute(String name)
{
if (name == null)
return null;
AttributeInfo result = null;
for (MetaData intf : _interfaces)
{
AttributeInfo r = intf.findAttribute(name);
if (r != null)
result = r;
}
if (_parent != null)
{
AttributeInfo r = _parent.findAttribute(name);
if (r != null)
result = r;
}
AttributeInfo r = _attributes.get(name);
if (r != null)
result = r;
return result;
}
Object invoke(String name, String[] params, Object[] args, ObjectMBean mbean) throws ReflectionException, MBeanException
{
String signature = signature(name, params);
OperationInfo info = findOperation(signature);
if (info == null)
throw new ReflectionException(new NoSuchMethodException(signature));
return info.invoke(args, mbean);
}
private OperationInfo findOperation(String signature)
{
OperationInfo result = null;
for (MetaData intf : _interfaces)
{
OperationInfo r = intf.findOperation(signature);
if (r != null)
result = r;
}
if (_parent != null)
{
OperationInfo r = _parent.findOperation(signature);
if (r != null)
result = r;
}
OperationInfo r = _operations.get(signature);
if (r != null)
result = r;
return result;
}
private static Object newInstance(Constructor<?> constructor, Object bean)
{
try
{
Object mbean = constructor.getParameterCount() == 0 ? constructor.newInstance() : constructor.newInstance(bean);
if (mbean instanceof ModelMBean)
((ModelMBean)mbean).setManagedResource(bean, "objectReference");
return mbean;
}
catch (Throwable x)
{
return null;
}
}
private void parseMethods(Class<?>... classes)
{
for (Class<?> klass : classes)
{
// Only work on the public method of the class, not of the hierarchy.
for (Method method : klass.getDeclaredMethods())
{
if (!Modifier.isPublic(method.getModifiers()))
continue;
ManagedAttribute attribute = method.getAnnotation(ManagedAttribute.class);
if (attribute != null)
{
AttributeInfo info = new AttributeInfo(attribute, method);
if (LOG.isDebugEnabled())
LOG.debug("Found attribute {} for {}: {}", info._name, klass.getName(), info);
_attributes.put(info._name, info);
}
ManagedOperation operation = method.getAnnotation(ManagedOperation.class);
if (operation != null)
{
OperationInfo info = new OperationInfo(operation, method);
if (LOG.isDebugEnabled())
LOG.debug("Found operation {} for {}: {}", info._name, klass.getName(), info);
_operations.put(info._name, info);
}
}
}
}
static String toAttributeName(String methodName)
{
String attributeName = methodName;
if (methodName.startsWith("get") || methodName.startsWith("set"))
attributeName = attributeName.substring(3);
else if (methodName.startsWith("is"))
attributeName = attributeName.substring(2);
return attributeName.substring(0, 1).toLowerCase(Locale.ENGLISH) + attributeName.substring(1);
}
private static boolean isManagedObject(Class<?> klass)
{
if (klass.isArray())
klass = klass.getComponentType();
if (klass.isPrimitive())
return false;
while (klass != null)
{
if (klass.isAnnotationPresent(ManagedObject.class))
return true;
klass = klass.getSuperclass();
}
return false;
}
private static String signature(String name, String[] params)
{
return String.format("%s(%s)", name, String.join(",", params));
}
private static String signature(Method method)
{
String signature = Arrays.stream(method.getParameterTypes())
.map(Class::getName)
.collect(Collectors.joining(","));
return String.format("%s(%s)", method.getName(), signature);
}
private MBeanInfo buildMBeanInfo(Class<?> klass)
{
ManagedObject managedObject = klass.getAnnotation(ManagedObject.class);
String description = managedObject == null ? "" : managedObject.value();
Map<String, MBeanAttributeInfo> attributeInfos = new HashMap<>();
collectMBeanAttributeInfos(attributeInfos);
Map<String, MBeanOperationInfo> operationInfos = new HashMap<>();
collectMBeanOperationInfos(operationInfos);
MBeanInfo mbeanInfo = _parent == null ? null : _parent.getMBeanInfo();
MBeanAttributeInfo[] attributes = attributeInfos.values().toArray(NO_ATTRIBUTES);
MBeanConstructorInfo[] constructors = mbeanInfo == null ? NO_CONSTRUCTORS : mbeanInfo.getConstructors();
MBeanOperationInfo[] operations = operationInfos.values().toArray(NO_OPERATIONS);
MBeanNotificationInfo[] notifications = mbeanInfo == null ? NO_NOTIFICATIONS : mbeanInfo.getNotifications();
return new MBeanInfo(klass.getName(), description, attributes, constructors, operations, notifications);
}
private void collectMBeanAttributeInfos(Map<String, MBeanAttributeInfo> attributeInfos)
{
// Start with interfaces, overwrite with superClass, then overwrite with local attributes.
for (MetaData intf : _interfaces)
intf.collectMBeanAttributeInfos(attributeInfos);
if (_parent != null)
{
MBeanAttributeInfo[] parentAttributes = _parent.getMBeanInfo().getAttributes();
for (MBeanAttributeInfo parentAttribute : parentAttributes)
attributeInfos.put(parentAttribute.getName(), parentAttribute);
}
for (Map.Entry<String, AttributeInfo> entry : _attributes.entrySet())
attributeInfos.put(entry.getKey(), entry.getValue()._info);
}
private void collectMBeanOperationInfos(Map<String, MBeanOperationInfo> operationInfos)
{
// Start with interfaces, overwrite with superClass, then overwrite with local operations.
for (MetaData intf : _interfaces)
intf.collectMBeanOperationInfos(operationInfos);
if (_parent != null)
{
MBeanOperationInfo[] parentOperations = _parent.getMBeanInfo().getOperations();
for (MBeanOperationInfo parentOperation : parentOperations)
{
String signature = signature(parentOperation.getName(), Arrays.stream(parentOperation.getSignature()).map(MBeanParameterInfo::getType).toArray(String[]::new));
operationInfos.put(signature, parentOperation);
}
}
for (Map.Entry<String, OperationInfo> entry : _operations.entrySet())
operationInfos.put(entry.getKey(), entry.getValue()._info);
}
private static MBeanException toMBeanException(InvocationTargetException x)
{
Throwable cause = x.getCause();
if (cause instanceof Exception)
return new MBeanException((Exception)cause);
else
return new MBeanException(x);
}
@Override
public String toString()
{
return String.format("%s@%x[%s, attrs=%s, opers=%s]", getClass().getSimpleName(), hashCode(),
_klass.getName(), _attributes.keySet(), _operations.keySet());
}
private static class AttributeInfo
{
private final String _name;
private final Method _getter;
private final Method _setter;
private final boolean _proxied;
private final boolean _convert;
private final MBeanAttributeInfo _info;
private AttributeInfo(ManagedAttribute attribute, Method getter)
{
String name = attribute.name();
if ("".equals(name))
name = toAttributeName(getter.getName());
_name = name;
_getter = getter;
boolean readOnly = attribute.readonly();
_setter = readOnly ? null : findSetter(attribute, getter, name);
_proxied = attribute.proxied();
Class<?> returnType = getter.getReturnType();
_convert = isManagedObject(returnType);
String signature = _convert ?
returnType.isArray() ? ObjectName[].class.getName() : ObjectName.class.getName() :
returnType.getName();
String description = attribute.value();
_info = new MBeanAttributeInfo(name, signature, description, true,
_setter != null, getter.getName().startsWith("is"));
}
Object getAttribute(ObjectMBean mbean) throws ReflectionException, MBeanException
{
try
{
Object target = mbean.getManagedObject();
if (_proxied || _getter.getDeclaringClass().isInstance(mbean))
target = mbean;
Object result = _getter.invoke(target);
if (result == null)
return null;
if (!_convert)
return result;
if (!_getter.getReturnType().isArray())
return mbean.findObjectName(result);
int length = Array.getLength(result);
ObjectName[] names = new ObjectName[length];
for (int i = 0; i < length; ++i)
names[i] = mbean.findObjectName(Array.get(result, i));
return names;
}
catch (InvocationTargetException x)
{
throw toMBeanException(x);
}
catch (Exception x)
{
throw new ReflectionException(x);
}
}
void setAttribute(Object value, ObjectMBean mbean) throws ReflectionException, MBeanException
{
if (LOG.isDebugEnabled())
LOG.debug("setAttribute {}.{}={} {}", mbean, _info.getName(), value, _info);
try
{
if (_setter == null)
return;
Object target = mbean.getManagedObject();
if (_proxied || _setter.getDeclaringClass().isInstance(mbean))
target = mbean;
if (!_convert || value == null)
{
_setter.invoke(target, value);
return;
}
if (!_getter.getReturnType().isArray())
{
value = mbean.findBean((ObjectName)value);
_setter.invoke(target, value);
return;
}
ObjectName[] names = (ObjectName[])value;
Object result = new Object[names.length];
for (int i = 0; i < names.length; ++i)
Array.set(result, i, mbean.findBean(names[i]));
_setter.invoke(target, result);
}
catch (InvocationTargetException x)
{
throw toMBeanException(x);
}
catch (Exception x)
{
throw new ReflectionException(x);
}
}
private Method findSetter(ManagedAttribute attribute, Method getter, String name)
{
String setterName = attribute.setter();
if ("".equals(setterName))
setterName = "set" + name.substring(0, 1).toUpperCase(Locale.ENGLISH) + name.substring(1);
Method setter = null;
Class<?> klass = getter.getDeclaringClass();
for (Method method : klass.getMethods())
{
if (method.getName().equals(setterName) && method.getParameterCount() == 1)
{
if (setter != null)
{
LOG.info("Multiple setters for mbean attribute {} in {}", name, klass);
continue;
}
if (!getter.getReturnType().equals(method.getParameterTypes()[0]))
{
LOG.info("Getter/setter type mismatch for mbean attribute {} in {}", name, klass);
continue;
}
setter = method;
}
}
return setter;
}
@Override
public String toString()
{
return String.format("%s@%x[%s,proxied=%b,convert=%b,info=%s]", getClass().getSimpleName(), hashCode(),
_name, _proxied, _convert, _info);
}
}
private static class OperationInfo
{
private final String _name;
private final Method _method;
private final boolean _proxied;
private final boolean _convert;
private final MBeanOperationInfo _info;
private OperationInfo(ManagedOperation operation, Method method)
{
_name = signature(method);
_method = method;
_proxied = operation.proxied();
Class<?> returnType = method.getReturnType();
_convert = isManagedObject(returnType);
String returnSignature = _convert ?
returnType.isArray() ? ObjectName[].class.getName() : ObjectName.class.getName() :
returnType.getName();
String impactName = operation.impact();
int impact = MBeanOperationInfo.UNKNOWN;
if ("ACTION".equals(impactName))
impact = MBeanOperationInfo.ACTION;
else if ("INFO".equals(impactName))
impact = MBeanOperationInfo.INFO;
else if ("ACTION_INFO".equals(impactName))
impact = MBeanOperationInfo.ACTION_INFO;
String description = operation.value();
MBeanParameterInfo[] parameterInfos = parameters(method.getParameterTypes(), method.getParameterAnnotations());
_info = new MBeanOperationInfo(method.getName(), description, parameterInfos, returnSignature, impact);
}
public Object invoke(Object[] args, ObjectMBean mbean) throws ReflectionException, MBeanException
{
if (LOG.isDebugEnabled())
LOG.debug("invoke {}.{}({}) {}", mbean, _info.getName(), Arrays.asList(args), _info);
try
{
Object target = mbean.getManagedObject();
if (_proxied || _method.getDeclaringClass().isInstance(mbean))
target = mbean;
Object result = _method.invoke(target, args);
if (result == null)
return null;
if (!_convert)
return result;
if (!_method.getReturnType().isArray())
return mbean.findObjectName(result);
int length = Array.getLength(result);
ObjectName[] names = new ObjectName[length];
for (int i = 0; i < length; ++i)
names[i] = mbean.findObjectName(Array.get(result, i));
return names;
}
catch (InvocationTargetException x)
{
throw toMBeanException(x);
}
catch (Exception x)
{
throw new ReflectionException(x);
}
}
private static MBeanParameterInfo[] parameters(Class<?>[] parameterTypes, Annotation[][] parametersAnnotations)
{
MBeanParameterInfo[] result = new MBeanParameterInfo[parameterTypes.length];
for (int i = 0; i < parametersAnnotations.length; i++)
{
MBeanParameterInfo info = null;
String typeName = parameterTypes[i].getName();
Annotation[] parameterAnnotations = parametersAnnotations[i];
for (Annotation parameterAnnotation : parameterAnnotations)
{
if (parameterAnnotation instanceof Name)
{
Name name = (Name)parameterAnnotation;
info = result[i] = new MBeanParameterInfo(name.value(), typeName, name.description());
break;
}
}
if (info == null)
result[i] = new MBeanParameterInfo("p" + i, typeName, "");
}
return result;
}
@Override
public String toString()
{
return String.format("%s@%x[%s,proxied=%b,convert=%b]", getClass().getSimpleName(), hashCode(),
_name, _proxied, _convert);
}
}
}

View File

@ -18,42 +18,15 @@
package org.eclipse.jetty.jmx;
import java.lang.annotation.Annotation;
import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import javax.management.Attribute;
import javax.management.AttributeList;
import javax.management.AttributeNotFoundException;
import javax.management.DynamicMBean;
import javax.management.MBeanAttributeInfo;
import javax.management.MBeanConstructorInfo;
import javax.management.MBeanException;
import javax.management.MBeanInfo;
import javax.management.MBeanNotificationInfo;
import javax.management.MBeanOperationInfo;
import javax.management.MBeanParameterInfo;
import javax.management.ObjectName;
import javax.management.ReflectionException;
import javax.management.modelmbean.ModelMBean;
import org.eclipse.jetty.util.Loader;
import org.eclipse.jetty.util.TypeUtil;
import org.eclipse.jetty.util.annotation.ManagedAttribute;
import org.eclipse.jetty.util.annotation.ManagedObject;
import org.eclipse.jetty.util.annotation.ManagedOperation;
import org.eclipse.jetty.util.annotation.Name;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
@ -72,119 +45,11 @@ import org.eclipse.jetty.util.log.Logger;
public class ObjectMBean implements DynamicMBean
{
private static final Logger LOG = Log.getLogger(ObjectMBean.class);
private static final Class<?>[] OBJ_ARG = new Class[]{Object.class};
private static final String OBJECT_NAME_CLASS = ObjectName.class.getName();
private static final String OBJECT_NAME_ARRAY_CLASS = ObjectName[].class.getName();
protected Object _managed;
private MBeanInfo _info;
private Map<String, Method> _getters = new HashMap<>();
private Map<String, Method> _setters = new HashMap<>();
private Map<String, Method> _methods = new HashMap<>();
// set of attributes mined from influence hierarchy
private Set<String> _attributes = new HashSet<>();
// set of attributes that are automatically converted to ObjectName
// as they represent other managed beans which can be linked to
private Set<String> _convert = new HashSet<>();
private ClassLoader _loader;
protected final Object _managed;
private MetaData _metaData;
private MBeanContainer _mbeanContainer;
/**
* <p>Creates an ObjectMBean for the given object.</p>
* <p>Attempts to create an ObjectMBean for the object by searching the package
* and class name space. For example an object of the type:</p>
* <pre>
* class com.acme.MyClass extends com.acme.util.BaseClass implements com.acme.Iface
* </pre>
* <p>then this method would look for the following classes:</p>
* <ul>
* <li>com.acme.jmx.MyClassMBean</li>
* <li>com.acme.util.jmx.BaseClassMBean</li>
* <li>org.eclipse.jetty.jmx.ObjectMBean</li>
* </ul>
*
* @param o The object
* @return A new instance of an MBean for the object or null.
*/
public static Object mbeanFor(Object o)
{
try
{
Class<?> oClass = o.getClass();
while (oClass != null)
{
String pName = oClass.getPackage().getName();
String cName = oClass.getName().substring(pName.length() + 1);
String mName = pName + ".jmx." + cName + "MBean";
try
{
Class<?> mClass;
try
{
// Look for an MBean class from the same loader that loaded the original class
mClass = (Object.class.equals(oClass)) ? oClass = ObjectMBean.class : Loader.loadClass(oClass, mName);
}
catch (ClassNotFoundException e)
{
// Not found, so if not the same as the thread context loader, try that.
if (Thread.currentThread().getContextClassLoader() == oClass.getClassLoader())
throw e;
LOG.ignore(e);
mClass = Loader.loadClass(oClass, mName);
}
if (LOG.isDebugEnabled())
LOG.debug("ObjectMBean: mbeanFor {} mClass={}", o, mClass);
Object mbean = null;
try
{
Constructor<?> constructor = mClass.getConstructor(OBJ_ARG);
mbean = constructor.newInstance(o);
}
catch (Exception e)
{
LOG.ignore(e);
if (ModelMBean.class.isAssignableFrom(mClass))
{
mbean = mClass.getDeclaredConstructor().newInstance();
((ModelMBean)mbean).setManagedResource(o, "objectReference");
}
}
if (LOG.isDebugEnabled())
LOG.debug("mbeanFor {} is {}", o, mbean);
return mbean;
}
catch (ClassNotFoundException e)
{
// The code below was modified to fix bugs 332200 and JETTY-1416
// The issue was caused by additional information added to the
// message after the class name when running in Apache Felix,
// as well as before the class name when running in JBoss.
if (e.getMessage().contains(mName))
LOG.ignore(e);
else
LOG.warn(e);
}
catch (Throwable e)
{
LOG.warn(e);
}
oClass = oClass.getSuperclass();
}
}
catch (Exception e)
{
LOG.ignore(e);
}
return null;
}
/**
* Creates a new ObjectMBean wrapping the given {@code managedObject}.
*
@ -193,7 +58,6 @@ public class ObjectMBean implements DynamicMBean
public ObjectMBean(Object managedObject)
{
_managed = managedObject;
_loader = Thread.currentThread().getContextClassLoader();
}
/**
@ -257,177 +121,34 @@ public class ObjectMBean implements DynamicMBean
return this._mbeanContainer;
}
@Override
public MBeanInfo getMBeanInfo()
/**
* @param o the object to wrap as MBean
* @return a new instance of an MBean for the object or null if the MBean cannot be created
* @deprecated Use {@link MBeanContainer#mbeanFor(Object)} instead
*/
@Deprecated
public static Object mbeanFor(Object o)
{
try
{
if (_info == null)
{
String desc = null;
List<MBeanAttributeInfo> attributes = new ArrayList<>();
List<MBeanOperationInfo> operations = new ArrayList<>();
// Find list of classes that can influence the mbean
Class<?> o_class = _managed.getClass();
List<Class<?>> influences = new ArrayList<>();
influences.add(this.getClass()); // always add MBean itself
influences = findInfluences(influences, _managed.getClass());
if (LOG.isDebugEnabled())
LOG.debug("Influence Count: {}", influences.size());
// Process Type Annotations
ManagedObject primary = o_class.getAnnotation(ManagedObject.class);
if (primary != null)
{
desc = primary.value();
}
else
{
if (LOG.isDebugEnabled())
LOG.debug("No @ManagedObject declared on {}", _managed.getClass());
}
// For each influence
for (Class<?> oClass : influences)
{
ManagedObject typeAnnotation = oClass.getAnnotation(ManagedObject.class);
if (LOG.isDebugEnabled())
LOG.debug("Influenced by: " + oClass.getCanonicalName());
if (typeAnnotation == null)
{
if (LOG.isDebugEnabled())
LOG.debug("Annotations not found for: {}", oClass.getCanonicalName());
continue;
}
// Process Method Annotations
for (Method method : oClass.getDeclaredMethods())
{
ManagedAttribute methodAttributeAnnotation = method.getAnnotation(ManagedAttribute.class);
if (methodAttributeAnnotation != null)
{
if (LOG.isDebugEnabled())
LOG.debug("Attribute Annotation found for: {}", method.getName());
MBeanAttributeInfo mai = defineAttribute(method, methodAttributeAnnotation);
if (mai != null)
attributes.add(mai);
}
ManagedOperation methodOperationAnnotation = method.getAnnotation(ManagedOperation.class);
if (methodOperationAnnotation != null)
{
if (LOG.isDebugEnabled())
LOG.debug("Method Annotation found for: {}", method.getName());
MBeanOperationInfo oi = defineOperation(method, methodOperationAnnotation);
if (oi != null)
operations.add(oi);
}
}
}
_info = new MBeanInfo(o_class.getName(),
desc,
attributes.toArray(new MBeanAttributeInfo[attributes.size()]),
new MBeanConstructorInfo[0],
operations.toArray(new MBeanOperationInfo[operations.size()]),
new MBeanNotificationInfo[0]);
}
}
catch (RuntimeException e)
{
LOG.warn(e);
throw e;
}
return _info;
return MBeanContainer.mbeanFor(null, o);
}
@Override
public Object getAttribute(String name) throws AttributeNotFoundException, ReflectionException
public MBeanInfo getMBeanInfo()
{
Method getter = _getters.get(name);
if (getter == null)
throw new AttributeNotFoundException(name);
return metaData().getMBeanInfo();
}
@Override
public Object getAttribute(String name) throws AttributeNotFoundException, ReflectionException, MBeanException
{
ClassLoader prevLoader = Thread.currentThread().getContextClassLoader();
try
{
Object o = _managed;
if (getter.getDeclaringClass().isInstance(this))
o = this; // mbean method
// get the attribute
Object r = getter.invoke(o, (java.lang.Object[])null);
// convert to ObjectName if the type has the @ManagedObject annotation
if (r != null)
{
if (r.getClass().isArray())
{
if (r.getClass().getComponentType().isAnnotationPresent(ManagedObject.class))
{
ObjectName[] on = new ObjectName[Array.getLength(r)];
for (int i = 0; i < on.length; i++)
on[i] = _mbeanContainer.findMBean(Array.get(r, i));
r = on;
}
}
else if (r instanceof Collection<?>)
{
@SuppressWarnings("unchecked")
Collection<Object> c = (Collection<Object>)r;
if (!c.isEmpty() && c.iterator().next().getClass().isAnnotationPresent(ManagedObject.class))
{
// check the first thing out
ObjectName[] on = new ObjectName[c.size()];
int i = 0;
for (Object obj : c)
{
on[i++] = _mbeanContainer.findMBean(obj);
}
r = on;
}
}
else
{
Class<?> clazz = r.getClass();
while (clazz != null)
{
if (clazz.isAnnotationPresent(ManagedObject.class))
{
ObjectName mbean = _mbeanContainer.findMBean(r);
if (mbean != null)
{
return mbean;
}
else
{
return null;
}
}
clazz = clazz.getSuperclass();
}
}
}
return r;
return metaData().getAttribute(name, this);
}
catch (IllegalAccessException e)
finally
{
LOG.warn(Log.EXCEPTION, e);
throw new AttributeNotFoundException(e.toString());
}
catch (InvocationTargetException e)
{
LOG.warn(Log.EXCEPTION, e);
throw new ReflectionException(new Exception(e.getCause()));
Thread.currentThread().setContextClassLoader(prevLoader);
}
}
@ -441,408 +162,77 @@ public class ObjectMBean implements DynamicMBean
{
results.add(new Attribute(name, getAttribute(name)));
}
catch (Exception e)
catch (Throwable x)
{
LOG.warn(Log.EXCEPTION, e);
if (LOG.isDebugEnabled())
LOG.debug(x);
}
}
return results;
}
@Override
public void setAttribute(Attribute attr) throws AttributeNotFoundException, ReflectionException
public void setAttribute(Attribute attribute) throws AttributeNotFoundException, ReflectionException, MBeanException
{
if (attr == null)
return;
if (LOG.isDebugEnabled())
LOG.debug("setAttribute " + _managed + ":" + attr.getName() + "=" + attr.getValue());
Method setter = _setters.get(attr.getName());
if (setter == null)
throw new AttributeNotFoundException(attr.getName());
ClassLoader prevLoader = Thread.currentThread().getContextClassLoader();
try
{
Object o = _managed;
if (setter.getDeclaringClass().isInstance(this))
o = this;
// get the value
Object value = attr.getValue();
// convert from ObjectName if need be
if (value != null && _convert.contains(attr.getName()))
{
if (value.getClass().isArray())
{
Class<?> t = setter.getParameterTypes()[0].getComponentType();
Object na = Array.newInstance(t, Array.getLength(value));
for (int i = Array.getLength(value); i-- > 0; )
Array.set(na, i, _mbeanContainer.findBean((ObjectName)Array.get(value, i)));
value = na;
}
else
value = _mbeanContainer.findBean((ObjectName)value);
}
// do the setting
setter.invoke(o, value);
}
catch (IllegalAccessException e)
{
LOG.warn(Log.EXCEPTION, e);
throw new AttributeNotFoundException(e.toString());
}
catch (InvocationTargetException e)
{
LOG.warn(Log.EXCEPTION, e);
throw new ReflectionException(new Exception(e.getCause()));
}
}
@Override
public AttributeList setAttributes(AttributeList attrs)
{
if (LOG.isDebugEnabled())
LOG.debug("setAttributes");
AttributeList results = new AttributeList(attrs.size());
for (Object element : attrs)
{
try
{
Attribute attr = (Attribute)element;
setAttribute(attr);
results.add(new Attribute(attr.getName(), getAttribute(attr.getName())));
}
catch (Exception e)
{
LOG.warn(Log.EXCEPTION, e);
}
}
return results;
}
@Override
public Object invoke(String name, Object[] params, String[] signature) throws MBeanException, ReflectionException
{
if (LOG.isDebugEnabled())
LOG.debug("ObjectMBean:invoke " + name);
StringBuilder builder = new StringBuilder(name);
builder.append("(");
if (signature != null)
for (int i = 0; i < signature.length; i++)
builder.append(i > 0 ? "," : "").append(signature[i]);
builder.append(")");
String methodKey = builder.toString();
ClassLoader old_loader = Thread.currentThread().getContextClassLoader();
try
{
Thread.currentThread().setContextClassLoader(_loader);
Method method = _methods.get(methodKey);
if (method == null)
throw new NoSuchMethodException(methodKey);
Object o = _managed;
if (method.getDeclaringClass().isInstance(this))
o = this;
return method.invoke(o, params);
}
catch (NoSuchMethodException e)
{
LOG.warn(Log.EXCEPTION, e);
throw new ReflectionException(e);
}
catch (IllegalAccessException e)
{
LOG.warn(Log.EXCEPTION, e);
throw new MBeanException(e);
}
catch (InvocationTargetException e)
{
LOG.warn(Log.EXCEPTION, e);
throw new ReflectionException(new Exception(e.getCause()));
metaData().setAttribute(attribute, this);
}
finally
{
Thread.currentThread().setContextClassLoader(old_loader);
Thread.currentThread().setContextClassLoader(prevLoader);
}
}
private static List<Class<?>> findInfluences(List<Class<?>> influences, Class<?> aClass)
@Override
public AttributeList setAttributes(AttributeList attributes)
{
if (aClass != null)
AttributeList results = new AttributeList(attributes.size());
for (Attribute attribute : attributes.asList())
{
if (!influences.contains(aClass))
try
{
// This class is a new influence
influences.add(aClass);
setAttribute(attribute);
results.add(new Attribute(attribute.getName(), getAttribute(attribute.getName())));
}
catch (Throwable x)
{
if (LOG.isDebugEnabled())
LOG.debug(x);
}
// So are the super classes
influences = findInfluences(influences, aClass.getSuperclass());
// So are the interfaces
Class<?>[] ifs = aClass.getInterfaces();
for (int i = 0; ifs != null && i < ifs.length; i++)
influences = findInfluences(influences, ifs[i]);
}
return influences;
return results;
}
/**
* <p>Defines an attribute for the managed object using the annotation attributes.</p>
*
* @param method the method on the managed objec
* @param attributeAnnotation the annotation with the attribute metadata
* @return an MBeanAttributeInfo with the attribute metadata
*/
private MBeanAttributeInfo defineAttribute(Method method, ManagedAttribute attributeAnnotation)
@Override
public Object invoke(String name, Object[] params, String[] signature) throws ReflectionException, MBeanException
{
// determine the name of the managed attribute
String name = attributeAnnotation.name();
if ("".equals(name))
name = toVariableName(method.getName());
if (_attributes.contains(name))
return null; // we have an attribute named this already
String description = attributeAnnotation.value();
boolean readonly = attributeAnnotation.readonly();
boolean onMBean = attributeAnnotation.proxied();
// determine if we should convert
Class<?> return_type = method.getReturnType();
// get the component type
Class<?> component_type = return_type;
while (component_type.isArray())
component_type = component_type.getComponentType();
// Test to see if the returnType or any of its super classes are managed objects
boolean convert = isAnnotationPresent(component_type, ManagedObject.class);
String uName = name.substring(0, 1).toUpperCase(Locale.ENGLISH) + name.substring(1);
Class<?> oClass = onMBean ? this.getClass() : _managed.getClass();
if (LOG.isDebugEnabled())
LOG.debug("defineAttribute {} {}:{}:{}:{}", name, onMBean, readonly, oClass, description);
Method setter = null;
// dig out a setter if one exists
if (!readonly)
{
String declaredSetter = attributeAnnotation.setter();
if (LOG.isDebugEnabled())
LOG.debug("DeclaredSetter: {}", declaredSetter);
for (Method method1 : oClass.getMethods())
{
if (!Modifier.isPublic(method1.getModifiers()))
continue;
if (!"".equals(declaredSetter))
{
// look for a declared setter
if (method1.getName().equals(declaredSetter) && method1.getParameterCount() == 1)
{
if (setter != null)
{
LOG.warn("Multiple setters for mbean attr {} in {}", name, oClass);
continue;
}
setter = method1;
if (!component_type.equals(method1.getParameterTypes()[0]))
{
LOG.warn("Type conflict for mbean attr {} in {}", name, oClass);
continue;
}
if (LOG.isDebugEnabled())
LOG.debug("Declared Setter: " + declaredSetter);
}
}
// look for a setter
if (method1.getName().equals("set" + uName) && method1.getParameterCount() == 1)
{
if (setter != null)
{
LOG.warn("Multiple setters for mbean attr {} in {}", name, oClass);
continue;
}
setter = method1;
if (!return_type.equals(method1.getParameterTypes()[0]))
LOG.warn("Type conflict for mbean attr {} in {}", name, oClass);
}
}
}
if (convert)
{
if (component_type.isPrimitive() && !component_type.isArray())
{
LOG.warn("Cannot convert mbean primitive {}", name);
return null;
}
if (LOG.isDebugEnabled())
LOG.debug("passed convert checks {} for type {}", name, component_type);
}
ClassLoader prevLoader = Thread.currentThread().getContextClassLoader();
try
{
// Remember the methods
_getters.put(name, method);
_setters.put(name, setter);
MBeanAttributeInfo info;
if (convert)
{
_convert.add(name);
info = new MBeanAttributeInfo(name,
component_type.isArray() ? OBJECT_NAME_ARRAY_CLASS : OBJECT_NAME_CLASS,
description,
true,
setter != null,
method.getName().startsWith("is"));
}
else
{
info = new MBeanAttributeInfo(name, description, method, setter);
}
_attributes.add(name);
return info;
return metaData().invoke(name, signature, params, this);
}
catch (Exception e)
finally
{
LOG.warn(e);
throw new IllegalArgumentException(e.toString());
Thread.currentThread().setContextClassLoader(prevLoader);
}
}
/**
* <p>Defines an operation for the managed object using the annotation attributes.</p>
*
* @param method the method on the managed object
* @param methodAnnotation the annotation with the operation metadata
* @return an MBeanOperationInfo with the operation metadata
*/
private MBeanOperationInfo defineOperation(Method method, ManagedOperation methodAnnotation)
ObjectName findObjectName(Object bean)
{
String description = methodAnnotation.value();
boolean onMBean = methodAnnotation.proxied();
// determine if we should convert
Class<?> returnType = method.getReturnType();
if (returnType.isArray())
{
if (LOG.isDebugEnabled())
LOG.debug("returnType is array, get component type");
returnType = returnType.getComponentType();
}
boolean convert = false;
if (returnType.isAnnotationPresent(ManagedObject.class))
convert = true;
String impactName = methodAnnotation.impact();
if (LOG.isDebugEnabled())
LOG.debug("defineOperation {} {}:{}:{}", method.getName(), onMBean, impactName, description);
try
{
// Resolve the impact
int impact = MBeanOperationInfo.UNKNOWN;
if ("UNKNOWN".equals(impactName))
impact = MBeanOperationInfo.UNKNOWN;
else if ("ACTION".equals(impactName))
impact = MBeanOperationInfo.ACTION;
else if ("INFO".equals(impactName))
impact = MBeanOperationInfo.INFO;
else if ("ACTION_INFO".equals(impactName))
impact = MBeanOperationInfo.ACTION_INFO;
else
LOG.warn("Unknown impact '" + impactName + "' for " + method);
Annotation[][] allParameterAnnotations = method.getParameterAnnotations();
Class<?>[] methodTypes = method.getParameterTypes();
MBeanParameterInfo[] pInfo = new MBeanParameterInfo[allParameterAnnotations.length];
for (int i = 0; i < allParameterAnnotations.length; ++i)
{
Annotation[] parameterAnnotations = allParameterAnnotations[i];
for (Annotation anno : parameterAnnotations)
{
if (anno instanceof Name)
{
Name nameAnnotation = (Name)anno;
pInfo[i] = new MBeanParameterInfo(nameAnnotation.value(), methodTypes[i].getName(), nameAnnotation.description());
}
}
}
StringBuilder builder = new StringBuilder(method.getName());
builder.append("(");
for (int i = 0; i < methodTypes.length; ++i)
{
builder.append(methodTypes[i].getName());
if (i != methodTypes.length - 1)
builder.append(",");
}
builder.append(")");
String signature = builder.toString();
Class<?> returnClass = method.getReturnType();
if (LOG.isDebugEnabled())
LOG.debug("Method Cache: " + signature);
if (_methods.containsKey(signature))
return null; // we have an operation for this already
_methods.put(signature, method);
if (convert)
_convert.add(signature);
return new MBeanOperationInfo(method.getName(), description, pInfo, returnClass.isPrimitive() ? TypeUtil.toName(returnClass) : (returnClass.getName()), impact);
}
catch (Exception e)
{
LOG.warn("Operation '" + method + "'", e);
throw new IllegalArgumentException(e.toString());
}
return _mbeanContainer.findMBean(bean);
}
protected String toVariableName(String methodName)
Object findBean(ObjectName objectName)
{
String variableName = methodName;
if (methodName.startsWith("get") || methodName.startsWith("set"))
variableName = variableName.substring(3);
else if (methodName.startsWith("is"))
variableName = variableName.substring(2);
return variableName.substring(0, 1).toLowerCase(Locale.ENGLISH) + variableName.substring(1);
return _mbeanContainer.findBean(objectName);
}
protected boolean isAnnotationPresent(Class<?> clazz, Class<? extends Annotation> annotation)
MetaData metaData()
{
Class<?> test = clazz;
while (test != null)
{
if (test.isAnnotationPresent(annotation))
return true;
else
test = test.getSuperclass();
}
return false;
if (_metaData == null)
_metaData = MBeanContainer.findMetaData(_mbeanContainer, _managed.getClass());
return _metaData;
}
}

View File

@ -25,7 +25,6 @@ import org.eclipse.jetty.util.annotation.ManagedOperation;
@ManagedObject(value = "Test the mbean extended stuff")
public class DerivedExtended extends Derived
{
private String doodle4 = "doodle4";
@ManagedAttribute(value = "The doodle4 name of something", name = "doodle4", setter = "setDoodle4")

View File

@ -18,24 +18,23 @@
package org.eclipse.jetty.jmx;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
import com.acme.Managed;
import java.lang.management.ManagementFactory;
import javax.management.MBeanServer;
import javax.management.ObjectName;
import com.acme.Managed;
import org.eclipse.jetty.util.component.Container;
import org.eclipse.jetty.util.component.ContainerLifeCycle;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
public class MBeanContainerTest
{
private MBeanContainer mbeanContainer;
@ -54,27 +53,21 @@ public class MBeanContainerTest
@Test
public void testMakeName()
{
// given
beanName = "mngd:bean";
// when
beanName = mbeanContainer.makeName(beanName);
// then
assertEquals("mngd_bean", beanName, "Bean name should be mngd_bean");
}
@Test
public void testFindBean()
{
// given
managed = getManaged();
// when
objectName = mbeanContainer.findMBean(managed);
assertNotNull(objectName);
// then
assertEquals(managed, mbeanContainer.findBean(objectName), "Bean must be added");
assertNull(mbeanContainer.findBean(null), "It must return null as there is no bean with the name null");
}
@ -104,40 +97,31 @@ public class MBeanContainerTest
@Test
public void testDomain()
{
// given
String domain = "Test";
// when
mbeanContainer.setDomain(domain);
// then
assertEquals(domain, mbeanContainer.getDomain(), "Domain name must be Test");
}
@Test
public void testBeanAdded() throws Exception
public void testBeanAdded()
{
// given
setBeanAdded();
// when
objectName = mbeanContainer.findMBean(managed);
// then
assertTrue(mbeanServer.isRegistered(objectName), "Bean must have been registered");
}
@Test
public void testBeanAddedNullCheck() throws Exception
public void testBeanAddedNullCheck()
{
// given
setBeanAdded();
Integer mbeanCount = mbeanServer.getMBeanCount();
// when
mbeanContainer.beanAdded(null, null);
// then
assertEquals(mbeanCount, mbeanServer.getMBeanCount(), "MBean count must not change after beanAdded(null, null) call");
}
@ -150,15 +134,12 @@ public class MBeanContainerTest
}
@Test
public void testBeanRemoved() throws Exception
public void testBeanRemoved()
{
// given
setUpBeanRemoved();
// when
mbeanContainer.beanRemoved(null, managed);
// then
assertNull(mbeanContainer.findMBean(managed), "Bean shouldn't be registered with container as we removed the bean");
}
@ -200,30 +181,24 @@ public class MBeanContainerTest
}
@Test
public void testDestroy() throws Exception
public void testDestroy()
{
// given
setUpDestroy();
// when
objectName = mbeanContainer.findMBean(managed);
mbeanContainer.destroy();
// then
assertFalse(mbeanContainer.getMBeanServer().isRegistered(objectName), "Unregistered bean - managed");
}
@Test
public void testDestroyInstanceNotFoundException() throws Exception
{
// given
setUpDestroy();
// when
objectName = mbeanContainer.findMBean(managed);
mbeanContainer.getMBeanServer().unregisterMBean(objectName);
// then
assertFalse(mbeanContainer.getMBeanServer().isRegistered(objectName), "Unregistered bean - managed");
// this flow covers InstanceNotFoundException. Actual code just eating
// the exception. i.e Actual code just printing the stacktrace, whenever

View File

@ -18,12 +18,6 @@
package org.eclipse.jetty.jmx;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
import com.acme.Derived;
import java.lang.management.ManagementFactory;
import javax.management.Attribute;
@ -31,198 +25,127 @@ import javax.management.MBeanInfo;
import javax.management.MBeanOperationInfo;
import javax.management.MBeanParameterInfo;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
import org.eclipse.jetty.util.thread.QueuedThreadPool;
import com.acme.Derived;
import com.acme.Managed;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertNotSame;
import static org.junit.jupiter.api.Assertions.assertSame;
import static org.junit.jupiter.api.Assertions.assertTrue;
public class ObjectMBeanTest
{
private static final Logger LOG = Log.getLogger(ObjectMBeanTest.class);
private static MBeanContainer container;
private MBeanContainer container;
@BeforeEach
public void before() throws Exception
public void before()
{
container = new MBeanContainer(ManagementFactory.getPlatformMBeanServer());
}
@AfterEach
public void after() throws Exception
public void after()
{
container.destroy();
container = null;
}
/*
* this test uses the com.acme.Derived test classes
*/
@Test
public void testMetaDataCaching()
{
Derived derived = new Derived();
ObjectMBean derivedMBean = (ObjectMBean)container.mbeanFor(derived);
ObjectMBean derivedMBean2 = (ObjectMBean)container.mbeanFor(derived);
assertNotSame(derivedMBean, derivedMBean2);
assertSame(derivedMBean.metaData(), derivedMBean2.metaData());
}
@Test
public void testDerivedAttributes() throws Exception
{
Derived derived = new Derived();
ObjectMBean mbean = (ObjectMBean)ObjectMBean.mbeanFor(derived);
Managed managed = derived.getManagedInstance();
ObjectMBean derivedMBean = (ObjectMBean)container.mbeanFor(derived);
ObjectMBean managedMBean = (ObjectMBean)container.mbeanFor(managed);
ObjectMBean managed = (ObjectMBean)ObjectMBean.mbeanFor(derived.getManagedInstance());
mbean.setMBeanContainer(container);
managed.setMBeanContainer(container);
container.beanAdded(null, derived);
container.beanAdded(null, managed);
container.beanAdded(null,derived);
container.beanAdded(null,derived.getManagedInstance());
MBeanInfo derivedInfo = derivedMBean.getMBeanInfo();
assertNotNull(derivedInfo);
MBeanInfo managedInfo = managedMBean.getMBeanInfo();
assertNotNull(managedInfo);
MBeanInfo toss = managed.getMBeanInfo();
assertEquals("com.acme.Derived", derivedInfo.getClassName(), "name does not match");
assertEquals("Test the mbean stuff", derivedInfo.getDescription(), "description does not match");
assertEquals(6, derivedInfo.getAttributes().length, "attribute count does not match");
assertEquals("Full Name", derivedMBean.getAttribute("fname"), "attribute values does not match");
assertNotNull(mbean.getMBeanInfo());
MBeanInfo info = mbean.getMBeanInfo();
assertEquals("com.acme.Derived", info.getClassName(), "name does not match");
assertEquals("Test the mbean stuff", info.getDescription(), "description does not match");
// for ( MBeanAttributeInfo i : info.getAttributes())
// {
// LOG.debug(i.toString());
// }
/*
* 2 attributes from lifecycle and 2 from Derived and 1 from MBean
*/
assertEquals(6, info.getAttributes().length, "attribute count does not match");
assertEquals("Full Name", mbean.getAttribute("fname"), "attribute values does not match");
mbean.setAttribute(new Attribute("fname","Fuller Name"));
assertEquals("Fuller Name", mbean.getAttribute("fname"), "set attribute value does not match");
assertEquals("goop", mbean.getAttribute("goop"), "proxy attribute values do not match");
// Thread.sleep(100000);
derivedMBean.setAttribute(new Attribute("fname", "Fuller Name"));
assertEquals("Fuller Name", derivedMBean.getAttribute("fname"), "set attribute value does not match");
assertEquals("goop", derivedMBean.getAttribute("goop"), "proxy attribute values do not match");
}
@Test
public void testDerivedOperations() throws Exception
{
Derived derived = new Derived();
ObjectMBean mbean = (ObjectMBean)ObjectMBean.mbeanFor(derived);
ObjectMBean mbean = (ObjectMBean)container.mbeanFor(derived);
mbean.setMBeanContainer(container);
container.beanAdded(null,derived);
container.beanAdded(null, derived);
MBeanInfo info = mbean.getMBeanInfo();
assertEquals(5, info.getOperations().length, "operation count does not match");
MBeanOperationInfo[] opinfos = info.getOperations();
MBeanOperationInfo[] operationInfos = info.getOperations();
boolean publish = false;
boolean doodle = false;
boolean good = false;
for (int i = 0; i < opinfos.length; ++i)
for (MBeanOperationInfo operationInfo : operationInfos)
{
MBeanOperationInfo opinfo = opinfos[i];
if ("publish".equals(opinfo.getName()))
if ("publish".equals(operationInfo.getName()))
{
publish = true;
assertEquals("publish something", opinfo.getDescription(), "description doesn't match");
assertEquals("publish something", operationInfo.getDescription(), "description doesn't match");
}
if ("doodle".equals(opinfo.getName()))
if ("doodle".equals(operationInfo.getName()))
{
doodle = true;
assertEquals("Doodle something", opinfo.getDescription(), "description doesn't match");
MBeanParameterInfo[] pinfos = opinfo.getSignature();
assertEquals("A description of the argument", pinfos[0].getDescription(), "parameter description doesn't match");
assertEquals("doodle", pinfos[0].getName(), "parameter name doesn't match");
assertEquals("Doodle something", operationInfo.getDescription(), "description doesn't match");
MBeanParameterInfo[] parameterInfos = operationInfo.getSignature();
assertEquals("A description of the argument", parameterInfos[0].getDescription(), "parameter description doesn't match");
assertEquals("doodle", parameterInfos[0].getName(), "parameter name doesn't match");
}
// This is a proxied operation on the JMX wrapper
if ("good".equals(opinfo.getName()))
// This is a proxied operation on the MBean wrapper.
if ("good".equals(operationInfo.getName()))
{
good = true;
assertEquals("test of proxy operations", opinfo.getDescription(), "description does not match");
assertEquals("not bad",mbean.invoke("good",new Object[] {}, new String[] {}), "execution contexts wrong");
assertEquals("test of proxy operations", operationInfo.getDescription(), "description does not match");
assertEquals("not bad", mbean.invoke("good", new Object[]{}, new String[]{}), "execution contexts wrong");
}
}
assertTrue(publish, "publish operation was not not found");
assertTrue(doodle, "doodle operation was not not found");
assertTrue(good, "good operation was not not found");
}
@Test
public void testDerivedObjectAttributes() throws Exception
public void testMethodNameMining()
{
Derived derived = new Derived();
ObjectMBean mbean = (ObjectMBean)ObjectMBean.mbeanFor(derived);
ObjectMBean managed = (ObjectMBean)ObjectMBean.mbeanFor(derived.getManagedInstance());
mbean.setMBeanContainer(container);
managed.setMBeanContainer(container);
assertNotNull(mbean.getMBeanInfo());
container.beanAdded(null,derived);
container.beanAdded(null,derived.getManagedInstance());
container.beanAdded(null,mbean);
container.beanAdded(null,managed);
// Managed managedInstance = (Managed)mbean.getAttribute("managedInstance");
// assertNotNull(managedInstance);
// assertEquals("foo", managedInstance.getManaged(), "managed instance returning nonsense");
assertEquals("fullName", MetaData.toAttributeName("getFullName"));
assertEquals("fullName", MetaData.toAttributeName("getfullName"));
assertEquals("fullName", MetaData.toAttributeName("isFullName"));
assertEquals("fullName", MetaData.toAttributeName("isfullName"));
assertEquals("fullName", MetaData.toAttributeName("setFullName"));
assertEquals("fullName", MetaData.toAttributeName("setfullName"));
assertEquals("fullName", MetaData.toAttributeName("FullName"));
assertEquals("fullName", MetaData.toAttributeName("fullName"));
}
@Test
@Disabled("ignore, used in testing jconsole atm")
public void testThreadPool() throws Exception
{
Derived derived = new Derived();
ObjectMBean mbean = (ObjectMBean)ObjectMBean.mbeanFor(derived);
ObjectMBean managed = (ObjectMBean)ObjectMBean.mbeanFor(derived.getManagedInstance());
mbean.setMBeanContainer(container);
managed.setMBeanContainer(container);
QueuedThreadPool qtp = new QueuedThreadPool();
ObjectMBean bqtp = (ObjectMBean)ObjectMBean.mbeanFor(qtp);
bqtp.getMBeanInfo();
container.beanAdded(null,derived);
container.beanAdded(null,derived.getManagedInstance());
container.beanAdded(null,mbean);
container.beanAdded(null,managed);
container.beanAdded(null,qtp);
Thread.sleep(10000000);
}
@Test
public void testMethodNameMining() throws Exception
{
ObjectMBean mbean = new ObjectMBean(new Derived());
assertEquals("fullName",mbean.toVariableName("getFullName"));
assertEquals("fullName",mbean.toVariableName("getfullName"));
assertEquals("fullName",mbean.toVariableName("isFullName"));
assertEquals("fullName",mbean.toVariableName("isfullName"));
assertEquals("fullName",mbean.toVariableName("setFullName"));
assertEquals("fullName",mbean.toVariableName("setfullName"));
assertEquals("fullName",mbean.toVariableName("FullName"));
assertEquals("fullName",mbean.toVariableName("fullName"));
}
}

View File

@ -18,10 +18,6 @@
package org.eclipse.jetty.jmx;
import com.acme.Derived;
import com.acme.DerivedExtended;
import com.acme.DerivedManaged;
import java.lang.management.ManagementFactory;
import java.util.ArrayList;
import java.util.Arrays;
@ -33,68 +29,33 @@ import javax.management.MBeanException;
import javax.management.MBeanInfo;
import javax.management.ReflectionException;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
import org.eclipse.jetty.util.log.StdErrLog;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import com.acme.Derived;
import com.acme.DerivedExtended;
import com.acme.DerivedManaged;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertThrows;
public class ObjectMBeanUtilTest
{
private ObjectMBean objectMBean;
private DerivedExtended derivedExtended;
private MBeanContainer container;
private MBeanInfo objectMBeanInfo;
private Object mBean;
private String value;
private Attribute attribute;
private AttributeList attributes;
private ObjectMBean mBeanDerivedManaged;
private Derived[] derivedes;
private ArrayList<Derived> aliasNames;
private DerivedManaged derivedManaged;
private static final int EMPTY = 0;
@BeforeAll
public static void beforeClass()
{
Logger ombLog = Log.getLogger(ObjectMBean.class);
if (ombLog instanceof StdErrLog && !ombLog.isDebugEnabled())
((StdErrLog)ombLog).setHideStacks(true);
}
@AfterAll
public static void afterClass()
{
Logger ombLog = Log.getLogger(ObjectMBean.class);
if (ombLog instanceof StdErrLog)
((StdErrLog)ombLog).setHideStacks(false);
}
@BeforeEach
public void setUp()
{
derivedExtended = new DerivedExtended();
objectMBean = new ObjectMBean(derivedExtended);
container = new MBeanContainer(ManagementFactory.getPlatformMBeanServer());
objectMBean.setMBeanContainer(container);
derivedExtended = new DerivedExtended();
objectMBean = (ObjectMBean)container.mbeanFor(derivedExtended);
objectMBeanInfo = objectMBean.getMBeanInfo();
}
@ -112,131 +73,93 @@ public class ObjectMBeanUtilTest
@Test
public void testMbeanForNullCheck()
{
// when
mBean = ObjectMBean.mbeanFor(null);
// then
Object mBean = container.mbeanFor(null);
assertNull(mBean, "As we are passing null value the output should be null");
}
@Test
public void testGetAttributeReflectionException() throws Exception
public void testGetAttributeMBeanException() throws Exception
{
// given
setUpGetAttribute("doodle4","charu");
Attribute attribute = new Attribute("doodle4", "charu");
objectMBean.setAttribute(attribute);
// when
ReflectionException e = assertThrows(ReflectionException.class, ()-> {
objectMBean.getAttribute("doodle4");
});
MBeanException e = assertThrows(MBeanException.class, () -> objectMBean.getAttribute("doodle4"));
// then
assertNotNull(e, "An InvocationTargetException must have occurred by now as doodle4() internally throwing exception");
}
private void setUpGetAttribute(String property, String value) throws Exception
{
Attribute attribute = new Attribute(property,value);
objectMBean.setAttribute(attribute);
}
@Test
public void testGetAttributeAttributeNotFoundException() throws Exception
public void testGetAttributeAttributeNotFoundException()
{
// when
AttributeNotFoundException e = assertThrows(AttributeNotFoundException.class, ()->{
objectMBean.getAttribute("ffname");
});
AttributeNotFoundException e = assertThrows(AttributeNotFoundException.class, () -> objectMBean.getAttribute("ffname"));
// then
assertNotNull(e, "An AttributeNotFoundException must have occurred by now as there is no " + "attribute with the name ffname in bean");
assertNotNull(e, "An AttributeNotFoundException must have occurred by now as there is no attribute with the name ffname in bean");
}
@Test
public void testSetAttributeWithCorrectAttrName() throws Exception
{
// given
setUpGetAttribute("fname","charu");
Attribute attribute = new Attribute("fname", "charu");
objectMBean.setAttribute(attribute);
// when
value = (String)objectMBean.getAttribute("fname");
String value = (String)objectMBean.getAttribute("fname");
// then
assertEquals("charu", value, "Attribute(fname) value must be equl to charu");
assertEquals("charu", value, "Attribute(fname) value must be equal to charu");
}
@Test
public void testSetAttributeNullCheck() throws Exception
{
// given
objectMBean.setAttribute(null);
// when
AttributeNotFoundException e = assertThrows(AttributeNotFoundException.class, ()->{
objectMBean.getAttribute(null);
});
AttributeNotFoundException e = assertThrows(AttributeNotFoundException.class, () -> objectMBean.getAttribute(null));
// then
assertNotNull(e,"An AttributeNotFoundException must have occurred by now as there is no attribute with the name null");
assertNotNull(e, "An AttributeNotFoundException must have occurred by now as there is no attribute with the name null");
}
@Test
public void testSetAttributeAttributeWithWrongAttrName() throws Exception
public void testSetAttributeAttributeWithWrongAttrName()
{
// given
attribute = new Attribute("fnameee","charu");
attribute = new Attribute("fnameee", "charu");
// when
AttributeNotFoundException e = assertThrows(AttributeNotFoundException.class, ()->{
objectMBean.setAttribute(attribute);
});
AttributeNotFoundException e = assertThrows(AttributeNotFoundException.class, () -> objectMBean.setAttribute(attribute));
// then
assertNotNull(e, "An AttributeNotFoundException must have occurred by now as there is no attribute " + "with the name ffname in bean");
}
@Test
public void testSetAttributesWithCorrectValues() throws Exception
public void testSetAttributesWithCorrectValues()
{
// given
attributes = getAttributes("fname","vijay");
attributes = objectMBean.setAttributes(attributes);
AttributeList attributes = getAttributes("fname", "vijay");
objectMBean.setAttributes(attributes);
// when
attributes = objectMBean.getAttributes(new String[]
{ "fname" });
attributes = objectMBean.getAttributes(new String[]{"fname"});
// then
assertEquals(1, attributes.size());
assertEquals("vijay", ((Attribute)(attributes.get(0))).getValue(), "Fname value must be equal to vijay");
}
@Test
public void testSetAttributesForArrayTypeAttribue() throws Exception
public void testSetAttributesForArrayTypeAttribute() throws Exception
{
// given
derivedes = getArrayTypeAttribute();
Derived[] deriveds = getArrayTypeAttribute();
// when
derivedManaged.setAddresses(derivedes);
derivedManaged.setAddresses(deriveds);
mBeanDerivedManaged.getMBeanInfo();
// then
assertNotNull(mBeanDerivedManaged.getAttribute("addresses"), "Address object shouldn't be null");
}
@Test
public void testSetAttributesForCollectionTypeAttribue() throws Exception
{
// given
aliasNames = getCollectionTypeAttribute();
ArrayList<Derived> aliasNames = new ArrayList<>(Arrays.asList(getArrayTypeAttribute()));
// when
derivedManaged.setAliasNames(aliasNames);
mBeanDerivedManaged.getMBeanInfo();
// then
assertNotNull(mBeanDerivedManaged.getAttribute("aliasNames"), "Address object shouldn't be null");
assertNull(mBeanDerivedManaged.getAttribute("derived"), "Derived object shouldn't registerd with container so its value will be null");
assertNull(mBeanDerivedManaged.getAttribute("derived"), "Derived object shouldn't registered with container so its value will be null");
}
private Derived[] getArrayTypeAttribute()
@ -246,119 +169,74 @@ public class ObjectMBeanUtilTest
MBeanContainer mBeanDerivedManagedContainer = new MBeanContainer(ManagementFactory.getPlatformMBeanServer());
mBeanDerivedManaged.setMBeanContainer(mBeanDerivedManagedContainer);
Derived derived0 = new Derived();
mBeanDerivedManagedContainer.beanAdded(null,derived0);
Derived[] derivedes = new Derived[3];
mBeanDerivedManagedContainer.beanAdded(null, derived0);
Derived[] deriveds = new Derived[3];
for (int i = 0; i < 3; i++)
{
derivedes[i] = new Derived();
}
derivedManaged.setAddresses(derivedes);
deriveds[i] = new Derived();
derivedManaged.setAddresses(deriveds);
mBeanDerivedManaged.getMBeanInfo();
ArrayList<Derived> aliasNames = new ArrayList<Derived>(Arrays.asList(derivedes));
ArrayList<Derived> aliasNames = new ArrayList<>(Arrays.asList(deriveds));
derivedManaged.setAliasNames(aliasNames);
return derivedes;
}
private ArrayList<Derived> getCollectionTypeAttribute()
{
ArrayList<Derived> aliasNames = new ArrayList<Derived>(Arrays.asList(getArrayTypeAttribute()));
return aliasNames;
return deriveds;
}
@Test
public void testSetAttributesException()
{
// given
attributes = getAttributes("fnameee","charu");
AttributeList attributes = getAttributes("fnameee", "charu");
// when
attributes = objectMBean.setAttributes(attributes);
// then
// Original code eating the exception and returning zero size list
assertEquals(EMPTY,attributes.size(),"As there is no attribute with the name fnameee, this should return empty");
assertEquals(0, attributes.size(), "As there is no attribute with the name fnameee, this should return empty");
}
private AttributeList getAttributes(String name, String value)
{
Attribute attribute = new Attribute(name,value);
Attribute attribute = new Attribute(name, value);
AttributeList attributes = new AttributeList();
attributes.add(attribute);
return attributes;
}
@Test
public void testInvokeMBeanException() throws Exception
public void testInvokeMBeanException()
{
// given
setMBeanInfoForInvoke();
ReflectionException e = assertThrows(ReflectionException.class, () -> objectMBean.invoke("doodle2", new Object[0], new String[0]));
// when
MBeanException e = assertThrows(MBeanException.class, ()->{
objectMBean.invoke("doodle2",new Object[] {},new String[] {});
});
// then
assertNotNull(e, "An MBeanException must have occurred by now as doodle2() in Derived bean throwing exception");
assertNotNull(e, "An ReflectionException must have occurred by now as doodle2() in Derived bean is private");
}
@Test
public void testInvokeReflectionException() throws Exception
public void testInvokeReflectionException()
{
// given
setMBeanInfoForInvoke();
MBeanException e = assertThrows(MBeanException.class, () -> objectMBean.invoke("doodle1", new Object[0], new String[0]));
// when
ReflectionException e = assertThrows(ReflectionException.class, ()->{
objectMBean.invoke("doodle1",new Object[] {},new String[] {});
});
// then
assertNotNull(e, "ReflectionException is null");
assertNotNull(e, "MBeanException is null");
}
@Test
public void testInvoke() throws Exception
{
// given
setMBeanInfoForInvoke();
String value = (String)objectMBean.invoke("good", new Object[0], new String[0]);
// when
value = (String)objectMBean.invoke("good",new Object[] {},new String[] {});
// then
assertEquals("not bad", value, "Method(good) invocation on objectMBean must return not bad");
}
@Test
public void testInvokeNoSuchMethodException() throws Exception
public void testInvokeNoSuchMethodException()
{
// given
setMBeanInfoForInvoke();
// DerivedMBean contains a managed method with the name good,
// we must call this method without any arguments.
ReflectionException e = assertThrows(ReflectionException.class, () ->
objectMBean.invoke("good", new Object[0], new String[]{"int aone"}));
// when
// DerivedMBean contains a managed method with the name good,we must
// call this method without any arguments
ReflectionException e = assertThrows(ReflectionException.class, ()->{
objectMBean.invoke("good",new Object[] {},new String[]
{ "int aone" });
});
// then
assertNotNull(e, "An ReflectionException must have occurred by now as we cannot call a methow with wrong signature");
}
private void setMBeanInfoForInvoke()
{
objectMBean = (ObjectMBean)ObjectMBean.mbeanFor(derivedExtended);
container.beanAdded(null,derivedExtended);
objectMBean.getMBeanInfo();
}
@Test
public void testToVariableName()
public void testToAttributeName()
{
assertEquals("fullName",objectMBean.toVariableName("isfullName"));
assertEquals("fullName", MetaData.toAttributeName("isfullName"));
}
}

View File

@ -20,27 +20,25 @@ package org.eclipse.jetty.jmx;
import java.util.Arrays;
import java.util.List;
import org.eclipse.jetty.util.log.jmx.LogMBean;
import org.junit.jupiter.api.Test;
import com.openpojo.reflection.impl.PojoClassFactory;
import com.openpojo.validation.Validator;
import com.openpojo.validation.ValidatorBuilder;
import com.openpojo.validation.test.impl.GetterTester;
import com.openpojo.validation.test.impl.SetterTester;
import org.eclipse.jetty.util.log.jmx.LogMBean;
import org.junit.jupiter.api.Test;
/*
* This class tests all the getters and setters for a given list of classes.
*/
public class PojoTest
{
private Validator validator;
@Test
public void testOpenPojo()
{
validator = ValidatorBuilder.create().with(new SetterTester()).with(new GetterTester()).build();
List<Class> classes = Arrays.asList(MBeanContainer.class,ObjectMBean.class,LogMBean.class);
Validator validator = ValidatorBuilder.create().with(new SetterTester()).with(new GetterTester()).build();
List<Class> classes = Arrays.asList(MBeanContainer.class, ObjectMBean.class, LogMBean.class);
for (Class clazz : classes)
{
validator.validate(PojoClassFactory.getPojoClass(clazz));

View File

@ -1,2 +1,2 @@
org.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.StdErrLog
org.eclipse.jetty.jmx.LEVEL=INFO
#org.eclipse.jetty.jmx.LEVEL=DEBUG

View File

@ -185,6 +185,26 @@
<artifactId>jetty-server</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-servlet</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-client</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-http</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-io</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-jmx</artifactId>

View File

@ -10,6 +10,7 @@
<properties>
<jetty.version>@project.version@</jetty.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencyManagement>

View File

@ -57,6 +57,7 @@
<systemPropertyVariables>
<jetty.port.file>${jetty.port.file}</jetty.port.file>
<helloServlet>true</helloServlet>
<maven.it.name>${project.groupId}:${project.artifactId}</maven.it.name>
</systemPropertyVariables>
<dependenciesToScan>
<dependency>org.eclipse.jetty:jetty-maven-plugin</dependency>

View File

@ -43,6 +43,7 @@
<configuration>
<systemPropertyVariables>
<jetty.port.file>${jetty.port.file}</jetty.port.file>
<maven.it.name>${project.groupId}:${project.artifactId}</maven.it.name>
<contentCheck>Bean Validation Webapp example</contentCheck>
</systemPropertyVariables>
<dependenciesToScan>

View File

@ -0,0 +1,12 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>test.jetty-maven-plugin-provided-module-dep</groupId>
<artifactId>parent</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<artifactId>api</artifactId>
</project>

View File

@ -0,0 +1,28 @@
//
// ========================================================================
// Copyright (c) 1995-2018 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 test;
public class Api
{
public void noOp()
{
}
}

View File

@ -0,0 +1,2 @@
invoker.goals = verify -V -e
#test-compile failsafe:integration-test

View File

@ -0,0 +1,22 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.eclipse.jetty.its</groupId>
<artifactId>it-parent-pom</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<groupId>test.jetty-maven-plugin-provided-module-dep</groupId>
<artifactId>parent</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>pom</packaging>
<modules>
<module>api</module>
<module>web</module>
</modules>
</project>

View File

@ -0,0 +1,21 @@
/*
* 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.
*/
File buildLog = new File( basedir, 'build.log' )
assert buildLog.text.contains( 'Started Jetty Server' )
assert buildLog.text.contains( 'ClassNotFoundException')

View File

@ -0,0 +1,58 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>test.jetty-maven-plugin-provided-module-dep</groupId>
<artifactId>parent</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<artifactId>web</artifactId>
<packaging>war</packaging>
<dependencies>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>api</artifactId>
<version>${project.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<configuration>
<failOnMissingWebXml>false</failOnMissingWebXml>
</configuration>
</plugin>
</plugins>
</pluginManagement>
<plugins>
<plugin>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-maven-plugin</artifactId>
<executions>
<execution>
<id>start-jetty</id>
<phase>test-compile</phase>
<goals>
<goal>start</goal>
</goals>
<configuration>
<nonBlocking>true</nonBlocking>
<jettyXml>${basedir}/src/config/jetty.xml</jettyXml>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

View File

@ -0,0 +1,48 @@
<?xml version="1.0"?>
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
<Configure id="Server" class="org.eclipse.jetty.server.Server">
<New id="httpConfig" class="org.eclipse.jetty.server.HttpConfiguration">
<Set name="secureScheme">https</Set>
<Set name="securePort">
<Property name="jetty.secure.port" default="8443"/>
</Set>
<Set name="outputBufferSize">32768</Set>
<Set name="requestHeaderSize">8192</Set>
<Set name="responseHeaderSize">8192</Set>
<Set name="headerCacheSize">4096</Set>
</New>
<Call name="addConnector">
<Arg>
<New class="org.eclipse.jetty.server.ServerConnector">
<Arg name="server">
<Ref refid="Server"/>
</Arg>
<Arg name="factories">
<Array type="org.eclipse.jetty.server.ConnectionFactory">
<Item>
<New class="org.eclipse.jetty.server.HttpConnectionFactory">
<Arg name="config">
<Ref refid="httpConfig"/>
</Arg>
</New>
</Item>
</Array>
</Arg>
<Call name="addLifeCycleListener">
<Arg>
<New class="org.eclipse.jetty.maven.plugin.ServerConnectorListener">
</New>
</Arg>
</Call>
<Set name="host">
<Property name="jetty.host"/>
</Set>
<Set name="port"><Property name="jetty.port" default="0"/>0
</Set>
<Set name="idleTimeout">30000</Set>
</New>
</Arg>
</Call>
</Configure>

View File

@ -16,40 +16,34 @@
// ========================================================================
//
package org.eclipse.jetty.gcloud.session;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.runner.RunWith;
import org.junit.runners.Suite;
package test;
/**
* GCloudTestSuite
*
* Sets up the gcloud emulator once before running all tests.
*
*/
@RunWith(Suite.class)
@Suite.SuiteClasses({
GCloudSessionDataStoreTest.class,
InvalidationSessionTest.class,
ClusteredSessionScavengingTest.class,
ClusteredOrphanedSessionTest.class
})
public class GCloudTestSuite
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;
@WebListener
public class ClassLoadingTestingServletContextListener
implements ServletContextListener
{
public static GCloudSessionTestSupport __testSupport;
@BeforeAll
public static void setUp () throws Exception
@Override
public void contextInitialized( ServletContextEvent sce )
{
__testSupport = new GCloudSessionTestSupport();
__testSupport.setUp();
try
{
Api api = new Api();
}
catch ( java.lang.Exception exception )
{
exception.printStackTrace();
}
//System.out.println("Class " + api.getClass().getName() + " is available and loaded by classloader " + api.getClass().getClassLoader().toString() + ". Expected ClassNotFoundException.");
}
@AfterAll
public static void tearDown () throws Exception
@Override
public void contextDestroyed( ServletContextEvent sce )
{
__testSupport.tearDown();
}
}
}

View File

@ -70,6 +70,7 @@
<jetty.port.file>${jetty.port.file}</jetty.port.file>
<pingServlet>true</pingServlet>
<helloServlet>true</helloServlet>
<maven.it.name>${project.groupId}:${project.artifactId}</maven.it.name>
</systemPropertyVariables>
<dependenciesToScan>
<dependency>org.eclipse.jetty:jetty-maven-plugin</dependency>

View File

@ -70,6 +70,7 @@
<jetty.port.file>${jetty.port.file}</jetty.port.file>
<pingServlet>true</pingServlet>
<helloServlet>true</helloServlet>
<maven.it.name>${project.groupId}:${project.artifactId}</maven.it.name>
</systemPropertyVariables>
<dependenciesToScan>
<dependency>org.eclipse.jetty:jetty-maven-plugin</dependency>

View File

@ -73,6 +73,7 @@
<jetty.port.file>${jetty.port.file}</jetty.port.file>
<pingServlet>true</pingServlet>
<helloServlet>true</helloServlet>
<maven.it.name>${project.groupId}:${project.artifactId}</maven.it.name>
</systemPropertyVariables>
<dependenciesToScan>
<dependency>org.eclipse.jetty:jetty-maven-plugin</dependency>

View File

@ -71,6 +71,7 @@
<jetty.port.file>${jetty.port.file}</jetty.port.file>
<pingServlet>true</pingServlet>
<helloServlet>true</helloServlet>
<maven.it.name>${project.groupId}:${project.artifactId}</maven.it.name>
</systemPropertyVariables>
<dependenciesToScan>
<dependency>org.eclipse.jetty:jetty-maven-plugin</dependency>

View File

@ -71,6 +71,7 @@
<jetty.port.file>${jetty.port.file}</jetty.port.file>
<pingServlet>true</pingServlet>
<helloServlet>true</helloServlet>
<maven.it.name>${project.groupId}:${project.artifactId}</maven.it.name>
</systemPropertyVariables>
<dependenciesToScan>
<dependency>org.eclipse.jetty:jetty-maven-plugin</dependency>

View File

@ -69,6 +69,7 @@
<jetty.port.file>${jetty.port.file}</jetty.port.file>
<pingServlet>true</pingServlet>
<helloServlet>true</helloServlet>
<maven.it.name>${project.groupId}:${project.artifactId}</maven.it.name>
</systemPropertyVariables>
<dependenciesToScan>
<dependency>org.eclipse.jetty:jetty-maven-plugin</dependency>

View File

@ -74,6 +74,7 @@
<systemPropertyVariables>
<jetty.port.file>${jetty.port.file}</jetty.port.file>
<contentCheck>Please enter your name</contentCheck>
<maven.it.name>${project.groupId}:${project.artifactId}</maven.it.name>
</systemPropertyVariables>
<dependenciesToScan>
<dependency>org.eclipse.jetty:jetty-maven-plugin</dependency>

View File

@ -532,9 +532,14 @@ public class JettyRunMojo extends AbstractJettyMojo
{
// Include runtime and compile time libraries, and possibly test libs too
if(artifact.getType().equals("war"))
{
continue;
}
if (Artifact.SCOPE_PROVIDED.equals(artifact.getScope()))
continue; //never add dependencies of scope=provided to the webapp's classpath (see also <useProvidedScope> param)
if (Artifact.SCOPE_TEST.equals(artifact.getScope()) && !useTestScope)
continue; //only add dependencies of scope=test if explicitly required
MavenProject mavenProject = getProjectReference( artifact, project );
if (mavenProject != null)
{
@ -544,12 +549,6 @@ public class JettyRunMojo extends AbstractJettyMojo
continue;
}
if (Artifact.SCOPE_PROVIDED.equals(artifact.getScope()))
continue; //never add dependencies of scope=provided to the webapp's classpath (see also <useProvidedScope> param)
if (Artifact.SCOPE_TEST.equals(artifact.getScope()) && !useTestScope)
continue; //only add dependencies of scope=test if explicitly required
dependencyFiles.add(artifact.getFile());
getLog().debug( "Adding artifact " + artifact.getFile().getName() + " with scope "+artifact.getScope()+" for WEB-INF/lib " );
}

View File

@ -51,23 +51,24 @@ public class TestGetContent
if (Boolean.getBoolean( "helloServlet" ))
{
String response = httpClient.GET( "http://localhost:" + port + "/hello?name=beer" ).getContentAsString();
assertEquals( "Hello beer", response.trim() );
assertEquals( "Hello beer", response.trim(), "it test " + System.getProperty( "maven.it.name" ) );
response = httpClient.GET( "http://localhost:" + port + "/hello?name=foo" ).getContentAsString();
assertEquals( "Hello foo", response.trim() );
assertEquals( "Hello foo", response.trim(), "it test " + System.getProperty( "maven.it.name" ) );
System.out.println( "helloServlet" );
}
if (Boolean.getBoolean( "pingServlet" ))
{
System.out.println( "pingServlet ok" );
String response = httpClient.GET( "http://localhost:" + port + "/ping?name=beer" ).getContentAsString();
assertEquals( "pong beer", response.trim() );
System.out.println( "pingServlet" );
String response = httpClient.GET( "http://localhost:" + port + "/ping?name=beer" ).getContentAsString();
assertEquals( "pong beer", response.trim(), "it test " + System.getProperty( "maven.it.name" ) );
System.out.println( "pingServlet ok" );
}
String contentCheck = System.getProperty( "contentCheck" );
if(StringUtils.isNotBlank( contentCheck ) )
{
String response = httpClient.GET( "http://localhost:" + port ).getContentAsString();
assertTrue(response.contains(contentCheck), "response not contentCheck: " + contentCheck + ", response:" + response);
assertTrue(response.contains(contentCheck), "it test " + System.getProperty( "maven.it.name" )
+ ", response not contentCheck: " + contentCheck + ", response:" + response);
System.out.println( "contentCheck" );
}
}

View File

@ -45,12 +45,15 @@
<artifactId>pax-exam-junit4</artifactId>
<version>${exam.version}</version>
<scope>test</scope>
<!-- not anymore as others tests use junit 5 -->
<!--
<exclusions>
<exclusion>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</exclusion>
</exclusions>
-->
</dependency>
<dependency>
<groupId>org.ops4j.pax.exam</groupId>

View File

@ -51,6 +51,7 @@ import org.eclipse.jetty.security.authentication.FormAuthenticator;
import org.eclipse.jetty.servlet.ErrorPageErrorHandler;
import org.eclipse.jetty.servlet.FilterHolder;
import org.eclipse.jetty.servlet.FilterMapping;
import org.eclipse.jetty.servlet.ListenerHolder;
import org.eclipse.jetty.servlet.ServletContextHandler.JspConfig;
import org.eclipse.jetty.servlet.ServletHandler;
import org.eclipse.jetty.servlet.ServletHolder;
@ -176,10 +177,10 @@ public class QuickStartDescriptorGenerator
.tag("param-value",_webApp.getInitParameter(p))
.closeTag();
if (_webApp.getEventListeners() != null)
for (EventListener e : _webApp.getEventListeners())
out.openTag("listener",origin(md,e.getClass().getCanonicalName() + ".listener"))
.tag("listener-class",e.getClass().getCanonicalName())
if (_webApp.getServletHandler().getListeners() != null)
for (ListenerHolder e : _webApp.getServletHandler().getListeners())
out.openTag("listener",origin(md,e.getClassName() + ".listener"))
.tag("listener-class",e.getClassName())
.closeTag();
ServletHandler servlets = _webApp.getServletHandler();

View File

@ -24,6 +24,7 @@ import static org.junit.jupiter.api.Assertions.*;
import java.io.File;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.servlet.ListenerHolder;
import org.eclipse.jetty.servlet.ServletHolder;
import org.eclipse.jetty.toolchain.test.FS;
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
@ -69,8 +70,10 @@ public class TestQuickStart
ServletHolder fooHolder = new ServletHolder();
fooHolder.setServlet(new FooServlet());
fooHolder.setName("foo");
quickstart.getServletHandler().addServlet(fooHolder);
quickstart.addEventListener(new FooContextListener());
quickstart.getServletHandler().addServlet(fooHolder);
ListenerHolder lholder = new ListenerHolder();
lholder.setListener(new FooContextListener());
quickstart.getServletHandler().addListener(lholder);
server.setHandler(quickstart);
server.start();
server.stop();

View File

@ -42,7 +42,7 @@ import java.io.StringReader;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.fail;
import static org.junit.jupiter.api.Assertions.fail;
public class CookiePatternRuleTest

View File

@ -226,7 +226,7 @@ public abstract class AbstractConnector extends ContainerLifeCycle implements Co
}
@Override
@ManagedAttribute("Idle timeout")
@ManagedAttribute("The connection idle timeout in milliseconds")
public long getIdleTimeout()
{
return _idleTimeout;

View File

@ -21,12 +21,12 @@ package org.eclipse.jetty.server.handler;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URL;
import java.net.URLClassLoader;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
@ -2585,35 +2585,25 @@ public class ContextHandler extends ScopedHandler implements Attributes, Gracefu
// no security manager just return the classloader
if (!_usingSecurityManager)
{
return _classLoader;
}
else
{
// check to see if the classloader of the caller is the same as the context
// classloader, or a parent of it
try
// classloader, or a parent of it, as required by the javadoc specification.
// Wrap in a PrivilegedAction so that only Jetty code will require the
// "createSecurityManager" permission, not also application code that calls this method.
Caller caller = AccessController.doPrivileged((PrivilegedAction<Caller>)Caller::new);
ClassLoader callerLoader = caller.getCallerClassLoader(2);
while (callerLoader != null)
{
Class<?> reflect = Loader.loadClass("sun.reflect.Reflection");
Method getCallerClass = reflect.getMethod("getCallerClass",Integer.TYPE);
Class<?> caller = (Class<?>)getCallerClass.invoke(null,2);
boolean ok = false;
ClassLoader callerLoader = caller.getClassLoader();
while (!ok && callerLoader != null)
{
if (callerLoader == _classLoader)
ok = true;
else
callerLoader = callerLoader.getParent();
}
if (ok)
if (callerLoader == _classLoader)
return _classLoader;
else
callerLoader = callerLoader.getParent();
}
catch (Exception e)
{
LOG.warn("Unable to check classloader of caller",e);
}
AccessController.checkPermission(new RuntimePermission("getClassLoader"));
return _classLoader;
}
@ -3083,4 +3073,17 @@ public class ContextHandler extends ScopedHandler implements Attributes, Gracefu
*/
void exitScope(Context context, Request request);
}
private static class Caller extends SecurityManager
{
public ClassLoader getCallerClassLoader(int depth)
{
if (depth < 0)
return null;
Class<?>[] classContext = getClassContext();
if (classContext.length <= depth)
return null;
return classContext[depth].getClassLoader();
}
}
}

View File

@ -32,12 +32,7 @@ import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.eclipse.jetty.http.CompressedContentFormat;
import org.eclipse.jetty.http.HttpField;
import org.eclipse.jetty.http.HttpHeader;
import org.eclipse.jetty.http.HttpMethod;
import org.eclipse.jetty.http.MimeTypes;
import org.eclipse.jetty.http.PreEncodedHttpField;
import org.eclipse.jetty.http.*;
import org.eclipse.jetty.http.pathmap.PathSpecSet;
import org.eclipse.jetty.server.DeflaterPool;
import org.eclipse.jetty.server.HttpOutput;
@ -156,6 +151,7 @@ public class GzipHandler extends HandlerWrapper implements GzipFactory
public static final int DEFAULT_MIN_GZIP_SIZE=16;
private static final Logger LOG = Log.getLogger(GzipHandler.class);
private static final HttpField X_CE_GZIP = new PreEncodedHttpField("X-Content-Encoding","gzip");
private static final HttpField TE_CHUNKED = new PreEncodedHttpField(HttpHeader.TRANSFER_ENCODING, HttpHeaderValue.CHUNKED.asString());
private static final Pattern COMMA_GZIP = Pattern.compile(".*, *gzip");
private int POOL_CAPACITY = -1;
@ -622,29 +618,46 @@ public class GzipHandler extends HandlerWrapper implements GzipFactory
// Handle request inflation
if (_inflateBufferSize>0)
{
boolean inflate = false;
for (ListIterator<HttpField> i = baseRequest.getHttpFields().listIterator(); i.hasNext();)
{
HttpField field = i.next();
if (field.getHeader()!=HttpHeader.CONTENT_ENCODING)
continue;
if (field.getValue().equalsIgnoreCase("gzip"))
if (field.getHeader()==HttpHeader.CONTENT_ENCODING)
{
i.set(X_CE_GZIP);
baseRequest.getHttpInput().addInterceptor(new GzipHttpInputInterceptor(baseRequest.getHttpChannel().getByteBufferPool(),_inflateBufferSize));
break;
}
if (field.getValue().equalsIgnoreCase("gzip"))
{
i.set(X_CE_GZIP);
inflate = true;
break;
}
if (COMMA_GZIP.matcher(field.getValue()).matches())
{
String v = field.getValue();
v = v.substring(0,v.lastIndexOf(','));
i.set(new HttpField(HttpHeader.CONTENT_ENCODING,v));
i.add(X_CE_GZIP);
baseRequest.getHttpInput().addInterceptor(new GzipHttpInputInterceptor(baseRequest.getHttpChannel().getByteBufferPool(),_inflateBufferSize));
break;
if (COMMA_GZIP.matcher(field.getValue()).matches())
{
String v = field.getValue();
v = v.substring(0, v.lastIndexOf(','));
i.set(new HttpField(HttpHeader.CONTENT_ENCODING, v));
i.add(X_CE_GZIP);
inflate = true;
break;
}
}
}
}
if (inflate)
{
baseRequest.getHttpInput().addInterceptor(new GzipHttpInputInterceptor(baseRequest.getHttpChannel().getByteBufferPool(), _inflateBufferSize));
for (ListIterator<HttpField> i = baseRequest.getHttpFields().listIterator(); i.hasNext();)
{
HttpField field = i.next();
if (field.getHeader()==HttpHeader.CONTENT_LENGTH)
{
i.set(new HttpField("X-Content-Length", field.getValue()));
break;
}
}
}
}
// Are we already being gzipped?

View File

@ -27,7 +27,6 @@ import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import java.io.IOException;
import java.io.InputStream;
import java.net.Socket;
@ -38,7 +37,8 @@ import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import static org.junit.Assert.*;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.jupiter.api.Assertions.*;
public class CustomResourcesMonitorTest
{
@ -111,28 +111,14 @@ public class CustomResourcesMonitorTest
InputStream input1 = socket1.getInputStream();
assertTrue(_fileOnDirectoryMonitor.isLowOnResources());
try
{
input1.read();
fail();
}
catch (SocketTimeoutException expected)
{
}
assertThrows(SocketTimeoutException.class, () -> input1.read());
// Wait a couple of lowResources idleTimeouts.
Thread.sleep(2 * lowResourcesIdleTimeout);
// Verify the new socket is still open.
assertTrue(_fileOnDirectoryMonitor.isLowOnResources());
try
{
input1.read();
fail();
}
catch (SocketTimeoutException expected)
{
}
assertThrows(SocketTimeoutException.class, () -> input1.read());
Files.delete( tmpFile );

View File

@ -23,6 +23,7 @@ import org.eclipse.jetty.util.thread.QueuedThreadPool;
import org.eclipse.jetty.util.thread.TimerScheduler;
import org.hamcrest.Matchers;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
@ -38,7 +39,6 @@ import java.util.concurrent.CountDownLatch;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.not;
import static org.junit.Assert.fail;
import static org.junit.jupiter.api.Assertions.*;
public class LowResourcesMonitorTest
@ -248,28 +248,15 @@ public class LowResourcesMonitorTest
InputStream input1 = socket1.getInputStream();
assertTrue(_lowResourcesMonitor.isLowOnResources());
try
{
input1.read();
fail();
}
catch (SocketTimeoutException expected)
{
}
assertThrows( SocketTimeoutException.class, () -> input1.read());
// Wait a couple of lowResources idleTimeouts.
Thread.sleep(2 * lowResourcesIdleTimeout);
// Verify the new socket is still open.
assertTrue(_lowResourcesMonitor.isLowOnResources());
try
{
input1.read();
fail();
}
catch (SocketTimeoutException expected)
{
}
assertThrows( SocketTimeoutException.class, () -> input1.read());
// Let the maxLowResourcesTime elapse.
Thread.sleep(maxLowResourcesTime);

View File

@ -21,54 +21,112 @@ package org.eclipse.jetty.servlet;
import java.util.EventListener;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
/**
* ListenerHolder
*
* Specialization of AbstractHolder for servlet listeners. This
* Specialization of BaseHolder for servlet listeners. This
* allows us to record where the listener originated - web.xml,
* annotation, api etc.
*/
public class ListenerHolder extends BaseHolder<EventListener>
{
private EventListener _listener;
private boolean _initialized = false;
public ListenerHolder ()
{
this (Source.EMBEDDED);
}
public ListenerHolder(Source source)
{
super(source);
}
public void setListener(EventListener listener)
{
_listener = listener;
setClassName(listener.getClass().getName());
setHeldClass(listener.getClass());
_extInstance=true;
}
public EventListener getListener()
{
return _listener;
}
/**
* Set an explicit instance. In this case,
* just like ServletHolder and FilterHolder,
* the listener will not be introspected for
* annotations like Resource etc.
*
* @param listener
*/
public void setListener (EventListener listener)
{
_listener = listener;
_extInstance=true;
setHeldClass(_listener.getClass());
setClassName(_listener.getClass().getName());
}
public void initialize (ServletContext context) throws Exception
{
if (!_initialized)
{
initialize();
if (_listener == null)
{
//create an instance of the listener and decorate it
try
{
_listener = (context instanceof ServletContextHandler.Context)
?((ServletContextHandler.Context)context).createListener(getHeldClass())
:getHeldClass().getDeclaredConstructor().newInstance();
}
catch (ServletException se)
{
Throwable cause = se.getRootCause();
if (cause instanceof InstantiationException)
throw (InstantiationException)cause;
if (cause instanceof IllegalAccessException)
throw (IllegalAccessException)cause;
throw se;
}
}
_initialized = true;
}
}
@Override
public void doStart() throws Exception
{
//Listeners always have an instance eagerly created, it cannot be deferred to the doStart method
if (_listener == null)
throw new IllegalStateException("No listener instance");
super.doStart();
if (!java.util.EventListener.class.isAssignableFrom(_class))
{
String msg = _class+" is not a java.util.EventListener";
super.stop();
throw new IllegalStateException(msg);
}
}
@Override
public void doStop() throws Exception
{
super.doStop();
if (!_extInstance)
_listener = null;
_initialized = false;
}
@Override
public String toString()
{
return super.toString()+(_listener == null?"":": "+getClassName());
}
return super.toString()+": "+getClassName();
}
}

View File

@ -356,13 +356,16 @@ public class ServletContextHandler extends ContextHandler
if (_servletHandler != null)
{
// Call decorators on all holders, and also on any EventListeners before
// decorators are called on any other classes (like servlets and filters)
//Ensure listener instances are created, added to ContextHandler
if(_servletHandler.getListeners() != null)
{
for (ListenerHolder holder:_servletHandler.getListeners())
{
_objFactory.decorate(holder.getListener());
holder.start();
//we need to pass in the context because the ServletHandler has not
//yet got a reference to the ServletContext (happens in super.startContext)
holder.initialize(_scontext);
addEventListener(holder.getListener());
}
}
}

View File

@ -31,6 +31,7 @@ import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.eclipse.jetty.http.BadMessageException;
import org.eclipse.jetty.server.Dispatcher;
import org.eclipse.jetty.server.HttpChannel;
import org.eclipse.jetty.server.LocalConnector;
@ -63,11 +64,13 @@ public class ErrorPageTest
context.addServlet(FailServlet.class, "/fail/*");
context.addServlet(FailClosedServlet.class, "/fail-closed/*");
context.addServlet(ErrorServlet.class, "/error/*");
context.addServlet(AppServlet.class, "/app/*");
ErrorPageErrorHandler error = new ErrorPageErrorHandler();
context.setErrorHandler(error);
error.addErrorPage(599,"/error/599");
error.addErrorPage(IllegalStateException.class.getCanonicalName(),"/error/TestException");
error.addErrorPage(BadMessageException.class,"/error/TestException");
error.addErrorPage(ErrorPageErrorHandler.GLOBAL_ERROR_PAGE,"/error/GlobalErrorPage");
_server.start();
@ -157,6 +160,33 @@ public class ErrorPageTest
}
}
@Test
public void testBadMessage() throws Exception
{
String response = _connector.getResponse("GET /app?baa=%88%A4 HTTP/1.0\r\n\r\n");
assertThat(response, Matchers.containsString("HTTP/1.1 400 Unable to parse URI query"));
assertThat(response, Matchers.containsString("ERROR_PAGE: /TestException"));
assertThat(response, Matchers.containsString("ERROR_MESSAGE: Unable to parse URI query"));
assertThat(response, Matchers.containsString("ERROR_CODE: 400"));
assertThat(response, Matchers.containsString("ERROR_EXCEPTION: org.eclipse.jetty.http.BadMessageException: 400: Unable to parse URI query"));
assertThat(response, Matchers.containsString("ERROR_EXCEPTION_TYPE: class org.eclipse.jetty.http.BadMessageException"));
assertThat(response, Matchers.containsString("ERROR_SERVLET: org.eclipse.jetty.servlet.ErrorPageTest$AppServlet-"));
assertThat(response, Matchers.containsString("ERROR_REQUEST_URI: /app"));
assertThat(response, Matchers.containsString("getParameterMap()= {}"));
}
public static class AppServlet extends HttpServlet implements Servlet
{
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
PrintWriter writer = response.getWriter();
writer.println(request.getRequestURI());
writer.println(request.getParameterMap().toString());
}
}
public static class FailServlet extends HttpServlet implements Servlet
{
@Override
@ -202,6 +232,7 @@ public class ErrorPageTest
writer.println("ERROR_EXCEPTION_TYPE: " + request.getAttribute(Dispatcher.ERROR_EXCEPTION_TYPE));
writer.println("ERROR_SERVLET: " + request.getAttribute(Dispatcher.ERROR_SERVLET_NAME));
writer.println("ERROR_REQUEST_URI: " + request.getAttribute(Dispatcher.ERROR_REQUEST_URI));
writer.println("getParameterMap()= " + request.getParameterMap());
}
}

View File

@ -18,32 +18,6 @@
package org.eclipse.jetty.servlet;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.equalToIgnoringCase;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.not;
import static org.hamcrest.Matchers.nullValue;
import static org.junit.jupiter.api.Assertions.assertEquals;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.eclipse.jetty.http.HttpTester;
import org.eclipse.jetty.server.LocalConnector;
import org.eclipse.jetty.server.Server;
@ -54,6 +28,33 @@ import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import javax.servlet.DispatcherType;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.EnumSet;
import java.util.Enumeration;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.*;
import static org.junit.jupiter.api.Assertions.assertEquals;
@SuppressWarnings("serial")
public class GzipHandlerTest
{
@ -104,6 +105,7 @@ public class GzipHandlerTest
servlets.addServletWithMapping(IncludeServlet.class,"/include");
servlets.addServletWithMapping(EchoServlet.class,"/echo/*");
servlets.addServletWithMapping(DumpServlet.class,"/dump/*");
servlets.addFilterWithMapping(CheckFilter.class,"/*", EnumSet.of(DispatcherType.REQUEST));
_server.start();
}
@ -508,6 +510,38 @@ public class GzipHandlerTest
assertThat(response.getContent(),is(data));
}
@Test
public void testGzipRequestChunked() throws Exception
{
String data = "Hello Nice World! ";
for (int i = 0; i < 10; ++i)
data += data;
ByteArrayOutputStream baos = new ByteArrayOutputStream();
GZIPOutputStream output = new GZIPOutputStream(baos);
output.write(data.getBytes(StandardCharsets.UTF_8));
output.close();
byte[] bytes = baos.toByteArray();
// generated and parsed test
HttpTester.Request request = HttpTester.newRequest();
HttpTester.Response response;
request.setMethod("POST");
request.setURI("/ctx/echo");
request.setVersion("HTTP/1.1");
request.setHeader("Host","tester");
request.setHeader("Content-Type","text/plain");
request.setHeader("Content-Encoding","gzip");
request.add("Transfer-Encoding", "chunked");
request.setContent(bytes);
response = HttpTester.parseResponse(_connector.getResponse(request.generate()));
assertThat(response.getStatus(),is(200));
assertThat(response.getContent(),is(data));
}
@Test
@ -568,5 +602,27 @@ public class GzipHandlerTest
assertThat(response.getStatus(),is(200));
assertThat(response.getContentBytes().length,is(512*1024));
}
public static class CheckFilter implements Filter
{
@Override
public void init(FilterConfig filterConfig) throws ServletException
{
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException
{
if (request.getParameter("X-Content-Encoding")!=null)
assertEquals(-1,request.getContentLength());
else if (request.getContentLength()>=0)
assertThat(request.getParameter("X-Content-Encoding"),Matchers.nullValue());
chain.doFilter(request,response);
}
@Override
public void destroy()
{
}
}
}

View File

@ -21,10 +21,10 @@ package org.eclipse.jetty.util;
import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assume.assumeTrue;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assumptions.assumeTrue;
import java.nio.file.Path;
import java.nio.file.Paths;

View File

@ -24,7 +24,8 @@ import org.hamcrest.Matchers;
import org.junit.jupiter.api.Test;
import static org.hamcrest.Matchers.equalTo;
import static org.junit.Assert.assertThat;
import static org.hamcrest.MatcherAssert.assertThat;
/* ------------------------------------------------------------ */

View File

@ -1911,17 +1911,11 @@ public class StandardDescriptorProcessor extends IterativeDescriptorProcessor
}
((WebDescriptor)descriptor).addClassName(className);
Class<? extends EventListener> listenerClass = (Class<? extends EventListener>)context.loadClass(className);
listener = newListenerInstance(context,listenerClass, descriptor);
if (!(listener instanceof EventListener))
{
LOG.warn("Not an EventListener: " + listener);
return;
}
context.addEventListener(listener);
ListenerHolder h = context.getServletHandler().newListenerHolder(new Source (Source.Origin.DESCRIPTOR, descriptor.getResource().toString()));
h.setClassName(className);
context.getServletHandler().addListener(h);
context.getMetaData().setOrigin(className+".listener", descriptor);
}
}
catch (Exception e)
@ -1960,14 +1954,4 @@ public class StandardDescriptorProcessor extends IterativeDescriptorProcessor
((ConstraintAware)context.getSecurityHandler()).setDenyUncoveredHttpMethods(true);
}
public EventListener newListenerInstance(WebAppContext context,Class<? extends EventListener> clazz, Descriptor descriptor) throws Exception
{
ListenerHolder h = context.getServletHandler().newListenerHolder(new Source (Source.Origin.DESCRIPTOR, descriptor.getResource().toString()));
EventListener l = context.getServletContext().createInstance(clazz);
h.setListener(l);
context.getServletHandler().addListener(h);
return l;
}
}

View File

@ -415,6 +415,8 @@ public class WebSocketUpgradeRequest extends HttpRequest implements CompleteList
this.localEndpoint = this.wsClient.getEventDriverFactory().wrap(localEndpoint);
this.fut = new CompletableFuture<Session>();
getConversation().setAttribute(HttpConnectionUpgrader.class.getName(), this);
}
private final String genRandomKey()
@ -504,7 +506,7 @@ public class WebSocketUpgradeRequest extends HttpRequest implements CompleteList
}
Throwable failure = result.getFailure();
if ((failure instanceof java.net.ConnectException) || (failure instanceof UpgradeException))
if ((failure instanceof java.io.IOException) || (failure instanceof UpgradeException))
{
// handle as-is
handleException(failure);
@ -519,7 +521,7 @@ public class WebSocketUpgradeRequest extends HttpRequest implements CompleteList
if (responseStatusCode != HttpStatus.SWITCHING_PROTOCOLS_101)
{
// Failed to upgrade (other reason)
handleException(new UpgradeException(requestURI,responseStatusCode,responseLine));
handleException(new UpgradeException(requestURI,responseStatusCode,"Failed to upgrade to websocket: Unexpected HTTP Response Status Code: " + responseLine));
}
}

View File

@ -620,7 +620,7 @@ public class WebSocketSession extends ContainerLifeCycle implements Session, Rem
if (LOG.isDebugEnabled())
{
LOG.debug("open -> {}",dump());
LOG.debug("[{}] open -> {}",getPolicy().getBehavior(),dump());
}
if(openFuture != null)

View File

@ -64,6 +64,7 @@ public class BlockheadClientRequest extends HttpRequest implements Response.Comp
super(client, new HttpConversation(), uri);
this.client = client;
this.fut = new CompletableFuture<>();
getConversation().setAttribute(HttpConnectionUpgrader.class.getName(), this);
}
public void setInitialBytes(ByteBuffer initialBytes)

View File

@ -0,0 +1,155 @@
//
// ========================================================================
// Copyright (c) 1995-2018 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.websocket.server;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.notNullValue;
import java.net.URI;
import java.util.concurrent.Future;
import org.eclipse.jetty.client.HttpClient;
import org.eclipse.jetty.http.HttpVersion;
import org.eclipse.jetty.server.HttpConfiguration;
import org.eclipse.jetty.server.HttpConnectionFactory;
import org.eclipse.jetty.server.SecureRequestCustomizer;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.ServerConnector;
import org.eclipse.jetty.server.SslConnectionFactory;
import org.eclipse.jetty.server.handler.DefaultHandler;
import org.eclipse.jetty.server.handler.HandlerList;
import org.eclipse.jetty.server.handler.SecuredRedirectHandler;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
import org.eclipse.jetty.util.ssl.SslContextFactory;
import org.eclipse.jetty.websocket.api.Session;
import org.eclipse.jetty.websocket.api.annotations.WebSocket;
import org.eclipse.jetty.websocket.client.ClientUpgradeRequest;
import org.eclipse.jetty.websocket.client.WebSocketClient;
import org.eclipse.jetty.websocket.server.helper.EchoServlet;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
public class RedirectWebSocketClientTest
{
public static Server server;
public static URI serverWsUri;
public static URI serverWssUri;
@BeforeAll
public static void startServer() throws Exception
{
server = new Server();
HttpConfiguration http_config = new HttpConfiguration();
http_config.setSecureScheme("https");
http_config.setSecurePort(0);
http_config.setOutputBufferSize(32768);
http_config.setRequestHeaderSize(8192);
http_config.setResponseHeaderSize(8192);
http_config.setSendServerVersion(true);
http_config.setSendDateHeader(false);
SslContextFactory sslContextFactory = newSslContextFactory();
// SSL HTTP Configuration
HttpConfiguration https_config = new HttpConfiguration(http_config);
https_config.addCustomizer(new SecureRequestCustomizer());
// SSL Connector
ServerConnector sslConnector = new ServerConnector(server, new SslConnectionFactory(sslContextFactory, HttpVersion.HTTP_1_1.asString()), new HttpConnectionFactory(https_config));
sslConnector.setPort(0);
server.addConnector(sslConnector);
// Normal Connector
ServerConnector connector = new ServerConnector(server);
connector.setPort(0);
server.addConnector(connector);
ServletContextHandler contextHandler = new ServletContextHandler();
contextHandler.setContextPath("/");
contextHandler.addServlet(EchoServlet.class, "/echo");
HandlerList handlers = new HandlerList();
handlers.addHandler(new SecuredRedirectHandler());
handlers.addHandler(contextHandler);
handlers.addHandler(new DefaultHandler());
server.setHandler(handlers);
server.start();
serverWsUri = URI.create("ws://localhost:" + connector.getLocalPort() + "/");
serverWssUri = URI.create("wss://localhost:" + sslConnector.getLocalPort() + "/");
// adjust HttpConfiguration in connector
HttpConnectionFactory connectionFactory = connector.getConnectionFactory(HttpConnectionFactory.class);
connectionFactory.getHttpConfiguration().setSecurePort(sslConnector.getLocalPort());
}
@AfterAll
public static void stopServer() throws Exception
{
server.stop();
}
private static SslContextFactory newSslContextFactory()
{
SslContextFactory ssl = new SslContextFactory();
ssl.setKeyStorePath(MavenTestingUtils.getTestResourceFile("keystore").getAbsolutePath());
ssl.setKeyStorePassword("storepwd");
ssl.setKeyManagerPassword("keypwd");
return ssl;
}
@Test
public void testRedirect() throws Exception
{
SslContextFactory ssl = newSslContextFactory();
ssl.setTrustAll(false);
ssl.setEndpointIdentificationAlgorithm(null);
HttpClient httpClient = new HttpClient(ssl);
WebSocketClient client = new WebSocketClient(httpClient);
client.addBean(httpClient, true);
client.start();
try
{
URI wsUri = serverWsUri.resolve("/echo");
ClientUpgradeRequest request = new ClientUpgradeRequest();
Future<Session> sessionFuture = client.connect(new EmptyWebSocket(), wsUri, request);
Session session = sessionFuture.get();
assertThat(session, is(notNullValue()));
}
finally
{
client.stop();
}
}
@WebSocket
public static class EmptyWebSocket {
}
}

128
pom.xml
View File

@ -37,6 +37,8 @@
<weld.version>2.4.5.Final</weld.version>
<jetty.perf-helper.version>1.0.5</jetty.perf-helper.version>
<unix.socket.tmp></unix.socket.tmp>
<!-- enable or not TestTracker junit5 extension i.e log message when test method is starting -->
<jetty.testtracker.log>false</jetty.testtracker.log>
<!-- some maven plugins versions -->
<maven.surefire.version>2.22.0</maven.surefire.version>
@ -49,7 +51,7 @@
<!-- testing -->
<jetty.test.version>5.0</jetty.test.version>
<jetty.test.version>5.1</jetty.test.version>
</properties>
<licenses>
@ -647,6 +649,8 @@
<systemPropertyVariables>
<java.io.tmpdir>${project.build.directory}</java.io.tmpdir>
<unix.socket.tmp>${unix.socket.tmp}</unix.socket.tmp>
<junit.jupiter.extensions.autodetection.enabled>true</junit.jupiter.extensions.autodetection.enabled>
<jetty.testtracker.log>${jetty.testtracker.log}</jetty.testtracker.log>
</systemPropertyVariables>
</configuration>
</plugin>
@ -1801,6 +1805,69 @@
</plugins>
</build>
</profile>
<profile>
<id>snapshot-repositories</id>
<activation>
<activeByDefault>false</activeByDefault>
</activation>
<repositories>
<repository>
<id>jetty-snapshots</id>
<name>jetty-snapshots</name>
<url>http://oss.sonatype.org/content/repositories/jetty-snapshots</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
<repository>
<id>apache.snapshots</id>
<url>https://repository.apache.org/content/repositories/snapshots</url>
<releases>
<enabled>false</enabled>
</releases>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
<repository>
<id>oss.snapshots</id>
<name>OSS Snapshots</name>
<url>https://oss.sonatype.org/content/repositories/snapshots</url>
<releases>
<enabled>false</enabled>
</releases>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
<repository>
<id>jetty.snapshots</id>
<name>Jetty Snapshots</name>
<url>https://oss.sonatype.org/content/repositories/jetty-snapshots</url>
<releases>
<enabled>false</enabled>
</releases>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
</repositories>
</profile>
<profile>
<id>cbi-repository</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<pluginRepositories>
<pluginRepository>
<id>cbi-releases</id>
<url>https://repo.eclipse.org/content/repositories/cbi-releases/</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</pluginRepository>
</pluginRepositories>
</profile>
</profiles>
<issueManagement>
@ -1898,65 +1965,6 @@
<url>https://webtide.com</url>
</organization>
<!-- SNAPSHOT Repository is only for temporary usage.
This configuration should not be checked in, as it
can result in bad success on CI. -->
<!--
<repositories>
<repository>
<id>jetty-snapshots</id>
<name>jetty-snapshots</name>
<url>http://oss.sonatype.org/content/repositories/jetty-snapshots</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
</repositories>
-->
<repositories>
<repository>
<id>apache.snapshots</id>
<url>https://repository.apache.org/content/repositories/snapshots</url>
<releases>
<enabled>false</enabled>
</releases>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
<repository>
<id>oss.snapshots</id>
<name>OSS Snapshots</name>
<url>https://oss.sonatype.org/content/repositories/snapshots</url>
<releases>
<enabled>false</enabled>
</releases>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
<repository>
<id>jetty.snapshots</id>
<name>Jetty Snapshots</name>
<url>https://oss.sonatype.org/content/repositories/jetty-snapshots</url>
<releases>
<enabled>false</enabled>
</releases>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>cbi-releases</id>
<url>https://repo.eclipse.org/content/repositories/cbi-releases/</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</pluginRepository>
</pluginRepositories>
<distributionManagement>
<repository>
<id>oss.sonatype.org</id>

View File

@ -258,7 +258,7 @@ public class JettyDistro
*/
public JettyDistro(Class<?> clazz, String artifact) throws IOException
{
this.jettyHomeDir = MavenTestingUtils.getTargetTestingDir(clazz,"jettyHome");
this.jettyHomeDir = MavenTestingUtils.getTargetTestingPath(clazz,"jettyHome").toFile();
if (artifact != null)
{
this.artifactName = artifact;

View File

@ -22,6 +22,7 @@ package org.eclipse.jetty.gcloud.session;
import org.eclipse.jetty.server.session.AbstractClusteredOrphanedSessionTest;
import org.eclipse.jetty.server.session.SessionDataStoreFactory;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
/**
@ -32,10 +33,25 @@ import org.junit.jupiter.api.Test;
public class ClusteredOrphanedSessionTest extends AbstractClusteredOrphanedSessionTest
{
public static GCloudSessionTestSupport __testSupport;
@BeforeAll
public static void setUp () throws Exception
{
__testSupport = new GCloudSessionTestSupport();
__testSupport.setUp();
}
@AfterAll
public static void tearDown () throws Exception
{
__testSupport.tearDown();
}
@AfterAll
public static void teardown () throws Exception
{
GCloudTestSuite.__testSupport.deleteSessions();
__testSupport.deleteSessions();
}
@ -46,7 +62,7 @@ public class ClusteredOrphanedSessionTest extends AbstractClusteredOrphanedSessi
@Override
public SessionDataStoreFactory createSessionDataStoreFactory()
{
return GCloudSessionTestSupport.newSessionDataStoreFactory(GCloudTestSuite.__testSupport.getDatastore());
return GCloudSessionTestSupport.newSessionDataStoreFactory(__testSupport.getDatastore());
}

View File

@ -22,6 +22,7 @@ package org.eclipse.jetty.gcloud.session;
import org.eclipse.jetty.server.session.AbstractClusteredSessionScavengingTest;
import org.eclipse.jetty.server.session.SessionDataStoreFactory;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
/**
* ClusteredSessionScavengingTest
@ -30,11 +31,26 @@ import org.junit.jupiter.api.AfterAll;
*/
public class ClusteredSessionScavengingTest extends AbstractClusteredSessionScavengingTest
{
public static GCloudSessionTestSupport __testSupport;
@BeforeAll
public static void setUp () throws Exception
{
__testSupport = new GCloudSessionTestSupport();
__testSupport.setUp();
}
@AfterAll
public static void tearDown () throws Exception
{
__testSupport.tearDown();
}
@AfterAll
public static void teardown () throws Exception
{
GCloudTestSuite.__testSupport.deleteSessions();
__testSupport.deleteSessions();
}
@ -44,7 +60,7 @@ public class ClusteredSessionScavengingTest extends AbstractClusteredSessionScav
@Override
public SessionDataStoreFactory createSessionDataStoreFactory()
{
return GCloudSessionTestSupport.newSessionDataStoreFactory(GCloudTestSuite.__testSupport.getDatastore());
return GCloudSessionTestSupport.newSessionDataStoreFactory(__testSupport.getDatastore());
}

View File

@ -22,7 +22,9 @@ package org.eclipse.jetty.gcloud.session;
import org.eclipse.jetty.server.session.AbstractSessionDataStoreTest;
import org.eclipse.jetty.server.session.SessionData;
import org.eclipse.jetty.server.session.SessionDataStoreFactory;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeAll;
/**
* GCloudSessionDataStoreTest
@ -32,24 +34,39 @@ import org.junit.jupiter.api.AfterEach;
public class GCloudSessionDataStoreTest extends AbstractSessionDataStoreTest
{
public static GCloudSessionTestSupport __testSupport;
@BeforeAll
public static void setUp () throws Exception
{
__testSupport = new GCloudSessionTestSupport();
__testSupport.setUp();
}
@AfterAll
public static void tearDown () throws Exception
{
__testSupport.tearDown();
}
@AfterEach
public void teardown () throws Exception
{
GCloudTestSuite.__testSupport.deleteSessions();
__testSupport.deleteSessions();
}
@Override
public SessionDataStoreFactory createSessionDataStoreFactory()
{
return GCloudSessionTestSupport.newSessionDataStoreFactory(GCloudTestSuite.__testSupport.getDatastore());
return GCloudSessionTestSupport.newSessionDataStoreFactory(__testSupport.getDatastore());
}
@Override
public void persistSession(SessionData data) throws Exception
{
GCloudTestSuite.__testSupport.createSession(data.getId(), data.getContextPath(), data.getVhost(), data.getLastNode(), data.getCreated(),
__testSupport.createSession(data.getId(), data.getContextPath(), data.getVhost(), data.getLastNode(), data.getCreated(),
data.getAccessed(), data.getLastAccessed(), data.getMaxInactiveMs(), data.getExpiry(),
data.getCookieSet(), data.getLastSaved(), data.getAllAttributes());
@ -60,7 +77,7 @@ public class GCloudSessionDataStoreTest extends AbstractSessionDataStoreTest
public void persistUnreadableSession(SessionData data) throws Exception
{
GCloudTestSuite.__testSupport.createSession(data.getId(), data.getContextPath(), data.getVhost(), data.getLastNode(), data.getCreated(),
__testSupport.createSession(data.getId(), data.getContextPath(), data.getVhost(), data.getLastNode(), data.getCreated(),
data.getAccessed(), data.getLastAccessed(), data.getMaxInactiveMs(), data.getExpiry(),
data.getCookieSet(), data.getLastSaved(), null);
}
@ -69,7 +86,7 @@ public class GCloudSessionDataStoreTest extends AbstractSessionDataStoreTest
@Override
public boolean checkSessionExists(SessionData data) throws Exception
{
return GCloudTestSuite.__testSupport.checkSessionExists(data.getId());
return __testSupport.checkSessionExists(data.getId());
}
@ -79,7 +96,7 @@ public class GCloudSessionDataStoreTest extends AbstractSessionDataStoreTest
@Override
public boolean checkSessionPersisted(SessionData data) throws Exception
{
return GCloudTestSuite.__testSupport.checkSessionPersisted(data);
return __testSupport.checkSessionPersisted(data);
}
}

View File

@ -23,6 +23,7 @@ package org.eclipse.jetty.gcloud.session;
import org.eclipse.jetty.server.session.AbstractClusteredInvalidationSessionTest;
import org.eclipse.jetty.server.session.SessionDataStoreFactory;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
/**
* InvalidationSessionTest
@ -31,11 +32,26 @@ import org.junit.jupiter.api.AfterAll;
*/
public class InvalidationSessionTest extends AbstractClusteredInvalidationSessionTest
{
public static GCloudSessionTestSupport __testSupport;
@BeforeAll
public static void setUp () throws Exception
{
__testSupport = new GCloudSessionTestSupport();
__testSupport.setUp();
}
@AfterAll
public static void tearDown () throws Exception
{
__testSupport.tearDown();
}
@AfterAll
public static void teardown () throws Exception
{
GCloudTestSuite.__testSupport.deleteSessions();
__testSupport.deleteSessions();
}
/**
@ -44,6 +60,6 @@ public class InvalidationSessionTest extends AbstractClusteredInvalidationSessio
@Override
public SessionDataStoreFactory createSessionDataStoreFactory()
{
return GCloudSessionTestSupport.newSessionDataStoreFactory(GCloudTestSuite.__testSupport.getDatastore());
return GCloudSessionTestSupport.newSessionDataStoreFactory(__testSupport.getDatastore());
}
}