Moved org.apache.felix.jmood to trunk

git-svn-id: https://svn.apache.org/repos/asf/incubator/felix/trunk@438973 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/org.apache.felix.jmood/pom.xml b/org.apache.felix.jmood/pom.xml
new file mode 100644
index 0000000..e51ae2e
--- /dev/null
+++ b/org.apache.felix.jmood/pom.xml
@@ -0,0 +1,90 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

+  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">

+    <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>JMood JMX Management Agent</name>

+  <artifactId>${groupId}.jmood</artifactId>

+  <dependencies>

+    <dependency>

+      <groupId>${pom.groupId}</groupId>

+      <artifactId>org.apache.felix.framework</artifactId>

+      <version>${pom.version}</version>

+      <scope>provided</scope>

+    </dependency>

+    <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>junit</groupId>

+      <artifactId>junit</artifactId>

+      <version>3.8.1</version>

+      <scope>test</scope>

+    </dependency>

+  </dependencies>

+  <build>

+    <resources>

+      <resource>

+        <directory>src/main/resources</directory>

+        <filtering>true</filtering>

+      </resource>

+    </resources>

+    <plugins>

+      <plugin>

+        <groupId>org.apache.felix.plugins</groupId>

+        <artifactId>maven-osgi-plugin</artifactId>

+        <version>${pom.version}</version>

+        <extensions>true</extensions>

+        <configuration>

+          <osgiManifest >

+            <bundleName>${name}</bundleName>

+            <bundleActivator>${artifactId}.Activator</bundleActivator>

+            <bundleDescription>JMood management agent</bundleDescription>

+            <bundleSymbolicName>${artifactId}</bundleSymbolicName>

+            <exportPackage>

+            <!-- TODO -->

+            </exportPackage>

+            <!--Automatic resolution includes not available, unused, mx4j stuff-->

+ 			<importPackage>

+			org.osgi.framework, org.osgi.util.tracker, org.osgi.service.log, org.osgi.service.packageadmin, org.osgi.service.startlevel, org.osgi.service.permissionadmin, org.osgi.service.useradmin, org.osgi.service.cm, javax.management, javax.management.remote

+			</importPackage>

+          </osgiManifest>

+        </configuration>

+      </plugin>

+     <plugin>

+      <groupId>org.apache.maven.plugins</groupId>

+      <artifactId>maven-surefire-plugin</artifactId>

+      <configuration>

+      <!--

+      Current tests are (unfinished) integration tests, and need 

+      to have the bundle available, so there's a chicken-egg problem there. Temporal workaround: omit tests in pom

+      -->

+      

+        <skip>true</skip>

+      </configuration>

+    </plugin>

+      

+    </plugins>

+  </build>

+  <reporting>

+    <plugins>

+      <plugin>

+        <groupId>org.apache.maven.plugins</groupId>

+        <artifactId>maven-project-info-reports-plugin</artifactId>

+      </plugin>

+    </plugins>

+  </reporting>

+</project>

diff --git a/org.apache.felix.jmood/src/main/java/org/apache/felix/jmood/Activator.java b/org.apache.felix.jmood/src/main/java/org/apache/felix/jmood/Activator.java
new file mode 100644
index 0000000..328f6ac
--- /dev/null
+++ b/org.apache.felix.jmood/src/main/java/org/apache/felix/jmood/Activator.java
@@ -0,0 +1,236 @@
+/*

+ *   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.jmood;

+

+import java.io.File;

+import java.io.FileOutputStream;

+import java.io.IOException;

+import java.io.InputStream;

+import java.lang.reflect.Method;

+import java.net.InetAddress;

+import java.net.URL;

+import java.rmi.RemoteException;

+import java.rmi.registry.LocateRegistry;

+import java.rmi.registry.Registry;

+import java.rmi.server.ExportException;

+import java.rmi.server.UnicastRemoteObject;

+import java.util.Properties;

+

+import javax.management.InstanceAlreadyExistsException;

+import javax.management.InstanceNotFoundException;

+import javax.management.MBeanRegistrationException;

+import javax.management.MBeanServer;

+import javax.management.MBeanServerFactory;

+import javax.management.MalformedObjectNameException;

+import javax.management.NotCompliantMBeanException;

+import javax.management.ObjectName;

+import javax.management.remote.JMXConnectorServer;

+import javax.management.remote.JMXConnectorServerFactory;

+import javax.management.remote.JMXServiceURL;

+

+

+import org.apache.felix.jmood.core.CoreController;

+import org.apache.felix.jmood.core.Framework;

+import org.apache.felix.jmood.utils.ObjectNames;

+import org.osgi.framework.BundleActivator;

+import org.osgi.framework.BundleContext;

+public class Activator implements BundleActivator{

+    private Properties props;

+    private String agentPropsPath="/agent.properties";

+    private static final String IS_POLICY_EMBEDDED="policy.embedded";

+    private static final String JAVA_SECURITY_POLICY="java.security.policy";

+    private MBeanServer server;

+    private JMXConnectorServer connectorServer;

+    private int rmiRegistryPort = 1199;

+    private AgentContext ac;

+    private static final String connectoServerOname="RemotingService:type=ConnectorServer, subtype=RMIConnectorServer, provider=JRE";

+    private CompendiumController compendium;

+    private Registry rmiRegistry;

+    

+

+    public void start(BundleContext context) throws Exception {

+        this.ac=new AgentContext(context);

+        this.ac.debug("starting");

+        try{

+        this.server=this.getMBeanServer();

+        }

+        catch (Exception e){

+        	this.ac.error("unexpected error", e);

+        	throw e;

+        }

+        this.ac.debug("got platform mbeanserver");

+        this.compendium = new CompendiumController(this.server,this.ac);

+        this.props = this.loadProperties();

+        this.ac.debug("props loaded");

+        //TODO Enable this when Felix has security support.RMI Serialization doesn't work well without it. In Equinox, it works fine

+        //this.setSecurityManager();

+        //ac.debug("security manager set");

+         this.ac.debug("registering mbeans");

+            this.registerMBeans();

+            this.initRMIConn();

+            this.ac.debug("rmi connection initialised and mbeans registered");

+            this.ac.debug("agent started");

+    }

+    public void stop(BundleContext context) throws Exception {

+        this.ac.debug("stopping");

+        this.stopRMIConn();

+        this.ac.closeTrackers();

+        this.unregisterMBeans();

+        this.ac.debug("done");

+    }

+    private void setSecurityManager() throws Exception{

+        //TODO check this when we add permission admin support to the bundle

+        //It caused StackOverFlow the second time the framework was run(?)

+    	

+        if (System.getSecurityManager() != null) {

+			return;

+		}

+		try {

+			this.ac.debug("Security manager does not exist");

+            if (this.props.getProperty(IS_POLICY_EMBEDDED).equalsIgnoreCase("true")){

+                this.ac.debug("Policy is embedded, copying it to filesystem...");

+                String policyName=this.props.getProperty(JAVA_SECURITY_POLICY);

+                //The policy is in the file system and should be copied...

+                File file=this.ac.getBundleContext().getDataFile(policyName);

+                if (file.exists()) {

+                    this.ac.debug("trying to delete file...");

+                    boolean deleted=file.delete();

+                    if(!deleted) {

+						this.ac.error("Could not delete existing policy file");

+					} else {

+						this.ac.debug("successfully deleted");

+					}

+                    file=this.ac.getBundleContext().getDataFile(policyName);

+                    file.createNewFile();

+                    this.ac.debug("new file created");

+                }

+

+                FileOutputStream o=new FileOutputStream (file);

+                InputStream i=this.ac.getBundleContext().getBundle().getResource("/"+policyName).openStream();

+                byte [] buffer=new byte [1024];

+                while (i.read(buffer)!=-1){

+                   o.write(buffer);

+                }

+                i.close();

+                o.flush();

+                o.close();

+                

+                System.setProperty(JAVA_SECURITY_POLICY, file.getAbsolutePath());

+            }

+            else{

+         System.setProperty(JAVA_SECURITY_POLICY, this.props.getProperty(JAVA_SECURITY_POLICY));

+            }

+         System.setSecurityManager(new SecurityManager());

+

+        }catch(Exception e){

+            this.ac.error("Unexpected exception", e);

+            }

+        this.ac.debug("Security policy: "+System.getProperty(JAVA_SECURITY_POLICY));

+        this.ac.debug("Security manager toString(): "+System.getSecurityManager().toString());

+

+        }

+        

+    private Properties loadProperties() throws Exception{

+        Properties props = new Properties();

+        URL u=this.ac.getBundleContext().getBundle().getResource(this.agentPropsPath);

+        props.load(u.openStream());

+        return props;

+    }

+

+    /**

+     * A getter method for retrieving the context of this bundle

+     * @return BundleContext the bundle context for this bundle

+     * @throws InstanceNotFoundException 

+     */

+

+    private void initRMIConn() throws IOException, InstanceAlreadyExistsException, MBeanRegistrationException, NotCompliantMBeanException, MalformedObjectNameException, NullPointerException, InstanceNotFoundException {

+    	Thread t=new Thread(){

+    		public void run() {

+    	        try {

+    	        	rmiRegistry=LocateRegistry.createRegistry(rmiRegistryPort);

+    	            } catch (RemoteException e) {

+    	                ac.warning(e.getMessage()+"\n"+"Possibly some other framework already running, skipping RMI registry creation");

+    	              return;

+    	           }

+    		}

+    	};

+    	t.setName("RMIREGISTRY");

+    	t.setContextClassLoader(this.getClass().getClassLoader());

+    	t.start();

+        InetAddress[] addresses=InetAddress.getAllByName(InetAddress.getLocalHost().getCanonicalHostName());

+        //Do not attach the agent to the loopback address

+        InetAddress address=null;

+        for (int i = 0; i < addresses.length; i++) {

+            if (!addresses[i].isLoopbackAddress()) {                    

+                address=addresses[i];

+                break;

+            }

+        }

+        if (address==null){

+        	StringBuffer msg=new StringBuffer("java.net.InetAddress could not find non-localhost IP. \n");

+        		msg.append(" Is there any network interface available? Are you using Linux?. \n")

+        		   .append("If you are using debian-based distros, try editing the /etc/hosts file so that it does not contain")

+        		   .append(" something like '127.0.0.1 ${hostname}'");

+        	this.ac.warning(msg.toString());

+        	address=InetAddress.getLocalHost();

+        }

+        JMXServiceURL url = new JMXServiceURL(

+                "service:jmx:rmi:///jndi/rmi://"+address.getHostName()+":"

+                        + this.rmiRegistryPort + "/server");

+                this.ac.debug(url.toString());                        

+        this.connectorServer = JMXConnectorServerFactory.newJMXConnectorServer(

+                url, null,this.server);

+

+        this.server.registerMBean(this.connectorServer, new ObjectName(connectoServerOname));

+        this.connectorServer.start();

+    }

+    private void stopRMIConn() throws Exception {

+        this.connectorServer.stop();

+        UnicastRemoteObject.unexportObject(this.rmiRegistry, true);

+        this.server.unregisterMBean(new ObjectName(connectoServerOname));

+        

+    }

+    

+    private void registerMBeans() throws Exception{

+        this.server.registerMBean(new CoreController(this.ac), new ObjectName(ObjectNames.CORE_CONTROLLER));

+        this.server.registerMBean(new Framework(this.ac), new ObjectName(ObjectNames.FRAMEWORK));

+        this.compendium.initController();

+        this.ac.debug("mbeans registered");

+

+        

+    }

+    private void unregisterMBeans() throws Exception{

+        this.server.unregisterMBean(new ObjectName(ObjectNames.CORE_CONTROLLER));

+        this.server.unregisterMBean(new ObjectName(ObjectNames.FRAMEWORK));

+        this.compendium.dispose();

+    }

+    private MBeanServer getMBeanServer() throws Exception{

+    	String jvm=System.getProperty("java.version"); //1.5.0 or higher

+    	this.ac.debug("java version is: "+jvm);

+    	String[] s=jvm.split("\\.");

+    	if(Integer.parseInt(s[1])<5){//In this way it should also work with Mustang

+				return MBeanServerFactory.createMBeanServer();

+		} else {

+				Class clazz =

+					Class.forName("java.lang.management.ManagementFactory");

+				Method m=clazz.getDeclaredMethod("getPlatformMBeanServer", new Class[0]);

+						return (MBeanServer) m.invoke(null,(Object[]) null);

+	}

+    }

+

+}

diff --git a/org.apache.felix.jmood/src/main/java/org/apache/felix/jmood/AgentConstants.java b/org.apache.felix.jmood/src/main/java/org/apache/felix/jmood/AgentConstants.java
new file mode 100644
index 0000000..7eea844
--- /dev/null
+++ b/org.apache.felix.jmood/src/main/java/org/apache/felix/jmood/AgentConstants.java
@@ -0,0 +1,31 @@
+/*

+ *   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.jmood;

+

+

+public interface AgentConstants {

+	public static final String FRAMEWORK_NOTIFICATION_TYPE =

+		"osgi.framework.framework";

+	public static final String USER_ADMIN_NOTIFICATION_TYPE = "osgi.useradmin";

+	public static final String SERVICE_NOTIFICATION_TYPE =

+		"osgi.framework.service";

+	public static final String LOG_NOTIFICATION_TYPE = "osgi.log";

+	public static final String USER = "User";

+	public static final String GROUP = "Group";

+	public static final String ROLE = "Role";

+

+}

diff --git a/org.apache.felix.jmood/src/main/java/org/apache/felix/jmood/AgentContext.java b/org.apache.felix.jmood/src/main/java/org/apache/felix/jmood/AgentContext.java
new file mode 100644
index 0000000..3377ad1
--- /dev/null
+++ b/org.apache.felix.jmood/src/main/java/org/apache/felix/jmood/AgentContext.java
@@ -0,0 +1,214 @@
+/*

+ *   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.jmood;

+

+

+import org.apache.felix.jmood.core.ServiceNotAvailableException;

+import org.osgi.framework.BundleContext;

+import org.osgi.framework.InvalidSyntaxException;

+import org.osgi.service.cm.ConfigurationAdmin;

+import org.osgi.service.log.LogReaderService;

+import org.osgi.service.log.LogService;

+import org.osgi.service.packageadmin.PackageAdmin;

+import org.osgi.service.permissionadmin.PermissionAdmin;

+import org.osgi.service.startlevel.StartLevel;

+import org.osgi.service.useradmin.UserAdmin;

+import org.osgi.util.tracker.ServiceTracker;

+

+

+/**

+ * 

+ *

+ */public class AgentContext {

+    private BundleContext context;

+    private ServiceTracker logTracker;

+    private ServiceTracker logReaderTracker;

+    private ServiceTracker startLevelTracker;

+    private ServiceTracker packageAdminTracker;

+    private ServiceTracker permissionAdminTracker;

+    private ServiceTracker userAdminTracker;

+    private ServiceTracker configAdminTracker;

+    

+    private int loglevel;

+    public static final int DEBUG=0;

+    public static final int INFO=1;

+    public static final int WARNING=2;

+    public static final int ERROR=3;

+    public AgentContext(BundleContext context) throws Exception{

+        super();

+        this.context=context;

+        this.setTrackers();

+    }

+    

+    ///////////////////////////////////////////////////////////////

+    //////////////////LOGGING/////////////////////////////////////

+    ///////////////////////////////////////////////////////////////

+    public void debug(String s){

+        if(this.loglevel==DEBUG) System.out.println("DEBUG: JMOOD. "+s);

+    }

+    public void info(String s){

+        if(this.loglevel<=INFO) System.out.println("INFO: JMOOD. "+s);

+    }

+    public void warning (String s){

+        if(this.loglevel<=WARNING) System.out.println("WARNING: JMOOD. "+s);

+    }

+    public void error(String s){

+        if(this.loglevel<=ERROR) System.out.println("ERROR: JMOOD. "+s);

+    }

+    public void error(String s, Exception e){

+        if(this.loglevel<=ERROR) {

+        	System.out.println("ERROR: JMOOD. "+s);

+        	e.printStackTrace();

+        }

+    }

+    public int getLoglevel() {

+        return loglevel;

+    }

+    public void setLoglevel(int level) {

+        this.loglevel=level;

+    }

+    //////////////////////////////////////////////////////////////

+    ///////////////////CONTEXT AND SERVICES//////////////////////

+    public BundleContext getBundleContext() {

+        return context;

+    }

+    public LogService getLogservice() {

+        int count = logTracker.getTrackingCount();

+        switch (count) {

+            case 0 :

+                return null;

+                //FUTURE WORK when there is more than one log service available, select "the best"

+            case 1 :

+            default :

+                return (LogService) logTracker.getService();

+        }

+    }

+    public StartLevel getStartLevel() throws ServiceNotAvailableException {

+        int count = startLevelTracker.getTrackingCount();

+        switch (count) {

+            case 0 :

+                throw new ServiceNotAvailableException("No start level service available");

+            case 1 :

+            default :

+                return (StartLevel) startLevelTracker.getService();

+        }

+    }

+    public PackageAdmin getPackageadmin() throws ServiceNotAvailableException{

+        int count = packageAdminTracker.getTrackingCount();

+        switch (count) {

+            case 0 :

+                throw new ServiceNotAvailableException("No package admin available");

+            case 1 :

+            default :

+                return (PackageAdmin) packageAdminTracker.getService();

+        }

+

+    }

+    public PermissionAdmin getPermissionadmin() {

+        int count = permissionAdminTracker.getTrackingCount();

+        switch (count) {

+            case 0 :

+                return null;

+            case 1 :

+            default :

+                return (PermissionAdmin) permissionAdminTracker.getService();

+        }

+    }

+    public UserAdmin getUserAdmin() {

+        int count = userAdminTracker.getTrackingCount();

+        switch (count) {

+            case 0 :

+                return null;

+            case 1 :

+            default :

+                return (UserAdmin) userAdminTracker.getService();

+        }

+    }

+    public ConfigurationAdmin getConfigurationAdmin() {

+        int count = configAdminTracker.getTrackingCount();

+        switch (count) {

+            case 0 :

+                return null;

+            case 1 :

+            default :

+                return (ConfigurationAdmin) configAdminTracker.getService();

+        }

+    }

+    //////////////////////////////////////////////////////////////////////

+    //////////////////PRIVATE////////////////////////////////////////////

+    private void setTrackers() {

+        try {

+            logTracker =

+                new ServiceTracker(

+                    context,

+                    context.createFilter(

+                        "(objectClass=" + LogService.class.getName() + ")"),

+                    null);

+        logReaderTracker =

+            new ServiceTracker(

+                context,

+                context.createFilter(

+                    "(objectClass=" + LogReaderService.class.getName() + ")"),

+                null);

+        startLevelTracker =

+            new ServiceTracker(

+                context,

+                context.createFilter(

+                    "(objectClass=" + StartLevel.class.getName() + ")"),

+                null);

+        packageAdminTracker =

+            new ServiceTracker(

+                context,

+                context.createFilter(

+                    "(objectClass=" + PackageAdmin.class.getName() + ")"),

+                null);

+        permissionAdminTracker =

+            new ServiceTracker(

+                context,

+                context.createFilter(

+                    "(objectClass=" + PermissionAdmin.class.getName() + ")"),

+                null);

+        userAdminTracker=new ServiceTracker(context, context.createFilter("(objectClass=" + UserAdmin.class.getName() + ")"), null);

+        configAdminTracker=new ServiceTracker(context, context.createFilter("(objectClass=" + ConfigurationAdmin.class.getName() + ")"), null);

+

+        } catch (InvalidSyntaxException e) {

+            warning("INVALID FILTER ");

+        }

+        

+

+

+        logTracker.open();

+        logReaderTracker.open();

+        startLevelTracker.open();

+        packageAdminTracker.open();

+        permissionAdminTracker.open();

+        userAdminTracker.open();

+        configAdminTracker.open();

+    }

+    void closeTrackers() {

+        logTracker.close();

+        logReaderTracker.close();

+        startLevelTracker.close();

+        packageAdminTracker.close();

+        permissionAdminTracker.close();

+        userAdminTracker.close();

+        configAdminTracker.close();

+

+        

+    }

+}

diff --git a/org.apache.felix.jmood/src/main/java/org/apache/felix/jmood/CompendiumController.java b/org.apache.felix.jmood/src/main/java/org/apache/felix/jmood/CompendiumController.java
new file mode 100644
index 0000000..eba0ccb
--- /dev/null
+++ b/org.apache.felix.jmood/src/main/java/org/apache/felix/jmood/CompendiumController.java
@@ -0,0 +1,213 @@
+/*

+ *   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.jmood;

+

+import java.util.Iterator;

+import java.util.Vector;

+

+import javax.management.InstanceAlreadyExistsException;

+import javax.management.InstanceNotFoundException;

+import javax.management.MBeanRegistrationException;

+import javax.management.MBeanServer;

+import javax.management.MalformedObjectNameException;

+import javax.management.NotCompliantMBeanException;

+import javax.management.ObjectName;

+

+import org.apache.felix.jmood.compendium.ConfigAdminManager;

+import org.apache.felix.jmood.compendium.ConfigAdminManagerMBean;

+import org.apache.felix.jmood.compendium.LogManager;

+import org.apache.felix.jmood.compendium.LogManagerMBean;

+import org.apache.felix.jmood.compendium.UserManager;

+import org.apache.felix.jmood.compendium.UserManagerMBean;

+import org.apache.felix.jmood.utils.ObjectNames;

+import org.osgi.framework.Constants;

+import org.osgi.framework.ServiceEvent;

+import org.osgi.framework.ServiceListener;

+import org.osgi.framework.ServiceReference;

+import org.osgi.service.cm.ConfigurationAdmin;

+import org.osgi.service.log.LogService;

+import org.osgi.service.useradmin.UserAdmin;

+

+

+/**

+ * This class will control the life-cycle of MBeans related to OSGi Compendium

+ * Services

+ * 

+ * 

+ */

+public class CompendiumController {

+

+    private AgentContext ac;

+

+    private ServiceListener sl;

+

+    private Vector svcs;

+

+    private MBeanServer server;

+

+    public CompendiumController(MBeanServer server, AgentContext ac) {

+        super();

+        this.ac = ac;

+        this.server = server;

+        svcs = new Vector();

+        svcs.add(ConfigurationAdmin.class.getName());

+        svcs.add(UserAdmin.class.getName());

+        svcs.add(LogService.class.getName());

+        sl = new ServiceListener() {

+            public void serviceChanged(ServiceEvent event) {

+                processServiceEvent(event);

+            }

+        };

+    }

+

+    public void initController() {

+        try {

+            if (ac.getConfigurationAdmin() != null) {

+                ConfigAdminManagerMBean ca = new ConfigAdminManager(ac);

+                server

+                        .registerMBean(ca, new ObjectName(

+                                ObjectNames.CM_SERVICE));

+            }

+            if (ac.getLogservice() != null) {

+                LogManagerMBean lm = new LogManager(ac);

+                server.registerMBean(lm,

+                        new ObjectName(ObjectNames.LOG_SERVICE));

+            }

+            if (ac.getUserAdmin() != null) {

+                UserManagerMBean um = new UserManager(ac);

+                server

+                        .registerMBean(um, new ObjectName(

+                                ObjectNames.UA_SERVICE));

+            }

+        } catch (InstanceAlreadyExistsException e) {

+            ac.error("Unexpected error", e);

+        } catch (MBeanRegistrationException e) {

+            ac.error("Unexpected error", e);

+        } catch (NotCompliantMBeanException e) {

+            ac.error("Unexpected error", e);

+        } catch (MalformedObjectNameException e) {

+            ac.error("Unexpected error", e);

+        } catch (NullPointerException e) {

+            ac.error("Unexpected error", e);

+        }

+        ac.getBundleContext().addServiceListener(sl);

+

+    }

+

+    public void dispose() {

+        ac.getBundleContext().removeServiceListener(sl);

+        try {

+            Iterator it = server.queryNames(

+                    new ObjectName(ObjectNames.COMPENDIUM + ":*"), null)

+                    .iterator();

+            while (it.hasNext())

+                server.unregisterMBean((ObjectName) it.next());

+

+        } catch (MalformedObjectNameException e) {

+            ac.error("Unexpected error", e);

+        } catch (NullPointerException e) {

+            ac.error("Unexpected error", e);

+        } catch (InstanceNotFoundException e) {

+            ac.error("Unexpected error", e);

+        } catch (MBeanRegistrationException e) {

+            ac.error("Unexpected error", e);

+        }

+    }

+

+    private void processServiceEvent(ServiceEvent event) {

+        String[] svs = (String[]) event.getServiceReference().getProperty(

+                Constants.OBJECTCLASS);

+        // Check if this event comes from an OSGi compendium service

+        for (int i = 0; i < svs.length; i++) {

+            if (svcs.contains(svs[i])) {

+                if (event.getType() == ServiceEvent.REGISTERED

+                        || event.getType() == ServiceEvent.UNREGISTERING)

+                    handleEvent(event.getServiceReference(), svs[i], event

+                            .getType());

+            }

+        }

+

+    }

+

+    private void handleEvent(ServiceReference serviceReference,

+            String iService, int eType) {

+        try {

+

+            if (iService.equals(ConfigurationAdmin.class.getName())) {

+                switch (eType) {

+                case ServiceEvent.REGISTERED:

+                    ConfigAdminManagerMBean ca = new ConfigAdminManager(ac);

+                    server.registerMBean(ca, new ObjectName(

+                            ObjectNames.CM_SERVICE));

+                    break;

+                case ServiceEvent.UNREGISTERING:

+                    server.unregisterMBean(new ObjectName(

+                            ObjectNames.CM_SERVICE));

+                    break;

+                default:

+                    break;

+                }

+            }

+

+            if (iService.equals(LogService.class.getName())) {

+                switch (eType) {

+                case ServiceEvent.REGISTERED:

+                    LogManagerMBean lm = new LogManager(ac);

+                    server.registerMBean(lm, new ObjectName(

+                            ObjectNames.LOG_SERVICE));

+                    break;

+                case ServiceEvent.UNREGISTERING:

+                    server.unregisterMBean(new ObjectName(

+                            ObjectNames.LOG_SERVICE));

+                    break;

+                default:

+                    break;

+                }

+            }

+

+            if (iService.equals(UserAdmin.class.getName())) {

+                switch (eType) {

+                case ServiceEvent.REGISTERED:

+                    UserManagerMBean um = new UserManager(ac);

+                    server.registerMBean(um, new ObjectName(

+                            ObjectNames.UA_SERVICE));

+                    break;

+                case ServiceEvent.UNREGISTERING:

+                    server.unregisterMBean(new ObjectName(

+                            ObjectNames.UA_SERVICE));

+                    break;

+                default:

+                    break;

+                }

+            }

+        } catch (InstanceAlreadyExistsException e) {

+            ac.error("Unexpected error", e);

+        } catch (MBeanRegistrationException e) {

+            ac.error("Unexpected error", e);

+        } catch (NotCompliantMBeanException e) {

+            ac.error("Unexpected error", e);

+        } catch (MalformedObjectNameException e) {

+            ac.error("Unexpected error", e);

+        } catch (NullPointerException e) {

+            ac.error("Unexpected error", e);

+        } catch (InstanceNotFoundException e) {

+            ac.error("Unexpected error", e);

+        }

+    }

+

+}

