提交 6fd650ad 编写于 作者: T tbell

Merge

......@@ -160,10 +160,8 @@ CORE_PKGS = \
javax.lang.model.type \
javax.lang.model.util \
javax.management \
javax.management.event \
javax.management.loading \
javax.management.monitor \
javax.management.namespace \
javax.management.relation \
javax.management.openmbean \
javax.management.timer \
......
......@@ -251,6 +251,7 @@ JAVA_JAVA_java = \
java/util/IdentityHashMap.java \
java/util/EnumMap.java \
java/util/Arrays.java \
java/util/DualPivotQuicksort.java \
java/util/TimSort.java \
java/util/ComparableTimSort.java \
java/util/ConcurrentModificationException.java \
......
......@@ -83,7 +83,7 @@ endif
#
# Find platform specific native code
#
vpath %.c $(PLATFORM_SRC)/native/sun/net/dns $(PLATFORM_SRC)/native/sun/net/www/protocol/http $(PLATFORM_SRC)/native/sun/net/spi
vpath %.c $(PLATFORM_SRC)/native/sun/net/dns $(PLATFORM_SRC)/native/sun/net/www/protocol/http/ntlm $(PLATFORM_SRC)/native/sun/net/spi
#
# Include rules
......
#
# Copyright 2006-2008 Sun Microsystems, Inc. All Rights Reserved.
# Copyright 2006-2009 Sun Microsystems, Inc. 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
......@@ -34,8 +34,8 @@ solaris_i586_5.10,\
solaris_x64_5.10,\
linux_i586_2.6,\
linux_x64_2.6,\
windows_i586,\
windows_x64
windows_i586_5.0,\
windows_x64_5.2
# The different build flavors we want
jprt.build.flavors=product,fastdebug
......@@ -51,21 +51,37 @@ jprt.run.flavor.c2.option=-server
jprt.solaris_sparcv9.build.platform.match32=solaris_sparc_5.10
jprt.solaris_x64.build.platform.match32=solaris_i586_5.10
# Standard list of jprt test targets for this workspace
# Standard test target for everybody
jprt.test.targets=*-*-*-jvm98
jprt.regression.test.targets= \
*-product-*-java/lang, \
*-product-*-java/security, \
*-product-*-java/text, \
*-product-*-java/util
#jprt.regression.test.targets= \
# *-product-*-java/awt, \
# *-product-*-java/beans, \
# *-product-*-java/io, \
# *-product-*-java/net, \
# *-product-*-java/nio, \
# *-product-*-java/rmi, \
# Test targets in test/Makefile (some longer running tests only test c2)
jprt.make.rule.test.targets= \
*-product-*-jdk_beans1, \
*-product-*-jdk_beans2, \
*-product-*-jdk_beans3, \
*-product-*-jdk_io, \
*-product-*-jdk_lang, \
*-product-*-jdk_management1, \
*-product-*-jdk_management2, \
*-product-*-jdk_math, \
*-product-*-jdk_misc, \
*-product-*-jdk_net, \
*-product-*-jdk_nio1, \
*-product-*-jdk_nio2, \
*-product-*-jdk_nio3, \
*-product-*-jdk_security1, \
*-product-*-jdk_security2, \
*-product-*-jdk_security3, \
*-product-*-jdk_text, \
*-product-*-jdk_tools1, \
*-product-*-jdk_tools2, \
*-product-*-jdk_util
# Some of these are crashing Xvfb or windows manager, need dedicated DISPLAY per test batch
jprt2.make.rule.test.targets= \
*-product-*-jdk_awt, \
*-product-*-jdk_rmi, \
*-product-*-jdk_swing, \
# Directories needed to build
jprt.bundle.exclude.src.dirs=build
......
......@@ -53,7 +53,6 @@ SUNWprivate_1.1 {
Java_sun_awt_image_GifImageDecoder_initIDs;
Java_sun_awt_image_GifImageDecoder_parseImage;
Java_sun_awt_image_ImageRepresentation_initIDs;
Java_sun_awt_image_ImageRepresentation_setBytePixels;
Java_sun_awt_image_ImageRepresentation_setDiffICM;
Java_sun_awt_image_ImageRepresentation_setICMpixels;
Java_sun_awt_image_ImagingLib_convolveBI;
......
......@@ -55,7 +55,6 @@ SUNWprivate_1.1 {
Java_sun_awt_image_GifImageDecoder_parseImage;
Java_sun_awt_image_Image_initIDs;
Java_sun_awt_image_ImageRepresentation_initIDs;
Java_sun_awt_image_ImageRepresentation_setBytePixels;
Java_sun_awt_image_ImageRepresentation_setDiffICM;
Java_sun_awt_image_ImageRepresentation_setICMpixels;
Java_sun_awt_image_ImagingLib_convolveBI;
......
......@@ -45,8 +45,14 @@ FILES_java = \
sun/net/dns/ResolverConfiguration.java \
sun/net/dns/ResolverConfigurationImpl.java \
sun/net/ftp/FtpClient.java \
sun/net/ftp/FtpClientProvider.java \
sun/net/ftp/FtpDirEntry.java \
sun/net/ftp/FtpReplyCode.java \
sun/net/ftp/FtpDirParser.java \
sun/net/ftp/FtpLoginException.java \
sun/net/ftp/FtpProtocolException.java \
sun/net/ftp/impl/FtpClient.java \
sun/net/ftp/impl/DefaultFtpClientProvider.java \
sun/net/spi/DefaultProxySelector.java \
sun/net/spi/nameservice/NameServiceDescriptor.java \
sun/net/spi/nameservice/NameService.java \
......@@ -79,7 +85,6 @@ FILES_java = \
sun/net/www/http/Hurryable.java \
sun/net/www/protocol/http/Handler.java \
sun/net/www/protocol/http/HttpURLConnection.java \
sun/net/www/protocol/http/HttpLogFormatter.java \
sun/net/www/protocol/http/HttpAuthenticator.java \
sun/net/www/protocol/http/AuthenticationHeader.java \
sun/net/www/protocol/http/AuthenticationInfo.java \
......@@ -89,11 +94,13 @@ FILES_java = \
sun/net/www/protocol/http/AuthScheme.java \
sun/net/www/protocol/http/BasicAuthentication.java \
sun/net/www/protocol/http/DigestAuthentication.java \
sun/net/www/protocol/http/NTLMAuthentication.java \
sun/net/www/protocol/http/NTLMAuthenticationProxy.java \
sun/net/www/protocol/http/NegotiateAuthentication.java \
sun/net/www/protocol/http/NegotiatorImpl.java \
sun/net/www/protocol/http/NegotiateCallbackHandler.java \
sun/net/www/protocol/http/Negotiator.java \
sun/net/www/protocol/http/ntlm/NTLMAuthentication.java \
sun/net/www/protocol/http/spnego/NegotiatorImpl.java \
sun/net/www/protocol/http/spnego/NegotiateCallbackHandler.java \
sun/net/www/protocol/http/logging/HttpLogFormatter.java \
sun/net/www/protocol/https/AbstractDelegateHttpsURLConnection.java \
sun/net/www/protocol/https/HttpsClient.java \
sun/net/www/protocol/https/DefaultHostnameVerifier.java \
......@@ -128,7 +135,7 @@ FILES_java = \
sun/net/idn/StringPrep.java
ifeq ($(PLATFORM), windows)
FILES_java += sun/net/www/protocol/http/NTLMAuthSequence.java
FILES_java += sun/net/www/protocol/http/ntlm/NTLMAuthSequence.java
endif
ifeq ($(PLATFORM), solaris)
......
......@@ -39,6 +39,7 @@ AUTO_FILES_JAVA_DIRS = \
sun/security/provider \
sun/security/rsa \
sun/security/ssl \
sun/security/ssl/krb5 \
sun/security/timestamp \
sun/security/validator \
sun/security/x509 \
......
......@@ -62,6 +62,8 @@ import javax.imageio.event.IIOReadWarningListener;
import java.io.*;
import java.nio.*;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.StringTokenizer;
......@@ -502,12 +504,18 @@ public class BMPImageReader extends ImageReader implements BMPConstants {
iis.reset();
try {
if (metadata.colorSpace == PROFILE_LINKED)
if (metadata.colorSpace == PROFILE_LINKED &&
isLinkedProfileAllowed() &&
!isUncOrDevicePath(profile))
{
String path = new String(profile, "windows-1252");
colorSpace =
new ICC_ColorSpace(ICC_Profile.getInstance(new String(profile)));
else
new ICC_ColorSpace(ICC_Profile.getInstance(path));
} else {
colorSpace =
new ICC_ColorSpace(ICC_Profile.getInstance(profile));
}
} catch (Exception e) {
colorSpace = ColorSpace.getInstance(ColorSpace.CS_sRGB);
}
......@@ -1745,4 +1753,69 @@ public class BMPImageReader extends ImageReader implements BMPConstants {
public void sequenceStarted(ImageReader src, int minIndex) {}
public void readAborted(ImageReader src) {}
}
private static Boolean isLinkedProfileDisabled = null;
private static boolean isLinkedProfileAllowed() {
if (isLinkedProfileDisabled == null) {
PrivilegedAction<Boolean> a = new PrivilegedAction<Boolean>() {
public Boolean run() {
return Boolean.getBoolean("sun.imageio.plugins.bmp.disableLinkedProfiles");
}
};
isLinkedProfileDisabled = AccessController.doPrivileged(a);
}
return !isLinkedProfileDisabled;
}
private static Boolean isWindowsPlatform = null;
/**
* Verifies whether the byte array contans a unc path.
* Non-UNC path examples:
* c:\path\to\file - simple notation
* \\?\c:\path\to\file - long notation
*
* UNC path examples:
* \\server\share - a UNC path in simple notation
* \\?\UNC\server\share - a UNC path in long notation
* \\.\some\device - a path to device.
*/
private static boolean isUncOrDevicePath(byte[] p) {
if (isWindowsPlatform == null) {
PrivilegedAction<Boolean> a = new PrivilegedAction<Boolean>() {
public Boolean run() {
String osname = System.getProperty("os.name");
return (osname != null &&
osname.toLowerCase().startsWith("win"));
}
};
isWindowsPlatform = AccessController.doPrivileged(a);
}
if (!isWindowsPlatform) {
/* no need for the check on platforms except windows */
return false;
}
/* normalize prefix of the path */
if (p[0] == '/') p[0] = '\\';
if (p[1] == '/') p[1] = '\\';
if (p[3] == '/') p[3] = '\\';
if ((p[0] == '\\') && (p[1] == '\\')) {
if ((p[2] == '?') && (p[3] == '\\')) {
// long path: whether unc or local
return ((p[4] == 'U' || p[4] == 'u') &&
(p[5] == 'N' || p[5] == 'n') &&
(p[6] == 'C' || p[6] == 'c'));
} else {
// device path or short unc notation
return true;
}
} else {
return false;
}
}
}
......@@ -25,6 +25,8 @@
package com.sun.java.swing.plaf.motif;
import sun.awt.AppContext;
import javax.swing.*;
import javax.swing.border.*;
import javax.swing.plaf.basic.*;
......@@ -46,16 +48,23 @@ import javax.swing.plaf.*;
*/
public class MotifButtonUI extends BasicButtonUI {
private final static MotifButtonUI motifButtonUI = new MotifButtonUI();
protected Color selectColor;
private boolean defaults_initialized = false;
private static final Object MOTIF_BUTTON_UI_KEY = new Object();
// ********************************
// Create PLAF
// ********************************
public static ComponentUI createUI(JComponent c){
public static ComponentUI createUI(JComponent c) {
AppContext appContext = AppContext.getAppContext();
MotifButtonUI motifButtonUI =
(MotifButtonUI) appContext.get(MOTIF_BUTTON_UI_KEY);
if (motifButtonUI == null) {
motifButtonUI = new MotifButtonUI();
appContext.put(MOTIF_BUTTON_UI_KEY, motifButtonUI);
}
return motifButtonUI;
}
......
......@@ -25,6 +25,8 @@
package com.sun.java.swing.plaf.motif;
import sun.awt.AppContext;
import javax.swing.*;
import javax.swing.plaf.*;
......@@ -45,7 +47,7 @@ import java.awt.*;
*/
public class MotifCheckBoxUI extends MotifRadioButtonUI {
private static final MotifCheckBoxUI motifCheckBoxUI = new MotifCheckBoxUI();
private static final Object MOTIF_CHECK_BOX_UI_KEY = new Object();
private final static String propertyPrefix = "CheckBox" + ".";
......@@ -55,7 +57,14 @@ public class MotifCheckBoxUI extends MotifRadioButtonUI {
// ********************************
// Create PLAF
// ********************************
public static ComponentUI createUI(JComponent c){
public static ComponentUI createUI(JComponent c) {
AppContext appContext = AppContext.getAppContext();
MotifCheckBoxUI motifCheckBoxUI =
(MotifCheckBoxUI) appContext.get(MOTIF_CHECK_BOX_UI_KEY);
if (motifCheckBoxUI == null) {
motifCheckBoxUI = new MotifCheckBoxUI();
appContext.put(MOTIF_CHECK_BOX_UI_KEY, motifCheckBoxUI);
}
return motifCheckBoxUI;
}
......
......@@ -25,6 +25,8 @@
package com.sun.java.swing.plaf.motif;
import sun.awt.AppContext;
import javax.swing.*;
import javax.swing.plaf.basic.BasicLabelUI;
import javax.swing.plaf.ComponentUI;
......@@ -44,9 +46,16 @@ import javax.swing.plaf.ComponentUI;
*/
public class MotifLabelUI extends BasicLabelUI
{
static MotifLabelUI sharedInstance = new MotifLabelUI();
private static final Object MOTIF_LABEL_UI_KEY = new Object();
public static ComponentUI createUI(JComponent c) {
return sharedInstance;
AppContext appContext = AppContext.getAppContext();
MotifLabelUI motifLabelUI =
(MotifLabelUI) appContext.get(MOTIF_LABEL_UI_KEY);
if (motifLabelUI == null) {
motifLabelUI = new MotifLabelUI();
appContext.put(MOTIF_LABEL_UI_KEY, motifLabelUI);
}
return motifLabelUI;
}
}
......@@ -25,6 +25,8 @@
package com.sun.java.swing.plaf.motif;
import sun.awt.AppContext;
import javax.swing.*;
import javax.swing.border.*;
import javax.swing.plaf.basic.BasicRadioButtonUI;
......@@ -47,7 +49,7 @@ import java.awt.*;
*/
public class MotifRadioButtonUI extends BasicRadioButtonUI {
private static final MotifRadioButtonUI motifRadioButtonUI = new MotifRadioButtonUI();
private static final Object MOTIF_RADIO_BUTTON_UI_KEY = new Object();
protected Color focusColor;
......@@ -57,6 +59,13 @@ public class MotifRadioButtonUI extends BasicRadioButtonUI {
// Create PLAF
// ********************************
public static ComponentUI createUI(JComponent c) {
AppContext appContext = AppContext.getAppContext();
MotifRadioButtonUI motifRadioButtonUI =
(MotifRadioButtonUI) appContext.get(MOTIF_RADIO_BUTTON_UI_KEY);
if (motifRadioButtonUI == null) {
motifRadioButtonUI = new MotifRadioButtonUI();
appContext.put(MOTIF_RADIO_BUTTON_UI_KEY, motifRadioButtonUI);
}
return motifRadioButtonUI;
}
......
......@@ -25,6 +25,8 @@
package com.sun.java.swing.plaf.motif;
import sun.awt.AppContext;
import java.awt.*;
import java.awt.event.*;
......@@ -48,7 +50,7 @@ import javax.swing.plaf.basic.*;
*/
public class MotifToggleButtonUI extends BasicToggleButtonUI
{
private final static MotifToggleButtonUI motifToggleButtonUI = new MotifToggleButtonUI();
private static final Object MOTIF_TOGGLE_BUTTON_UI_KEY = new Object();
protected Color selectColor;
......@@ -58,6 +60,13 @@ public class MotifToggleButtonUI extends BasicToggleButtonUI
// Create PLAF
// ********************************
public static ComponentUI createUI(JComponent b) {
AppContext appContext = AppContext.getAppContext();
MotifToggleButtonUI motifToggleButtonUI =
(MotifToggleButtonUI) appContext.get(MOTIF_TOGGLE_BUTTON_UI_KEY);
if (motifToggleButtonUI == null) {
motifToggleButtonUI = new MotifToggleButtonUI();
appContext.put(MOTIF_TOGGLE_BUTTON_UI_KEY, motifToggleButtonUI);
}
return motifToggleButtonUI;
}
......
......@@ -35,6 +35,7 @@ import java.awt.*;
import static com.sun.java.swing.plaf.windows.TMSchema.*;
import static com.sun.java.swing.plaf.windows.TMSchema.Part.*;
import static com.sun.java.swing.plaf.windows.XPStyle.Skin;
import sun.awt.AppContext;
/**
......@@ -52,8 +53,6 @@ import static com.sun.java.swing.plaf.windows.XPStyle.Skin;
*/
public class WindowsButtonUI extends BasicButtonUI
{
private final static WindowsButtonUI windowsButtonUI = new WindowsButtonUI();
protected int dashedRectGapX;
protected int dashedRectGapY;
protected int dashedRectGapWidth;
......@@ -63,11 +62,19 @@ public class WindowsButtonUI extends BasicButtonUI
private boolean defaults_initialized = false;
private static final Object WINDOWS_BUTTON_UI_KEY = new Object();
// ********************************
// Create PLAF
// ********************************
public static ComponentUI createUI(JComponent c){
public static ComponentUI createUI(JComponent c) {
AppContext appContext = AppContext.getAppContext();
WindowsButtonUI windowsButtonUI =
(WindowsButtonUI) appContext.get(WINDOWS_BUTTON_UI_KEY);
if (windowsButtonUI == null) {
windowsButtonUI = new WindowsButtonUI();
appContext.put(WINDOWS_BUTTON_UI_KEY, windowsButtonUI);
}
return windowsButtonUI;
}
......@@ -151,7 +158,7 @@ public class WindowsButtonUI extends BasicButtonUI
* allocating them in each paint call substantially reduced the time
* it took paint to run. Obviously, this method can't be re-entered.
*/
private static Rectangle viewRect = new Rectangle();
private Rectangle viewRect = new Rectangle();
public void paint(Graphics g, JComponent c) {
if (XPStyle.getXP() != null) {
......
......@@ -25,6 +25,8 @@
package com.sun.java.swing.plaf.windows;
import sun.awt.AppContext;
import javax.swing.plaf.basic.*;
import javax.swing.*;
import javax.swing.plaf.*;
......@@ -49,7 +51,7 @@ public class WindowsCheckBoxUI extends WindowsRadioButtonUI
// of BasicCheckBoxUI because we want to pick up all the
// painting changes made in MetalRadioButtonUI.
private static final WindowsCheckBoxUI windowsCheckBoxUI = new WindowsCheckBoxUI();
private static final Object WINDOWS_CHECK_BOX_UI_KEY = new Object();
private final static String propertyPrefix = "CheckBox" + ".";
......@@ -59,6 +61,13 @@ public class WindowsCheckBoxUI extends WindowsRadioButtonUI
// Create PLAF
// ********************************
public static ComponentUI createUI(JComponent c) {
AppContext appContext = AppContext.getAppContext();
WindowsCheckBoxUI windowsCheckBoxUI =
(WindowsCheckBoxUI) appContext.get(WINDOWS_CHECK_BOX_UI_KEY);
if (windowsCheckBoxUI == null) {
windowsCheckBoxUI = new WindowsCheckBoxUI();
appContext.put(WINDOWS_CHECK_BOX_UI_KEY, windowsCheckBoxUI);
}
return windowsCheckBoxUI;
}
......
......@@ -26,6 +26,8 @@
package com.sun.java.swing.plaf.windows;
import sun.swing.SwingUtilities2;
import sun.awt.AppContext;
import java.awt.Color;
import java.awt.Graphics;
......@@ -51,12 +53,19 @@ import javax.swing.plaf.basic.BasicLabelUI;
*/
public class WindowsLabelUI extends BasicLabelUI {
private final static WindowsLabelUI windowsLabelUI = new WindowsLabelUI();
private static final Object WINDOWS_LABEL_UI_KEY = new Object();
// ********************************
// Create PLAF
// ********************************
public static ComponentUI createUI(JComponent c){
public static ComponentUI createUI(JComponent c) {
AppContext appContext = AppContext.getAppContext();
WindowsLabelUI windowsLabelUI =
(WindowsLabelUI) appContext.get(WINDOWS_LABEL_UI_KEY);
if (windowsLabelUI == null) {
windowsLabelUI = new WindowsLabelUI();
appContext.put(WINDOWS_LABEL_UI_KEY, windowsLabelUI);
}
return windowsLabelUI;
}
......
......@@ -25,6 +25,8 @@
package com.sun.java.swing.plaf.windows;
import sun.awt.AppContext;
import javax.swing.plaf.basic.*;
import javax.swing.*;
import javax.swing.plaf.*;
......@@ -44,7 +46,7 @@ import java.awt.*;
*/
public class WindowsRadioButtonUI extends BasicRadioButtonUI
{
private static final WindowsRadioButtonUI windowsRadioButtonUI = new WindowsRadioButtonUI();
private static final Object WINDOWS_RADIO_BUTTON_UI_KEY = new Object();
protected int dashedRectGapX;
protected int dashedRectGapY;
......@@ -59,6 +61,13 @@ public class WindowsRadioButtonUI extends BasicRadioButtonUI
// Create PLAF
// ********************************
public static ComponentUI createUI(JComponent c) {
AppContext appContext = AppContext.getAppContext();
WindowsRadioButtonUI windowsRadioButtonUI =
(WindowsRadioButtonUI) appContext.get(WINDOWS_RADIO_BUTTON_UI_KEY);
if (windowsRadioButtonUI == null) {
windowsRadioButtonUI = new WindowsRadioButtonUI();
appContext.put(WINDOWS_RADIO_BUTTON_UI_KEY, windowsRadioButtonUI);
}
return windowsRadioButtonUI;
}
......
......@@ -25,6 +25,8 @@
package com.sun.java.swing.plaf.windows;
import sun.awt.AppContext;
import javax.swing.plaf.basic.*;
import javax.swing.border.*;
import javax.swing.plaf.*;
......@@ -49,18 +51,25 @@ import java.beans.PropertyChangeEvent;
*/
public class WindowsToggleButtonUI extends BasicToggleButtonUI
{
protected static int dashedRectGapX;
protected static int dashedRectGapY;
protected static int dashedRectGapWidth;
protected static int dashedRectGapHeight;
protected int dashedRectGapX;
protected int dashedRectGapY;
protected int dashedRectGapWidth;
protected int dashedRectGapHeight;
protected Color focusColor;
private final static WindowsToggleButtonUI windowsToggleButtonUI = new WindowsToggleButtonUI();
private static final Object WINDOWS_TOGGLE_BUTTON_UI_KEY = new Object();
private boolean defaults_initialized = false;
public static ComponentUI createUI(JComponent b) {
AppContext appContext = AppContext.getAppContext();
WindowsToggleButtonUI windowsToggleButtonUI =
(WindowsToggleButtonUI) appContext.get(WINDOWS_TOGGLE_BUTTON_UI_KEY);
if (windowsToggleButtonUI == null) {
windowsToggleButtonUI = new WindowsToggleButtonUI();
appContext.put(WINDOWS_TOGGLE_BUTTON_UI_KEY, windowsToggleButtonUI);
}
return windowsToggleButtonUI;
}
......
/*
* Copyright 1999-2008 Sun Microsystems, Inc. All Rights Reserved.
* Copyright 1999-2007 Sun Microsystems, Inc. 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
......@@ -176,18 +176,6 @@ public class JmxProperties {
public static final String RELATION_LOGGER_NAME =
"javax.management.relation";
/**
* Logger name for Namespaces.
*/
public static final String NAMESPACE_LOGGER_NAME =
"javax.management.namespace";
/**
* Logger name for Namespaces.
*/
public static final Logger NAMESPACE_LOGGER =
Logger.getLogger(NAMESPACE_LOGGER_NAME);
/**
* Logger for Relation Service.
*/
......
......@@ -69,9 +69,9 @@ public class ServiceName {
/**
* The version of the JMX specification implemented by this product.
* <BR>
* The value is <CODE>2.0</CODE>.
* The value is <CODE>1.4</CODE>.
*/
public static final String JMX_SPEC_VERSION = "2.0";
public static final String JMX_SPEC_VERSION = "1.4";
/**
* The vendor of the JMX specification implemented by this product.
......
/*
* Copyright 2007-2008 Sun Microsystems, Inc. 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. Sun designates this
* particular file as subject to the "Classpath" exception as provided
* by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*/
package com.sun.jmx.event;
import com.sun.jmx.remote.util.ClassLogger;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.atomic.AtomicInteger;
public class DaemonThreadFactory implements ThreadFactory {
public DaemonThreadFactory(String nameTemplate) {
this(nameTemplate, null);
}
// nameTemplate should be a format with %d in it, which will be replaced
// by a sequence number of threads created by this factory.
public DaemonThreadFactory(String nameTemplate, ThreadGroup threadGroup) {
if (logger.debugOn()) {
logger.debug("DaemonThreadFactory",
"Construct a new daemon factory: "+nameTemplate);
}
if (threadGroup == null) {
SecurityManager s = System.getSecurityManager();
threadGroup = (s != null) ? s.getThreadGroup() :
Thread.currentThread().getThreadGroup();
}
this.nameTemplate = nameTemplate;
this.threadGroup = threadGroup;
}
public Thread newThread(Runnable r) {
final String name =
String.format(nameTemplate, threadNumber.getAndIncrement());
Thread t = new Thread(threadGroup, r, name, 0);
t.setDaemon(true);
if (t.getPriority() != Thread.NORM_PRIORITY)
t.setPriority(Thread.NORM_PRIORITY);
if (logger.debugOn()) {
logger.debug("newThread",
"Create a new daemon thread with the name "+t.getName());
}
return t;
}
private final String nameTemplate;
private final ThreadGroup threadGroup;
private final AtomicInteger threadNumber = new AtomicInteger(1);
private static final ClassLogger logger =
new ClassLogger("com.sun.jmx.event", "DaemonThreadFactory");
}
/*
* Copyright 2007-2008 Sun Microsystems, Inc. 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. Sun designates this
* particular file as subject to the "Classpath" exception as provided
* by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*/
package com.sun.jmx.event;
import com.sun.jmx.remote.util.ClassLogger;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import javax.management.remote.NotificationResult;
import javax.management.remote.TargetedNotification;
public class EventBuffer {
public EventBuffer() {
this(Integer.MAX_VALUE, null);
}
public EventBuffer(int capacity) {
this(capacity, new ArrayList<TargetedNotification>());
}
public EventBuffer(int capacity, final List<TargetedNotification> list) {
if (logger.traceOn()) {
logger.trace("EventBuffer", "New buffer with the capacity: "
+capacity);
}
if (capacity < 1) {
throw new IllegalArgumentException(
"The capacity must be bigger than 0");
}
if (list == null) {
throw new NullPointerException("Null list.");
}
this.capacity = capacity;
this.list = list;
}
public void add(TargetedNotification tn) {
if (logger.traceOn()) {
logger.trace("add", "Add one notif.");
}
synchronized(lock) {
if (list.size() == capacity) { // have to throw one
passed++;
list.remove(0);
if (logger.traceOn()) {
logger.trace("add", "Over, remove the oldest one.");
}
}
list.add(tn);
lock.notify();
}
}
public void add(TargetedNotification[] tns) {
if (tns == null || tns.length == 0) {
return;
}
if (logger.traceOn()) {
logger.trace("add", "Add notifs: "+tns.length);
}
synchronized(lock) {
final int d = list.size() - capacity + tns.length;
if (d > 0) { // have to throw
passed += d;
if (logger.traceOn()) {
logger.trace("add",
"Over, remove the oldest: "+d);
}
if (tns.length <= capacity){
list.subList(0, d).clear();
} else {
list.clear();
TargetedNotification[] tmp =
new TargetedNotification[capacity];
System.arraycopy(tns, tns.length-capacity, tmp, 0, capacity);
tns = tmp;
}
}
Collections.addAll(list,tns);
lock.notify();
}
}
public NotificationResult fetchNotifications(long startSequenceNumber,
long timeout,
int maxNotifications) {
if (logger.traceOn()) {
logger.trace("fetchNotifications",
"Being called: "
+startSequenceNumber+" "
+timeout+" "+maxNotifications);
}
if (startSequenceNumber < 0 ||
timeout < 0 ||
maxNotifications < 0) {
throw new IllegalArgumentException("Negative value.");
}
TargetedNotification[] tns = new TargetedNotification[0];
long earliest = startSequenceNumber < passed ?
passed : startSequenceNumber;
long next = earliest;
final long startTime = System.currentTimeMillis();
long toWait = timeout;
synchronized(lock) {
int toSkip = (int)(startSequenceNumber - passed);
// skip those before startSequenceNumber.
while (!closed && toSkip > 0) {
toWait = timeout - (System.currentTimeMillis() - startTime);
if (list.size() == 0) {
if (toWait <= 0) {
// the notification of startSequenceNumber
// does not arrive yet.
return new NotificationResult(startSequenceNumber,
startSequenceNumber,
new TargetedNotification[0]);
}
waiting(toWait);
continue;
}
if (toSkip <= list.size()) {
list.subList(0, toSkip).clear();
passed += toSkip;
break;
} else {
passed += list.size();
toSkip -= list.size();
list.clear();
}
}
earliest = passed;
if (list.size() == 0) {
toWait = timeout - (System.currentTimeMillis() - startTime);
waiting(toWait);
}
if (list.size() == 0) {
tns = new TargetedNotification[0];
} else if (list.size() <= maxNotifications) {
tns = list.toArray(new TargetedNotification[0]);
} else {
tns = new TargetedNotification[maxNotifications];
for (int i=0; i<maxNotifications; i++) {
tns[i] = list.get(i);
}
}
next = earliest + tns.length;
}
if (logger.traceOn()) {
logger.trace("fetchNotifications",
"Return: "+earliest+" "+next+" "+tns.length);
}
return new NotificationResult(earliest, next, tns);
}
public int size() {
return list.size();
}
public void addLost(long nb) {
synchronized(lock) {
passed += nb;
}
}
public void close() {
if (logger.traceOn()) {
logger.trace("clear", "done");
}
synchronized(lock) {
list.clear();
closed = true;
lock.notifyAll();
}
}
// -------------------------------------------
// private classes
// -------------------------------------------
private void waiting(long timeout) {
final long startTime = System.currentTimeMillis();
long toWait = timeout;
synchronized(lock) {
while (!closed && list.size() == 0 && toWait > 0) {
try {
lock.wait(toWait);
toWait = timeout - (System.currentTimeMillis() - startTime);
} catch (InterruptedException ire) {
logger.trace("waiting", ire);
break;
}
}
}
}
private final int capacity;
private final List<TargetedNotification> list;
private boolean closed;
private long passed = 0;
private final int[] lock = new int[0];
private static final ClassLogger logger =
new ClassLogger("javax.management.event", "EventBuffer");
}
/*
* Copyright 2002-2008 Sun Microsystems, Inc. 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. Sun designates this
* particular file as subject to the "Classpath" exception as provided
* by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*/
package com.sun.jmx.event;
import java.io.IOException;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import javax.management.MBeanServerConnection;
import javax.management.event.EventClient;
import javax.management.event.EventClientDelegate;
import javax.management.event.EventConsumer;
import javax.management.event.NotificationManager;
/**
* Override the methods related to the notification to use the
* Event service.
*/
public interface EventConnection extends MBeanServerConnection, EventConsumer {
public EventClient getEventClient();
public static class Factory {
public static EventConnection make(
final MBeanServerConnection mbsc,
final EventClient eventClient)
throws IOException {
if (!mbsc.isRegistered(EventClientDelegate.OBJECT_NAME)) {
throw new IOException(
"The server does not support the event service.");
}
InvocationHandler ih = new InvocationHandler() {
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
Class<?> intf = method.getDeclaringClass();
try {
if (intf.isInstance(eventClient))
return method.invoke(eventClient, args);
else
return method.invoke(mbsc, args);
} catch (InvocationTargetException e) {
throw e.getCause();
}
}
};
// It is important to declare NotificationManager.class first
// in the array below, so that the relevant addNL and removeNL
// methods will show up with method.getDeclaringClass() as
// being from that interface and not MBeanServerConnection.
return (EventConnection) Proxy.newProxyInstance(
NotificationManager.class.getClassLoader(),
new Class<?>[] {
NotificationManager.class, EventConnection.class,
},
ih);
}
}
}
/*
* Copyright 2007-2008 Sun Microsystems, Inc. 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. Sun designates this
* particular file as subject to the "Classpath" exception as provided
* by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*/
package com.sun.jmx.event;
import com.sun.jmx.mbeanserver.GetPropertyAction;
import com.sun.jmx.remote.util.ClassLogger;
import java.security.AccessController;
import javax.management.event.EventClient;
/**
*
* @author sjiang
*/
public class EventParams {
public static final String DEFAULT_LEASE_TIMEOUT =
"com.sun.event.lease.time";
@SuppressWarnings("cast") // cast for jdk 1.5
public static long getLeaseTimeout() {
long timeout = EventClient.DEFAULT_REQUESTED_LEASE_TIME;
try {
final GetPropertyAction act =
new GetPropertyAction(DEFAULT_LEASE_TIMEOUT);
final String s = (String)AccessController.doPrivileged(act);
if (s != null) {
timeout = Long.parseLong(s);
}
} catch (RuntimeException e) {
logger.fine("getLeaseTimeout", "exception getting property", e);
}
return timeout;
}
/** Creates a new instance of EventParams */
private EventParams() {
}
private static final ClassLogger logger =
new ClassLogger("javax.management.event", "EventParams");
}
/*
* Copyright 2007-2008 Sun Microsystems, Inc. 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. Sun designates this
* particular file as subject to the "Classpath" exception as provided
* by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*/
package com.sun.jmx.event;
import com.sun.jmx.remote.util.ClassLogger;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;
/**
* <p>Manage a renewable lease. The lease can be renewed indefinitely
* but if the lease runs to its current expiry date without being renewed
* then the expiry callback is invoked. If the lease has already expired
* when renewal is attempted then the lease method returns zero.</p>
* @author sjiang
* @author emcmanus
*/
// The synchronization logic of this class is tricky to deal correctly with the
// case where the lease expires at the same time as the |lease| or |stop| method
// is called. If the lease is active then the field |scheduled| represents
// the expiry task; otherwise |scheduled| is null. Renewing or stopping the
// lease involves canceling this task and setting |scheduled| either to a new
// task (to renew) or to null (to stop).
//
// Suppose the expiry task runs at the same time as the |lease| method is called.
// If the task enters its synchronized block before the method starts, then
// it will set |scheduled| to null and the method will return 0. If the method
// starts before the task enters its synchronized block, then the method will
// cancel the task which will see that when it later enters the block.
// Similar reasoning applies to the |stop| method. It is not expected that
// different threads will call |lease| or |stop| simultaneously, although the
// logic should be correct then too.
public class LeaseManager {
public LeaseManager(Runnable callback) {
this(callback, EventParams.getLeaseTimeout());
}
public LeaseManager(Runnable callback, long timeout) {
if (logger.traceOn()) {
logger.trace("LeaseManager", "new manager with lease: "+timeout);
}
if (callback == null) {
throw new NullPointerException("Null callback.");
}
if (timeout <= 0)
throw new IllegalArgumentException("Timeout must be positive: " + timeout);
this.callback = callback;
schedule(timeout);
}
/**
* <p>Renew the lease for the given time. The new time can be shorter
* than the previous one, in which case the lease will expire earlier
* than it would have.</p>
*
* <p>Calling this method after the lease has expired will return zero
* immediately and have no other effect.</p>
*
* @param timeout the new lifetime. If zero, the lease
* will expire immediately.
*/
public synchronized long lease(long timeout) {
if (logger.traceOn()) {
logger.trace("lease", "new lease to: "+timeout);
}
if (timeout < 0)
throw new IllegalArgumentException("Negative lease: " + timeout);
if (scheduled == null)
return 0L;
scheduled.cancel(false);
if (logger.traceOn())
logger.trace("lease", "start lease: "+timeout);
schedule(timeout);
return timeout;
}
private class Expire implements Runnable {
ScheduledFuture<?> task;
public void run() {
synchronized (LeaseManager.this) {
if (task.isCancelled())
return;
scheduled = null;
}
callback.run();
executor.shutdown();
}
}
private synchronized void schedule(long timeout) {
Expire expire = new Expire();
scheduled = executor.schedule(expire, timeout, TimeUnit.MILLISECONDS);
expire.task = scheduled;
}
/**
* <p>Cancel the lease without calling the expiry callback.</p>
*/
public synchronized void stop() {
logger.trace("stop", "canceling lease");
scheduled.cancel(false);
scheduled = null;
try {
executor.shutdown();
} catch (SecurityException e) {
// OK: caller doesn't have RuntimePermission("modifyThread")
// which is unlikely in reality but triggers a test failure otherwise
logger.trace("stop", "exception from executor.shutdown", e);
}
}
private final Runnable callback;
private ScheduledFuture<?> scheduled; // If null, the lease has expired.
private static final ThreadFactory threadFactory =
new DaemonThreadFactory("JMX LeaseManager %d");
private final ScheduledExecutorService executor
= Executors.newScheduledThreadPool(1, threadFactory);
private static final ClassLogger logger =
new ClassLogger("javax.management.event", "LeaseManager");
}
/*
* Copyright 2007-2008 Sun Microsystems, Inc. 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. Sun designates this
* particular file as subject to the "Classpath" exception as provided
* by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*/
package com.sun.jmx.event;
import com.sun.jmx.remote.util.ClassLogger;
import java.util.concurrent.Callable;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
/**
*
* @author sjiang
*/
public class LeaseRenewer {
public LeaseRenewer(ScheduledExecutorService scheduler, Callable<Long> doRenew) {
if (logger.traceOn()) {
logger.trace("LeaseRenewer", "New LeaseRenewer.");
}
if (doRenew == null) {
throw new NullPointerException("Null job to call server.");
}
this.doRenew = doRenew;
nextRenewTime = System.currentTimeMillis();
this.scheduler = scheduler;
future = this.scheduler.schedule(myRenew, 0, TimeUnit.MILLISECONDS);
}
public void close() {
if (logger.traceOn()) {
logger.trace("close", "Close the lease.");
}
synchronized(lock) {
if (closed) {
return;
} else {
closed = true;
}
}
try {
future.cancel(false); // not interrupt if running
} catch (Exception e) {
// OK
if (logger.debugOn()) {
logger.debug("close", "Failed to cancel the leasing job.", e);
}
}
}
public boolean closed() {
synchronized(lock) {
return closed;
}
}
// ------------------------------
// private
// ------------------------------
private final Runnable myRenew = new Runnable() {
public void run() {
synchronized(lock) {
if (closed()) {
return;
}
}
long next = nextRenewTime - System.currentTimeMillis();
if (next < MIN_MILLIS) {
try {
if (logger.traceOn()) {
logger.trace("myRenew-run", "");
}
next = doRenew.call().longValue();
} catch (Exception e) {
logger.fine("myRenew-run", "Failed to renew lease", e);
close();
}
if (next > 0 && next < Long.MAX_VALUE) {
next = next/2;
next = (next < MIN_MILLIS) ? MIN_MILLIS : next;
} else {
close();
}
}
nextRenewTime = System.currentTimeMillis() + next;
if (logger.traceOn()) {
logger.trace("myRenew-run", "Next leasing: "+next);
}
synchronized(lock) {
if (!closed) {
future = scheduler.schedule(this, next, TimeUnit.MILLISECONDS);
}
}
}
};
private final Callable<Long> doRenew;
private ScheduledFuture<?> future;
private boolean closed = false;
private long nextRenewTime;
private final int[] lock = new int[0];
private final ScheduledExecutorService scheduler;
private static final long MIN_MILLIS = 50;
private static final ClassLogger logger =
new ClassLogger("javax.management.event", "LeaseRenewer");
}
/*
* Copyright 2007-2008 Sun Microsystems, Inc. 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. Sun designates this
* particular file as subject to the "Classpath" exception as provided
* by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*/
package com.sun.jmx.event;
import com.sun.jmx.remote.util.ClassLogger;
import java.util.concurrent.Executor;
import java.util.concurrent.RejectedExecutionException;
/**
* <p>A task that is repeatedly run by an Executor. The task will be
* repeated as long as the {@link #isSuspended()} method returns true. Once
* that method returns false, the task is no longer executed until someone
* calls {@link #resume()}.</p>
* @author sjiang
*/
public abstract class RepeatedSingletonJob implements Runnable {
public RepeatedSingletonJob(Executor executor) {
if (executor == null) {
throw new NullPointerException("Null executor!");
}
this.executor = executor;
}
public boolean isWorking() {
return working;
}
public void resume() {
synchronized(this) {
if (!working) {
if (logger.traceOn()) {
logger.trace("resume", "");
}
working = true;
execute();
}
}
}
public abstract void task();
public abstract boolean isSuspended();
public void run() {
if (logger.traceOn()) {
logger.trace("run", "execute the task");
}
try {
task();
} catch (Exception e) {
// A correct task() implementation should not throw exceptions.
// It may cause isSuspended() to start returning true, though.
logger.trace("run", "failed to execute the task", e);
}
synchronized(this) {
if (!isSuspended()) {
execute();
} else {
if (logger.traceOn()) {
logger.trace("run", "suspend the task");
}
working = false;
}
}
}
private void execute() {
try {
executor.execute(this);
} catch (RejectedExecutionException e) {
logger.warning(
"execute",
"Executor threw exception (" + this.getClass().getName() + ")",
e);
throw new RejectedExecutionException(
"Executor.execute threw exception -" +
"should not be possible", e);
// User-supplied Executor should not be configured in a way that
// might cause this exception, for example if it is shared between
// several client objects and doesn't have capacity for one job
// from each one. CR 6732037 will add text to the spec explaining
// the problem. The rethrown exception will propagate either out
// of resume() to user code, or out of run() to the Executor
// (which will probably ignore it).
}
}
private boolean working = false;
private final Executor executor;
private static final ClassLogger logger =
new ClassLogger("javax.management.event", "RepeatedSingletonJob");
}
/*
* Copyright 2008 Sun Microsystems, Inc. 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. Sun designates this
* particular file as subject to the "Classpath" exception as provided
* by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*/
package com.sun.jmx.interceptor;
import com.sun.jmx.defaults.JmxProperties;
import com.sun.jmx.mbeanserver.MBeanInstantiator;
import com.sun.jmx.mbeanserver.Repository;
import com.sun.jmx.mbeanserver.Util;
import com.sun.jmx.namespace.DomainInterceptor;
import java.util.Queue;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.management.MBeanServer;
import javax.management.MBeanServerDelegate;
import javax.management.ObjectName;
import javax.management.QueryExp;
import javax.management.namespace.JMXDomain;
import static javax.management.namespace.JMXNamespaces.NAMESPACE_SEPARATOR;
/**
* A dispatcher that dispatch incoming MBeanServer requests to
* DomainInterceptors.
* <p><b>
* This API is a Sun internal API and is subject to changes without notice.
* </b></p>
* @since 1.7
*/
//
// See comments in DispatchInterceptor.
//
class DomainDispatchInterceptor
extends DispatchInterceptor<DomainInterceptor, JMXDomain> {
/**
* A logger for this class.
**/
private static final Logger LOG = JmxProperties.NAMESPACE_LOGGER;
private static final ObjectName ALL_DOMAINS =
JMXDomain.getDomainObjectName("*");
/**
* A QueryInterceptor that perform & aggregates queries spanning several
* domains.
*/
final static class AggregatingQueryInterceptor extends QueryInterceptor {
private final DomainDispatchInterceptor parent;
AggregatingQueryInterceptor(DomainDispatchInterceptor dispatcher) {
super(dispatcher.nextInterceptor);
parent = dispatcher;
}
/**
* Perform queryNames or queryMBeans, depending on which QueryInvoker
* is passed as argument. This is closures without closures.
**/
@Override
<T> Set<T> query(ObjectName pattern, QueryExp query,
QueryInvoker<T> invoker, MBeanServer localNamespace) {
final Set<T> local = invoker.query(localNamespace, pattern, query);
// Add all matching MBeans from local namespace.
final Set<T> res = Util.cloneSet(local);
if (pattern == null) pattern = ObjectName.WILDCARD;
final boolean all = pattern.getDomain().equals("*");
final String domain = pattern.getDomain();
// If there's no domain pattern, just include the pattern's domain.
// Otherwiae, loop over all virtual domains (parent.getKeys()).
final String[] keys =
(pattern.isDomainPattern() ?
parent.getKeys() : new String[]{domain});
// Add all matching MBeans from each virtual domain
//
for (String key : keys) {
// Only invoke those virtual domain which are selected
// by the domain pattern
//
if (!all && !Util.isDomainSelected(key, domain))
continue;
try {
final MBeanServer mbs = parent.getInterceptor(key);
// mbs can be null if the interceptor was removed
// concurrently...
// See handlerMap and getKeys() in DispatchInterceptor
//
if (mbs == null) continue;
// If the domain is selected, we can replace the pattern
// by the actual domain. This is safer if we want to avoid
// a domain (which could be backed up by an MBeanServer) to
// return names from outside the domain.
// So instead of asking the domain handler for "foo" to
// return all names which match "?o*:type=Bla,*" we're
// going to ask it to return all names which match
// "foo:type=Bla,*"
//
final ObjectName subPattern = pattern.withDomain(key);
res.addAll(invoker.query(mbs, subPattern, query));
} catch (Exception x) {
LOG.finest("Ignoring exception " +
"when attempting to query namespace "+key+": "+x);
continue;
}
}
return res;
}
}
private final DefaultMBeanServerInterceptor nextInterceptor;
private final String mbeanServerName;
private final MBeanServerDelegate delegate;
/**
* Creates a DomainDispatchInterceptor with the specified
* repository instance.
*
* @param outer A pointer to the MBeanServer object that must be
* passed to the MBeans when invoking their
* {@link javax.management.MBeanRegistration} interface.
* @param delegate A pointer to the MBeanServerDelegate associated
* with the new MBeanServer. The new MBeanServer must register
* this MBean in its MBean repository.
* @param instantiator The MBeanInstantiator that will be used to
* instantiate MBeans and take care of class loading issues.
* @param repository The repository to use for this MBeanServer
*/
public DomainDispatchInterceptor(MBeanServer outer,
MBeanServerDelegate delegate,
MBeanInstantiator instantiator,
Repository repository,
NamespaceDispatchInterceptor namespaces) {
nextInterceptor = new DefaultMBeanServerInterceptor(outer,
delegate, instantiator,repository,namespaces);
mbeanServerName = Util.getMBeanServerSecurityName(delegate);
this.delegate = delegate;
}
final boolean isLocalHandlerNameFor(String domain,
ObjectName handlerName) {
if (domain == null) return true;
return handlerName.getDomain().equals(domain) &&
JMXDomain.TYPE_ASSIGNMENT.equals(
handlerName.getKeyPropertyListString());
}
@Override
void validateHandlerNameFor(String key, ObjectName name) {
super.validateHandlerNameFor(key,name);
final String[] domains = nextInterceptor.getDomains();
for (int i=0;i<domains.length;i++) {
if (domains[i].equals(key))
throw new IllegalArgumentException("domain "+key+
" is not empty");
}
}
@Override
final MBeanServer getInterceptorOrNullFor(ObjectName name) {
if (name == null) return nextInterceptor;
final String domain = name.getDomain();
if (domain.endsWith(NAMESPACE_SEPARATOR))
return nextInterceptor; // This can be a namespace handler.
if (domain.contains(NAMESPACE_SEPARATOR))
return null; // shouldn't reach here.
if (isLocalHandlerNameFor(domain,name)) {
// This is the name of a JMXDomain MBean. Return nextInterceptor.
LOG.finer("dispatching to local namespace");
return nextInterceptor;
}
final DomainInterceptor ns = getInterceptor(domain);
if (ns == null) {
// no JMXDomain found for that domain - return nextInterceptor.
if (LOG.isLoggable(Level.FINER)) {
LOG.finer("dispatching to local namespace: " + domain);
}
return getNextInterceptor();
}
if (LOG.isLoggable(Level.FINER)) {
LOG.finer("dispatching to domain: " + domain);
}
return ns;
}
// This method returns true if the given pattern must be evaluated against
// several interceptors. This happens when either:
//
// a) the pattern can select several domains (it's null, or it's a
// domain pattern)
// or b) it's not a domain pattern, but it might select the name of a
// JMXDomain MBean in charge of that domain. Since the JMXDomain
// MBean is located in the nextInterceptor, the pattern might need
// to be evaluated on two interceptors.
//
// 1. When this method returns false, the query is evaluated on a single
// interceptor:
// The interceptor for pattern.getDomain(), if there is one,
// or the next interceptor, if there is none.
//
// 2. When this method returns true, we loop over all the domain
// interceptors:
// in the list, and if the domain pattern matches the interceptor domain
// we evaluate the query on that interceptor and aggregate the results.
// Eventually we also evaluate the pattern against the next interceptor.
//
// See getInterceptorForQuery below.
//
private boolean multipleQuery(ObjectName pattern) {
// case a) above
if (pattern == null) return true;
if (pattern.isDomainPattern()) return true;
// case b) above.
//
// This is a bit of a hack. If there's any chance that a JMXDomain
// MBean name is selected by the given pattern then we must include
// the local namespace in our search.
//
// Returning true will have this effect. see 2. above.
//
if (pattern.apply(ALL_DOMAINS.withDomain(pattern.getDomain())))
return true;
return false;
}
@Override
final QueryInterceptor getInterceptorForQuery(ObjectName pattern) {
// Check if we need to aggregate.
if (multipleQuery(pattern))
return new AggregatingQueryInterceptor(this);
// We don't need to aggregate: do the "simple" thing...
final String domain = pattern.getDomain();
// Do we have a virtual domain?
final DomainInterceptor ns = getInterceptor(domain);
if (ns != null) {
if (LOG.isLoggable(Level.FINER))
LOG.finer("dispatching to domain: " + domain);
return new QueryInterceptor(ns);
}
// We don't have a virtual domain. Send to local domains.
if (LOG.isLoggable(Level.FINER))
LOG.finer("dispatching to local namespace: " + domain);
return new QueryInterceptor(nextInterceptor);
}
@Override
final ObjectName getHandlerNameFor(String key) {
return JMXDomain.getDomainObjectName(key);
}
@Override
final public String getHandlerKey(ObjectName name) {
return name.getDomain();
}
@Override
final DomainInterceptor createInterceptorFor(String key,
ObjectName name, JMXDomain handler,
Queue<Runnable> postRegisterQueue) {
final DomainInterceptor ns =
new DomainInterceptor(mbeanServerName,handler,key);
ns.addPostRegisterTask(postRegisterQueue, delegate);
if (LOG.isLoggable(Level.FINER)) {
LOG.finer("DomainInterceptor created: "+ns);
}
return ns;
}
@Override
final void interceptorReleased(DomainInterceptor interceptor,
Queue<Runnable> postDeregisterQueue) {
interceptor.addPostDeregisterTask(postDeregisterQueue, delegate);
}
@Override
final DefaultMBeanServerInterceptor getNextInterceptor() {
return nextInterceptor;
}
/**
* Returns the list of domains in which any MBean is currently
* registered.
*/
@Override
public String[] getDomains() {
// A JMXDomain is registered in its own domain.
// Therefore, nextInterceptor.getDomains() contains all domains.
// In addition, nextInterceptor will perform the necessary
// MBeanPermission checks for getDomains().
//
return nextInterceptor.getDomains();
}
/**
* Returns the number of MBeans registered in the MBean server.
*/
@Override
public Integer getMBeanCount() {
int count = getNextInterceptor().getMBeanCount();
final String[] keys = getKeys();
for (String key:keys) {
final MBeanServer mbs = getInterceptor(key);
if (mbs == null) continue;
count += mbs.getMBeanCount();
}
return count;
}
}
/*
* Copyright 2008 Sun Microsystems, Inc. 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. Sun designates this
* particular file as subject to the "Classpath" exception as provided
* by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*/
package com.sun.jmx.interceptor;
import java.io.ObjectInputStream;
import javax.management.InstanceNotFoundException;
import javax.management.MBeanException;
import javax.management.ObjectName;
import javax.management.OperationsException;
import javax.management.ReflectionException;
import javax.management.loading.ClassLoaderRepository;
/**
* An abstract class for MBeanServerInterceptorSupport.
* Some methods in MBeanServerInterceptor should never be called.
* This base class provides an implementation of these methods that simply
* throw an {@link UnsupportedOperationException}.
* <p><b>
* This API is a Sun internal API and is subject to changes without notice.
* </b></p>
* @since 1.7
*/
public abstract class MBeanServerInterceptorSupport
implements MBeanServerInterceptor {
/**
* This method should never be called.
* Throws UnsupportedOperationException.
*/
public Object instantiate(String className)
throws ReflectionException, MBeanException {
throw new UnsupportedOperationException("Not applicable.");
}
/**
* This method should never be called.
* Throws UnsupportedOperationException.
*/
public Object instantiate(String className, ObjectName loaderName)
throws ReflectionException, MBeanException,
InstanceNotFoundException {
throw new UnsupportedOperationException("Not applicable.");
}
/**
* This method should never be called.
* Throws UnsupportedOperationException.
*/
public Object instantiate(String className, Object[] params,
String[] signature) throws ReflectionException, MBeanException {
throw new UnsupportedOperationException("Not applicable.");
}
/**
* This method should never be called.
* Throws UnsupportedOperationException.
*/
public Object instantiate(String className, ObjectName loaderName,
Object[] params, String[] signature)
throws ReflectionException, MBeanException,
InstanceNotFoundException {
throw new UnsupportedOperationException("Not applicable.");
}
/**
* This method should never be called.
* Throws UnsupportedOperationException.
*/
@Deprecated
public ObjectInputStream deserialize(ObjectName name, byte[] data)
throws InstanceNotFoundException, OperationsException {
throw new UnsupportedOperationException("Not applicable.");
}
/**
* This method should never be called.
* Throws UnsupportedOperationException.
*/
@Deprecated
public ObjectInputStream deserialize(String className, byte[] data)
throws OperationsException, ReflectionException {
throw new UnsupportedOperationException("Not applicable.");
}
/**
* This method should never be called.
* Throws UnsupportedOperationException.
*/
@Deprecated
public ObjectInputStream deserialize(String className,
ObjectName loaderName, byte[] data)
throws InstanceNotFoundException, OperationsException,
ReflectionException {
throw new UnsupportedOperationException("Not applicable.");
}
/**
* This method should never be called.
* Throws UnsupportedOperationException.
*/
public ClassLoaderRepository getClassLoaderRepository() {
throw new UnsupportedOperationException("Not applicable.");
}
}
/*
* Copyright 2008 Sun Microsystems, Inc. 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. Sun designates this
* particular file as subject to the "Classpath" exception as provided
* by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*/
package com.sun.jmx.interceptor;
import com.sun.jmx.defaults.JmxProperties;
import com.sun.jmx.mbeanserver.MBeanInstantiator;
import com.sun.jmx.mbeanserver.Repository;
import com.sun.jmx.mbeanserver.Util;
import com.sun.jmx.namespace.NamespaceInterceptor;
import java.util.Queue;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.management.MBeanServer;
import javax.management.MBeanServerDelegate;
import javax.management.ObjectName;
import javax.management.RuntimeOperationsException;
import javax.management.namespace.JMXDomain;
import javax.management.namespace.JMXNamespace;
import static javax.management.namespace.JMXNamespaces.NAMESPACE_SEPARATOR;
/**
* A dispatcher that dispatches to NamespaceInterceptors.
* <p><b>
* This API is a Sun internal API and is subject to changes without notice.
* </b></p>
* @since 1.7
*/
public class NamespaceDispatchInterceptor
extends DispatchInterceptor<NamespaceInterceptor, JMXNamespace> {
/**
* A logger for this class.
**/
private static final Logger LOG = JmxProperties.NAMESPACE_LOGGER;
private static final int NAMESPACE_SEPARATOR_LENGTH =
NAMESPACE_SEPARATOR.length();
private static final ObjectName X3 = ObjectName.valueOf("x:x=x");
private final DomainDispatchInterceptor nextInterceptor;
private final String serverName;
/**
* Creates a NamespaceDispatchInterceptor with the specified
* repository instance.
* <p>Do not forget to call <code>initialize(outer,delegate)</code>
* before using this object.
*
* @param outer A pointer to the MBeanServer object that must be
* passed to the MBeans when invoking their
* {@link javax.management.MBeanRegistration} interface.
* @param delegate A pointer to the MBeanServerDelegate associated
* with the new MBeanServer. The new MBeanServer must register
* this MBean in its MBean repository.
* @param instantiator The MBeanInstantiator that will be used to
* instantiate MBeans and take care of class loading issues.
* @param repository The repository to use for this MBeanServer
*/
public NamespaceDispatchInterceptor(MBeanServer outer,
MBeanServerDelegate delegate,
MBeanInstantiator instantiator,
Repository repository) {
nextInterceptor = new DomainDispatchInterceptor(outer,delegate,
instantiator,repository,this);
serverName = Util.getMBeanServerSecurityName(delegate);
}
/**
* Get first name space in ObjectName path. Ignore leading namespace
* separators. Includes the trailing //.
*
* Examples:
* <pre>
* For ObjectName: Returns:
* foo//bar//baz:x=x -> "foo//"
* foo//:type=JMXNamespace -> "foo//"
* foo//:x=x -> "foo//"
* foo////:x=x -> "foo//"
* //foo//bar//baz:x=x -> "//"
* ////foo//bar//baz:x=x -> "//"
* //:x=x -> "//"
* foo:x=x -> ""
* (null) -> ""
* :x=x -> ""
*
* </pre>
**/
static String getFirstNamespaceWithSlash(ObjectName name) {
if (name == null) return "";
final String domain = name.getDomain();
if (domain.equals("")) return "";
// go to next separator
final int end = domain.indexOf(NAMESPACE_SEPARATOR);
if (end == -1) return ""; // no namespace
// This is the first element in the namespace path.
final String namespace =
domain.substring(0,end+NAMESPACE_SEPARATOR_LENGTH);
return namespace;
}
/**
* Called by the DefaultMBeanServerInterceptor, just before adding an
* MBean to the repository.
*
* @param resource the MBean to be registered.
* @param logicalName the name of the MBean to be registered.
*/
final void checkLocallyRegistrable(Object resource,
ObjectName logicalName) {
if (!(resource instanceof JMXNamespace) &&
logicalName.getDomain().contains(NAMESPACE_SEPARATOR))
throw new IllegalArgumentException(String.valueOf(logicalName)+
": Invalid ObjectName for an instance of " +
resource.getClass().getName());
}
// Removes the trailing //. namespaceWithSlash should be either
// "" or a namespace path ending with //.
//
private final String getKeyFor(String namespaceWithSlash) {
final int end = namespaceWithSlash.length() -
NAMESPACE_SEPARATOR_LENGTH;
if (end <= 0) return "";
final String key = namespaceWithSlash.substring(0,end);
return key;
}
@Override
final MBeanServer getInterceptorOrNullFor(ObjectName name) {
final String namespace = getFirstNamespaceWithSlash(name);
// Leading separators should trigger instance not found exception.
// returning null here has this effect.
//
if (namespace.equals(NAMESPACE_SEPARATOR)) {
LOG.finer("ObjectName starts with: "+namespace);
return null;
}
// namespace="" means that there was no namespace path in the
// ObjectName. => delegate to the next interceptor (local MBS)
// name.getDomain()=namespace means that we have an ObjectName of
// the form blah//:x=x. This is either a JMXNamespace or a non
// existent MBean. => delegate to the next interceptor (local MBS)
if (namespace.equals("") || name.getDomain().equals(namespace)) {
LOG.finer("dispatching to local name space");
return nextInterceptor;
}
// There was a namespace path in the ObjectName. Returns the
// interceptor that handles it, or null if there is no such
// interceptor.
final String key = getKeyFor(namespace);
final NamespaceInterceptor ns = getInterceptor(key);
if (LOG.isLoggable(Level.FINER)) {
if (ns != null) {
LOG.finer("dispatching to name space: " + key);
} else {
LOG.finer("no handler for: " + key);
}
}
return ns;
}
@Override
final QueryInterceptor getInterceptorForQuery(ObjectName pattern) {
final String namespace = getFirstNamespaceWithSlash(pattern);
// Leading separators should trigger instance not found exception.
// returning null here has this effect.
//
if (namespace.equals(NAMESPACE_SEPARATOR)) {
LOG.finer("ObjectName starts with: "+namespace);
return null;
}
// namespace="" means that there was no namespace path in the
// ObjectName. => delegate to the next interceptor (local MBS)
// name.getDomain()=namespace means that we have an ObjectName of
// the form blah//:x=x. This is either a JMXNamespace or a non
// existent MBean. => delegate to the next interceptor (local MBS)
if (namespace.equals("") || pattern.getDomain().equals(namespace)) {
LOG.finer("dispatching to local name space");
return new QueryInterceptor(nextInterceptor);
}
// This is a 'hack' to check whether the first namespace is a pattern.
// We wan to throw RTOE wrapping IAE in that case
if (X3.withDomain(namespace).isDomainPattern()) {
throw new RuntimeOperationsException(
new IllegalArgumentException("Pattern not allowed in namespace path"));
}
// There was a namespace path in the ObjectName. Returns the
// interceptor that handles it, or null if there is no such
// interceptor.
//
final String key = getKeyFor(namespace);
final NamespaceInterceptor ns = getInterceptor(key);
if (LOG.isLoggable(Level.FINER)) {
if (ns != null) {
LOG.finer("dispatching to name space: " + key);
} else {
LOG.finer("no handler for: " + key);
}
}
if (ns == null) return null;
return new QueryInterceptor(ns);
}
@Override
final ObjectName getHandlerNameFor(String key) {
return ObjectName.valueOf(key+NAMESPACE_SEPARATOR,
"type", JMXNamespace.TYPE);
}
@Override
final public String getHandlerKey(ObjectName name) {
final String namespace = getFirstNamespaceWithSlash(name);
// namespace is either "" or a namespace ending with //
return getKeyFor(namespace);
}
@Override
final NamespaceInterceptor createInterceptorFor(String key,
ObjectName name, JMXNamespace handler,
Queue<Runnable> postRegisterQueue) {
final NamespaceInterceptor ns =
new NamespaceInterceptor(serverName,handler,key);
if (LOG.isLoggable(Level.FINER)) {
LOG.finer("NamespaceInterceptor created: "+ns);
}
return ns;
}
@Override
final DomainDispatchInterceptor getNextInterceptor() {
return nextInterceptor;
}
/**
* Returns the list of domains in which any MBean is currently
* registered.
*/
@Override
public String[] getDomains() {
return nextInterceptor.getDomains();
}
@Override
public void addInterceptorFor(ObjectName name, JMXNamespace handler,
Queue<Runnable> postRegisterQueue) {
if (handler instanceof JMXDomain)
nextInterceptor.addInterceptorFor(name,
(JMXDomain)handler,postRegisterQueue);
else super.addInterceptorFor(name,handler,postRegisterQueue);
}
@Override
public void removeInterceptorFor(ObjectName name, JMXNamespace handler,
Queue<Runnable> postDeregisterQueue) {
if (handler instanceof JMXDomain)
nextInterceptor.removeInterceptorFor(name,(JMXDomain)handler,
postDeregisterQueue);
else super.removeInterceptorFor(name,handler,postDeregisterQueue);
}
}
/*
* Copyright 2008 Sun Microsystems, Inc. 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. Sun designates this
* particular file as subject to the "Classpath" exception as provided
* by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*/
package com.sun.jmx.interceptor;
import com.sun.jmx.mbeanserver.Util;
import java.util.Arrays;
import java.util.Collections;
import java.util.Set;
import java.util.TreeSet;
import javax.management.Attribute;
import javax.management.AttributeList;
import javax.management.AttributeNotFoundException;
import javax.management.DynamicMBean;
import javax.management.InstanceAlreadyExistsException;
import javax.management.InstanceNotFoundException;
import javax.management.IntrospectionException;
import javax.management.InvalidAttributeValueException;
import javax.management.ListenerNotFoundException;
import javax.management.MBeanException;
import javax.management.MBeanInfo;
import javax.management.MBeanRegistrationException;
import javax.management.MBeanServer;
import javax.management.NotCompliantMBeanException;
import javax.management.NotificationEmitter;
import javax.management.NotificationFilter;
import javax.management.NotificationListener;
import javax.management.ObjectInstance;
import javax.management.ObjectName;
import javax.management.QueryExp;
import javax.management.ReflectionException;
import javax.management.namespace.JMXNamespaces;
import javax.management.namespace.MBeanServerSupport;
import javax.management.remote.IdentityMBeanServerForwarder;
/**
* <p>An {@link MBeanServerForwarder} that simulates the existence of a
* given MBean. Requests for that MBean, call it X, are intercepted by the
* forwarder, and requests for any other MBean are forwarded to the next
* forwarder in the chain. Requests such as queryNames which can span both the
* X and other MBeans are handled by merging the results for X with the results
* from the next forwarder, unless the "visible" parameter is false, in which
* case X is invisible to such requests.</p>
*/
public class SingleMBeanForwarder extends IdentityMBeanServerForwarder {
private final ObjectName mbeanName;
private final boolean visible;
private DynamicMBean mbean;
private MBeanServer mbeanMBS = new MBeanServerSupport() {
@Override
public DynamicMBean getDynamicMBeanFor(ObjectName name)
throws InstanceNotFoundException {
if (mbeanName.equals(name)) {
return mbean;
} else {
throw new InstanceNotFoundException(name.toString());
}
}
@Override
protected Set<ObjectName> getNames() {
return Collections.singleton(mbeanName);
}
@Override
public NotificationEmitter getNotificationEmitterFor(
ObjectName name) {
if (mbean instanceof NotificationEmitter)
return (NotificationEmitter) mbean;
return null;
}
// This will only be called if mbeanName has an empty domain.
// In that case a getAttribute (e.g.) of that name will have the
// domain replaced by MBeanServerSupport with the default domain,
// so we must be sure that the default domain is empty too.
@Override
public String getDefaultDomain() {
return mbeanName.getDomain();
}
};
public SingleMBeanForwarder(
ObjectName mbeanName, DynamicMBean mbean, boolean visible) {
this.mbeanName = mbeanName;
this.visible = visible;
setSingleMBean(mbean);
}
protected void setSingleMBean(DynamicMBean mbean) {
this.mbean = mbean;
}
@Override
public void addNotificationListener(ObjectName name, ObjectName listener,
NotificationFilter filter,
Object handback)
throws InstanceNotFoundException {
if (mbeanName.equals(name))
mbeanMBS.addNotificationListener(name, listener, filter, handback);
else
super.addNotificationListener(name, listener, filter, handback);
}
@Override
public void addNotificationListener(ObjectName name,
NotificationListener listener,
NotificationFilter filter,
Object handback)
throws InstanceNotFoundException {
if (mbeanName.equals(name))
mbeanMBS.addNotificationListener(name, listener, filter, handback);
else
super.addNotificationListener(name, listener, filter, handback);
}
@Override
public ObjectInstance createMBean(String className, ObjectName name,
ObjectName loaderName, Object[] params,
String[] signature)
throws ReflectionException,
InstanceAlreadyExistsException,
MBeanRegistrationException,
MBeanException,
NotCompliantMBeanException,
InstanceNotFoundException {
if (mbeanName.equals(name))
throw new InstanceAlreadyExistsException(mbeanName.toString());
else
return super.createMBean(className, name, loaderName, params, signature);
}
@Override
public ObjectInstance createMBean(String className, ObjectName name,
Object[] params, String[] signature)
throws ReflectionException, InstanceAlreadyExistsException,
MBeanRegistrationException, MBeanException,
NotCompliantMBeanException {
if (mbeanName.equals(name))
throw new InstanceAlreadyExistsException(mbeanName.toString());
return super.createMBean(className, name, params, signature);
}
@Override
public ObjectInstance createMBean(String className, ObjectName name,
ObjectName loaderName)
throws ReflectionException,
InstanceAlreadyExistsException,
MBeanRegistrationException,
MBeanException,
NotCompliantMBeanException,
InstanceNotFoundException {
if (mbeanName.equals(name))
throw new InstanceAlreadyExistsException(mbeanName.toString());
return super.createMBean(className, name, loaderName);
}
@Override
public ObjectInstance createMBean(String className, ObjectName name)
throws ReflectionException,
InstanceAlreadyExistsException,
MBeanRegistrationException,
MBeanException,
NotCompliantMBeanException {
if (mbeanName.equals(name))
throw new InstanceAlreadyExistsException(mbeanName.toString());
return super.createMBean(className, name);
}
@Override
public Object getAttribute(ObjectName name, String attribute)
throws MBeanException,
AttributeNotFoundException,
InstanceNotFoundException,
ReflectionException {
if (mbeanName.equals(name))
return mbeanMBS.getAttribute(name, attribute);
else
return super.getAttribute(name, attribute);
}
@Override
public AttributeList getAttributes(ObjectName name, String[] attributes)
throws InstanceNotFoundException, ReflectionException {
if (mbeanName.equals(name))
return mbeanMBS.getAttributes(name, attributes);
else
return super.getAttributes(name, attributes);
}
@Override
public ClassLoader getClassLoader(ObjectName loaderName)
throws InstanceNotFoundException {
if (mbeanName.equals(loaderName))
return mbeanMBS.getClassLoader(loaderName);
else
return super.getClassLoader(loaderName);
}
@Override
public ClassLoader getClassLoaderFor(ObjectName name)
throws InstanceNotFoundException {
if (mbeanName.equals(name))
return mbeanMBS.getClassLoaderFor(name);
else
return super.getClassLoaderFor(name);
}
@Override
public String[] getDomains() {
String[] domains = super.getDomains();
if (!visible)
return domains;
TreeSet<String> domainSet = new TreeSet<String>(Arrays.asList(domains));
domainSet.add(mbeanName.getDomain());
return domainSet.toArray(new String[domainSet.size()]);
}
@Override
public Integer getMBeanCount() {
Integer count = super.getMBeanCount();
if (visible && !super.isRegistered(mbeanName))
count++;
return count;
}
@Override
public MBeanInfo getMBeanInfo(ObjectName name)
throws InstanceNotFoundException,
IntrospectionException,
ReflectionException {
if (mbeanName.equals(name))
return mbeanMBS.getMBeanInfo(name);
else
return super.getMBeanInfo(name);
}
@Override
public ObjectInstance getObjectInstance(ObjectName name)
throws InstanceNotFoundException {
if (mbeanName.equals(name))
return mbeanMBS.getObjectInstance(name);
else
return super.getObjectInstance(name);
}
@Override
public Object invoke(ObjectName name, String operationName, Object[] params,
String[] signature)
throws InstanceNotFoundException,
MBeanException,
ReflectionException {
if (mbeanName.equals(name))
return mbeanMBS.invoke(name, operationName, params, signature);
else
return super.invoke(name, operationName, params, signature);
}
@Override
public boolean isInstanceOf(ObjectName name, String className)
throws InstanceNotFoundException {
if (mbeanName.equals(name))
return mbeanMBS.isInstanceOf(name, className);
else
return super.isInstanceOf(name, className);
}
@Override
public boolean isRegistered(ObjectName name) {
if (mbeanName.equals(name))
return true;
else
return super.isRegistered(name);
}
/**
* This is a ugly hack. Although jmx.context//*:* matches jmx.context//:*
* queryNames(jmx.context//*:*,null) must not return jmx.context//:*
* @param pattern the pattern to match against. must not be null.
* @return true if mbeanName can be included, false if it must not.
*/
private boolean applies(ObjectName pattern) {
// we know pattern is not null.
if (!visible || !pattern.apply(mbeanName))
return false;
final String dompat = pattern.getDomain();
if (!dompat.contains(JMXNamespaces.NAMESPACE_SEPARATOR))
return true; // We already checked that patterns apply.
if (mbeanName.getDomain().endsWith(JMXNamespaces.NAMESPACE_SEPARATOR)) {
// only matches if pattern ends with //
return dompat.endsWith(JMXNamespaces.NAMESPACE_SEPARATOR);
}
// should not come here, unless mbeanName contains a // in the
// middle of its domain, which would be weird.
// let query on mbeanMBS proceed and take care of that.
//
return true;
}
@Override
public Set<ObjectInstance> queryMBeans(ObjectName name, QueryExp query) {
Set<ObjectInstance> names = super.queryMBeans(name, query);
if (visible) {
if (name == null || applies(name) ) {
// Don't assume mbs.queryNames returns a writable set.
names = Util.cloneSet(names);
names.addAll(mbeanMBS.queryMBeans(name, query));
}
}
return names;
}
@Override
public Set<ObjectName> queryNames(ObjectName name, QueryExp query) {
Set<ObjectName> names = super.queryNames(name, query);
if (visible) {
if (name == null || applies(name)) {
// Don't assume mbs.queryNames returns a writable set.
names = Util.cloneSet(names);
names.addAll(mbeanMBS.queryNames(name, query));
}
}
return names;
}
@Override
public ObjectInstance registerMBean(Object object, ObjectName name)
throws InstanceAlreadyExistsException,
MBeanRegistrationException,
NotCompliantMBeanException {
if (mbeanName.equals(name))
throw new InstanceAlreadyExistsException(mbeanName.toString());
else
return super.registerMBean(object, name);
}
@Override
public void removeNotificationListener(ObjectName name,
NotificationListener listener,
NotificationFilter filter,
Object handback)
throws InstanceNotFoundException,
ListenerNotFoundException {
if (mbeanName.equals(name))
mbeanMBS.removeNotificationListener(name, listener, filter, handback);
else
super.removeNotificationListener(name, listener, filter, handback);
}
@Override
public void removeNotificationListener(ObjectName name,
NotificationListener listener)
throws InstanceNotFoundException, ListenerNotFoundException {
if (mbeanName.equals(name))
mbeanMBS.removeNotificationListener(name, listener);
else
super.removeNotificationListener(name, listener);
}
@Override
public void removeNotificationListener(ObjectName name, ObjectName listener,
NotificationFilter filter,
Object handback)
throws InstanceNotFoundException,
ListenerNotFoundException {
if (mbeanName.equals(name))
mbeanMBS.removeNotificationListener(name, listener, filter, handback);
else
super.removeNotificationListener(name, listener, filter, handback);
}
@Override
public void removeNotificationListener(ObjectName name, ObjectName listener)
throws InstanceNotFoundException, ListenerNotFoundException {
if (mbeanName.equals(name))
mbeanMBS.removeNotificationListener(name, listener);
else
super.removeNotificationListener(name, listener);
}
@Override
public void setAttribute(ObjectName name, Attribute attribute)
throws InstanceNotFoundException,
AttributeNotFoundException,
InvalidAttributeValueException,
MBeanException,
ReflectionException {
if (mbeanName.equals(name))
mbeanMBS.setAttribute(name, attribute);
else
super.setAttribute(name, attribute);
}
@Override
public AttributeList setAttributes(ObjectName name,
AttributeList attributes)
throws InstanceNotFoundException, ReflectionException {
if (mbeanName.equals(name))
return mbeanMBS.setAttributes(name, attributes);
else
return super.setAttributes(name, attributes);
}
@Override
public void unregisterMBean(ObjectName name)
throws InstanceNotFoundException,
MBeanRegistrationException {
if (mbeanName.equals(name))
mbeanMBS.unregisterMBean(name);
else
super.unregisterMBean(name);
}
}
......@@ -31,15 +31,13 @@ import java.lang.reflect.Type;
import javax.management.Descriptor;
import javax.management.MBeanException;
import javax.management.openmbean.MXBeanMapping;
import javax.management.openmbean.MXBeanMappingFactory;
import javax.management.openmbean.OpenDataException;
import javax.management.openmbean.OpenType;
final class ConvertingMethod {
static ConvertingMethod from(Method m, MXBeanMappingFactory mappingFactory) {
static ConvertingMethod from(Method m) {
try {
return new ConvertingMethod(m, mappingFactory);
return new ConvertingMethod(m);
} catch (OpenDataException ode) {
final String msg = "Method " + m.getDeclaringClass().getName() +
"." + m.getName() + " has parameter or return type that " +
......@@ -53,7 +51,7 @@ final class ConvertingMethod {
}
Descriptor getDescriptor() {
return Introspector.descriptorForElement(method, false);
return Introspector.descriptorForElement(method);
}
Type getGenericReturnType() {
......@@ -206,9 +204,9 @@ final class ConvertingMethod {
return method.getDeclaringClass() + "." + method.getName();
}
private ConvertingMethod(Method m, MXBeanMappingFactory mappingFactory)
throws OpenDataException {
private ConvertingMethod(Method m) throws OpenDataException {
this.method = m;
MXBeanMappingFactory mappingFactory = MXBeanMappingFactory.DEFAULT;
returnMapping =
mappingFactory.mappingForType(m.getGenericReturnType(), mappingFactory);
Type[] params = m.getGenericParameterTypes();
......
......@@ -28,8 +28,6 @@ package com.sun.jmx.mbeanserver;
import static com.sun.jmx.mbeanserver.Util.*;
import static com.sun.jmx.mbeanserver.MXBeanIntrospector.typeName;
import javax.management.openmbean.MXBeanMappingClass;
import static javax.management.openmbean.SimpleType.*;
import com.sun.jmx.remote.util.EnvHelp;
......@@ -69,8 +67,6 @@ import javax.management.openmbean.CompositeDataInvocationHandler;
import javax.management.openmbean.CompositeDataSupport;
import javax.management.openmbean.CompositeDataView;
import javax.management.openmbean.CompositeType;
import javax.management.openmbean.MXBeanMapping;
import javax.management.openmbean.MXBeanMappingFactory;
import javax.management.openmbean.OpenDataException;
import javax.management.openmbean.OpenType;
import javax.management.openmbean.SimpleType;
......@@ -165,34 +161,29 @@ public class DefaultMXBeanMappingFactory extends MXBeanMappingFactory {
private static final class Mappings
extends WeakHashMap<Type, WeakReference<MXBeanMapping>> {}
private static final Map<MXBeanMappingFactory, Mappings> factoryMappings =
new WeakHashMap<MXBeanMappingFactory, Mappings>();
private static final Mappings mappings = new Mappings();
private static final Map<Type, MXBeanMapping> permanentMappings = newMap();
/** Following List simply serves to keep a reference to predefined
MXBeanMappings so they don't get garbage collected. */
private static final List<MXBeanMapping> permanentMappings = newList();
private static synchronized MXBeanMapping getMapping(
Type type, MXBeanMappingFactory factory) {
Mappings mappings = factoryMappings.get(factory);
if (mappings == null) {
mappings = new Mappings();
factoryMappings.put(factory, mappings);
}
private static synchronized MXBeanMapping getMapping(Type type) {
WeakReference<MXBeanMapping> wr = mappings.get(type);
return (wr == null) ? null : wr.get();
}
private static synchronized void putMapping(
Type type, MXBeanMapping mapping, MXBeanMappingFactory factory) {
Mappings mappings = factoryMappings.get(factory);
if (mappings == null) {
mappings = new Mappings();
factoryMappings.put(factory, mappings);
}
private static synchronized void putMapping(Type type, MXBeanMapping mapping) {
WeakReference<MXBeanMapping> wr =
new WeakReference<MXBeanMapping>(mapping);
mappings.put(type, wr);
}
private static synchronized void putPermanentMapping(
Type type, MXBeanMapping mapping) {
putMapping(type, mapping);
permanentMappings.add(mapping);
}
static {
/* Set up the mappings for Java types that map to SimpleType. */
......@@ -213,7 +204,7 @@ public class DefaultMXBeanMappingFactory extends MXBeanMappingFactory {
throw new Error(e);
}
final MXBeanMapping mapping = new IdentityMapping(c, t);
permanentMappings.put(c, mapping);
putPermanentMapping(c, mapping);
if (c.getName().startsWith("java.lang.")) {
try {
......@@ -221,7 +212,7 @@ public class DefaultMXBeanMappingFactory extends MXBeanMappingFactory {
final Class<?> primitiveType = (Class<?>) typeField.get(null);
final MXBeanMapping primitiveMapping =
new IdentityMapping(primitiveType, t);
permanentMappings.put(primitiveType, primitiveMapping);
putPermanentMapping(primitiveType, primitiveMapping);
if (primitiveType != void.class) {
final Class<?> primitiveArrayType =
Array.newInstance(primitiveType, 0).getClass();
......@@ -230,8 +221,8 @@ public class DefaultMXBeanMappingFactory extends MXBeanMappingFactory {
final MXBeanMapping primitiveArrayMapping =
new IdentityMapping(primitiveArrayType,
primitiveArrayOpenType);
permanentMappings.put(primitiveArrayType,
primitiveArrayMapping);
putPermanentMapping(primitiveArrayType,
primitiveArrayMapping);
}
} catch (NoSuchFieldException e) {
// OK: must not be a primitive wrapper
......@@ -255,7 +246,7 @@ public class DefaultMXBeanMappingFactory extends MXBeanMappingFactory {
MXBeanMapping mapping;
mapping = getMapping(objType, null);
mapping = getMapping(objType);
if (mapping != null)
return mapping;
......@@ -268,7 +259,7 @@ public class DefaultMXBeanMappingFactory extends MXBeanMappingFactory {
inProgress.remove(objType);
}
putMapping(objType, mapping, factory);
putMapping(objType, mapping);
return mapping;
}
......@@ -278,14 +269,6 @@ public class DefaultMXBeanMappingFactory extends MXBeanMappingFactory {
/* It's not yet worth formalizing these tests by having for example
an array of factory classes, each of which says whether it
recognizes the Type (Chain of Responsibility pattern). */
MXBeanMapping mapping = permanentMappings.get(objType);
if (mapping != null)
return mapping;
Class<?> erasure = erasure(objType);
MXBeanMappingClass mappingClass =
erasure.getAnnotation(MXBeanMappingClass.class);
if (mappingClass != null)
return makeAnnotationMapping(mappingClass, objType, factory);
if (objType instanceof GenericArrayType) {
Type componentType =
((GenericArrayType) objType).getGenericComponentType();
......@@ -313,51 +296,6 @@ public class DefaultMXBeanMappingFactory extends MXBeanMappingFactory {
throw new OpenDataException("Cannot map type: " + objType);
}
private static MXBeanMapping
makeAnnotationMapping(MXBeanMappingClass mappingClass,
Type objType,
MXBeanMappingFactory factory)
throws OpenDataException {
Class<? extends MXBeanMapping> c = mappingClass.value();
Constructor<? extends MXBeanMapping> cons;
try {
cons = c.getConstructor(Type.class);
} catch (NoSuchMethodException e) {
final String msg =
"Annotation @" + MXBeanMappingClass.class.getName() +
" must name a class with a public constructor that has a " +
"single " + Type.class.getName() + " argument";
OpenDataException ode = new OpenDataException(msg);
ode.initCause(e);
throw ode;
}
try {
return cons.newInstance(objType);
} catch (Exception e) {
final String msg =
"Could not construct a " + c.getName() + " for @" +
MXBeanMappingClass.class.getName();
OpenDataException ode = new OpenDataException(msg);
ode.initCause(e);
throw ode;
}
}
private static Class<?> erasure(Type t) {
if (t instanceof Class<?>)
return (Class<?>) t;
if (t instanceof ParameterizedType)
return erasure(((ParameterizedType) t).getRawType());
/* Other cases: GenericArrayType, TypeVariable, WildcardType.
* Returning the erasure of GenericArrayType is not necessary because
* anyway we will be recursing on the element type, and we'll erase
* then. Returning the erasure of the other two would mean returning
* the type bound (e.g. Foo in <T extends Foo> or <? extends Foo>)
* and since we don't treat this as Foo elsewhere we shouldn't here.
*/
return Object.class;
}
private static <T extends Enum<T>> MXBeanMapping
makeEnumMapping(Class<?> enumClass, Class<T> fake) {
return new EnumMapping<T>(Util.<Class<T>>cast(enumClass));
......
/*
* Copyright 2005-2008 Sun Microsystems, Inc. All Rights Reserved.
* Copyright 2005 Sun Microsystems, Inc. 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
......@@ -25,7 +25,7 @@
package com.sun.jmx.mbeanserver;
import javax.management.DynamicWrapperMBean;
import javax.management.DynamicMBean;
import javax.management.MBeanServer;
import javax.management.ObjectName;
......@@ -35,7 +35,17 @@ import javax.management.ObjectName;
*
* @since 1.6
*/
public interface DynamicMBean2 extends DynamicWrapperMBean {
public interface DynamicMBean2 extends DynamicMBean {
/**
* The resource corresponding to this MBean. This is the object whose
* class name should be reflected by the MBean's
* getMBeanInfo().getClassName() for example. For a "plain"
* DynamicMBean it will be "this". For an MBean that wraps another
* object, like javax.management.StandardMBean, it will be the wrapped
* object.
*/
public Object getResource();
/**
* The name of this MBean's class, as used by permission checks.
* This is typically equal to getResource().getClass().getName().
......
......@@ -25,14 +25,9 @@
package com.sun.jmx.mbeanserver;
import com.sun.jmx.remote.util.EnvHelp;
import java.beans.BeanInfo;
import java.beans.PropertyDescriptor;
import java.lang.annotation.Annotation;
import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.Proxy;
......@@ -40,39 +35,21 @@ import java.lang.reflect.UndeclaredThrowableException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Level;
import javax.management.AttributeNotFoundException;
import javax.management.Description;
import javax.management.Descriptor;
import javax.management.DescriptorFields;
import javax.management.DescriptorKey;
import javax.management.DynamicMBean;
import javax.management.ImmutableDescriptor;
import javax.management.MBean;
import javax.management.MBeanInfo;
import javax.management.MXBean;
import javax.management.NotCompliantMBeanException;
import javax.management.openmbean.CompositeData;
import javax.management.openmbean.MXBeanMappingFactory;
import static com.sun.jmx.defaults.JmxProperties.MBEANSERVER_LOGGER;
import com.sun.jmx.mbeanserver.Util;
import com.sun.jmx.remote.util.EnvHelp;
import java.beans.BeanInfo;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Array;
import java.lang.reflect.InvocationTargetException;
import java.util.LinkedHashSet;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.management.AttributeNotFoundException;
import javax.management.JMX;
import javax.management.ObjectName;
import javax.management.ObjectNameTemplate;
import javax.management.openmbean.CompositeData;
import javax.management.openmbean.MXBeanMappingFactory;
/**
* This class contains the methods for performing all the tests needed to verify
......@@ -82,13 +59,7 @@ import javax.management.openmbean.MXBeanMappingFactory;
*/
public class Introspector {
/**
* Pattern used to extract Attribute Names from ObjectNameTemplate Annotation
* For example, in the following example, the Name attribute value is
* retrieved : ":type=MyType, name={Name}"
*/
private static Pattern OBJECT_NAME_PATTERN_TEMPLATE =
Pattern.compile("(\\{[^\\}]+\\})|(=\"\\{[^\\}]+\\}\")");
/*
* ------------------------------------------
* PRIVATE CONSTRUCTORS
......@@ -164,10 +135,6 @@ public class Introspector {
public static void checkCompliance(Class<?> mbeanClass)
throws NotCompliantMBeanException {
// Check that @Resource is used correctly (if it used).
MBeanInjector.validate(mbeanClass);
// Is DynamicMBean?
//
if (DynamicMBean.class.isAssignableFrom(mbeanClass))
......@@ -190,36 +157,16 @@ public class Introspector {
} catch (NotCompliantMBeanException e) {
mxbeanException = e;
}
// Is @MBean or @MXBean class?
// In fact we find @MBean or @MXBean as a hacky variant of
// getStandardMBeanInterface or getMXBeanInterface. If we get here
// then nothing worked.
final String msg =
"MBean class " + mbeanClass.getName() + " does not implement " +
"DynamicMBean; does not follow the Standard MBean conventions (" +
mbeanException.toString() + "); does not follow the MXBean conventions (" +
mxbeanException.toString() + "); and does not have or inherit the @" +
MBean.class.getSimpleName() + " or @" + MXBean.class.getSimpleName() +
" annotation";
"DynamicMBean, and neither follows the Standard MBean conventions (" +
mbeanException.toString() + ") nor the MXBean conventions (" +
mxbeanException.toString() + ")";
throw new NotCompliantMBeanException(msg);
}
/**
* <p>Make a DynamicMBean out of the existing MBean object. The object
* may already be a DynamicMBean, or it may be a Standard MBean or
* MXBean, possibly defined using {@code @MBean} or {@code @MXBean}.</p>
* @param mbean the object to convert to a DynamicMBean.
* @param <T> a type parameter defined for implementation convenience
* (which would have to be removed if this method were part of the public
* API).
* @return the converted DynamicMBean.
* @throws NotCompliantMBeanException if {@code mbean} is not a compliant
* MBean object, including the case where it is null.
*/
public static <T> DynamicMBean makeDynamicMBean(T mbean)
throws NotCompliantMBeanException {
if (mbean == null)
throw new NotCompliantMBeanException("Null MBean object");
throws NotCompliantMBeanException {
if (mbean instanceof DynamicMBean)
return (DynamicMBean) mbean;
final Class<?> mbeanClass = mbean.getClass();
......@@ -240,18 +187,8 @@ public class Introspector {
// to be an MBean or an MXBean. We will call checkCompliance()
// to generate the appropriate exception.
}
if (c != null) {
MXBeanMappingFactory factory;
try {
factory = MXBeanMappingFactory.forInterface(c);
} catch (IllegalArgumentException e) {
NotCompliantMBeanException ncmbe =
new NotCompliantMBeanException(e.getMessage());
ncmbe.initCause(e);
throw ncmbe;
}
return new MXBeanSupport(mbean, c, factory);
}
if (c != null)
return new MXBeanSupport(mbean, c);
checkCompliance(mbeanClass);
throw new NotCompliantMBeanException("Not compliant"); // not reached
}
......@@ -280,10 +217,9 @@ public class Introspector {
return testCompliance(baseClass, null);
}
public static void testComplianceMXBeanInterface(Class<?> interfaceClass,
MXBeanMappingFactory factory)
public static void testComplianceMXBeanInterface(Class<?> interfaceClass)
throws NotCompliantMBeanException {
MXBeanIntrospector.getInstance(factory).getAnalyzer(interfaceClass);
MXBeanIntrospector.getInstance().getAnalyzer(interfaceClass);
}
/**
......@@ -352,8 +288,6 @@ public class Introspector {
*/
public static <T> Class<? super T> getStandardMBeanInterface(Class<T> baseClass)
throws NotCompliantMBeanException {
if (baseClass.isAnnotationPresent(MBean.class))
return baseClass;
Class<? super T> current = baseClass;
Class<? super T> mbeanInterface = null;
while (current != null) {
......@@ -384,8 +318,6 @@ public class Introspector {
*/
public static <T> Class<? super T> getMXBeanInterface(Class<T> baseClass)
throws NotCompliantMBeanException {
if (hasMXBeanAnnotation(baseClass))
return baseClass;
try {
return MXBeanSupport.findMXBeanInterface(baseClass);
} catch (Exception e) {
......@@ -393,61 +325,12 @@ public class Introspector {
}
}
public static <T> Class<? super T> getStandardOrMXBeanInterface(
Class<T> baseClass, boolean mxbean)
throws NotCompliantMBeanException {
if (mxbean)
return getMXBeanInterface(baseClass);
else
return getStandardMBeanInterface(baseClass);
}
public static ObjectName templateToObjectName(Descriptor descriptor,
DynamicMBean mbean)
throws NotCompliantMBeanException {
String template = (String)
descriptor.getFieldValue(JMX.OBJECT_NAME_TEMPLATE);
if(template == null) return null;
try {
Matcher m = OBJECT_NAME_PATTERN_TEMPLATE.matcher(template);
while (m.find()){
String grp = m.group();
System.out.println("GROUP " + grp);
String attributeName = null;
boolean quote = false;
if(grp.startsWith("=\"{")) {
attributeName = grp.substring(3, grp.length() - 2);
quote = true;
} else
attributeName = grp.substring(1, grp.length() - 1);
Object attributeValue = mbean.getAttribute(attributeName);
String validValue = quote ?
"=" + ObjectName.quote(attributeValue.toString()) :
attributeValue.toString();
template = template.replace(grp, validValue);
}
return new ObjectName(template);
}catch(Exception ex) {
NotCompliantMBeanException ncex = new
NotCompliantMBeanException(ObjectNameTemplate.class.
getSimpleName() + " annotation value [" + template + "] " +
"is invalid. " + ex);
ncex.initCause(ex);
throw ncex;
}
}
/*
* ------------------------------------------
* PRIVATE METHODS
* ------------------------------------------
*/
static boolean hasMXBeanAnnotation(Class<?> c) {
MXBean m = c.getAnnotation(MXBean.class);
return (m != null && m.value());
}
/**
* Try to find the MBean interface corresponding to the class aName
......@@ -469,77 +352,11 @@ public class Introspector {
return null;
}
public static String descriptionForElement(AnnotatedElement elmt) {
if (elmt == null)
return null;
Description d = elmt.getAnnotation(Description.class);
if (d == null)
return null;
return d.value();
}
public static String descriptionForParameter(
Annotation[] parameterAnnotations) {
for (Annotation a : parameterAnnotations) {
if (a instanceof Description)
return ((Description) a).value();
}
return null;
}
public static String nameForParameter(
Annotation[] parameterAnnotations) {
for (Annotation a : parameterAnnotations) {
Class<? extends Annotation> ac = a.annotationType();
// You'd really have to go out of your way to have more than
// one @Name annotation, so we don't check for that.
if (ac.getSimpleName().equals("Name")) {
try {
Method value = ac.getMethod("value");
if (value.getReturnType() == String.class &&
value.getParameterTypes().length == 0) {
return (String) value.invoke(a);
}
} catch (Exception e) {
MBEANSERVER_LOGGER.log(
Level.WARNING,
"Unexpected exception getting @" + ac.getName(),
e);
}
}
}
return null;
}
public static Descriptor descriptorForElement(final AnnotatedElement elmt,
boolean isSetter) {
public static Descriptor descriptorForElement(final AnnotatedElement elmt) {
if (elmt == null)
return ImmutableDescriptor.EMPTY_DESCRIPTOR;
final Annotation[] annots = elmt.getAnnotations();
Descriptor descr = descriptorForAnnotations(annots);
String[] exceptions = {};
if(elmt instanceof Method)
exceptions = getAllExceptions(((Method) elmt).getExceptionTypes());
else
if(elmt instanceof Constructor<?>)
exceptions = getAllExceptions(((Constructor<?>) elmt).
getExceptionTypes());
if(exceptions.length > 0 ) {
String fieldName = isSetter ? JMX.SET_EXCEPTIONS_FIELD :
JMX.EXCEPTIONS_FIELD;
String[] fieldNames = {fieldName};
Object[] fieldValues = {exceptions};
descr = ImmutableDescriptor.union(descr,
new ImmutableDescriptor(fieldNames, fieldValues));
}
return descr;
}
public static Descriptor descriptorForAnnotation(Annotation annot) {
return descriptorForAnnotations(new Annotation[] {annot});
return descriptorForAnnotations(annots);
}
public static Descriptor descriptorForAnnotations(Annotation[] annots) {
......@@ -547,9 +364,36 @@ public class Introspector {
return ImmutableDescriptor.EMPTY_DESCRIPTOR;
Map<String, Object> descriptorMap = new HashMap<String, Object>();
for (Annotation a : annots) {
if (a instanceof DescriptorFields)
addDescriptorFieldsToMap(descriptorMap, (DescriptorFields) a);
addAnnotationFieldsToMap(descriptorMap, a);
Class<? extends Annotation> c = a.annotationType();
Method[] elements = c.getMethods();
for (Method element : elements) {
DescriptorKey key = element.getAnnotation(DescriptorKey.class);
if (key != null) {
String name = key.value();
Object value;
try {
value = element.invoke(a);
} catch (RuntimeException e) {
// we don't expect this - except for possibly
// security exceptions?
// RuntimeExceptions shouldn't be "UndeclaredThrowable".
// anyway...
//
throw e;
} catch (Exception e) {
// we don't expect this
throw new UndeclaredThrowableException(e);
}
value = annotationToField(value);
Object oldValue = descriptorMap.put(name, value);
if (oldValue != null && !equals(oldValue, value)) {
final String msg =
"Inconsistent values for descriptor field " + name +
" from annotations: " + value + " :: " + oldValue;
throw new IllegalArgumentException(msg);
}
}
}
}
if (descriptorMap.isEmpty())
......@@ -558,76 +402,6 @@ public class Introspector {
return new ImmutableDescriptor(descriptorMap);
}
/**
* Array of thrown excepions.
* @param exceptions can be null;
* @return An Array of Exception class names. Size is 0 if method is null.
*/
private static String[] getAllExceptions(Class<?>[] exceptions) {
Set<String> set = new LinkedHashSet<String>();
for(Class<?>ex : exceptions)
set.add(ex.getName());
String[] arr = new String[set.size()];
return set.toArray(arr);
}
private static void addDescriptorFieldsToMap(
Map<String, Object> descriptorMap, DescriptorFields df) {
for (String field : df.value()) {
int eq = field.indexOf('=');
if (eq < 0) {
throw new IllegalArgumentException(
"@DescriptorFields string must contain '=': " +
field);
}
String name = field.substring(0, eq);
String value = field.substring(eq + 1);
addToMap(descriptorMap, name, value);
}
}
private static void addAnnotationFieldsToMap(
Map<String, Object> descriptorMap, Annotation a) {
Class<? extends Annotation> c = a.annotationType();
Method[] elements = c.getMethods();
for (Method element : elements) {
DescriptorKey key = element.getAnnotation(DescriptorKey.class);
if (key != null) {
String name = key.value();
Object value;
try {
value = element.invoke(a);
} catch (RuntimeException e) {
// we don't expect this - except for possibly
// security exceptions?
// RuntimeExceptions shouldn't be "UndeclaredThrowable".
// anyway...
throw e;
} catch (Exception e) {
// we don't expect this
throw new UndeclaredThrowableException(e);
}
if (!key.omitIfDefault() ||
!equals(value, element.getDefaultValue())) {
value = annotationToField(value);
addToMap(descriptorMap, name, value);
}
}
}
}
private static void addToMap(
Map<String, Object> descriptorMap, String name, Object value) {
Object oldValue = descriptorMap.put(name, value);
if (oldValue != null && !equals(oldValue, value)) {
final String msg =
"Inconsistent values for descriptor field " + name +
" from annotations: " + value + " :: " + oldValue;
throw new IllegalArgumentException(msg);
}
}
/**
* Throws a NotCompliantMBeanException or a SecurityException.
* @param notCompliant the class which was under examination
......
......@@ -25,14 +25,14 @@
package com.sun.jmx.mbeanserver;
import com.sun.jmx.interceptor.DefaultMBeanServerInterceptor;
import com.sun.jmx.interceptor.MBeanServerInterceptor;
import static com.sun.jmx.defaults.JmxProperties.MBEANSERVER_LOGGER;
import com.sun.jmx.interceptor.NamespaceDispatchInterceptor;
import java.io.ObjectInputStream;
import java.security.AccessController;
import java.security.Permission;
import java.security.PrivilegedExceptionAction;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.logging.Level;
......@@ -108,8 +108,6 @@ public final class JmxMBeanServer
/** The MBeanServerDelegate object representing the MBean Server */
private final MBeanServerDelegate mBeanServerDelegateObject;
private final String mbeanServerName;
/**
* <b>Package:</b> Creates an MBeanServer with the
* specified default domain name, outer interface, and delegate.
......@@ -241,10 +239,9 @@ public final class JmxMBeanServer
final Repository repository = new Repository(domain);
this.mbsInterceptor =
new NamespaceDispatchInterceptor(outer, delegate, instantiator,
new DefaultMBeanServerInterceptor(outer, delegate, instantiator,
repository);
this.interceptorsEnabled = interceptors;
this.mbeanServerName = Util.getMBeanServerSecurityName(delegate);
initialize();
}
......@@ -940,8 +937,7 @@ public final class JmxMBeanServer
throws ReflectionException, MBeanException {
/* Permission check */
checkMBeanPermission(mbeanServerName, className, null, null,
"instantiate");
checkMBeanPermission(className, null, null, "instantiate");
return instantiator.instantiate(className);
}
......@@ -978,8 +974,7 @@ public final class JmxMBeanServer
InstanceNotFoundException {
/* Permission check */
checkMBeanPermission(mbeanServerName, className, null,
null, "instantiate");
checkMBeanPermission(className, null, null, "instantiate");
ClassLoader myLoader = outerShell.getClass().getClassLoader();
return instantiator.instantiate(className, loaderName, myLoader);
......@@ -1017,8 +1012,7 @@ public final class JmxMBeanServer
throws ReflectionException, MBeanException {
/* Permission check */
checkMBeanPermission(mbeanServerName, className, null, null,
"instantiate");
checkMBeanPermission(className, null, null, "instantiate");
ClassLoader myLoader = outerShell.getClass().getClassLoader();
return instantiator.instantiate(className, params, signature,
......@@ -1061,8 +1055,7 @@ public final class JmxMBeanServer
InstanceNotFoundException {
/* Permission check */
checkMBeanPermission(mbeanServerName, className, null,
null, "instantiate");
checkMBeanPermission(className, null, null, "instantiate");
ClassLoader myLoader = outerShell.getClass().getClassLoader();
return instantiator.instantiate(className,loaderName,params,signature,
......@@ -1333,8 +1326,7 @@ public final class JmxMBeanServer
**/
public ClassLoaderRepository getClassLoaderRepository() {
/* Permission check */
checkMBeanPermission(mbeanServerName, null, null,
null, "getClassLoaderRepository");
checkMBeanPermission(null, null, null, "getClassLoaderRepository");
return secureClr;
}
......@@ -1487,16 +1479,14 @@ public final class JmxMBeanServer
// SECURITY CHECKS
//----------------
private static void checkMBeanPermission(String serverName,
String classname,
private static void checkMBeanPermission(String classname,
String member,
ObjectName objectName,
String actions)
throws SecurityException {
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
Permission perm = new MBeanPermission(serverName,
classname,
Permission perm = new MBeanPermission(classname,
member,
objectName,
actions);
......
......@@ -33,10 +33,6 @@ import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.management.MBean;
import javax.management.MXBean;
import javax.management.ManagedAttribute;
import javax.management.ManagedOperation;
import javax.management.NotCompliantMBeanException;
/**
......@@ -55,15 +51,15 @@ import javax.management.NotCompliantMBeanException;
*/
class MBeanAnalyzer<M> {
static interface MBeanVisitor<M, X extends Exception> {
static interface MBeanVisitor<M> {
public void visitAttribute(String attributeName,
M getter,
M setter) throws X;
M setter);
public void visitOperation(String operationName,
M operation) throws X;
M operation);
}
<X extends Exception> void visit(MBeanVisitor<M, X> visitor) throws X {
void visit(MBeanVisitor<M> visitor) {
// visit attributes
for (Map.Entry<String, AttrMethods<M>> entry : attrMap.entrySet()) {
String name = entry.getKey();
......@@ -108,7 +104,10 @@ class MBeanAnalyzer<M> {
private MBeanAnalyzer(Class<?> mbeanType,
MBeanIntrospector<M> introspector)
throws NotCompliantMBeanException {
introspector.checkCompliance(mbeanType);
if (!mbeanType.isInterface()) {
throw new NotCompliantMBeanException("Not an interface: " +
mbeanType.getName());
}
try {
initMaps(mbeanType, introspector);
......@@ -129,26 +128,18 @@ class MBeanAnalyzer<M> {
for (Method m : methods) {
final String name = m.getName();
final int nParams = m.getParameterTypes().length;
final boolean managedOp = m.isAnnotationPresent(ManagedOperation.class);
final boolean managedAttr = m.isAnnotationPresent(ManagedAttribute.class);
if (managedOp && managedAttr) {
throw new NotCompliantMBeanException("Method " + name +
" has both @ManagedOperation and @ManagedAttribute");
}
final M cm = introspector.mFrom(m);
String attrName = "";
if (!managedOp) {
if (name.startsWith("get"))
attrName = name.substring(3);
else if (name.startsWith("is")
&& m.getReturnType() == boolean.class)
attrName = name.substring(2);
}
if (name.startsWith("get"))
attrName = name.substring(3);
else if (name.startsWith("is")
&& m.getReturnType() == boolean.class)
attrName = name.substring(2);
if (attrName.length() != 0 && nParams == 0
&& m.getReturnType() != void.class && !managedOp) {
&& m.getReturnType() != void.class) {
// It's a getter
// Check we don't have both isX and getX
AttrMethods<M> am = attrMap.get(attrName);
......@@ -165,7 +156,7 @@ class MBeanAnalyzer<M> {
attrMap.put(attrName, am);
} else if (name.startsWith("set") && name.length() > 3
&& nParams == 1 &&
m.getReturnType() == void.class && !managedOp) {
m.getReturnType() == void.class) {
// It's a setter
attrName = name.substring(3);
AttrMethods<M> am = attrMap.get(attrName);
......@@ -178,9 +169,6 @@ class MBeanAnalyzer<M> {
}
am.setter = cm;
attrMap.put(attrName, am);
} else if (managedAttr) {
throw new NotCompliantMBeanException("Method " + name +
" has @ManagedAttribute but is not a valid getter or setter");
} else {
// It's an operation
List<M> cms = opMap.get(name);
......
......@@ -613,15 +613,6 @@ public class MBeanInstantiator {
return clr;
}
/**
* Returns the class of a primitive type.
* @param name The type for which we the associated class.
* @return the class, or null if name is not primitive.
*/
public static Class<?> primitiveType(String name) {
return primitiveClasses.get(name);
}
/**
* Load a class with the specified loader, or with this object
* class loader if the specified loader is null.
......
......@@ -37,7 +37,7 @@ import javax.management.MBeanServer;
import javax.management.NotCompliantMBeanException;
import javax.management.ObjectName;
import javax.management.ReflectionException;
import javax.management.openmbean.MXBeanMappingFactory;
import com.sun.jmx.mbeanserver.MXBeanMappingFactory;
/**
* Base class for MBeans. There is one instance of this class for
......@@ -121,8 +121,7 @@ import javax.management.openmbean.MXBeanMappingFactory;
public abstract class MBeanSupport<M>
implements DynamicMBean2, MBeanRegistration {
<T> MBeanSupport(T resource, Class<T> mbeanInterfaceType,
MXBeanMappingFactory mappingFactory)
<T> MBeanSupport(T resource, Class<T> mbeanInterfaceType)
throws NotCompliantMBeanException {
if (mbeanInterfaceType == null)
throw new NotCompliantMBeanException("Null MBean interface");
......@@ -133,14 +132,13 @@ public abstract class MBeanSupport<M>
throw new NotCompliantMBeanException(msg);
}
this.resource = resource;
MBeanIntrospector<M> introspector = getMBeanIntrospector(mappingFactory);
MBeanIntrospector<M> introspector = getMBeanIntrospector();
this.perInterface = introspector.getPerInterface(mbeanInterfaceType);
this.mbeanInfo = introspector.getMBeanInfo(resource, perInterface);
}
/** Return the appropriate introspector for this type of MBean. */
abstract MBeanIntrospector<M>
getMBeanIntrospector(MXBeanMappingFactory mappingFactory);
abstract MBeanIntrospector<M> getMBeanIntrospector();
/**
* Return a cookie for this MBean. This cookie will be passed to
......@@ -262,14 +260,10 @@ public abstract class MBeanSupport<M>
return resource.getClass().getName();
}
public final Object getWrappedObject() {
public final Object getResource() {
return resource;
}
public final ClassLoader getWrappedClassLoader() {
return resource.getClass().getClassLoader();
}
public final Class<?> getMBeanInterface() {
return perInterface.getMBeanInterface();
}
......
......@@ -28,26 +28,18 @@ package com.sun.jmx.mbeanserver;
import com.sun.jmx.mbeanserver.MBeanIntrospector.MBeanInfoMap;
import com.sun.jmx.mbeanserver.MBeanIntrospector.PerInterfaceMap;
import java.lang.annotation.Annotation;
import java.lang.ref.WeakReference;
import java.lang.reflect.GenericArrayType;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Map;
import java.util.WeakHashMap;
import javax.management.Description;
import javax.management.Descriptor;
import javax.management.ImmutableDescriptor;
import javax.management.IntrospectionException;
import javax.management.JMX;
import javax.management.MBeanAttributeInfo;
import javax.management.MBeanException;
import javax.management.MBeanOperationInfo;
import javax.management.MBeanParameterInfo;
import javax.management.ManagedOperation;
import javax.management.NotCompliantMBeanException;
import javax.management.openmbean.MXBeanMappingFactory;
import javax.management.openmbean.OpenMBeanAttributeInfoSupport;
import javax.management.openmbean.OpenMBeanOperationInfoSupport;
import javax.management.openmbean.OpenMBeanParameterInfo;
......@@ -60,36 +52,10 @@ import javax.management.openmbean.OpenType;
* @since 1.6
*/
class MXBeanIntrospector extends MBeanIntrospector<ConvertingMethod> {
/* We keep one MXBeanIntrospector per MXBeanMappingFactory, since the results
* of the introspection depend on the factory. The MXBeanIntrospector
* has a reference back to the factory, so we wrap it in a WeakReference.
* It will be strongly referenced by any MXBeanSupport instances using it;
* if there are none then it is OK to gc it.
*/
private static final
Map<MXBeanMappingFactory, WeakReference<MXBeanIntrospector>> map =
new WeakHashMap<MXBeanMappingFactory, WeakReference<MXBeanIntrospector>>();
static MXBeanIntrospector getInstance(MXBeanMappingFactory factory) {
if (factory == null)
factory = MXBeanMappingFactory.DEFAULT;
synchronized (map) {
MXBeanIntrospector intro;
WeakReference<MXBeanIntrospector> wr = map.get(factory);
if (wr != null) {
intro = wr.get();
if (intro != null)
return intro;
}
intro = new MXBeanIntrospector(factory);
wr = new WeakReference<MXBeanIntrospector>(intro);
map.put(factory, wr);
return intro;
}
}
private static final MXBeanIntrospector instance = new MXBeanIntrospector();
private MXBeanIntrospector(MXBeanMappingFactory factory) {
this.mappingFactory = factory;
static MXBeanIntrospector getInstance() {
return instance;
}
@Override
......@@ -115,7 +81,7 @@ class MXBeanIntrospector extends MBeanIntrospector<ConvertingMethod> {
@Override
ConvertingMethod mFrom(Method m) {
return ConvertingMethod.from(m, mappingFactory);
return ConvertingMethod.from(m);
}
@Override
......@@ -176,17 +142,13 @@ class MXBeanIntrospector extends MBeanIntrospector<ConvertingMethod> {
@Override
MBeanAttributeInfo getMBeanAttributeInfo(String attributeName,
ConvertingMethod getter, ConvertingMethod setter)
throws IntrospectionException {
ConvertingMethod getter, ConvertingMethod setter) {
final boolean isReadable = (getter != null);
final boolean isWritable = (setter != null);
final boolean isIs = isReadable && getName(getter).startsWith("is");
final String description = getAttributeDescription(
attributeName, attributeName,
getter == null ? null : getter.getMethod(),
setter == null ? null : setter.getMethod());
final String description = attributeName;
final OpenType<?> openType;
final Type originalType;
......@@ -235,17 +197,13 @@ class MXBeanIntrospector extends MBeanIntrospector<ConvertingMethod> {
MBeanOperationInfo getMBeanOperationInfo(String operationName,
ConvertingMethod operation) {
final Method method = operation.getMethod();
String description = operationName;
final String description = operationName;
/* Ideally this would be an empty string, but
OMBOperationInfo constructor forbids that. */
Description d = method.getAnnotation(Description.class);
if (d != null)
description = d.value();
OMBOperationInfo constructor forbids that. Also, we
could consult an annotation to get a useful
description. */
int impact = MBeanOperationInfo.UNKNOWN;
ManagedOperation annot = method.getAnnotation(ManagedOperation.class);
if (annot != null)
impact = annot.impact().getCode();
final int impact = MBeanOperationInfo.UNKNOWN;
final OpenType<?> returnType = operation.getOpenReturnType();
final Type originalReturnType = operation.getGenericReturnType();
......@@ -257,15 +215,8 @@ class MXBeanIntrospector extends MBeanIntrospector<ConvertingMethod> {
boolean openParameterTypes = true;
Annotation[][] annots = method.getParameterAnnotations();
for (int i = 0; i < paramTypes.length; i++) {
String paramName = Introspector.nameForParameter(annots[i]);
if (paramName == null)
paramName = "p" + i;
String paramDescription =
Introspector.descriptionForParameter(annots[i]);
if (paramDescription == null)
paramDescription = paramName;
final String paramName = "p" + i;
final String paramDescription = paramName;
final OpenType<?> openType = paramTypes[i];
final Type originalType = originalParamTypes[i];
Descriptor descriptor =
......@@ -292,7 +243,7 @@ class MXBeanIntrospector extends MBeanIntrospector<ConvertingMethod> {
Descriptor descriptor =
typeDescriptor(returnType, originalReturnType);
descriptor = ImmutableDescriptor.union(descriptor,
Introspector.descriptorForElement(method, false));
Introspector.descriptorForElement(method));
final MBeanOperationInfo oi;
if (openReturnType && openParameterTypes) {
/* If the return value and all the parameters can be faithfully
......@@ -343,17 +294,6 @@ class MXBeanIntrospector extends MBeanIntrospector<ConvertingMethod> {
return ImmutableDescriptor.EMPTY_DESCRIPTOR;
}
@Override
Descriptor getSpecificMBeanDescriptor() {
if (mappingFactory == MXBeanMappingFactory.DEFAULT)
return ImmutableDescriptor.EMPTY_DESCRIPTOR;
else {
return new ImmutableDescriptor(
JMX.MXBEAN_MAPPING_FACTORY_CLASS_FIELD + "=" +
mappingFactory.getClass().getName());
}
}
private static Descriptor typeDescriptor(OpenType<?> openType,
Type originalType) {
return new ImmutableDescriptor(
......@@ -421,7 +361,5 @@ class MXBeanIntrospector extends MBeanIntrospector<ConvertingMethod> {
private final PerInterfaceMap<ConvertingMethod>
perInterfaceMap = new PerInterfaceMap<ConvertingMethod>();
private final MBeanInfoMap mbeanInfoMap = new MBeanInfoMap();
private final MXBeanMappingFactory mappingFactory;
private static final MBeanInfoMap mbeanInfoMap = new MBeanInfoMap();
}
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册