You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@felix.apache.org by sf...@apache.org on 2006/07/17 14:14:33 UTC

svn commit: r422696 [4/4] - in /incubator/felix/trunk/org.apache.felix.mosgi.jmx.agent: ./ src/ src/main/ src/main/java/ src/main/java/org/ src/main/java/org/apache/ src/main/java/org/apache/felix/ src/main/java/org/apache/felix/mosgi/ src/main/java/or...

Added: incubator/felix/trunk/org.apache.felix.mosgi.jmx.agent/src/main/java/org/apache/felix/mosgi/jmx/agent/mx4j/server/interceptor/DefaultMBeanServerInterceptor.java
URL: http://svn.apache.org/viewvc/incubator/felix/trunk/org.apache.felix.mosgi.jmx.agent/src/main/java/org/apache/felix/mosgi/jmx/agent/mx4j/server/interceptor/DefaultMBeanServerInterceptor.java?rev=422696&view=auto
==============================================================================
--- incubator/felix/trunk/org.apache.felix.mosgi.jmx.agent/src/main/java/org/apache/felix/mosgi/jmx/agent/mx4j/server/interceptor/DefaultMBeanServerInterceptor.java (added)
+++ incubator/felix/trunk/org.apache.felix.mosgi.jmx.agent/src/main/java/org/apache/felix/mosgi/jmx/agent/mx4j/server/interceptor/DefaultMBeanServerInterceptor.java Mon Jul 17 05:14:31 2006
@@ -0,0 +1,157 @@
+/*
+ * Copyright (C) MX4J.
+ * All rights reserved.
+ *
+ * This software is distributed under the terms of the MX4J License version 1.0.
+ * See the terms of the MX4J License in the documentation provided with this software.
+ */
+/*
+ *   Copyright 2005 The Apache Software Foundation
+ *
+ *   Licensed under the Apache License, Version 2.0 (the "License");
+ *   you may not use this file except in compliance with the License.
+ *   You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing, software
+ *   distributed under the License is distributed on an "AS IS" BASIS,
+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *   See the License for the specific language governing permissions and
+ *   limitations under the License.
+ *
+ */
+package org.apache.felix.mosgi.jmx.agent.mx4j.server.interceptor;
+
+import java.util.List;
+
+import javax.management.Attribute;
+import javax.management.AttributeList;
+import javax.management.AttributeNotFoundException;
+import javax.management.InvalidAttributeValueException;
+import javax.management.ListenerNotFoundException;
+import javax.management.MBeanException;
+import javax.management.MBeanInfo;
+import javax.management.MBeanRegistrationException;
+import javax.management.NotificationFilter;
+import javax.management.NotificationListener;
+import javax.management.ReflectionException;
+
+import org.apache.felix.mosgi.jmx.agent.mx4j.log.Log;
+import org.apache.felix.mosgi.jmx.agent.mx4j.log.Logger;
+import org.apache.felix.mosgi.jmx.agent.mx4j.server.MBeanMetaData;
+
+/**
+ * Base class for MBeanServer --> MBean interceptors.
+ *
+ * @author <a href="mailto:biorn_steedom@users.sourceforge.net">Simone Bordet</a>
+ * @version $Revision: 1.2 $
+ */
+public abstract class DefaultMBeanServerInterceptor implements MBeanServerInterceptor, DefaultMBeanServerInterceptorMBean
+{
+	private boolean enabled = true;
+	private String logCategory;
+	private List chain;
+
+	protected DefaultMBeanServerInterceptor()
+	{
+		// It's amazing how setting up here this string dramatically reduces the times to get the Logger instance
+		logCategory = getClass().getName() + "." + getType();
+	}
+
+	/**
+	 * Returns whether this interceptor is enabled
+	 * @see #setEnabled
+	 */
+	public boolean isEnabled()
+	{
+		return enabled;
+	}
+
+	/**
+	 * Enables or disables this interceptor
+	 * @see #isEnabled
+	 */
+	public void setEnabled(boolean enabled)
+	{
+		this.enabled = enabled;
+	}
+
+	/**
+	 * Returns the type of this interceptor
+	 */
+	public abstract String getType();
+
+	protected synchronized MBeanServerInterceptor getNext()
+	{
+		int index = chain.indexOf(this);
+		MBeanServerInterceptor next = (MBeanServerInterceptor)chain.get(index + 1);
+		next.setChain(chain);
+		return next;
+	}
+
+	public synchronized void setChain(List chain)
+	{
+		this.chain = chain;
+	}
+
+	protected Logger getLogger()
+	{
+		return Log.getLogger(logCategory);
+	}
+
+	public void addNotificationListener(MBeanMetaData metadata, NotificationListener listener, NotificationFilter filter, Object handback)
+	{
+		getNext().addNotificationListener(metadata, listener, filter, handback);
+	}
+
+   public void removeNotificationListener(MBeanMetaData metadata, NotificationListener listener) throws ListenerNotFoundException
+   {
+      getNext().removeNotificationListener(metadata, listener);
+   }
+
+	public void removeNotificationListener(MBeanMetaData metadata, NotificationListener listener, NotificationFilter filter, Object handback) throws ListenerNotFoundException
+	{
+		getNext().removeNotificationListener(metadata, listener, filter, handback);
+	}
+
+	public void instantiate(MBeanMetaData metadata, String className, String[] params, Object[] args) throws ReflectionException, MBeanException
+	{
+		getNext().instantiate(metadata, className, params, args);
+	}
+
+	public void registration(MBeanMetaData metadata, int operation) throws MBeanRegistrationException
+	{
+		getNext().registration(metadata, operation);
+	}
+
+	public MBeanInfo getMBeanInfo(MBeanMetaData metadata)
+	{
+		return getNext().getMBeanInfo(metadata);
+	}
+
+	public Object invoke(MBeanMetaData metadata, String method, String[] params, Object[] args) throws MBeanException, ReflectionException
+	{
+		return getNext().invoke(metadata, method, params, args);
+	}
+
+	public AttributeList getAttributes(MBeanMetaData metadata, String[] attributes)
+	{
+		return getNext().getAttributes(metadata, attributes);
+	}
+
+	public AttributeList setAttributes(MBeanMetaData metadata, AttributeList attributes)
+	{
+		return getNext().setAttributes(metadata, attributes);
+	}
+
+	public Object getAttribute(MBeanMetaData metadata, String attribute) throws MBeanException, AttributeNotFoundException, ReflectionException
+	{
+		return getNext().getAttribute(metadata, attribute);
+	}
+
+	public void setAttribute(MBeanMetaData metadata, Attribute attribute) throws MBeanException, AttributeNotFoundException, InvalidAttributeValueException, ReflectionException
+	{
+		getNext().setAttribute(metadata, attribute);
+	}
+}

Added: incubator/felix/trunk/org.apache.felix.mosgi.jmx.agent/src/main/java/org/apache/felix/mosgi/jmx/agent/mx4j/server/interceptor/DefaultMBeanServerInterceptorMBean.java
URL: http://svn.apache.org/viewvc/incubator/felix/trunk/org.apache.felix.mosgi.jmx.agent/src/main/java/org/apache/felix/mosgi/jmx/agent/mx4j/server/interceptor/DefaultMBeanServerInterceptorMBean.java?rev=422696&view=auto
==============================================================================
--- incubator/felix/trunk/org.apache.felix.mosgi.jmx.agent/src/main/java/org/apache/felix/mosgi/jmx/agent/mx4j/server/interceptor/DefaultMBeanServerInterceptorMBean.java (added)
+++ incubator/felix/trunk/org.apache.felix.mosgi.jmx.agent/src/main/java/org/apache/felix/mosgi/jmx/agent/mx4j/server/interceptor/DefaultMBeanServerInterceptorMBean.java Mon Jul 17 05:14:31 2006
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) MX4J.
+ * All rights reserved.
+ *
+ * This software is distributed under the terms of the MX4J License version 1.0.
+ * See the terms of the MX4J License in the documentation provided with this software.
+ */
+
+/*
+ *   Copyright 2005 The Apache Software Foundation
+ *
+ *   Licensed under the Apache License, Version 2.0 (the "License");
+ *   you may not use this file except in compliance with the License.
+ *   You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing, software
+ *   distributed under the License is distributed on an "AS IS" BASIS,
+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *   See the License for the specific language governing permissions and
+ *   limitations under the License.
+ *
+ */
+package org.apache.felix.mosgi.jmx.agent.mx4j.server.interceptor;
+
+/**
+ * Management interface for the DefaultMBeanServerInterceptor MBean
+ * @author <a href="mailto:biorn_steedom@users.sourceforge.net">Simone Bordet</a>
+ * @version $Revision: 1.1.1.1 $
+ */
+public interface DefaultMBeanServerInterceptorMBean
+{
+   /**
+    * Returns whether this interceptor is enabled
+    * @see #setEnabled
+    */
+   public boolean isEnabled();
+
+   /**
+    * Enables or disables this interceptor
+    * @see #isEnabled
+    */
+   public void setEnabled(boolean enabled);
+
+   /**
+    * Returns the type of this interceptor
+    */
+   public String getType();
+}

