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/20 11:35:21 UTC

svn commit: r423854 [1/2] - in /incubator/felix/trunk/org.apache.felix.mosgi.jmx.rmiconnector: ./ 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/...

Author: sfrenot
Date: Thu Jul 20 02:35:19 2006
New Revision: 423854

URL: http://svn.apache.org/viewvc?rev=423854&view=rev
Log: (empty)

Added:
    incubator/felix/trunk/org.apache.felix.mosgi.jmx.rmiconnector/   (with props)
    incubator/felix/trunk/org.apache.felix.mosgi.jmx.rmiconnector/pom.xml
    incubator/felix/trunk/org.apache.felix.mosgi.jmx.rmiconnector/src/
    incubator/felix/trunk/org.apache.felix.mosgi.jmx.rmiconnector/src/main/
    incubator/felix/trunk/org.apache.felix.mosgi.jmx.rmiconnector/src/main/java/
    incubator/felix/trunk/org.apache.felix.mosgi.jmx.rmiconnector/src/main/java/org/
    incubator/felix/trunk/org.apache.felix.mosgi.jmx.rmiconnector/src/main/java/org/apache/
    incubator/felix/trunk/org.apache.felix.mosgi.jmx.rmiconnector/src/main/java/org/apache/felix/
    incubator/felix/trunk/org.apache.felix.mosgi.jmx.rmiconnector/src/main/java/org/apache/felix/mosgi/
    incubator/felix/trunk/org.apache.felix.mosgi.jmx.rmiconnector/src/main/java/org/apache/felix/mosgi/jmx/
    incubator/felix/trunk/org.apache.felix.mosgi.jmx.rmiconnector/src/main/java/org/apache/felix/mosgi/jmx/rmiconnector/
    incubator/felix/trunk/org.apache.felix.mosgi.jmx.rmiconnector/src/main/java/org/apache/felix/mosgi/jmx/rmiconnector/RmiConnectorActivator.java
    incubator/felix/trunk/org.apache.felix.mosgi.jmx.rmiconnector/src/main/java/org/apache/felix/mosgi/jmx/rmiconnector/mx4j/
    incubator/felix/trunk/org.apache.felix.mosgi.jmx.rmiconnector/src/main/java/org/apache/felix/mosgi/jmx/rmiconnector/mx4j/remote/
    incubator/felix/trunk/org.apache.felix.mosgi.jmx.rmiconnector/src/main/java/org/apache/felix/mosgi/jmx/rmiconnector/mx4j/remote/AbstractHeartBeat.java
    incubator/felix/trunk/org.apache.felix.mosgi.jmx.rmiconnector/src/main/java/org/apache/felix/mosgi/jmx/rmiconnector/mx4j/remote/ClientProxy.java
    incubator/felix/trunk/org.apache.felix.mosgi.jmx.rmiconnector/src/main/java/org/apache/felix/mosgi/jmx/rmiconnector/mx4j/remote/ConnectionNotificationEmitter.java
    incubator/felix/trunk/org.apache.felix.mosgi.jmx.rmiconnector/src/main/java/org/apache/felix/mosgi/jmx/rmiconnector/mx4j/remote/ConnectionResolver.java
    incubator/felix/trunk/org.apache.felix.mosgi.jmx.rmiconnector/src/main/java/org/apache/felix/mosgi/jmx/rmiconnector/mx4j/remote/DefaultRemoteNotificationServerHandler.java
    incubator/felix/trunk/org.apache.felix.mosgi.jmx.rmiconnector/src/main/java/org/apache/felix/mosgi/jmx/rmiconnector/mx4j/remote/HeartBeat.java
    incubator/felix/trunk/org.apache.felix.mosgi.jmx.rmiconnector/src/main/java/org/apache/felix/mosgi/jmx/rmiconnector/mx4j/remote/MX4JRemoteConstants.java
    incubator/felix/trunk/org.apache.felix.mosgi.jmx.rmiconnector/src/main/java/org/apache/felix/mosgi/jmx/rmiconnector/mx4j/remote/MX4JRemoteUtils.java
    incubator/felix/trunk/org.apache.felix.mosgi.jmx.rmiconnector/src/main/java/org/apache/felix/mosgi/jmx/rmiconnector/mx4j/remote/NotificationTuple.java
    incubator/felix/trunk/org.apache.felix.mosgi.jmx.rmiconnector/src/main/java/org/apache/felix/mosgi/jmx/rmiconnector/mx4j/remote/ProviderFactory.java
    incubator/felix/trunk/org.apache.felix.mosgi.jmx.rmiconnector/src/main/java/org/apache/felix/mosgi/jmx/rmiconnector/mx4j/remote/ProviderHelper.java
    incubator/felix/trunk/org.apache.felix.mosgi.jmx.rmiconnector/src/main/java/org/apache/felix/mosgi/jmx/rmiconnector/mx4j/remote/RemoteNotificationClientHandler.java
    incubator/felix/trunk/org.apache.felix.mosgi.jmx.rmiconnector/src/main/java/org/apache/felix/mosgi/jmx/rmiconnector/mx4j/remote/RemoteNotificationServerHandler.java
    incubator/felix/trunk/org.apache.felix.mosgi.jmx.rmiconnector/src/main/java/org/apache/felix/mosgi/jmx/rmiconnector/mx4j/remote/provider/
    incubator/felix/trunk/org.apache.felix.mosgi.jmx.rmiconnector/src/main/java/org/apache/felix/mosgi/jmx/rmiconnector/mx4j/remote/provider/RMIClientProvider.java
    incubator/felix/trunk/org.apache.felix.mosgi.jmx.rmiconnector/src/main/java/org/apache/felix/mosgi/jmx/rmiconnector/mx4j/remote/provider/RMIServerProvider.java
    incubator/felix/trunk/org.apache.felix.mosgi.jmx.rmiconnector/src/main/java/org/apache/felix/mosgi/jmx/rmiconnector/mx4j/remote/provider/rmi/
    incubator/felix/trunk/org.apache.felix.mosgi.jmx.rmiconnector/src/main/java/org/apache/felix/mosgi/jmx/rmiconnector/mx4j/remote/provider/rmi/ServerProvider.java
    incubator/felix/trunk/org.apache.felix.mosgi.jmx.rmiconnector/src/main/java/org/apache/felix/mosgi/jmx/rmiconnector/mx4j/remote/resolver/
    incubator/felix/trunk/org.apache.felix.mosgi.jmx.rmiconnector/src/main/java/org/apache/felix/mosgi/jmx/rmiconnector/mx4j/remote/resolver/rmi/
    incubator/felix/trunk/org.apache.felix.mosgi.jmx.rmiconnector/src/main/java/org/apache/felix/mosgi/jmx/rmiconnector/mx4j/remote/resolver/rmi/RMIResolver.java
    incubator/felix/trunk/org.apache.felix.mosgi.jmx.rmiconnector/src/main/java/org/apache/felix/mosgi/jmx/rmiconnector/mx4j/remote/rmi/
    incubator/felix/trunk/org.apache.felix.mosgi.jmx.rmiconnector/src/main/java/org/apache/felix/mosgi/jmx/rmiconnector/mx4j/remote/rmi/ClientExceptionCatcher.java
    incubator/felix/trunk/org.apache.felix.mosgi.jmx.rmiconnector/src/main/java/org/apache/felix/mosgi/jmx/rmiconnector/mx4j/remote/rmi/ClientInvoker.java
    incubator/felix/trunk/org.apache.felix.mosgi.jmx.rmiconnector/src/main/java/org/apache/felix/mosgi/jmx/rmiconnector/mx4j/remote/rmi/ClientUnmarshaller.java
    incubator/felix/trunk/org.apache.felix.mosgi.jmx.rmiconnector/src/main/java/org/apache/felix/mosgi/jmx/rmiconnector/mx4j/remote/rmi/RMIConnectionInvoker.java
    incubator/felix/trunk/org.apache.felix.mosgi.jmx.rmiconnector/src/main/java/org/apache/felix/mosgi/jmx/rmiconnector/mx4j/remote/rmi/RMIConnectionProxy.java
    incubator/felix/trunk/org.apache.felix.mosgi.jmx.rmiconnector/src/main/java/org/apache/felix/mosgi/jmx/rmiconnector/mx4j/remote/rmi/RMIConnectionSubjectInvoker.java
    incubator/felix/trunk/org.apache.felix.mosgi.jmx.rmiconnector/src/main/java/org/apache/felix/mosgi/jmx/rmiconnector/mx4j/remote/rmi/RMIHeartBeat.java
    incubator/felix/trunk/org.apache.felix.mosgi.jmx.rmiconnector/src/main/java/org/apache/felix/mosgi/jmx/rmiconnector/mx4j/remote/rmi/RMIMarshaller.java
    incubator/felix/trunk/org.apache.felix.mosgi.jmx.rmiconnector/src/main/java/org/apache/felix/mosgi/jmx/rmiconnector/mx4j/remote/rmi/RMIRemoteNotificationServerHandler.java

Propchange: incubator/felix/trunk/org.apache.felix.mosgi.jmx.rmiconnector/
------------------------------------------------------------------------------
--- svn:ignore (added)
+++ svn:ignore Thu Jul 20 02:35:19 2006
@@ -0,0 +1,17 @@
+classes
+target
+*.log
+*.ipr
+*.iws
+*.iml
+lib
+bundle
+dist
+.project
+.classpath
+bin
+build
+.settings
+.wtpmodules
+.deployables
+