diff --git a/org.apache.felix.jmood/src/main/java/org/apache/felix/jmood/compendium/ConfigAdminManager.java b/org.apache.felix.jmood/src/main/java/org/apache/felix/jmood/compendium/ConfigAdminManager.java
new file mode 100644
index 0000000..2a01db4
--- /dev/null
+++ b/org.apache.felix.jmood/src/main/java/org/apache/felix/jmood/compendium/ConfigAdminManager.java
@@ -0,0 +1,357 @@
+/*

+ *   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.jmood.compendium;

+import java.io.IOException;

+import java.math.BigDecimal;

+import java.math.BigInteger;

+import java.util.Dictionary;

+import java.util.Enumeration;

+import java.util.Iterator;

+import java.util.Set;

+

+import javax.management.InstanceNotFoundException;

+import javax.management.MBeanRegistration;

+import javax.management.MBeanRegistrationException;

+import javax.management.MBeanServer;

+import javax.management.MalformedObjectNameException;

+import javax.management.NotificationBroadcasterSupport;

+import javax.management.ObjectName;

+

+import org.apache.felix.jmood.AgentContext;

+import org.apache.felix.jmood.utils.ObjectNames;

+import org.osgi.service.cm.Configuration;

+import org.osgi.service.cm.ConfigurationAdmin;

+

+//import es.upm.dit.osgi.management.agent.AgentConstants;

+/**

+ * This is the main class of the config admin module. As such, it is responsible for controlling all the issues related to it. This class implements

+ * the ConfigAdminManagerMXBean which defines its management interface. It creates a ConfigurationDelegate object for each available 

+ * Configuration  object.

+ *

+ */

+public class ConfigAdminManager extends NotificationBroadcasterSupport

+	implements MBeanRegistration, ConfigAdminManagerMBean{

+	/*NOTE: The spec says that ConfigurationException's should be used by management systems

+	 * in order to inform a human manager in a suitable way. However, this is not possible unless we implement the service

+	 * because nowhere in the spec is there a way of accesing those exceptions (unless the implementation of the cm chooses to log the exception, which is not even suggested in the spec) 

+	*/

+	private MBeanServer server;

+    private AgentContext ac;

+    private ConfigurationAdmin cadmin;

+    public ConfigAdminManager(AgentContext ac) {

+        this.ac=ac;

+

+    }

+	/** 

+	 * This is called before the module is loaded. It initializes the module. 

+	 * @see javax.management.MBeanRegistration#preRegister(javax.management.MBeanServer, javax.management.ObjectName)

+	 */

+	public ObjectName preRegister(MBeanServer server, ObjectName name)

+		throws Exception {

+		this.server = server;

+		return name;

+	}

+

+	/** 

+	 * @see javax.management.MBeanRegistration#postRegister(java.lang.Boolean)

+	 */

+	public void postRegister(Boolean registrationDone) {}

+	/**

+	 * @see javax.management.MBeanRegistration#preDeregister()

+	 */

+	public void preDeregister() throws Exception {

+		//Remove the service

+		//and remove all mbeans from this module...

+        unregisterMBeans();

+        }

+	/**

+	 * @see javax.management.MBeanRegistration#postDeregister()

+	 */

+	public void postDeregister() {}

+

+	/**

+	 * @see org.apache.felix.jmood.compendium.ConfigAdminManagerMBean#listConfigurations(java.lang.String)

+	 */

+

+	public String[] listConfigurations(String filter) throws Exception {

+		ConfigurationAdmin cad=ac.getConfigurationAdmin();

+		Configuration[] confs = null;

+		if (cad!= null) {

+			confs = cad.listConfigurations(filter);

+            refresh();

+			if (confs == null)

+				return null;

+		}

+		String[] result = new String[confs.length];

+		for (int i = 0; i < confs.length; i++)

+			result[i] = this.getObjectName(confs[i]);

+		return result;

+	}

+

+	/**

+	 * @see org.apache.felix.jmood.compendium.ConfigAdminManagerMBean#getConfiguration(java.lang.String)

+	 */

+	public String getConfiguration(String pid) throws Exception {

+        //FIXME this should not be invoked

+        //if created, the configuration is attached to the management agent's location

+		ac.debug("ConfigAdmin, getting config for pid: "+pid);

+		if (pid.contains(":")) throw new IllegalArgumentException("pid not compliant with jmx. Please remove ':' from the pid");

+		ConfigurationAdmin cad=ac.getConfigurationAdmin();

+		if (cad != null) {

+			Configuration config = cad.getConfiguration(pid);

+			refresh();

+			return this.getObjectName(config);

+		

+		} else

+			return null;

+	}

+

+	/**

+	 *  This method gets a configuration object related to a pid and a bundle location

+	 * @param pid Persistent ID

+	 * @param location Bundle location of the service 

+	 * @see org.apache.felix.jmood.compendium.ConfigAdminManagerMBean#getConfiguration(java.lang.String, java.lang.String)

+	 */

+	public String getConfiguration(String pid, String location)

+		throws Exception {

+		//":" is reserved in objectnames, as a work around we do not permit pids containing it

+			if (pid.contains(":")) throw new IllegalArgumentException("pid not compliant with jmx. Please remove ':' from the pid");

+			ConfigurationAdmin cad=ac.getConfigurationAdmin();

+		if (cad != null) {

+			Configuration config = cad.getConfiguration(pid, location);

+			refresh();

+			return this.getObjectName(config);

+		} else

+			return null;

+	}

+	/**

+	 * @see org.apache.felix.jmood.compendium.ConfigAdminManagerMBean#createFactoryConfiguration(java.lang.String)

+	 */

+	public String createFactoryConfiguration(String pid) throws Exception {

+		ConfigurationAdmin cad=ac.getConfigurationAdmin();

+		if (cad != null) {

+			Configuration conf = cad.createFactoryConfiguration(pid);

+			refresh();

+			return this.getObjectName(conf);

+		} else

+			return null;

+	}

+

+	/**

+	 * @see org.apache.felix.jmood.compendium.ConfigAdminManagerMBean#createFactoryConfiguration(java.lang.String, java.lang.String)

+	 */

+	public String createFactoryConfiguration(String pid, String location)

+		throws Exception {

+		ConfigurationAdmin cad=ac.getConfigurationAdmin();

+		if (cad != null) {

+			Configuration conf = cad.createFactoryConfiguration(pid, location);

+			refresh();

+			return this.getObjectName(conf);

+		} else

+			return null;

+	}

+	/** 

+	 *  Delete the configurations identified by the LDAP filter

+	 * @param filter LDAP String representing the configurations that want to be deleted 

+	 * @see org.apache.felix.jmood.compendium.ConfigAdminManagerMBean#deleteConfigurations(java.lang.String)

+	 */

+	public void deleteConfigurations(String filter) throws Exception {

+		ConfigurationAdmin cad=ac.getConfigurationAdmin();

+		Configuration[] confs = null;

+		if (cad!= null) {

+			confs = cad.listConfigurations(filter);

+		}

+		if (confs != null)

+			for (int i = 0; i < confs.length; i++) {

+				confs[i].delete();

+			}

+		refresh();

+	}

+

+	/**

+	 * Removes a property from all the configurations selected by an LDAP expression 

+	 * @see org.apache.felix.jmood.compendium.ConfigAdminManagerMBean#removePropertyFromConfigurations(java.lang.String, java.lang.String)

+	 */

+	public void removePropertyFromConfigurations(String filter, String name)

+		throws Exception {

+		ConfigurationAdmin cad=ac.getConfigurationAdmin();

+		Configuration[] confs = null;

+		if (cad != null) {

+			confs = cad.listConfigurations(filter);

+		}

+		if (confs != null)

+			for (int i = 0; i < confs.length; i++) {

+				Dictionary dic = confs[i].getProperties();

+				Enumeration keys = dic.keys();

+				while (keys.hasMoreElements()) {

+					String key = (String) keys.nextElement();

+					if (key.equals(name)) {

+						dic.remove(key);

+						try {

+							confs[i].update(dic);

+						} catch (IOException e) {

+						    ac.error("Unexpected exception", (Exception)e);

+						}

+					}

+				}

+			}

+	}

+

+	/** 

+	 * Updates or adds a property to configurations selected by an LDAP expression

+	 * Arrays and vectors not supported

+	 * @see org.apache.felix.jmood.compendium.ConfigAdminManagerMBean#addPropertyToConfigurations(java.lang.String, java.lang.String, java.lang.String, java.lang.String)

+	 */

+	public void addPropertyToConfigurations(

+		String filter,

+		String name,

+		String value,

+		String type)

+		throws Exception {

+		if (isValidType(type)) {

+			ConfigurationAdmin cad=ac.getConfigurationAdmin();

+			Configuration[] confs = null;

+			if (cad != null) {

+				confs = cad.listConfigurations(filter);

+			}

+			if (confs != null)

+				for (int i = 0; i < confs.length; i++) {

+					Dictionary dic = confs[i].getProperties();

+					dic.put(name, castValueToType(type, value));

+					try {

+						confs[i].update(dic);

+					} catch (IOException e) {

+                        ac.error("Unexpected exception", (Exception)e);

+					}

+				}

+		}

+	}

+

+	/**

+	 *  

+	 * Validate that the value type is supported

+	 * @param type

+	 */

+	protected static boolean isValidType(String type) {

+		String[] validTypes =

+			{

+				"String",

+				"Integer",

+				"Long",

+				"Float",

+				"Double",

+				"Byte",

+				"Short",

+				"Character",

+				"Boolean",

+				"BigInteger",

+				"BigDecimal" };

+		for (int i = 0; i < validTypes.length; i++) {

+			if (validTypes[i].equalsIgnoreCase(type))

+				return true;

+		}

+		return false;

+	}

+	protected static Object castValueToType(String type, String value) {

+		value = value.equals("") ? null : value;

+		if (type.equals("String")) {

+			return value == null ? new String() : new String(value);

+		} else if (type.equals("Integer")) {

+			return value == null ? new Integer(0) : new Integer(value);

+		} else if (type.equals("Long")) {

+			return value == null ? new Long(0) : new Long(value);

+		} else if (type.equals("Float")) {

+			return value == null ? new Float(0) : new Float(value);

+		} else if (type.equals("Double")) {

+			return value == null ? new Double(0) : new Double(value);

+		} else if (type.equals("Byte")) {

+			return value == null ? new Byte("0") : new Byte(value);

+		} else if (type.equals("Short")) {

+			return value == null ? new Short("0") : new Short(value);

+		} else if (type.equals("BigInteger")) {

+			return value == null ? new BigInteger("0") : new BigInteger(value);

+		} else if (type.equals("BigDecimal")) {

+			return value == null ? new BigDecimal(0) : new BigDecimal(value);

+		} else if (type.equals("Character")) {

+			return value == null

+				? new Character('a')

+				: new Character(value.charAt(0));

+		} else if (type.equals("Boolean")) {

+			return value == null ? new Boolean(false) : new Boolean(value);

+		} else {

+			// Unsupported type

+			return null;

+		}

+	}

+    private void registerMBeans() throws Exception{

+        ConfigurationAdmin cad=ac.getConfigurationAdmin();

+        if (cad==null) {

+            ac.debug("could not add any conf mbean, conf admin not available");

+            return;

+        }

+            ac.debug("creating mbeans for existing config objects");

+            Configuration[] confs = null;

+            //confs contains the new config objects

+            //The old ones are in configObjects, whose key is the object name.

+            confs = cad.listConfigurations(null);

+            if (confs!=null) {

+                ac.debug("Existing conf objects: ");

+            for(int i=0;i<confs.length;i++) {

+                ac.debug("\t"+confs[i].getPid());

+                //now we add the new ones 

+                String oname = this.getObjectName(confs[i]);

+                server.registerMBean(

+                        new ConfigurationDelegate(confs[i], ac),

+                        new ObjectName(oname));

+                ac.debug("Succesfully registered? "+!server.queryMBeans(new ObjectName(oname), null).isEmpty());

+                }

+            }

+                

+    }

+	public synchronized void refresh() throws Exception {

+        //Extremely innefficient but KISS

+        unregisterMBeans();

+        registerMBeans();

+	}

+    public boolean isAvailable() {

+        return ac.getConfigurationAdmin()==null?false:true;

+    }

+    private void unregisterMBeans() throws MalformedObjectNameException, NullPointerException, InstanceNotFoundException, MBeanRegistrationException{

+        Set set =

+            server.queryNames(

+                new ObjectName(ObjectNames.ALL_CM_OBJECT),

+                null);

+        Iterator it = set.iterator();

+        while (it.hasNext()) {

+            ObjectName oname=(ObjectName) it.next();

+            ac.debug("Unregistering config mbean: "+oname);

+            server.unregisterMBean(oname);

+        }

+    }

+

+    private String getObjectName(Configuration configuration) {

+		StringBuffer posfix = new StringBuffer();

+		posfix.append("pid=" + configuration.getPid());

+		if (configuration.getFactoryPid() != null)

+			posfix.append(

+				",isFactory=true,FactoryPid=" + configuration.getFactoryPid());

+		else

+			posfix.append(",isFactory=false");

+		String oname = ObjectNames.CM_OBJECT + posfix.toString();

+		return oname;

+	}

+}

diff --git a/org.apache.felix.jmood/src/main/java/org/apache/felix/jmood/compendium/ConfigAdminManagerMBean.java b/org.apache.felix.jmood/src/main/java/org/apache/felix/jmood/compendium/ConfigAdminManagerMBean.java
new file mode 100644
index 0000000..f4a2bf3
--- /dev/null
+++ b/org.apache.felix.jmood/src/main/java/org/apache/felix/jmood/compendium/ConfigAdminManagerMBean.java
@@ -0,0 +1,77 @@
+/*

+ *   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.jmood.compendium;

+

+

+public interface ConfigAdminManagerMBean {

+	/**

+	 * @see org.apache.felix.jmood.compendium.ConfigAdminManagerMBean#listConfigurations(java.lang.String)

+	 */

+	public abstract String[] listConfigurations(String filter)

+		throws Exception;

+	/**

+	 * @see org.apache.felix.jmood.compendium.ConfigAdminManagerMBean#getConfiguration(java.lang.String)

+	 */

+	public abstract String getConfiguration(String pid) throws Exception;

+	/**

+	 *  This method gets a configuration object related to a pid and a bundle location

+	 * @param pid Persistent ID

+	 * @param location Bundle location of the service 

+	 * @see org.apache.felix.jmood.compendium.ConfigAdminManagerMBean#getConfiguration(java.lang.String, java.lang.String)

+	 */

+	public abstract String getConfiguration(String pid, String location)

+		throws Exception;

+	/**

+	 * @see org.apache.felix.jmood.compendium.ConfigAdminManagerMBean#createFactoryConfiguration(java.lang.String)

+	 */

+	public abstract String createFactoryConfiguration(String pid)

+		throws Exception;

+	/**

+	 * @see org.apache.felix.jmood.compendium.ConfigAdminManagerMBean#createFactoryConfiguration(java.lang.String, java.lang.String)

+	 */

+	public abstract String createFactoryConfiguration(

+		String pid,

+		String location)

+		throws Exception;

+	/** 

+	 *  Delete the configurations identified by the LDAP filter

+	 * @param filter LDAP String representing the configurations that want to be deleted 

+	 * @see org.apache.felix.jmood.compendium.ConfigAdminManagerMBean#deleteConfigurations(java.lang.String)

+	 */

+	public abstract void deleteConfigurations(String filter) throws Exception;

+	/**

+	 * Removes a property from all the configurations selected by an LDAP expression 

+	 * @see org.apache.felix.jmood.compendium.ConfigAdminManagerMBean#removePropertyFromConfigurations(java.lang.String, java.lang.String)

+	 */

+	public abstract void removePropertyFromConfigurations(

+		String filter,

+		String name)

+		throws Exception;

+	/** 

+	 * Updates or adds a property to configurations selected by an LDAP expression

+	 * Arrays and vectors not supported

+	 * @see org.apache.felix.jmood.compendium.ConfigAdminManagerMBean#addPropertyToConfigurations(java.lang.String, java.lang.String, java.lang.String, java.lang.String)

+	 */

+	public abstract void addPropertyToConfigurations(

+		String filter,

+		String name,

+		String value,

+		String type)

+		throws Exception;

+	public abstract void refresh() throws Exception;

+    public abstract boolean isAvailable() throws Exception;

+}
\ No newline at end of file
diff --git a/org.apache.felix.jmood/src/main/java/org/apache/felix/jmood/compendium/ConfigurationDelegate.java b/org.apache.felix.jmood/src/main/java/org/apache/felix/jmood/compendium/ConfigurationDelegate.java
new file mode 100644
index 0000000..02c2b3f
--- /dev/null
+++ b/org.apache.felix.jmood/src/main/java/org/apache/felix/jmood/compendium/ConfigurationDelegate.java
@@ -0,0 +1,170 @@
+/*

+ *   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.jmood.compendium;

+

+import java.io.IOException;

+import java.util.Dictionary;

+import java.util.Enumeration;

+import java.util.Hashtable;

+

+import javax.management.MBeanRegistration;

+import javax.management.MBeanServer;

+import javax.management.ObjectName;

+

+import org.apache.felix.jmood.AgentContext;

+import org.osgi.service.cm.Configuration;

+

+

+public class ConfigurationDelegate implements  MBeanRegistration, ConfigurationDelegateMBean {

+	private Configuration configuration;

+	private MBeanServer server;

+	private ObjectName oname;

+    private AgentContext ac;

+	public ConfigurationDelegate(Configuration configuration, AgentContext ac){

+		this.configuration=configuration;

+        this.ac=ac;

+	}

+

+	/**

+	 * @see org.osgi.service.cm.Configuration#getPid()

+	 */

+	public String getPid() {

+

+		return configuration.getPid();

+	}

+

+	/**

+	 * @see org.osgi.service.cm.Configuration#getProperties()

+	 */

+	public Hashtable getProperties() {

+		Dictionary dic=configuration.getProperties();

+		Enumeration keys=dic.keys();

+		Hashtable properties=new Hashtable();

+		while(keys.hasMoreElements()) {

+			Object key=keys.nextElement();

+			properties.put(key, dic.get(key));

+		}

+		return properties;

+	}

+

+	/**

+	 * @see org.osgi.service.cm.Configuration#update(java.util.Dictionary)

+	 *hashtable is a dictionary!

+	 */

+	public void update(Hashtable properties) throws IOException {

+		configuration.update(properties);

+	}

+

+	/**

+	 * @see org.osgi.service.cm.Configuration#delete()

+	 */

+	public void delete() throws Exception {

+		server.unregisterMBean(oname);

+		configuration.delete();

+	}

+

+	/**

+	 * @see org.osgi.service.cm.Configuration#getFactoryPid()

+	 */

+	public String getFactoryPid() {

+		return configuration.getFactoryPid();

+	}

+

+	/**

+	 * @see org.osgi.service.cm.Configuration#update()

+	 */

+	public void update() throws IOException {

+		configuration.update();

+	}

+

+	/**

+	 * @see org.osgi.service.cm.Configuration#setBundleLocation(java.lang.String)

+	 */

+	public void setBundleLocation(String bundleLocation) {

+		configuration.setBundleLocation(bundleLocation);

+	}

+

+	/**

+	 * @see org.osgi.service.cm.Configuration#getBundleLocation()

+	 */

+	public String getBundleLocation() {

+		return configuration.getBundleLocation();

+	}

+	/**

+	 * @see javax.management.MBeanRegistration#postDeregister()

+	 */

+	public void postDeregister() {

+	}

+

+	/**

+	 * @see javax.management.MBeanRegistration#postRegister(java.lang.Boolean)

+	 */

+	public void postRegister(Boolean registrationDone) {

+	}

+

+	/**

+	 * @see javax.management.MBeanRegistration#preDeregister()

+	 */

+	public void preDeregister() throws Exception {

+	}

+

+	/**

+	 * @see javax.management.MBeanRegistration#preRegister(javax.management.MBeanServer, javax.management.ObjectName)

+	 */

+	public ObjectName preRegister(MBeanServer server, ObjectName name)

+		throws Exception {

+			this.oname=name;

+			this.server=server;

+		return name;

+	}

+

+	/**

+	 * @see org.apache.felix.jmood.compendium.ConfigurationDelegateMBean#getProperty(java.lang.String)

+	 */

+	public String getProperty(String key) throws Exception {

+		Object result= configuration.getProperties().get(key);

+		if (result==null) return null;

+		if (result instanceof String) return (String) result;

+		else return result.toString();

+	}

+

+	/**

+	 * @see org.apache.felix.jmood.compendium.ConfigurationDelegateMBean#setProperty(java.lang.String, java.lang.String)

+	 */

+	public void setProperty(String key, String value, String type) throws Exception {

+		if (ConfigAdminManager.isValidType(type)) {

+					Dictionary dic = configuration.getProperties();

+					dic.put(key, ConfigAdminManager.castValueToType(type, value));

+					try {

+						configuration.update(dic);

+					} catch (IOException e) {

+                        ac.error("Unexpected exception", (Exception)e);

+					}

+				}

+	}

+	public void deleteProperty(String key) throws Exception{

+				Dictionary dic = configuration.getProperties();

+				Enumeration keys = dic.keys();

+				while (keys.hasMoreElements()) {

+					String k = (String) keys.nextElement();

+					if (k.equals(key)) {

+						dic.remove(k);

+							configuration.update(dic);

+					}

+				}

+			}

+}
\ No newline at end of file
diff --git a/org.apache.felix.jmood/src/main/java/org/apache/felix/jmood/compendium/ConfigurationDelegateMBean.java b/org.apache.felix.jmood/src/main/java/org/apache/felix/jmood/compendium/ConfigurationDelegateMBean.java
new file mode 100644
index 0000000..8724cce
--- /dev/null
+++ b/org.apache.felix.jmood/src/main/java/org/apache/felix/jmood/compendium/ConfigurationDelegateMBean.java
@@ -0,0 +1,64 @@
+/*

+ *   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.jmood.compendium;

+import java.util.Hashtable;

+

+public interface ConfigurationDelegateMBean {

+	/* (no Javadoc)

+	 * @see org.osgi.service.cm.Configuration#getPid()

+	 */

+	public abstract String getPid() throws Exception;

+	/* (no Javadoc)

+	 * @see org.osgi.service.cm.Configuration#getProperties()

+	 */

+	public abstract Hashtable getProperties() throws Exception;

+	/* (no Javadoc)

+	 * @see org.osgi.service.cm.Configuration#update(java.util.Dictionary)

+	 *hashtable is a dictionary!

+	 */

+	public abstract void update(Hashtable properties) throws Exception;

+	/* (no Javadoc)

+	 * @see org.osgi.service.cm.Configuration#delete()

+	 */

+	public abstract void delete() throws Exception;

+	/* (no Javadoc)

+	 * @see org.osgi.service.cm.Configuration#getFactoryPid()

+	 */

+	public abstract String getFactoryPid() throws Exception;

+	/* (no Javadoc)

+	 * @see org.osgi.service.cm.Configuration#update()

+	 */

+	public abstract void update() throws Exception;

+	/* (no Javadoc)

+	 * @see org.osgi.service.cm.Configuration#setBundleLocation(java.lang.String)

+	 */

+	public abstract void setBundleLocation(String bundleLocation) throws Exception;

+	/* (no Javadoc)

+	 * @see org.osgi.service.cm.Configuration#getBundleLocation()

+	 */

+	public abstract String getBundleLocation() throws Exception;

+	/* (no Javadoc)

+	 * @see org.apache.felix.jmood.modules.configadmin.ConfigurationDelegateMXBean#getProperty(java.lang.String)

+	 */

+	public abstract String getProperty(String key) throws Exception;

+	/* (no Javadoc)

+	 * @see org.apache.felix.jmood.modules.configadmin.ConfigurationDelegateMXBean#setProperty(java.lang.String, java.lang.String)

+	 */

+	public abstract void setProperty(String key, String value, String type)

+		throws Exception;

+	public abstract void deleteProperty(String key) throws Exception;

+}
\ No newline at end of file
diff --git a/org.apache.felix.jmood/src/main/java/org/apache/felix/jmood/compendium/LogManager.java b/org.apache.felix.jmood/src/main/java/org/apache/felix/jmood/compendium/LogManager.java
new file mode 100644
index 0000000..5e181ed
--- /dev/null
+++ b/org.apache.felix.jmood/src/main/java/org/apache/felix/jmood/compendium/LogManager.java
@@ -0,0 +1,227 @@
+/*

+ *   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.jmood.compendium;

+

+import java.util.*;

+import javax.management.*;

+import javax.management.openmbean.*;

+

+import org.apache.felix.jmood.AgentConstants;

+import org.apache.felix.jmood.AgentContext;

+import org.apache.felix.jmood.utils.*;

+import org.osgi.framework.*;

+import org.osgi.service.log.*;

+

+

+/**

+ * 

+ * This class enables remote management of

+ *         org.osgi.service.log.LogReaderService It enables the operator to read

+ *         the system log.

+ */

+// FUTURE WORK: limitations of Log manager: if the service appears or

+// disappears, and/or there ismore than one service available, correct

+// functioning is not guaranteed. A New manager should be branched for each

+// available log service, and info should be merged to expose it afterwards.

+// FUTURE WORK: Log Listener should be an anonymous class

+// FUTURE WORK: Add persistence to the log manager

+public class LogManager extends NotificationBroadcasterSupport implements