Added: incubator/felix/trunk/org.apache.felix.mosgi.jmx.agent/src/main/java/org/apache/felix/mosgi/jmx/agent/mx4j/server/interceptor/InvokerMBeanServerInterceptor.java
URL: http://svn.apache.org/viewvc/incubator/felix/trunk/org.apache.felix.mosgi.jmx.agent/src/main/java/org/apache/felix/mosgi/jmx/agent/mx4j/server/interceptor/InvokerMBeanServerInterceptor.java?rev=422696&view=auto
==============================================================================
--- incubator/felix/trunk/org.apache.felix.mosgi.jmx.agent/src/main/java/org/apache/felix/mosgi/jmx/agent/mx4j/server/interceptor/InvokerMBeanServerInterceptor.java (added)
+++ incubator/felix/trunk/org.apache.felix.mosgi.jmx.agent/src/main/java/org/apache/felix/mosgi/jmx/agent/mx4j/server/interceptor/InvokerMBeanServerInterceptor.java Mon Jul 17 05:14:31 2006
@@ -0,0 +1,399 @@
+/*
+ * Copyright (C) MX4J.
+ * All rights reserved.
+ *
+ * This software is distributed under the terms of the MX4J License version 1.0.
+ * See the terms of the MX4J License in the documentation provided with this software.
+ */
+/*
+ *   Copyright 2005 The Apache Software Foundation
+ *
+ *   Licensed under the Apache License, Version 2.0 (the "License");
+ *   you may not use this file except in compliance with the License.
+ *   You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing, software
+ *   distributed under the License is distributed on an "AS IS" BASIS,
+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *   See the License for the specific language governing permissions and
+ *   limitations under the License.
+ *
+ */
+package org.apache.felix.mosgi.jmx.agent.mx4j.server.interceptor;
+
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+
+import javax.management.Attribute;
+import javax.management.AttributeList;
+import javax.management.AttributeNotFoundException;
+import javax.management.DynamicMBean;
+import javax.management.InvalidAttributeValueException;
+import javax.management.JMRuntimeException;
+import javax.management.ListenerNotFoundException;
+import javax.management.MBeanException;
+import javax.management.MBeanInfo;
+import javax.management.MBeanRegistration;
+import javax.management.MBeanRegistrationException;
+import javax.management.MBeanServer;
+import javax.management.NotificationBroadcaster;
+import javax.management.NotificationFilter;
+import javax.management.NotificationListener;
+import javax.management.ObjectInstance;
+import javax.management.ObjectName;
+import javax.management.ReflectionException;
+import javax.management.RuntimeErrorException;
+import javax.management.RuntimeMBeanException;
+import javax.management.NotificationEmitter;
+
+import org.apache.felix.mosgi.jmx.agent.mx4j.ImplementationException;
+import org.apache.felix.mosgi.jmx.agent.mx4j.log.Logger;
+import org.apache.felix.mosgi.jmx.agent.mx4j.server.MBeanMetaData;
+import org.apache.felix.mosgi.jmx.agent.mx4j.util.Utils;
+
+/**
+ * The last MBeanServer --$gt; MBean interceptor in the chain.
+ * It calls the MBean instance; if the MBean is a dynamic MBean, the call is direct, otherwise the call is delegated
+ * to an {@link mx4j.server.MBeanInvoker MBeanInvoker}.
+ *
+ * @author <a href="mailto:biorn_steedom@users.sourceforge.net">Simone Bordet</a>
+ * @version $Revision: 1.1.1.1 $
+ */
+public class InvokerMBeanServerInterceptor extends DefaultMBeanServerInterceptor implements InvokerMBeanServerInterceptorMBean
+{
+   private MBeanServer outerServer;
+
+   /**
+    * Instantiates a new interceptor instance.
+    * @param outerServer the {@link MBeanServer} instance that is passed to
+    * {@link MBeanRegistration#preRegister(MBeanServer, ObjectName)}.
+    */
+   public InvokerMBeanServerInterceptor(MBeanServer outerServer)
+   {
+      this.outerServer = outerServer;
+   }
+
+   /**
+    * Returns the type of this interceptor
+    */
+   public String getType()
+   {
+      return "invoker";
+   }
+
+   /**
+    * This interceptor is always enabled
+    */
+   public boolean isEnabled()
+   {
+      return true;
+   }
+
+   public void addNotificationListener(MBeanMetaData metadata, NotificationListener listener, NotificationFilter filter, Object handback)
+   {
+      ((NotificationBroadcaster)metadata.mbean).addNotificationListener(listener, filter, handback);
+   }
+
+   public void removeNotificationListener(MBeanMetaData metadata, NotificationListener listener) throws ListenerNotFoundException
+   {
+      ((NotificationBroadcaster)metadata.mbean).removeNotificationListener(listener);
+   }
+
+   public void removeNotificationListener(MBeanMetaData metadata, NotificationListener listener, NotificationFilter filter, Object handback)
+           throws ListenerNotFoundException
+   {
+      ((NotificationEmitter)metadata.mbean).removeNotificationListener(listener, filter, handback);
+   }
+
+   public void instantiate(MBeanMetaData metadata, String className, String[] params, Object[] args) throws ReflectionException, MBeanException
+   {
+      try
+      {
+         ClassLoader loader = metadata.classloader;
+         Class cls = null;
+         if (loader != null)
+            cls = loader.loadClass(className);
+         else
+            cls = Class.forName(className, false, null);
+
+         Class[] signature = Utils.loadClasses(loader, params);
+
+         Constructor ctor = cls.getConstructor(signature);
+
+         metadata.mbean = ctor.newInstance(args);
+      }
+      catch (ClassNotFoundException x)
+      {
+         throw new ReflectionException(x);
+      }
+      catch (NoSuchMethodException x)
+      {
+         throw new ReflectionException(x);
+      }
+      catch (InstantiationException x)
+      {
+         throw new ReflectionException(x);
+      }
+      catch (IllegalAccessException x)
+      {
+         throw new ReflectionException(x);
+      }
+      catch (IllegalArgumentException x)
+      {
+         throw new ReflectionException(x);
+      }
+      catch (InvocationTargetException x)
+      {
+         Throwable t = x.getTargetException();
+         if (t instanceof Error)
+         {
+            throw new RuntimeErrorException((Error)t);
+         }
+         else if (t instanceof RuntimeException)
+         {
+            throw new RuntimeMBeanException((RuntimeException)t);
+         }
+         else
+         {
+            throw new MBeanException((Exception)t);
+         }
+      }
+   }
+
+   public void registration(MBeanMetaData metadata, int operation) throws MBeanRegistrationException
+   {
+      if (!(metadata.mbean instanceof MBeanRegistration)) return;
+
+      MBeanRegistration registrable = (MBeanRegistration)metadata.mbean;
+
+      try
+      {
+         switch (operation)
+         {
+            case PRE_REGISTER:
+               ObjectName objName = registrable.preRegister(outerServer, metadata.name);
+               metadata.name = objName;
+               break;
+            case POST_REGISTER_TRUE:
+               registrable.postRegister(Boolean.TRUE);
+               break;
+            case POST_REGISTER_FALSE:
+               registrable.postRegister(Boolean.FALSE);
+               break;
+            case PRE_DEREGISTER:
+               registrable.preDeregister();
+               break;
+            case POST_DEREGISTER:
+               registrable.postDeregister();
+               break;
+            default:
+               throw new ImplementationException();
+         }
+      }
+      catch (RuntimeException x) {
+      	throw new RuntimeMBeanException(x);
+      }
+      catch (Exception x)
+      {
+         if (x instanceof MBeanRegistrationException)
+         {
+            throw (MBeanRegistrationException)x;
+         }
+         throw new MBeanRegistrationException(x);
+      }
+   }
+
+   public MBeanInfo getMBeanInfo(MBeanMetaData metadata)
+   {
+      if (metadata.dynamic)
+      {
+         // From JMX 1.1 the MBeanInfo may be dynamically changed at every time, let's refresh it
+		 MBeanInfo info = null;
+		 try {
+			 info = ((DynamicMBean)metadata.mbean).getMBeanInfo();
+		 } catch (RuntimeException x) {
+			 throw new RuntimeMBeanException(x);
+		 }
+         if (info == null) return null;
+         metadata.info = info;
+
+         // Refresh also ObjectInstance.getClassName(), if it's the case
+         String className = info.getClassName();
+         if (!metadata.instance.getClassName().equals(className))
+         {
+            metadata.instance = new ObjectInstance(metadata.name, className);
+         }
+      }
+
+      return (MBeanInfo)metadata.info.clone();
+   }
+
+   public Object invoke(MBeanMetaData metadata, String method, String[] params, Object[] args) throws MBeanException, ReflectionException
+   {
+      if (metadata.dynamic)
+      {
+         try
+         {
+            return ((DynamicMBean)metadata.mbean).invoke(method, args, params);
+         }
+         catch (JMRuntimeException x)
+         {
+            throw x;
+         }
+         catch (RuntimeException x)
+         {
+            throw new RuntimeMBeanException(x);
+         }
+         catch (Error x)
+         {
+            throw new RuntimeErrorException(x);
+         }
+      }
+      else
+      {
+         return metadata.invoker.invoke(metadata, method, params, args);
+      }
+   }
+
+   public Object getAttribute(MBeanMetaData metadata, String attribute) throws MBeanException, AttributeNotFoundException, ReflectionException
+   {
+      if (metadata.dynamic)
+      {
+         try
+         {
+            return ((DynamicMBean)metadata.mbean).getAttribute(attribute);
+         }
+         catch (JMRuntimeException x)
+         {
+            throw x;
+         }
+         catch (RuntimeException x)
+         {
+            throw new RuntimeMBeanException(x);
+         }
+         catch (Error x)
+         {
+            throw new RuntimeErrorException(x);
+         }
+      }
+      else
+      {
+         return metadata.invoker.getAttribute(metadata, attribute);
+      }
+   }
+
+   public void setAttribute(MBeanMetaData metadata, Attribute attribute) throws MBeanException, AttributeNotFoundException, InvalidAttributeValueException, ReflectionException
+   {
+      if (metadata.dynamic)
+      {
+         try
+         {
+            ((DynamicMBean)metadata.mbean).setAttribute(attribute);
+         }
+         catch (JMRuntimeException x)
+         {
+            throw x;
+         }
+         catch (RuntimeException x)
+         {
+            throw new RuntimeMBeanException(x);
+         }
+         catch (Error x)
+         {
+            throw new RuntimeErrorException(x);
+         }
+      }
+      else
+      {
+         metadata.invoker.setAttribute(metadata, attribute);
+      }
+   }
+
+   public AttributeList getAttributes(MBeanMetaData metadata, String[] attributes)
+   {
+      if (metadata.dynamic)
+      {
+         try
+         {
+            return ((DynamicMBean)metadata.mbean).getAttributes(attributes);
+         }
+         catch (JMRuntimeException x)
+         {
+            throw x;
+         }
+         catch (RuntimeException x)
+         {
+            throw new RuntimeMBeanException(x);
+         }
+         catch (Error x)
+         {
+            throw new RuntimeErrorException(x);
+         }
+      }
+      else
+      {
+         AttributeList list = new AttributeList();
+         for (int i = 0; i < attributes.length; ++i)
+         {
+            String name = attributes[i];
+            try
+            {
+               Object value = getAttribute(metadata, name);
+               Attribute attr = new Attribute(name, value);
+               list.add(attr);
+            }
+            catch (Exception ignored)
+            {
+               Logger logger = getLogger();
+               if (logger.isEnabledFor(Logger.DEBUG)) logger.debug("Exception caught from getAttributes(), ignoring attribute " + name);
+            }
+         }
+         return list;
+      }
+   }
+
+   public AttributeList setAttributes(MBeanMetaData metadata, AttributeList attributes)
+   {
+      if (metadata.dynamic)
+      {
+         try
+         {
+            return ((DynamicMBean)metadata.mbean).setAttributes(attributes);
+         }
+         catch (JMRuntimeException x)
+         {
+            throw x;
+         }
+         catch (RuntimeException x)
+         {
+            throw new RuntimeMBeanException(x);
+         }
+         catch (Error x)
+         {
+            throw new RuntimeErrorException(x);
+         }
+      }
+      else
+      {
+         AttributeList list = new AttributeList();
+         for (int i = 0; i < attributes.size(); ++i)
+         {
+            Attribute attr = (Attribute)attributes.get(i);
+            try
+            {
+               setAttribute(metadata, attr);
+               list.add(attr);
+            }
+            catch (Exception ignored)
+            {
+               Logger logger = getLogger();
+               if (logger.isEnabledFor(Logger.DEBUG)) logger.debug("Exception caught from setAttributes(), ignoring attribute " + attr, ignored);
+            }
+         }
+         return list;
+      }
+   }
+}