Added: incubator/felix/trunk/org.apache.felix.mosgi.jmx.rmiconnector/pom.xml
URL: http://svn.apache.org/viewvc/incubator/felix/trunk/org.apache.felix.mosgi.jmx.rmiconnector/pom.xml?rev=423854&view=auto
==============================================================================
--- incubator/felix/trunk/org.apache.felix.mosgi.jmx.rmiconnector/pom.xml (added)
+++ incubator/felix/trunk/org.apache.felix.mosgi.jmx.rmiconnector/pom.xml Thu Jul 20 02:35:19 2006
@@ -0,0 +1,75 @@
+<project>
+  <parent>
+    <groupId>org.apache.felix</groupId>
+    <artifactId>felix</artifactId>
+    <version>0.8.0-SNAPSHOT</version>
+  </parent>
+  <modelVersion>4.0.0</modelVersion>
+  <packaging>osgi-bundle</packaging>
+  <name>MOSGi JMX rmiconnector</name>
+  <artifactId>org.apache.felix.mosgi.jmx.rmiconnector</artifactId>
+  <dependencies>
+    <dependency>
+      <groupId>${pom.groupId}</groupId>
+      <artifactId>org.osgi.core</artifactId>
+      <version>${pom.version}</version>
+      <scope>provided</scope>
+    </dependency>
+    <dependency>
+      <groupId>${pom.groupId}</groupId>
+      <artifactId>org.osgi.compendium</artifactId>
+      <version>${pom.version}</version>
+      <scope>provided</scope>
+    </dependency>
+    <dependency>
+      <groupId>${pom.groupId}</groupId>
+      <artifactId>org.apache.felix.mosgi.jmx.agent</artifactId>
+      <version>${pom.version}</version>
+      <scope>provided</scope>
+    </dependency>
+    <dependency>
+      <groupId>${pom.groupId}</groupId>
+      <artifactId>org.apache.felix.mosgi.jmx.registry</artifactId>
+      <version>${pom.version}</version>
+      <scope>provided</scope>
+    </dependency>
+    <dependency>
+      <groupId>${pom.groupId}</groupId>
+      <artifactId>org.apache.felix.framework</artifactId>
+      <version>${pom.version}</version>
+      <scope>provided</scope>
+    </dependency>
+  </dependencies>
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.felix.plugins</groupId>
+        <artifactId>maven-osgi-plugin</artifactId>
+        <version>${pom.version}</version>
+        <extensions>true</extensions>
+        <configuration>
+          <osgiManifest>
+            <bundleName>MOSGi JMX-MX4J RMI Connector</bundleName>
+            <bundleDescription>MOSGi JMX-MX4J RMI Connector</bundleDescription>
+            <bundleActivator>auto-detect</bundleActivator>
+            <bundleDocUrl>http://oscar-osgi.sf.net/obr2/${pom.artifactId}/</bundleDocUrl>
+            <bundleUrl>http://oscar-osgi.sf.net/obr2/${pom.artifactId}/${pom.artifactId}-${pom.version}.jar</bundleUrl>
+            <bundleSource>http://oscar-osgi.sf.net/obr2/${pom.artifactId}/${pom.artifactId}-${pom.version}-src.jar</bundleSource>
+            <bundleSymbolicName>${pom.artifactId}</bundleSymbolicName>
+            <exportPackage>
+	      org.apache.felix.mosgi.jmx.rmiconnector.mx4j.remote.provider.rmi;specification-version="1.0.0"
+            </exportPackage>
+	    <importPackage>
+  	      org.osgi.service.log;specification-version="1.0.0",
+	      org.osgi.framework;specification-version="1.0.0",
+	      org.apache.felix.mosgi.jmx.registry.mx4j.tools.naming;specification-version="1.0.0",
+	      org.apache.felix.mosgi.jmx.rmiconnector.mx4j.remote.provider.rmi;specification-version="1.0.0",
+	      javax.management;specification-version="1.0.0",
+	      javax.management.remote;specification-version="1.0.0"
+	    </importPackage>
+          </osgiManifest>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+</project>

Added: incubator/felix/trunk/org.apache.felix.mosgi.jmx.rmiconnector/src/main/java/org/apache/felix/mosgi/jmx/rmiconnector/RmiConnectorActivator.java
URL: http://svn.apache.org/viewvc/incubator/felix/trunk/org.apache.felix.mosgi.jmx.rmiconnector/src/main/java/org/apache/felix/mosgi/jmx/rmiconnector/RmiConnectorActivator.java?rev=423854&view=auto
==============================================================================
--- incubator/felix/trunk/org.apache.felix.mosgi.jmx.rmiconnector/src/main/java/org/apache/felix/mosgi/jmx/rmiconnector/RmiConnectorActivator.java (added)
+++ incubator/felix/trunk/org.apache.felix.mosgi.jmx.rmiconnector/src/main/java/org/apache/felix/mosgi/jmx/rmiconnector/RmiConnectorActivator.java Thu Jul 20 02:35:19 2006
@@ -0,0 +1,200 @@
+/*
+ *   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.rmiconnector;
+
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceReference;
+import org.osgi.framework.ServiceListener;
+import org.osgi.framework.ServiceEvent;
+
+import org.osgi.service.log.LogService;
+
+import org.apache.felix.framework.cache.BundleCache;
+
+import javax.management.MBeanServer;
+import javax.management.ObjectName;
+import javax.management.remote.JMXConnectorServer;
+import javax.management.remote.JMXConnectorServerFactory;
+import javax.management.remote.JMXServiceURL;
+
+import org.apache.felix.mosgi.jmx.registry.mx4j.tools.naming.NamingServiceIfc;  
+
+import java.net.InetAddress;
+
+public class RmiConnectorActivator implements BundleActivator, ServiceListener{
+  public static BundleContext bc;
+
+  private ObjectName connectorServerName=new ObjectName("RmiConnector:name=RMIConnector");
+
+  private JMXConnectorServer connectorServer;
+  private MBeanServer mbs;
+  private NamingServiceIfc nsi;
+  private ServiceReference mBeanServerSR, namingServiceIfcSR;
+
+  private String version=null;
+
+  public RmiConnectorActivator() throws javax.management.MalformedObjectNameException {}
+  
+  ////////////////////////////////////////////////////
+  //          BundleActivator                       //
+  ////////////////////////////////////////////////////
+  public void start(BundleContext bc) throws Exception{
+		this.version=(String)bc.getBundle().getHeaders().get(Constants.BUNDLE_VERSION);
+    RmiConnectorActivator.bc=bc;
+    this.mBeanServerSR=bc.getServiceReference(MBeanServer.class.getName());
+    this.namingServiceIfcSR=bc.getServiceReference(NamingServiceIfc.class.getName());
+    RmiConnectorActivator. bc.addServiceListener(this, "(|(objectClass="+NamingServiceIfc.class.getName()+")"+"(objectClass="+MBeanServer.class.getName()+"))");
+    if (this.mBeanServerSR!=null && this.namingServiceIfcSR!=null){
+      this.startRmiConnector();
+    } else {
+      if (this.mBeanServerSR == null){
+        RmiConnectorActivator.log(LogService.LOG_WARNING,"No JMX Agent found",null);
+      }else if (this.namingServiceIfcSR==null){
+        RmiConnectorActivator.log(LogService.LOG_WARNING,"No RMI Registry found", null);
+      }
+    }
+  }
+
+  public void stop(BundleContext bc) throws Exception {
+    this.stopRmiConnector();
+    RmiConnectorActivator.bc=null;
+  }
+
+  //////////////////////////////////////////////////////
+  //          ServiceListener                        //
+  //////////////////////////////////////////////////////
+  public void serviceChanged(ServiceEvent serviceevent) {
+    ServiceReference servicereference= serviceevent.getServiceReference();
+    String [] ast=(String[])(servicereference.getProperty("objectClass"));
+    String as=ast[0];
+    switch (serviceevent.getType()) {
+      case ServiceEvent.REGISTERED :
+        if (as.equals(NamingServiceIfc.class.getName())){
+          this.namingServiceIfcSR=servicereference;
+        }else if (as.equals(MBeanServer.class.getName())){
+          this.mBeanServerSR=servicereference;
+        }
+        if (this.namingServiceIfcSR!=null && this.mBeanServerSR!=null){
+          try{
+            this.startRmiConnector();
+          }catch (Exception e){
+            e.printStackTrace();
+          }
+        }
+        break;
+      case ServiceEvent.UNREGISTERING :
+        try{
+          this.stopRmiConnector();
+        }catch (Exception e){
+          e.printStackTrace();
+        }
+        break;
+    }
+  }
+
+  public static void log(int prio, String message, Throwable t){
+    if (RmiConnectorActivator.bc!=null){
+      ServiceReference logSR=RmiConnectorActivator.bc.getServiceReference(LogService.class.getName());
+      if (logSR!=null){
+        ((LogService)RmiConnectorActivator.bc.getService(logSR)).log(prio, message, t);
+      }else{
+        System.out.println("No Log Service");
+      }
+    }else{
+      System.out.println(RmiConnectorActivator.class.getName()+": No bundleContext");
+    }
+  }
+
+  private void startRmiConnector() throws Exception{
+    String profile=bc.getProperty(BundleCache.CACHE_PROFILE_PROP);
+    if (profile==null){
+      profile=System.getProperty(BundleCache.CACHE_PROFILE_PROP);
+		}
+    String rmiPort=bc.getProperty("insa.jmxconsole.rmiport."+profile);
+    if (rmiPort==null){
+      rmiPort="1099";
+    }
+    String url="service:jmx:rmi:///jndi/rmi://"+ InetAddress.getLocalHost().getHostAddress()+":"+rmiPort+"/"+profile;
+    RmiConnectorActivator.log(LogService.LOG_INFO, "insa.jmx.rmiconnector.url ==> "+url, null);
+    
+    RmiConnectorActivator.log(LogService.LOG_INFO, "Starting JMX Rmi Connector "+version,null);
+    this.mbs=(MBeanServer)bc.getService(this.mBeanServerSR);
+    this.nsi=(NamingServiceIfc)bc.getService(this.namingServiceIfcSR);
+    JMXServiceURL address=new JMXServiceURL(url);
+/*
+    Map environment = new HashMap();
+    environment.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.rmi.registry.RegistryContextFactory");
+    environment.put(Context.PROVIDER_URL, "rmi://localhost:"+rmiPort);
+    environment.put(JMXConnectorServerFactory.PROTOCOL_PROVIDER_CLASS_LOADER,this.getClass().getClassLoader());
+  */
+
+/* Loggin 
+Thread.currentThread().setContextClassLoader(this.getClass().getClassLoader());
+java.util.logging.ConsoleHandler ch=new java.util.logging.ConsoleHandler();
+ch.setLevel(java.util.logging.Level.FINEST);
+java.util.logging.Logger.getLogger("javax.management.remote.misc").setLevel(java.util.logging.Level.FINEST);
+java.util.logging.Logger.getLogger("javax.management.remote.rmi").setLevel(java.util.logging.Level.FINEST);
+java.util.logging.Logger.getLogger("javax.management.remote.rmi").addHandler(ch);
+java.util.logging.Logger.getLogger("javax.management.remote.misc").addHandler(ch);
+*/
+
+		/*
+		java.util.Map env = new java.util.HashMap();
+		env.put(JMXConnectorServerFactory.PROTOCOL_PROVIDER_CLASS_LOADER, this.getClass().getClassLoader());
+		env.put("jmx.remote.protocol.provider.pkgs", "mx4j.remote.provider");
+		*/
+
+    this.connectorServer = JMXConnectorServerFactory.newJMXConnectorServer(address, null, this.mbs);
+
+    RmiConnectorActivator.log(LogService.LOG_DEBUG, "===> "+this.connectorServer, null);
+    RmiConnectorActivator.log(LogService.LOG_DEBUG, "======> "+this.connectorServer.getMBeanServer(), null);
+
+//    this.mbs.registerMBean(this.connectorServer, this.connectorServerName);
+//    this.connectorServer = JMXConnectorServerFactory.newJMXConnectorServer(address, null, java.lang.management.ManagementFactory.getPlatformMBeanServer());
+    this.connectorServer.start();
+
+    RmiConnectorActivator.log(LogService.LOG_INFO, "JMX Rmi Connector started "+version,null);
+  }
+
+  private void stopRmiConnector() throws Exception {
+    RmiConnectorActivator.log(LogService.LOG_INFO, "Stopping JMX Rmi connector "+version,null);
+    if (this.connectorServer!=null){
+      this.connectorServer.stop();
+      this.connectorServer=null;
+    }
+
+    if (this.mbs!=null){
+//SFR   this.mbs.unregisterMBean(this.connectorServerName);
+      this.mbs=null;
+    }
+
+    this.nsi=null;
+
+    if (this.mBeanServerSR!=null){
+      RmiConnectorActivator.bc.ungetService(this.mBeanServerSR);
+      this.mBeanServerSR=null;
+    }
+    if (this.namingServiceIfcSR!=null){
+      RmiConnectorActivator.bc.ungetService(this.namingServiceIfcSR);
+      this.namingServiceIfcSR=null;
+    }
+    this.connectorServerName=null;
+    RmiConnectorActivator.log(LogService.LOG_INFO, "Rmi Connector stopped "+version,null);
+  }
+}