+        LogListener, MBeanRegistration, LogManagerMBean {

+    private LogReaderService logReader = null;

+

+    private ServiceReference[] refs;

+

+    private LogService log = null;

+

+    private String[][] Log;

+

+    private static final int DefaultLogLevel = 0;

+

+    private int LogLevel;

+

+    private Vector entryVector;

+

+    private static int sequenceNumber = 0;

+

+    private AgentContext ac;

+

+    private ServiceRegistration registration;

+

+    // FUTURE WORK: add persistence to sequence numbers

+    public LogManager(AgentContext ac) {

+        this.ac = ac;

+    }

+

+    public void setLogLevel(int level) {

+        // FUTURE WORK This setting only affects to the agent. Extend it to the

+        // service. This is implementation dependent.

+        this.LogLevel = level;

+    }

+

+    public int getLogLevel() {

+        return LogLevel;

+    }

+

+    public CompositeData[] getLog() {

+        if (entryVector == null) {

+            return null;

+        } else {

+            try {

+

+                CompositeData[] value = new CompositeData[entryVector.size()];

+                for (int i = 0; i < entryVector.size(); i++) {

+                    value[i] = OSGi2JMXCodec

+                            .encodeLogEntry((LogEntry) entryVector.elementAt(i));

+                }

+                return value;

+            } catch (Exception e) {

+                ac.error("Unexpected exception", e);

+                return null;

+            }

+        }

+

+    }

+

+    /**

+     * This method exposes the attribute LogFromReader for remote management.

+     * The main difference with the log attribute is that the later uses the

+     * level configuration specified by the log level attribute and as a

+     * drawback does not include log entries registered before the log manager

+     * was started.

+     * 

+     * @return

+     */

+    public String[] getLogMessages() {

+        if (entryVector == null)

+            return null;

+        String[] msgs = new String[entryVector.size()];

+        for (int i = 0; i < msgs.length; i++) {

+            LogEntry entry = (LogEntry) entryVector.elementAt(i);

+            msgs[i] = "BUNDLE " + entry.getBundle().getBundleId() + " ("

+                    + entry.getBundle().getLocation() + "): LEVEL="

+                    + this.getLevelAsString(entry.getLevel()) + "; MESSAGE="

+                    + entry.getMessage();

+        }

+        return msgs;

+

+    }

+

+    /**

+     * @see javax.management.MBeanRegistration#postDeregister()

+     * 

+     */

+    public void postDeregister() {

+    }

+

+    /**

+     * @see javax.management.MBeanRegistration#postRegister(java.lang.Boolean)

+     * @param registrationDone

+     */

+    public void postRegister(Boolean registrationDone) {

+    }

+

+    /**

+     * @see javax.management.MBeanRegistration#preDeregister()

+     * @throws java.lang.Exception

+     */

+    public void preDeregister() throws Exception {

+        registration.unregister();

+    }

+

+    /**

+     * @see javax.management.MBeanRegistration#preRegister(javax.management.MBeanServer,

+     *      javax.management.ObjectName)

+     * @param server

+     * @param name

+     * @return

+     * @throws java.lang.Exception

+     */

+    public ObjectName preRegister(MBeanServer server, ObjectName name) {

+        this.entryVector = new Vector();

+        this.LogLevel = DefaultLogLevel;

+        registration=ac.getBundleContext().registerService(LogListener.class.getName(), this, null);

+        return name;

+    }

+

+    /**

+     * @see org.osgi.service.log.LogListener#logged(org.osgi.service.log.LogEntry)

+     * @param arg0

+     */

+    public void logged(LogEntry entry) {

+        if (entry.getLevel() >= this.LogLevel) {

+            this.notifyLogEntry(entry);

+            entryVector.add(entry);

+        }

+

+    }

+

+    private void notifyLogEntry(LogEntry entry) {

+        // TEST: See if user data are correctly received. This we cannot do with

+        // MC4J

+        String Level = this.getLevelAsString(entry.getLevel());

+        try {

+            ObjectName source = new ObjectName(ObjectNames.LOG_SERVICE);

+            String message = "Log entry added: Bundle "

+                    + entry.getBundle().getLocation() + " with id "

+                    + entry.getBundle().getBundleId()

+                    + " has added a new log entry of level " + Level

+                    + ". The message is: " + entry.getMessage();

+            Notification notification = new Notification(

+                    AgentConstants.LOG_NOTIFICATION_TYPE, source,

+                    sequenceNumber++, message);

+            // User data is CompositeData with the info of the log entry

+

+            CompositeData userData = OSGi2JMXCodec.encodeLogEntry(entry);

+

+            // Before using composite data, we used a simple string array:

+            /*

+             * String[] userData = new String[4]; userData[0] =

+             * entry.getBundle().getLocation(); userData[1] = new

+             * Long(entry.getBundle().getBundleId()).toString(); userData[2] =

+             * Level; userData[3] = entry.getMessage();

+             */

+

+            notification.setUserData(userData);

+            sendNotification(notification);

+        } catch (Exception e) {

+            ac.error("Unexpected exception", e);

+        }

+    }

+

+    private String getLevelAsString(int level) {

+        String Level;

+        switch (level) {

+        case LogService.LOG_DEBUG:

+            Level = "DEBUG";

+            break;

+        case LogService.LOG_WARNING:

+            Level = "WARNING";

+            break;

+        case LogService.LOG_INFO:

+            Level = "INFO";

+            break;

+        case LogService.LOG_ERROR:

+            Level = "ERROR";

+            break;

+        default:

+            Level = "UserDefined: " + level;

+            break;

+        }

+        return Level;

+

+    }

+}

diff --git a/org.apache.felix.jmood/src/main/java/org/apache/felix/jmood/compendium/LogManagerMBean.java b/org.apache.felix.jmood/src/main/java/org/apache/felix/jmood/compendium/LogManagerMBean.java
new file mode 100644
index 0000000..cfdabc1
--- /dev/null
+++ b/org.apache.felix.jmood/src/main/java/org/apache/felix/jmood/compendium/LogManagerMBean.java
@@ -0,0 +1,32 @@
+/*

+ *   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.jmood.compendium;

+

+import javax.management.openmbean.CompositeData;

+

+public interface LogManagerMBean {

+	//FUTURE WORK: add persistence to sequence numbers

+	public abstract void setLogLevel(int level) throws Exception;

+	public abstract int getLogLevel() throws Exception;

+	public abstract CompositeData[] getLog() throws Exception;

+	/**

+	 * This method exposes the attribute LogFromReader for remote management. The main difference with the log attribute is that the later 

+	 * uses the level configuration specified by the log level attribute and as a drawback does not include log entries registered before the log manager was started.

+	 * @return

+	 */

+	public abstract String[] getLogMessages() throws Exception;

+}
\ No newline at end of file
diff --git a/org.apache.felix.jmood/src/main/java/org/apache/felix/jmood/compendium/UserManager.java b/org.apache.felix.jmood/src/main/java/org/apache/felix/jmood/compendium/UserManager.java
new file mode 100644
index 0000000..9ea2556
--- /dev/null
+++ b/org.apache.felix.jmood/src/main/java/org/apache/felix/jmood/compendium/UserManager.java
@@ -0,0 +1,482 @@
+/*

+ *   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.jmood.compendium;

+

+import java.util.Dictionary;

+import java.util.Enumeration;

+import java.util.Hashtable;

+import java.util.Vector;

+

+import javax.management.MBeanRegistration;

+import javax.management.MBeanServer;

+import javax.management.Notification;

+import javax.management.NotificationBroadcasterSupport;

+import javax.management.ObjectName;

+import javax.management.openmbean.CompositeData;

+

+import org.apache.felix.jmood.AgentConstants;

+import org.apache.felix.jmood.AgentContext;

+import org.apache.felix.jmood.utils.OSGi2JMXCodec;

+import org.apache.felix.jmood.utils.ObjectNames;

+import org.osgi.service.useradmin.Group;

+import org.osgi.service.useradmin.Role;

+import org.osgi.service.useradmin.User;

+import org.osgi.service.useradmin.UserAdminEvent;

+import org.osgi.service.useradmin.UserAdminListener;

+

+/**

+ * User manager for the gateway. This mbean provides access to the user admin

+ * functionality.

+ * 

+ * 

+ */

+public class UserManager extends NotificationBroadcasterSupport implements

+        MBeanRegistration, UserManagerMBean {

+    private AgentContext ac;

+

+    private UserManager um;

+

+    public UserManager(AgentContext ac) {

+        this.ac = ac;

+        this.um = this;

+    }

+

+    private static long sequenceNumber = 0;

+

+    /**

+     * Creates a role of the specified type, case insensitive, with the

+     * specified name

+     * 

+     * @param name

+     * @param type

+     * @throws Exception

+     */

+    public void createRole(String name, String type) throws Exception {

+        int t = -1;

+        if (type.equalsIgnoreCase(AgentConstants.GROUP))

+            t = Role.GROUP;

+        else if (type.equalsIgnoreCase(AgentConstants.USER))

+            t = Role.USER;

+        else

+            throw new Exception(

+                    "Incorrect type name. Valid names: User | Group. Case Insensitive");

+        try {

+            ac.getUserAdmin().createRole(name, t);

+        } catch (NullPointerException npe) {

+            ac.debug("UserAdmin not available. Could not create Role");

+        }

+    }

+

+    public CompositeData getRole(String name) throws Exception {

+        try {

+            return OSGi2JMXCodec.encodeRole(ac.getUserAdmin().getRole(name));

+        } catch (NullPointerException npe) {

+            ac.debug("UserAdmin not available. Could not get Role");

+            return null;

+        }

+    }

+

+    public CompositeData getGroup(String groupname) {

+        try {

+            Role group = ac.getUserAdmin().getRole(groupname);

+            if (group.getType() == Role.GROUP)

+                return OSGi2JMXCodec.encodeGroup((Group) group);

+            else

+                return null;

+

+        } catch (NullPointerException npe) {

+            ac.debug("UserAdmin not available. ");

+            return null;

+        } catch (Exception e) {

+            ac.error("unexpected exception", e);

+            return null;

+        }

+    }

+

+    public CompositeData getUser(String username) throws Exception {

+        try {

+            Role user = ac.getUserAdmin().getRole(username);

+            if (user.getType() == Role.USER)

+                return OSGi2JMXCodec.encodeUser((User) user);

+            else

+                return null;

+        } catch (NullPointerException npe) {

+            ac.debug("UserAdmin not available. ");

+            return null;

+        }

+

+    }

+

+    public CompositeData getAuthorization(String user) {

+        try {

+            return OSGi2JMXCodec.encodeAuthorization(ac.getUserAdmin()

+                    .getAuthorization((User) ac.getUserAdmin().getRole(user)));

+        } catch (Exception e) {

+            ac.error("unexpected exception", e);

+            return null;

+

+        }

+    }

+

+    public String[] getRoles(String filter) throws Exception {

+        try {

+            Role[] roles = ac.getUserAdmin().getRoles(filter);

+            String[] result = new String[roles.length];

+            for (int i = 0; i < roles.length; i++) {

+                result[i] = roles[i].getName();

+            }

+            return result;

+        } catch (NullPointerException npe) {

+            ac.debug("UserAdmin not available. ");

+            return null;

+        }

+

+    }

+

+    public String getUser(String key, String value) {

+        try {

+            return ac.getUserAdmin().getUser(key, value).getName();

+

+        } catch (NullPointerException npe) {

+            ac.debug("UserAdmin not available. ");

+            return null;

+        }

+    }

+

+    public boolean removeRole(String name) {

+        try {

+            return ac.getUserAdmin().removeRole(name);

+        } catch (NullPointerException npe) {

+            ac.debug("UserAdmin not available. ");

+            return false;

+        }

+    }

+

+    public String[] getRoles() throws Exception {

+        try {

+            Role[] roles = ac.getUserAdmin().getRoles(null);

+            String[] result = new String[roles.length];

+            for (int i = 0; i < roles.length; i++) {

+                result[i] = roles[i].getName();

+            }

+            return result;

+        } catch (NullPointerException npe) {

+            ac.debug("UserAdmin not available. ");

+            return null;

+        }

+    }

+

+    public String[] getGroups() throws Exception {

+        try {

+            Role[] roles = ac.getUserAdmin().getRoles(null);

+            Vector tmp = new Vector();

+            int j = 0;

+            for (int i = 0; i < roles.length; i++) {

+                if (roles[i].getType() == Role.GROUP) {

+                    j++;

+                    tmp.add(roles[i].getName());

+                }

+            }

+            if (j == 0)

+                return new String[0];

+            else {

+                String[] result = new String[j];

+                tmp.copyInto(result);

+                return result;

+            }

+        } catch (NullPointerException npe) {

+            ac.debug("UserAdmin not available. ");

+            return null;

+        }

+

+    }

+

+    public String[] getUsers() throws Exception {

+        try {

+            Role[] roles = ac.getUserAdmin().getRoles(null);

+            Vector tmp = new Vector();

+            int j = 0;

+            for (int i = 0; i < roles.length; i++) {

+                if (roles[i].getType() == Role.USER) {

+                    j++;

+                    tmp.add(roles[i].getName());

+                }

+            }

+            if (j == 0)

+                return new String[0];

+            else {

+                String[] result = new String[j];

+                tmp.copyInto(result);

+                return result;

+            }

+        } catch (NullPointerException npe) {

+            ac.debug("UserAdmin not available. ");

+            return null;

+        }

+

+    }

+

+    public String[] getMembers(String groupname) {

+        try {

+            Group group = (Group) ac.getUserAdmin().getRole(groupname);

+            Role[] members = group.getMembers();

+            if (members == null)

+                return null;

+            String[] names = new String[members.length];

+            for (int i = 0; i < members.length; i++) {

+                names[i] = members[i].getName();

+            }

+            return names;

+        } catch (NullPointerException npe) {

+            ac.debug("UserAdmin not available. ");

+            return null;

+        }

+    }

+

+    public String[] getRequiredMembers(String groupname) {

+        try {

+            Group group = (Group) ac.getUserAdmin().getRole(groupname);

+            Role[] members = group.getRequiredMembers();

+            if (members == null)

+                return null;

+            String[] names = new String[members.length];

+            for (int i = 0; i < members.length; i++) {

+                names[i] = members[i].getName();

+            }

+            return names;

+        } catch (NullPointerException npe) {

+            ac.debug("UserAdmin not available. ");

+            return null;

+        }

+

+    }

+

+    public boolean addMember(String groupname, String rolename) {

+        try {

+            Role group = ac.getUserAdmin().getRole(groupname);

+            Role role = ac.getUserAdmin().getRole(rolename);

+            if (!(group.getType() == Role.GROUP))

+                return false;

+            return ((Group) group).addMember(role);

+        } catch (NullPointerException npe) {

+            ac.debug("UserAdmin not available. ");

+            return false;

+        }

+    }

+

+    public boolean addRequiredMember(String groupname, String rolename) {

+        try {

+            Role group = ac.getUserAdmin().getRole(groupname);

+            Role role = ac.getUserAdmin().getRole(rolename);

+            if (!(group.getType() == Role.GROUP))

+                return false;

+            return ((Group) group).addRequiredMember(role);

+        } catch (NullPointerException npe) {

+            ac.debug("UserAdmin not available. ");

+            return false;

+        }

+

+    }

+

+    public boolean removeMember(String groupname, String rolename) {

+        try {

+            Role group = ac.getUserAdmin().getRole(groupname);

+            Role role = ac.getUserAdmin().getRole(rolename);

+            if (!(group.getType() == Role.GROUP))

+                return false;

+            return ((Group) group).removeMember(role);

+        } catch (NullPointerException npe) {

+            ac.debug("UserAdmin not available. ");

+            return false;

+        }

+    }

+

+    public String[] getImpliedRoles(String username) throws Exception {

+        try {

+            Role role = ac.getUserAdmin().getRole(username);

+            if (role.getType() == Role.USER && role instanceof User) {

+                return ac.getUserAdmin().getAuthorization((User) role)

+                        .getRoles();

+            } else

+                return null;

+        } catch (NullPointerException npe) {

+            ac.debug("UserAdmin not available. ");

+            return null;

+        }

+    }

+

+    public void addProperty(String key, Object value, String rolename)

+            throws IllegalArgumentException {

+        try {

+            if (value instanceof Byte[]) {

+                Byte[] ByteValue = (Byte[]) value;

+                byte[] primitive = new byte[ByteValue.length];

+                for (int i = 0; i < ByteValue.length; i++)

+                    primitive[i] = ByteValue[i].byteValue();

+                value = primitive;

+            } else if (!(value instanceof String) && !(value instanceof byte[]))

+                throw new IllegalArgumentException(

+                        "Credentials can only be byte[] or String");

+            Role role = ac.getUserAdmin().getRole(rolename);

+            role.getProperties().put(key, value);

+        } catch (NullPointerException npe) {

+            ac.debug("UserAdmin not available. ");

+        }

+

+    }

+

+    public void removeProperty(String key, String rolename) {

+        try {

+            Role role = ac.getUserAdmin().getRole(rolename);

+            role.getProperties().remove(key);

+        } catch (NullPointerException npe) {

+            ac.debug("UserAdmin not available. ");

+        }

+

+    }

+

+    public void addCredential(String key, Object value, String username)

+            throws IllegalArgumentException {

+        try {

+            if (value instanceof Byte[]) {

+                Byte[] ByteValue = (Byte[]) value;

+                byte[] primitive = new byte[ByteValue.length];

+                for (int i = 0; i < ByteValue.length; i++)

+                    primitive[i] = ByteValue[i].byteValue();

+                value = primitive;

+            } else if (!(value instanceof String) && !(value instanceof byte[]))

+                throw new IllegalArgumentException(

+                        "Credentials can only be byte[] or String");

+            User user = (User) ac.getUserAdmin().getRole(username);

+            user.getCredentials().put(key, value);

+        } catch (NullPointerException npe) {

+            ac.debug("UserAdmin not available. ");

+        }

+

+    }

+

+    public void removeCredential(String key, String username) {

+        try {

+            User user = (User) ac.getUserAdmin().getRole(username);

+            user.getCredentials().remove(key);

+        } catch (NullPointerException npe) {

+            ac.debug("UserAdmin not available. ");

+        } catch (Exception e) {

+            ac.error("unexpected exception", e);

+        }

+    }

+

+    public Hashtable getProperties(String rolename) {

+        try {

+            Role role = ac.getUserAdmin().getRole(rolename);

+            Dictionary dic = role.getProperties();

+            Hashtable props = new Hashtable();

+            Enumeration keys = dic.keys();

+            while (keys.hasMoreElements()) {

+                Object key = keys.nextElement();

+                props.put(key, dic.get(key));

+            }

+            return props;

+        } catch (NullPointerException npe) {

+            ac.debug("UserAdmin not available. ");

+            return null;

+        }

+    }

+

+    public Hashtable getCredentials(String username) {

+        try {

+            User user = (User) ac.getUserAdmin().getRole(username);

+            Dictionary dic = user.getCredentials();

+            Hashtable credentials = new Hashtable();

+            Enumeration keys = dic.keys();

+            while (keys.hasMoreElements()) {

+                Object key = keys.nextElement();

+                credentials.put(key, dic.get(key));

+            }

+            return credentials;

+        } catch (NullPointerException npe) {

+            ac.debug("UserAdmin not available. ");

+            return null;

+        }

+

+    }

+

+    // /////////////////////MBEANREGISTRATION

+    // METHODS///////////////////////////////////////////////////

+    public void postDeregister() {

+    }

+

+    public void postRegister(Boolean registrationDone) {

+    }

+

+    public void preDeregister() throws Exception {

+    }

+

+    /**

+     * @see javax.management.MBeanRegistration#preRegister(javax.management.MBeanServer,

+     *      javax.management.ObjectName)

+     * @param server

+     * @param name

+     * @return

+     * @throws java.lang.Exception

+     */

+    public ObjectName preRegister(MBeanServer server, ObjectName name)

+            throws Exception {

+        ac.getBundleContext().registerService(

+                UserAdminListener.class.getName(), new UserAdminListener() {

+                    public void roleChanged(UserAdminEvent e) {

+                        um.notifyUserAdminEvent(e);

+                    }

+                }, null);

+        try {

+            ac.getUserAdmin().removeRole(AgentConstants.USER);

+        } catch (NullPointerException npe) {

+            ac.debug("UserAdmin not available. ");

+        }

+        return name;

+

+    }

+

+    // ///////PRIVATE METHODS//////////////////////////

+    private void notifyUserAdminEvent(UserAdminEvent event) {

+        String typedesc = null;

+        switch (event.getType()) {

+        case UserAdminEvent.ROLE_CREATED:

+            typedesc = "created";

+            break;

+        case UserAdminEvent.ROLE_CHANGED:

+            typedesc = "changed";

+            break;

+        case UserAdminEvent.ROLE_REMOVED:

+            typedesc = "removed";

+            break;

+        }

+        try {

+            ObjectName source = new ObjectName(ObjectNames.UA_SERVICE);

+            String message = "User Admin event: Role "

+                    + event.getRole().getName() + typedesc;

+            Notification notification = new Notification(

+                    AgentConstants.USER_ADMIN_NOTIFICATION_TYPE, source,

+                    sequenceNumber++, message);

+            CompositeData userData = OSGi2JMXCodec.encodeUserAdminEvent(event);

+            notification.setUserData(userData);

+            sendNotification(notification);

+        } catch (Exception e) {

+            ac.error("Unexpected exception", e);

+        }

+    }

+}

diff --git a/org.apache.felix.jmood/src/main/java/org/apache/felix/jmood/compendium/UserManagerMBean.java b/org.apache.felix.jmood/src/main/java/org/apache/felix/jmood/compendium/UserManagerMBean.java
new file mode 100644
index 0000000..910fb4f
--- /dev/null
+++ b/org.apache.felix.jmood/src/main/java/org/apache/felix/jmood/compendium/UserManagerMBean.java
@@ -0,0 +1,55 @@
+/*

+ *   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.jmood.compendium;

+

+import java.util.Hashtable;

+

+import javax.management.openmbean.CompositeData;

+

+public interface UserManagerMBean {

+	/**

+	 * Creates a role of the specified type, case insensitive, with the specified name

+	 * @param name

+	 * @param type

+	 * @throws Exception

+	 */

+	public abstract void createRole(String name, String type) throws Exception;

+	public abstract CompositeData getRole(String name) throws Exception;

+	public abstract CompositeData getGroup(String groupname) throws Exception;

+	public abstract CompositeData getUser(String username) throws Exception;

+	public abstract CompositeData getAuthorization(String user) throws Exception;

+	public abstract String[] getRoles(String filter) throws Exception;

+	public abstract String getUser(String key, String value) throws Exception;

+	public abstract boolean removeRole(String name) throws Exception;

+	public abstract String[] getRoles() throws Exception;

+	public abstract String[] getGroups() throws Exception;

+	public abstract String[] getUsers() throws Exception;

+	public abstract String[] getMembers(String groupname) throws Exception;

+	public abstract String[] getRequiredMembers(String groupname) throws Exception;

+	public abstract boolean addMember(String groupname, String rolename) throws Exception;

+	public abstract boolean addRequiredMember(

+		String groupname,

+		String rolename) throws Exception;

+	public abstract boolean removeMember(String groupname, String rolename) throws Exception;

+	public abstract String[] getImpliedRoles(String username) throws Exception;

+	public abstract void addProperty(String key, Object value, String rolename) throws Exception;

+	public abstract void removeProperty(String key, String rolename) throws Exception;

+	public abstract void addCredential(String key,Object value, String username) throws Exception;

+	public abstract void removeCredential(String key, String username) throws Exception;

+	public abstract Hashtable getProperties(String rolename) throws Exception;

+	public abstract Hashtable getCredentials(String username) throws Exception;

+}
\ No newline at end of file
diff --git a/org.apache.felix.jmood/src/main/java/org/apache/felix/jmood/core/BundleNotAvailableException.java b/org.apache.felix.jmood/src/main/java/org/apache/felix/jmood/core/BundleNotAvailableException.java
new file mode 100644
index 0000000..06e9ec5
--- /dev/null
+++ b/org.apache.felix.jmood/src/main/java/org/apache/felix/jmood/core/BundleNotAvailableException.java
@@ -0,0 +1,42 @@
+/*

+ *   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.jmood.core;

+

+public class BundleNotAvailableException extends Exception {

+

+    public BundleNotAvailableException() {

+        super();

+        // TODO Auto-generated constructor stub

+    }

+

+    public BundleNotAvailableException(String message) {

+        super(message);

+        // TODO Auto-generated constructor stub

+    }

+

+    public BundleNotAvailableException(String message, Throwable cause) {

+        super(message, cause);

+        // TODO Auto-generated constructor stub

+    }

+

+    public BundleNotAvailableException(Throwable cause) {

+        super(cause);

+        // TODO Auto-generated constructor stub

+    }

+

+}

diff --git a/org.apache.felix.jmood/src/main/java/org/apache/felix/jmood/core/CoreController.java b/org.apache.felix.jmood/src/main/java/org/apache/felix/jmood/core/CoreController.java
new file mode 100644
index 0000000..af81b1b
--- /dev/null
+++ b/org.apache.felix.jmood/src/main/java/org/apache/felix/jmood/core/CoreController.java
@@ -0,0 +1,341 @@
+/*

+ *   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.jmood.core;

+

+import java.io.IOException;

+import java.net.MalformedURLException;

+import java.net.URL;

+import java.util.Iterator;

+import java.util.Vector;

+

+import org.apache.felix.jmood.AgentContext;

+import org.apache.felix.jmood.utils.InstrumentationSupport;

+import org.osgi.framework.Bundle;

+import org.osgi.framework.BundleException;

+import org.osgi.framework.Constants;

+import org.osgi.service.packageadmin.PackageAdmin;

+import org.osgi.service.startlevel.StartLevel;

+

+

+public class CoreController implements CoreControllerMBean {

+	private AgentContext ac;

+

+	public CoreController(AgentContext ac) {

+		super();

+		this.ac = ac;

+	}

+

+	/*

+	 * (non-Javadoc)

+	 * 

+	 * @see org.apache.felix.jmood.core.CoreControllerMBean#startBundle(java.lang.String)

+	 */

+	public void startBundle(String bundleSymbolicName) throws BundleException,

+			BundleNotAvailableException {

+		String[] s = bundleSymbolicName.split(";");

+		long id = InstrumentationSupport.getBundleId(bundleSymbolicName, ac);

+		ac.getBundleContext().getBundle(id).start();

+

+	}

+

+	/*

+	 * (non-Javadoc)

+	 * 

+	 * @see org.apache.felix.jmood.core.CoreControllerMBean#batchStartBundles(java.lang.String[])

+	 */

+	public void batchStartBundles(String[] bundleSymbolicNames)

+			throws BundleException, BundleNotAvailableException {

+		if (bundleSymbolicNames == null)

+			throw new IllegalArgumentException(

+					"Array of bundles cannot be null");

+		for (int i = 0; i < bundleSymbolicNames.length; i++) {

+			this.startBundle(bundleSymbolicNames[i]);

+		}

+

+	}

+

+	/*

+	 * (non-Javadoc)

+	 * 

+	 * @see org.apache.felix.jmood.core.CoreControllerMBean#stopBundle(java.lang.String)

+	 */

+	public void stopBundle(String bundleSymbolicName) throws BundleException,

+			BundleNotAvailableException {

+		long id = InstrumentationSupport.getBundleId(bundleSymbolicName, ac);

+		ac.getBundleContext().getBundle(id).stop();

+	}

+

+	/*

+	 * (non-Javadoc)

+	 * 

+	 * @see org.apache.felix.jmood.core.CoreControllerMBean#batchStopBundles(java.lang.String[])

+	 */

+	public void batchStopBundles(String[] bundleSymbolicNames)

+			throws BundleException, BundleNotAvailableException {

+		if (bundleSymbolicNames == null)

+			throw new IllegalArgumentException(

+					"Array of bundles cannot be null");

+		for (int i = 0; i < bundleSymbolicNames.length; i++) {

+			this.stopBundle(bundleSymbolicNames[i]);

+		}

+	}

+

+	/*

+	 * (non-Javadoc)

+	 * 

+	 * @see org.apache.felix.jmood.core.CoreControllerMBean#updateBundle(java.lang.String)

+	 */

+	public void updateBundle(String bundleSymbolicName) throws BundleException,

+			BundleNotAvailableException {

+		long id = InstrumentationSupport.getBundleId(bundleSymbolicName, ac);

+		ac.getBundleContext().getBundle(id).update();

+	}

+

+	/*

+	 * (non-Javadoc)

+	 * 

+	 * @see org.apache.felix.jmood.core.CoreControllerMBean#batchUpdateBundles(java.lang.String[])

+	 */

+	public void batchUpdateBundles(String[] bundleSymbolicNames)

+			throws BundleException, BundleNotAvailableException {

+		if (bundleSymbolicNames == null)

+			throw new IllegalArgumentException(

+					"Array of bundles cannot be null");

+		for (int i = 0; i < bundleSymbolicNames.length; i++) {

+			this.updateBundle(bundleSymbolicNames[i]);

+		}

+	}

+

+	/*

+	 * (non-Javadoc)

+	 * 

+	 * @see org.apache.felix.jmood.core.CoreControllerMBean#updateBundleFromUrl(java.lang.String,

+	 *      java.lang.String)

+	 */

+	public void updateBundleFromUrl(String bundleSymbolicName, String url)

+			throws BundleException, BundleNotAvailableException,

+			MalformedURLException, IOException {

+		long id = InstrumentationSupport.getBundleId(bundleSymbolicName, ac);

+		ac.getBundleContext().getBundle(id).update((new URL(url)).openStream());

+	}

+

+	/*

+	 * (non-Javadoc)

+	 * 

+	 * @see org.apache.felix.jmood.core.CoreControllerMBean#batchUpdateBundleFromUrl(java.lang.String[],

+	 *      java.lang.String[])

+	 */

+	public void batchUpdateBundleFromUrl(String[] bundleSymbolicNames,

+			String[] urls) throws BundleException, BundleNotAvailableException,