Added: incubator/felix/trunk/org.apache.felix.mosgi.jmx.agent/src/main/java/org/apache/felix/mosgi/jmx/agent/mx4j/server/interceptor/InvokerMBeanServerInterceptorMBean.java
URL: http://svn.apache.org/viewvc/incubator/felix/trunk/org.apache.felix.mosgi.jmx.agent/src/main/java/org/apache/felix/mosgi/jmx/agent/mx4j/server/interceptor/InvokerMBeanServerInterceptorMBean.java?rev=422696&view=auto
==============================================================================
--- incubator/felix/trunk/org.apache.felix.mosgi.jmx.agent/src/main/java/org/apache/felix/mosgi/jmx/agent/mx4j/server/interceptor/InvokerMBeanServerInterceptorMBean.java (added)
+++ incubator/felix/trunk/org.apache.felix.mosgi.jmx.agent/src/main/java/org/apache/felix/mosgi/jmx/agent/mx4j/server/interceptor/InvokerMBeanServerInterceptorMBean.java Mon Jul 17 05:14:31 2006
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) MX4J.
+ * All rights reserved.
+ *
+ * This software is distributed under the terms of the MX4J License version 1.0.
+ * See the terms of the MX4J License in the documentation provided with this software.
+ */
+
+/*
+ *   Copyright 2005 The Apache Software Foundation
+ *
+ *   Licensed under the Apache License, Version 2.0 (the "License");
+ *   you may not use this file except in compliance with the License.
+ *   You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing, software
+ *   distributed under the License is distributed on an "AS IS" BASIS,
+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *   See the License for the specific language governing permissions and
+ *   limitations under the License.
+ *
+ */
+package org.apache.felix.mosgi.jmx.agent.mx4j.server.interceptor;
+
+/**
+ * Management interface for the InvokerMBeanServerInterceptor MBean
+ * @author <a href="mailto:biorn_steedom@users.sourceforge.net">Simone Bordet</a>
+ * @version $Revision: 1.1.1.1 $
+ */
+public interface InvokerMBeanServerInterceptorMBean
+{
+   /**
+    * Returns the type of this interceptor
+    */
+   public String getType();
+
+   /**
+    * This interceptor is always enabled
+    */
+   public boolean isEnabled();
+}

Added: incubator/felix/trunk/org.apache.felix.mosgi.jmx.agent/src/main/java/org/apache/felix/mosgi/jmx/agent/mx4j/server/interceptor/MBeanServerInterceptor.java
URL: http://svn.apache.org/viewvc/incubator/felix/trunk/org.apache.felix.mosgi.jmx.agent/src/main/java/org/apache/felix/mosgi/jmx/agent/mx4j/server/interceptor/MBeanServerInterceptor.java?rev=422696&view=auto
==============================================================================
--- incubator/felix/trunk/org.apache.felix.mosgi.jmx.agent/src/main/java/org/apache/felix/mosgi/jmx/agent/mx4j/server/interceptor/MBeanServerInterceptor.java (added)
+++ incubator/felix/trunk/org.apache.felix.mosgi.jmx.agent/src/main/java/org/apache/felix/mosgi/jmx/agent/mx4j/server/interceptor/MBeanServerInterceptor.java Mon Jul 17 05:14:31 2006
@@ -0,0 +1,139 @@
+/*
+ * Copyright (C) MX4J.
+ * All rights reserved.
+ *
+ * This software is distributed under the terms of the MX4J License version 1.0.
+ * See the terms of the MX4J License in the documentation provided with this software.
+ */
+/*
+ *   Copyright 2005 The Apache Software Foundation
+ *
+ *   Licensed under the Apache License, Version 2.0 (the "License");
+ *   you may not use this file except in compliance with the License.
+ *   You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing, software
+ *   distributed under the License is distributed on an "AS IS" BASIS,
+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *   See the License for the specific language governing permissions and
+ *   limitations under the License.
+ *
+ */
+package org.apache.felix.mosgi.jmx.agent.mx4j.server.interceptor;
+
+
+import java.util.List;
+
+import javax.management.Attribute;
+import javax.management.AttributeList;
+import javax.management.AttributeNotFoundException;
+import javax.management.InvalidAttributeValueException;
+import javax.management.ListenerNotFoundException;
+import javax.management.MBeanException;
+import javax.management.MBeanInfo;
+import javax.management.MBeanRegistrationException;
+import javax.management.NotificationFilter;
+import javax.management.NotificationListener;
+import javax.management.ReflectionException;
+
+import org.apache.felix.mosgi.jmx.agent.mx4j.server.MBeanMetaData;
+
+/**
+ * MBeanServer --&gt; MBean interceptor.
+ * These interceptors are used internally to implement MBeanServer functionality prior to call
+ * MBeans, and can be used to customize MBeanServer implementation by users.
+ *
+ * @author <a href="mailto:biorn_steedom@users.sourceforge.net">Simone Bordet</a>
+ * @version $Revision: 1.1.1.1 $
+ */
+public interface MBeanServerInterceptor
+{
+   /**
+    * Constant used to specify the status of the MBean registration in {@link #registration}
+    */
+	public static final int PRE_REGISTER = 1;
+   /**
+    * Constant used to specify the status of the MBean registration in {@link #registration}
+    */
+	public static final int POST_REGISTER_TRUE = 2;
+   /**
+    * Constant used to specify the status of the MBean registration in {@link #registration}
+    */
+	public static final int POST_REGISTER_FALSE = 3;
+   /**
+    * Constant used to specify the status of the MBean registration in {@link #registration}
+    */
+	public static final int PRE_DEREGISTER = 4;
+   /**
+    * Constant used to specify the status of the MBean registration in {@link #registration}
+    */
+	public static final int POST_DEREGISTER = 5;
+
+	/**
+	 * A concise string that tells the type of this interceptor
+	 */
+	public String getType();
+
+   /**
+    * Sets the chain of interceptors on this interceptor. This interceptor will use this list to
+    * find the interceptor in the chain after itself
+    * @param interceptors The list of interceptors
+    */
+	public void setChain(List interceptors);
+
+   /**
+    * Adds the given notification listener to the MBean, along with the given filter and handback
+    */
+	public void addNotificationListener(MBeanMetaData metadata, NotificationListener listener, NotificationFilter filter, Object handback);
+
+   /**
+    * Removes the given notification listener from the MBean.
+    */
+	public void removeNotificationListener(MBeanMetaData metadata, NotificationListener listener) throws ListenerNotFoundException;
+   /**
+    * Removes the given notification listener from the MBean, specified by the given filter and handback.
+    */
+   public void removeNotificationListener(MBeanMetaData metadata, NotificationListener listener, NotificationFilter filter, Object handback) throws ListenerNotFoundException;
+
+   /**
+    * Instantiate the given className passing the given arguments to the constructor with the given signature
+    */
+	public void instantiate(MBeanMetaData metadata, String className, String[] params, Object[] args) throws ReflectionException, MBeanException;
+
+   /**
+    * Calls the specified {@link javax.management.MBeanRegistration} method on the MBean instance.
+    */
+	public void registration(MBeanMetaData metadata, int operation) throws MBeanRegistrationException;
+
+   /**
+    * Calls getMBeanInfo on the MBean instance (only on DynamicMBeans).
+    */
+	public MBeanInfo getMBeanInfo(MBeanMetaData metadata);
+
+   /**
+    * Invokes the specified MBean operation on the MBean instance
+    */
+	public Object invoke(MBeanMetaData metadata, String method, String[] params, Object[] args) throws MBeanException, ReflectionException;
+
+   /**
+    * Gets the specified attributes values from the MBean instance.
+    */
+	public AttributeList getAttributes(MBeanMetaData metadata, String[] attributes);
+
+   /**
+    * Sets the specified attributes values on the MBean instance.
+    */
+	public AttributeList setAttributes(MBeanMetaData metadata, AttributeList attributes);
+
+   /**
+    * Gets the specified attribute value from the MBean instance.
+    */
+	public Object getAttribute(MBeanMetaData metadata, String attribute) throws MBeanException, AttributeNotFoundException, ReflectionException;
+
+   /**
+    * Sets the specified attribute value on the MBean instance.
+    */
+	public void setAttribute(MBeanMetaData metadata, Attribute attribute) throws MBeanException, AttributeNotFoundException, InvalidAttributeValueException, ReflectionException;
+}