Added: incubator/felix/trunk/org.apache.felix.mosgi.jmx.rmiconnector/src/main/java/org/apache/felix/mosgi/jmx/rmiconnector/mx4j/remote/AbstractHeartBeat.java
URL: http://svn.apache.org/viewvc/incubator/felix/trunk/org.apache.felix.mosgi.jmx.rmiconnector/src/main/java/org/apache/felix/mosgi/jmx/rmiconnector/mx4j/remote/AbstractHeartBeat.java?rev=423854&view=auto
==============================================================================
--- incubator/felix/trunk/org.apache.felix.mosgi.jmx.rmiconnector/src/main/java/org/apache/felix/mosgi/jmx/rmiconnector/mx4j/remote/AbstractHeartBeat.java (added)
+++ incubator/felix/trunk/org.apache.felix.mosgi.jmx.rmiconnector/src/main/java/org/apache/felix/mosgi/jmx/rmiconnector/mx4j/remote/AbstractHeartBeat.java Thu Jul 20 02:35:19 2006
@@ -0,0 +1,118 @@
+/*
+ * 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.rmiconnector.mx4j.remote;
+
+import java.io.IOException;
+import java.util.Map;
+
+/**
+ *
+ * @author <a href="mailto:biorn_steedom@users.sourceforge.net">Simone Bordet</a>
+ * @version $Revision: 1.1.1.1 $
+ */
+public abstract class AbstractHeartBeat implements HeartBeat, Runnable
+{
+   private final ConnectionNotificationEmitter emitter;
+   private long pulsePeriod;
+   private int maxRetries;
+   private Thread thread;
+   private volatile boolean stopped;
+
+   protected AbstractHeartBeat(ConnectionNotificationEmitter emitter, Map environment)
+   {
+      this.emitter = emitter;
+      if (environment != null)
+      {
+         try
+         {
+            pulsePeriod = ((Long)environment.get(MX4JRemoteConstants.CONNECTION_HEARTBEAT_PERIOD)).longValue();
+         }
+         catch (Exception ignored)
+         {
+         }
+         try
+         {
+            maxRetries = ((Integer)environment.get(MX4JRemoteConstants.CONNECTION_HEARTBEAT_RETRIES)).intValue();
+         }
+         catch (Exception ignored)
+         {
+         }
+      }
+      if (pulsePeriod <= 0) pulsePeriod = 5000;
+      if (maxRetries <= 0) maxRetries = 3;
+   }
+
+   protected abstract void pulse() throws IOException;
+
+   public void start() throws IOException
+   {
+      thread = new Thread(this, "Connection HeartBeat");
+      thread.setDaemon(true);
+      thread.start();
+   }
+
+   public void stop() throws IOException
+   {
+      if (stopped) return;
+      stopped = true;
+      thread.interrupt();
+   }
+
+   public void run()
+   {
+      int retries = 0;
+      while (!stopped && !thread.isInterrupted())
+      {
+         try
+         {
+            Thread.sleep(pulsePeriod);
+
+            try
+            {
+               pulse();
+               retries = 0;
+            }
+            catch (IOException x)
+            {
+               if (retries++ == maxRetries)
+               {
+                  // The connection has died
+                  sendConnectionNotificationFailed();
+                  // And go on
+               }
+            }
+         }
+         catch (InterruptedException x)
+         {
+            Thread.currentThread().interrupt();
+            return;
+         }
+      }
+   }
+
+   protected void sendConnectionNotificationFailed()
+   {
+      emitter.sendConnectionNotificationFailed();
+   }
+}

Added: incubator/felix/trunk/org.apache.felix.mosgi.jmx.rmiconnector/src/main/java/org/apache/felix/mosgi/jmx/rmiconnector/mx4j/remote/ClientProxy.java
URL: http://svn.apache.org/viewvc/incubator/felix/trunk/org.apache.felix.mosgi.jmx.rmiconnector/src/main/java/org/apache/felix/mosgi/jmx/rmiconnector/mx4j/remote/ClientProxy.java?rev=423854&view=auto
==============================================================================
--- incubator/felix/trunk/org.apache.felix.mosgi.jmx.rmiconnector/src/main/java/org/apache/felix/mosgi/jmx/rmiconnector/mx4j/remote/ClientProxy.java (added)
+++ incubator/felix/trunk/org.apache.felix.mosgi.jmx.rmiconnector/src/main/java/org/apache/felix/mosgi/jmx/rmiconnector/mx4j/remote/ClientProxy.java Thu Jul 20 02:35:19 2006
@@ -0,0 +1,56 @@
+/*
+ * 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.rmiconnector.mx4j.remote;
+
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.lang.reflect.InvocationTargetException;
+
+import javax.management.MBeanServerConnection;
+
+/**
+ * @author <a href="mailto:biorn_steedom@users.sourceforge.net">Simone Bordet</a>
+ * @version $Revision: 1.1.1.1 $
+ */
+public class ClientProxy implements InvocationHandler
+{
+   private final MBeanServerConnection target;
+
+   protected ClientProxy(MBeanServerConnection target)
+   {
+      this.target = target;
+   }
+
+   public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
+   {
+      try
+      {
+         return method.invoke(target, args);
+      }
+      catch (InvocationTargetException x)
+      {
+         throw x.getTargetException();
+      }
+   }
+}

Added: incubator/felix/trunk/org.apache.felix.mosgi.jmx.rmiconnector/src/main/java/org/apache/felix/mosgi/jmx/rmiconnector/mx4j/remote/ConnectionNotificationEmitter.java
URL: http://svn.apache.org/viewvc/incubator/felix/trunk/org.apache.felix.mosgi.jmx.rmiconnector/src/main/java/org/apache/felix/mosgi/jmx/rmiconnector/mx4j/remote/ConnectionNotificationEmitter.java?rev=423854&view=auto
==============================================================================
--- incubator/felix/trunk/org.apache.felix.mosgi.jmx.rmiconnector/src/main/java/org/apache/felix/mosgi/jmx/rmiconnector/mx4j/remote/ConnectionNotificationEmitter.java (added)
+++ incubator/felix/trunk/org.apache.felix.mosgi.jmx.rmiconnector/src/main/java/org/apache/felix/mosgi/jmx/rmiconnector/mx4j/remote/ConnectionNotificationEmitter.java Thu Jul 20 02:35:19 2006
@@ -0,0 +1,92 @@
+/*
+ * 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.rmiconnector.mx4j.remote;
+
+import java.io.IOException;
+
+import javax.management.NotificationBroadcasterSupport;
+import javax.management.remote.JMXConnectionNotification;
+import javax.management.remote.JMXConnector;
+import javax.management.remote.rmi.RMIConnector;
+
+/**
+ *
+ * @author <a href="mailto:biorn_steedom@users.sourceforge.net">Simone Bordet</a>
+ * @version $Revision: 1.1.1.1 $
+ */
+public class ConnectionNotificationEmitter extends NotificationBroadcasterSupport
+{
+   private static long sequenceNumber;
+
+   private JMXConnector connector;
+
+   public ConnectionNotificationEmitter(JMXConnector connector)
+   {
+      this.connector = connector;
+   }
+
+   private long getNextNotificationNumber()
+   {
+      synchronized (RMIConnector.class)
+      {
+         return sequenceNumber++;
+      }
+   }
+
+   private String getConnectionId()
+   {
+      try
+      {
+         return connector.getConnectionId();
+      }
+      catch (IOException x)
+      {
+         return null;
+      }
+   }
+
+   public void sendConnectionNotificationOpened()
+   {
+      JMXConnectionNotification notification = new JMXConnectionNotification(JMXConnectionNotification.OPENED, connector, getConnectionId(), getNextNotificationNumber(), "Connection opened", null);
+      sendNotification(notification);
+   }
+
+   public void sendConnectionNotificationClosed()
+   {
+      JMXConnectionNotification notification = new JMXConnectionNotification(JMXConnectionNotification.CLOSED, connector, getConnectionId(), getNextNotificationNumber(), "Connection closed", null);
+      sendNotification(notification);
+   }
+
+   public void sendConnectionNotificationFailed()
+   {
+      JMXConnectionNotification notification = new JMXConnectionNotification(JMXConnectionNotification.FAILED, connector, getConnectionId(), getNextNotificationNumber(), "Connection failed", null);
+      sendNotification(notification);
+   }
+
+   public void sendConnectionNotificationLost(long howMany)
+   {
+      JMXConnectionNotification notification = new JMXConnectionNotification(JMXConnectionNotification.NOTIFS_LOST, connector, getConnectionId(), getNextNotificationNumber(), "Some notification (" + howMany + ") was lost", null);
+      sendNotification(notification);
+   }
+}