+			MalformedURLException, IOException {

+		if (bundleSymbolicNames == null || urls == null)

+			throw new IllegalArgumentException("arguments cannot be null");

+		if (urls.length != bundleSymbolicNames.length)

+			throw new IllegalArgumentException(

+					"Each bundle needs a corresponding url");

+		for (int i = 0; i < bundleSymbolicNames.length; i++) {

+			this.updateBundleFromUrl(bundleSymbolicNames[i], urls[i]);

+		}

+	}

+

+	/*

+	 * (non-Javadoc)

+	 * 

+	 * @see org.apache.felix.jmood.core.CoreControllerMBean#installBundle(java.lang.String)

+	 */

+	public void installBundle(String bundleLocation) throws BundleException {

+		ac.getBundleContext().installBundle(bundleLocation);

+	}

+

+	/*

+	 * (non-Javadoc)

+	 * 

+	 * @see org.apache.felix.jmood.core.CoreControllerMBean#batchInstallBundle(java.lang.String[])

+	 */

+	public void batchInstallBundle(String[] bundleLocations)

+			throws BundleException {

+		for (int i = 0; i < bundleLocations.length; i++) {

+			this.installBundle(bundleLocations[i]);

+		}

+	}

+

+	/*

+	 * (non-Javadoc)

+	 * 

+	 * @see org.apache.felix.jmood.core.CoreControllerMBean#setBundleStartLevel(java.lang.String,

+	 *      int)

+	 */

+	public void setBundleStartLevel(String bundleSymbolicName, int newlevel)

+			throws BundleNotAvailableException, ServiceNotAvailableException {

+		StartLevel sl = ac.getStartLevel();

+		if (sl == null) {

+			ac.debug("tried to modify startlevel, but no service found");

+			throw new ServiceNotAvailableException(

+					"Start Level service not available");

+		}

+		long id = InstrumentationSupport.getBundleId(bundleSymbolicName, ac);

+		ac.getStartLevel().setBundleStartLevel(

+				ac.getBundleContext().getBundle(id), newlevel);

+	}

+

+	/*

+	 * (non-Javadoc)

+	 * 

+	 * @see org.apache.felix.jmood.core.CoreControllerMBean#batchSetBundleStartLevel(java.lang.String[],

+	 *      int[])

+	 */

+	public void batchSetBundleStartLevel(String[] bundleSymbolicNames,

+			int[] newlevels) {

+		if (bundleSymbolicNames == null || newlevels == null)

+			throw new IllegalArgumentException("arguments cannot be null");

+		if (newlevels.length != bundleSymbolicNames.length)

+			throw new IllegalArgumentException(

+					"Each bundle needs a corresponding new level");

+		for (int i = 0; i < newlevels.length; i++) {

+		}

+	}

+

+	/*

+	 * (non-Javadoc)

+	 * 

+	 * @see org.apache.felix.jmood.core.CoreControllerMBean#refreshPackages(java.lang.String[])

+	 */

+	public void refreshPackages(String[] bundleSymbolicNames)

+			throws BundleNotAvailableException, ServiceNotAvailableException {

+		if (bundleSymbolicNames == null)

+			throw new IllegalArgumentException("argument cannot be null");

+		Bundle[] bundles = new Bundle[bundleSymbolicNames.length];

+		for (int i = 0; i < bundles.length; i++) {

+			long id = InstrumentationSupport.getBundleId(

+					bundleSymbolicNames[i], ac);

+			bundles[i] = ac.getBundleContext().getBundle(id);

+			if (bundles[i] == null)

+				throw new BundleNotAvailableException(

+						"could not get bundle whose id" + id);

+		}

+		ac.getPackageadmin().refreshPackages(bundles);

+	}

+

+	/*

+	 * (non-Javadoc)

+	 * 

+	 * @see org.apache.felix.jmood.core.CoreControllerMBean#resolveBundles(java.lang.String[])

+	 */

+	public void resolveBundles(String[] bundleSymbolicNames)

+			throws BundleNotAvailableException, ServiceNotAvailableException {

+		if (bundleSymbolicNames == null)

+			throw new IllegalArgumentException("argument cannot be null");

+		Bundle[] bundles = new Bundle[bundleSymbolicNames.length];

+		for (int i = 0; i < bundles.length; i++) {

+			long id = InstrumentationSupport.getBundleId(

+					bundleSymbolicNames[i], ac);

+			bundles[i] = ac.getBundleContext().getBundle(id);

+			if (bundles[i] == null)

+				throw new BundleNotAvailableException(

+						"could not get bundle whose id" + id);

+		}

+		ac.getPackageadmin().resolveBundles(bundles);

+	}

+

+	/*

+	 * (non-Javadoc)

+	 * 

+	 * @see org.apache.felix.jmood.core.CoreControllerMBean#setPlatformStartLevel(int)

+	 */

+	public void setPlatformStartLevel(int newlevel)

+			throws ServiceNotAvailableException {

+		ac.getStartLevel().setStartLevel(newlevel);

+	}

+

+	/*

+	 * (non-Javadoc)

+	 * 

+	 * @see org.apache.felix.jmood.core.CoreControllerMBean#getPlatformStartLevel()

+	 */

+	public int getPlatformStartLevel() throws ServiceNotAvailableException {

+		return ac.getStartLevel().getStartLevel();

+	}

+

+	/*

+	 * (non-Javadoc)

+	 * 

+	 * @see org.apache.felix.jmood.core.CoreControllerMBean#setInitialBundleStartLevel(int)

+	 */

+	public void setInitialBundleStartLevel(int newlevel)

+			throws ServiceNotAvailableException {

+		ac.getStartLevel().setInitialBundleStartLevel(newlevel);

+	}

+

+	/*

+	 * (non-Javadoc)

+	 * 

+	 * @see org.apache.felix.jmood.core.CoreControllerMBean#getInitialBundleStartLevel()

+	 */

+	public int getInitialBundleStartLevel() throws ServiceNotAvailableException {

+		return ac.getStartLevel().getInitialBundleStartLevel();

+	}

+

+	/*

+	 * (non-Javadoc)

+	 * 

+	 * @see org.apache.felix.jmood.core.CoreControllerMBean#restartFramework()

+	 */

+	public void restartFramework() throws NotImplementedException {

+		try {

+			ac.getBundleContext().getBundle(0).update();

+		} catch (BundleException be) {

+			throw new NotImplementedException(

+					"Restarting not implemented in this framework", be);

+		}

+	}

+

+	/*

+	 * (non-Javadoc)

+	 * 

+	 * @see org.apache.felix.jmood.core.CoreControllerMBean#shutdownFramework()

+	 */

+	public void shutdownFramework() throws NotImplementedException {

+		try {

+			ac.getBundleContext().getBundle(0).stop();

+		} catch (BundleException be) {

+			throw new NotImplementedException(

+					"Shutting down not implemented in this framework", be);

+		}

+	}

+

+	/*

+	 * (non-Javadoc)

+	 * 

+	 * @see org.apache.felix.jmood.core.CoreControllerMBean#updateFramework()

+	 */

+	public void updateFramework() throws NotImplementedException {

+		// TODO

+		throw new NotImplementedException(

+				"Feature not implemented for this framework");

+	}

+

+	public void uninstallBundle(String bundleSymbolicName)

+			throws BundleNotAvailableException, BundleException {

+		if (bundleSymbolicName == null)

+			throw new IllegalArgumentException("argument cannot be null");

+		String[] s = bundleSymbolicName.split(";");

+		long id = InstrumentationSupport.getBundleId(bundleSymbolicName, ac);

+		ac.getBundleContext().getBundle(id).uninstall();

+

+	}

+}

diff --git a/org.apache.felix.jmood/src/main/java/org/apache/felix/jmood/core/CoreControllerMBean.java b/org.apache.felix.jmood/src/main/java/org/apache/felix/jmood/core/CoreControllerMBean.java
new file mode 100644
index 0000000..85e8fca
--- /dev/null
+++ b/org.apache.felix.jmood/src/main/java/org/apache/felix/jmood/core/CoreControllerMBean.java
@@ -0,0 +1,101 @@
+/*

+ *   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.jmood.core;

+

+import java.io.IOException;

+import java.net.MalformedURLException;

+

+import org.osgi.framework.BundleException;

+

+/**

+ * The CoreController mbean provides mechanisms to exert control over the

+ * framework. For many operations, it provides a batch mechanism to avoid 

+ * excessive message passing when interacting remotely. 

+ *

+ */

+public interface CoreControllerMBean {

+

+    public abstract void startBundle(String bundleSymbolicName)

+            throws BundleException, BundleNotAvailableException;

+

+    public abstract void batchStartBundles(String[] bundleSymbolicNames)

+            throws BundleException, BundleNotAvailableException;

+

+    public abstract void stopBundle(String bundleSymbolicName)

+            throws BundleException, BundleNotAvailableException;

+

+    public abstract void batchStopBundles(String[] bundleSymbolicNames)

+            throws BundleException, BundleNotAvailableException;

+

+    public abstract void updateBundle(String bundleSymbolicName)

+            throws BundleException, BundleNotAvailableException;

+    

+    public abstract void uninstallBundle(String bundleSymbolicName)

+			throws BundleNotAvailableException, BundleException;

+

+    public abstract void batchUpdateBundles(String[] bundleSymbolicNames)

+            throws BundleException, BundleNotAvailableException;

+

+    public abstract void updateBundleFromUrl(String bundleSymbolicName,

+            String url) throws BundleException, BundleNotAvailableException,

+            MalformedURLException, IOException;

+

+    public abstract void batchUpdateBundleFromUrl(String[] bundleSymbolicNames,

+            String[] urls) throws BundleException, BundleNotAvailableException,

+            MalformedURLException, IOException;

+

+    public abstract void installBundle(String bundleLocation)

+            throws BundleException;

+

+    public abstract void batchInstallBundle(String[] bundleLocations)

+            throws BundleException;

+

+    public abstract void setBundleStartLevel(String bundleSymbolicName,

+            int newlevel) throws BundleNotAvailableException,

+            ServiceNotAvailableException;

+

+    public abstract void batchSetBundleStartLevel(String[] bundleSymbolicNames,

+            int[] newlevels);

+

+    public abstract void refreshPackages(String[] bundleSymbolicNames)

+            throws BundleNotAvailableException, ServiceNotAvailableException;

+

+    public abstract void resolveBundles(String[] bundleSymbolicNames)

+            throws BundleNotAvailableException, ServiceNotAvailableException;

+

+    public abstract void setPlatformStartLevel(int newlevel) throws ServiceNotAvailableException;

+

+    public abstract int getPlatformStartLevel() throws ServiceNotAvailableException;

+

+    /**

+     * 

+     * @param newlevel

+     * @throws ServiceNotAvailableException if StartLevel service not available, or RuntimeMBeanException that wraps an IllegalArgumentException, as specified 

+     * by the Start Level service.  

+     */

+    public abstract void setInitialBundleStartLevel(int newlevel) throws ServiceNotAvailableException;

+

+    public abstract int getInitialBundleStartLevel() throws ServiceNotAvailableException;

+

+    public abstract void restartFramework() throws NotImplementedException;

+

+    public abstract void shutdownFramework() throws NotImplementedException;

+

+    public abstract void updateFramework() throws NotImplementedException;

+

+}
\ No newline at end of file
diff --git a/org.apache.felix.jmood/src/main/java/org/apache/felix/jmood/core/Framework.java b/org.apache.felix.jmood/src/main/java/org/apache/felix/jmood/core/Framework.java
new file mode 100644
index 0000000..8d1a242
--- /dev/null
+++ b/org.apache.felix.jmood/src/main/java/org/apache/felix/jmood/core/Framework.java
@@ -0,0 +1,386 @@
+/*

+ *   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.jmood.core;

+

+import java.util.Hashtable;

+import java.util.Iterator;

+import java.util.Set;

+

+import javax.management.InstanceAlreadyExistsException;

+import javax.management.InstanceNotFoundException;

+import javax.management.MBeanRegistration;

+import javax.management.MBeanRegistrationException;

+import javax.management.MBeanServer;

+import javax.management.MalformedObjectNameException;

+import javax.management.NotCompliantMBeanException;

+import javax.management.ObjectName;

+

+import org.apache.felix.jmood.AgentContext;

+import org.apache.felix.jmood.core.instrumentation.BundleInfo;

+import org.apache.felix.jmood.core.instrumentation.FrameworkSnapshot;

+import org.apache.felix.jmood.core.instrumentation.PackageInfo;

+import org.apache.felix.jmood.core.instrumentation.ServiceInfo;

+import org.apache.felix.jmood.utils.InstrumentationSupport;

+import org.apache.felix.jmood.utils.ObjectNames;

+import org.osgi.framework.Bundle;

+import org.osgi.framework.BundleEvent;

+import org.osgi.framework.BundleListener;

+import org.osgi.framework.Constants;

+import org.osgi.framework.FrameworkEvent;

+import org.osgi.framework.FrameworkListener;

+import org.osgi.framework.InvalidSyntaxException;

+import org.osgi.framework.ServiceEvent;

+import org.osgi.framework.ServiceListener;

+import org.osgi.framework.ServiceReference;

+import org.osgi.service.packageadmin.ExportedPackage;

+import org.osgi.service.packageadmin.PackageAdmin;

+public class Framework implements FrameworkMBean, MBeanRegistration {

+	private MBeanRegistrator registrator;

+

+	private AgentContext ac;

+

+	private FrameworkSnapshot snapshot;

+

+	public Framework(AgentContext ac) {

+		super();

+		this.ac = ac;

+		snapshot = new FrameworkSnapshot(ac);

+	}

+

+	/*

+	 * (non-Javadoc)

+	 * 

+	 * @see org.apache.felix.jmood.core.FrameworkMBean#getBundles()

+	 */

+	public BundleInfo[] getBundles() {

+		snapshot.refreshSnapshot();

+		return snapshot.getAllBundles();

+	}

+

+	/*

+	 * (non-Javadoc)

+	 * 

+	 * @see org.apache.felix.jmood.core.FrameworkMBean#getServiceInfo()

+	 */

+	public ServiceInfo[] getServiceInfo() throws InvalidSyntaxException {

+		snapshot.refreshSnapshot();

+		return snapshot.getAllServiceInfo();

+	}

+

+	/*

+	 * (non-Javadoc)

+	 * 

+	 * @see org.apache.felix.jmood.core.FrameworkMBean#getPackageInfo()

+	 */

+	public PackageInfo[] getPackageInfo() throws ServiceNotAvailableException {

+		snapshot.refreshSnapshot();

+		return snapshot.getAllPackageInfo();

+	}

+

+	public Hashtable getProperties() {

+		Hashtable props = new Hashtable();

+		// We do not cache it just in case some value changes (although

+		// unlikely)

+		props.put(Constants.FRAMEWORK_VERSION, ac.getBundleContext()

+				.getProperty(Constants.FRAMEWORK_VERSION));

+		props.put(Constants.FRAMEWORK_VENDOR, ac.getBundleContext()

+				.getProperty(Constants.FRAMEWORK_VENDOR));

+		props.put(Constants.FRAMEWORK_LANGUAGE, ac.getBundleContext()

+				.getProperty(Constants.FRAMEWORK_LANGUAGE));

+		props.put(Constants.FRAMEWORK_OS_NAME, ac.getBundleContext()

+				.getProperty(Constants.FRAMEWORK_OS_NAME));

+		props.put(Constants.FRAMEWORK_OS_VERSION, ac.getBundleContext()

+				.getProperty(Constants.FRAMEWORK_OS_VERSION));

+		props.put(Constants.FRAMEWORK_PROCESSOR, ac.getBundleContext()

+				.getProperty(Constants.FRAMEWORK_PROCESSOR));

+		String bootdel = ac.getBundleContext().getProperty(

+				Constants.FRAMEWORK_BOOTDELEGATION);

+		if (bootdel != null)

+			props.put(Constants.FRAMEWORK_BOOTDELEGATION, bootdel);

+		String execenv = ac.getBundleContext().getProperty(

+				Constants.FRAMEWORK_EXECUTIONENVIRONMENT);

+		if (execenv != null)

+			props.put(Constants.FRAMEWORK_EXECUTIONENVIRONMENT, execenv);

+		String syspkgs = ac.getBundleContext().getProperty(

+				Constants.FRAMEWORK_SYSTEMPACKAGES);

+		if (syspkgs != null)

+			props.put(Constants.FRAMEWORK_SYSTEMPACKAGES, syspkgs);

+		return props;

+	}

+

+	public String getProperty(String key) {

+		return ac.getBundleContext().getProperty(key);

+	}

+

+	public ObjectName preRegister(MBeanServer server, ObjectName name)

+			throws Exception {

+		registrator = new MBeanRegistrator(server, ac);

+		return name;

+	}

+

+	public void postRegister(Boolean registrationDone) {

+		registrator.init();

+	}

+

+	public void preDeregister() throws Exception {

+		registrator.dispose();

+

+	}

+

+	public void postDeregister() {

+	}

+}

+	class MBeanRegistrator {

+		private MBeanServer server;

+		

+		private AgentContext ac;

+

+		private FrameworkListener fl;

+

+		private BundleListener bl;

+

+		private ServiceListener sl;

+

+		protected MBeanRegistrator(MBeanServer server, AgentContext ac) {

+			this.server = server;

+			this.ac=ac;

+			

+			fl = new FrameworkListener() {

+				public void frameworkEvent(FrameworkEvent event) {

+					if (event.getType() == FrameworkEvent.PACKAGES_REFRESHED) {

+						// We cannot know which are the affected packages, just refresh all

+						//However, registering mbeans is expensive, as it involves reflection

+						//TODO improve this

+						unregisterPackageMBeans();

+						registerPackageMBeans();

+						unregisterBundleMBeans();

+						registerBundleMBeans();

+					}

+				}

+			};

+			bl = new BundleListener() {

+				public void bundleChanged(BundleEvent event) {

+					switch (event.getType()){

+					case BundleEvent.INSTALLED:

+						registerBundleMBean(event.getBundle());

+						break;

+					case BundleEvent.UNINSTALLED:

+						//Ignore: uninstalled bundles are not removed until refreshed

+						break;

+					case BundleEvent.UPDATED:

+						//Ignore Update  

+						break;

+					default: //nothing todo for the rest of the events

+						break;

+					}

+				}

+			};

+			sl = new ServiceListener() {

+				public void serviceChanged(ServiceEvent event) {

+					switch (event.getType()) {

+					case ServiceEvent.UNREGISTERING:

+						unregisterServiceMBean(event.getServiceReference());

+						break;

+					case ServiceEvent.REGISTERED:

+						registerServiceMBean(event.getServiceReference());

+						break;

+					default://nothing todo if MODIFIED

+						break;

+					}

+				}

+			};

+		}

+		protected void init(){

+			registerBundleMBeans();

+			registerServiceMBeans();

+			registerPackageMBeans();

+			ac.getBundleContext().addFrameworkListener(fl);

+			ac.getBundleContext().addBundleListener(bl);

+			ac.getBundleContext().addServiceListener(sl);

+		}

+		protected void dispose() {

+			ac.getBundleContext().removeFrameworkListener(fl);

+			ac.getBundleContext().removeBundleListener(bl);

+			ac.getBundleContext().removeServiceListener(sl);

+			unregisterBundleMBeans();

+			unregisterServiceMBeans();

+			unregisterPackageMBeans();

+		}

+		private void unregisterBundleMBeans(){

+			try {

+			Set bundles = server.queryNames(new ObjectName(

+					ObjectNames.ALLBUNDLES), null);

+			for (Iterator iter = bundles.iterator(); iter.hasNext();) {

+				ObjectName oname = (ObjectName) iter.next();

+				server.unregisterMBean(oname);

+			}

+			

+			} catch (MalformedObjectNameException mone) {

+			ac.error("unexpected error:", mone);

+		} catch (NullPointerException npe) {

+			//No registered bundle mbeans

+		} catch (InstanceNotFoundException infe) {

+			ac.error("unexpected error:", infe);

+		} catch (MBeanRegistrationException mre) {

+			ac.error("unexpected error:", mre);

+		}

+		}

+

+		private void unregisterServiceMBeans(){

+			try {

+				Set services = server.queryNames(new ObjectName(

+						ObjectNames.ALLSERVICES), null);

+				for (Iterator iter = services.iterator(); iter.hasNext();) {

+					ObjectName oname = (ObjectName) iter.next();

+					server.unregisterMBean(oname);

+				}

+			} catch (MalformedObjectNameException mone) {

+				ac.error("unexpected error:", mone);

+			} catch (NullPointerException npe) {

+				//No registered service mbeans

+			} catch (InstanceNotFoundException infe) {

+				ac.error("unexpected error:", infe);

+			} catch (MBeanRegistrationException mre) {

+				ac.error("unexpected error:", mre);

+			}

+				

+		}

+		private void unregisterPackageMBeans(){

+			try {

+				Set pkgs = server.queryNames(new ObjectName(

+						ObjectNames.ALLPACKAGES), null);

+				for (Iterator iter = pkgs.iterator(); iter.hasNext();) {

+					ObjectName oname = (ObjectName) iter.next();

+					server.unregisterMBean(oname);

+				}

+			} catch (MalformedObjectNameException mone) {

+				ac.error("unexpected error:", mone);

+			} catch (NullPointerException npe) {

+				//No registered package mbeans

+			} catch (InstanceNotFoundException infe) {

+				ac.error("unexpected error:", infe);

+			} catch (MBeanRegistrationException mre) {

+				ac.error("unexpected error:", mre);

+			}

+			

+		}

+		private void unregisterServiceMBean(ServiceReference service){

+			try {

+				server.unregisterMBean(new ObjectName(ObjectNames.SERVICE+service.getProperty(Constants.SERVICE_ID)));

+			} catch (InstanceNotFoundException infe) {

+				ac.error("Unexpected error", infe);

+			} catch (MBeanRegistrationException mre) {

+				ac.error("Unexpected error", mre);

+			} catch (MalformedObjectNameException mone) {

+				ac.error("Unexpected error", mone);

+			}

+		}

+		private void registerBundleMBean(Bundle bundle){

+			try {

+				server.registerMBean(new ManagedBundle(bundle, ac),

+						new ObjectName(ObjectNames.BUNDLE

+								+ InstrumentationSupport

+										.getSymbolicName(bundle)));

+				ac.debug("registered mbean for "

+						+ bundle.getSymbolicName());

+

+			} catch (InstanceAlreadyExistsException iaee) {

+				ac.error("unexpected error:", iaee);

+			} catch (MBeanRegistrationException mre) {

+				ac.error("unexpected error:", mre);

+			} catch (NotCompliantMBeanException ncme) {

+				ac.error("unexpected error:", ncme);

+			} catch (MalformedObjectNameException mone) {

+				ac.error("unexpected error:", mone);

+			} catch (NullPointerException npe) {

+				ac.error("unexpected error:", npe);

+			}

+		}

+		private void registerBundleMBeans(){

+				Bundle[] bundles = ac.getBundleContext().getBundles();

+				for (int i = 0; i < bundles.length; i++) {

+					registerBundleMBean(bundles[i]);

+				}

+			}

+		private void registerServiceMBean(ServiceReference service){

+			try {

+				server.registerMBean(new ManagedService(service),

+						new ObjectName(ObjectNames.SERVICE

+								+ service.getProperty(

+										Constants.SERVICE_ID)));

+				ac.debug("registed mbean for "

+						+ service.getProperty(

+								Constants.SERVICE_ID));

+			} catch (InstanceAlreadyExistsException iaee) {

+				ac.error("unexpected error:", iaee);

+			} catch (MBeanRegistrationException mre) {

+				ac.error("unexpected error:", mre);

+			} catch (NotCompliantMBeanException ncme) {

+				ac.error("unexpected error:", ncme);

+			} catch (MalformedObjectNameException mone) {

+				ac.error("unexpected error:", mone);

+			} catch (NullPointerException npe) {

+				ac.error("unexpected error:", npe);

+			}

+			

+		}

+		private void registerServiceMBeans(){

+			try {

+				ServiceReference[] services=ac.getBundleContext().getServiceReferences(null, null);

+				if (services != null) {

+					for (int i = 0; i < services.length; i++) {

+						registerServiceMBean(services[i]);

+					}

+				} else

+					ac.debug("no services found");

+			} catch (InvalidSyntaxException ie) {

+				ac.error("unexpected error:", ie);

+			}

+		}

+		private void registerPackageMBeans(){

+			try {

+				ExportedPackage[] pkgs=ac.getPackageadmin().getExportedPackages((Bundle)null);

+				if (pkgs != null) {

+					for (int i = 0; i < pkgs.length; i++) {

+						try {

+							server.registerMBean(new ManagedPackage(pkgs[i]),

+									new ObjectName(ObjectNames.PACKAGE

+											+ InstrumentationSupport.getPackageName(pkgs[i])));

+							ac.debug("registed mbean for " + InstrumentationSupport.getPackageName(pkgs[i]));

+

+						} catch (InstanceAlreadyExistsException iaee) {

+							ac.error("unexpected error:", iaee);

+						} catch (MBeanRegistrationException mre) {

+							ac.error("unexpected error:", mre);

+						} catch (NotCompliantMBeanException ncme) {

+							ac.error("unexpected error:", ncme);

+						} catch (MalformedObjectNameException mone) {

+							ac.error("unexpected error:", mone);

+						} catch (NullPointerException npe) {

+							ac.error("unexpected error:", npe);

+						}

+					}

+				} else

+					ac.debug("no packages found");

+			} catch (ServiceNotAvailableException se) {

+				ac.error("No package admin available", se);

+			}

+		}

+	}

+

+

diff --git a/org.apache.felix.jmood/src/main/java/org/apache/felix/jmood/core/FrameworkMBean.java b/org.apache.felix.jmood/src/main/java/org/apache/felix/jmood/core/FrameworkMBean.java
new file mode 100644
index 0000000..d71552d
--- /dev/null
+++ b/org.apache.felix.jmood/src/main/java/org/apache/felix/jmood/core/FrameworkMBean.java
@@ -0,0 +1,95 @@
+/*

+ *   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.jmood.core;

+

+import java.util.Hashtable;

+

+import javax.management.MBeanRegistration;

+

+import org.apache.felix.jmood.core.instrumentation.BundleInfo;

+import org.apache.felix.jmood.core.instrumentation.PackageInfo;

+import org.apache.felix.jmood.core.instrumentation.ServiceInfo;

+import org.osgi.framework.InvalidSyntaxException;

+

+

+/**

+ * This mbean provides access to the basic framework information:

+ * <ul>

+ * <li><code>BundleInfo</code></li>

+ * <li><code>PackageInfo</code></li>

+ * <li><code>ServiceInfo</code></li>

+ * </ul>

+ * 

+ * The idea underlying this is to provide both a reasonably fast way to access

+ * all the framework information, avoiding too much message-passing overhead, while at the same time provide console-friendly

+ * information. 

+ * <p>

+ * Internally, implementations of Info objects include references to each other,

+ * so that with getBundleInfo() you get information, indirectly, of all the services

+ * and packages.

+ * </p>

+ * <p>

+ * This mbean also dynamically registers mbeans representing those objects

+ * to ease-up direct usage by generic JMX mgmt consoles (such as Jconsole)

+ * that are not aware of the data types used. While CompositeDataTypes could

+ * be used (as in former JMood implementations), they are too cumbersome to use

+ * and place too much dependency on JMX. 

+ * </p>

+ * 

+ * @see org.apache.felix.jmood.core.instrumentation.BundleInfo

+ * @see org.apache.felix.jmood.core.instrumentation.PackageInfo

+ * @see org.apache.felix.jmood.core.instrumentation.ServiceInfo

+ *

+ */