Added: incubator/felix/trunk/org.apache.felix.mosgi.jmx.agent/src/main/java/org/apache/felix/mosgi/jmx/agent/mx4j/server/interceptor/MBeanServerInterceptorConfigurator.java
URL: http://svn.apache.org/viewvc/incubator/felix/trunk/org.apache.felix.mosgi.jmx.agent/src/main/java/org/apache/felix/mosgi/jmx/agent/mx4j/server/interceptor/MBeanServerInterceptorConfigurator.java?rev=422696&view=auto
==============================================================================
--- incubator/felix/trunk/org.apache.felix.mosgi.jmx.agent/src/main/java/org/apache/felix/mosgi/jmx/agent/mx4j/server/interceptor/MBeanServerInterceptorConfigurator.java (added)
+++ incubator/felix/trunk/org.apache.felix.mosgi.jmx.agent/src/main/java/org/apache/felix/mosgi/jmx/agent/mx4j/server/interceptor/MBeanServerInterceptorConfigurator.java Mon Jul 17 05:14:31 2006
@@ -0,0 +1,197 @@
+/*
+ * Copyright (C) MX4J.
+ * All rights reserved.
+ *
+ * This software is distributed under the terms of the MX4J License version 1.0.
+ * See the terms of the MX4J License in the documentation provided with this software.
+ */
+
+/*
+ *   Copyright 2005 The Apache Software Foundation
+ *
+ *   Licensed under the Apache License, Version 2.0 (the "License");
+ *   you may not use this file except in compliance with the License.
+ *   You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing, software
+ *   distributed under the License is distributed on an "AS IS" BASIS,
+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *   See the License for the specific language governing permissions and
+ *   limitations under the License.
+ *
+ */
+package org.apache.felix.mosgi.jmx.agent.mx4j.server.interceptor;
+
+import java.util.ArrayList;
+
+import javax.management.MBeanException;
+import javax.management.MBeanServer;
+import javax.management.ObjectName;
+
+import org.apache.felix.mosgi.jmx.agent.mx4j.ImplementationException;
+
+/**
+ * MBean that configures the MBeanServer --> MBean interceptor chain.
+ *
+ * @author <a href="mailto:biorn_steedom@users.sourceforge.net">Simone Bordet</a>
+ * @version $Revision: 1.1.1.1 $
+ */
+public class MBeanServerInterceptorConfigurator implements MBeanServerInterceptorConfiguratorMBean
+{
+	public static final String OBJECT_NAME = "JMImplementation:type=MBeanServerInterceptorConfigurator";
+
+	private final MBeanServer server;
+	private final ArrayList preInterceptors = new ArrayList();
+	private final ArrayList postInterceptors = new ArrayList();
+	private final ArrayList clientInterceptors = new ArrayList();
+	private volatile boolean running;
+   private boolean chainModified;
+   private MBeanServerInterceptor head;
+
+   /**
+	 * Creates an instance of this configurator, for the given MBeanServer
+	 */
+	public MBeanServerInterceptorConfigurator(MBeanServer server)
+	{
+		this.server = server;
+      chainModified = true;
+	}
+
+	/**
+	 * Appends the given interceptor, provided by the client, to the existing interceptor chain.
+	 * @see #registerInterceptor
+	 */
+	public void addInterceptor(MBeanServerInterceptor interceptor)
+	{
+		synchronized (clientInterceptors)
+		{
+			clientInterceptors.add(interceptor);
+         chainModified = true;
+		}
+	}
+
+	/**
+	 * Appends the given interceptor, provided by the client, to the existing interceptor chain and registers it as MBean.
+	 * @see #addInterceptor
+	 */
+	public void registerInterceptor(MBeanServerInterceptor interceptor, ObjectName name) throws MBeanException
+	{
+		// First, try register this interceptor. The call will use the old interceptor chain
+		try
+		{
+			server.registerMBean(interceptor, name);
+         addInterceptor(interceptor);
+		}
+		catch (Exception x)
+		{
+			throw new MBeanException(x, "Could not register interceptor with name " + name);
+		}
+	}
+
+	/**
+	 * Removes all the interceptors added via {@link #addInterceptor(MBeanServerInterceptor interceptor)}.
+	 * @see #addInterceptor
+	 */
+	public void clearInterceptors()
+	{
+		synchronized (clientInterceptors)
+		{
+			clientInterceptors.clear();
+         chainModified = true;
+		}
+	}
+
+	/**
+	 * Adds the given interceptor at the beginning of the interceptor chain, before the custom interceptors that may be added
+	 * via {@link #addInterceptor}.
+	 * This method is called by the MBeanServer during initialization, to configure the interceptors needed to work properly.
+	 */
+	public void addPreInterceptor(MBeanServerInterceptor interceptor)
+	{
+		if (isRunning()) throw new ImplementationException();
+      preInterceptors.add(interceptor);
+	}
+
+	/**
+	 * Adds the given interceptor at the end of the interceptor chain, after the custom interceptors that may be added
+	 * via {@link #addInterceptor}.
+	 * This method is called by the MBeanServer during initialization, to configure the interceptors needed to work properly.
+	 */
+	public void addPostInterceptor(MBeanServerInterceptor interceptor)
+	{
+      if (isRunning()) throw new ImplementationException();
+      postInterceptors.add(interceptor);
+	}
+
+	/**
+	 * Returns the head interceptor of the interceptor chain.
+	 * The head interceptor is always present.
+	 */
+	public MBeanServerInterceptor getHeadInterceptor()
+	{
+		if (!isRunning()) return null;
+
+      if (chainModified) setupChain();
+
+      return head;
+	}
+
+   private void setupChain()
+   {
+      chainModified = false;
+
+      int size = clientInterceptors.size();
+      ArrayList chain = new ArrayList(preInterceptors.size() + size + postInterceptors.size());
+      chain.addAll(preInterceptors);
+      if (size > 0)
+      {
+         synchronized (clientInterceptors)
+         {
+            chain.addAll(clientInterceptors);
+         }
+      }
+      chain.addAll(postInterceptors);
+
+      // Set the chain on the first interceptor
+      MBeanServerInterceptor first = (MBeanServerInterceptor)chain.get(0);
+      first.setChain(chain);
+
+      head = first;
+   }
+
+	/**
+	 * Starts this configurator, so that the MBeanServer is now able to accept incoming calls.
+	 * @see #stop
+	 * @see #isRunning
+	 */
+	public void start()
+	{
+		if (!isRunning())
+		{
+			running = true;
+		}
+	}
+
+	/**
+	 * Stops this configurator, so that the MBeanServer is not able to accept incoming calls.
+	 * @see #start
+	 */
+	public void stop()
+	{
+		if (isRunning())
+		{
+			running = false;
+		}
+	}
+
+	/**
+	 * Returns whether this configurator is running and thus if the MBeanServer can accept incoming calls
+	 * @see #start
+	 */
+	public boolean isRunning()
+	{
+		return running;
+	}
+}

Added: incubator/felix/trunk/org.apache.felix.mosgi.jmx.agent/src/main/java/org/apache/felix/mosgi/jmx/agent/mx4j/server/interceptor/MBeanServerInterceptorConfiguratorMBean.java
URL: http://svn.apache.org/viewvc/incubator/felix/trunk/org.apache.felix.mosgi.jmx.agent/src/main/java/org/apache/felix/mosgi/jmx/agent/mx4j/server/interceptor/MBeanServerInterceptorConfiguratorMBean.java?rev=422696&view=auto
==============================================================================
--- incubator/felix/trunk/org.apache.felix.mosgi.jmx.agent/src/main/java/org/apache/felix/mosgi/jmx/agent/mx4j/server/interceptor/MBeanServerInterceptorConfiguratorMBean.java (added)
+++ incubator/felix/trunk/org.apache.felix.mosgi.jmx.agent/src/main/java/org/apache/felix/mosgi/jmx/agent/mx4j/server/interceptor/MBeanServerInterceptorConfiguratorMBean.java Mon Jul 17 05:14:31 2006
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) MX4J.
+ * All rights reserved.
+ *
+ * This software is distributed under the terms of the MX4J License version 1.0.
+ * See the terms of the MX4J License in the documentation provided with this software.
+ */
+/*
+ *   Copyright 2005 The Apache Software Foundation
+ *
+ *   Licensed under the Apache License, Version 2.0 (the "License");
+ *   you may not use this file except in compliance with the License.
+ *   You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing, software
+ *   distributed under the License is distributed on an "AS IS" BASIS,
+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *   See the License for the specific language governing permissions and
+ *   limitations under the License.
+ *
+ */
+package org.apache.felix.mosgi.jmx.agent.mx4j.server.interceptor;
+
+
+import javax.management.MBeanException;
+import javax.management.ObjectName;
+
+/**
+ * Management interface for the MBeanServerInterceptorConfigurator MBean.
+ * @author <a href="mailto:biorn_steedom@users.sourceforge.net">Simone Bordet</a>
+ * @version $Revision: 1.1.1.1 $
+ */
+public interface MBeanServerInterceptorConfiguratorMBean
+{
+   /**
+    * Appends the given interceptor, provided by the client, to the existing interceptor chain.
+    * @see #registerInterceptor
+    */
+   public void addInterceptor(MBeanServerInterceptor interceptor);
+
+   /**
+    * Appends the given interceptor, provided by the client, to the existing interceptor chain and registers it as MBean.
+    * @see #addInterceptor
+    */
+   public void registerInterceptor(MBeanServerInterceptor interceptor, ObjectName name) throws MBeanException;
+
+   /**
+    * Removes all the interceptors added via {@link #addInterceptor(MBeanServerInterceptor interceptor)}.
+    * @see #addInterceptor
+    */
+   public void clearInterceptors();
+
+   /**
+    * Starts this configurator, so that the MBeanServer is now able to accept incoming calls.
+    * @see #stop
+    * @see #isRunning
+    */
+   public void start();
+
+   /**
+    * Stops this configurator, so that the MBeanServer is not able to accept incoming calls.
+    * @see #start
+    */
+   public void stop();
+
+   /**
+    * Returns whether this configurator is running and thus if the MBeanServer can accept incoming calls
+    * @see #start
+    */
+   public boolean isRunning();
+}

Added: incubator/felix/trunk/org.apache.felix.mosgi.jmx.agent/src/main/java/org/apache/felix/mosgi/jmx/agent/mx4j/server/interceptor/NotificationListenerMBeanServerInterceptor.java
URL: http://svn.apache.org/viewvc/incubator/felix/trunk/org.apache.felix.mosgi.jmx.agent/src/main/java/org/apache/felix/mosgi/jmx/agent/mx4j/server/interceptor/NotificationListenerMBeanServerInterceptor.java?rev=422696&view=auto
==============================================================================
--- incubator/felix/trunk/org.apache.felix.mosgi.jmx.agent/src/main/java/org/apache/felix/mosgi/jmx/agent/mx4j/server/interceptor/NotificationListenerMBeanServerInterceptor.java (added)
+++ incubator/felix/trunk/org.apache.felix.mosgi.jmx.agent/src/main/java/org/apache/felix/mosgi/jmx/agent/mx4j/server/interceptor/NotificationListenerMBeanServerInterceptor.java Mon Jul 17 05:14:31 2006
@@ -0,0 +1,150 @@
+/*
+ * Copyright (C) MX4J.
+ * All rights reserved.
+ *
+ * This software is distributed under the terms of the MX4J License version 1.0.
+ * See the terms of the MX4J License in the documentation provided with this software.
+ */
+/*
+ *   Copyright 2005 The Apache Software Foundation
+ *
+ *   Licensed under the Apache License, Version 2.0 (the "License");
+ *   you may not use this file except in compliance with the License.
+ *   You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing, software
+ *   distributed under the License is distributed on an "AS IS" BASIS,
+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *   See the License for the specific language governing permissions and
+ *   limitations under the License.
+ *
+ */
+package org.apache.felix.mosgi.jmx.agent.mx4j.server.interceptor;
+
+import javax.management.ListenerNotFoundException;
+import javax.management.Notification;
+import javax.management.NotificationFilter;
+import javax.management.NotificationListener;
+import javax.management.ObjectName;
+
+import org.apache.felix.mosgi.jmx.agent.mx4j.server.MBeanMetaData;
+
+/**
+ * Interceptor that takes care of replacing the source of Notifications to the
+ * ObjectName of the NotificationBroadcaster that emitted it.
+ *
+ * @author <a href="mailto:biorn_steedom@users.sourceforge.net">Simone Bordet</a>
+ * @version $Revision: 1.1.1.1 $
+ */
+public class NotificationListenerMBeanServerInterceptor extends DefaultMBeanServerInterceptor
+{
+   private static class ListenerWrapper implements NotificationListener
+   {
+      private final NotificationListener listener;
+      private final ObjectName objectName;
+
+      private ListenerWrapper(NotificationListener listener, ObjectName name)
+      {
+         this.listener = listener;
+         this.objectName = name;
+      }
+
+      public void handleNotification(Notification notification, Object handback)
+      {
+         // The JMX spec does not specify how to change the source to be the ObjectName
+         // of the broadcaster. If we serialize the calls to the listeners, then it's
+         // possible to change the source and restore it back to the old value before
+         // calling the next listener; but if we want to support concurrent calls
+         // to the listeners, this is not possible. Here I chose to support concurrent
+         // calls so I change the value once and I never restore it.
+         Object src = notification.getSource();
+         if (!(src instanceof ObjectName))
+         {
+            // Change the source to be the ObjectName of the notification broadcaster
+            // if we are not already an ObjectName (compliant with RI behaviour)
+            notification.setSource(objectName);
+         }
+
+         // Notify the real listener
+         NotificationListener listener = getTargetListener();
+         listener.handleNotification(notification, handback);
+      }
+
+      private NotificationListener getTargetListener()
+      {
+         return listener;
+      }
+
+      public int hashCode()
+      {
+         return getTargetListener().hashCode();
+      }
+
+      public boolean equals(Object obj)
+      {
+         if (obj == null) return false;
+         if (obj == this) return true;
+
+         try
+         {
+            ListenerWrapper other = (ListenerWrapper)obj;
+            return getTargetListener().equals(other.getTargetListener());
+         }
+         catch (ClassCastException ignored)
+         {
+         }
+         return false;
+      }
+
+      public String toString()
+      {
+         return getTargetListener().toString();
+      }
+   }
+
+   public String getType()
+   {
+      return "notificationlistener";
+   }
+
+   public void addNotificationListener(MBeanMetaData metadata, NotificationListener listener, NotificationFilter filter, Object handback)
+   {
+      if (isEnabled())
+      {
+         ListenerWrapper wrapper = new ListenerWrapper(listener, metadata.name);
+         super.addNotificationListener(metadata, wrapper, filter, handback);
+      }
+      else
+      {
+         super.addNotificationListener(metadata, listener, filter, handback);
+      }
+   }
+
+   public void removeNotificationListener(MBeanMetaData metadata, NotificationListener listener) throws ListenerNotFoundException
+   {
+      if (isEnabled())
+      {
+         ListenerWrapper wrapper = new ListenerWrapper(listener, metadata.name);
+         super.removeNotificationListener(metadata, wrapper);
+      }
+      else
+      {
+         super.removeNotificationListener(metadata, listener);
+      }
+   }
+
+   public void removeNotificationListener(MBeanMetaData metadata, NotificationListener listener, NotificationFilter filter, Object handback) throws ListenerNotFoundException
+   {
+      if (isEnabled())
+      {
+         ListenerWrapper wrapper = new ListenerWrapper(listener, metadata.name);
+         super.removeNotificationListener(metadata, wrapper, filter, handback);
+      }
+      else
+      {
+         super.removeNotificationListener(metadata, listener, filter, handback);
+      }
+   }
+}