Added: incubator/felix/trunk/org.apache.felix.mosgi.jmx.rmiconnector/src/main/java/org/apache/felix/mosgi/jmx/rmiconnector/mx4j/remote/ConnectionResolver.java
URL: http://svn.apache.org/viewvc/incubator/felix/trunk/org.apache.felix.mosgi.jmx.rmiconnector/src/main/java/org/apache/felix/mosgi/jmx/rmiconnector/mx4j/remote/ConnectionResolver.java?rev=423854&view=auto
==============================================================================
--- incubator/felix/trunk/org.apache.felix.mosgi.jmx.rmiconnector/src/main/java/org/apache/felix/mosgi/jmx/rmiconnector/mx4j/remote/ConnectionResolver.java (added)
+++ incubator/felix/trunk/org.apache.felix.mosgi.jmx.rmiconnector/src/main/java/org/apache/felix/mosgi/jmx/rmiconnector/mx4j/remote/ConnectionResolver.java Thu Jul 20 02:35:19 2006
@@ -0,0 +1,149 @@
+/*
+ * 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.rmiconnector.mx4j.remote;
+
+import java.io.IOException;
+import java.util.Map;
+import java.util.StringTokenizer;
+
+import javax.management.remote.JMXServiceURL;
+
+import org.apache.felix.mosgi.jmx.rmiconnector.mx4j.remote.MX4JRemoteConstants;
+import org.apache.felix.mosgi.jmx.rmiconnector.mx4j.remote.ProviderHelper;
+
+import org.osgi.service.log.LogService;
+
+import org.apache.felix.mosgi.jmx.rmiconnector.RmiConnectorActivator;
+
+/**
+ * ConnectionResolver handles the details of creating connections for different protocols.
+ * Subclasses for the specific protocol are found using a mechanism very similar to the
+ * one specified by {@link javax.management.remote.JMXConnectorFactory}. Here a subclass
+ * has a fully qualified name specified like this:
+ * <package>.resolver.<protocol>.<PROTOCOL>Resolver, for example
+ * {@link mx4j.remote.resolver.rmi.RMIResolver}
+ * This class is used from both the client and the server.
+ * The former uses it to lookup stubs or connections to the server side; the latter uses it
+ * to create server instances and make them availale to clients, for example via JNDI.
+ *
+ * @author <a href="mailto:biorn_steedom@users.sourceforge.net">Simone Bordet</a>
+ * @version $Revision: 1.1.1.1 $
+ */
+public abstract class ConnectionResolver extends ProviderHelper
+{
+   /**
+    * Returns a subclass of ConnectionResolver for the specified protocol.
+    */
+   public static ConnectionResolver getInstance(String proto) {
+      String protocol = normalizeProtocol(proto);
+      String resolverPackages = findResolverPackageList();
+//sfr      return loadResolver(resolverPackages, protocol, Thread.currentThread().getContextClassLoader());
+      return loadResolver(resolverPackages, protocol, ConnectionResolver.class.getClassLoader());
+   }
+
+   private static String findResolverPackageList() {
+      String packages = findSystemPackageList(MX4JRemoteConstants.PROTOCOL_RESOLVER_PACKAGES);
+      if (packages == null)
+         packages = MX4JRemoteConstants.RESOLVER_PACKAGES;
+      else
+         packages += MX4JRemoteConstants.RESOLVER_PACKAGES_SEPARATOR + MX4JRemoteConstants.RESOLVER_PACKAGES;
+      RmiConnectorActivator.log(LogService.LOG_DEBUG,"Resolver packages list is: " + packages, null);
+      return packages;
+   }
+
+   private static ConnectionResolver loadResolver(String packages, String protocol, ClassLoader loader) {
+      StringTokenizer tokenizer = new StringTokenizer(packages, MX4JRemoteConstants.RESOLVER_PACKAGES_SEPARATOR);
+      while (tokenizer.hasMoreTokens()) {
+         String pkg = tokenizer.nextToken().trim();
+         RmiConnectorActivator.log(LogService.LOG_DEBUG,"Resolver package: " + pkg,null);
+         if (pkg.length() == 0) continue;
+
+         String className = protocol.toUpperCase() + MX4JRemoteConstants.RESOLVER_CLASS;
+         String resolverClassName = constructClassName(pkg, protocol, className);
+
+         Class resolverClass = null;
+         try
+         {
+            resolverClass = loadClass(resolverClassName, loader);
+         }
+         catch (ClassNotFoundException x)
+         {
+            RmiConnectorActivator.log(LogService.LOG_DEBUG,"Resolver class " + resolverClassName + " not found, continuing with next package",null);
+            continue;
+         }
+         catch (Exception x)
+         {
+            RmiConnectorActivator.log(LogService.LOG_WARNING, "Cannot load resolver class " + resolverClassName, x);
+            return null;
+         }
+
+         try
+         {
+            return (ConnectionResolver)resolverClass.newInstance();
+         }
+         catch (Exception x)
+         {
+            RmiConnectorActivator.log(LogService.LOG_WARNING,"Cannot instantiate resolver class " + resolverClassName, x);
+            return null;
+         }
+      }
+
+      // Nothing found
+       RmiConnectorActivator.log(LogService.LOG_DEBUG,"Could not find resolver for protocol " + protocol + " in package list '" + packages + "'", null);
+      return null;
+   }
+
+   /**
+    * Looks up a connection to the server side as specified in the given JMXServiceURL.
+    * This method is used by {@link javax.management.remote.JMXConnector}s.
+    */
+   public abstract Object lookupClient(JMXServiceURL url, Map environment) throws IOException;
+
+   /**
+    * Connects the client returned by {@link #lookupClient} to the server side
+    */
+   public abstract Object bindClient(Object client, Map environment) throws IOException;
+
+   /**
+    * Creates an instance of the server as specified in the given JMXServiceURL.
+    * It is only a factory method, it should just return a fresh instance of the server;
+    * other methods are responsible to make it available to clients (for example exporting it).
+    * This method is used by {@link javax.management.remote.JMXConnectorServer}s.
+    * @see #bindServer
+    */
+   public abstract Object createServer(JMXServiceURL url, Map environment) throws IOException;
+
+   /**
+    * Binds the server created by {@link #createServer} to a place specified in the JMXServiceURL.
+    * @return a new JMXServiceURL that specifies where the server has been bound to.
+    * @see #unbindServer
+    */
+   public abstract JMXServiceURL bindServer(Object server, JMXServiceURL url, Map environment) throws IOException;
+
+   /**
+    * Unbinds the server created by {@link #createServer} from the place specified in the JMXServiceURL.
+    * @see #bindServer
+    */
+   public abstract void unbindServer(Object server, JMXServiceURL address, Map environment) throws IOException;
+}

