diff -r 88b85470e72c -r f50545b5e2f1 src/share/jaxws_classes/com/sun/xml/internal/ws/server/MonitorBase.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/jaxws_classes/com/sun/xml/internal/ws/server/MonitorBase.java Tue Mar 06 16:09:35 2012 -0800 @@ -0,0 +1,434 @@ +/* + * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.sun.xml.internal.ws.server; + +import com.sun.istack.internal.NotNull; +import com.sun.istack.internal.Nullable; +import com.sun.xml.internal.ws.api.EndpointAddress; +import com.sun.xml.internal.ws.api.config.management.policy.ManagedClientAssertion; +import com.sun.xml.internal.ws.api.config.management.policy.ManagedServiceAssertion; +import com.sun.xml.internal.ws.api.config.management.policy.ManagementAssertion.Setting; +import com.sun.xml.internal.ws.api.server.BoundEndpoint; +import com.sun.xml.internal.ws.api.server.Container; +import com.sun.xml.internal.ws.api.server.Module; +import com.sun.xml.internal.ws.api.server.WSEndpoint; +import com.sun.xml.internal.ws.client.Stub; +import com.sun.org.glassfish.external.amx.AMXGlassfish; +import com.sun.org.glassfish.gmbal.Description; +import com.sun.org.glassfish.gmbal.InheritedAttribute; +import com.sun.org.glassfish.gmbal.InheritedAttributes; +import com.sun.org.glassfish.gmbal.ManagedData; +import com.sun.org.glassfish.gmbal.ManagedObjectManager; +import com.sun.org.glassfish.gmbal.ManagedObjectManagerFactory; +import java.io.IOException; +import java.lang.reflect.*; +import java.net.URL; +import java.util.List; +import java.util.logging.Level; +import java.util.logging.Logger; +import javax.management.ObjectName; +import javax.xml.namespace.QName; + +// BEGIN IMPORTS FOR RewritingMOM +import java.util.ResourceBundle ; +import java.io.Closeable ; +import java.lang.reflect.AnnotatedElement ; +import java.lang.annotation.Annotation ; +import javax.management.ObjectName ; +import javax.management.MBeanServer ; +import com.sun.org.glassfish.gmbal.AMXClient; +import com.sun.org.glassfish.gmbal.GmbalMBean; +// END IMPORTS FOR RewritingMOM + +/** + * @author Harold Carr + */ +public abstract class MonitorBase { + + private static final Logger logger = Logger.getLogger( + com.sun.xml.internal.ws.util.Constants.LoggingDomain + ".monitoring"); + + /** + * Endpoint monitoring is ON by default. + * + * prop | no assert | assert/no mon | assert/mon off | assert/mon on + * ------------------------------------------------------------------- + * not set | on | on | off | on + * false | off | off | off | off + * true | on | on | off | on + */ + @NotNull public ManagedObjectManager createManagedObjectManager(final WSEndpoint endpoint) { + // serviceName + portName identifies the managed objects under it. + // There can be multiple services in the container. + // The same serviceName+portName can live in different apps at + // different endpoint addresses. + // + // In general, monitoring will add -N, where N is unique integer, + // in case of collisions. + // + // The endpoint address would be unique, but we do not know + // the endpoint address until the first request comes in, + // which is after monitoring is setup. + + String rootName = + endpoint.getServiceName().getLocalPart() + + "-" + + endpoint.getPortName().getLocalPart(); + + if (rootName.equals("-")) { + rootName = "provider"; + } + + // contextPath is not always available + final String contextPath = getContextPath(endpoint); + if (contextPath != null) { + rootName = contextPath + "-" + rootName; + } + + final ManagedServiceAssertion assertion = + ManagedServiceAssertion.getAssertion(endpoint); + if (assertion != null) { + final String id = assertion.getId(); + if (id != null) { + rootName = id; + } + if (assertion.monitoringAttribute() == Setting.OFF) { + return disabled("This endpoint", rootName); + } + } + + if (endpointMonitoring.equals(Setting.OFF)) { + return disabled("Global endpoint", rootName); + } + return createMOMLoop(rootName, 0); + } + + private String getContextPath(final WSEndpoint endpoint) { + try { + Container container = endpoint.getContainer(); + Method getSPI = + container.getClass().getDeclaredMethod("getSPI", Class.class); + getSPI.setAccessible(true); + Class servletContextClass = + Class.forName("javax.servlet.ServletContext"); + Object servletContext = + getSPI.invoke(container, servletContextClass); + if (servletContext != null) { + Method getContextPath = servletContextClass.getDeclaredMethod("getContextPath"); + getContextPath.setAccessible(true); + return (String) getContextPath.invoke(servletContext); + } + return null; + } catch (Throwable t) { + logger.log(Level.FINEST, "getContextPath", t); + } + return null; + } + + /** + * Client monitoring is OFF by default because there is + * no standard stub.close() method. Therefore people do + * not typically close a stub when they are done with it + * (even though the RI does provide a .close). + *
+     * prop    |  no assert | assert/no mon | assert/mon off | assert/mon on
+     * -------------------------------------------------------------------
+     * not set |    off     |      off      |     off        |     on
+     * false   |    off     |      off      |     off        |     off
+     * true    |    on      |      on       |     off        |     on
+     * 
+ */ + @NotNull public ManagedObjectManager createManagedObjectManager(final Stub stub) { + EndpointAddress ea = stub.requestContext.getEndpointAddress(); + if (ea == null) { + return ManagedObjectManagerFactory.createNOOP(); + } + + String rootName = ea.toString(); + + final ManagedClientAssertion assertion = + ManagedClientAssertion.getAssertion(stub.getPortInfo()); + if (assertion != null) { + final String id = assertion.getId(); + if (id != null) { + rootName = id; + } + if (assertion.monitoringAttribute() == Setting.OFF) { + return disabled("This client", rootName); + } else if (assertion.monitoringAttribute() == Setting.ON && + clientMonitoring != Setting.OFF) { + return createMOMLoop(rootName, 0); + } + } + + if (clientMonitoring == Setting.NOT_SET || + clientMonitoring == Setting.OFF) + { + return disabled("Global client", rootName); + } + return createMOMLoop(rootName, 0); + } + + @NotNull private ManagedObjectManager disabled(final String x, final String rootName) { + final String msg = x + " monitoring disabled. " + rootName + " will not be monitored"; + logger.log(Level.CONFIG, msg); + return ManagedObjectManagerFactory.createNOOP(); + } + + private @NotNull ManagedObjectManager createMOMLoop(final String rootName, final int unique) { + final boolean isFederated = AMXGlassfish.getGlassfishVersion() != null; + ManagedObjectManager mom = createMOM(isFederated); + mom = initMOM(mom); + mom = createRoot(mom, rootName, unique); + return mom; + } + + private @NotNull ManagedObjectManager createMOM(final boolean isFederated) { + try { + return new RewritingMOM(isFederated ? + ManagedObjectManagerFactory.createFederated( + AMXGlassfish.DEFAULT.serverMon(AMXGlassfish.DEFAULT.dasName())) + : + ManagedObjectManagerFactory.createStandalone("com.sun.metro")); + } catch (Throwable t) { + if (isFederated) { + logger.log(Level.CONFIG, "Problem while attempting to federate with GlassFish AMX monitoring. Trying standalone.", t); + return createMOM(false); + } else { + logger.log(Level.WARNING, "Ignoring exception - starting up without monitoring", t); + return ManagedObjectManagerFactory.createNOOP(); + } + } + } + + private @NotNull ManagedObjectManager initMOM(final ManagedObjectManager mom) { + try { + if (typelibDebug != -1) { + mom.setTypelibDebug(typelibDebug); + } + if (registrationDebug.equals("FINE")) { + mom.setRegistrationDebug(ManagedObjectManager.RegistrationDebugLevel.FINE); + } else if (registrationDebug.equals("NORMAL")) { + mom.setRegistrationDebug(ManagedObjectManager.RegistrationDebugLevel.NORMAL); + } else { + mom.setRegistrationDebug(ManagedObjectManager.RegistrationDebugLevel.NONE); + } + + mom.setRuntimeDebug(runtimeDebug); + + // Instead of GMBAL throwing an exception and logging + // duplicate name, just have it return null. + mom.suppressDuplicateRootReport(true); + + mom.stripPrefix( + "com.sun.xml.internal.ws.server", + "com.sun.xml.internal.ws.rx.rm.runtime.sequence"); + + // Add annotations to a standard class + mom.addAnnotation(javax.xml.ws.WebServiceFeature.class, DummyWebServiceFeature.class.getAnnotation(ManagedData.class)); + mom.addAnnotation(javax.xml.ws.WebServiceFeature.class, DummyWebServiceFeature.class.getAnnotation(Description.class)); + mom.addAnnotation(javax.xml.ws.WebServiceFeature.class, DummyWebServiceFeature.class.getAnnotation(InheritedAttributes.class)); + + // Defer so we can register "this" as root from + // within constructor. + mom.suspendJMXRegistration(); + + } catch (Throwable t) { + try { + mom.close(); + } catch (IOException e) { + logger.log(Level.CONFIG, "Ignoring exception caught when closing unused ManagedObjectManager", e); + } + logger.log(Level.WARNING, "Ignoring exception - starting up without monitoring", t); + return ManagedObjectManagerFactory.createNOOP(); + } + return mom; + } + + private ManagedObjectManager createRoot(final ManagedObjectManager mom, final String rootName, int unique) { + final String name = rootName + (unique == 0 ? "" : "-" + String.valueOf(unique)); + try { + final Object ignored = mom.createRoot(this, name); + if (ignored != null) { + ObjectName ignoredName = mom.getObjectName(mom.getRoot()); + // The name is null when the MOM is a NOOP. + if (ignoredName != null) { + logger.log(Level.INFO, "Metro monitoring rootname successfully set to: " + ignoredName); + } + return mom; + } + try { + mom.close(); + } catch (IOException e) { + logger.log(Level.CONFIG, "Ignoring exception caught when closing unused ManagedObjectManager", e); + } + final String basemsg ="Duplicate Metro monitoring rootname: " + name + " : "; + if (unique > maxUniqueEndpointRootNameRetries) { + final String msg = basemsg + "Giving up."; + logger.log(Level.INFO, msg); + return ManagedObjectManagerFactory.createNOOP(); + } + final String msg = basemsg + "Will try to make unique"; + logger.log(Level.CONFIG, msg); + return createMOMLoop(rootName, ++unique); + } catch (Throwable t) { + logger.log(Level.WARNING, "Error while creating monitoring root with name: " + rootName, t); + return ManagedObjectManagerFactory.createNOOP(); + } + } + + public static void closeMOM(ManagedObjectManager mom) { + try { + final ObjectName name = mom.getObjectName(mom.getRoot()); + // The name is null when the MOM is a NOOP. + if (name != null) { + logger.log(Level.INFO, "Closing Metro monitoring root: " + name); + } + mom.close(); + } catch (java.io.IOException e) { + logger.log(Level.WARNING, "Ignoring error when closing Managed Object Manager", e); + } + } + + private static Setting clientMonitoring = Setting.NOT_SET; + private static Setting endpointMonitoring = Setting.NOT_SET; + private static int typelibDebug = -1; + private static String registrationDebug = "NONE"; + private static boolean runtimeDebug = false; + private static int maxUniqueEndpointRootNameRetries = 100; + private static final String monitorProperty = "com.sun.xml.internal.ws.monitoring."; + + private static Setting propertyToSetting(String propName) { + String s = System.getProperty(propName); + if (s == null) { + return Setting.NOT_SET; + } + s = s.toLowerCase(); + if (s.equals("false") || s.equals("off")) { + return Setting.OFF; + } else if (s.equals("true") || s.equals("on")) { + return Setting.ON; + } + return Setting.NOT_SET; + } + + static { + try { + endpointMonitoring = propertyToSetting(monitorProperty + "endpoint"); + + clientMonitoring = propertyToSetting(monitorProperty + "client"); + + Integer i = Integer.getInteger(monitorProperty + "typelibDebug"); + if (i != null) { + typelibDebug = i; + } + + String s = System.getProperty(monitorProperty + "registrationDebug"); + if (s != null) { + registrationDebug = s.toUpperCase(); + } + + s = System.getProperty(monitorProperty + "runtimeDebug"); + if (s != null && s.toLowerCase().equals("true")) { + runtimeDebug = true; + } + + i = Integer.getInteger(monitorProperty + "maxUniqueEndpointRootNameRetries"); + if (i != null) { + maxUniqueEndpointRootNameRetries = i; + } + } catch (Exception e) { + logger.log(Level.WARNING, "Error while reading monitoring properties", e); + } + } +} + + +// This enables us to annotate the WebServiceFeature class even thought +// we can't explicitly put the annotations in the class itself. +@ManagedData +@Description("WebServiceFeature") +@InheritedAttributes({ + @InheritedAttribute(methodName="getID", description="unique id for this feature"), + @InheritedAttribute(methodName="isEnabled", description="true if this feature is enabled") +}) +interface DummyWebServiceFeature {} + +class RewritingMOM implements ManagedObjectManager +{ + private final ManagedObjectManager mom; + + private final static String gmbalQuotingCharsRegex = "\n|\\|\"|\\*|\\?|:|=|,"; + private final static String jmxQuotingCharsRegex = ",|=|:|\""; + private final static String replacementChar = "-"; + + RewritingMOM(final ManagedObjectManager mom) { this.mom = mom; } + + private String rewrite(final String x) { + return x.replaceAll(gmbalQuotingCharsRegex, replacementChar); + } + + // The interface + + public void suspendJMXRegistration() { mom.suspendJMXRegistration(); } + public void resumeJMXRegistration() { mom.resumeJMXRegistration(); } + public GmbalMBean createRoot() { return mom.createRoot(); } + public GmbalMBean createRoot(Object root) { return mom.createRoot(root); } + public GmbalMBean createRoot(Object root, String name) { + return mom.createRoot(root, rewrite(name)); + } + public Object getRoot() { return mom.getRoot(); } + public GmbalMBean register(Object parent, Object obj, String name) { + return mom.register(parent, obj, rewrite(name)); + } + public GmbalMBean register(Object parent, Object obj) { return mom.register(parent, obj);} + public GmbalMBean registerAtRoot(Object obj, String name) { + return mom.registerAtRoot(obj, rewrite(name)); + } + public GmbalMBean registerAtRoot(Object obj) { return mom.registerAtRoot(obj); } + public void unregister(Object obj) { mom.unregister(obj); } + public ObjectName getObjectName(Object obj) { return mom.getObjectName(obj); } + public AMXClient getAMXClient(Object obj) { return mom.getAMXClient(obj); } + public Object getObject(ObjectName oname) { return mom.getObject(oname); } + public void stripPrefix(String... str) { mom.stripPrefix(str); } + public void stripPackagePrefix() { mom.stripPackagePrefix(); } + public String getDomain() { return mom.getDomain(); } + public void setMBeanServer(MBeanServer server){mom.setMBeanServer(server); } + public MBeanServer getMBeanServer() { return mom.getMBeanServer(); } + public void setResourceBundle(ResourceBundle rb) { mom.setResourceBundle(rb); } + public ResourceBundle getResourceBundle() { return mom.getResourceBundle(); } + public void addAnnotation(AnnotatedElement element, Annotation annotation) { mom.addAnnotation(element, annotation); } + public void setRegistrationDebug(RegistrationDebugLevel level) { mom.setRegistrationDebug(level); } + public void setRuntimeDebug(boolean flag) { mom.setRuntimeDebug(flag); } + public void setTypelibDebug(int level) { mom.setTypelibDebug(level); } + public String dumpSkeleton(Object obj) { return mom.dumpSkeleton(obj); } + public void suppressDuplicateRootReport(boolean suppressReport) { mom.suppressDuplicateRootReport(suppressReport); } + public void close() throws IOException { mom.close(); } + public void setJMXRegistrationDebug(boolean x) { mom.setJMXRegistrationDebug(x); } + public boolean isManagedObject(Object x) { return mom.isManagedObject(x); } +} + +// End of file.