+public interface FrameworkMBean {

+

+    public abstract BundleInfo[] getBundles();

+

+    public abstract ServiceInfo[] getServiceInfo()

+            throws InvalidSyntaxException;

+

+    public abstract PackageInfo[] getPackageInfo()

+            throws ServiceNotAvailableException;

+    /**

+     * This hashtable contains the framework properties:

+     * <ul>

+     * <li><code>FRAMEWORK_VERSION</code></li>

+     * <li><code>FRAMEWORK_VENDOR</code></li>

+     * <li><code>FRAMEWORK_LANGUAGE</code></li>

+     * <li><code>FRAMEWORK_OS_NAME</code></li>

+     * <li><code>FRAMEWORK_OS_VERSION</code></li>

+     * <li><code>FRAMEWORK_PROCESSOR</code></li>

+     * </ul><p>Plus, if available:</p><ul>

+     * <li><code>FRAMEWORK_BOOTDELEGATION</code></li>

+     * <li><code>FRAMEWORK_EXECUTIONENVIRONMENT</code></li>

+     * <li><code>FRAMEWORK_SYSTEMPACKAGES</code></li>

+     * </ul>

+     * For any other properties, we suggest to use the getProperty(String key)

+     * @return

+     * @see org.osgi.framework.Constants

+     */

+    public abstract Hashtable getProperties();

+    /**

+     * 

+     * @param key

+     * @return return the property value or null if undefined. System properties are also

+     * searched for if the property is not found in the framework properties 

+     */

+    public String getProperty(String key);

+

+}
\ No newline at end of file
diff --git a/org.apache.felix.jmood/src/main/java/org/apache/felix/jmood/core/ManagedBundle.java b/org.apache.felix.jmood/src/main/java/org/apache/felix/jmood/core/ManagedBundle.java
new file mode 100644
index 0000000..4ceb2e3
--- /dev/null
+++ b/org.apache.felix.jmood/src/main/java/org/apache/felix/jmood/core/ManagedBundle.java
@@ -0,0 +1,206 @@
+/*

+ *   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.jmood.core;

+

+import java.io.IOException;

+import java.net.MalformedURLException;

+import java.net.URL;

+import java.util.Enumeration;

+import java.util.Hashtable;

+

+import org.apache.felix.jmood.AgentContext;

+import org.apache.felix.jmood.utils.InstrumentationSupport;

+import org.osgi.framework.Bundle;

+import org.osgi.framework.BundleException;

+import org.osgi.service.packageadmin.RequiredBundle;

+

+/**

+ * This class implements the MBean interface. In order to obtain 

+ * the string representation of bundles, services and packages

+ * it uses the CoreUtils static methods.

+ * @see org.apache.felix.jmood.utils.InstrumentationSupport

+ *

+ */

+public class ManagedBundle implements ManagedBundleMBean {

+    private Bundle bundle;

+    private AgentContext ac;

+    public ManagedBundle(Bundle bundle, AgentContext ac) {

+        super();

+        this.bundle=bundle;

+        this.ac=ac;

+    }

+    /* (non-Javadoc)

+     * @see org.apache.felix.jmood.core.ManagedBundleMBean#getBundleId()

+     */

+    public long getBundleId() {

+        return bundle.getBundleId();

+    }

+    /* (non-Javadoc)

+     * @see org.apache.felix.jmood.core.ManagedBundleMBean#getExportedPackages()

+     */

+    public String[] getExportedPackages() throws ServiceNotAvailableException{

+        return InstrumentationSupport.getPackageNames(ac.getPackageadmin().getExportedPackages(bundle));

+    }

+    /* (non-Javadoc)

+     * @see org.apache.felix.jmood.core.ManagedBundleMBean#getFragments()

+     */

+    public String[] getFragments() throws ServiceNotAvailableException{

+        return InstrumentationSupport.getSymbolicNames(ac.getPackageadmin().getFragments(bundle));

+    }

+    /* (non-Javadoc)

+     * @see org.apache.felix.jmood.core.ManagedBundleMBean#getHeaders()

+     */

+    public Hashtable getHeaders() {

+        Hashtable ht=new Hashtable();

+        Enumeration keys=bundle.getHeaders().keys();

+        while(keys.hasMoreElements()) {

+            Object key=keys.nextElement();

+            ht.put(key, bundle.getHeaders().get(key));

+        }

+        return ht;

+    }

+    /* (non-Javadoc)

+     * @see org.apache.felix.jmood.core.ManagedBundleMBean#getHosts()

+     */

+    public String[] getHosts() throws ServiceNotAvailableException{

+        return InstrumentationSupport.getSymbolicNames(ac.getPackageadmin().getHosts(bundle));

+    }

+    /* (non-Javadoc)

+     * @see org.apache.felix.jmood.core.ManagedBundleMBean#getImportedPackages()

+     */

+    public String[] getImportedPackages() throws ServiceNotAvailableException {

+        return InstrumentationSupport.getPackageNames(InstrumentationSupport.getImportedPackages(bundle, ac));

+    }

+    /* (non-Javadoc)

+     * @see org.apache.felix.jmood.core.ManagedBundleMBean#getLastModified()

+     */

+    public long getLastModified() {

+        return bundle.getLastModified();

+    }

+    /* (non-Javadoc)

+     * @see org.apache.felix.jmood.core.ManagedBundleMBean#getRegisteredServices()

+     */

+    public String[] getRegisteredServices() {

+        return InstrumentationSupport.getServiceNames(bundle.getRegisteredServices());

+    }

+    /* (non-Javadoc)

+     * @see org.apache.felix.jmood.core.ManagedBundleMBean#getRequiredBundles()

+     */

+    public String[] getBundleDependencies() throws ServiceNotAvailableException{

+        Bundle[] required=InstrumentationSupport.getBundleDependencies(bundle, ac);

+        return InstrumentationSupport.getSymbolicNames(required);

+    }

+    /* (non-Javadoc)

+     * @see org.apache.felix.jmood.core.ManagedBundleMBean#getRequiringBundles()

+     */

+    public String[] getRequiringBundles() throws ServiceNotAvailableException {

+        return InstrumentationSupport.getSymbolicNames(InstrumentationSupport.getRequiringBundles(bundle, ac));

+    }

+    /* (non-Javadoc)

+     * @see org.apache.felix.jmood.core.ManagedBundleMBean#getServicesInUse()

+     */

+    public String[] getServicesInUse() {

+        return InstrumentationSupport.getServiceNames(bundle.getServicesInUse());

+    }

+    /* (non-Javadoc)

+     * @see org.apache.felix.jmood.core.ManagedBundleMBean#getStartLevel()

+     */

+    public int getStartLevel() throws ServiceNotAvailableException {

+        return ac.getStartLevel().getBundleStartLevel(bundle);

+    }

+    public void setStartLevel(int level) throws ServiceNotAvailableException{

+        ac.getStartLevel().setBundleStartLevel(this.bundle, level);

+    }

+

+    /* (non-Javadoc)

+     * @see org.apache.felix.jmood.core.ManagedBundleMBean#getState()

+     */

+    public String getState() {

+        return InstrumentationSupport.getState(bundle.getState());

+    }

+    /* (non-Javadoc)

+     * @see org.apache.felix.jmood.core.ManagedBundleMBean#getSymbolicName()

+     */

+    public String getSymbolicName() {

+        return bundle.getSymbolicName();

+    }

+    /* (non-Javadoc)

+     * @see org.apache.felix.jmood.core.ManagedBundleMBean#isBundlePersistentlyStarted()

+     */

+    public boolean isBundlePersistentlyStarted() throws ServiceNotAvailableException {

+    	try{

+    	return ac.getStartLevel().isBundlePersistentlyStarted(bundle);

+    	} catch (NullPointerException npe){

+    		ac.error("npe", npe);

+    		throw npe;

+    	}

+    }

+    /* (non-Javadoc)

+     * @see org.apache.felix.jmood.core.ManagedBundleMBean#isFragment()

+     */

+    public boolean isFragment() throws ServiceNotAvailableException{

+        return InstrumentationSupport.isFragment(bundle, ac);

+    }

+    /* (non-Javadoc)

+     * @see org.apache.felix.jmood.core.ManagedBundleMBean#isRemovalPending()

+     */

+    public boolean isRemovalPending() throws ServiceNotAvailableException{

+    	RequiredBundle r=InstrumentationSupport.getRequiredBundle(bundle, ac);

+    	if(r==null) return false; 

+        return r.isRemovalPending();

+    }

+    /* (non-Javadoc)

+     * @see org.apache.felix.jmood.core.ManagedBundleMBean#isRequired()

+     */

+    public boolean isRequired() throws ServiceNotAvailableException{

+        return InstrumentationSupport.isBundleRequired(bundle, ac);

+    }

+	public void start() throws BundleException {

+		bundle.start();

+		

+	}

+	public void stop() throws BundleException {

+		bundle.stop();

+	}

+	public void update() throws BundleException {

+		bundle.update();

+		

+	}

+	public void updateFromUrl(String url) throws MalformedURLException, BundleException, IOException {

+		//TODO should we use url handler service?

+		bundle.update(new URL(url).openStream());

+		

+	}

+	public void refreshBundle() throws BundleNotAvailableException, ServiceNotAvailableException {

+		CoreController c=new CoreController(ac);

+		String[] b={bundle.getSymbolicName()};

+		c.refreshPackages(b);

+		

+	}

+	public void resolveBundle() throws BundleNotAvailableException, ServiceNotAvailableException {

+		CoreController c=new CoreController(ac);

+		String[] b={bundle.getSymbolicName()};

+		c.resolveBundles(b);

+	}

+	public void uninstall() throws BundleException {

+		bundle.uninstall();

+		

+	}

+    

+

+}

diff --git a/org.apache.felix.jmood/src/main/java/org/apache/felix/jmood/core/ManagedBundleMBean.java b/org.apache.felix.jmood/src/main/java/org/apache/felix/jmood/core/ManagedBundleMBean.java
new file mode 100644
index 0000000..f909d56
--- /dev/null
+++ b/org.apache.felix.jmood/src/main/java/org/apache/felix/jmood/core/ManagedBundleMBean.java
@@ -0,0 +1,77 @@
+/*

+ *   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.jmood.core;

+

+import java.io.IOException;

+import java.net.MalformedURLException;

+import java.util.Hashtable;

+

+import org.osgi.framework.BundleException;

+public interface ManagedBundleMBean {

+

+    public abstract long getBundleId();

+

+    public abstract String[] getExportedPackages() throws ServiceNotAvailableException;

+

+    public abstract String[] getFragments() throws ServiceNotAvailableException;

+

+    public abstract Hashtable getHeaders();

+

+    public abstract String[] getHosts() throws ServiceNotAvailableException;

+

+    public abstract String[] getImportedPackages() throws ServiceNotAvailableException;

+

+    public abstract long getLastModified();

+

+    public abstract String[] getRegisteredServices();

+

+    public abstract String[] getBundleDependencies() throws ServiceNotAvailableException;

+

+    public abstract String[] getRequiringBundles() throws ServiceNotAvailableException;

+

+    public abstract String[] getServicesInUse();

+

+    public abstract int getStartLevel() throws ServiceNotAvailableException;

+

+    public abstract String getState();

+

+    public abstract String getSymbolicName();

+

+    public abstract boolean isBundlePersistentlyStarted() throws ServiceNotAvailableException;

+

+    public abstract boolean isFragment() throws ServiceNotAvailableException;

+

+    public abstract boolean isRemovalPending() throws ServiceNotAvailableException;

+

+    public abstract boolean isRequired() throws ServiceNotAvailableException;

+    

+    public abstract void start() throws BundleException;

+

+    public abstract void stop() throws BundleException;

+    

+    public abstract void update() throws BundleException;

+    

+    public abstract void uninstall() throws BundleException;

+    

+    public abstract void updateFromUrl(String url) throws MalformedURLException, BundleException, IOException;

+    

+    public abstract void refreshBundle() throws BundleNotAvailableException, ServiceNotAvailableException;

+    

+    public abstract void resolveBundle() throws BundleNotAvailableException, ServiceNotAvailableException;

+

+}
\ No newline at end of file
diff --git a/org.apache.felix.jmood/src/main/java/org/apache/felix/jmood/core/ManagedPackage.java b/org.apache.felix.jmood/src/main/java/org/apache/felix/jmood/core/ManagedPackage.java
new file mode 100644
index 0000000..3021f69
--- /dev/null
+++ b/org.apache.felix.jmood/src/main/java/org/apache/felix/jmood/core/ManagedPackage.java
@@ -0,0 +1,60 @@
+/*

+ *   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.jmood.core;

+

+import org.apache.felix.jmood.core.instrumentation.PackageInfo;

+import org.apache.felix.jmood.utils.InstrumentationSupport;

+import org.osgi.service.packageadmin.ExportedPackage;

+

+public class ManagedPackage implements ManagedPackageMBean {

+    private ExportedPackage pkg;

+    public ManagedPackage(ExportedPackage pkg) {

+        super();

+        this.pkg=pkg;

+    }

+    /* (non-Javadoc)

+     * @see org.apache.felix.jmood.core.ManagedPackageMBean#getExportingBundle()

+     */

+    public String getExportingBundle() {

+        return InstrumentationSupport.getSymbolicName(pkg.getExportingBundle());

+    }

+    /* (non-Javadoc)

+     * @see org.apache.felix.jmood.core.ManagedPackageMBean#getImportingBundles()

+     */

+    public String[] getImportingBundles() {

+        return InstrumentationSupport.getSymbolicNames(pkg.getImportingBundles());

+    }

+    /* (non-Javadoc)

+     * @see org.apache.felix.jmood.core.ManagedPackageMBean#getName()

+     */

+    public String getName() {

+        return pkg.getName();

+    }

+    /* (non-Javadoc)

+     * @see org.apache.felix.jmood.core.ManagedPackageMBean#getVersion()

+     */

+    public String getVersion() {

+        return pkg.getVersion().toString();

+    }

+    /* (non-Javadoc)

+     * @see org.apache.felix.jmood.core.ManagedPackageMBean#isRemovalPending()

+     */

+    public boolean isRemovalPending() {

+        return pkg.isRemovalPending();

+    }

+}

diff --git a/org.apache.felix.jmood/src/main/java/org/apache/felix/jmood/core/ManagedPackageMBean.java b/org.apache.felix.jmood/src/main/java/org/apache/felix/jmood/core/ManagedPackageMBean.java
new file mode 100644
index 0000000..c3700ac
--- /dev/null
+++ b/org.apache.felix.jmood/src/main/java/org/apache/felix/jmood/core/ManagedPackageMBean.java
@@ -0,0 +1,53 @@
+/*

+ *   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.jmood.core;

+public interface ManagedPackageMBean {

+

+    /**

+     * 

+     * @return the symbolic name of the exporting bundle

+     */

+    public abstract String getExportingBundle();

+

+    /**

+     * 

+     * @return the symbolic names of the importing bundles

+     */

+    public abstract String[] getImportingBundles();

+

+    /**

+     * 

+     * @return the package name

+     */

+    public abstract String getName();

+

+    /**

+     * 

+     * @return the package version

+     */

+    public abstract String getVersion();

+

+    /**

+     * 

+     * @return <code>true</code> if the associated package is being exported

+     *         by a bundle that has been updated or uninstalled. 

+     * @see org.osgi.service.packageadmin.ExportedPackage

+     */

+    public abstract boolean isRemovalPending();

+

+}
\ No newline at end of file
diff --git a/org.apache.felix.jmood/src/main/java/org/apache/felix/jmood/core/ManagedService.java b/org.apache.felix.jmood/src/main/java/org/apache/felix/jmood/core/ManagedService.java
new file mode 100644
index 0000000..d6f2883
--- /dev/null
+++ b/org.apache.felix.jmood/src/main/java/org/apache/felix/jmood/core/ManagedService.java
@@ -0,0 +1,59 @@
+/*

+ *   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.jmood.core;

+

+import java.util.Hashtable;

+

+import org.apache.felix.jmood.core.instrumentation.ServiceInfo;

+import org.apache.felix.jmood.utils.InstrumentationSupport;

+import org.osgi.framework.Constants;

+import org.osgi.framework.ServiceReference;

+

+public class ManagedService implements ManagedServiceMBean {

+    private ServiceReference svc;

+    public ManagedService(ServiceReference svc) {

+        super();

+        this.svc=svc;

+    }

+    /* (non-Javadoc)

+     * @see org.apache.felix.jmood.core.ManagedServiceMBean#getBundle()

+     */

+    public String getBundle() {

+        return InstrumentationSupport.getSymbolicName(svc.getBundle());

+    }

+    /* (non-Javadoc)

+     * @see org.apache.felix.jmood.core.ManagedServiceMBean#getProperties()

+     */

+    public Hashtable getProperties() {

+    	String[] keys=svc.getPropertyKeys();

+    	Hashtable ht=new Hashtable();

+    	for (int i = 0; i < keys.length; i++) {

+			ht.put(keys[i], svc.getProperty(keys[i]));

+		}

+        return ht;

+    }

+    /* (non-Javadoc)

+     * @see org.apache.felix.jmood.core.ManagedServiceMBean#getUsingBundles()

+     */

+    public String[] getUsingBundles() {

+        return InstrumentationSupport.getSymbolicNames(svc.getUsingBundles());

+    }

+    public String[] getServiceInterfaces(){

+    	return (String[]) svc.getProperty(Constants.OBJECTCLASS);

+    }

+}

diff --git a/org.apache.felix.jmood/src/main/java/org/apache/felix/jmood/core/ManagedServiceMBean.java b/org.apache.felix.jmood/src/main/java/org/apache/felix/jmood/core/ManagedServiceMBean.java
new file mode 100644
index 0000000..e8c1dd7
--- /dev/null
+++ b/org.apache.felix.jmood/src/main/java/org/apache/felix/jmood/core/ManagedServiceMBean.java
@@ -0,0 +1,48 @@
+/*

+ *   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.jmood.core;

+

+import java.util.Hashtable;

+public interface ManagedServiceMBean {

+

+    /**

+     * 

+     * @return The registering bundle symbolic name

+     */

+    public abstract String getBundle();

+    

+    /**

+     * 

+     * @return a hashtable containing the same properties contained in

+     * the dictionary object used when registering the service. These include

+     * the standard mandatory service.id and objectClass properties as

+     * defined in the <i>org.osgi.framework.Constants</i> interface

+     * @see org.osgi.framework.Constants

+     */

+    public abstract Hashtable getProperties();

+

+    /**

+     * 

+     * @return the symbolic names of the bundles using the service

+     */

+    public abstract String[] getUsingBundles();

+    

+    public String[] getServiceInterfaces();

+

+

