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