Added: incubator/felix/trunk/org.apache.felix.mosgi.jmx.agent/src/main/java/org/apache/felix/mosgi/jmx/agent/mx4j/server/interceptor/SecurityMBeanServerInterceptor.java
URL: http://svn.apache.org/viewvc/incubator/felix/trunk/org.apache.felix.mosgi.jmx.agent/src/main/java/org/apache/felix/mosgi/jmx/agent/mx4j/server/interceptor/SecurityMBeanServerInterceptor.java?rev=422696&view=auto
==============================================================================
--- incubator/felix/trunk/org.apache.felix.mosgi.jmx.agent/src/main/java/org/apache/felix/mosgi/jmx/agent/mx4j/server/interceptor/SecurityMBeanServerInterceptor.java (added)
+++ incubator/felix/trunk/org.apache.felix.mosgi.jmx.agent/src/main/java/org/apache/felix/mosgi/jmx/agent/mx4j/server/interceptor/SecurityMBeanServerInterceptor.java Mon Jul 17 05:14:31 2006
@@ -0,0 +1,209 @@
+/*
+ * Copyright (C) MX4J.
+ * All rights reserved.
+ *
+ * This software is distributed under the terms of the MX4J License version 1.0.
+ * See the terms of the MX4J License in the documentation provided with this software.
+ */
+/*
+ *   Copyright 2005 The Apache Software Foundation
+ *
+ *   Licensed under the Apache License, Version 2.0 (the "License");
+ *   you may not use this file except in compliance with the License.
+ *   You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing, software
+ *   distributed under the License is distributed on an "AS IS" BASIS,
+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *   See the License for the specific language governing permissions and
+ *   limitations under the License.
+ *
+ */
+package org.apache.felix.mosgi.jmx.agent.mx4j.server.interceptor;
+
+
+import java.security.AccessControlException;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.security.ProtectionDomain;
+import java.util.ArrayList;
+
+import javax.management.Attribute;
+import javax.management.AttributeList;
+import javax.management.AttributeNotFoundException;
+import javax.management.InvalidAttributeValueException;
+import javax.management.ListenerNotFoundException;
+import javax.management.MBeanException;
+import javax.management.MBeanInfo;
+import javax.management.MBeanRegistrationException;
+import javax.management.NotificationFilter;
+import javax.management.NotificationListener;
+import javax.management.ObjectName;
+import javax.management.ReflectionException;
+import javax.management.MBeanPermission;
+import javax.management.MBeanTrustPermission;
+
+import org.apache.felix.mosgi.jmx.agent.mx4j.server.MBeanMetaData;
+
+/**
+ * Interceptor that takes care of performing security checks (in case the SecurityManager is installed) for
+ * MBeanServer to MBean calls.
+ *
+ * @author <a href="mailto:biorn_steedom@users.sourceforge.net">Simone Bordet</a>
+ * @version $Revision: 1.1.1.1 $
+ */
+public class SecurityMBeanServerInterceptor extends DefaultMBeanServerInterceptor implements SecurityMBeanServerInterceptorMBean
+{
+   public String getType()
+   {
+      return "security";
+   }
+
+   public boolean isEnabled()
+   {
+      return true;
+   }
+
+   public void addNotificationListener(MBeanMetaData metadata, NotificationListener listener, NotificationFilter filter, Object handback)
+   {
+      checkPermission(metadata.info.getClassName(), null, metadata.name, "addNotificationListener");
+      super.addNotificationListener(metadata, listener, filter, handback);
+   }
+
+   public void removeNotificationListener(MBeanMetaData metadata, NotificationListener listener) throws ListenerNotFoundException
+   {
+      checkPermission(metadata.info.getClassName(), null, metadata.name, "removeNotificationListener");
+      super.removeNotificationListener(metadata, listener);
+   }
+
+   public void removeNotificationListener(MBeanMetaData metadata, NotificationListener listener, NotificationFilter filter, Object handback) throws ListenerNotFoundException
+   {
+      checkPermission(metadata.info.getClassName(), null, metadata.name, "removeNotificationListener");
+      super.removeNotificationListener(metadata, listener, filter, handback);
+   }
+
+   public void instantiate(MBeanMetaData metadata, String className, String[] params, Object[] args) throws ReflectionException, MBeanException
+   {
+      checkPermission(className, null, metadata.name, "instantiate");
+      super.instantiate(metadata, className, params, args);
+   }
+
+   public MBeanInfo getMBeanInfo(MBeanMetaData metadata)
+   {
+      checkPermission(metadata.info.getClassName(), null, metadata.name, "getMBeanInfo");
+      return super.getMBeanInfo(metadata);
+   }
+
+   public Object invoke(MBeanMetaData metadata, String method, String[] params, Object[] args) throws MBeanException, ReflectionException
+   {
+      checkPermission(metadata.info.getClassName(), method, metadata.name, "invoke");
+      return super.invoke(metadata, method, params, args);
+   }
+
+   public AttributeList getAttributes(MBeanMetaData metadata, String[] attributes)
+   {
+      Object[] secured = filterAttributes(metadata.info.getClassName(), metadata.name, attributes, true);
+      String[] array = new String[secured.length];
+      for (int i = 0; i < array.length; ++i) array[i] = (String)secured[i];
+      return super.getAttributes(metadata, array);
+   }
+
+   public AttributeList setAttributes(MBeanMetaData metadata, AttributeList attributes)
+   {
+      Object[] secured = filterAttributes(metadata.info.getClassName(), metadata.name, attributes.toArray(), false);
+      AttributeList list = new AttributeList();
+      for (int i = 0; i < secured.length; ++i) list.add(secured[i]);
+      return super.setAttributes(metadata, list);
+   }
+
+   public Object getAttribute(MBeanMetaData metadata, String attribute) throws MBeanException, AttributeNotFoundException, ReflectionException
+   {
+      checkPermission(metadata.info.getClassName(), attribute, metadata.name, "getAttribute");
+      return super.getAttribute(metadata, attribute);
+   }
+
+   public void setAttribute(MBeanMetaData metadata, Attribute attribute) throws MBeanException, AttributeNotFoundException, InvalidAttributeValueException, ReflectionException
+   {
+      checkPermission(metadata.info.getClassName(), attribute.getName(), metadata.name, "setAttribute");
+      super.setAttribute(metadata, attribute);
+   }
+
+   public void registration(MBeanMetaData metadata, int operation) throws MBeanRegistrationException
+   {
+      switch (operation)
+      {
+         case PRE_REGISTER:
+            checkPermission(metadata.info.getClassName(), null, metadata.name, "registerMBean");
+            checkTrustRegistration(metadata.mbean.getClass());
+            break;
+         case POST_REGISTER_TRUE:
+            // The MBean can implement MBeanRegistration and change the ObjectName
+            checkPermission(metadata.info.getClassName(), null, metadata.name, "registerMBean");
+            break;
+         case PRE_DEREGISTER:
+            checkPermission(metadata.info.getClassName(), null, metadata.name, "unregisterMBean");
+            break;
+         default:
+            break;
+      }
+      super.registration(metadata, operation);
+   }
+
+   private void checkPermission(String className, String methodName, ObjectName objectname, String action)
+   {
+      SecurityManager sm = System.getSecurityManager();
+      if (sm != null)
+      {
+         sm.checkPermission(new MBeanPermission(className, methodName, objectname, action));
+      }
+   }
+
+   private void checkTrustRegistration(final Class cls)
+   {
+      SecurityManager sm = System.getSecurityManager();
+      if (sm != null)
+      {
+         ProtectionDomain domain = (ProtectionDomain)AccessController.doPrivileged(new PrivilegedAction()
+         {
+            public Object run()
+            {
+               return cls.getProtectionDomain();
+            }
+         });
+
+         MBeanTrustPermission permission = new MBeanTrustPermission("register");
+         if (!domain.implies(permission))
+         {
+            throw new AccessControlException("Access denied " + permission + ": MBean class " + cls.getName() + " is not trusted for registration");
+         }
+      }
+   }
+
+   private Object[] filterAttributes(String className, ObjectName objectName, Object[] attributes, boolean isGet)
+   {
+      SecurityManager sm = System.getSecurityManager();
+      if (sm == null) return attributes;
+
+      ArrayList list = new ArrayList();
+
+      for (int i = 0; i < attributes.length; ++i)
+      {
+         Object attribute = attributes[i];
+         String name = isGet ? (String)attribute : ((Attribute)attribute).getName();
+
+         try
+         {
+            checkPermission(className, name, objectName, isGet ? "getAttribute" : "setAttribute");
+            list.add(attribute);
+         }
+         catch (SecurityException ignore)
+         {
+            // This is ok.  We just don't add this attribute to the list
+         }
+      }
+
+      return list.toArray();
+   }
+}