Added: incubator/felix/trunk/org.apache.felix.mosgi.jmx.rmiconnector/src/main/java/org/apache/felix/mosgi/jmx/rmiconnector/mx4j/remote/DefaultRemoteNotificationServerHandler.java
URL: http://svn.apache.org/viewvc/incubator/felix/trunk/org.apache.felix.mosgi.jmx.rmiconnector/src/main/java/org/apache/felix/mosgi/jmx/rmiconnector/mx4j/remote/DefaultRemoteNotificationServerHandler.java?rev=423854&view=auto
==============================================================================
--- incubator/felix/trunk/org.apache.felix.mosgi.jmx.rmiconnector/src/main/java/org/apache/felix/mosgi/jmx/rmiconnector/mx4j/remote/DefaultRemoteNotificationServerHandler.java (added)
+++ incubator/felix/trunk/org.apache.felix.mosgi.jmx.rmiconnector/src/main/java/org/apache/felix/mosgi/jmx/rmiconnector/mx4j/remote/DefaultRemoteNotificationServerHandler.java Thu Jul 20 02:35:19 2006
@@ -0,0 +1,339 @@
+/*
+ * 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.rmiconnector.mx4j.remote;
+
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+import javax.management.Notification;
+import javax.management.NotificationListener;
+import javax.management.ObjectName;
+import javax.management.NotificationFilter;
+import javax.management.remote.NotificationResult;
+import javax.management.remote.TargetedNotification;
+
+import org.osgi.service.log.LogService;
+
+import org.apache.felix.mosgi.jmx.rmiconnector.RmiConnectorActivator;
+
+
+/**
+ * @author <a href="mailto:biorn_steedom@users.sourceforge.net">Simone Bordet</a>
+ * @version $Revision: 1.1.1.1 $
+ */
+public class DefaultRemoteNotificationServerHandler implements RemoteNotificationServerHandler
+{
+   private static int listenerID;
+
+   private final NotificationListener listener;
+   private final Map tuples = new HashMap();
+   private final NotificationBuffer buffer;
+
+   public DefaultRemoteNotificationServerHandler(Map environment)
+   {
+      listener = new ServerListener();
+      buffer = new NotificationBuffer(environment);
+   }
+
+   public Integer generateListenerID(ObjectName name, NotificationFilter filter)
+   {
+      synchronized (DefaultRemoteNotificationServerHandler.class)
+      {
+         return new Integer(++listenerID);
+      }
+   }
+
+   public NotificationListener getServerNotificationListener()
+   {
+      return listener;
+   }
+
+   public void addNotificationListener(Integer id, NotificationTuple tuple)
+   {
+      synchronized (tuples)
+      {
+         tuples.put(id, tuple);
+      }
+   }
+
+   public void removeNotificationListener(Integer id)
+   {
+      synchronized (tuples)
+      {
+         tuples.remove(id);
+      }
+   }
+
+   public NotificationTuple getNotificationListener(Integer id)
+   {
+      synchronized (tuples)
+      {
+         return (NotificationTuple)tuples.get(id);
+      }
+   }
+
+   public NotificationResult fetchNotifications(long sequenceNumber, int maxNotifications, long timeout)
+   {
+      return buffer.getNotifications(sequenceNumber, maxNotifications, timeout);
+   }
+
+   /**
+    * Called when there are no notifications to send to the client.
+    * It is guaranteed that no notification can be added before this method waits on the given lock.
+    * It should wait on the given lock for the specified timeout, and return true
+    * to send notifications (if no notifications arrived, an empty notification array
+    * will be returned to the client), or false if no notifications should be sent to
+    * the client.
+    * @param lock The object on which {@link #wait} should be called
+    * @param timeout The amount of time to wait (guaranteed to be strictly greater than 0)
+    */
+   protected boolean waitForNotifications(Object lock, long timeout)
+   {
+      synchronized (lock)
+      {
+         try
+         {
+            lock.wait(timeout);
+         }
+         catch (InterruptedException x)
+         {
+            Thread.currentThread().interrupt();
+         }
+      }
+      return true;
+   }
+
+   /**
+    * This method filters the given notification array and returns a possibly smaller array containing
+    * only notifications that passed successfully the filtering.
+    * Default behavior is no filtering, but subclasses may choose to change this bahavior.
+    * For example, for RMI, one can assure that all notifications are truly serializable, and log those
+    * that are not.
+    */
+   protected TargetedNotification[] filterNotifications(TargetedNotification[] notifications)
+   {
+      return notifications;
+   }
+
+   private void addNotification(Integer id, Notification notification)
+   {
+      buffer.add(new TargetedNotification(notification, id));
+   }
+
+   public class ServerListener implements NotificationListener
+   {
+      public void handleNotification(Notification notification, Object handback)
+      {
+         Integer id = (Integer)handback;
+         addNotification(id, notification);
+      }
+   }
+
+   public class NotificationBuffer
+   {
+      private final List buffer = new LinkedList();
+      private int maxCapacity;
+      private int purgeDistance;
+      private long firstSequence;
+      private long lastSequence;
+      private long lowestExpectedSequence;
+
+      public NotificationBuffer(Map environment)
+      {
+         if (environment != null)
+         {
+            try
+            {
+               maxCapacity = ((Integer)environment.get(MX4JRemoteConstants.NOTIFICATION_BUFFER_CAPACITY)).intValue();
+            }
+            catch (Exception ignored)
+            {
+            }
+
+            try
+            {
+               purgeDistance = ((Integer)environment.get(MX4JRemoteConstants.NOTIFICATION_PURGE_DISTANCE)).intValue();
+            }
+            catch (Exception ignored)
+            {
+            }
+         }
+         if (maxCapacity <= 0) maxCapacity = 1024;
+         if (purgeDistance <= 0) purgeDistance = 128;
+      }
+
+      public int getSize()
+      {
+         synchronized (buffer)
+         {
+            return buffer.size();
+         }
+      }
+
+      public void add(TargetedNotification notification)
+      {
+         synchronized (buffer)
+         {
+            if (buffer.size() == maxCapacity)
+            {
+               RmiConnectorActivator.log(LogService.LOG_DEBUG, "Notification buffer full: " + this, null);
+               removeRange(0, 1);
+            }
+            buffer.add(notification);
+            ++lastSequence;
+            RmiConnectorActivator.log(LogService.LOG_DEBUG,"Notification added to buffer: " + this, null);
+            buffer.notifyAll();
+         }
+      }
+
+      private void removeRange(int start, int end)
+      {
+         synchronized (buffer)
+         {
+            buffer.subList(start, end).clear();
+            firstSequence += end - start;
+         }
+      }
+
+      private long getFirstSequenceNumber()
+      {
+         synchronized (buffer)
+         {
+            return firstSequence;
+         }
+      }
+
+      private long getLastSequenceNumber()
+      {
+         synchronized (buffer)
+         {
+            return lastSequence;
+         }
+      }
+
+      public NotificationResult getNotifications(long sequenceNumber, int maxNotifications, long timeout)
+      {
+         synchronized (buffer)
+         {
+            NotificationResult result = null;
+            int size = 0;
+            if (sequenceNumber < 0)
+            {
+               // We loose the notifications between addNotificationListener() and fetchNotifications(), but c'est la vie.
+               long sequence = getLastSequenceNumber();
+               size = new Long(sequence + 1).intValue();
+               result = new NotificationResult(getFirstSequenceNumber(), sequence, new TargetedNotification[0]);
+                RmiConnectorActivator.log(LogService.LOG_DEBUG,"First fetchNotification call: " + this + ", returning " + result, null);
+            }
+            else
+            {
+               int start = new Long(sequenceNumber - getFirstSequenceNumber()).intValue();
+
+               List sublist = null;
+               boolean send = false;
+               while (size == 0)
+               {
+                  int end = buffer.size();
+                  if (end - start > maxNotifications) end = start + maxNotifications;
+
+                  sublist = buffer.subList(start, end);
+                  size = sublist.size();
+
+                  if (send) break;
+
+                  if (size == 0)
+                  {
+                     if (timeout <= 0) break;
+                      RmiConnectorActivator.log(LogService.LOG_DEBUG,"No notifications to send, waiting " + timeout + " ms", null);
+
+                     // We wait for notifications to arrive. Since we release the lock on the buffer
+                     // other threads can modify it. To avoid ConcurrentModificationException we compute
+                     // again the sublist
+                     send = waitForNotifications(buffer, timeout);
+                  }
+               }
+
+               TargetedNotification[] notifications = (TargetedNotification[])sublist.toArray(new TargetedNotification[size]);
+               notifications = filterNotifications(notifications);
+               result = new NotificationResult(getFirstSequenceNumber(), sequenceNumber + size, notifications);
+                RmiConnectorActivator.log(LogService.LOG_DEBUG,"Non-first fetchNotification call: " + this + ", returning " + result, null);
+
+               purgeNotifications(sequenceNumber, size);
+               RmiConnectorActivator.log(LogService.LOG_DEBUG,"Purged Notifications: " + this, null);
+            }
+            return result;
+         }
+      }
+
+      private void purgeNotifications(long sequenceNumber, int size)
+      {
+         // Record the lowest expected sequence number sent by the client.
+         // New clients will always have an initial big sequence number
+         // (they're initialized with getLastSequenceNumber()), while old
+         // clients can have lesser sequence numbers.
+         // Here we record the lesser of these sequence numbers, that is the
+         // sequence number of the oldest notification any client may ever ask.
+         // This way we can purge old notifications that have already been
+         // delivered to clients.
+
+         // The worst case is when a client has a long interval between fetchNotifications()
+         // calls, and another client has a short interval. The lowestExpectedSequence will
+         // grow with the second client, until a purge happens, so the first client can
+         // loose notifications. By tuning appropriately the purgeDistance and the interval
+         // between fetchNotifications() calls, it should never happen.
+
+         synchronized (buffer)
+         {
+            if (sequenceNumber <= lowestExpectedSequence)
+            {
+               long lowest = Math.min(lowestExpectedSequence, sequenceNumber);
+
+               if (lowest - getFirstSequenceNumber() > purgeDistance)
+               {
+                  // Purge only half of the old notifications, for safety
+                  int purgeSize = purgeDistance >> 1;
+                  removeRange(0, purgeSize);
+               }
+
+               lowestExpectedSequence = sequenceNumber + size;
+            }
+         }
+      }
+
+      public String toString()
+      {
+         StringBuffer buffer = new StringBuffer("NotificationBuffer@");
+         buffer.append(Integer.toHexString(hashCode())).append("[");
+         buffer.append("first=").append(getFirstSequenceNumber()).append(", ");
+         buffer.append("last=").append(getLastSequenceNumber()).append(", ");
+         buffer.append("size=").append(getSize()).append(", ");
+         buffer.append("lowest expected=").append(lowestExpectedSequence).append(", ");
+         buffer.append("maxCapacity=").append(maxCapacity).append(", ");
+         buffer.append("purgeDistance=").append(purgeDistance).append("]");
+         return buffer.toString();
+      }
+   }
+}

Added: incubator/felix/trunk/org.apache.felix.mosgi.jmx.rmiconnector/src/main/java/org/apache/felix/mosgi/jmx/rmiconnector/mx4j/remote/HeartBeat.java
URL: http://svn.apache.org/viewvc/incubator/felix/trunk/org.apache.felix.mosgi.jmx.rmiconnector/src/main/java/org/apache/felix/mosgi/jmx/rmiconnector/mx4j/remote/HeartBeat.java?rev=423854&view=auto
==============================================================================
--- incubator/felix/trunk/org.apache.felix.mosgi.jmx.rmiconnector/src/main/java/org/apache/felix/mosgi/jmx/rmiconnector/mx4j/remote/HeartBeat.java (added)
+++ incubator/felix/trunk/org.apache.felix.mosgi.jmx.rmiconnector/src/main/java/org/apache/felix/mosgi/jmx/rmiconnector/mx4j/remote/HeartBeat.java Thu Jul 20 02:35:19 2006
@@ -0,0 +1,37 @@
+/*
+ * 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.rmiconnector.mx4j.remote;
+
+import java.io.IOException;
+
+/**
+ *
+ * @author <a href="mailto:biorn_steedom@users.sourceforge.net">Simone Bordet</a>
+ * @version $Revision: 1.1.1.1 $
+ */
+public interface HeartBeat
+{
+   public void start() throws IOException;
+   public void stop() throws IOException;
+}