+}
\ No newline at end of file
diff --git a/org.apache.felix.jmood/src/main/java/org/apache/felix/jmood/core/NotImplementedException.java b/org.apache.felix.jmood/src/main/java/org/apache/felix/jmood/core/NotImplementedException.java
new file mode 100644
index 0000000..62d51f5
--- /dev/null
+++ b/org.apache.felix.jmood/src/main/java/org/apache/felix/jmood/core/NotImplementedException.java
@@ -0,0 +1,41 @@
+/*

+ *   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.jmood.core;

+public class NotImplementedException extends Exception {

+

+    public NotImplementedException() {

+        super();

+        // TODO Auto-generated constructor stub

+    }

+

+    public NotImplementedException(String message) {

+        super(message);

+        // TODO Auto-generated constructor stub

+    }

+

+    public NotImplementedException(String message, Throwable cause) {

+        super(message, cause);

+        // TODO Auto-generated constructor stub

+    }

+

+    public NotImplementedException(Throwable cause) {

+        super(cause);

+        // TODO Auto-generated constructor stub

+    }

+

+}

diff --git a/org.apache.felix.jmood/src/main/java/org/apache/felix/jmood/core/ServiceNotAvailableException.java b/org.apache.felix.jmood/src/main/java/org/apache/felix/jmood/core/ServiceNotAvailableException.java
new file mode 100644
index 0000000..9a0b3d8
--- /dev/null
+++ b/org.apache.felix.jmood/src/main/java/org/apache/felix/jmood/core/ServiceNotAvailableException.java
@@ -0,0 +1,42 @@
+/*

+ *   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.jmood.core;

+

+public class ServiceNotAvailableException extends Exception {

+

+    public ServiceNotAvailableException() {

+        super();

+        // TODO Auto-generated constructor stub

+    }

+

+    public ServiceNotAvailableException(String message) {

+        super(message);

+        // TODO Auto-generated constructor stub

+    }

+

+    public ServiceNotAvailableException(String message, Throwable cause) {

+        super(message, cause);

+        // TODO Auto-generated constructor stub

+    }

+

+    public ServiceNotAvailableException(Throwable cause) {

+        super(cause);

+        // TODO Auto-generated constructor stub

+    }

+

+}

diff --git a/org.apache.felix.jmood/src/main/java/org/apache/felix/jmood/core/instrumentation/BundleInfo.java b/org.apache.felix.jmood/src/main/java/org/apache/felix/jmood/core/instrumentation/BundleInfo.java
new file mode 100644
index 0000000..855bcd4
--- /dev/null
+++ b/org.apache.felix.jmood/src/main/java/org/apache/felix/jmood/core/instrumentation/BundleInfo.java
@@ -0,0 +1,171 @@
+/*

+ *   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.jmood.core.instrumentation;

+

+import java.io.Serializable;

+import java.util.Hashtable;

+public class BundleInfo implements Serializable {

+    

+    //mgmt attributes

+    private int startLevel;

+    private String state;

+    private ServiceInfo[] registeredServices; 

+    private ServiceInfo[] servicesInUse;

+    private Hashtable headers;

+    private long bundleId;

+    private PackageInfo[] exportedPackages; 

+    private PackageInfo[] importedPackages;

+    private BundleInfo[] fragments;

+    private BundleInfo[] hosts;

+    private BundleInfo[] requiredBundles;

+    private BundleInfo[] requiringBundles;

+    private long lastModified;

+    private String symbolicName;

+    //private String version; //Included in the headers except for required bundles

+    private boolean bundlePersistentlyStarted;

+    private boolean removalPending;

+    private boolean required; 

+    private boolean fragment; 

+//    private R4Permission[] permissions;//TODO This should include conditional permz as well as regular ones

+//    private R4Configuration[] configurations; //TODO

+    

+    public BundleInfo() {

+    }

+    

+    

+    ////////////GETTERS'n'SETTERS////////////////////////

+    public boolean isFragment() {

+        return fragment;

+    }

+

+

+    protected void setFragment(boolean fragment) {

+        this.fragment = fragment;

+    }

+

+

+    public long getLastModified() {

+        return lastModified;

+    }

+

+

+    protected void setLastModified(long lastModified) {

+        this.lastModified = lastModified;

+    }

+

+

+    public boolean isRequired() {

+        return required;

+    }

+

+

+    protected void setRequired(boolean required) {

+        this.required = required;

+    }

+    public long getBundleId() {

+        return bundleId;

+    }

+    protected void setBundleId(long bundleId) {

+        this.bundleId = bundleId;

+    }

+    public boolean isBundlePersistentlyStarted() {

+        return bundlePersistentlyStarted;

+    }

+    protected void setBundlePersistentlyStarted(boolean bundlePersistentlyStarted) {

+        this.bundlePersistentlyStarted = bundlePersistentlyStarted;

+    }

+    public PackageInfo[] getExportedPackages() {

+        return exportedPackages;

+    }

+    protected void setExportedPackages(PackageInfo[] exportedPackages) {

+        this.exportedPackages = exportedPackages;

+    }

+    public BundleInfo[] getFragments() {

+        return fragments;

+    }

+    protected void setFragments(BundleInfo[] fragments) {

+        this.fragments = fragments;

+    }

+    public Hashtable getHeaders() {

+        return headers;

+    }

+    protected void setHeaders(Hashtable headers) {

+        this.headers = headers;

+    }

+    public BundleInfo[] getHosts() {

+        return hosts;

+    }

+    protected void setHosts(BundleInfo[] hosts) {

+        this.hosts = hosts;

+    }

+    public PackageInfo[] getImportedPackages() {

+        return importedPackages;

+    }

+    protected void setImportedPackages(PackageInfo[] importedPackages) {

+        this.importedPackages = importedPackages;

+    }

+    public ServiceInfo[] getRegisteredServices() {

+        return registeredServices;

+    }

+    protected void setRegisteredServices(ServiceInfo[] registeredServices) {

+        this.registeredServices = registeredServices;

+    }

+    public boolean isRemovalPending() {

+        return removalPending;

+    }

+    protected void setRemovalPending(boolean removalPending) {

+        this.removalPending = removalPending;

+    }

+    public BundleInfo[] getRequiredBundles() {

+        return requiredBundles;

+    }

+    protected void setRequiredBundles(BundleInfo[] requiredBundles) {

+        this.requiredBundles = requiredBundles;

+    }

+    public BundleInfo[] getRequiringBundles() {

+        return requiringBundles;

+    }

+    protected void setRequiringBundles(BundleInfo[] requiringBundles) {

+        this.requiringBundles = requiringBundles;

+    }

+    public ServiceInfo[] getServicesInUse() {

+        return servicesInUse;

+    }

+    protected void setServicesInUse(ServiceInfo[] servicesInUse) {

+        this.servicesInUse = servicesInUse;

+    }

+    public int getStartLevel() {

+        return startLevel;

+    }

+    protected void setStartLevel(int startLevel) {

+        this.startLevel = startLevel;

+    }

+    public String getState() {

+        return state;

+    }

+    protected void setState(String state) {

+        this.state = state;

+    }

+    public String getSymbolicName() {

+        return symbolicName;

+    }

+    protected void setSymbolicName(String symbolicName) {

+        this.symbolicName = symbolicName;

+    }

+    

+}

diff --git a/org.apache.felix.jmood/src/main/java/org/apache/felix/jmood/core/instrumentation/FrameworkSnapshot.java b/org.apache.felix.jmood/src/main/java/org/apache/felix/jmood/core/instrumentation/FrameworkSnapshot.java
new file mode 100644
index 0000000..a0145f6
--- /dev/null
+++ b/org.apache.felix.jmood/src/main/java/org/apache/felix/jmood/core/instrumentation/FrameworkSnapshot.java
@@ -0,0 +1,245 @@
+/*

+ *   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.jmood.core.instrumentation;

+

+import java.util.Enumeration;

+import java.util.Hashtable;

+

+import org.apache.felix.jmood.AgentContext;

+import org.apache.felix.jmood.core.ServiceNotAvailableException;

+import org.apache.felix.jmood.utils.InstrumentationSupport;

+import org.osgi.framework.Bundle;

+import org.osgi.framework.Constants;

+import org.osgi.framework.ServiceReference;

+import org.osgi.service.packageadmin.ExportedPackage;

+

+public class FrameworkSnapshot {

+	private Hashtable bundles = new Hashtable(); //<Long, BundleInfo>

+

+	private Hashtable services = new Hashtable();//<Long, ServiceInfo>

+

+	private Hashtable packages = new Hashtable();//<String, PackageInfo>

+

+	private AgentContext ac;

+

+	private long timestamp;

+

+	public FrameworkSnapshot(AgentContext ac) {

+		super();

+		this.ac = ac;

+		this.populate();

+	}

+

+	public long getShotTime() {

+		return timestamp;

+	}

+

+	public void refreshSnapshot() {

+		bundles = new Hashtable();

+		services = new Hashtable();

+		packages = new Hashtable();

+		this.populate();

+		ac.debug("factory-bundles found: " + bundles.size());

+		ac.debug("factory-services found: " + services.size());

+		ac.debug("factory-packages found: " + packages.size());

+

+	}

+

+	public BundleInfo[] getAllBundles() {

+		Enumeration b = bundles.elements();

+		BundleInfo[] binfo = new BundleInfo[bundles.size()];

+		for (int i = 0; i < binfo.length; i++) {

+			binfo[i] = (BundleInfo) b.nextElement();

+		}

+		return binfo;

+	}

+

+	public ServiceInfo[] getAllServiceInfo() {

+		Enumeration s = services.elements();

+		ServiceInfo[] sinfo = new ServiceInfo[services.size()];

+		for (int i = 0; i < sinfo.length; i++) {

+			sinfo[i] = (ServiceInfo) s.nextElement();

+		}

+		return sinfo;

+	}

+

+	public PackageInfo[] getAllPackageInfo() {

+		Enumeration p = packages.elements();

+		PackageInfo[] pinfo = new PackageInfo[packages.size()];

+		for (int i = 0; i < pinfo.length; i++) {

+			pinfo[i] = (PackageInfo) p.nextElement();

+		}

+		return pinfo;

+	}

+

+	// ///////////PRIVATE METHODS//////////////////////////

+

+	private void populate() {

+		Bundle[] bundles = ac.getBundleContext().getBundles();

+		BundleInfo[] binfo = new BundleInfo[bundles.length];

+		for (int i = 0; i < binfo.length; i++) {

+			binfo[i] = getBundleInfo(bundles[i]);

+		}

+		this.timestamp = System.currentTimeMillis();

+	}

+

+private BundleInfo getBundleInfo(Bundle bundle) {

+        if (bundle==null) return null;

+        ac.debug("creating R4 bundleinfo:  "+bundle.getSymbolicName());

+        Long key = new Long(bundle.getBundleId());

+        if (bundles.containsKey(key))

+            return (BundleInfo) bundles.get(key);

+        BundleInfo b = new BundleInfo();

+        b.setBundleId(bundle.getBundleId());

+        bundles.put(key, b);

+        try{

+            b.setFragments(this.getFragments(bundle));

+            b.setHeaders(InstrumentationSupport.getHashtable(bundle.getHeaders()));

+            b.setLastModified(bundle.getLastModified());

+            b.setRegisteredServices(this.getSvcsInfo(bundle.getRegisteredServices()));

+        	b.setBundlePersistentlyStarted(InstrumentationSupport.isBundlePersistentlyStarted(bundle, ac));

+        	b.setStartLevel(InstrumentationSupport.getBundleStartLevel(bundle, ac));

+        	b.setExportedPackages(this.getPkgInfo(InstrumentationSupport.getExportedPackages(bundle, ac)));

+        	b.setFragment(InstrumentationSupport.isFragment(bundle, ac));

+        	b.setRequired(InstrumentationSupport.isBundleRequired(bundle, ac));

+        	b.setRemovalPending(InstrumentationSupport.isRequiredBundleRemovalPending(bundle, ac));

+        	b.setRequiredBundles(this.getBundleDependencies(bundle));

+        	b.setRequiringBundles(this.getBInfos(InstrumentationSupport.getRequiringBundles(bundle, ac)));

+        	b.setImportedPackages(this.getImportedPackages(bundle));

+        }catch(ServiceNotAvailableException sae){

+        	//Not needed, since they are default values, placed for clarity

+        	b.setBundlePersistentlyStarted(false);

+        	b.setStartLevel(-1);

+        	b.setExportedPackages(null);

+        	b.setFragment(false);

+        	b.setRequired(false);

+        	b.setRemovalPending(false);

+            b.setRequiredBundles(null);

+            b.setRequiringBundles(null);

+            b.setImportedPackages(null);

+            ac.warning(sae.getMessage());

+        }

+        b.setServicesInUse(this.getSvcsInfo(bundle.getServicesInUse()));

+        b.setState(InstrumentationSupport.getState(bundle.getState()));

+        b.setSymbolicName(bundle.getSymbolicName());

+        return b;

+    }	private ServiceInfo getServiceInfo(ServiceReference svc) {

+		if (svc == null)

+			return null;

+		ac.debug("Creating R4service for service id "

+				+ svc.getProperty(Constants.SERVICE_ID));

+		Long key = (Long) svc.getProperty(Constants.SERVICE_ID);

+		if (services.containsKey(key))

+			return (ServiceInfo) services.get(key);

+		ServiceInfo s = new ServiceInfo();

+		services.put(key, s);

+

+		// now we set the atts

+		s.setBundle(this.getBundleInfo(svc.getBundle()));

+		Bundle[] using = svc.getUsingBundles();

+		if (using != null) {

+			BundleInfo[] r4Using = new BundleInfo[using.length];

+			for (int i = 0; i < r4Using.length; i++) {

+				r4Using[i] = getBundleInfo(using[i]);

+			}

+			s.setUsingBundles(r4Using);

+		}

+		Hashtable props = new Hashtable();//<String, Object>

+		String[] keys=svc.getPropertyKeys();

+		for (int i=0; i<keys.length;i++) {

+			props.put(keys[i], svc.getProperty(keys[i]));

+		}

+		s.setProperties(props);

+		return s;

+

+	}

+

+	private PackageInfo getPackageInfo(ExportedPackage pkg) {

+		if (pkg == null)

+			return null;

+		ac.debug("Creating PackageInfo for package " + pkg.getName());

+		String key = pkg.getName();

+		if (packages.containsKey(key))

+			return (PackageInfo) packages.get(key);

+		PackageInfo p = new PackageInfo();

+		packages.put(key, p);

+		p.setExportingBundle(getBundleInfo(pkg.getExportingBundle()));

+		Bundle[] importing = pkg.getImportingBundles();

+		if (importing != null) {

+			BundleInfo[] r4importing = new BundleInfo[importing.length];

+			for (int i = 0; i < r4importing.length; i++) {

+				r4importing[i] = getBundleInfo(importing[i]);

+			}

+			p.setImportingBundles(r4importing);

+		}

+		p.setName(pkg.getName());

+		p.setRemovalPending(pkg.isRemovalPending());

+		p.setVersion(pkg.getVersion().toString());

+		return p;

+	}

+

+	private BundleInfo[] getFragments(Bundle bundle) throws ServiceNotAvailableException{

+		Bundle[] fragments = ac.getPackageadmin().getFragments(bundle);

+		if (fragments == null)

+			return null;

+		BundleInfo[] r4fragments = new BundleInfo[fragments.length];

+		for (int i = 0; i < fragments.length; i++) {

+			r4fragments[i] = getBundleInfo(fragments[i]);

+		}

+		return r4fragments;

+	}

+

+	private ServiceInfo[] getSvcsInfo(ServiceReference[] svcs) {

+		if (svcs == null)

+			return null;

+		ServiceInfo[] r4svcs = new ServiceInfo[svcs.length];

+		for (int i = 0; i < svcs.length; i++) {

+			r4svcs[i] = getServiceInfo(svcs[i]);

+		}

+		return r4svcs;

+	}

+

+	private PackageInfo[] getImportedPackages(Bundle bundle) throws ServiceNotAvailableException {

+			return this.getPkgInfo(InstrumentationSupport.getImportedPackages(bundle, ac));

+	}

+

+	private PackageInfo[] getPkgInfo(ExportedPackage[] pkgs) {

+		if (pkgs == null)

+			return null;

+		PackageInfo[] r4pkgs = new PackageInfo[pkgs.length];

+		for (int i = 0; i < pkgs.length; i++) {

+			r4pkgs[i] = getPackageInfo(pkgs[i]);

+		}

+		return r4pkgs;

+	}

+

+

+	private BundleInfo[] getBundleDependencies(Bundle bundle) throws ServiceNotAvailableException {

+			Bundle[] required = InstrumentationSupport.getBundleDependencies(bundle, ac);

+			return this.getBInfos(required); 

+		}

+	private BundleInfo[] getBInfos(Bundle[] bundles){

+		if(bundles==null) return null;

+		BundleInfo[] info = new BundleInfo[bundles.length];

+		for (int i = 0; i < info.length; i++) {

+			info[i] = getBundleInfo(bundles[i]);

+		}

+		return info;

+		

+	}

+}

diff --git a/org.apache.felix.jmood/src/main/java/org/apache/felix/jmood/core/instrumentation/PackageInfo.java b/org.apache.felix.jmood/src/main/java/org/apache/felix/jmood/core/instrumentation/PackageInfo.java
new file mode 100644
index 0000000..dfbd4b7
--- /dev/null
+++ b/org.apache.felix.jmood/src/main/java/org/apache/felix/jmood/core/instrumentation/PackageInfo.java
@@ -0,0 +1,72 @@
+/*

+ *   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.jmood.core.instrumentation;

+

+import java.io.Serializable;

+

+public class PackageInfo implements Serializable{

+    private BundleInfo exportingBundle;

+    private BundleInfo [] importingBundles;

+    private String name;

+    private String version;

+    private boolean removalPending;

+    

+    public PackageInfo() {

+        super();

+    }

+

+    public BundleInfo getExportingBundle() {

+        return exportingBundle;

+    }

+

+    protected void setExportingBundle(BundleInfo exportingBundle) {

+        this.exportingBundle = exportingBundle;

+    }

+

+    public BundleInfo[] getImportingBundles() {

+        return importingBundles;

+    }

+

+    protected void setImportingBundles(BundleInfo[] importingBundles) {

+        this.importingBundles = importingBundles;

+    }

+

+    public String getName() {

+        return name;

+    }

+

+    protected void setName(String name) {

+        this.name = name;

+    }

+

+    public boolean isRemovalPending() {

+        return removalPending;

+    }

+

+    protected void setRemovalPending(boolean removalPending) {

+        this.removalPending = removalPending;

+    }

+

+    public String getVersion() {

+        return version;

+    }

+

+    protected void setVersion(String version) {

+        this.version = version;

+    }

+}

diff --git a/org.apache.felix.jmood/src/main/java/org/apache/felix/jmood/core/instrumentation/ServiceInfo.java b/org.apache.felix.jmood/src/main/java/org/apache/felix/jmood/core/instrumentation/ServiceInfo.java
new file mode 100644
index 0000000..4ea7feb
--- /dev/null
+++ b/org.apache.felix.jmood/src/main/java/org/apache/felix/jmood/core/instrumentation/ServiceInfo.java
@@ -0,0 +1,49 @@
+/*

+ *   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.jmood.core.instrumentation;

+

+import java.io.Serializable;

+import java.util.Hashtable;

+

+public class ServiceInfo implements Serializable{

+    private BundleInfo bundle;

+    private BundleInfo[] usingBundles;

+    private Hashtable properties;

+    public ServiceInfo() {

+        super();

+        // TODO Auto-generated constructor stub

+    }

+    public BundleInfo getBundle() {

+        return bundle;

+    }

+    protected void setBundle(BundleInfo bundle) {

+        this.bundle = bundle;

+    }

+    public Hashtable getProperties() {

+        return properties;

+    }

+    protected void setProperties(Hashtable properties) {

+        this.properties = properties;

+    }

+    public BundleInfo[] getUsingBundles() {

+        return usingBundles;

+    }

+    protected void setUsingBundles(BundleInfo[] usingBundles) {

+        this.usingBundles = usingBundles;

+    }

+}

diff --git a/org.apache.felix.jmood/src/main/java/org/apache/felix/jmood/utils/CompositeDataItemNames.java b/org.apache.felix.jmood/src/main/java/org/apache/felix/jmood/utils/CompositeDataItemNames.java
new file mode 100644
index 0000000..0e1dde6
--- /dev/null
+++ b/org.apache.felix.jmood/src/main/java/org/apache/felix/jmood/utils/CompositeDataItemNames.java
@@ -0,0 +1,64 @@
+/*

+ *   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.jmood.utils;

+

+public interface CompositeDataItemNames {

+	public static final String BUNDLE_ID="BundleId";

+	public static final String BUNDLE_LOCATION="BundleLocation";

+	public static final String EVENT_TYPE="Type";

+	public static final String ENCODED_SERVICE="Service";

+	public static final String ENCODED_EXCEPTION="Throwable";

+	public static final String ENCODED_ROLE="Role";

+	public static final String OBJECT_CLASS="objectClass";

+	public static final String CLASSNAME="ClassName";

+	public static final String FILENAME="FileName";

+	public static final String LINE_NUMBER="LineNumber";

+	public static final String METHOD_NAME="MethodName";

+	public static final String IS_NATIVE_METHOD="isNativeMethod";

+	public static final String EXCEPTION_MESSAGE="Message";

+	public static final String STACK_TRACE="StackTrace";

+	public static final String KEYS_FOR_STRING_VALUES="KeysForStringValues";

+	public static final String KEYS_FOR_BYTEARRAY_VALUES="KeysForByteArrayValues";

+	public static final String STRING_VALUES="StringValues";

+	public static final String BYTEARRAY_VALUES="ByteArrayValues";

+	public static final String ENCODED_CREDENTIALS="credentials";

+	public static final String ROLE_NAME="name";

+	public static final String ROLE_TYPE="type";

+	public static final String ROLE_ENCODED_PROPERTIES="properties";

+	public static final String ENCODED_USER="User";

+	public static final String GROUP_MEMBERS="members";

+	public static final String GROUP_REQUIRED_MEMBERS="requiredMembers";

+	public static final String USER_NAME="UserName";

+	public static final String ROLE_NAMES="RoleNames";

+	public static final String LOG_LEVEL="Level";

+	public static final String LOG_MESSAGE="Message";

+	public static final String LOG_TIME="Time";

+	public static final String[] AUTHORIZATION={USER_NAME,ROLE_NAMES};

+	public static final String[] BUNDLE_EVENT={BUNDLE_ID,BUNDLE_LOCATION, EVENT_TYPE};

+	public static final String[] SERVICE_EVENT={ENCODED_SERVICE, EVENT_TYPE};

+	public static final String[] USER_EVENT={EVENT_TYPE, ENCODED_ROLE, ENCODED_SERVICE};

+	public static final String[] FRAMEWORK_EVENT={BUNDLE_ID,BUNDLE_LOCATION, ENCODED_EXCEPTION,EVENT_TYPE };

+	public static final String[] SERVICE={BUNDLE_ID,BUNDLE_LOCATION,OBJECT_CLASS};

+	public static final String[] STACK_TRACE_ELEMENT={CLASSNAME,FILENAME,LINE_NUMBER,METHOD_NAME,IS_NATIVE_METHOD};

+	public static final String[] EXCEPTION={EXCEPTION_MESSAGE,STACK_TRACE};

+	public static final String[] ROLE_PROPERTIES={KEYS_FOR_STRING_VALUES,KEYS_FOR_BYTEARRAY_VALUES,STRING_VALUES,BYTEARRAY_VALUES};

+	public static final String[] USER_CREDENTIALS=ROLE_PROPERTIES;

+	public static final String[] USER={ENCODED_ROLE,ENCODED_CREDENTIALS};

+	public static final String[] ROLE={ROLE_NAME,ROLE_TYPE,ROLE_ENCODED_PROPERTIES};

+	public static final String[] GROUP={ENCODED_USER,GROUP_MEMBERS,GROUP_REQUIRED_MEMBERS};

+	public static final String[] LOG_ENTRY={BUNDLE_ID,BUNDLE_LOCATION, ENCODED_EXCEPTION,LOG_LEVEL,LOG_MESSAGE,ENCODED_SERVICE,LOG_TIME};

+}

diff --git a/org.apache.felix.jmood/src/main/java/org/apache/felix/jmood/utils/InstrumentationSupport.java b/org.apache.felix.jmood/src/main/java/org/apache/felix/jmood/utils/InstrumentationSupport.java
new file mode 100644
index 0000000..efa9af5
--- /dev/null
+++ b/org.apache.felix.jmood/src/main/java/org/apache/felix/jmood/utils/InstrumentationSupport.java
@@ -0,0 +1,293 @@
+/*

+ *   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.jmood.utils;

+

+import java.util.Dictionary;

+import java.util.Enumeration;

+import java.util.Hashtable;

+import java.util.Vector;

+

+import org.apache.felix.jmood.AgentContext;

+import org.apache.felix.jmood.core.BundleNotAvailableException;

+import org.apache.felix.jmood.core.ServiceNotAvailableException;

+import org.osgi.framework.Bundle;

+import org.osgi.framework.Constants;

+import org.osgi.framework.ServiceReference;

+import org.osgi.service.packageadmin.ExportedPackage;

+import org.osgi.service.packageadmin.PackageAdmin;

+import org.osgi.service.packageadmin.RequiredBundle;

+

+

+/**

+ * This class contains helper methods 

+ * 

+ *

+ */

+public class InstrumentationSupport {

+	private AgentContext ac;

+	public InstrumentationSupport(AgentContext ac){

+		this.ac=ac;

+	}

+    /**

+     * <p>For each BundleInfo, this method returns the symbolic name String, which we define as the concatenation of  

+     * the getSymbolicName of the <code>Bundle</code> interface and the bundle version as specified 

+     * in the bundle header. Both parts are divided by a semicolon. An example would be:</p>

+     * <p>

+     * <code>com.acme.foo;1.0.0</code>

+     * </p>

+     * @param bundles The <code>Bundle</code> array to be converted

+     * @return The String array

+     * @see org.osgi.framework.Bundle#getSymbolicName()

+     */

+    public static String[] getSymbolicNames(Bundle[] bundles) {

+        if(bundles==null) return null;

+        String[] names=new String[bundles.length];

+        for (int i = 0; i < names.length; i++) {

+            names[i]=getSymbolicName(bundles[i]);

+        }

+        return names;

+    }

+    public static String getSymbolicName(Bundle bundle){

+        return bundle.getSymbolicName()+";"+bundle.getHeaders().get(Constants.BUNDLE_VERSION);

+    	

+    }

+

+    /**

+     * <p>

+     * 

+     * OSGi exported packages can be uniquely identified by the tuple (packageName, packageVersion). 

+     * This methods returns a String array representing those packages with the following syntax:

+     * </p>

+     * <p>

+     * <i>packageName</i>;<i>packageVersion</i> 

+     * </p><p>

+     * where packageName is as returned by the method <i>getName()</i> and packageVersion as returned by the method <i>getVersion()</i>

+     * in package admin's <code>ExportedPackage</code> class.

+     * </p>

+     * @param packages The <code>ExportedPackage</code> array to be converted

+     * @return The String array

+     * @see org.osgi.service.packageadmin.ExportedPackage

+     */

+    public static String[] getPackageNames(ExportedPackage[] packages) {

+        if (packages==null) return null;

+        String[] names=new String[packages.length];

+        for (int i = 0; i < names.length; i++) {

+            names[i]=getPackageName(packages[i]);

+        }

+        return names;

+    

+    }

+	public static String getPackageName(ExportedPackage pkg) {

+		return pkg.getName()+";"+pkg.getVersion().toString();

+	}

+

+

+    /**

+     * <p>

+     * OSGi Services can be registered under more than one interface (objectClass in 

+     * the spec). Services have a mandatory unique service id (as defined in the SERVICE_ID property of the org.osgi.framework.Constants interface), during their lifetime (i.e, until they are 

+     * garbage collected). To show this information in a consistent way, we use the following String representation

+     * of the service:

+     * </p>

+     * <p>

+     * <i>objectClass1</i>[;<i>objectClass2</i>[;<i>objectClass3</i>...]]:<i>service.id</i> 

+     * </p><p>

+     * where objectClass1..objectClassN are the elements of the mandatory objectClass array

+     * included in the service property dictionary (and set by the framework at registration time. The property name is defined in <code>org.osgi.framework.Constants#OBJECTCLASS</code> 

+     * </p>

+     * @param services The <code>ServiceReference</code> array to be converted

+     * @return The String array

+     * @see org.osgi.framework.Constants#OBJECTCLASS

+     * @see org.osgi.framework.Constants#SERVICE_ID

+     * @see org.osgi.framework.ServiceReference

+     */

+    public static String[] getServiceNames(ServiceReference[] services) {

+        if(services==null) return null;

+        String[] names=new String[services.length];

+        for (int i = 0; i < names.length; i++) {

+            String[] objectClass=(String[])services[i].getProperty(Constants.OBJECTCLASS);

+            //We asume that the framework always returns a non-empty, non-null array.

+            StringBuffer sb=new StringBuffer(objectClass[0]);

+            for (int j = 1; j < objectClass.length; j++) {

+                sb.append(";");

+                sb.append(objectClass[j]);

+            }

+            sb.append(services[i].getProperty(Constants.SERVICE_ID));

+            names[i]=sb.toString();

+        }

+        return names;

+    }

+    public static ExportedPackage[] getImportedPackages(Bundle bundle, AgentContext ac) throws ServiceNotAvailableException {

+        Vector imported = new Vector();

+        Bundle[] allBundles = ac.getBundleContext().getBundles();

+        for (int i=0; i<allBundles.length;i++) {

+        	Bundle b=allBundles[i];

+            ExportedPackage[] eps=ac.getPackageadmin()

+            .getExportedPackages(b);

+            if(eps==null) continue;

+            exported: for (int j=0;j<eps.length;j++) {

+            	ExportedPackage ep = eps[j];

+                Bundle[] imp=ep.getImportingBundles();

+                if(imp==null) continue;

+                for (int k=0;k<imp.length;k++) {

+                	Bundle b2 =imp[k];

+                    if (b2.getBundleId() == bundle.getBundleId()) {

+                        imported.add(ep);

+                        continue exported;

+                    }

+                }

+            }

+        }

+        if (imported.size() == 0)

+            return null;

+        else return (ExportedPackage[])imported.toArray(new ExportedPackage[imported.size()]);

+

+    }

+    public static Bundle[] getRequiringBundles(Bundle bundle, AgentContext ac) throws ServiceNotAvailableException{

+        if (bundle==null) throw new IllegalArgumentException("Bundle argument should not be null");

+        if (bundle.getSymbolicName()==null) return null;

+        RequiredBundle[] required=ac.getPackageadmin().getRequiredBundles(bundle.getSymbolicName());

+        if (required==null) return null;

+            RequiredBundle b=null;

+            for (int i=0;i<required.length;i++) {

+                if(bundle.getBundleId()==required[i].getBundle().getBundleId()) {

+                    b=required[i];

+                    break;

+                }

+            }

+            if(b==null) {

+                ac.error(InstrumentationSupport.class.getName()+": required bundle should not be null!!!!", new Exception());

+                return null;

+            }

+            return b.getRequiringBundles();

+    }

+    public static Bundle[] getBundleDependencies(Bundle bundle, AgentContext ac) throws ServiceNotAvailableException{

+        Bundle[] all=ac.getBundleContext().getBundles();

+        Vector required=new Vector();

+        for (int i = 0; i < all.length; i++) {

+            Bundle[] requiring=getRequiringBundles(all[i], ac);

+            if (requiring==null) continue;

+            for (int j = 0; j < requiring.length; j++) {

+            	//If the solicited bundle is requiring the bundle all[i] we mark it as required

+				if (requiring[j].getBundleId()==bundle.getBundleId()) required.add(all[i]);

+			}

+        }

+        if (required.size()==0) return null;

+        return (Bundle[])required.toArray(new Bundle[required.size()]);

+    }

+    public static boolean isBundleRequired(Bundle bundle, AgentContext ac) throws ServiceNotAvailableException {

+    	if (getRequiredBundle(bundle, ac)==null) return false;

+    	return true;

+    }

+    public static boolean isRequiredBundleRemovalPending(Bundle bundle, AgentContext ac)throws ServiceNotAvailableException{

+    	RequiredBundle r=getRequiredBundle(bundle, ac);

+    	if (r==null) return false;

+    	return r.isRemovalPending();

+    }

+    public static RequiredBundle getRequiredBundle(Bundle bundle, AgentContext ac)throws ServiceNotAvailableException{

+        RequiredBundle[] required=ac.getPackageadmin().getRequiredBundles(bundle.getSymbolicName());

+        if(required==null) return null;

+        for (int i = 0; i < required.length; i++) {

+			if (required[i].getBundle().getBundleId()==bundle.getBundleId()) return required[i];

+		}

+    	return null;

+    }

+	public static String getState(int state) {

+		switch (state) {

+		case Bundle.ACTIVE:

+			return "ACTIVE";

+		case Bundle.INSTALLED:

+			return "INSTALLED";

+		case Bundle.RESOLVED:

+			return "RESOLVED";

+		case Bundle.STARTING:

+			return "STARTING";

+		case Bundle.STOPPING:

+			return "STOPPING";

+		case Bundle.UNINSTALLED:

+			return "UNINSTALLED";

+		}

+		return null;

+	}

+	public static boolean isBundlePersistentlyStarted(Bundle bundle, AgentContext ac)throws ServiceNotAvailableException{

+            // BUG in KNOPFLERFISH: isPersistentlyStarted throws NPE if called

+			// on System bundle

+            // Workaround: system bundle should always be persistently started, return true

+            if (bundle.getBundleId()==0) return true;

+            else

+            return ac.getStartLevel().isBundlePersistentlyStarted(bundle);

+            // End workaround

+	}

+

+	public static int getBundleStartLevel(Bundle bundle, AgentContext ac) throws ServiceNotAvailableException {

+        return ac.getStartLevel().getBundleStartLevel(bundle);

+	}

+

+	public static ExportedPackage[] getExportedPackages(Bundle bundle, AgentContext ac) throws ServiceNotAvailableException{

+	        return ac.getPackageadmin().getExportedPackages(bundle);

+	}

+

+	public static boolean isFragment(Bundle bundle, AgentContext ac) throws ServiceNotAvailableException{

+        if(ac.getPackageadmin().getBundleType(bundle)==PackageAdmin.BUNDLE_TYPE_FRAGMENT) return true;

+    	return false;

+	}

+	public static Hashtable getHashtable(Dictionary dic){

+			Hashtable ht = new Hashtable();

+			for (Enumeration keys = dic.keys(); keys.hasMoreElements();) {

+				Object key = keys.nextElement();

+				// Not inmutable, but unlikely to change

+				ht.put(key, dic.get(key));

+			}

+			return ht;

+		}

+    public static long getBundleId(String symbolicName, AgentContext ac) throws BundleNotAvailableException{

+        if(symbolicName==null) throw new IllegalArgumentException("Symbolic name cannot be null");

+        String  [] s=symbolicName.split(";");

+        if(s==null||s.length==0) throw new BundleNotAvailableException("Could not find bundle identified by "+symbolicName);

+    	Bundle[] bundles=ac.getBundleContext().getBundles();

+        long id=-1;

+        Vector candidates=new Vector();

+        for(int i=0;i<bundles.length;i++) {

+        	//First find all bundles with symbolicName

+        	String name=bundles[i].getSymbolicName();

+        	if(name==null) continue;

+        	if (s[0].equals(name)){ 

+            	candidates.add(new Long(bundles[i].getBundleId()));

+            }

+        }

+        //now search the one that matches the version

+        for(int i=0; i< candidates.size();i++){

+        	long cId=((Long)candidates.elementAt(i)).longValue();

+        	Bundle c=ac.getBundleContext().getBundle(cId);

+        	String version=(String)c.getHeaders().get(Constants.BUNDLE_VERSION);

+        	if(s.length==1){//no version available

+        		ac.debug("no version available for "+symbolicName);

+        		if(candidates.size()>1) throw new BundleNotAvailableException("could not distinguish among multiple candidates");

+        		if(candidates.size()==1) {

+        			id=cId;

+        			break;

+        		}

+        	}

+        	if (version.equals(s[1])) id=cId;

+        }

+        if(id==-1) throw new BundleNotAvailableException("No " + symbolicName+ "installed");

+        return id;

+    }

+

+

+}