Added: incubator/felix/trunk/org.apache.felix.mosgi.jmx.agent/src/main/java/org/apache/felix/mosgi/jmx/agent/mx4j/server/interceptor/SecurityMBeanServerInterceptorMBean.java
URL: http://svn.apache.org/viewvc/incubator/felix/trunk/org.apache.felix.mosgi.jmx.agent/src/main/java/org/apache/felix/mosgi/jmx/agent/mx4j/server/interceptor/SecurityMBeanServerInterceptorMBean.java?rev=422696&view=auto
==============================================================================
--- incubator/felix/trunk/org.apache.felix.mosgi.jmx.agent/src/main/java/org/apache/felix/mosgi/jmx/agent/mx4j/server/interceptor/SecurityMBeanServerInterceptorMBean.java (added)
+++ incubator/felix/trunk/org.apache.felix.mosgi.jmx.agent/src/main/java/org/apache/felix/mosgi/jmx/agent/mx4j/server/interceptor/SecurityMBeanServerInterceptorMBean.java Mon Jul 17 05:14:31 2006
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) MX4J.
+ * All rights reserved.
+ *
+ * This software is distributed under the terms of the MX4J License version 1.0.
+ * See the terms of the MX4J License in the documentation provided with this software.
+ */
+/*
+ *   Copyright 2005 The Apache Software Foundation
+ *
+ *   Licensed under the Apache License, Version 2.0 (the "License");
+ *   you may not use this file except in compliance with the License.
+ *   You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing, software
+ *   distributed under the License is distributed on an "AS IS" BASIS,
+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *   See the License for the specific language governing permissions and
+ *   limitations under the License.
+ *
+ */
+package org.apache.felix.mosgi.jmx.agent.mx4j.server.interceptor;
+
+
+/**
+ * Management interface for the SecurityMBeanServerInterceptor MBean
+ * @author <a href="mailto:biorn_steedom@users.sourceforge.net">Simone Bordet</a>
+ * @version $Revision: 1.1.1.1 $
+ */
+public interface SecurityMBeanServerInterceptorMBean
+{
+   /**
+    * Returns the type of this interceptor
+    */
+   public String getType();
+
+   /**
+    * This interceptor is always enabled
+    */
+   public boolean isEnabled();
+}