Added: incubator/felix/trunk/org.apache.felix.mosgi.jmx.rmiconnector/src/main/java/org/apache/felix/mosgi/jmx/rmiconnector/mx4j/remote/MX4JRemoteConstants.java
URL: http://svn.apache.org/viewvc/incubator/felix/trunk/org.apache.felix.mosgi.jmx.rmiconnector/src/main/java/org/apache/felix/mosgi/jmx/rmiconnector/mx4j/remote/MX4JRemoteConstants.java?rev=423854&view=auto
==============================================================================
--- incubator/felix/trunk/org.apache.felix.mosgi.jmx.rmiconnector/src/main/java/org/apache/felix/mosgi/jmx/rmiconnector/mx4j/remote/MX4JRemoteConstants.java (added)
+++ incubator/felix/trunk/org.apache.felix.mosgi.jmx.rmiconnector/src/main/java/org/apache/felix/mosgi/jmx/rmiconnector/mx4j/remote/MX4JRemoteConstants.java Thu Jul 20 02:35:19 2006
@@ -0,0 +1,112 @@
+/*
+ * 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.rmiconnector.mx4j.remote;
+
+/**
+ * @author <a href="mailto:biorn_steedom@users.sourceforge.net">Simone Bordet</a>
+ * @version $Revision: 1.1.1.1 $
+ */
+public interface MX4JRemoteConstants
+{
+   /**
+    * A vertical bar '|' as mandated by the spec
+    */
+   public static final String PROVIDER_PACKAGES_SEPARATOR = "|";
+   /**
+    * MX4J provider packages list for JMXConnector and JMXConnectorServer factories
+    */
+   public static final String PROVIDER_PACKAGES = "org.apache.felix.mosgi.jmx.rmiconnector.mx4j.remote.provider" + PROVIDER_PACKAGES_SEPARATOR + "org.apache.felix.mosgi.jmx.rmiconnector.mx4j.tools.remote.provider";
+   /**
+    * The string 'ClientProvider' as mandated by the spec
+    */
+   public static final String CLIENT_PROVIDER_CLASS = "ClientProvider";
+   /**
+    * The string 'ServerProvider' as mandated by the spec
+    */
+   public static final String SERVER_PROVIDER_CLASS = "ServerProvider";
+
+
+   /**
+    * The key that specifies resolver packages, very much like
+    * {@link javax.management.remote.JMXConnectorFactory#PROTOCOL_PROVIDER_PACKAGES}
+    */
+   public static final String PROTOCOL_RESOLVER_PACKAGES = "mx4j.remote.resolver.pkgs";
+   /**
+    * A vertical bar '|'
+    */
+   public static final String RESOLVER_PACKAGES_SEPARATOR = PROVIDER_PACKAGES_SEPARATOR;
+   /**
+    * MX4J provider packages list for {@link mx4j.remote.ConnectionResolver} subclasses
+    */
+   public static final String RESOLVER_PACKAGES = "org.apache.felix.mosgi.jmx.rmiconnector.mx4j.remote.resolver" + RESOLVER_PACKAGES_SEPARATOR + "org.apache.felix.mosgi.jmx.rmiconnector.mx4j.tools.remote.resolver";
+   /**
+    * The string 'Resolver'
+    */
+   public static final String RESOLVER_CLASS = "Resolver";
+
+   /**
+    * The reference implementation uses this property to specify the notification fetch timeout (in ms).
+    * MX4J will use the same for compatibility. DO NOT CHANGE IT unless the reference implementation changes it.
+    */
+   public static final String FETCH_NOTIFICATIONS_TIMEOUT = "jmx.remote.x.client.fetch.timeout";
+   /**
+    * The reference implementation uses this property to specify the maximum number of notification to fetch.
+    * MX4J will use the same for compatibility. DO NOT CHANGE IT unless the reference implementation changes it.
+    */
+   public static final String FETCH_NOTIFICATIONS_MAX_NUMBER = "jmx.remote.x.client.max.notifications";
+   /**
+    * The reference implementation uses this property to specify the notification buffer size.
+    * MX4J will use the same for compatibility. DO NOT CHANGE IT unless the reference implementation changes it.
+    */
+   public static final String NOTIFICATION_BUFFER_CAPACITY = "jmx.remote.x.buffer.size";
+   /**
+    * MX4J's implementation uses this property to specify the distance between the lowest expected notification
+    * sequence number (sent by the client via fetchNotifications()) and the minimum sequence number of the
+    * notification buffer. When this difference is greater than the value of this property, old notifications
+    * are eliminated from the notification buffer
+    */
+   public static final String NOTIFICATION_PURGE_DISTANCE = "jmx.remote.x.notification.purge.distance";
+   /**
+    * MX4J's implementation uses this property to specify the amount of time (in ms) the client should sleep
+    * between notification fetches. A value of 0 means there will be no sleep (fetches will be done one
+    * after the other).
+    */
+   public static final String FETCH_NOTIFICATIONS_SLEEP = "jmx.remote.x.notification.fetch.sleep";
+
+   /**
+    * MX4J's implementation uses this property to specify the period (in ms) of the heartbeat pulse for
+    * {@link javax.management.remote.JMXConnector JMXConnectors} that use heartbeat to check if the
+    * connection with {@link javax.management.remote.JMXConnectorServer JMXConnectorServers} is still alive.
+    * @see #CONNECTION_HEARTBEAT_RETRIES
+    */
+   public static final String CONNECTION_HEARTBEAT_PERIOD = "jmx.remote.x.connection.heartbeat.period";
+   /**
+    * MX4J's implementation uses this property to specify the number of retries of heartbeat pulses before
+    * declaring the connection between a {@link javax.management.remote.JMXConnector JMXConnector} and a
+    * {@link javax.management.remote.JMXConnectorServer JMXConnectorServer} failed, at which a
+    * {@link javax.management.remote.JMXConnectionNotification notification failed} is emitted.
+    * @see #CONNECTION_HEARTBEAT_PERIOD
+    */
+   public static final String CONNECTION_HEARTBEAT_RETRIES = "jmx.remote.x.connection.heartbeat.retries";
+}

Added: incubator/felix/trunk/org.apache.felix.mosgi.jmx.rmiconnector/src/main/java/org/apache/felix/mosgi/jmx/rmiconnector/mx4j/remote/MX4JRemoteUtils.java
URL: http://svn.apache.org/viewvc/incubator/felix/trunk/org.apache.felix.mosgi.jmx.rmiconnector/src/main/java/org/apache/felix/mosgi/jmx/rmiconnector/mx4j/remote/MX4JRemoteUtils.java?rev=423854&view=auto
==============================================================================
--- incubator/felix/trunk/org.apache.felix.mosgi.jmx.rmiconnector/src/main/java/org/apache/felix/mosgi/jmx/rmiconnector/mx4j/remote/MX4JRemoteUtils.java (added)
+++ incubator/felix/trunk/org.apache.felix.mosgi.jmx.rmiconnector/src/main/java/org/apache/felix/mosgi/jmx/rmiconnector/mx4j/remote/MX4JRemoteUtils.java Thu Jul 20 02:35:19 2006
@@ -0,0 +1,344 @@
+/*
+ * 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.rmiconnector.mx4j.remote;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.ObjectOutputStream;
+import java.io.Serializable;
+import java.lang.reflect.Constructor;
+
+import java.security.AccessControlContext;
+import java.security.AccessController;
+import java.security.CodeSource;
+import java.security.DomainCombiner;
+import java.security.Permission;
+import java.security.PermissionCollection;
+import java.security.Principal;
+import java.security.PrivilegedAction;
+import java.security.PrivilegedActionException;
+import java.security.PrivilegedExceptionAction;
+import java.security.ProtectionDomain;
+import javax.security.auth.AuthPermission;
+import javax.security.auth.Policy;
+import javax.security.auth.Subject;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+
+import javax.management.remote.SubjectDelegationPermission;
+
+/**
+ *
+ * @author <a href="mailto:biorn_steedom@users.sourceforge.net">Simone Bordet</a>
+ * @version $Revision: 1.2 $
+ */
+public class MX4JRemoteUtils
+{
+   private static int connectionNumber;
+
+   /**
+    * Returns a copy of the given Map that does not contain non-serializable entries
+    */
+   public static Map removeNonSerializableEntries(Map map)
+   {
+      Map newMap = new HashMap(map.size());
+      for (Iterator i = map.entrySet().iterator(); i.hasNext();)
+      {
+         Map.Entry entry = (Map.Entry)i.next();
+         if (isSerializable(entry)) newMap.put(entry.getKey(), entry.getValue());
+      }
+      return newMap;
+   }
+
+   private static boolean isSerializable(Object object)
+   {
+      if (object instanceof Map.Entry) return isSerializable(((Map.Entry)object).getKey()) && isSerializable(((Map.Entry)object).getValue());
+      if (object == null) return true;
+      if (object instanceof String) return true;
+      if (object instanceof Number) return true;
+      if (!(object instanceof Serializable)) return false;
+
+      return isTrulySerializable(object);
+   }
+
+   public static boolean isTrulySerializable(Object object)
+   {
+      // Give up and serialize the object
+      try
+      {
+         ByteArrayOutputStream baos = new ByteArrayOutputStream();
+         ObjectOutputStream oos = new ObjectOutputStream(baos);
+         oos.writeObject(object);
+         oos.close();
+         return true;
+      }
+      catch (IOException ignored)
+      {
+      }
+      return false;
+   }
+
+   public static String createConnectionID(String protocol, String callerAddress, int callerPort, Subject subject)
+   {
+      // See JSR 160 specification at javax/management/remote/package-summary.html
+
+      StringBuffer buffer = new StringBuffer(protocol);
+      buffer.append(':');
+      if (callerAddress != null) buffer.append("//").append(callerAddress);
+      if (callerPort >= 0) buffer.append(':').append(callerPort);
+      buffer.append(' ');
+
+      if (subject != null)
+      {
+         Set principals = subject.getPrincipals();
+         for (Iterator i = principals.iterator(); i.hasNext();)
+         {
+            Principal principal = (Principal)i.next();
+            String name = principal.getName();
+            name = name.replace(' ', '_');
+            buffer.append(name);
+            if (i.hasNext()) buffer.append(';');
+         }
+      }
+      buffer.append(' ');
+
+      buffer.append("0x").append(Integer.toHexString(getNextConnectionNumber()));
+
+      return buffer.toString();
+   }
+
+   private static synchronized int getNextConnectionNumber()
+   {
+      return ++connectionNumber;
+   }
+
+   public static Object subjectInvoke(Subject subject, Subject delegate, AccessControlContext context, PrivilegedExceptionAction action) throws Exception
+   {
+      if (delegate != null)
+      {
+         if (subject == null) throw new SecurityException("There is no authenticated subject to delegate to");
+         checkSubjectDelegationPermission(delegate, getSubjectContext(subject, context));
+      }
+
+      if (subject == null)
+      {
+         if (context == null) return action.run();
+         try
+         {
+            return AccessController.doPrivileged(action, context);
+         }
+         catch (PrivilegedActionException x)
+         {
+            throw x.getException();
+         }
+      }
+
+      try
+      {
+         AccessControlContext subjectContext = getSubjectContext(subject, context);
+         return Subject.doAsPrivileged(subject, action, subjectContext);
+      }
+      catch (PrivilegedActionException x)
+      {
+         throw x.getException();
+      }
+   }
+
+   private static void checkSubjectDelegationPermission(final Subject delegate, AccessControlContext context) throws SecurityException
+   {
+      final SecurityManager sm = System.getSecurityManager();
+      if (sm != null)
+      {
+         AccessController.doPrivileged(new PrivilegedAction()
+         {
+            public Object run()
+            {
+               StringBuffer buffer = new StringBuffer();
+               Set principals = delegate.getPrincipals();
+               for (Iterator i = principals.iterator(); i.hasNext();)
+               {
+                  Principal principal = (Principal)i.next();
+                  buffer.setLength(0);
+                  String permission = buffer.append(principal.getClass().getName()).append(".").append(principal.getName()).toString();
+                  sm.checkPermission(new SubjectDelegationPermission(permission));
+               }
+               return null;
+            }
+         }, context);
+      }
+   }
+
+   /**
+    * Returns a suitable AccessControlContext that restricts access in a {@link Subject#doAsPrivileged} call
+    * based on the current JAAS authorization policy, and combined with the given context.
+    *
+    * This is needed because the server stack frames in a call to a JMXConnectorServer are,
+    * for example for RMI, like this:
+    * <pre>
+    * java.lang.Thread.run()
+    *   [rmi runtime classes]
+    *     javax.management.remote.rmi.RMIConnectionImpl
+    *       [mx4j JSR 160 implementation code]
+    *         javax.security.auth.Subject.doAsPrivileged()
+    *           [mx4j JSR 160 implementation code]
+    *             [mx4j JSR 3 implementation code]
+    * </pre>
+    * All protection domains in this stack frames have AllPermission, normally, and the Subject.doAsPrivileged()
+    * call stops the checks very early. <br>
+    *
+    * So we need a restricting context (created at the start() of the connector server), and furthermore we need
+    * to combine the restricting context with a "special" context that does not have the same location as the
+    * JSR 3 and 160 classes and implementation (in particular will have a null location). <br>
+    * The "injection" of this synthetic ProtectionDomain allows to give AllPermission to the JSR 3 and 160 classes
+    * and implementation, but still have the possibility to specify a JAAS policy with MBeanPermissions in this way:
+    * <pre>
+    * grant principal javax.management.remote.JMXPrincipal "mx4j"
+    * {
+    *    permission javax.management.MBeanPermission "*", "getAttribute";
+    * };
+    * </pre>
+    */
+   private static AccessControlContext getSubjectContext(final Subject subject, final AccessControlContext context)
+   {
+      final SecurityManager sm = System.getSecurityManager();
+      if (sm == null)
+      {
+         return context;
+      }
+      else
+      {
+         return (AccessControlContext)AccessController.doPrivileged(new PrivilegedAction()
+         {
+            public Object run()
+            {
+               InjectingDomainCombiner combiner = new InjectingDomainCombiner(subject);
+               AccessControlContext acc = new AccessControlContext(context, combiner);
+               AccessController.doPrivileged(new PrivilegedAction()
+               {
+                  public Object run()
+                  {
+                     // Check this permission, that is required anyway, to combine the domains
+                     sm.checkPermission(new AuthPermission("doAsPrivileged"));
+                     return null;
+                  }
+               }, acc);
+               ProtectionDomain[] combined = combiner.getCombinedDomains();
+               return new AccessControlContext(combined);
+            }
+         });
+      }
+   }
+
+   private static class InjectingDomainCombiner implements DomainCombiner
+   {
+      private static Constructor domainConstructor;
+
+      static
+      {
+         try
+         {
+            domainConstructor = ProtectionDomain.class.getConstructor(new Class[]{CodeSource.class, PermissionCollection.class, ClassLoader.class, Principal[].class});
+         }
+         catch (Exception x)
+         {
+         }
+      }
+
+      private ProtectionDomain domain;
+      private ProtectionDomain[] combined;
+
+      public InjectingDomainCombiner(Subject subject)
+      {
+         if (domainConstructor != null)
+         {
+            Principal[] principals = (Principal[])subject.getPrincipals().toArray(new Principal[0]);
+            try
+            {
+               domain = (ProtectionDomain)domainConstructor.newInstance(new Object[]{new CodeSource(null, (java.security.cert.Certificate[])null), null, null, principals});
+            }
+            catch (Exception x)
+            {
+            }
+         }
+
+         if (domain == null)
+         {
+            // This is done for JDK 1.3 compatibility.
+            domain = new SubjectProtectionDomain(new CodeSource(null, (java.security.cert.Certificate[])null), subject);
+         }
+      }
+
+      public ProtectionDomain[] combine(ProtectionDomain[] current, ProtectionDomain[] assigned)
+      {
+         int length = current.length;
+         ProtectionDomain[] result = null;
+         if (assigned == null || assigned.length == 0)
+         {
+            result = new ProtectionDomain[length + 1];
+            System.arraycopy(current, 0, result, 0, length);
+         }
+         else
+         {
+            result = new ProtectionDomain[length + assigned.length + 1];
+            System.arraycopy(current, 0, result, 0, length);
+            System.arraycopy(assigned, 0, result, length, assigned.length);
+         }
+         result[result.length - 1] = domain;
+         this.combined = result;
+         return result;
+      }
+
+      public ProtectionDomain[] getCombinedDomains()
+      {
+         return combined;
+      }
+
+      private static class SubjectProtectionDomain extends ProtectionDomain
+      {
+         private final Subject subject;
+
+         public SubjectProtectionDomain(CodeSource codesource, Subject subject)
+         {
+            super(codesource, null);
+            this.subject = subject;
+         }
+
+         public boolean implies(Permission permission)
+         {
+            Policy policy = (Policy)AccessController.doPrivileged(new PrivilegedAction()
+            {
+               public Object run()
+               {
+                  return Policy.getPolicy();
+               }
+            });
+            PermissionCollection permissions = policy.getPermissions(subject, getCodeSource());
+            return permissions.implies(permission);
+         }
+      }
+   }
+}

