Daniel,

On 12/14/23 09:43, Daniel Skiles wrote:
Do you have any pointers on how to do that using JMX?  So far as I can tell
from what little documentation I can find on the tomcat site, this is how
it's done.

I'm suspicious that there might be an issue in
Tomcat's MbeansDescriptorsIntrospectionSource.createManagedBean(...)
method.  I'm not familiar with the code, but it appears that there might be
an issue with how that map is constructed.

+1

The operations map is keyed on method-name which means that overloads are not supported.

I suppose it's possible that the introspecter doesn't always get the methods back from the reflection process in exactly the same order, and the last one always wins. This would explain why it sometimes works and sometimes does not work.

The best solution would be to explicitly-define this operation in the MBeans XML-based registration. Then no introspection is necessary and we always get the right method.

-chris

On Thu, Dec 14, 2023 at 4:25 AM Rémy Maucherat <r...@apache.org> wrote:

On Wed, Dec 13, 2023 at 9:43 PM Daniel Skiles
<dski...@docfinity.com.invalid> wrote:

The object and operation I'm trying to address is Catalina -->
ProtocolHandler --> <port> --> <host> --> operations -->
addSslHostConfig.

The parameters are an SslHostConfig object and the boolean value "true".

The operation is "addSslHostConfig".

The code I sent in the previous message works 100% of the time in 9.0.82.
In 9.0.83, it works about 50% of the time.  I can always query that the
operation exists, but roughly half the time it will fail with a JMX
exception saying that the operation does not exist.

I am not positive, but I believe the behavior in 9.0.83 might have to do
with the fact that the catalina java code now has a one argument and two
argument variant of the same method.

I'm pretty sure you got the explanation right. It is very similar to
using reflection here. You're doing the lookup based on the method
name, which matches something. However, if you want to avoid an error,
you also have to check that the arguments match, otherwise you're
going to randomly pick one of the two methods and fail half the time.

Rémy

On Wed, Dec 13, 2023 at 10:27 AM Christopher Schultz <
ch...@christopherschultz.net> wrote:

Daniel,

On 12/12/23 19:45, Daniel Skiles wrote:
I apologize for it being a bit rough - it's what I was using to
troubleshoot locally.

import static java.util.Objects.nonNull;

import java.lang.management.ManagementFactory;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import java.util.function.Predicate;

import javax.management.MBeanInfo;
import javax.management.MBeanOperationInfo;
import javax.management.MBeanServer;
import javax.management.ObjectName;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.tomcat.util.net.SSLHostConfig;
import org.apache.tomcat.util.net.SSLHostConfigCertificate;
import org.apache.tomcat.util.net.SSLHostConfigCertificate.Type;

@javax.annotation.ManagedBean
public class MbeanFailure {
private static final Logger LOGGER = LogManager.getLogger();

private static final String LOCALHOST = "127.0.0.1";
private static final String SUBTYPE = "subType";
private static final String ADD_SSL_HOST_CONFIG_OP =
"addSslHostConfig";

private static final Predicate<ObjectName> NOT_LOCALHOST =
Predicate.not(on
->


Optional.ofNullable(on).map(ObjectName::getCanonicalName).orElse("").contains(LOCALHOST));
private static final Predicate<ObjectName>  NOT_SUBTYPE =
Predicate.not(on
->


Optional.ofNullable(on).map(ObjectName::getCanonicalName).orElse("").contains(SUBTYPE));

@javax.annotation.PostConstruct
public void run() throws Exception {
final MBeanServer server =
ManagementFactory.getPlatformMBeanServer();

final SSLHostConfig config = new SSLHostConfig();

config.setProtocols("TLSv1.2");
config.setHostName("test.test.com");
config.setCiphers("TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256");

final SSLHostConfigCertificate cert = new
SSLHostConfigCertificate(config,
Type.UNDEFINED);

config.addCertificate(cert);
final Map<MBeanServer, ObjectName> references =
getObjectReferences(server,
"ProtocolHandler");

references.forEach((s, op) -> invoke(s, op, ADD_SSL_HOST_CONFIG_OP,
new
Object[] {config}, new String[]
{SSLHostConfig.class.getCanonicalName()}));
}

public Map<MBeanServer, ObjectName> getObjectReferences(final
MBeanServer
server, final String discriminator) {

final  Map<MBeanServer, ObjectName> results = new HashMap<>();

final Predicate<ObjectName> extendedFilters =
NOT_LOCALHOST.and(NOT_SUBTYPE);

final Optional<ObjectName> candidate = server.queryNames(null,
null).stream()
.filter(on -> nonNull(on.getCanonicalName()))
.filter(on -> on.getCanonicalName().contains(discriminator))
.filter(extendedFilters)
.findAny();

candidate.ifPresent(on -> results.put(server, on));

return Map.copyOf(results);
}

public Object invoke(final MBeanServer server, final ObjectName
objectName,
final String method, final Object[] params, final String[]
signature) {
try {
//This should return addSslHostConfig(SSLHostConfig, boolean)
final MBeanInfo info = server.getMBeanInfo(objectName);

final MBeanOperationInfo methodInfo =
Arrays.stream(info.getOperations())
.filter(i -> i.getName().equals(method))
.findAny()
.orElseThrow(() -> new RuntimeException("Could not find method
named" +
method));

LOGGER.error("Found available operation {}", methodInfo);

final Object result = server.invoke(objectName, method, params,
signature);
return result;
} catch (final Exception e) {
throw new RuntimeException("Error invoking " + method + " with
params " +
Arrays.toString(params) + " and signature " +
Arrays.toString(signature),
e);
}
}
}

What objctName do you think you are addressing, here? What parameters
are you passing it and what types? What parameters and types are
expected by the operation you are trying to invoke?

-chris

On Fri, Dec 8, 2023 at 4:55 PM Christopher Schultz <
ch...@christopherschultz.net> wrote:

Daniel,

On 12/7/23 13:25, Daniel Skiles wrote:
All,
I've been doing some testing, and I'm pretty sure the
addSslHostConfig
operation on ProtocolHandler is busted in 9.0.83.

In versions prior to 9.0.82, you can call the operation with a
single
argument of type SSLHostConfig.

In 9.0.82, that contract seems to have been broken, and you had to
call
it with two arguments:  an SSLHostConfig and a boolean.

In 9.0.83, it seems as though both operations are present, but
which
one
is actually accessible at runtime is non-deterministic.

This behavior presents through a direct invoke(...) call and via a
JMX
Proxy object instantiated through JMX.newMBeanProxy.

I have attached a sample file that reproduces the behavior
(sometimes,
as it is nondeterministic).

Is this a bug, or am I simply using the available feature
incorrectly?

If it is the former, how do I formally report this?  If it is the
latter, what is the "correct" way to call this operation from JMX?

I think your attachment was stripped. Can it be posted in-line?

-chris


---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscr...@tomcat.apache.org
For additional commands, e-mail: users-h...@tomcat.apache.org




---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscr...@tomcat.apache.org
For additional commands, e-mail: users-h...@tomcat.apache.org



---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscr...@tomcat.apache.org
For additional commands, e-mail: users-h...@tomcat.apache.org




---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscr...@tomcat.apache.org
For additional commands, e-mail: users-h...@tomcat.apache.org

Reply via email to