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