diff --git a/org.apache.felix.jmood/src/main/java/org/apache/felix/jmood/utils/OSGi2JMXCodec.java b/org.apache.felix.jmood/src/main/java/org/apache/felix/jmood/utils/OSGi2JMXCodec.java
new file mode 100644
index 0000000..a9b414d
--- /dev/null
+++ b/org.apache.felix.jmood/src/main/java/org/apache/felix/jmood/utils/OSGi2JMXCodec.java
@@ -0,0 +1,305 @@
+/*

+ *   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.jmood.utils;

+import java.util.*;

+import javax.management.openmbean.*;

+import org.osgi.service.useradmin.*;

+import org.osgi.service.log.*;

+import org.osgi.framework.*;

+

+/**

+ * This class's task is to be in charge of all needed type conversions

+ * inside the management agent. This involves translating osgi-defined types

+ * to jmx's open types. It implements methods for obtaining open instances. 

+ * This class implements the singleton pattern.

+ * 

+ */

+//TODO this class is only used by log and useradmin mbeans, should be just remove it?

+public class OSGi2JMXCodec {

+	public static CompositeData encodeBundleEvent(BundleEvent event) throws Exception{

+		if(event==null) return null;

+		String[] itemNames=CompositeDataItemNames.BUNDLE_EVENT;

+		Object[] itemValues=new Object [3];

+		itemValues[0]=new Integer((int)event.getBundle().getBundleId());

+		itemValues[1]=event.getBundle().getLocation();

+		itemValues[2]=new Integer(event.getType());

+		return new CompositeDataSupport(

+			OSGiTypes.BUNDLEEVENT,

+			itemNames,

+			itemValues);

+	}

+	public static CompositeData encodeServiceEvent(ServiceEvent event) throws Exception{

+		if(event==null) return null;

+		String[] itemNames=CompositeDataItemNames.SERVICE_EVENT;

+		Object[] itemValues=new Object[2];

+		itemValues[0]=encodeService(event.getServiceReference());

+		itemValues[1]=new Integer(event.getType());

+		return new CompositeDataSupport(

+						OSGiTypes.SERVICEEVENT,

+						itemNames,

+						itemValues);

+		

+	}

+	public static CompositeData encodeFrameworkEvent(FrameworkEvent event) throws Exception{

+		if(event==null) return null;

+		String[] itemNames=CompositeDataItemNames.FRAMEWORK_EVENT;

+		Object[] itemValues=new Object[4];

+		itemValues[0]=new Integer((int)event.getBundle().getBundleId());

+		itemValues[1]=event.getBundle().getLocation();

+				if (event.getThrowable()==null) itemValues[2]=null;

+				else itemValues[2]=encodeException(event.getThrowable());

+				itemValues[3]=new Integer(event.getType());

+			return new CompositeDataSupport(

+						OSGiTypes.FRAMEWORKEVENT,

+						itemNames,

+						itemValues);

+

+	}

+	public static CompositeData encodeUserAdminEvent(UserAdminEvent event) throws Exception{

+		//type: better as a String or as a number? for the moment number.

+		//FUTURE WORK Enable some bulk methods in most used parts: optimization issue

+		if(event==null) return null;

+		String [] itemNames =CompositeDataItemNames.USER_EVENT;

+		Object[] itemValues=new Object[3];

+		itemValues[0]=new Integer(event.getType());

+		itemValues[1]=encodeRole(event.getRole());

+		itemValues[2]=encodeService(event.getServiceReference());

+		return new CompositeDataSupport(

+			OSGiTypes.USERADMINEVENT,

+			itemNames,

+			itemValues);

+		}

+	public static CompositeData[] encodeLog(Enumeration enumeration) throws Exception{

+		if(enumeration==null) return null;

+			Vector vector=new Vector();

+			while(enumeration.hasMoreElements()){

+				vector.add(encodeLogEntry((LogEntry)enumeration.nextElement()));

+			}

+			CompositeData[] value=new CompositeData[vector.size()];

+			vector.copyInto(value);

+			return value;

+	}

+	public static CompositeData encodeUser(User user) throws Exception {

+		if(user==null) return null;

+			String[] itemNames = CompositeDataItemNames.USER;

+			Object[] itemValues = new Object[2];

+			itemValues[0] = encodeRole((Role)user);

+			itemValues[1] =

+				OSGi2JMXCodec.encodeUserCredentials(user.getCredentials());

+			return new CompositeDataSupport(

+				OSGiTypes.USER,

+				itemNames,

+				itemValues);

+	}

+	public static CompositeData encodeRole(Role role) throws Exception {

+		if (role==null) return null;

+		Object[] itemValues = new Object[3];

+		itemValues[0] = role.getName();

+		itemValues[1] = new Integer(role.getType());

+		itemValues[2] =

+			OSGi2JMXCodec.encodeRoleProperties(role.getProperties());

+		CompositeData cdata =

+			new CompositeDataSupport(

+				OSGiTypes.ROLE,

+		 CompositeDataItemNames.ROLE,

+		 		itemValues);

+		return cdata;

+	}

+	public static CompositeData encodeGroup(Group group) throws Exception {

+		if(group==null) return null;

+		String[] itemNames = CompositeDataItemNames.GROUP;

+		Object[] itemValues = new Object[3];

+		itemValues[0] = encodeUser((User)group);

+		Role[] members = group.getMembers();

+		String[] membersNames;

+		if (members!=null){		

+				membersNames = new String[members.length];

+		for (int i = 0; i < members.length; i++)

+			membersNames[i] = members[i].getName();

+		}

+		else{ 

+		 membersNames=new String[0];

+		}

+		itemValues[1] = membersNames;

+		Role[] requiredMembers = group.getRequiredMembers();

+		String [] requiredMembersNames;

+		if(requiredMembers!=null){

+			requiredMembersNames = new String[requiredMembers.length];

+			for (int i = 0; i < requiredMembers.length; i++)

+				requiredMembersNames[i] = requiredMembers[i].getName();

+		}else requiredMembersNames=new String[0];

+		itemValues[2] = requiredMembersNames;

+		return new CompositeDataSupport(OSGiTypes.GROUP, itemNames, itemValues);

+	}

+	public static CompositeData encodeAuthorization(Authorization authorization)

+		throws Exception {

+			if(authorization==null) return null;

+		Object[] itemValues = new Object[2];

+		String[] itemNames = CompositeDataItemNames.AUTHORIZATION;

+		itemValues[0] = authorization.getName();

+		itemValues[1] = authorization.getRoles();

+		return new CompositeDataSupport(

+			OSGiTypes.AUTHORIZATION,

+			itemNames,

+			itemValues);

+	}

+	public static CompositeData encodeLogEntry(LogEntry entry)

+		throws Exception {

+			if (entry==null) return null;

+		String[] itemNames = CompositeDataItemNames.LOG_ENTRY;

+		Object[] itemValues = new Object[7];

+		itemValues[0] = new Integer((int) entry.getBundle().getBundleId());

+		itemValues[1] =entry.getBundle().getLocation();

+		itemValues[2] = OSGi2JMXCodec.encodeException(entry.getException());

+		itemValues[3] = new Integer(entry.getLevel());

+		itemValues[4] = entry.getMessage();

+		itemValues[5] =

+			OSGi2JMXCodec.encodeService(entry.getServiceReference());

+		itemValues[6] = new Integer((int) entry.getTime());

+		return new CompositeDataSupport(

+			OSGiTypes.LOGENTRY,

+			itemNames,

+			itemValues);

+	}

+	public static CompositeData encodeRoleProperties(Dictionary RoleProperties)

+		throws Exception {

+		if (RoleProperties==null) return null;

+		if(RoleProperties.isEmpty()) return null;

+		Enumeration propkeys= RoleProperties.keys();

+		Vector  byteKeys=new Vector();

+		Vector byteValues=new Vector();

+		Vector StringKeys=new Vector();

+		Vector StringValues=new Vector();

+		while(propkeys.hasMoreElements()){

+			Object key=propkeys.nextElement();

+			Object value= RoleProperties.get(key);

+			if ( value instanceof byte[] ) {

+				byteKeys.add(key);

+				byteValues.add(value);

+				}

+				else if (value instanceof String) {

+					 StringKeys.add(key);

+					 StringValues.add(value);

+			}

+		}

+		Byte[][] bvalues=new Byte[byteValues.size()][];

+		for(int i=0; i<byteValues.size();i++){

+			byte[] array=(byte[])byteValues.elementAt(i);

+			bvalues[i]=OSGi2JMXCodec.byte2Byte(array);

+		}

+		Object[] propsItemValues = new Object[4];

+		String[] bkeys = new String[byteKeys.size()];

+		byteKeys.copyInto(bkeys);

+		//byteValues.copyInto(bvalues);

+		String[] skeys = new String[StringKeys.size()];

+		StringKeys.copyInto(skeys);

+		String[] svalues = new String[StringValues.size()];

+		StringValues.copyInto(svalues);

+		propsItemValues[1] = bkeys;

+		propsItemValues[3] = bvalues;

+		propsItemValues[0] =skeys;

+		propsItemValues[2]=svalues;

+		return new CompositeDataSupport(

+			OSGiTypes.ROLEPROPERTIES,

+			CompositeDataItemNames.ROLE_PROPERTIES,

+			propsItemValues);

+	}

+	public static CompositeData encodeUserCredentials(Dictionary credentials)

+		throws Exception {

+			if (credentials==null) return null;

+			if(credentials.isEmpty())return null;

+		String[] itemNames = CompositeDataItemNames.USER_CREDENTIALS;

+		//For the moment, user credentials and role properties have the same structure...

+		CompositeData cdata=OSGi2JMXCodec.encodeRoleProperties(credentials);

+		Object[] values=cdata.getAll(CompositeDataItemNames.USER_CREDENTIALS);

+		return new CompositeDataSupport(

+			OSGiTypes.USERCREDENTIALS,

+			itemNames,

+			values);

+	}

+	public static CompositeData encodeService(ServiceReference service)

+		throws Exception {

+			if(service==null) return null;

+		Object[] itemValues = new Object[3];

+		String[] itemNames = CompositeDataItemNames.SERVICE;

+		int id;

+		String[] objectClass;

+		String BundleLocation;

+		if(service==null){

+			id=-1;

+			objectClass=new String[1];

+			objectClass[0]="No service related to this log entry";

+			BundleLocation="none";

+		}else {

+			id=(int) service.getBundle().getBundleId();

+			objectClass= (String[])service.getProperty(itemNames[1]);

+			BundleLocation=service.getBundle().getLocation();

+		}

+		itemValues[0] = new Integer(id);

+		itemValues[1] =BundleLocation;

+		itemValues[2] =objectClass;

+		return new CompositeDataSupport(

+			OSGiTypes.SERVICE,

+			itemNames,

+			itemValues);

+	}

+	public static CompositeData encodeException(Throwable throwable)

+		throws Exception {

+		if (throwable==null) return null;

+		Object[] itemValues = new Object[2];

+		String[] itemNames = CompositeDataItemNames.EXCEPTION;

+		String message;

+		if (throwable==null) message="This log entry has not an associated exception"; 

+		else message= throwable.getMessage();

+		itemValues[0] =message;

+		StackTraceElement[] stack=throwable.getStackTrace();

+		if(stack==null) itemValues[1]=null;

+		else{

+		CompositeData[] cstack=new CompositeData[stack.length];

+		for (int i=0;i<stack.length;i++) cstack[i]=encodeStackTraceElement(stack[i]);

+		itemValues[1]=cstack;

+		} 

+		return new CompositeDataSupport(

+			OSGiTypes.EXCEPTION,

+			itemNames,

+			itemValues);

+	}

+	public static CompositeData encodeStackTraceElement(StackTraceElement element) throws Exception{

+		Object[] itemValues = new Object[5];

+		String[] itemNames = CompositeDataItemNames.STACK_TRACE_ELEMENT;

+		itemValues[0]=element.getClassName();

+		itemValues[1]=element.getFileName();

+		itemValues[2]=new Integer(element.getLineNumber());

+		itemValues[3]=element.getMethodName();

+		itemValues[4]=new Boolean(element.isNativeMethod());

+		return new CompositeDataSupport(

+			OSGiTypes.STACKTRACE_ELEMENT,

+			itemNames,

+			itemValues);

+	}

+	public static byte[] Byte2byte(Byte[] bytes){

+		byte[] result=new byte[ bytes.length];

+		for(int i=0;i<bytes.length;i++) result[i]=bytes[i].byteValue();

+		return result;

+	}

+	public static Byte[] byte2Byte(byte[] bytes){

+		Byte[] result=new Byte[ bytes.length];

+		for(int i=0;i<bytes.length;i++) result[i]=new Byte(bytes[i]);

+		return result;

+

+	}

+}
\ No newline at end of file
diff --git a/org.apache.felix.jmood/src/main/java/org/apache/felix/jmood/utils/OSGiTypes.java b/org.apache.felix.jmood/src/main/java/org/apache/felix/jmood/utils/OSGiTypes.java
new file mode 100644
index 0000000..196cef9
--- /dev/null
+++ b/org.apache.felix.jmood/src/main/java/org/apache/felix/jmood/utils/OSGiTypes.java
@@ -0,0 +1,482 @@
+/*

+ *   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.jmood.utils;

+import javax.management.openmbean.*;

+/**

+ * This class defines open types in a static way for the management agent. An open type instance defines the structure of an open data.

+ * For more information on open types and open data see jmx specification.

+ *

+ */

+public class OSGiTypes {

+	public final static CompositeType USER;

+	public final static CompositeType ROLE;

+	public final static CompositeType GROUP;

+	public final static CompositeType USERADMINEVENT;

+	public final static CompositeType AUTHORIZATION;

+	public final static CompositeType LOGENTRY;

+	public final static CompositeType ROLEPROPERTIES;

+	public final static CompositeType USERCREDENTIALS;

+	public final static CompositeType SERVICE;

+	public final static CompositeType EXCEPTION;

+	public final static CompositeType BUNDLEEVENT;

+	public final static CompositeType SERVICEEVENT;

+	public final static CompositeType FRAMEWORKEVENT;

+	public final static CompositeType STACKTRACE_ELEMENT;

+	protected static OpenType[] DICTIONARYITEMTYPES = null;

+	//protected static String[] RoleItemNames = null;

+	//protected static String[] RolePropertiesItemNames = null;

+

+	static {

+		try {

+			DICTIONARYITEMTYPES = new OpenType[4];

+			DICTIONARYITEMTYPES[0] = new ArrayType(1, SimpleType.STRING);

+			DICTIONARYITEMTYPES[1] = new ArrayType(1, SimpleType.STRING);

+			DICTIONARYITEMTYPES[2] = new ArrayType(1, SimpleType.STRING);

+			DICTIONARYITEMTYPES[3] = new ArrayType(2, SimpleType.BYTE);

+		} catch (Exception e) {

+			e.printStackTrace();

+		}

+		STACKTRACE_ELEMENT=createStackTraceElementType();	

+		ROLEPROPERTIES = createRolePropertiesType();

+		USERCREDENTIALS = createUserCredentialsType();

+		SERVICE = createServiceType();

+		EXCEPTION = createExceptionType();

+		ROLE = createRoleType();

+		USER = createUserType();

+		GROUP = createGroupType();

+		AUTHORIZATION = createAuthorizationType();

+		LOGENTRY = createLogEntryType();

+		USERADMINEVENT=createUserAdminEventType();

+		BUNDLEEVENT=createBundleEventType();

+		SERVICEEVENT=createServiceEventType();

+		FRAMEWORKEVENT=createFrameworkEventType();

+	}

+		private static CompositeType createBundleEventType(){

+			String description="This type encapsulates OSGi bundle events";

+			String[] itemNames=CompositeDataItemNames.BUNDLE_EVENT;

+			OpenType[] itemTypes=new OpenType[3];

+			String[] itemDescriptions=new String[3];

+		/*	itemNames[0]="BundleId";

+			itemNames[1]="BundleLocation";

+			itemNames[2]="Type";*/

+			itemTypes[0]=SimpleType.INTEGER;

+			itemTypes[1]=SimpleType.STRING;

+			itemTypes[2]=SimpleType.INTEGER;

+			itemDescriptions[0]="The ID of the bundle that generated this event";

+			itemDescriptions[1]="The location of the bundle that generated this event";

+			itemDescriptions[2]="The type of the event: {INSTALLED=1, STARTED=2, STOPPED=4, UPDATED=8, UNINSTALLED=16}";

+			try {

+				return new CompositeType(

+					"BundleEvent",

+					description,

+					itemNames,

+					itemDescriptions,

+					itemTypes);

+			} catch (OpenDataException e) {

+				e.printStackTrace();

+				return null;

+			}

+			

+		}

+		private static CompositeType createServiceEventType(){

+						String description="This type encapsulates OSGi service events";

+						String[] itemNames=CompositeDataItemNames.SERVICE_EVENT;

+						OpenType[] itemTypes=new OpenType[2];

+						String[] itemDescriptions=new String[2];

+						/*itemNames[0]="Service";

+						itemNames[1]="Type";

+						*/

+						itemTypes[0]=SERVICE;

+						itemTypes[1]=SimpleType.INTEGER;

+						itemDescriptions[0]="The service associated with this event";

+						itemDescriptions[1]="The type of the event: {REGISTERED=1, MODIFIED=2 UNREGISTERING=3}";

+						try {

+							return new CompositeType(

+								"ServiceEvent",

+								description,

+								itemNames,

+								itemDescriptions,

+								itemTypes);

+						} catch (OpenDataException e) {

+							e.printStackTrace();

+							return null;

+						}

+			

+		}

+		private static CompositeType createFrameworkEventType(){

+			String description="This type encapsulates OSGi framework events";

+			String[] itemNames=CompositeDataItemNames.FRAMEWORK_EVENT;

+			OpenType[] itemTypes=new OpenType[4];

+			String[] itemDescriptions=new String[4];

+			/*itemNames[0]="BundleId";

+			itemNames[1] ="BundleLocation";

+			itemNames[2]="Throwable";

+			itemNames[3]="Type";

+			*/

+			itemTypes[0]=SimpleType.INTEGER;

+			itemTypes[1]=SimpleType.STRING;

+			itemTypes[2]= EXCEPTION;

+			itemTypes[3]=SimpleType.INTEGER;

+			itemDescriptions[0]="The id of the bundle that os related to this event";

+			itemDescriptions[1]="The location of the bundle that os related to this event";

+			itemDescriptions[2]="The associated exception";

+			itemDescriptions[3]="The type of the event: {STARTED=1, ERROR=2, PACKAGES_REFRESHED=4, STARTLEVEL_CHANGED=8}";

+			try {

+				return new CompositeType(

+					"FrameworkEvent",

+					description,

+					itemNames,

+					itemDescriptions,

+					itemTypes);

+			} catch (OpenDataException e) {

+				e.printStackTrace();

+				return null;

+			}

+		}

+		private static CompositeType createUserAdminEventType(){

+			String description="This type encapsulates OSGi user admin events";

+			String[] itemNames=CompositeDataItemNames.USER_EVENT;

+			OpenType[] itemTypes=new OpenType[3];

+			String[] itemDescriptions=new String[3];

+			/*itemNames[0]="Type";

+			itemNames[1]="Role";

+			itemNames[2]="Service";

+			*/

+			itemTypes[0]=SimpleType.INTEGER;

+			itemTypes[1]=ROLE;

+			itemTypes[2]=SERVICE;

+			itemDescriptions[0]="The type of the event: {ROLE_CREATED= 1, ROLE_CHANGED=2, ROLE_REMOVED=4}";

+			itemDescriptions[1]="The role associated with this event";

+			itemDescriptions[2]="The UserAdmin service associated with this event. In some gateways, there might be more than one service available.";

+			try {

+				return new CompositeType(

+					"UserAdminEvent",

+					description,

+					itemNames,

+					itemDescriptions,

+					itemTypes);

+			} catch (OpenDataException e) {

+				e.printStackTrace();

+				return null;

+			}

+		}

+		private static CompositeType createServiceType() {

+		String description =

+			"The mapping of the service information for log entries";

+		String[] ServiceItemNames = CompositeDataItemNames.SERVICE;

+		/*ServiceItemNames[0] = "BundleId";

+		ServiceItemNames[1] = "BundleLocation";

+		ServiceItemNames[2] = "objectClass";*/

+		String[] itemDescriptions = new String[3];

+		itemDescriptions[0] =

+			"The id of the bundle which registered the service";

+		itemDescriptions[1] ="The location of the bundle that registered the service";

+		itemDescriptions[2] =

+			"An string array containing the interfaces under which the service has been registered";

+		OpenType[] itemTypes = new OpenType[3];

+		itemTypes[0] = SimpleType.INTEGER;

+		itemTypes[1] =SimpleType.STRING;

+		try {

+			itemTypes[2] = new ArrayType(1, SimpleType.STRING);

+			return new CompositeType(

+				"Service",

+				description,

+				ServiceItemNames,

+				itemDescriptions,

+				itemTypes);

+		} catch (OpenDataException e) {

+			e.printStackTrace();

+			return null;

+		}

+	}

+	private static CompositeType createStackTraceElementType() {

+		//classname,filename,int linenumber,string method name,boolean isNativeMethod	

+		String description = "The mapping for of stack trace's elements";

+		String[] itemNames =CompositeDataItemNames.STACK_TRACE_ELEMENT;

+		/*itemNames[0] = "ClassName";

+		itemNames[1]="FileName";

+		itemNames[2]="LineNumber";

+		itemNames[3]="MethodName";

+		itemNames[4]="isNativeMethod";*/

+		String[] itemDescriptions = new String[5];

+		itemDescriptions[0] = "the class where occured";

+		itemDescriptions[1]="the file name";

+		itemDescriptions[2] = "the line number";

+		itemDescriptions[3] = "the method name";

+		itemDescriptions[4] = "True if it is a native method";

+		OpenType[] itemTypes = new OpenType[5];

+		itemTypes[0] = SimpleType.STRING;

+		itemTypes[1] = SimpleType.STRING;

+		itemTypes[2] = SimpleType.INTEGER;

+		itemTypes[3] = SimpleType.STRING;

+		itemTypes[4] = SimpleType.BOOLEAN;

+		try {

+			return new CompositeType(

+				"Exception",

+				description,

+				itemNames,

+				itemDescriptions,

+				itemTypes);

+		} catch (OpenDataException e) {

+			e.printStackTrace();

+			return null;

+		}

+	}

+	private static CompositeType createExceptionType() {

+		String description = "The exception mapping for logging purposes";

+		String[] itemNames = CompositeDataItemNames.EXCEPTION;

+		/*itemNames[0] = "Message";

+		itemNames[1]="StackTrace";*/

+		String[] itemDescriptions = new String[2];

+		itemDescriptions[0] = "The exception's message";

+		itemDescriptions[1]="The exception's stack trace";

+		OpenType[] itemTypes = new OpenType[2];

+		itemTypes[0] = SimpleType.STRING;

+		try {

+			itemTypes[1] = new ArrayType(1, STACKTRACE_ELEMENT);

+			return new CompositeType(

+				"Exception",

+				description,

+				itemNames,

+				itemDescriptions,

+				itemTypes);

+		} catch (OpenDataException e) {

+			e.printStackTrace();

+			return null;

+		}

+

+	}

+	private static CompositeType createRolePropertiesType() {

+		String description =

+			"The properties dictionary mapping of a Role. It has four fields: KeysForStringValues, KeysForByteArrayValues, StringValues, ByteArrayValues";

+		String[] RolePropertiesItemNames = CompositeDataItemNames.ROLE_PROPERTIES;

+		/*RolePropertiesItemNames[0] = "KeysForStringValues";

+		RolePropertiesItemNames[1] = "KeysForByteArrayValues";

+		RolePropertiesItemNames[3] = "ByteArrayValues";

+		RolePropertiesItemNames[2] = "StringValues";*/

+		String[] itemDescriptions = new String[4];

+		itemDescriptions[0] =

+			"A string array containing the keys for the properties which are Strings";

+		itemDescriptions[1] =

+			"A string array containing the keys for the properties which are byte[]";

+		itemDescriptions[2] =

+			"A string array containing the values of the properties which are Strings";

+		itemDescriptions[3] =

+			"A 2D-array containing the values of the properties which are byte[]. byte[i] is the i-nth Byte[], whose key is at KeysForByteArrayValues[i]";

+		try {

+			return new CompositeType(

+				"RoleProperties",

+				description,

+				RolePropertiesItemNames,

+				itemDescriptions,

+				DICTIONARYITEMTYPES);

+		} catch (OpenDataException e) {

+			e.printStackTrace();

+			return null;

+		}

+	}

+

+	private static CompositeType createUserCredentialsType() {

+		//BUG possibly problems here with indexes which is which. review

+		String description = "The credentials for a user";

+		String[] itemNames = CompositeDataItemNames.USER_CREDENTIALS;

+		/*itemNames[0] = "KeysForStringValues";

+		itemNames[1] = "KeysForByteArrayValues";

+		itemNames[3] = "ByteArrayValues";

+		itemNames[2] = "StringValues";

+		*/

+		String[] itemDescriptions = new String[4];

+		itemDescriptions[0] =

+			"A string array containing the keys for the credentials which are Strings";

+		itemDescriptions[1] =

+			"A string array containing the keys for the credentials which are byte[]";

+		itemDescriptions[2] =

+			"A string array containing the values of the credentials which are Strings";

+		itemDescriptions[3] =

+			"A 2D-array containing the values of the credentials which are byte[]. byte[i] is the i-nth Byte[], whose key is at KeysForByteArrayValues[i]";

+		try {

+

+		return new CompositeType(

+				"UserCredentials",

+				description,

+				itemNames,

+				itemDescriptions,

+				OSGiTypes.DICTIONARYITEMTYPES);

+		} catch (OpenDataException e) {

+			e.printStackTrace();

+			return null;

+		}

+	}

+

+	private static CompositeType createUserType() {

+		//public CompositeType(String typeName, String description, String[] itemNames, String[] itemDescriptions, OpenType[] itemTypes)		

+		String description =

+			"Mapping of org.osgi.service.useradmin.User for remote management purposes. User extends Role";

+		String[] itemNames = CompositeDataItemNames.USER;

+		/*itemNames[0] = "Role";

+		itemNames[1] = "credentials";*/

+		String[] itemDescriptions = new String[2];

+		itemDescriptions[0] = "The role object that is extended by this user object";

+		itemDescriptions[1] = "The credentials for this user";

+		OpenType[] itemTypes = new OpenType[2];

+		itemTypes[0] = ROLE;

+		itemTypes[1] = USERCREDENTIALS;

+		try {

+

+			return new CompositeType(

+				"User",

+				description,

+				itemNames,

+				itemDescriptions,

+				itemTypes);

+		} catch (OpenDataException e) {

+			e.printStackTrace();

+			return null;

+		}

+	}

+	private static CompositeType createRoleType() {

+		createRolePropertiesType();

+		String description =

+			"Mapping of org.osgi.service.useradmin.Role for remote management purposes. User and Group extend Role";

+		String []RoleItemNames = CompositeDataItemNames.ROLE;

+		/*RoleItemNames[0] = "name";

+		RoleItemNames[1] = "type";

+		RoleItemNames[2] = "properties";*/

+		String[] itemDescriptions = new String[3];

+		itemDescriptions[0] =

+			"The name of the role. Can be either a group or a user";

+		itemDescriptions[1] =

+			"An integer representing type of the role: {0=Role,1=user,2=group}";

+		itemDescriptions[2] =

+			"A properties list as defined by org.osgi.service.useradmin.Role";

+		OpenType[] itemTypes = new OpenType[3];

+		itemTypes[0] = SimpleType.STRING;

+		itemTypes[1] = SimpleType.INTEGER;

+		itemTypes[2] = ROLEPROPERTIES;

+		try {

+

+			return new CompositeType(

+				"Role",

+				description,

+				RoleItemNames,

+				itemDescriptions,

+				itemTypes);

+		} catch (OpenDataException e) {

+			e.printStackTrace();

+			return null;

+		}

+	}

+	private static CompositeType createGroupType() {

+		String description =

+			"Mapping of org.osgi.service.useradmin.Group for remote management purposes. Group extends User which in turn extends Role";

+		String[] itemNames = CompositeDataItemNames.GROUP;

+		/*itemNames[0] = "User";

+		itemNames[1] = "members";

+		itemNames[2] = "requiredMembers";

+		*/

+		String[] itemDescriptions = new String[3];

+		itemDescriptions[0] = "The user object that is extended by this group object";

+		itemDescriptions[1] = "The members of this group";

+		itemDescriptions[2] = "The required members for this group";

+		OpenType[] itemTypes = new OpenType[3];

+		itemTypes[0] = USER;

+		try {

+			itemTypes[1] = new ArrayType(1, SimpleType.STRING);

+			itemTypes[2] = new ArrayType(1, SimpleType.STRING);

+			return new CompositeType(

+				"Group",

+				description,

+				itemNames,

+				itemDescriptions,

+				itemTypes);

+		} catch (OpenDataException e) {

+			e.printStackTrace();

+			return null;

+		}

+	}

+	private static CompositeType createAuthorizationType() {

+		String description =

+			"An authorization object defines which roles has a user got";

+		String[] itemNames = CompositeDataItemNames.AUTHORIZATION;

+		/*itemNames[0] = "UserName";

+		itemNames[1] = "RoleNames";*/

+		String[] itemDescriptions = new String[2];

+		itemDescriptions[0] = "The user name for this authorization object";

+		itemDescriptions[1] =

+			"The names of the roles encapsulated by this auth object";

+		OpenType[] itemTypes = new OpenType[2];

+		itemTypes[0] = SimpleType.STRING;

+		try {

+			itemTypes[1] = new ArrayType(1, SimpleType.STRING);

+			return new CompositeType(

+				"Authorization",

+				description,

+				itemNames,

+				itemDescriptions,

+				itemTypes);

+		} catch (OpenDataException e) {

+			e.printStackTrace();

+			return null;

+		}

+	}

+	private static CompositeType createLogEntryType() {

+		String description =

+			"A log entry type encapsulates a org.osgi.service.log.LogEntry";

+		String[] itemNames = CompositeDataItemNames.LOG_ENTRY;

+		/*itemNames[0] = "BundleId";

+		itemNames[1] = "BundleLocation";

+		itemNames[2] = "Throwable";

+		itemNames[3] = "Level";

+		itemNames[4] = "Message";

+		itemNames[5] = "ServiceReference";

+		itemNames[6] = "Time";*/

+		String[] itemDescriptions = new String[7];

+		itemDescriptions[0] =

+			"The id for the bundle that generated the log entry";

+		itemDescriptions[1] =

+					"The location of the bundle that generated the log entry";

+		itemDescriptions[2] =

+			"The ExceptionType that caused the error, or null if there was none";

+		itemDescriptions[3] = "The level of entry: DEBUG, INFO, ERROR, WARNING";

+		itemDescriptions[4] = "The log message";

+		itemDescriptions[5] =

+			"The service that generated the log entry, or null if not available";

+		itemDescriptions[6] = "The time at which the exception occurred";

+		OpenType[] itemTypes = new OpenType[7];

+		itemTypes[0] = SimpleType.INTEGER;

+		itemTypes[1]=SimpleType.STRING;

+		itemTypes[2] = EXCEPTION;

+		itemTypes[3] = SimpleType.INTEGER;

+		itemTypes[4] = SimpleType.STRING;

+		

+		try {

+			itemTypes[5] = SERVICE;

+			itemTypes[6] = SimpleType.INTEGER;

+			return new CompositeType(

+				"LogEntry",

+				description,

+				itemNames,

+				itemDescriptions,

+				itemTypes);

+		} catch (OpenDataException e) {

+			e.printStackTrace();

+			return null;

+		}

+	}

+	

+}