Added: incubator/felix/trunk/org.apache.felix.mosgi.jmx.rmiconnector/src/main/java/org/apache/felix/mosgi/jmx/rmiconnector/mx4j/remote/NotificationTuple.java
URL: http://svn.apache.org/viewvc/incubator/felix/trunk/org.apache.felix.mosgi.jmx.rmiconnector/src/main/java/org/apache/felix/mosgi/jmx/rmiconnector/mx4j/remote/NotificationTuple.java?rev=423854&view=auto
==============================================================================
--- incubator/felix/trunk/org.apache.felix.mosgi.jmx.rmiconnector/src/main/java/org/apache/felix/mosgi/jmx/rmiconnector/mx4j/remote/NotificationTuple.java (added)
+++ incubator/felix/trunk/org.apache.felix.mosgi.jmx.rmiconnector/src/main/java/org/apache/felix/mosgi/jmx/rmiconnector/mx4j/remote/NotificationTuple.java Thu Jul 20 02:35:19 2006
@@ -0,0 +1,147 @@
+/*
+ * 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.rmiconnector.mx4j.remote;
+
+import javax.management.NotificationFilter;
+import javax.management.Notification;
+import javax.management.ObjectName;
+import javax.management.NotificationListener;
+
+/**
+ *
+ * @author <a href="mailto:biorn_steedom@users.sourceforge.net">Simone Bordet</a>
+ * @version $Revision: 1.1.1.1 $
+ */
+public class NotificationTuple
+{
+   private static final NotificationFilter NO_FILTER = new NotificationFilter()
+   {
+      public boolean isNotificationEnabled(Notification notification)
+      {
+         return true;
+      }
+
+      public String toString()
+      {
+         return "no filter";
+      }
+   };
+   private static final Object NO_HANDBACK = new Object()
+   {
+      public String toString()
+      {
+         return "no handback";
+      }
+   };
+
+   private final ObjectName observed;
+   private final NotificationListener listener;
+   private final NotificationFilter filter;
+   private final Object handback;
+   private boolean invokeFilter;
+
+   public NotificationTuple(ObjectName observed, NotificationListener listener)
+   {
+      this(observed, listener, NO_FILTER, NO_HANDBACK);
+   }
+
+   public NotificationTuple(ObjectName observed, NotificationListener listener, NotificationFilter filter, Object handback)
+   {
+      this.observed = observed;
+      this.listener = listener;
+      this.filter = filter;
+      this.handback = handback;
+      this.invokeFilter = false;
+   }
+
+   public NotificationListener getNotificationListener()
+   {
+      return listener;
+   }
+
+   public Object getHandback()
+   {
+      if (handback == NO_HANDBACK) return null;
+      return handback;
+   }
+
+   public NotificationFilter getNotificationFilter()
+   {
+      if (filter == NO_FILTER) return null;
+      return filter;
+   }
+
+   public void setInvokeFilter(boolean invoke)
+   {
+      this.invokeFilter = invoke;
+   }
+
+   public boolean getInvokeFilter()
+   {
+      if (!invokeFilter) return false;
+      NotificationFilter filter = getNotificationFilter();
+      if (filter == null) return false;
+      return true;
+   }
+
+   public boolean equals(Object obj)
+   {
+      if (this == obj) return true;
+      if (!(obj instanceof NotificationTuple)) return false;
+
+      final NotificationTuple other = (NotificationTuple)obj;
+
+      if (!observed.equals(other.observed)) return false;
+      if (!listener.equals(other.listener)) return false;
+
+      // Special treatment for special filter
+      if (filter == NO_FILTER) return true;
+      if (other.filter == NO_FILTER) return true;
+
+      if (filter != null ? !filter.equals(other.filter) : other.filter != null) return false;
+      if (handback != null ? !handback.equals(other.handback) : other.handback != null) return false;
+
+      return true;
+   }
+
+   public int hashCode()
+   {
+      int result;
+      result = observed.hashCode();
+      result = 29 * result + listener.hashCode();
+      result = 29 * result + (filter != null ? filter.hashCode() : 0);
+      result = 29 * result + (handback != null ? handback.hashCode() : 0);
+      return result;
+   }
+
+   public String toString()
+   {
+      StringBuffer buffer = new StringBuffer("NotificationTuple [");
+      buffer.append(observed).append(", ");
+      buffer.append(listener).append(", ");
+      buffer.append(filter).append(", ");
+      buffer.append(handback).append("]");
+      return buffer.toString();
+   }
+}

