Christ, Thanks for the explanation. The XML-based registration - is that something I would do as a user, or something that would be changed on the Tomcat side as part of its release bundle?
On Thu, Dec 14, 2023 at 10:17 AM Christopher Schultz < ch...@christopherschultz.net> wrote: > 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 > >