Added: incubator/felix/trunk/org.apache.felix.mosgi.jmx.agent/src/main/java/org/apache/felix/mosgi/jmx/agent/mx4j/util/Base64Codec.java
URL: http://svn.apache.org/viewvc/incubator/felix/trunk/org.apache.felix.mosgi.jmx.agent/src/main/java/org/apache/felix/mosgi/jmx/agent/mx4j/util/Base64Codec.java?rev=422696&view=auto
==============================================================================
--- incubator/felix/trunk/org.apache.felix.mosgi.jmx.agent/src/main/java/org/apache/felix/mosgi/jmx/agent/mx4j/util/Base64Codec.java (added)
+++ incubator/felix/trunk/org.apache.felix.mosgi.jmx.agent/src/main/java/org/apache/felix/mosgi/jmx/agent/mx4j/util/Base64Codec.java Mon Jul 17 05:14:31 2006
@@ -0,0 +1,402 @@
+/*
+ * Copyright (C) MX4J.
+ * All rights reserved.
+ *
+ * This software is distributed under the terms of the MX4J License version 1.0.
+ * See the terms of the MX4J License in the documentation provided with this software.
+ */
+/*
+ *   Copyright 2005 The Apache Software Foundation
+ *
+ *   Licensed under the Apache License, Version 2.0 (the "License");
+ *   you may not use this file except in compliance with the License.
+ *   You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing, software
+ *   distributed under the License is distributed on an "AS IS" BASIS,
+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *   See the License for the specific language governing permissions and
+ *   limitations under the License.
+ *
+ */
+package org.apache.felix.mosgi.jmx.agent.mx4j.util;
+
+
+/**
+ * This class is copy/paste of Jakarta's Commons-Codec v1.1 <code>org.apache.commons.codec.binary.Base64</code>
+ * implementation.
+ * It is reproduced here because we don't want to require a new jar just to perform Base64 code/decoding.
+ *
+ * @author <a href="mailto:biorn_steedom@users.sourceforge.net">Simone Bordet</a>
+ * @version $Revision: 1.1.1.1 $
+ */
+public class Base64Codec
+{
+   static final int CHUNK_SIZE = 76;
+   static final byte[] CHUNK_SEPARATOR = "\n".getBytes();
+
+   static final int BASELENGTH = 255;
+   static final int LOOKUPLENGTH = 64;
+   static final int TWENTYFOURBITGROUP = 24;
+   static final int EIGHTBIT = 8;
+   static final int SIXTEENBIT = 16;
+   static final int SIXBIT = 6;
+   static final int FOURBYTE = 4;
+   static final int SIGN = -128;
+   static final byte PAD = (byte)'=';
+
+   private static byte[] base64Alphabet = new byte[BASELENGTH];
+   private static byte[] lookUpBase64Alphabet = new byte[LOOKUPLENGTH];
+
+   static
+   {
+      for (int i = 0; i < BASELENGTH; i++)
+      {
+         base64Alphabet[i] = (byte)-1;
+      }
+      for (int i = 'Z'; i >= 'A'; i--)
+      {
+         base64Alphabet[i] = (byte)(i - 'A');
+      }
+      for (int i = 'z'; i >= 'a'; i--)
+      {
+         base64Alphabet[i] = (byte)(i - 'a' + 26);
+      }
+      for (int i = '9'; i >= '0'; i--)
+      {
+         base64Alphabet[i] = (byte)(i - '0' + 52);
+      }
+
+      base64Alphabet['+'] = 62;
+      base64Alphabet['/'] = 63;
+
+      for (int i = 0; i <= 25; i++)
+      {
+         lookUpBase64Alphabet[i] = (byte)('A' + i);
+      }
+
+      for (int i = 26, j = 0; i <= 51; i++, j++)
+      {
+         lookUpBase64Alphabet[i] = (byte)('a' + j);
+      }
+
+      for (int i = 52, j = 0; i <= 61; i++, j++)
+      {
+         lookUpBase64Alphabet[i] = (byte)('0' + j);
+      }
+
+      lookUpBase64Alphabet[62] = (byte)'+';
+      lookUpBase64Alphabet[63] = (byte)'/';
+   }
+
+   private Base64Codec()
+   {
+   }
+
+   public static boolean isArrayByteBase64(byte[] arrayOctect)
+   {
+      arrayOctect = discardWhitespace(arrayOctect);
+
+      int length = arrayOctect.length;
+      if (length == 0)
+      {
+         return true;
+      }
+      for (int i = 0; i < length; i++)
+      {
+         if (!isBase64(arrayOctect[i]))
+         {
+            return false;
+         }
+      }
+      return true;
+   }
+
+   public static byte[] encodeBase64(byte[] binaryData)
+   {
+      return (encodeBase64(binaryData, false));
+   }
+
+   public static byte[] decodeBase64(byte[] base64Data)
+   {
+      // RFC 2045 suggests line wrapping at (no more than) 76
+      // characters -- we may have embedded whitespace.
+      base64Data = discardWhitespace(base64Data);
+
+      // handle the edge case, so we don't have to worry about it later
+      if (base64Data.length == 0)
+      {
+         return new byte[0];
+      }
+
+      int numberQuadruple = base64Data.length / FOURBYTE;
+      byte decodedData[] = null;
+      byte b1 = 0, b2 = 0, b3 = 0, b4 = 0, marker0 = 0, marker1 = 0;
+
+      // Throw away anything not in base64Data
+
+      int encodedIndex = 0;
+      int dataIndex = 0;
+      {
+         // this sizes the output array properly - rlw
+         int lastData = base64Data.length;
+         // ignore the '=' padding
+         while (base64Data[lastData - 1] == PAD)
+         {
+            if (--lastData == 0)
+            {
+               return new byte[0];
+            }
+         }
+         decodedData = new byte[lastData - numberQuadruple];
+      }
+
+      for (int i = 0; i < numberQuadruple; i++)
+      {
+         dataIndex = i * 4;
+         marker0 = base64Data[dataIndex + 2];
+         marker1 = base64Data[dataIndex + 3];
+
+         b1 = base64Alphabet[base64Data[dataIndex]];
+         b2 = base64Alphabet[base64Data[dataIndex + 1]];
+
+         if (marker0 != PAD && marker1 != PAD)
+         {
+            //No PAD e.g 3cQl
+            b3 = base64Alphabet[marker0];
+            b4 = base64Alphabet[marker1];
+
+            decodedData[encodedIndex] = (byte)(b1 << 2 | b2 >> 4);
+            decodedData[encodedIndex + 1] =
+                    (byte)(((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf));
+            decodedData[encodedIndex + 2] = (byte)(b3 << 6 | b4);
+         }
+         else if (marker0 == PAD)
+         {
+            //Two PAD e.g. 3c[Pad][Pad]
+            decodedData[encodedIndex] = (byte)(b1 << 2 | b2 >> 4);
+         }
+         else if (marker1 == PAD)
+         {
+            //One PAD e.g. 3cQ[Pad]
+            b3 = base64Alphabet[marker0];
+
+            decodedData[encodedIndex] = (byte)(b1 << 2 | b2 >> 4);
+            decodedData[encodedIndex + 1] =
+                    (byte)(((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf));
+         }
+         encodedIndex += 3;
+      }
+      return decodedData;
+   }
+
+   private static byte[] encodeBase64Chunked(byte[] binaryData)
+   {
+      return (encodeBase64(binaryData, true));
+   }
+
+   private static boolean isBase64(byte octect)
+   {
+      if (octect == PAD)
+      {
+         return true;
+      }
+      else if (base64Alphabet[octect] == -1)
+      {
+         return false;
+      }
+      else
+      {
+         return true;
+      }
+   }
+
+   private static byte[] encodeBase64(byte[] binaryData, boolean isChunked)
+   {
+      int lengthDataBits = binaryData.length * EIGHTBIT;
+      int fewerThan24bits = lengthDataBits % TWENTYFOURBITGROUP;
+      int numberTriplets = lengthDataBits / TWENTYFOURBITGROUP;
+      byte encodedData[] = null;
+      int encodedDataLength = 0;
+      int nbrChunks = 0;
+
+      if (fewerThan24bits != 0)
+      {
+         //data not divisible by 24 bit
+         encodedDataLength = (numberTriplets + 1) * 4;
+      }
+      else
+      {
+         // 16 or 8 bit
+         encodedDataLength = numberTriplets * 4;
+      }
+
+      // If the output is to be "chunked" into 76 character sections,
+      // for compliance with RFC 2045 MIME, then it is important to
+      // allow for extra length to account for the separator(s)
+      if (isChunked)
+      {
+
+         nbrChunks =
+                 (CHUNK_SEPARATOR.length == 0
+                 ? 0
+                 : (int)Math.ceil((float)encodedDataLength / CHUNK_SIZE));
+         encodedDataLength += nbrChunks * CHUNK_SEPARATOR.length;
+      }
+
+      encodedData = new byte[encodedDataLength];
+
+      byte k = 0, l = 0, b1 = 0, b2 = 0, b3 = 0;
+
+      int encodedIndex = 0;
+      int dataIndex = 0;
+      int i = 0;
+      int nextSeparatorIndex = CHUNK_SIZE;
+      int chunksSoFar = 0;
+
+      //log.debug("number of triplets = " + numberTriplets);
+      for (i = 0; i < numberTriplets; i++)
+      {
+         dataIndex = i * 3;
+         b1 = binaryData[dataIndex];
+         b2 = binaryData[dataIndex + 1];
+         b3 = binaryData[dataIndex + 2];
+
+         //log.debug("b1= " + b1 +", b2= " + b2 + ", b3= " + b3);
+
+         l = (byte)(b2 & 0x0f);
+         k = (byte)(b1 & 0x03);
+
+         byte val1 =
+                 ((b1 & SIGN) == 0)
+                 ? (byte)(b1 >> 2)
+                 : (byte)((b1) >> 2 ^ 0xc0);
+         byte val2 =
+                 ((b2 & SIGN) == 0)
+                 ? (byte)(b2 >> 4)
+                 : (byte)((b2) >> 4 ^ 0xf0);
+         byte val3 =
+                 ((b3 & SIGN) == 0)
+                 ? (byte)(b3 >> 6)
+                 : (byte)((b3) >> 6 ^ 0xfc);
+
+         encodedData[encodedIndex] = lookUpBase64Alphabet[val1];
+         //log.debug( "val2 = " + val2 );
+         //log.debug( "k4   = " + (k<<4) );
+         //log.debug(  "vak  = " + (val2 | (k<<4)) );
+         encodedData[encodedIndex + 1] =
+                 lookUpBase64Alphabet[val2 | (k << 4)];
+         encodedData[encodedIndex + 2] =
+                 lookUpBase64Alphabet[(l << 2) | val3];
+         encodedData[encodedIndex + 3] = lookUpBase64Alphabet[b3 & 0x3f];
+
+         encodedIndex += 4;
+
+         // If we are chunking, let's put a chunk separator down.
+         if (isChunked)
+         {
+            // this assumes that CHUNK_SIZE % 4 == 0
+            if (encodedIndex == nextSeparatorIndex)
+            {
+               System.arraycopy(
+                       CHUNK_SEPARATOR,
+                       0,
+                       encodedData,
+                       encodedIndex,
+                       CHUNK_SEPARATOR.length);
+               chunksSoFar++;
+               nextSeparatorIndex =
+                       (CHUNK_SIZE * (chunksSoFar + 1))
+                       + (chunksSoFar * CHUNK_SEPARATOR.length);
+               encodedIndex += CHUNK_SEPARATOR.length;
+            }
+         }
+      }
+
+      // form integral number of 6-bit groups
+      dataIndex = i * 3;
+
+      if (fewerThan24bits == EIGHTBIT)
+      {
+         b1 = binaryData[dataIndex];
+         k = (byte)(b1 & 0x03);
+         //log.debug("b1=" + b1);
+         //log.debug("b1<<2 = " + (b1>>2) );
+         byte val1 =
+                 ((b1 & SIGN) == 0)
+                 ? (byte)(b1 >> 2)
+                 : (byte)((b1) >> 2 ^ 0xc0);
+         encodedData[encodedIndex] = lookUpBase64Alphabet[val1];
+         encodedData[encodedIndex + 1] = lookUpBase64Alphabet[k << 4];
+         encodedData[encodedIndex + 2] = PAD;
+         encodedData[encodedIndex + 3] = PAD;
+      }
+      else if (fewerThan24bits == SIXTEENBIT)
+      {
+
+         b1 = binaryData[dataIndex];
+         b2 = binaryData[dataIndex + 1];
+         l = (byte)(b2 & 0x0f);
+         k = (byte)(b1 & 0x03);
+
+         byte val1 =
+                 ((b1 & SIGN) == 0)
+                 ? (byte)(b1 >> 2)
+                 : (byte)((b1) >> 2 ^ 0xc0);
+         byte val2 =
+                 ((b2 & SIGN) == 0)
+                 ? (byte)(b2 >> 4)
+                 : (byte)((b2) >> 4 ^ 0xf0);
+
+         encodedData[encodedIndex] = lookUpBase64Alphabet[val1];
+         encodedData[encodedIndex + 1] =
+                 lookUpBase64Alphabet[val2 | (k << 4)];
+         encodedData[encodedIndex + 2] = lookUpBase64Alphabet[l << 2];
+         encodedData[encodedIndex + 3] = PAD;
+      }
+
+      if (isChunked)
+      {
+         // we also add a separator to the end of the final chunk.
+         if (chunksSoFar < nbrChunks)
+         {
+            System.arraycopy(
+                    CHUNK_SEPARATOR,
+                    0,
+                    encodedData,
+                    encodedDataLength - CHUNK_SEPARATOR.length,
+                    CHUNK_SEPARATOR.length);
+         }
+      }
+
+      return encodedData;
+   }
+
+   private static byte[] discardWhitespace(byte[] data)
+   {
+      byte groomedData[] = new byte[data.length];
+      int bytesCopied = 0;
+
+      for (int i = 0; i < data.length; i++)
+      {
+         switch (data[i])
+         {
+            case (byte)' ':
+            case (byte)'\n':
+            case (byte)'\r':
+            case (byte)'\t':
+               break;
+            default:
+               groomedData[bytesCopied++] = data[i];
+         }
+      }
+
+      byte packedData[] = new byte[bytesCopied];
+
+      System.arraycopy(groomedData, 0, packedData, 0, bytesCopied);
+
+      return packedData;
+   }
+}

Added: incubator/felix/trunk/org.apache.felix.mosgi.jmx.agent/src/main/java/org/apache/felix/mosgi/jmx/agent/mx4j/util/MethodTernaryTree.java
URL: http://svn.apache.org/viewvc/incubator/felix/trunk/org.apache.felix.mosgi.jmx.agent/src/main/java/org/apache/felix/mosgi/jmx/agent/mx4j/util/MethodTernaryTree.java?rev=422696&view=auto
==============================================================================
--- incubator/felix/trunk/org.apache.felix.mosgi.jmx.agent/src/main/java/org/apache/felix/mosgi/jmx/agent/mx4j/util/MethodTernaryTree.java (added)
+++ incubator/felix/trunk/org.apache.felix.mosgi.jmx.agent/src/main/java/org/apache/felix/mosgi/jmx/agent/mx4j/util/MethodTernaryTree.java Mon Jul 17 05:14:31 2006
@@ -0,0 +1,199 @@
+/*
+ * Copyright (C) MX4J.
+ * All rights reserved.
+ *
+ * This software is distributed under the terms of the MX4J License version 1.0.
+ * See the terms of the MX4J License in the documentation provided with this software.
+ */
+/*
+ *   Copyright 2005 The Apache Software Foundation
+ *
+ *   Licensed under the Apache License, Version 2.0 (the "License");
+ *   you may not use this file except in compliance with the License.
+ *   You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing, software
+ *   distributed under the License is distributed on an "AS IS" BASIS,
+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *   See the License for the specific language governing permissions and
+ *   limitations under the License.
+ *
+ */
+package org.apache.felix.mosgi.jmx.agent.mx4j.util;
+
+
+/**
+ * Specialized ternary tree for method metadata information. <p>
+ * In JMX methods are referred to with the method name and the String[] representing the signature.
+ * One can decide to cache method information using as key a concatenation of method name + signature,
+ * but the cost of concatenation is very high, while hashmap access is fast.
+ * Ternary trees avoid string concatenation, and result to be 10x faster than concatenation + hashmap.
+ * However, the signature of a standard TernaryTree would be <code>Object get(Object[] key)</code> and
+ * <code>void put(Object[] key, Object value)</code>. Unfortunately normalizing method name + signature
+ * into a single array is also very expensive. <br>
+ * This version leaves method name and signature separated to have the fastest access possible to
+ * method information.
+ * See <a href="http://www.ddj.com/documents/s=921/ddj9804a/9804a.htm">here</a> for further information
+ * on TernaryTrees.
+ *
+ * @author <a href="mailto:biorn_steedom@users.sourceforge.net">Simone Bordet</a>
+ * @version $Revision: 1.1.1.1 $
+ */
+public class MethodTernaryTree
+{
+	private Node m_root;
+
+	/**
+	 * Returns the method information given the method name and its signature.
+	 * @see #put
+	 */
+	public Object get(String methodName, String[] signature)
+	{
+		if (signature == null) {throw new IllegalArgumentException();}
+		return search(methodName, signature);
+	}
+
+	/**
+	 * Inserts in this TernaryTree the given method information, using as key the method name and its signature
+	 * @see #get
+	 */
+	public void put(String methodName, String[] signature, Object information)
+	{
+		if (signature == null) {throw new IllegalArgumentException();}
+		m_root = insert(m_root, methodName, signature, signature.length, information);
+	}
+
+	private Object search(String methodName, String[] signature)
+	{
+		Node node = m_root;
+		int index = 0;
+		while (node != null)
+		{
+			Object key = index == 0 ? methodName : signature[index - 1];
+			if (key == null) {throw new IllegalArgumentException();}
+
+			int split = splitFunction(key);
+			if (split < node.splitValue)
+			{
+				node = node.left;
+			}
+			else if (split == node.splitValue)
+			{
+				if (index == signature.length)
+				{
+					// Two objects may return the same split, because the splitFunction is not perfect
+					// (ie does not always yield different values for different objects, eg hash functions)
+					if (node.keys == null) {return null;}
+					for (int i = 0; i < node.keys.length; ++i)
+					{
+						if (node.keys[i].equals(key))
+						{
+							return node.values[i];
+						}
+					}
+					return null;
+				}
+				else
+				{
+					++index;
+					node = node.middle;
+				}
+			}
+			else
+			{
+				node = node.right;
+			}
+		}
+		return null;
+	}
+
+	private Node insert(Node node, String methodName, String[] signature, int length, Object value)
+	{
+		Object key = methodName;
+		if (key == null) {throw new IllegalArgumentException();}
+
+		int split = splitFunction(key);
+		if (node == null)
+		{
+			node = new Node();
+			node.splitValue = split;
+		}
+
+		if (split < node.splitValue)
+		{
+			node.left = insert(node.left, methodName, signature, length, value);
+		}
+		else if (split == node.splitValue)
+		{
+			// Two objects may return the same split, because the splitFunction is not perfect
+			// (ie does not always yield different values for different objects, eg hash functions)
+			if (length == 0)
+			{
+				if (node.keys == null)
+				{
+					node.keys = new Object[1];
+					node.values = new Object[1];
+					node.keys[0] = key;
+					node.values[0] = value;
+				}
+				else
+				{
+					// Loop to see if the key already exists
+					boolean found = false;
+					for (int i = 0; i < node.keys.length; ++i)
+					{
+						if (node.keys[i].equals(key))
+						{
+							// Already present, replace the value
+							node.keys[i] = key;
+							node.values[i] = value;
+							found = true;
+							break;
+						}
+					}
+					// Not present, add it
+					if (!found)
+					{
+						int len = node.keys.length;
+						Object[] olds = node.keys;
+						node.keys = new Object[len + 1];
+						System.arraycopy(olds, 0, node.keys, 0, len);
+						node.keys[len] = key;
+
+						olds = node.values;
+						node.values = new Object[len + 1];
+						System.arraycopy(olds, 0, node.values, 0, len);
+						node.values[len] = value;
+					}
+				}
+			}
+			else
+			{
+				node.middle = insert(node.middle, signature[signature.length - length], signature, length - 1, value);
+			}
+		}
+		else
+		{
+			node.right = insert(node.right, methodName, signature, length, value);
+		}
+
+		return node;
+	}
+
+	protected int splitFunction(Object obj)
+	{
+		return obj.hashCode();
+	}
+
+	private class Node
+	{
+		private int splitValue;
+		private Node right;
+		private Node middle;
+		private Node left;
+		private Object[] keys;
+		private Object[] values;
+	}
+}

Added: incubator/felix/trunk/org.apache.felix.mosgi.jmx.agent/src/main/java/org/apache/felix/mosgi/jmx/agent/mx4j/util/Utils.java
URL: http://svn.apache.org/viewvc/incubator/felix/trunk/org.apache.felix.mosgi.jmx.agent/src/main/java/org/apache/felix/mosgi/jmx/agent/mx4j/util/Utils.java?rev=422696&view=auto
==============================================================================
--- incubator/felix/trunk/org.apache.felix.mosgi.jmx.agent/src/main/java/org/apache/felix/mosgi/jmx/agent/mx4j/util/Utils.java (added)
+++ incubator/felix/trunk/org.apache.felix.mosgi.jmx.agent/src/main/java/org/apache/felix/mosgi/jmx/agent/mx4j/util/Utils.java Mon Jul 17 05:14:31 2006
@@ -0,0 +1,287 @@
+/*
+ * Copyright (C) MX4J.
+ * All rights reserved.
+ *
+ * This software is distributed under the terms of the MX4J License version 1.0.
+ * See the terms of the MX4J License in the documentation provided with this software.
+ */
+/*
+ *   Copyright 2005 The Apache Software Foundation
+ *
+ *   Licensed under the Apache License, Version 2.0 (the "License");
+ *   you may not use this file except in compliance with the License.
+ *   You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing, software
+ *   distributed under the License is distributed on an "AS IS" BASIS,
+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *   See the License for the specific language governing permissions and
+ *   limitations under the License.
+ *
+ */
+package org.apache.felix.mosgi.jmx.agent.mx4j.util;
+
+
+import java.lang.reflect.Array;
+import java.lang.reflect.Method;
+
+/**
+ * Several utility functions for the JMX implementation
+ *
+ * @author <a href="mailto:biorn_steedom@users.sourceforge.net">Simone Bordet</a>
+ * @version $Revision: 1.1.1.1 $
+ */
+public class Utils
+{
+	/**
+	 * This methods load a class given the classloader and the name of the class, and work for
+	 * extended names of primitive types. <p>
+	 * If you try to do ClassLoader.loadClass("boolean") it barfs it cannot find the class,
+	 * so this method cope with this problem.
+	 */
+	public static Class loadClass(ClassLoader loader, String name) throws ClassNotFoundException
+	{
+		if (name == null) throw new ClassNotFoundException("null");
+
+		name = name.trim();
+		if (name.equals("boolean")) return boolean.class;
+		else if (name.equals("byte")) return byte.class;
+		else if (name.equals("char")) return char.class;
+		else if (name.equals("short")) return short.class;
+		else if (name.equals("int")) return int.class;
+		else if (name.equals("long")) return long.class;
+		else if (name.equals("float")) return float.class;
+		else if (name.equals("double")) return double.class;
+		else if (name.equals("java.lang.String")) return String.class;
+		else if (name.equals("java.lang.Object")) return Object.class;
+		else if (name.startsWith("["))
+		{
+			// It's an array, figure out how many dimensions
+			int dimension = 0;
+			while (name.charAt(dimension) == '[')
+			{
+				++dimension;
+			}
+			char type = name.charAt(dimension);
+			Class cls = null;
+			switch (type)
+			{
+				case 'Z':
+					cls = boolean.class;
+					break;
+				case 'B':
+					cls = byte.class;
+					break;
+				case 'C':
+					cls = char.class;
+					break;
+				case 'S':
+					cls = short.class;
+					break;
+				case 'I':
+					cls = int.class;
+					break;
+				case 'J':
+					cls = long.class;
+					break;
+				case 'F':
+					cls = float.class;
+					break;
+				case 'D':
+					cls = double.class;
+					break;
+				case 'L':
+					// Strip the semicolon at the end
+					String n = name.substring(dimension + 1, name.length() - 1);
+					cls = loadClass(loader, n);
+					break;
+			}
+
+			if (cls == null)
+			{
+				throw new ClassNotFoundException(name);
+			}
+			else
+			{
+				int[] dim = new int[dimension];
+				return Array.newInstance(cls, dim).getClass();
+			}
+		}
+		else
+		{
+         if (loader != null)
+			   return loader.loadClass(name);
+         else
+            return Class.forName(name, false, null);
+		}
+	}
+
+	/**
+	 * Returns the classes whose names are specified by the <code>names</code> argument, loaded with the
+	 * specified classloader.
+	 */
+	public static Class[] loadClasses(ClassLoader loader, String[] names) throws ClassNotFoundException
+	{
+		int n = names.length;
+		Class[] cls = new Class[n];
+		for (int i = 0; i < n; ++i)
+		{
+			String name = names[i];
+			cls[i] = loadClass(loader, name);
+		}
+		return cls;
+	}
+
+	/**
+	 * Returns true is the given method is a JMX attribute getter method
+	 */
+	public static boolean isAttributeGetter(Method m)
+	{
+		if (m == null) return false;
+
+		String name = m.getName();
+		Class retType = m.getReturnType();
+		Class[] params = m.getParameterTypes();
+		if (retType != Void.TYPE && params.length == 0)
+		{
+			if (name.startsWith("get") && name.length() > 3) return true;
+			else if (name.startsWith("is") && retType == Boolean.TYPE) return true;
+		}
+		return false;
+	}
+
+	/**
+	 * Returns true if the method is a JMX attribute setter method
+	 */
+	public static boolean isAttributeSetter(Method m)
+	{
+		if (m == null) return false;
+
+		String name = m.getName();
+		Class retType = m.getReturnType();
+		Class[] params = m.getParameterTypes();
+		if (retType == Void.TYPE && params.length == 1 && name.startsWith("set") && name.length() > 3)
+		{
+			return true;
+		}
+		return false;
+	}
+
+	public static boolean wildcardMatch(String pattern, String string)
+	{
+		int stringLength = string.length();
+		int stringIndex = 0;
+		for (int patternIndex = 0; patternIndex < pattern.length(); ++patternIndex)
+		{
+			char c = pattern.charAt(patternIndex);
+			if (c == '*')
+			{
+				// Recurse with the pattern without this '*' and the actual string, until
+				// match is found or we inspected the whole string
+				while (stringIndex < stringLength)
+				{
+					if (wildcardMatch(pattern.substring(patternIndex + 1), string.substring(stringIndex)))
+					{
+						return true;
+					}
+					// No match found, try a shorter string, since we are matching '*'
+					++stringIndex;
+				}
+			}
+			else if (c == '?')
+			{
+				// Increment the string index, since '?' match a single char in the string
+				++stringIndex;
+				if (stringIndex > stringLength)
+				{
+					return false;
+				}
+			}
+			else
+			{
+				// A normal character in the pattern, must match the one in the string
+				if (stringIndex >= stringLength || c != string.charAt(stringIndex))
+				{
+					return false;
+				}
+				++stringIndex;
+			}
+		}
+
+		// I've inspected the whole pattern, but not the whole string
+		return stringIndex == stringLength;
+	}
+
+	public static boolean arrayEquals(Object[] arr1, Object[] arr2)
+	{
+		if (arr1 == null && arr2 == null) return true;
+		if (arr1 == null ^ arr2 == null) return false;
+		if (!arr1.getClass().equals(arr2.getClass())) return false;
+		if (arr1.length != arr2.length) return false;
+
+		for (int i = 0; i < arr1.length; ++i)
+		{
+			Object obj1 = arr1[i];
+			Object obj2 = arr2[i];
+			if (obj1 == null ^ obj2 == null) return false;
+			if (obj1 != null && !obj1.equals(obj2)) return false;
+		}
+		return true;
+	}
+
+	public static boolean arrayEquals(byte[] arr1, byte[] arr2)
+	{
+		if (arr1 == null && arr2 == null) return true;
+		if (arr1 == null ^ arr2 == null) return false;
+		if (!arr1.getClass().equals(arr2.getClass())) return false;
+		if (arr1.length != arr2.length) return false;
+
+		for (int i = 0; i < arr1.length; ++i)
+		{
+			byte b1 = arr1[i];
+			byte b2 = arr2[i];
+			if (b1 != b2) return false;
+		}
+		return true;
+	}
+
+	public static int arrayHashCode(Object[] arr)
+	{
+		int hash = 0;
+		if (arr != null)
+		{
+			// Avoid that 2 arrays of length 0 but different classes return same hash
+			hash ^= arr.getClass().hashCode();
+			for (int i = 0; i < arr.length; ++i)
+			{
+				hash ^= arr[i] == null ? 0 : arr[i].hashCode();
+			}
+		}
+		return hash;
+	}
+
+	public static int arrayHashCode(byte[] arr)
+	{
+		int hash = 0;
+		if (arr != null)
+		{
+			// Avoid that 2 arrays of length 0 but different classes return same hash
+			hash ^= arr.getClass().hashCode();
+			for (int i = 0; i < arr.length; ++i)
+			{
+				hash ^= arr[i];
+			}
+		}
+		return hash;
+	}
+
+	public static char[] arrayCopy(char[] chars)
+	{
+		if (chars == null) return null;
+		char[] copy = new char[chars.length];
+		System.arraycopy(chars, 0, copy, 0, chars.length);
+		return copy;
+	}
+}