Added: incubator/felix/trunk/org.apache.felix.mosgi.jmx.rmiconnector/src/main/java/org/apache/felix/mosgi/jmx/rmiconnector/mx4j/remote/ProviderFactory.java
URL: http://svn.apache.org/viewvc/incubator/felix/trunk/org.apache.felix.mosgi.jmx.rmiconnector/src/main/java/org/apache/felix/mosgi/jmx/rmiconnector/mx4j/remote/ProviderFactory.java?rev=423854&view=auto
==============================================================================
--- incubator/felix/trunk/org.apache.felix.mosgi.jmx.rmiconnector/src/main/java/org/apache/felix/mosgi/jmx/rmiconnector/mx4j/remote/ProviderFactory.java (added)
+++ incubator/felix/trunk/org.apache.felix.mosgi.jmx.rmiconnector/src/main/java/org/apache/felix/mosgi/jmx/rmiconnector/mx4j/remote/ProviderFactory.java Thu Jul 20 02:35:19 2006
@@ -0,0 +1,180 @@
+/*
+ * 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.rmiconnector.mx4j.remote;
+
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.util.Map;
+import java.util.StringTokenizer;
+
+import javax.management.remote.JMXConnectorFactory;
+import javax.management.remote.JMXConnectorProvider;
+import javax.management.remote.JMXConnectorServerFactory;
+import javax.management.remote.JMXConnectorServerProvider;
+import javax.management.remote.JMXProviderException;
+import javax.management.remote.JMXServiceURL;
+
+import org.osgi.service.log.LogService;
+
+import org.apache.felix.mosgi.jmx.rmiconnector.RmiConnectorActivator;
+
+import org.apache.felix.mosgi.jmx.rmiconnector.mx4j.remote.MX4JRemoteConstants;
+import org.apache.felix.mosgi.jmx.rmiconnector.mx4j.remote.ProviderHelper;
+
+/**
+ *
+ * @author <a href="mailto:biorn_steedom@users.sourceforge.net">Simone Bordet</a>
+ * @version $Revision: 1.2 $
+ */
+public class ProviderFactory extends ProviderHelper
+{
+   public static JMXConnectorProvider newJMXConnectorProvider(JMXServiceURL url, Map env) throws IOException
+   {
+      // Yes, throw NPE if url is null (spec compliant)
+      String protocol = normalizeProtocol(url.getProtocol());
+      String providerPackages = findProviderPackageList(env, JMXConnectorFactory.PROTOCOL_PROVIDER_PACKAGES);
+      ClassLoader classLoader = findProviderClassLoader(env, JMXConnectorFactory.PROTOCOL_PROVIDER_CLASS_LOADER);
+      JMXConnectorProvider provider = (JMXConnectorProvider)loadProvider(providerPackages, protocol, MX4JRemoteConstants.CLIENT_PROVIDER_CLASS, classLoader);
+      return provider;
+   }
+
+   public static JMXConnectorServerProvider newJMXConnectorServerProvider(JMXServiceURL url, Map env) throws IOException
+   {
+      // Yes, throw NPE if url is null (spec compliant)
+      String protocol = normalizeProtocol(url.getProtocol());
+      String providerPackages = findProviderPackageList(env, JMXConnectorServerFactory.PROTOCOL_PROVIDER_PACKAGES);
+      ClassLoader classLoader = findProviderClassLoader(env, JMXConnectorFactory.PROTOCOL_PROVIDER_CLASS_LOADER);
+      JMXConnectorServerProvider provider = (JMXConnectorServerProvider)loadProvider(providerPackages, protocol, MX4JRemoteConstants.SERVER_PROVIDER_CLASS, classLoader);
+      return provider;
+   }
+
+   private static String findEnvironmentProviderPackageList(Map environment, String key) throws JMXProviderException
+   {
+      String providerPackages = null;
+      if (environment != null)
+      {
+         Object pkgs = environment.get(key);
+         RmiConnectorActivator.log(LogService.LOG_DEBUG, "Provider packages in the environment: " + pkgs, null);
+         if (pkgs != null && !(pkgs instanceof String)) throw new JMXProviderException("Provider package list must be a string");
+         providerPackages = (String)pkgs;
+      }
+      return providerPackages;
+   }
+
+   private static String findProviderPackageList(Map environment, final String providerPkgsKey) throws JMXProviderException
+   {
+      // 1. Look in the environment
+      // 2. Look for system property
+      // 3. Use implementation's provider
+
+      String providerPackages = findEnvironmentProviderPackageList(environment, providerPkgsKey);
+
+      if (providerPackages == null)
+      {
+         providerPackages = findSystemPackageList(providerPkgsKey);
+      }
+
+      if (providerPackages != null && providerPackages.trim().length() == 0) throw new JMXProviderException("Provider package list cannot be an empty string");
+
+      if (providerPackages == null)
+         providerPackages = MX4JRemoteConstants.PROVIDER_PACKAGES;
+      else
+         providerPackages += MX4JRemoteConstants.PROVIDER_PACKAGES_SEPARATOR + MX4JRemoteConstants.PROVIDER_PACKAGES;
+
+      RmiConnectorActivator.log(LogService.LOG_DEBUG,"Provider packages list is: " + providerPackages,null);
+
+      return providerPackages;
+   }
+
+   private static ClassLoader findProviderClassLoader(Map environment, String providerLoaderKey)
+   {
+
+      ClassLoader classLoader = null;
+      if (environment != null)
+      {
+         Object loader = environment.get(providerLoaderKey);
+         RmiConnectorActivator.log(LogService.LOG_DEBUG,"Provider classloader in the environment: " + loader, null);
+         if (loader != null && !(loader instanceof ClassLoader)) throw new IllegalArgumentException("Provider classloader is not a ClassLoader");
+         classLoader = (ClassLoader)loader;
+      }
+
+      if (classLoader == null)
+      {
+         //classLoader = Thread.currentThread().getContextClassLoader();
+         classLoader = ProviderFactory.class.getClassLoader();
+         RmiConnectorActivator.log(LogService.LOG_DEBUG,"Provider classloader (was null) in the environment: " + classLoader, null);
+      }
+
+      // Add the classloader as required by the spec
+      environment.put(JMXConnectorFactory.PROTOCOL_PROVIDER_CLASS_LOADER, classLoader);
+      RmiConnectorActivator.log(LogService.LOG_WARNING,"Provider classloader added to the environment", null);
+
+      return classLoader;
+   }
+
+   private static Object loadProvider(String packages, String protocol, String className, ClassLoader loader) throws JMXProviderException, MalformedURLException
+   {
+      StringTokenizer tokenizer = new StringTokenizer(packages, MX4JRemoteConstants.PROVIDER_PACKAGES_SEPARATOR);
+      while (tokenizer.hasMoreTokens())
+      {
+         String pkg = tokenizer.nextToken().trim();
+         RmiConnectorActivator.log(LogService.LOG_DEBUG,"Provider package: " + pkg, null);
+
+         // The spec states the package cannot be empty
+         if (pkg.length() == 0) throw new JMXProviderException("Empty package list not allowed: " + packages);
+
+         String providerClassName = constructClassName(pkg, protocol, className);
+
+         Class providerClass = null;
+         try
+         {
+            providerClass = loadClass(providerClassName, loader);
+         }
+         catch (ClassNotFoundException x)
+         {
+            RmiConnectorActivator.log(LogService.LOG_DEBUG,"Provider class " + providerClassName + " not found, continuing with next package",null);
+            continue;
+         }
+         catch (Exception x)
+         {
+            RmiConnectorActivator.log(LogService.LOG_WARNING,"Cannot load provider class " + providerClassName, x);
+            throw new JMXProviderException("Cannot load provider class " + providerClassName, x);
+         }
+
+         try
+         {
+            return providerClass.newInstance();
+         }
+         catch (Exception x)
+         {
+            RmiConnectorActivator.log(LogService.LOG_WARNING,"Cannot instantiate provider class " + providerClassName, x);
+            throw new JMXProviderException("Cannot instantiate provider class " + providerClassName, x);
+         }
+      }
+
+      // Nothing found
+      RmiConnectorActivator.log(LogService.LOG_DEBUG,"Could not find provider for protocol " + protocol + " in package list '" + packages + "'", null);
+      throw new MalformedURLException("Could not find provider for protocol " + protocol + " in package list '" + packages + "'");
+   }
+}

Added: incubator/felix/trunk/org.apache.felix.mosgi.jmx.rmiconnector/src/main/java/org/apache/felix/mosgi/jmx/rmiconnector/mx4j/remote/ProviderHelper.java
URL: http://svn.apache.org/viewvc/incubator/felix/trunk/org.apache.felix.mosgi.jmx.rmiconnector/src/main/java/org/apache/felix/mosgi/jmx/rmiconnector/mx4j/remote/ProviderHelper.java?rev=423854&view=auto
==============================================================================
--- incubator/felix/trunk/org.apache.felix.mosgi.jmx.rmiconnector/src/main/java/org/apache/felix/mosgi/jmx/rmiconnector/mx4j/remote/ProviderHelper.java (added)
+++ incubator/felix/trunk/org.apache.felix.mosgi.jmx.rmiconnector/src/main/java/org/apache/felix/mosgi/jmx/rmiconnector/mx4j/remote/ProviderHelper.java Thu Jul 20 02:35:19 2006
@@ -0,0 +1,71 @@
+/*
+ *   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.rmiconnector.mx4j.remote;
+
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+
+import org.osgi.service.log.LogService;
+
+import org.apache.felix.mosgi.jmx.rmiconnector.RmiConnectorActivator;
+
+/**
+ *
+ * @version $Revision: 1.2 $
+ */
+public abstract class ProviderHelper
+{
+   protected static String normalizeProtocol(String protocol)
+   {
+      // Replace special chars as required by the spec
+      String normalized = protocol.replace('+', '.');
+      normalized = normalized.replace('-', '_');
+      RmiConnectorActivator.log(LogService.LOG_INFO, "Normalizing protocol: " + protocol + " --> " + normalized, null);
+      return normalized;
+   }
+
+   protected static String findSystemPackageList(final String key)
+   {
+      String providerPackages = (String)AccessController.doPrivileged(new PrivilegedAction()
+      {
+         public Object run()
+         {
+            return System.getProperty(key);
+         }
+      });
+      RmiConnectorActivator.log(LogService.LOG_DEBUG,"Packages in the system property '" + key + "': " + providerPackages,null);
+      return providerPackages;
+   }
+
+   protected static Class loadClass(String className, ClassLoader loader) throws ClassNotFoundException
+   {
+      RmiConnectorActivator.log(LogService.LOG_DEBUG,"Loading class: " + className +" From "+loader,null);
+      if (loader == null){
+         loader= ProviderHelper.class.getClassLoader();
+         RmiConnectorActivator.log(LogService.LOG_DEBUG,"a new loader "+loader,null);
+         
+         	//Thread.currentThread().getContextClassLoader();
+      }
+      return loader.loadClass(className);
+   }
+
+   protected static String constructClassName(String packageName, String protocol, String className)
+   {
+      return new StringBuffer(packageName).append(".").append(protocol).append(".").append(className).toString();
+   }
+
+}