diff --git a/org.apache.felix.jmood/src/main/java/org/apache/felix/jmood/utils/ObjectNames.java b/org.apache.felix.jmood/src/main/java/org/apache/felix/jmood/utils/ObjectNames.java
new file mode 100644
index 0000000..0a9b893
--- /dev/null
+++ b/org.apache.felix.jmood/src/main/java/org/apache/felix/jmood/utils/ObjectNames.java
@@ -0,0 +1,51 @@
+/*

+ *   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.jmood.utils;

+

+/**

+ * This interface holds the <code>ObjectName</code>s under which the

+ * core MBeans (<code>CoreControllerMBean</code>, <code>ManagedBundleMBean</code>, 

+ * <code>ManagedServiceMBean</code>) and <code>ManagedPackageMBean</code>

+ * Note that service, bundle and package data mbeans are created dynamically

+ * and need a dynamic property to be added to the objectName.

+ *

+ */

+public interface ObjectNames {

+    public static final String CORE= "osgi.core";

+    public static final String COMPENDIUM="osgi.compendium";

+    public static final String CORE_CONTROLLER=CORE+":type=controller";

+    public static final String FRAMEWORK=CORE+":type=framework";

+    public static final String BUNDLE=CORE+":type=bundle, symbolicName=";

+    public static final String SERVICE=CORE+":type=service, service.id=";

+    public static final String CM_SERVICE=COMPENDIUM+":service=cm, type=manager";

+    public static final String CM_OBJECT=COMPENDIUM+":service=cm, type=object,"; 

+    public static final String LOG_SERVICE = COMPENDIUM+":service=log";

+    public static final String UA_SERVICE = COMPENDIUM+":service=useradmin"; 

+

+    /**

+     * package mbean object names also contain a version property to 

+     * avoid <code>InstanceAlreadyExistsException</code> when two

+     * versions of the same package co-exist.  

+     */

+    public static final String PACKAGE=CORE+":type=package, name=";

+    public static final String ALLBUNDLES=CORE+":type=bundle,*";

+    public static final String ALLSERVICES=CORE+":type=service,*";

+    public static final String ALLPACKAGES=CORE+":type=package,*";

+    public static final String ALL_CM_OBJECT=COMPENDIUM+":service=cm, type=object,*";

+    

+}

diff --git a/org.apache.felix.jmood/src/main/resources/agent.properties b/org.apache.felix.jmood/src/main/resources/agent.properties
new file mode 100644
index 0000000..baa3218
--- /dev/null
+++ b/org.apache.felix.jmood/src/main/resources/agent.properties
@@ -0,0 +1,2 @@
+java.security.policy=simple.policy

+policy.embedded=true
\ No newline at end of file
diff --git a/org.apache.felix.jmood/src/main/resources/simple.policy b/org.apache.felix.jmood/src/main/resources/simple.policy
new file mode 100644
index 0000000..f6bec57
--- /dev/null
+++ b/org.apache.felix.jmood/src/main/resources/simple.policy
@@ -0,0 +1,4 @@
+grant {

+  permission java.security.AllPermission;

+};

+

diff --git a/org.apache.felix.jmood/src/site/site.xml b/org.apache.felix.jmood/src/site/site.xml
new file mode 100644
index 0000000..6a4774b
--- /dev/null
+++ b/org.apache.felix.jmood/src/site/site.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>

+<project name="Maven">

+  <bannerLeft>

+    <name>Maven</name>

+    <src>http://maven.apache.org/images/apache-maven-project.png</src>

+    <href>http://maven.apache.org/</href>

+  </bannerLeft>

+  <bannerRight>

+    <src>http://maven.apache.org/images/maven-small.gif</src>

+  </bannerRight>

+  <body>

+    <links>

+      <item name="Apache" href="http://www.apache.org/" />

+      <item name="Maven 1.0" href="http://maven.apache.org/"/>

+      <item name="Maven 2" href="http://maven.apache.org/maven2/"/>

+    </links>

+

+    <menu name="Maven 2.0">

+      <item name="Introduction" href="index.html"/>

+      <item name="Download" href="download.html"/>

+      <item name="Release Notes" href="release-notes.html" />

+      <item name="General Information" href="about.html"/>

+      <item name="For Maven 1.0 Users" href="maven1.html"/>

+      <item name="Road Map" href="roadmap.html" />

+    </menu>

+    ${reports}

+  </body>

+</project>
\ No newline at end of file
diff --git a/org.apache.felix.jmood/src/test/java/org/apache/felix/jmood/FelixLauncher.java b/org.apache.felix.jmood/src/test/java/org/apache/felix/jmood/FelixLauncher.java
new file mode 100644
index 0000000..70e9d5a
--- /dev/null
+++ b/org.apache.felix.jmood/src/test/java/org/apache/felix/jmood/FelixLauncher.java
@@ -0,0 +1,156 @@
+package org.apache.felix.jmood;

+/*

+ *   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.

+ *

+ */

+

+import java.io.BufferedReader;

+import java.io.File;

+import java.io.InputStreamReader;

+import java.util.ArrayList;

+import java.util.HashMap;

+import java.util.List;

+import java.util.Map;

+import java.util.logging.Logger;

+

+import javax.management.MBeanServerConnection;

+

+import org.apache.felix.framework.Felix;

+import org.apache.felix.framework.util.MutablePropertyResolver;

+import org.apache.felix.framework.util.MutablePropertyResolverImpl;

+import org.osgi.framework.Constants;

+public class FelixLauncher {

+

+    private MutablePropertyResolver props;

+	private Felix framework;

+	private List bundles;

+	private List packages;

+	private File cacheDir;

+	public FelixLauncher() {

+        super();

+    	cacheDir = new File("./cache");

+    	System.out.println(cacheDir.getAbsolutePath());

+		clearCache(cacheDir);

+    	cacheDir.mkdir();

+        

+        framework = new Felix();

+		Map m=new HashMap();

+		bundles=new ArrayList();

+		packages=new ArrayList();

+

+        props = new MutablePropertyResolverImpl(m);

+        props.put("felix.cache.profiledir", cacheDir.getAbsolutePath());

+

+    }

+	public void addBundle(String url){

+		if (!bundles.contains(url))

+		bundles.add(url);

+	}

+	public void addPackage(String packageName){

+		if(!packages.contains(packageName))

+		packages.add(packageName);

+	}

+	public void start(){

+		StringBuffer autostart=new StringBuffer();

+		for (int i=0; i<bundles.size(); i++){

+			String bundle=(String)bundles.get(i);

+			autostart.append(bundle).append(" ");

+		}

+		props.put("felix.auto.start.1", autostart.toString());

+		StringBuffer spkg=new StringBuffer((String)packages.get(0));

+		packages.remove(0);

+		for (int i=0; i<packages.size(); i++){

+			String pkg=(String)packages.get(i);

+			spkg.append(", "+pkg);

+		}

+		

+		

+        props.put(Constants.FRAMEWORK_SYSTEMPACKAGES, spkg.toString());

+

+        framework.start(props,null);

+	}

+	public void blockingStart() throws Exception{

+		this.start();

+        int to=0;

+        while(framework.getStatus()!=Felix.RUNNING_STATUS) {

+            Thread.sleep(10);

+            to++;

+            if(to>100) throw new Exception("timeout");

+        }

+

+	}

+	public void shutdown(){

+		framework.shutdown();

+		clearCache(cacheDir);

+	}

+

+	private void clearCache(File cacheDir) {

+		if(!isCache(cacheDir)){

+			System.out.println("not valid cache");

+			return;

+		}

+		File[] files=cacheDir.listFiles();

+		for(int i=0; i<files.length; i++){

+			recursiveDelete(files[i]);

+		}

+	}

+	private void recursiveDelete(File file){

+	   if(file.isDirectory()){

+			File[] files=file.listFiles();

+			for(int i=0; i<files.length; i++){

+				File f=files[i];	

+				recursiveDelete(f);

+		   }

+	   }

+	   file.delete();

+	}

+	private boolean isCache(File cacheDir){

+		if(!cacheDir.exists()||!cacheDir.isDirectory()) return false;

+		else{

+			String[] names=cacheDir.list();

+			for(int i=0;i<names.length;i++){

+				String name=names[i];

+				if(!name.startsWith("bundle")) return false;

+			}

+			return true;

+		}

+	}

+

+    /**

+     * @param args

+     */

+    public static void main(String[] args) throws Exception{

+    	FelixLauncher launcher=new FelixLauncher();

+        String jmood="file:target/org.apache.felix.jmood-0.8.0-SNAPSHOT.jar";

+        String jmxintrospector="file:../org.apache.felix.mishell/target/org.apache.felix.mishell-0.8.0-SNAPSHOT.jar";

+    	launcher.addBundle(jmood);

+    	launcher.addBundle(jmxintrospector);

+        launcher.addPackage("org.osgi.framework");

+        launcher.addPackage("org.osgi.util.tracker");

+        launcher.addPackage("org.osgi.service.log");

+        launcher.addPackage("org.osgi.service.packageadmin");

+        launcher.addPackage("org.osgi.service.startlevel");

+        launcher.addPackage("org.osgi.service.permissionadmin");

+        launcher.addPackage("org.osgi.service.useradmin");

+        launcher.addPackage("org.osgi.service.cm");

+        launcher.addPackage("javax.management");

+        launcher.addPackage("javax.management.remote");

+        launcher.addPackage("javax.script");

+    	launcher.start();

+    }

+	public Felix getFramework() {

+		return framework;

+	}

+}

diff --git a/org.apache.felix.jmood/src/test/java/org/apache/felix/jmood/core/BundleMBeanTestCase.java b/org.apache.felix.jmood/src/test/java/org/apache/felix/jmood/core/BundleMBeanTestCase.java
new file mode 100644
index 0000000..1f6908c
--- /dev/null
+++ b/org.apache.felix.jmood/src/test/java/org/apache/felix/jmood/core/BundleMBeanTestCase.java
@@ -0,0 +1,92 @@
+/*

+ *   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.jmood.core;

+import java.util.Iterator;

+import java.util.logging.Logger;

+

+import javax.management.InstanceNotFoundException;

+import javax.management.MBeanServerInvocationHandler;

+import javax.management.ObjectName;

+

+import org.apache.felix.jmood.core.ManagedBundleMBean;

+import org.apache.felix.jmood.core.ManagedServiceMBean;

+import org.osgi.framework.Bundle;

+import org.osgi.framework.Constants;

+

+import org.apache.felix.jmood.utils.ObjectNames;

+

+

+public class BundleMBeanTestCase extends TestHarness {

+//	private String bname="es.upm.dit.jmood;0.9.0";

+//	private static Logger l=Logger.getLogger(BundleMBeanTestCase.class.getPackage().getName());

+//	private ObjectName jmood;

+	public BundleMBeanTestCase() throws Exception{

+		super();

+//		jmood=new ObjectName(ObjectNames.BUNDLE+bname);

+	}

+	protected void setUp()throws Exception{

+		super.setUp();

+	}

+	protected void tearDown()throws Exception{

+		super.tearDown();

+	}

+	public void testAttributes() throws Exception{

+//		super.testAttributes(jmood,ManagedBundleMBean.class);

+//		l.finest("testing Start level attribute");

+//		getServer().getAttribute(jmood, "StartLevel");

+	}

+	public void testUpdateInvariant()throws Exception{

+		//JMood update should be invariant

+		//TODO Should we refresh?

+//		getServer().invoke(jmood,"update",null, null);

+//		boolean wait=true;

+//		String state=null;

+//		for(int i=0;wait&&i<10;i++){

+//			try{

+//				Thread.sleep(10);

+//		state=(String)(getServer().getAttribute(jmood,"State"));

+//		wait=state.equals("STOPPING")||state.equals("STARTING");

+//			}catch (InstanceNotFoundException e){}

+//		}

+//		assertTrue("state: "+state,state.equals("ACTIVE"));

+	}

+	public void testServiceMBeans()throws Exception{

+//		Iterator it=getServer().queryNames(new ObjectName(ObjectNames.ALLSERVICES), null).iterator();

+//		while(it.hasNext()){

+//			super.testAttributes((ObjectName) it.next(),ManagedServiceMBean.class);

+//		}

+	}

+	public void testBundleMBeans()throws Exception{

+//		Iterator it=getServer().queryNames(new ObjectName(ObjectNames.ALLBUNDLES), null).iterator();

+//		while(it.hasNext()){

+//			super.testAttributes((ObjectName) it.next(),ManagedBundleMBean.class);

+//		}

+	}

+	public void testPackageMBeans()throws Exception{

+//		//Currently fails for Felix because no package mbeans are registered

+//		Iterator it=getServer().queryNames(new ObjectName(ObjectNames.ALLSERVICES), null).iterator();

+//		while(it.hasNext()){

+//			super.testAttributes((ObjectName) it.next(),ManagedBundleMBean.class);

+//		}

+	}

+    public void testUpdate()throws Exception{

+//        ManagedBundleMBean bundle=(ManagedBundleMBean)MBeanServerInvocationHandler.newProxyInstance(getServer(), jmood, ManagedBundleMBean.class, false);

+//        l.info("Last modified: "+bundle.getSymbolicName());

+   }

+    

+}

diff --git a/org.apache.felix.jmood/src/test/java/org/apache/felix/jmood/core/CoreTestCase.java b/org.apache.felix.jmood/src/test/java/org/apache/felix/jmood/core/CoreTestCase.java
new file mode 100644
index 0000000..ca45e90
--- /dev/null
+++ b/org.apache.felix.jmood/src/test/java/org/apache/felix/jmood/core/CoreTestCase.java
@@ -0,0 +1,292 @@
+/*

+ *   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.jmood.core;

+import java.util.logging.Logger;

+

+import javax.management.MBeanServerInvocationHandler;

+import javax.management.ObjectName;

+import javax.management.RuntimeMBeanException;

+

+import junit.framework.Assert;

+

+import org.apache.felix.jmood.core.CoreControllerMBean;

+import org.apache.felix.jmood.core.ServiceNotAvailableException;

+import org.osgi.framework.BundleException;

+

+import org.apache.felix.jmood.utils.ObjectNames;

+

+public class CoreTestCase extends TestHarness {

+//    CoreControllerMBean core;

+    private static Logger l=Logger.getLogger(CoreTestCase.class.getPackage().getName());

+

+    public CoreTestCase() throws Exception {

+        super();

+    }

+

+    protected void setUp() throws Exception {

+        super.setUp();

+//        core = (CoreControllerMBean) MBeanServerInvocationHandler

+//                .newProxyInstance(getServer(), new ObjectName(

+//                        ObjectNames.CORE_CONTROLLER),

+//                        CoreControllerMBean.class, false);

+    }

+

+    protected void tearDown() throws Exception {

+        super.tearDown();

+    }

+

+    /*

+     * Test method for

+     * 'es.upm.dit.osgi.management.agent.core.CoreController.startBundle(String)'

+     */

+    public void testStartBundle() {

+

+    }

+

+    /*

+     * Test method for

+     * 'es.upm.dit.osgi.management.agent.core.CoreController.batchStartBundles(String[])'

+     */

+    public void testBatchStartBundles() {

+        // TODO Auto-generated method stub

+

+    }

+

+    /*

+     * Test method for

+     * 'es.upm.dit.osgi.management.agent.core.CoreController.stopBundle(String)'

+     */

+    public void testStopBundle() {

+        // TODO Auto-generated method stub

+

+    }

+

+    /*

+     * Test method for

+     * 'es.upm.dit.osgi.management.agent.core.CoreController.batchStopBundles(String[])'

+     */

+    public void testBatchStopBundles() {

+        // TODO Auto-generated method stub

+

+    }

+

+    /*

+     * Test method for

+     * 'es.upm.dit.osgi.management.agent.core.CoreController.updateBundle(String)'

+     */

+    public void testUpdateBundle() {

+        // TODO Auto-generated method stub

+

+    }

+

+    /*

+     * Test method for

+     * 'es.upm.dit.osgi.management.agent.core.CoreController.batchUpdateBundles(String[])'

+     */

+    public void testBatchUpdateBundles() {

+        // TODO Auto-generated method stub

+

+    }

+

+    /*

+     * Test method for

+     * 'es.upm.dit.osgi.management.agent.core.CoreController.updateBundleFromUrl(String,

+     * String)'

+     */

+    public void testUpdateBundleFromUrl() {

+        // TODO Auto-generated method stub

+

+    }

+

+    /*

+     * Test method for

+     * 'es.upm.dit.osgi.management.agent.core.CoreController.batchUpdateBundleFromUrl(String[],

+     * String[])'

+     */

+    public void testBatchUpdateBundleFromUrl() {

+        // TODO Auto-generated method stub

+

+    }

+

+    /*

+     * Test method for

+     * 'es.upm.dit.osgi.management.agent.core.CoreController.installBundle(String)'

+     */

+    public void testInstallBundle() throws Exception {

+//        String[] badUrls= {null, "MiCarro", "http://www.dit.upm.es"};

+//        for (int i = 0; i < badUrls.length; i++) {

+//            try {

+//                core.installBundle(badUrls[i]);

+//                assertTrue("Should've thrown bundle exception", false);

+//            } catch (BundleException e) {

+//                // OK

+//            }

+//        }

+//        String[] goodUrls= {"http://maquina:9000/testing/bundle1.jar", "http://maquina:9000/testing/bundle2.jar"};

+//        for (int i = 0; i < goodUrls.length; i++) {

+//                core.installBundle(goodUrls[i]);

+//        }

+    }

+

+    /*

+     * Test method for

+     * 'es.upm.dit.osgi.management.agent.core.CoreController.batchInstallBundle(String[])'

+     */

+    public void testBatchInstallBundle() throws Exception{

+//        String[] badUrls= {null, "MiCarro", "http://www.dit.upm.es"};

+//        try {

+//            core.batchInstallBundle(badUrls);

+//            assertTrue("Should've thrown bundle exception", false);

+//        } catch (BundleException e) {

+//            // OK

+//        }

+//        

+//        String[] goodUrls= {"http://maquina:9000/testing/bundle1.jar", "http://maquina:9000/testing/bundle2.jar"};

+//        core.batchInstallBundle(goodUrls);

+

+    }

+

+    /*

+     * Test method for

+     * 'es.upm.dit.osgi.management.agent.core.CoreController.setBundleStartLevel(String,

+     * int)'

+     */

+    public void testSetBundleStartLevel() {

+        // TODO Auto-generated method stub

+

+    }

+

+    /*

+     * Test method for

+     * 'es.upm.dit.osgi.management.agent.core.CoreController.batchSetBundleStartLevel(String[],

+     * int[])'

+     */

+    public void testBatchSetBundleStartLevel() {

+        // TODO Auto-generated method stub

+

+    }

+

+    /*

+     * Test method for

+     * 'es.upm.dit.osgi.management.agent.core.CoreController.refreshPackages(String[])'

+     */

+    public void testRefreshPackages() throws Exception{

+//        try {

+//        core.refreshPackages(null);

+//        }

+//        catch(RuntimeMBeanException e) {

+//            assertTrue(e.getTargetException() instanceof IllegalArgumentException);

+//        }

+//        core.refreshPackages(new String[] {"es.upm.dit.jmood;0.9.0"});

+//

+    }

+

+    /*

+     * Test method for

+     * 'es.upm.dit.osgi.management.agent.core.CoreController.resolveBundles(String[])'

+     */

+    public void testResolveBundles() throws Exception{

+//        try {

+//        core.resolveBundles(null);

+//        }

+//        catch(RuntimeMBeanException e) {

+//            assertTrue(e.getTargetException() instanceof IllegalArgumentException);

+//        }

+//        core.resolveBundles(new String[] {"es.upm.dit.jmood;0.9.0"});

+

+    }

+

+    /*

+     * Test method for

+     * 'es.upm.dit.osgi.management.agent.core.CoreController.setPlatformStartLevel(int)'

+     */

+    public void testSetPlatformStartLevel() {

+        // TODO Auto-generated method stub

+

+    }

+

+    /*

+     * Test method for

+     * 'es.upm.dit.osgi.management.agent.core.CoreController.getPlatformStartLevel()'

+     */

+    public void testGetPlatformStartLevel() {

+        // TODO Auto-generated method stub

+

+    }

+

+    /*

+     * Test method for

+     * 'es.upm.dit.osgi.management.agent.core.CoreController.setInitialBundleStartLevel(int)'

+     */

+    public void testSetInitialBundleStartLevel() throws Exception{

+//        int init=core.getInitialBundleStartLevel();

+//        l.info("INITIAL BUNDLE STARTLEVEL"+ init);

+//        int [] good= {1,10, 3};

+//        int [] bad= {-1,0};

+//        for (int i = 0; i < good.length; i++) {

+//            core.setInitialBundleStartLevel(good[i]);

+//            assertEquals(core.getInitialBundleStartLevel(), good[i]);

+//        }

+//        for (int i = 0; i < bad.length; i++) {

+//            try {

+//            core.setInitialBundleStartLevel(bad[i]);

+//            assertTrue(false);

+//            } catch(RuntimeMBeanException e) {

+//                assertTrue(e.getTargetException() instanceof IllegalArgumentException);

+//            }

+//        }

+

+    }

+

+    /*

+     * Test method for

+     * 'es.upm.dit.osgi.management.agent.core.CoreController.getInitialBundleStartLevel()'

+     */

+    public void testGetInitialBundleStartLevel() throws Exception{

+//        core.getInitialBundleStartLevel();

+

+    }

+

+    /*

+     * Test method for

+     * 'es.upm.dit.osgi.management.agent.core.CoreController.restartFramework()'

+     */

+    public void testRestartFramework() {

+        // TODO Auto-generated method stub

+

+    }

+

+    /*

+     * Test method for

+     * 'es.upm.dit.osgi.management.agent.core.CoreController.shutdownFramework()'

+     */

+    public void testShutdownFramework() {

+        // TODO Auto-generated method stub

+

+    }

+

+    /*

+     * Test method for

+     * 'es.upm.dit.osgi.management.agent.core.CoreController.updateFramework()'

+     */

+    public void testUpdateFramework() {

+        // TODO Auto-generated method stub

+

+    }

+

+}

diff --git a/org.apache.felix.jmood/src/test/java/org/apache/felix/jmood/core/TestHarness.java b/org.apache.felix.jmood/src/test/java/org/apache/felix/jmood/core/TestHarness.java
new file mode 100644
index 0000000..4293883
--- /dev/null
+++ b/org.apache.felix.jmood/src/test/java/org/apache/felix/jmood/core/TestHarness.java
@@ -0,0 +1,51 @@
+/*

+ *   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.jmood.core;

+import junit.framework.TestCase;

+

+import org.apache.felix.jmood.FelixLauncher;

+

+public class TestHarness extends TestCase {

+	private FelixLauncher launcher;

+	protected void setUp() throws Exception {

+		//ISSUE: this is not a unit test, but maven runs it as one

+		//before it builds the jar

+        super.setUp();

+        launcher=new FelixLauncher();

+        String jmood="file:target/org.apache.felix.jmood-0.8.0-SNAPSHOT.jar";

+        launcher.addBundle(jmood);

+        launcher.addPackage("org.osgi.framework");

+        launcher.addPackage("org.osgi.util.tracker");

+        launcher.addPackage("org.osgi.service.log");

+        launcher.addPackage("org.osgi.service.packageadmin");

+        launcher.addPackage("org.osgi.service.startlevel");

+        launcher.addPackage("org.osgi.service.permissionadmin");

+        launcher.addPackage("org.osgi.service.useradmin");

+        launcher.addPackage("org.osgi.service.cm");

+        launcher.addPackage("javax.management");

+        launcher.addPackage("javax.management.remote");

+        launcher.blockingStart();

+	}

+	protected void tearDown() throws Exception {

+		super.tearDown();

+		launcher.shutdown();

+	}

+	public void testDummy() {

+		//to avoid test not found assertion error

+	}

+}