You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@felix.apache.org by Karl Pauls <ka...@gmail.com> on 2007/07/09 19:00:53 UTC

Re: svn commit: r554318 [1/2] - in /felix/sandbox/donsez/monitoradmin: ./ doc/ src/ src/main/ src/main/java/ src/main/java/org/ src/main/java/org/apache/ src/main/java/org/apache/felix/ src/main/java/org/apache/felix/monitor/ src/main/java/org/osgi/

I see that this commit contains EPL licensed code. This should change
as soon as possible. I assume there is an ASL version available (since
this are files from OSGi)?

Other then that, I'd love to see somebody look into this since we
don't have an implementation of the MonitorAdmin atm.... Thanks for
making it available :-)

regards,

Karl

p.s.: do we have any convention regarding packages names for stuff in
the sandboxes? This one claims the org.apache.felix.monitor namespace
...

On 7/8/07, donsez@apache.org <do...@apache.org> wrote:
> Author: donsez
> Date: Sat Jul  7 22:49:38 2007
> New Revision: 554318
>
> URL: http://svn.apache.org/viewvc?view=rev&rev=554318
> Log:
> creation of the monitor bundle, an implementation of the monitor admin bundle
>
> Added:
>     felix/sandbox/donsez/monitoradmin/
>     felix/sandbox/donsez/monitoradmin/doc/
>     felix/sandbox/donsez/monitoradmin/doc/readme.html   (with props)
>     felix/sandbox/donsez/monitoradmin/pom.xml   (with props)
>     felix/sandbox/donsez/monitoradmin/src/
>     felix/sandbox/donsez/monitoradmin/src/main/
>     felix/sandbox/donsez/monitoradmin/src/main/java/
>     felix/sandbox/donsez/monitoradmin/src/main/java/org/
>     felix/sandbox/donsez/monitoradmin/src/main/java/org/apache/
>     felix/sandbox/donsez/monitoradmin/src/main/java/org/apache/felix/
>     felix/sandbox/donsez/monitoradmin/src/main/java/org/apache/felix/monitor/
>     felix/sandbox/donsez/monitoradmin/src/main/java/org/apache/felix/monitor/Constants.java   (with props)
>     felix/sandbox/donsez/monitoradmin/src/main/java/org/apache/felix/monitor/MonitorAdminImpl.java   (with props)
>     felix/sandbox/donsez/monitoradmin/src/main/java/org/osgi/
>     felix/sandbox/donsez/monitoradmin/src/main/java/org/osgi/service/
>     felix/sandbox/donsez/monitoradmin/src/main/java/org/osgi/service/monitor/
>     felix/sandbox/donsez/monitoradmin/src/main/java/org/osgi/service/monitor/MonitorAdmin.java   (with props)
>     felix/sandbox/donsez/monitoradmin/src/main/java/org/osgi/service/monitor/MonitorListener.java   (with props)
>     felix/sandbox/donsez/monitoradmin/src/main/java/org/osgi/service/monitor/MonitorPermission.java   (with props)
>     felix/sandbox/donsez/monitoradmin/src/main/java/org/osgi/service/monitor/Monitorable.java   (with props)
>     felix/sandbox/donsez/monitoradmin/src/main/java/org/osgi/service/monitor/MonitoringJob.java   (with props)
>     felix/sandbox/donsez/monitoradmin/src/main/java/org/osgi/service/monitor/StatusVariable.java   (with props)
>     felix/sandbox/donsez/monitoradmin/src/main/java/org/osgi/service/monitor/package.html   (with props)
>
> Added: felix/sandbox/donsez/monitoradmin/doc/readme.html
> URL: http://svn.apache.org/viewvc/felix/sandbox/donsez/monitoradmin/doc/readme.html?view=auto&rev=554318
> ==============================================================================
> --- felix/sandbox/donsez/monitoradmin/doc/readme.html (added)
> +++ felix/sandbox/donsez/monitoradmin/doc/readme.html Sat Jul  7 22:49:38 2007
> @@ -0,0 +1,71 @@
> +<!DOCTYPE doctype PUBLIC "-//w3c//dtd html 4.0 transitional//en">
> +<html>
> +<head>
> +  <meta http-equiv="Content-Type"
> + content="text/html; charset=iso-8859-1">
> +  <title>Monitor</title>
> +</head>
> +<body alink="#ff0000" vlink="#551a8b" link="#0000ee" bgcolor="#ffffff"
> + text="#000000">
> +<h1><i>Monitor</i></h1>
> +
> +<p><b>Description</b><br>
> +This bundle provides a MonitorAdmin service (Chapter 119 Monitor Admin Service Specification Version 1.0)
> +</p>
> +</font>
> +
> +<p><b>Contributor(s)</b><br>
> +Apache Felix Project Team</p>
> +
> +<p><b>License</b><br>
> +ASL2
> +</p>
> +
> +<p><b>Services</b><br>
> +<ul>
> +<li>org.osgi.service.monitor.MonitorAdmin</li>
> +<li>org.osgi.service.monitor.MonitorListener</li>
> +</ul>
> +</p>
> +
> +
> +<p><b>Provisions</b><br>
> +None
> +</p>
> +
> +<p id="doc"><b>Documentation</b><br>
> +<ul>
> +<li><a href=".">general</a></li>
> +<li><a href="api">JavaDoc</a></li>
> +</ul>
> +</p>
> +
> +<p><b>Demo</b><br>
> +run commands in <a href="http://www.apache.org/~donsez/dev/osgi/script/monitor.txt">http://www.apache.org/~donsez/dev/osgi/script/monitor.txt</a>.
> +</p>
> +
> +
> +
> +<p id="history"><b>History</b><br>
> +<ul>
> +<li>0.1.0 : first draft implementation from the chapter 119 OSGi Mobile (Draft November 7, 2005 8:36 pm)</li>
> +</ul>
> +</p>
> +
> +
> +
> +<p id="todolist"><b>TODOLIST</b><br>
> +<ul>
> +<li>security: check permissions (MonitorPermission)</li>
> +<li>complete monitoring job requester removal</li>
> +</ul>
> +</p>
> +
> +<p id="link"><b>Links</b><br>
> +<ul>
> +</ul>
> +</p>
> +
> +
> +</body>
> +</html>
>
> Propchange: felix/sandbox/donsez/monitoradmin/doc/readme.html
> ------------------------------------------------------------------------------
>     svn:eol-style = native
>
> Added: felix/sandbox/donsez/monitoradmin/pom.xml
> URL: http://svn.apache.org/viewvc/felix/sandbox/donsez/monitoradmin/pom.xml?view=auto&rev=554318
> ==============================================================================
> --- felix/sandbox/donsez/monitoradmin/pom.xml (added)
> +++ felix/sandbox/donsez/monitoradmin/pom.xml Sat Jul  7 22:49:38 2007
> @@ -0,0 +1,116 @@
> +<!--
> + Licensed to the Apache Software Foundation (ASF) under one
> + or more contributor license agreements.  See the NOTICE file
> + distributed with this work for additional information
> + regarding copyright ownership.  The ASF licenses this file
> + to you 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.
> +-->
> +<project>
> +
> +       <properties>
> +               <repositoryLocation>http://www.apache.org/~donsez/dev/osgi/</repositoryLocation>
> +               <description>provides an implementation of Monitor Admin.</description>
> +       </properties>
> +
> +  <parent>
> +    <groupId>org.apache.felix</groupId>
> +    <artifactId>felix</artifactId>
> +    <version>0.9.0-incubator-SNAPSHOT</version>
> +  </parent>
> +
> +  <modelVersion>4.0.0</modelVersion>
> +  <packaging>bundle</packaging>
> +  <name>Apache Felix Monitor Admin</name>
> +  <artifactId>org.apache.felix.monitor</artifactId>
> +  <description>${description}</description>
> +
> +  <dependencies>
> +    <dependency>
> +      <groupId>${pom.groupId}</groupId>
> +      <artifactId>org.osgi.core</artifactId>
> +      <version>${pom.version}</version>
> +    </dependency>
> +    <dependency>
> +      <groupId>${pom.groupId}</groupId>
> +      <artifactId>org.osgi.compendium</artifactId>
> +      <version>${pom.version}</version>
> +    </dependency>
> +  </dependencies>
> +  <build>
> +    <plugins>
> +      <plugin>
> +        <groupId>org.apache.felix</groupId>
> +        <artifactId>maven-bundle-plugin</artifactId>
> +        <extensions>true</extensions>
> +        <configuration>
> +          <instructions>
> +
> +               <!-- docs in http://cwiki.apache.org/FELIX/bundle-plugin-for-maven-bnd.html and http://cwiki.apache.org/FELIX/osgi-plugin-for-maven-2.html -->
> +
> +            <Export-Service>
> +               org.osgi.service.monitor.MonitorAdmin,
> +               org.osgi.service.monitor.MonitorListener
> +            </Export-Service>
> +
> +                       <Import-Service>
> +                               org.osgi.service.monitor.Monitorable,
> +                               org.osgi.service.event.EventAdmin
> +                       </Import-Service>
> +
> +            <Private-Package>${pom.artifactId}.*</Private-Package>
> +            <Import-Package>*</Import-Package>
> +            <!--
> +               org.osgi.framework;specification-version=1.3.0,
> +                               org.osgi.util.tracker;specification-version=1.3.0,
> +                               org.osgi.service.event;specification-version=1.0.0
> +                       -->
> +
> +            <Export-Package>org.osgi.service.monitor</Export-Package>
> +
> +            <Bundle-Activator>${pom.artifactId}.MonitorAdminImpl</Bundle-Activator>
> +
> +            <!--
> +            <Bundle-DocURL>${repositoryLocation}${pom.artifactId}/index.html</Bundle-DocURL>
> +            <Bundle-Url>${repositoryLocation}${pom.artifactId}/${pom.artifactId}-${pom.version}.jar</Bundle-Url>
> +            <Bundle-Source>${repositoryLocation}${pom.artifactId}/${pom.artifactId}-${pom.version}-src.jar</Bundle-Source>
> +                       -->
> +
> +            <!--
> +            <Bundle-SymbolicName>${pom.artifactId}</Bundle-SymbolicName>
> +            <Bundle-Description>${description}</Bundle-Description>
> +            <Bundle-Vendor>Apache Software Foundation</Bundle-Vendor>
> +                       -->
> +
> +          </instructions>
> +        </configuration>
> +      </plugin>
> +    </plugins>
> +  </build>
> +  <!--
> +  <repositories>
> +    <repository>
> +      <id>apache.m2.incubator</id>
> +      <name>Apache M2 Incubator Repository</name>
> +      <url>http://people.apache.org/repo/m2-incubating-repository/</url>
> +    </repository>
> +  </repositories>
> +  <pluginRepositories>
> +    <pluginRepository>
> +      <id>apache.m2.incubator</id>
> +      <name>Apache M2 Incubator Repository</name>
> +      <url>http://people.apache.org/repo/m2-incubating-repository/</url>
> +    </pluginRepository>
> +  </pluginRepositories>
> +  -->
> +</project>
>
> Propchange: felix/sandbox/donsez/monitoradmin/pom.xml
> ------------------------------------------------------------------------------
>     svn:eol-style = native
>
> Added: felix/sandbox/donsez/monitoradmin/src/main/java/org/apache/felix/monitor/Constants.java
> URL: http://svn.apache.org/viewvc/felix/sandbox/donsez/monitoradmin/src/main/java/org/apache/felix/monitor/Constants.java?view=auto&rev=554318
> ==============================================================================
> --- felix/sandbox/donsez/monitoradmin/src/main/java/org/apache/felix/monitor/Constants.java (added)
> +++ felix/sandbox/donsez/monitoradmin/src/main/java/org/apache/felix/monitor/Constants.java Sat Jul  7 22:49:38 2007
> @@ -0,0 +1,37 @@
> +/*
> + * Licensed to the Apache Software Foundation (ASF) under one
> + * or more contributor license agreements.  See the NOTICE file
> + * distributed with this work for additional information
> + * regarding copyright ownership.  The ASF licenses this file
> + * to you 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.monitor;
> +
> +/**
> + * this interface provides constants related to the Monitor Admin.
> + * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
> + */
> +
> +public interface Constants {
> +       // The events posted by MonitorAdmin contain the following properties:
> +       public final static String TOPIC = "org/osgi/service/monitor";
> +       // The identifier of the Monitorable
> +       public final static String MON_MONITORABLE_PID="mon.monitorable.pid";
> +       // The identifier of the StatusVariable within the given Monitorable
> +       public final static String MON_STATUSVARIABLE_NAME="mon.statusvariable.name";
> +       // The value of the StatusVariable, represented as a String
> +       public final static String MON_STATUSVARIABLE_VALUE="mon.statusvariable.value";
> +       // The identifier of the initiator of the monitoring job (only present if the event was generated due to a monitoring job)
> +       public final static String MON_LISTENER_ID="mon.listener.id";
> +}
>
> Propchange: felix/sandbox/donsez/monitoradmin/src/main/java/org/apache/felix/monitor/Constants.java
> ------------------------------------------------------------------------------
>     svn:eol-style = native
>
> Added: felix/sandbox/donsez/monitoradmin/src/main/java/org/apache/felix/monitor/MonitorAdminImpl.java
> URL: http://svn.apache.org/viewvc/felix/sandbox/donsez/monitoradmin/src/main/java/org/apache/felix/monitor/MonitorAdminImpl.java?view=auto&rev=554318
> ==============================================================================
> --- felix/sandbox/donsez/monitoradmin/src/main/java/org/apache/felix/monitor/MonitorAdminImpl.java (added)
> +++ felix/sandbox/donsez/monitoradmin/src/main/java/org/apache/felix/monitor/MonitorAdminImpl.java Sat Jul  7 22:49:38 2007
> @@ -0,0 +1,904 @@
> +/*
> + * Licensed to the Apache Software Foundation (ASF) under one
> + * or more contributor license agreements.  See the NOTICE file
> + * distributed with this work for additional information
> + * regarding copyright ownership.  The ASF licenses this file
> + * to you 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.monitor;
> +
> +import java.util.ArrayList;
> +import java.util.Dictionary;
> +import java.util.HashMap;
> +import java.util.Hashtable;
> +import java.util.Iterator;
> +import java.util.LinkedList;
> +import java.util.List;
> +import java.util.Map;
> +import java.util.SortedSet;
> +import java.util.TreeSet;
> +
> +import org.osgi.framework.Bundle;
> +import org.osgi.framework.BundleActivator;
> +import org.osgi.framework.BundleContext;
> +import org.osgi.framework.Constants;
> +import org.osgi.framework.ServiceFactory;
> +import org.osgi.framework.ServiceReference;
> +import org.osgi.framework.ServiceRegistration;
> +import org.osgi.service.event.Event;
> +import org.osgi.service.event.EventAdmin;
> +import org.osgi.service.monitor.MonitorAdmin;
> +import org.osgi.service.monitor.MonitorListener;
> +import org.osgi.service.monitor.Monitorable;
> +import org.osgi.service.monitor.MonitoringJob;
> +import org.osgi.service.monitor.StatusVariable;
> +import org.osgi.util.tracker.ServiceTracker;
> +import org.osgi.util.tracker.ServiceTrackerCustomizer;
> +
> +
> +/**
> + * this class provides an implementation of the Monitor Admin.
> + * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
> + */
> +
> +public class MonitorAdminImpl implements BundleActivator, org.apache.felix.monitor.Constants {
> +
> +       class MonitoringJobImpl implements MonitoringJob, MonitorListener {
> +
> +               private MonitorAdminProxy monitorAdminProxy;
> +
> +               private String initiator;
> +
> +               private String[] statusVariables;
> +
> +               private int schedule;
> +
> +               private int count;
> +
> +               private boolean isStopped=false;
> +
> +               private int currentCounter=0;
> +
> +               private Thread thread;
> +
> +               /**
> +                * @param monitorAdminProxy
> +                *            the monitorAdminProxy which start the job
> +                * @param initiator
> +                *            the identifier of the entity that initiated the job
> +                * @param statusVariables
> +                *            the list of StatusVariables to be monitored, with each
> +                *            StatusVariable name given in
> +                *            [Monitorable_PID]/[StatusVariable_ID] format
> +                * @param count
> +                *            the number of changes that must happen to a StatusVariable
> +                *            before a new notification is sent
> +                * @throws IllegalArgumentException
> +                * @throws SecurityException
> +                */
> +               public MonitoringJobImpl(
> +                               MonitorAdminProxy monitorAdminProxy, String initiator,
> +                               String[] statusVariables, int count)
> +                               throws IllegalArgumentException, SecurityException {
> +                       this.monitorAdminProxy = monitorAdminProxy;
> +                       this.initiator = initiator;
> +                       this.statusVariables = statusVariables;
> +                       this.count = count;
> +                       this.schedule = 0;
> +
> +                       subscribeStatusVariables();
> +               }
> +
> +
> +               /**
> +                * @param monitorAdminProxy
> +                *            the monitorAdminProxy which start the job
> +                * @param initiator
> +                *            the identifier of the entity that initiated the job
> +                * @param statusVariables
> +                *            the list of StatusVariables to be monitored, with each
> +                *            StatusVariable name given in
> +                *            [Monitorable_PID]/[StatusVariable_ID] format
> +                * @param schedule
> +                *            the time in seconds between two measurements
> +                * @param count
> +                *            the number of measurements to be taken, or 0 for the
> +                *            measurement to run until explicitely stopped
> +                *
> +                * @throws IllegalArgumentException
> +                * @throws SecurityException
> +                */
> +               public MonitoringJobImpl(
> +                               MonitorAdminProxy monitorAdminProxy, String initiator,
> +                               String[] statusVariables, int schedule, int count)
> +                               throws IllegalArgumentException, SecurityException {
> +                       this.monitorAdminProxy = monitorAdminProxy;
> +                       this.initiator = initiator;
> +                       this.statusVariables = statusVariables;
> +                       this.count = count;
> +                       this.schedule = schedule;
> +
> +                       thread=new Thread(new MyRunnable());
> +                       thread.start();
> +               }
> +
> +               class MyRunnable implements Runnable {
> +
> +                       public void run() {
> +                               while(!isStopped){ // TODO check if notification is before or after the sleep ?
> +                                       for(int i=0;i<statusVariables.length;i++){
> +                                               String path=statusVariables[i];
> +                                               StatusVariable statusVariable=monitorAdminProxy.getStatusVariable(path);
> +                                               updated(path.substring(0,path.indexOf('/')),statusVariable);
> +                                       }
> +
> +                                       if(--count>0){
> +                                               isStopped=true;
> +                                       }
> +
> +                                       try {
> +                                               Thread.sleep(schedule*1000);
> +                                       } catch (InterruptedException e) {
> +                                       }
> +                                       // if(isStopped) break;
> +
> +                               }
> +                       }
> +               }
> +
> +               public void stop() {
> +                       isStopped=true;
> +                       unsubscribeStatusVariables();
> +                       monitorAdminProxy.monitoringJobs.remove(this);
> +               }
> +
> +               private void subscribeStatusVariables() {
> +                       for(int i=0;i<statusVariables.length;i++){
> +                               String statusVariableName=statusVariables[i];
> +                               List list=(List)subscriptions.get(statusVariableName);
> +                               if(list==null) {
> +                                       list=new LinkedList();
> +                                       subscriptions.put(statusVariableName,list);
> +                               }
> +                               list.add(this);
> +                       }
> +               }
> +
> +               private void unsubscribeStatusVariables() {
> +                       for(int i=0;i<statusVariables.length;i++){
> +                               String statusVariableName=statusVariables[i];
> +                               List list=(List)subscriptions.get(statusVariableName);
> +                               if(list!=null) {
> +                                       list.remove(this);
> +                               } // else never occurs
> +                               if(list.isEmpty())
> +                                       subscriptions.remove(statusVariableName);
> +                       }
> +               }
> +
> +               public String getInitiator() {
> +                       return initiator;
> +               }
> +
> +               public String[] getStatusVariableNames() {
> +                       return statusVariables;
> +               }
> +
> +               public long getSchedule() {
> +                       return schedule;
> +               }
> +
> +               public int getReportCount() {
> +                       return count;
> +               }
> +
> +               public boolean isLocal() {
> +                       return true;
> +               }
> +
> +               public void updated(String monitorableId, StatusVariable statusVariable)
> +                               throws IllegalArgumentException {
> +                       if(isStopped) return;
> +                       if(schedule==0){
> +                               if((++currentCounter)<count) return;
> +                               currentCounter=0;
> +                       } else {
> +                               // TODO
> +
> +                       }
> +
> +                       if (monitorableId == null)
> +                               throw new IllegalArgumentException("null monitorableId");
> +                       if (statusVariable == null)
> +                               throw new IllegalArgumentException("null statusVariable");
> +                       String topic = TOPIC;
> +                       Dictionary properties = new Hashtable();
> +                       properties.put("mon.monitorable.pid", monitorableId);
> +                       properties.put("mon.statusvariable.name", statusVariable.getID());
> +
> +                       Object value = null;
> +                       switch (statusVariable.getType()) { // TODO float->double, int->long
> +                       case StatusVariable.TYPE_BOOLEAN:
> +                               value = new Boolean(statusVariable.getBoolean());
> +                               break;
> +                       case StatusVariable.TYPE_FLOAT:
> +                               value = new Float(statusVariable.getFloat());
> +                               break;
> +                       case StatusVariable.TYPE_INTEGER:
> +                               value = new Integer(statusVariable.getInteger());
> +                               break;
> +                       case StatusVariable.TYPE_STRING:
> +                               value = statusVariable.getString();
> +                               break;
> +                       }
> +                       properties.put(MON_STATUSVARIABLE_VALUE, value);
> +                       properties.put(MON_LISTENER_ID, initiator);
> +                       Event event = new Event(topic, properties);
> +                       EventAdmin eventAdmin = (EventAdmin) eventAdminServiceTracker
> +                                       .getService();
> +                       if (eventAdmin != null)
> +                               eventAdmin.sendEvent(event);
> +               }
> +       }
> +
> +       class MonitorAdminServiceFactory implements ServiceFactory {
> +
> +               List monitorAdminProxies = new ArrayList();
> +
> +               MonitorAdminImpl monitorAdminImpl;
> +
> +               MonitorAdminServiceFactory(MonitorAdminImpl monitorAdminImpl) {
> +                       this.monitorAdminImpl = monitorAdminImpl;
> +               }
> +
> +               public Object getService(Bundle bundle,
> +                               ServiceRegistration serviceRegistration) {
> +                       MonitorAdminProxy monitorAdminProxy = new MonitorAdminProxy(bundle,
> +                                       monitorAdminImpl);
> +                       monitorAdminProxies.add(monitorAdminProxy);
> +                       return monitorAdminProxy;
> +               }
> +
> +               public void ungetService(Bundle bundle,
> +                               ServiceRegistration serviceRegistration, Object object) {
> +                       monitorAdminProxies.remove(object);
> +               }
> +       }
> +
> +       class MonitorAdminProxy implements MonitorAdmin {
> +               Bundle bundle;
> +
> +               MonitorAdminImpl monitorAdminImpl;
> +
> +               List monitoringJobs = new ArrayList();
> +
> +               MonitorAdminProxy(Bundle bundle, MonitorAdminImpl monitorAdminImpl) {
> +                       this.bundle = bundle;
> +                       this.monitorAdminImpl = monitorAdminImpl;
> +               }
> +
> +               /**
> +                * ? Returns a StatusVariable addressed by its full path. The entity
> +                * which queries a StatusVariable needs to hold MonitorPermission for
> +                * the given target with the read action present.
> +                *
> +                * @param path
> +                *            the full path of the StatusVariable in
> +                *            [Monitorable_ID]/[StatusVariable_ID] format
> +                * @return the StatusVariable object
> +                * @throws IllegalArgumentException –
> +                *             if path is null or otherwise invalid, or points to a
> +                *             non-existing StatusVariable
> +                * @throws SecurityException –
> +                *             if the caller does not hold a MonitorPermission for the
> +                *             StatusVariable specified by path with the read action
> +                *             present
> +                */
> +               public StatusVariable getStatusVariable(String path)
> +                               throws IllegalArgumentException, SecurityException {
> +                       checkPermissions();
> +
> +                       if (path == null)
> +                               throw new IllegalArgumentException("null path");
> +                       int pos = path.indexOf('/');
> +                       if (pos <= 0 || pos == path.length() - 1)
> +                               throw new IllegalArgumentException("invalid path");
> +                       String pid = path.substring(0, pos);
> +                       String name = path.substring(pos + 1);
> +                       MonitorableEntry monitorableEntry = (MonitorableEntry) monitorables
> +                                       .get(pid);
> +                       if (monitorableEntry == null)
> +                               throw new IllegalArgumentException(
> +                                               "no such monitorable service for this pid");
> +                       return monitorableEntry.monitorable.getStatusVariable(name);
> +               }
> +
> +               /**
> +                * The Monitorable instances are not accessible through the
> +                * MonitorAdmin, so that requests to individual status variables can be
> +                * filtered with respect to the publishing rights of the Monitorable and
> +                * the reading rights of the caller. The returned array contains the
> +                * names in alphabetical order. It cannot be null, an empty array is
> +                * returned if no Monitorable services are registered. Returns the array
> +                * of Monitorable names
> +                *
> +                * @return the names of the Monitorable services that are currently
> +                *         registered.
> +                */
> +               public String[] getMonitorableNames() {
> +                       SortedSet pids = new TreeSet();
> +                       Iterator iterator = monitorables.keySet().iterator();
> +                       while (iterator.hasNext()) {
> +                               String pid = (String) iterator.next();
> +                               pids.add(pid);
> +                       }
> +                       return (String[]) pids.toArray(new String[pids.size()]);
> +               }
> +
> +               /**
> +                * The StatusVariables will hold the values taken at the time of this
> +                * method call. Only those status variables are returned where the
> +                * following two conditions are met: • the specified Monitorable holds a
> +                * MonitorPermission for the status variable with the publish action
> +                * present • the caller holds a MonitorPermission for the status
> +                * variable with the read action present
> +                * <p>
> +                * The elements in the returned array are in no particular order. The
> +                * return value cannot be null, an empty array is returned if no
> +                * (authorized and readable) Status Variables are provided by the given
> +                * Monitorable. Returns a list of StatusVariable objects published by
> +                * the specified Monitorable
> +                *
> +                * @param monitorableId
> +                *            the identifier of a Monitorable instance
> +                * @return the StatusVariable objects published by a Monitorable
> +                *         instance.
> +                * @throws IllegalArgumentException –
> +                *             if monitorableId is null or otherwise invalid, or points
> +                *             to a non-existing Monitorable
> +                */
> +               public StatusVariable[] getStatusVariables(String monitorableId)
> +                               throws IllegalArgumentException {
> +                       checkPermissions();
> +                       if (monitorableId == null)
> +                               throw new IllegalArgumentException("null monitorableId");
> +                       MonitorableEntry monitorableEntry = (MonitorableEntry) monitorables
> +                                       .get(monitorableId);
> +                       if (monitorableEntry == null)
> +                               throw new IllegalArgumentException(
> +                                               "no such monitorable service for this pid");
> +                       Monitorable monitorable = monitorableEntry.monitorable;
> +                       String[] statusVariableNames = monitorableEntry.statusVariableNames;
> +                       StatusVariable[] statusVariables = new StatusVariable[statusVariableNames.length];
> +                       for (int i = 0; i < statusVariableNames.length; i++) {
> +                               statusVariables[i] = monitorable
> +                                               .getStatusVariable(statusVariableNames[i]);
> +                       }
> +                       return statusVariables;
> +               }
> +
> +               /**
> +                * ? Returns the list of StatusVariable names published by a
> +                * Monitorable instance. Only those status variables are listed where
> +                * the following two conditions are met: • the specified Monitorable
> +                * holds a MonitorPermission for the status variable with the publish
> +                * action present • the caller holds a MonitorPermission for the status
> +                * variable with the read action present The returned array does not
> +                * contain duplicates, and the elements are in alphabetical order. It
> +                * cannot be null, an empty array is returned if no (authorized and
> +                * readable) Status Variables are provided by the given Monitorable.
> +                *
> +                * @param monitorableId
> +                *            the identifier of a Monitorable instance
> +                * @return a list of StatusVariable objects names published by the
> +                *         specified Monitorable
> +                * @throws IllegalArgumentException –
> +                *             if monitorableId is null or otherwise invalid, or points
> +                *             to a non-existing Monitorable
> +                */
> +               public String[] getStatusVariableNames(String monitorableId)
> +                               throws IllegalArgumentException {
> +                       checkPermissions();
> +                       if (monitorableId == null)
> +                               throw new IllegalArgumentException("null monitorableId");
> +                       MonitorableEntry monitorableEntry = (MonitorableEntry) monitorables
> +                                       .get(monitorableId);
> +                       if (monitorableEntry == null)
> +                               throw new IllegalArgumentException(
> +                                               "no such monitorable service for this pid");
> +                       return monitorableEntry.statusVariableNames;
> +               }
> +
> +               /**
> +                * ? Switches event sending on or off for the specified
> +                * StatusVariables. When the MonitorAdmin is notified about a
> +                * StatusVariable being updated it sends an event unless this feature is
> +                * switched off. Note that events within a monitoring job can not be
> +                * switched off. The event sending state of the StatusVariables must not
> +                * be persistently stored. When a StatusVariable is registered for the
> +                * first time in a framework session, its event sending state is set to
> +                * ON by default.
> +                * <p>
> +                * Usage of the Â"*Â" wildcard is allowed in the path argument of this
> +                * method as a convenience feature. The wildcard can be used in either
> +                * or both path fragments, but only at the end of the fragments. The
> +                * semantics of the wildcard is that it stands for any matching
> +                * StatusVariable at the time of the method call, it does not affect the
> +                * event sending status of StatusVariables which are not yet registered.
> +                * As an example, when the switchEvents(Â"MyMonitorable/ Â", false) method
> +                * is executed, event sending from all StatusVariables of the
> +                * MyMonitorable service are switched off. However, if the MyMonitorable
> +                * service starts to publish a new StatusVariable later, itÂ's event
> +                * sending status is on by default.
> +                *
> +                * @param path
> +                *            the identifier of the StatusVariable(s) in
> +                *            [Monitorable_id]/ [StatusVariable_id] format, possibly
> +                *            with the Â"*Â" wildcard at the end of either path fragment
> +                * @param on
> +                *            false if event sending should be switched off, true if it
> +                *            should be switched on for the given path
> +                * @throws SecurityException –
> +                *             if the caller does not hold MonitorPermission with the
> +                *             switchevents action or if there is any StatusVariable in
> +                *             the path field for which it is not allowed to switch
> +                *             event sending on or off as per the target field of the
> +                *             permission
> +                * @throws IllegalArgumentException –
> +                *             if path is null or otherwise invalid, or points to a
> +                *             non-existing StatusVariable
> +                * @see org.osgi.service.monitor.MonitorAdmin#switchEvents(java.lang.String,
> +                *      boolean)
> +                */
> +               public void switchEvents(String path, boolean on)
> +                               throws IllegalArgumentException, SecurityException {
> +                       checkPermissions();
> +                       // TODO
> +                       throw new IllegalArgumentException("not implemented");
> +               }
> +
> +               /**
> +                * ? Issues a request to reset a given StatusVariable. Depending on the
> +                * semantics of the StatusVariable this call may or may not succeed: it
> +                * makes sense to reset a counter to its starting value, but e.g. a
> +                * StatusVariable of type String might not have a meaningful default
> +                * value. Note that for numeric Status- Variables the starting value may
> +                * not necessarily be 0. Resetting a StatusVariable triggers a monitor
> +                * event if the StatusVariable supports update notifications.
> +                * <p>
> +                * The entity that wants to reset the StatusVariable needs to hold
> +                * MonitorPermission with the reset action present. The target field of
> +                * the permission must match the StatusVariable name to be reset.
> +                *
> +                * @param path
> +                *            the identifier of the StatusVariable in
> +                *            [Monitorable_id]/[StatusVariable_id] format
> +                * @return true if the Monitorable could successfully reset the given
> +                *         StatusVariable, false otherwise
> +                * @throws IllegalArgumentException –
> +                *             if path is null or otherwise invalid, or points to a
> +                *             non-existing StatusVariable
> +                * @throws SecurityException –
> +                *             if the caller does not hold MonitorPermission with the
> +                *             reset action or if the specified StatusVariable is not
> +                *             allowed to be reset as per the target field of the
> +                *             permission
> +                * @see org.osgi.service.monitor.MonitorAdmin#resetStatusVariable(java.lang.String)
> +                */
> +               public boolean resetStatusVariable(String path)
> +                               throws IllegalArgumentException, SecurityException {
> +                       checkPermissions();
> +                       if (path == null)
> +                               throw new IllegalArgumentException("null path");
> +                       int pos = path.indexOf('/');
> +                       if (pos <= 0 || pos == path.length() - 1)
> +                               throw new IllegalArgumentException("invalid path");
> +                       String pid = path.substring(0, pos);
> +                       String name = path.substring(pos + 1);
> +                       MonitorableEntry monitorableEntry = (MonitorableEntry) monitorables
> +                                       .get(pid);
> +                       if (monitorableEntry == null)
> +                               throw new IllegalArgumentException(
> +                                               "no such monitorable service for this pid");
> +                       return monitorableEntry.monitorable.resetStatusVariable(name);
> +               }
> +
> +               /**
> +                * The entity that queries a StatusVariable needs to hold
> +                * MonitorPermission for the given target with the read action present.
> +                *
> +                * @param path
> +                *            the full path of the StatusVariable in
> +                *            [Monitorable_ID]/[StatusVariable_ID] format ?return a
> +                *            human readable description of the given StatusVariable.
> +                *            The null value may be returned if there is no description
> +                *            for the given StatusVariable.
> +                * @eturn the human readable description of this StatusVariable or null
> +                *        if it is not set
> +                * @throws IllegalArgumentException –
> +                *             if path is null or otherwise invalid, or points to a
> +                *             non-existing StatusVariable
> +                * @throwsSecurityException – if the caller does not hold a
> +                *                          MonitorPermission for the StatusVariable
> +                *                          specified by path with the read action
> +                *                          present *
> +                * @see org.osgi.service.monitor.MonitorAdmin#getDescription(java.lang.String)
> +                */
> +               public String getDescription(String path)
> +                               throws IllegalArgumentException, SecurityException {
> +                       checkPermissions();
> +                       if (path == null)
> +                               throw new IllegalArgumentException("null path");
> +                       int pos = path.indexOf('/');
> +                       if (pos <= 0 || pos == path.length() - 1)
> +                               throw new IllegalArgumentException("invalid path");
> +                       String pid = path.substring(0, pos);
> +                       String name = path.substring(pos + 1);
> +                       MonitorableEntry monitorableEntry = (MonitorableEntry) monitorables
> +                                       .get(pid);
> +                       if (monitorableEntry == null)
> +                               throw new IllegalArgumentException(
> +                                               "no such monitorable service for this pid");
> +                       return monitorableEntry.monitorable.getDescription(name);
> +               }
> +
> +               /**
> +                * ? Starts a time based MonitoringJob with the parameters provided.
> +                * Monitoring events will be sent according to the specified schedule.
> +                * All specified StatusVariables must exist when the job is started. The
> +                * initiator string is used in the mon.listener.id field of all events
> +                * triggered by the job, to allow filtering the events based on the
> +                * initiator.
> +                * <p>
> +                * The schedule parameter specifies the time in seconds between two
> +                * measurements, it must be greater than 0. The first measurement will
> +                * be taken when the timer expires for the first time, not when this
> +                * method is called.
> +                * <p>
> +                * The count parameter defines the number of measurements to be taken,
> +                * and must either be a positive integer, or 0 if the measurement is to
> +                * run until explicitely stopped.
> +                * <p>
> +                * The entity which initiates a MonitoringJob needs to hold
> +                * MonitorPermission for all the specified target StatusVariables with
> +                * the startjob action present. If the permissionÂ's action string
> +                * specifies a minimal sampling interval then the schedule parameter
> +                * should be at least as great as the value in the action string.
> +                *
> +                * @param initiator
> +                *            the identifier of the entity that initiated the job
> +                * @param statusVariables
> +                *            the list of StatusVariables to be monitored, with each
> +                *            StatusVariable name given in
> +                *            [Monitorable_PID]/[StatusVariable_ID] format
> +                * @param schedule
> +                *            the time in seconds between two measurements
> +                * @param count
> +                *            the number of measurements to be taken, or 0 for the
> +                *            measurement to run until explicitely stopped
> +                *
> +                * @return the successfully started job object, cannot be null
> +                * @throws IllegalArgumentException
> +                *             if the list of StatusVariable names contains an invalid
> +                *             or non-existing StatusVariable; if initiator is null or
> +                *             empty; or if the schedule or count parameters are invalid
> +                * @throws SecurityException –
> +                *             if the caller does not hold MonitorPermission for all the
> +                *             specified StatusVariables, with the startjob action
> +                *             present, or if the permission does not allow starting the
> +                *             job with the given frequency
> +                * @see org.osgi.service.monitor.MonitorAdmin#startScheduledJob(java.lang.String,
> +                *      java.lang.String[], int, int)
> +                */
> +               public MonitoringJob startScheduledJob(String initiator,
> +                               String[] statusVariables, int schedule, int count)
> +                               throws IllegalArgumentException, SecurityException {
> +                       checkPermissions();
> +                       MonitoringJob monitoringJob = new MonitoringJobImpl(this,
> +                                       initiator, statusVariables, schedule, count);
> +                       monitoringJobs.add(monitoringJob);
> +                       return monitoringJob;
> +               }
> +
> +               /**
> +                * Starts a change based MonitoringJob with the parameters provided.
> +                * Monitoring events will be sent when the StatusVariables of this job
> +                * are updated. All specified StatusVariables must exist when the job is
> +                * started, and all must support update notifications. The initiator
> +                * string is used in the mon.listener. id field of all events triggered
> +                * by the job, to allow filtering the events based on the initiator.
> +                * <p>
> +                * The count parameter specifies the number of changes that must happen
> +                * to a StatusVariable before a new notification is sent, this must be a
> +                * positive integer.
> +                * <p>
> +                * The entity which initiates a MonitoringJob needs to hold
> +                * MonitorPermission for all the specified target StatusVariables with
> +                * the startjob action present.
> +                *
> +                * @param initiator
> +                *            the identifier of the entity that initiated the job
> +                * @param statusVariables
> +                *            the list of StatusVariables to be monitored, with each
> +                *            StatusVariable name given in
> +                *            [Monitorable_PID]/[StatusVariable_ID] format
> +                * @param count
> +                *            the number of changes that must happen to a StatusVariable
> +                *            before a new notification is sent
> +                *
> +                * @return the successfully started job object, cannot be null
> +                * @throws IllegalArgumentException –
> +                *             if the list of StatusVariable names contains an invalid
> +                *             or non-existing StatusVariable, or one that does not
> +                *             support notifications; if the initiator is null or empty;
> +                *             or if count is invalid
> +                * @throws SecurityException –
> +                *             if the caller does not hold MonitorPermission for all the
> +                *             specified StatusVariables, with the startjob action
> +                *             present
> +                * @see org.osgi.service.monitor.MonitorAdmin#startJob(java.lang.String,
> +                *      java.lang.String[], int)
> +                */
> +               public MonitoringJob startJob(String initiator,
> +                               String[] statusVariables, int count)
> +                               throws IllegalArgumentException, SecurityException {
> +                       checkPermissions();
> +                       MonitoringJob monitoringJob = new MonitoringJobImpl(this,
> +                                       initiator, statusVariables, count);
> +                       monitoringJobs.add(monitoringJob);
> +                       return monitoringJob;
> +               }
> +
> +               /*
> +                * Returns the list of currently running MonitoringJobs. Jobs are only
> +                * visible to callers that have the necessary permissions: to receive a
> +                * Monitoring Job in the returned list, the caller must hold all
> +                * permissions required for starting the job. This means that if the
> +                * caller does not have MonitorPermission with the proper startjob
> +                * action for all the Status Variables monitored by a job, then that job
> +                * will be silently omitted from the results. The returned array cannot
> +                * be null, an empty array is returned if there are no running jobs
> +                * visible to the caller at the time of the call. Returns the list of
> +                * running jobs visible to the caller
> +                *
> +                * @see org.osgi.service.monitor.MonitorAdmin#getRunningJobs()
> +                */
> +               public MonitoringJob[] getRunningJobs() {
> +                       return (MonitoringJob[]) monitoringJobs
> +                                       .toArray(new MonitoringJob[monitoringJobs.size()]);
> +               }
> +
> +               private void checkPermissions() throws SecurityException {
> +                       // TODO
> +
> +               }
> +       }
> +
> +       class MonitorListenerServiceFactory implements ServiceFactory {
> +
> +               List monitorListenerProxies = new ArrayList();
> +
> +               MonitorAdminImpl monitorAdminImpl;
> +
> +               MonitorListenerServiceFactory(MonitorAdminImpl monitorAdminImpl) {
> +                       this.monitorAdminImpl = monitorAdminImpl;
> +               }
> +
> +               public Object getService(Bundle bundle,
> +                               ServiceRegistration serviceRegistration) {
> +                       MonitorListenerProxy monitorListenerProxy = new MonitorListenerProxy(
> +                                       bundle, monitorAdminImpl);
> +                       monitorListenerProxies.add(monitorListenerProxy);
> +                       return monitorListenerProxy;
> +               }
> +
> +               public void ungetService(Bundle bundle,
> +                               ServiceRegistration serviceRegistration, Object object) {
> +                       monitorListenerProxies.remove(object);
> +               }
> +       }
> +
> +       class MonitorListenerProxy implements MonitorListener {
> +               Bundle bundle;
> +
> +               MonitorAdminImpl monitorAdminImpl;
> +
> +               MonitorListenerProxy(Bundle bundle, MonitorAdminImpl monitorAdminImpl) {
> +                       this.bundle = bundle;
> +                       this.monitorAdminImpl = monitorAdminImpl;
> +               }
> +
> +               /**
> +                * ? Callback for notification of a StatusVariable change.
> +                *
> +                * @param monitorableId
> +                *            the identifier of the Monitorable instance reporting the
> +                *            change
> +                * @param statusVariable
> +                *            the StatusVariable that has changed
> +                * @throws IllegalArgumentException –
> +                *             if the specified monitorable ID is invalid (null, empty,
> +                *             or contains illegal characters), or if statusVariable is
> +                *             null
> +                * @see org.osgi.service.monitor.MonitorListener#updated(java.lang.String,
> +                *      org.osgi.service.monitor.StatusVariable)
> +                */
> +               public void updated(String monitorableId, StatusVariable statusVariable)
> +                               throws IllegalArgumentException {
> +                       if (monitorableId == null)
> +                               throw new IllegalArgumentException("null monitorableId");
> +                       if (statusVariable == null)
> +                               throw new IllegalArgumentException("null statusVariable");
> +                       String topic = TOPIC;
> +                       Dictionary properties = new Hashtable();
> +                       properties.put(MON_MONITORABLE_PID, monitorableId);
> +                       properties.put(MON_STATUSVARIABLE_NAME, statusVariable.getID());
> +
> +                       Object value = null;
> +                       switch (statusVariable.getType()) { // TODO float->double, int->long
> +                       case StatusVariable.TYPE_BOOLEAN:
> +                               value = new Boolean(statusVariable.getBoolean());
> +                               break;
> +                       case StatusVariable.TYPE_FLOAT:
> +                               value = new Float(statusVariable.getFloat());
> +                               break;
> +                       case StatusVariable.TYPE_INTEGER:
> +                               value = new Integer(statusVariable.getInteger());
> +                               break;
> +                       case StatusVariable.TYPE_STRING:
> +                               value = statusVariable.getString();
> +                               break;
> +                       }
> +                       properties.put(MON_STATUSVARIABLE_VALUE, value);
> +                       // mon.listener.id: The identifier of the initiator of the
> +                       // monitoring job (only present if the event was generated due to a
> +                       // monitoring job))
> +                       Event event = new Event(topic, properties);
> +                       EventAdmin eventAdmin = (EventAdmin) eventAdminServiceTracker
> +                                       .getService();
> +                       if (eventAdmin != null)
> +                               eventAdmin.sendEvent(event);
> +
> +                       // broadcast to MonitoringJob
> +                       StringBuffer sb=new StringBuffer(monitorableId);
> +                       sb.append('/').append(statusVariable.getID());
> +                       String path=sb.toString();
> +                       List list=(List)subscriptions.get(path);
> +                       if(list!=null) {
> +                               Iterator iterator=list.iterator();
> +                               while(iterator.hasNext()){
> +                                       MonitoringJobImpl monitoringJobImpl=(MonitoringJobImpl)iterator.next();
> +                                       monitoringJobImpl.updated(monitorableId,statusVariable);
> +                               }
> +                       }
> +               }
> +       }
> +
> +       class MonitorableEntry {
> +               Monitorable monitorable;
> +
> +               String pid;
> +
> +               String[] statusVariableNames;
> +
> +               MonitorableEntry(Monitorable monitorable, String pid,
> +                               String[] statusVariableNames) {
> +                       this.monitorable = monitorable;
> +                       this.pid = pid;
> +                       this.statusVariableNames = statusVariableNames;
> +               }
> +       }
> +
> +       class MyServiceTrackerCustomizerForMonitorable implements
> +                       ServiceTrackerCustomizer {
> +
> +               public Object addingService(ServiceReference serviceReference) {
> +                       String pid = (String) serviceReference
> +                                       .getProperty(Constants.SERVICE_PID);
> +                       if (pid == null) {
> +                               System.err.println("Warning: The "+Constants.SERVICE_PID+" of service "+Constants.SERVICE_ID+ " is not setted");
> +                               return null;
> +                       }
> +
> +                       if(monitorables.containsKey(pid)){
> +                               // TODO change for logger
> +                               System.err.println("Warning: The "+Constants.SERVICE_PID+"(="+pid+") of service "+Constants.SERVICE_ID+ " is already registered by another bundle");
> +                               return null;
> +                       }
> +
> +                       Monitorable monitorable = (Monitorable) bundleContext
> +                                       .getService(serviceReference);
> +                       if (monitorable == null)
> +                               return null;
> +                       String[] statusVariableNames = monitorable.getStatusVariableNames();
> +                       if (statusVariableNames == null || statusVariableNames.length == 0) {
> +                               bundleContext.ungetService(serviceReference);
> +                               return null;
> +                       }
> +                       monitorables.put(pid, new MonitorableEntry(monitorable, pid,
> +                                       statusVariableNames));
> +                       return monitorable;
> +               }
> +
> +               public void modifiedService(ServiceReference serviceReference,
> +                               Object object) {
> +                       // TODO
> +               }
> +
> +               public void removedService(ServiceReference serviceReference,
> +                               Object object) {
> +                       Monitorable monitorable = (Monitorable) object;
> +                       Iterator iterator = monitorables.entrySet().iterator();
> +                       while (iterator.hasNext()) {
> +                               Map.Entry mapEntry = (Map.Entry) iterator.next();
> +                               MonitorableEntry monitorableEntry = (MonitorableEntry) mapEntry
> +                                               .getValue();
> +                               if (monitorableEntry.monitorable.equals(monitorable)) {
> +                                       iterator.remove();
> +                                       break;
> +                               }
> +                       }
> +                       bundleContext.ungetService(serviceReference);
> +               }
> +       }
> +
> +       private BundleContext bundleContext;
> +
> +       private ServiceTracker eventAdminServiceTracker;
> +
> +       private ServiceTracker monitorableServiceTracker;
> +
> +       private Map monitorables = new HashMap();
> +
> +       /**
> +        * path -> list of MonitoringJobImpl
> +        */
> +       private Map subscriptions = new HashMap();
> +
> +
> +       public void start(BundleContext bundleContext) throws Exception {
> +               this.bundleContext = bundleContext;
> +               eventAdminServiceTracker = new ServiceTracker(bundleContext,
> +                               EventAdmin.class.getName(), null);
> +               eventAdminServiceTracker.open();
> +
> +               monitorableServiceTracker = new ServiceTracker(bundleContext,
> +                               Monitorable.class.getName(),
> +                               new MyServiceTrackerCustomizerForMonitorable());
> +               monitorableServiceTracker.open();
> +
> +               bundleContext.registerService(MonitorAdmin.class.getName(),
> +                               new MonitorAdminServiceFactory(this), null);
> +               bundleContext.registerService(MonitorListener.class.getName(),
> +                               new MonitorListenerServiceFactory(this), null);
> +       }
> +
> +       public void stop(BundleContext context) throws Exception {
> +               stopAllMonitoringJobs();
> +               monitorableServiceTracker.close(); // unget all services ???
> +               Iterator iterator = monitorables.keySet().iterator();
> +               while (iterator.hasNext()) {
> +                       ServiceReference serviceReference = (ServiceReference) iterator
> +                                       .next();
> +                       bundleContext.ungetService(serviceReference);
> +               }
> +               eventAdminServiceTracker.close();
> +       }
> +
> +       private void stopAllMonitoringJobs() {
> +               // TODO
> +
> +       }
> +
> +}
>
> Propchange: felix/sandbox/donsez/monitoradmin/src/main/java/org/apache/felix/monitor/MonitorAdminImpl.java
> ------------------------------------------------------------------------------
>     svn:eol-style = native
>
> Added: felix/sandbox/donsez/monitoradmin/src/main/java/org/osgi/service/monitor/MonitorAdmin.java
> URL: http://svn.apache.org/viewvc/felix/sandbox/donsez/monitoradmin/src/main/java/org/osgi/service/monitor/MonitorAdmin.java?view=auto&rev=554318
> ==============================================================================
> --- felix/sandbox/donsez/monitoradmin/src/main/java/org/osgi/service/monitor/MonitorAdmin.java (added)
> +++ felix/sandbox/donsez/monitoradmin/src/main/java/org/osgi/service/monitor/MonitorAdmin.java Sat Jul  7 22:49:38 2007
> @@ -0,0 +1,344 @@
> +/*
> + * $Header: /cvshome/build/org.osgi.service.monitor/src/org/osgi/service/monitor/MonitorAdmin.java,v 1.20 2005/07/29 18:03:09 tszeredi Exp $
> + *
> + * Copyright (c) OSGi Alliance (2004, 2005). All Rights Reserved.
> + *
> + * This program and the accompanying materials are made available under the
> + * terms of the Eclipse Public License v1.0 which accompanies this
> + * distribution, and is available at http://www.eclipse.org/legal/epl-v10.html.
> + */
> +
> +package org.osgi.service.monitor;
> +
> +/**
> + * A <code>MonitorAdmin</code> implementation handles
> + * <code>StatusVariable</code> query requests and measurement job control
> + * requests.
> + * <p>
> + * Note that an alternative but not recommended way of obtaining
> + * <code>StatusVariable</code>s is that applications having the required
> + * <code>ServicePermissions</code> can query the list of
> + * <code>Monitorable</code> services from the service registry and then query
> + * the list of <code>StatusVariable</code> names from the
> + * <code>Monitorable</code> services. This way all services which publish
> + * <code>StatusVariable</code>s will be returned regardless of whether they
> + * do or do not hold the necessary <code>MonitorPermission</code> for
> + * publishing <code>StatusVariable</code>s. By using the
> + * <code>MonitorAdmin</code> to obtain the <code>StatusVariable</code>s it
> + * is guaranteed that only those <code>Monitorable</code> services will be
> + * accessed who are authorized to publish <code>StatusVariable</code>s. It is
> + * the responsibility of the <code>MonitorAdmin</code> implementation to check
> + * the required permissions and show only those variables which pass this check.
> + * <p>
> + * The events posted by <code>MonitorAdmin</code> contain the following
> + * properties:
> + * <ul>
> + * <li><code>mon.monitorable.pid</code>: The identifier of the
> + * <code>Monitorable</code>
> + * <li><code>mon.statusvariable.name</code>: The identifier of the
> + * <code>StatusVariable</code> within the given <code>Monitorable</code>
> + * <li><code>mon.statusvariable.value</code>: The value of the
> + * <code>StatusVariable</code>, represented as a <code>String</code>
> + * <li><code>mon.listener.id</code>: The identifier of the initiator of the
> + * monitoring job (only present if the event was generated due to a monitoring
> + * job)
> + * </ul>
> + * <p>
> + * Most of the methods require either a Monitorable ID or a Status Variable path
> + * parameter, the latter in [Monitorable_ID]/[StatusVariable_ID] format.  These
> + * parameters must not be <code>null</code>, and the IDs they contain must
> + * conform to their respective definitions in {@link Monitorable} and
> + * {@link StatusVariable}.  If any of the restrictions are violated, the method
> + * must throw an <code>IllegalArgumentException</code>.
> + */
> +public interface MonitorAdmin {
> +
> +    /**
> +     * Returns a <code>StatusVariable</code> addressed by its full path.
> +     * The entity which queries a <code>StatusVariable</code> needs to hold
> +     * <code>MonitorPermission</code> for the given target with the
> +     * <code>read</code> action present.
> +     *
> +     * @param path the full path of the <code>StatusVariable</code> in
> +     *        [Monitorable_ID]/[StatusVariable_ID] format
> +     * @return the <code>StatusVariable</code> object
> +     * @throws java.lang.IllegalArgumentException if <code>path</code> is
> +     *         <code>null</code> or otherwise invalid, or points to a
> +     *         non-existing <code>StatusVariable</code>
> +     * @throws java.lang.SecurityException if the caller does not hold a
> +     *         <code>MonitorPermission</code> for the
> +     *         <code>StatusVariable</code> specified by <code>path</code>
> +     *         with the <code>read</code> action present
> +     */
> +    public StatusVariable getStatusVariable(String path)
> +            throws IllegalArgumentException, SecurityException;
> +
> +    /**
> +     * Returns the names of the <code>Monitorable</code> services that are
> +     * currently registered. The <code>Monitorable</code> instances are not
> +     * accessible through the <code>MonitorAdmin</code>, so that requests to
> +     * individual status variables can be filtered with respect to the
> +     * publishing rights of the <code>Monitorable</code> and the reading
> +     * rights of the caller.
> +     * <p>
> +     * The returned array contains the names in alphabetical order. It cannot be
> +     * <code>null</code>, an empty array is returned if no
> +     * <code>Monitorable</code> services are registered.
> +     *
> +     * @return the array of <code>Monitorable</code> names
> +     */
> +    public String[] getMonitorableNames();
> +
> +    /**
> +     * Returns the <code>StatusVariable</code> objects published by a
> +     * <code>Monitorable</code> instance. The <code>StatusVariables</code>
> +     * will hold the values taken at the time of this method call. Only those
> +     * status variables are returned where the following two conditions are met:
> +     * <ul>
> +     * <li>the specified <code>Monitorable</code> holds a
> +     * <code>MonitorPermission</code> for the status variable with the
> +     * <code>publish</code> action present
> +     * <li>the caller holds a <code>MonitorPermission</code> for the status
> +     * variable with the <code>read</code> action present
> +     * </ul>
> +     * All other status variables are silently ignored, they are omitted from
> +     * the result.
> +     * <p>
> +     * The returned array does not contain duplicates, and the elements are in
> +     * no particular order. It cannot be <code>null</code>, an empty array is
> +     * returned if no (authorized and readable) Status Variables are provided
> +     * by the given <code>Monitorable</code>.
> +     *
> +     * @param monitorableId the identifier of a <code>Monitorable</code>
> +     *        instance
> +     * @return a list of <code>StatusVariable</code> objects published
> +     *         by the specified <code>Monitorable</code>
> +     * @throws java.lang.IllegalArgumentException if <code>monitorableId</code>
> +     *         is <code>null</code> or otherwise invalid, or points to a
> +     *         non-existing <code>Monitorable</code>
> +     */
> +    public StatusVariable[] getStatusVariables(String monitorableId)
> +            throws IllegalArgumentException;
> +
> +    /**
> +     * Returns the list of <code>StatusVariable</code> names published by a
> +     * <code>Monitorable</code> instance. Only those status variables are
> +     * listed where the following two conditions are met:
> +     * <ul>
> +     * <li>the specified <code>Monitorable</code> holds a
> +     * <code>MonitorPermission</code> for the status variable with the
> +     * <code>publish</code> action present
> +     * <li>the caller holds a <code>MonitorPermission</code> for
> +     * the status variable with the <code>read</code> action present
> +     * </ul>
> +     * All other status variables are silently ignored, their names are omitted
> +     * from the list.
> +     * <p>
> +     * The returned array does not contain duplicates, and the elements are in
> +     * alphabetical order. It cannot be <code>null</code>, an empty array is
> +     * returned if no (authorized and readable) Status Variables are provided
> +     * by the given <code>Monitorable</code>.
> +     *
> +     * @param monitorableId the identifier of a <code>Monitorable</code>
> +     *        instance
> +     * @return a list of <code>StatusVariable</code> objects names
> +     *         published by the specified <code>Monitorable</code>
> +     * @throws java.lang.IllegalArgumentException if <code>monitorableId</code>
> +     *         is <code>null</code> or otherwise invalid, or points to a
> +     *         non-existing <code>Monitorable</code>
> +     */
> +    public String[] getStatusVariableNames(String monitorableId)
> +            throws IllegalArgumentException;
> +
> +    /**
> +     * Switches event sending on or off for the specified
> +     * <code>StatusVariable</code>s. When the <code>MonitorAdmin</code> is
> +     * notified about a <code>StatusVariable</code> being updated it sends an
> +     * event unless this feature is switched off. Note that events within a
> +     * monitoring job can not be switched off. The event sending state of the
> +     * <code>StatusVariables</code> must not be persistently stored. When a
> +     * <code>StatusVariable</code> is registered for the first time in a
> +     * framework session, its event sending state is set to ON by default.
> +     * <p>
> +     * Usage of the "*" wildcard is allowed in the path argument of this method
> +     * as a convenience feature. The wildcard can be used in either or both path
> +     * fragments, but only at the end of the fragments.  The semantics of the
> +     * wildcard is that it stands for any matching <code>StatusVariable</code>
> +     * at the time of the method call, it does not affect the event sending
> +     * status of <code>StatusVariable</code>s which are not yet registered. As
> +     * an example, when the <code>switchEvents("MyMonitorable/*", false)</code>
> +     * method is executed, event sending from all <code>StatusVariables</code>
> +     * of the MyMonitorable service are switched off. However, if the
> +     * MyMonitorable service starts to publish a new <code>StatusVariable</code>
> +     * later, it's event sending status is on by default.
> +     *
> +     * @param path the identifier of the <code>StatusVariable</code>(s) in
> +     *        [Monitorable_id]/[StatusVariable_id] format, possibly with the
> +     *        "*" wildcard at the end of either path fragment
> +     * @param on <code>false</code> if event sending should be switched off,
> +     *        <code>true</code> if it should be switched on for the given path
> +     * @throws java.lang.SecurityException if the caller does not hold
> +     *         <code>MonitorPermission</code> with the
> +     *         <code>switchevents</code> action or if there is any
> +     *         <code>StatusVariable</code> in the <code>path</code> field for
> +     *         which it is not allowed to switch event sending on or off as per
> +     *         the target field of the permission
> +     * @throws java.lang.IllegalArgumentException if <code>path</code> is
> +     *         <code>null</code> or otherwise invalid, or points to a
> +     *         non-existing <code>StatusVariable</code>
> +     */
> +    public void switchEvents(String path, boolean on)
> +        throws IllegalArgumentException, SecurityException;
> +
> +    /**
> +     * Issues a request to reset a given <code>StatusVariable</code>.
> +     * Depending on the semantics of the <code>StatusVariable</code> this call
> +     * may or may not succeed: it makes sense to reset a counter to its starting
> +     * value, but e.g. a <code>StatusVariable</code> of type String might not
> +     * have a meaningful default value. Note that for numeric
> +     * <code>StatusVariable</code>s the starting value may not necessarily be
> +     * 0. Resetting a <code>StatusVariable</code> triggers a monitor event if
> +     * the <code>StatusVariable</code> supports update notifications.
> +     * <p>
> +     * The entity that wants to reset the <code>StatusVariable</code> needs to
> +     * hold <code>MonitorPermission</code> with the <code>reset</code>
> +     * action present. The target field of the permission must match the
> +     * <code>StatusVariable</code> name to be reset.
> +     *
> +     * @param path the identifier of the <code>StatusVariable</code> in
> +     *        [Monitorable_id]/[StatusVariable_id] format
> +     * @return <code>true</code> if the <code>Monitorable</code> could
> +     *         successfully reset the given <code>StatusVariable</code>,
> +     *         <code>false</code> otherwise
> +     * @throws java.lang.IllegalArgumentException if <code>path</code> is
> +     *         <code>null</code> or otherwise invalid, or points to a
> +     *         non-existing <code>StatusVariable</code>
> +     * @throws java.lang.SecurityException if the caller does not hold
> +     *         <code>MonitorPermission</code> with the <code>reset</code>
> +     *         action or if the specified <code>StatusVariable</code> is not
> +     *         allowed to be reset as per the target field of the permission
> +     */
> +    public boolean resetStatusVariable(String path)
> +            throws IllegalArgumentException, SecurityException;
> +
> +    /**
> +     * Returns a human readable description of the given
> +     * <code>StatusVariable</code>. The <code>null</code> value may be returned
> +     * if there is no description for the given <code>StatusVariable</code>.
> +     * <p>
> +     * The entity that queries a <code>StatusVariable</code> needs to hold
> +     * <code>MonitorPermission</code> for the given target with the
> +     * <code>read</code> action present.
> +     *
> +     * @param path the full path of the <code>StatusVariable</code> in
> +     *        [Monitorable_ID]/[StatusVariable_ID] format
> +     * @return the human readable description of this
> +     *         <code>StatusVariable</code> or <code>null</code> if it is not
> +     *         set
> +     * @throws java.lang.IllegalArgumentException if <code>path</code> is
> +     *         <code>null</code> or otherwise invalid, or points to a
> +     *         non-existing <code>StatusVariable</code>
> +     * @throws java.lang.SecurityException if the caller does not hold a
> +     *         <code>MonitorPermission</code> for the
> +     *         <code>StatusVariable</code> specified by <code>path</code>
> +     *         with the <code>read</code> action present
> +     */
> +    public String getDescription(String path)
> +            throws IllegalArgumentException, SecurityException;
> +
> +    /**
> +     * Starts a time based <code>MonitoringJob</code> with the parameters
> +     * provided. Monitoring events will be sent according to the specified
> +     * schedule. All specified <code>StatusVariable</code>s must exist when the
> +     * job is started. The initiator string is used in the
> +     * <code>mon.listener.id</code> field of all events triggered by the job,
> +     * to allow filtering the events based on the initiator.
> +     * <p>
> +     * The <code>schedule</code> parameter specifies the time in seconds
> +     * between two measurements, it must be greater than 0.  The first
> +     * measurement will be taken when the timer expires for the first time, not
> +     * when this method is called.
> +     * <p>
> +     * The <code>count</code> parameter defines the number of measurements to be
> +     * taken, and must either be a positive integer, or 0 if the measurement is
> +     * to run indefinitely.
> +     * <p>
> +     * The entity which initiates a <code>MonitoringJob</code> needs to hold
> +     * <code>MonitorPermission</code> for all the specified target
> +     * <code>StatusVariable</code>s with the <code>startjob</code> action
> +     * present. If the permission's action string specifies a minimal sampling
> +     * interval then the <code>schedule</code> parameter should be at least as
> +     * great as the value in the action string.
> +     *
> +     * @param initiator the identifier of the entity that initiated the job
> +     * @param statusVariables the list of <code>StatusVariable</code>s to be
> +     *        monitored, with each <code>StatusVariable</code> name given in
> +     *        [Monitorable_PID]/[StatusVariable_ID] format
> +     * @param schedule the time in seconds between two measurements
> +     * @param count the number of measurements to be taken, or 0 for the
> +     *        measurement to run indefinitely
> +     * @return the successfully started job object, cannot be <code>null</code>
> +     * @throws java.lang.IllegalArgumentException if the list of
> +     *         <code>StatusVariable</code> names contains an invalid or
> +     *         non-existing <code>StatusVariable</code>; if
> +     *         <code>initiator</code> is <code>null</code> or empty; or if the
> +     *         <code>schedule</code> or <code>count</code> parameters are
> +     *         invalid
> +     * @throws java.lang.SecurityException if the caller does not hold
> +     *         <code>MonitorPermission</code> for all the specified
> +     *         <code>StatusVariable</code>s, with the <code>startjob</code>
> +     *         action present, or if the permission does not allow starting the
> +     *         job with the given frequency
> +     */
> +    public MonitoringJob startScheduledJob(String initiator,
> +            String[] statusVariables, int schedule, int count)
> +            throws IllegalArgumentException, SecurityException;
> +
> +    /**
> +     * Starts a change based <code>MonitoringJob</code> with the parameters
> +     * provided. Monitoring events will be sent when the
> +     * <code>StatusVariable</code>s of this job are updated. All specified
> +     * <code>StatusVariable</code>s must exist when the job is started, and
> +     * all must support update notifications. The initiator string is used in
> +     * the <code>mon.listener.id</code> field of all events triggered by the
> +     * job, to allow filtering the events based on the initiator.
> +     * <p>
> +     * The <code>count</code> parameter specifies the number of changes that
> +     * must happen to a <code>StatusVariable</code> before a new notification is
> +     * sent, this must be a positive integer.
> +     * <p>
> +     * The entity which initiates a <code>MonitoringJob</code> needs to hold
> +     * <code>MonitorPermission</code> for all the specified target
> +     * <code>StatusVariable</code>s with the <code>startjob</code> action
> +     * present.
> +     *
> +     * @param initiator the identifier of the entity that initiated the job
> +     * @param statusVariables the list of <code>StatusVariable</code>s to be
> +     *        monitored, with each <code>StatusVariable</code> name given in
> +     *        [Monitorable_PID]/[StatusVariable_ID] format
> +     * @param count the number of changes that must happen to a
> +     *        <code>StatusVariable</code> before a new notification is sent
> +     * @return the successfully started job object, cannot be <code>null</code>
> +     * @throws java.lang.IllegalArgumentException if the list of
> +     *         <code>StatusVariable</code> names contains an invalid or
> +     *         non-existing <code>StatusVariable</code>, or one that does not
> +     *         support notifications; if the <code>initiator</code> is
> +     *         <code>null</code> or empty; or if <code>count</code> is invalid
> +     * @throws java.lang.SecurityException if the caller does not hold
> +     *         <code>MonitorPermission</code> for all the specified
> +     *         <code>StatusVariable</code>s, with the <code>startjob</code>
> +     *         action present
> +     */
> +    public MonitoringJob startJob(String initiator, String[] statusVariables,
> +            int count) throws IllegalArgumentException, SecurityException;
> +
> +    /**
> +     * Returns the list of currently running <code>MonitoringJob</code>s.
> +     * <p>
> +     * The returned array cannot be <code>null</code>, an empty array is
> +     * returned if there are no running jobs at the time of the call.
> +     *
> +     * @return the list of running jobs
> +     */
> +    public MonitoringJob[] getRunningJobs();
> +}
> \ No newline at end of file
>
> Propchange: felix/sandbox/donsez/monitoradmin/src/main/java/org/osgi/service/monitor/MonitorAdmin.java
> ------------------------------------------------------------------------------
>     svn:eol-style = native
>
> Added: felix/sandbox/donsez/monitoradmin/src/main/java/org/osgi/service/monitor/MonitorListener.java
> URL: http://svn.apache.org/viewvc/felix/sandbox/donsez/monitoradmin/src/main/java/org/osgi/service/monitor/MonitorListener.java?view=auto&rev=554318
> ==============================================================================
> --- felix/sandbox/donsez/monitoradmin/src/main/java/org/osgi/service/monitor/MonitorListener.java (added)
> +++ felix/sandbox/donsez/monitoradmin/src/main/java/org/osgi/service/monitor/MonitorListener.java Sat Jul  7 22:49:38 2007
> @@ -0,0 +1,34 @@
> +/*
> + * $Header: /cvshome/build/org.osgi.service.monitor/src/org/osgi/service/monitor/MonitorListener.java,v 1.7 2005/06/17 14:35:17 tszeredi Exp $
> + *
> + * Copyright (c) OSGi Alliance (2004, 2005). All Rights Reserved.
> + *
> + * This program and the accompanying materials are made available under the
> + * terms of the Eclipse Public License v1.0 which accompanies this
> + * distribution, and is available at http://www.eclipse.org/legal/epl-v10.html.
> + */
> +
> +package org.osgi.service.monitor;
> +
> +/**
> + * The <code>MonitorListener</code> is used by <code>Monitorable</code>
> + * services to send notifications when a <code>StatusVariable</code> value is
> + * changed. The <code>MonitorListener</code> should register itself as a
> + * service at the OSGi Service Registry. This interface is implemented by the
> + * Monitor Admin component.
> + */
> +public interface MonitorListener {
> +    /**
> +     * Callback for notification of a <code>StatusVariable</code> change.
> +     *
> +     * @param monitorableId the identifier of the <code>Monitorable</code>
> +     *        instance reporting the change
> +     * @param statusVariable the <code>StatusVariable</code> that has changed
> +     * @throws java.lang.IllegalArgumentException if the specified monitorable
> +     *         ID is invalid (<code>null</code>, empty, or contains illegal
> +     *         characters), or if <code>statusVariable</code> is
> +     *         <code>null</code>
> +     */
> +    public void updated(String monitorableId, StatusVariable statusVariable)
> +            throws IllegalArgumentException;
> +}
>
> Propchange: felix/sandbox/donsez/monitoradmin/src/main/java/org/osgi/service/monitor/MonitorListener.java
> ------------------------------------------------------------------------------
>     svn:eol-style = native
>
> Added: felix/sandbox/donsez/monitoradmin/src/main/java/org/osgi/service/monitor/MonitorPermission.java
> URL: http://svn.apache.org/viewvc/felix/sandbox/donsez/monitoradmin/src/main/java/org/osgi/service/monitor/MonitorPermission.java?view=auto&rev=554318
> ==============================================================================
> --- felix/sandbox/donsez/monitoradmin/src/main/java/org/osgi/service/monitor/MonitorPermission.java (added)
> +++ felix/sandbox/donsez/monitoradmin/src/main/java/org/osgi/service/monitor/MonitorPermission.java Sat Jul  7 22:49:38 2007
> @@ -0,0 +1,325 @@
> +/*
> + * $Header: /cvshome/build/org.osgi.service.monitor/src/org/osgi/service/monitor/MonitorPermission.java,v 1.9 2005/06/24 20:27:16 tszeredi Exp $
> + *
> + * Copyright (c) OSGi Alliance (2005). All Rights Reserved.
> + *
> + * This program and the accompanying materials are made available under the
> + * terms of the Eclipse Public License v1.0 which accompanies this
> + * distribution, and is available at http://www.eclipse.org/legal/epl-v10.html.
> + */
> +
> +package org.osgi.service.monitor;
> +
> +import java.security.Permission;
> +import java.util.StringTokenizer;
> +
> +/**
> + * Indicates the callers authority to publish, read or reset
> + * <code>StatusVariable</code>s, to switch event sending on or off or to
> + * start monitoring jobs. The target of the permission is the identifier of the
> + * <code>StatusVariable</code>, the action can be <code>read</code>,
> + * <code>publish</code>,<code>reset</code>,<code>startjob</code>,
> + * <code>switchevents</code>, or the combination of these separated by
> + * commas.
> + */
> +public class MonitorPermission extends Permission {
> +    // TODO add static final serialVersionUID
> +
> +    /**
> +     * Holders of <code>MonitorPermission</code> with the <code>read</code>
> +     * action present are allowed to read the value of the
> +     * <code>StatusVariable</code>s specified in the permission's target field.
> +     */
> +    public static final String READ = "read";
> +
> +    /**
> +     * Holders of <code>MonitorPermission</code> with the <code>reset</code>
> +     * action present are allowed to reset the value of the
> +     * <code>StatusVariable</code>s specified in the permission's target field.
> +     */
> +    public static final String RESET = "reset";
> +
> +    /**
> +     * Holders of <code>MonitorPermission</code> with the <code>publish</code>
> +     * action present are <code>Monitorable</code> services that are allowed
> +     * to publish the <code>StatusVariable</code>s specified in the
> +     * permission's target field.  Note, that this permission cannot be enforced
> +     * when a <code>Monitorable</code> registers to the framework, because the
> +     * Service Registry does not know about this permission.  Instead, any
> +     * <code>StatusVariable</code>s published by a <code>Monitorable</code>
> +     * without the corresponding <code>publish</code> permission are silently
> +     * ignored by <code>MonitorAdmin</code>, and are therefore invisible to the
> +     * users of the monitoring service.
> +     */
> +    public static final String PUBLISH = "publish";
> +
> +    /**
> +     * Holders of <code>MonitorPermission</code> with the <code>startjob</code>
> +     * action present are allowed to initiate monitoring jobs involving the
> +     * <code>StatusVariable</code>s specified in the permission's target field.
> +     * <p>
> +     * A minimal sampling interval can be optionally defined in the following
> +     * form: <code>startjob:n</code>.  This allows the holder of the permission
> +     * to initiate time based jobs with a measurement interval of at least
> +     * <code>n</code> seconds. If <code>n</code> is not specified or 0 then the
> +     * holder of this permission is allowed to start monitoring jobs specifying
> +     * any frequency.
> +     */
> +    public static final String STARTJOB = "startjob";
> +
> +    /**
> +     * Holders of <code>MonitorPermission</code> with the
> +     * <code>switchevents</code> action present are allowed to switch event
> +     * sending on or off for the value of the <code>StatusVariable</code>s
> +     * specified in the permission's target field.
> +     */
> +    public static final String SWITCHEVENTS = "switchevents";
> +
> +    private static final int READ_FLAG         = 0x1;
> +    private static final int RESET_FLAG        = 0x2;
> +    private static final int PUBLISH_FLAG      = 0x4;
> +    private static final int STARTJOB_FLAG     = 0x8;
> +    private static final int SWITCHEVENTS_FLAG = 0x10;
> +
> +    private String monId;
> +    private String varId;
> +    private boolean prefixMonId;
> +    private boolean prefixVarId;
> +    private int mask;
> +    private int minJobInterval;
> +
> +    /**
> +     * Create a <code>MonitorPermission</code> object, specifying the target
> +     * and actions.
> +     * <p>
> +     * The meaning of the <code>statusVariable</code> parameter is slightly
> +     * different depending on the <code>action</code> field, see the
> +     * descriptions of the individual actions.  In general, the wildcard
> +     * <code>*</code> is allowed in both fragments of the target string, but
> +     * only at the end of the fragments.
> +     * <p>
> +     * The following targets are valid:
> +     * <code>com.mycomp.myapp/queue_length</code>,
> +     * <code>com.mycomp.myapp/*</code>, <code>com.mycomp.&#42;/*</code>,
> +     * <code>&#42;/*</code>, <code>&#42;/queue_length</code>,
> +     * <code>&#42;/queue*</code>.
> +     * <p>
> +     * The following targets are invalid:
> +     * <code>*.myapp/queue_length</code>, <code>com.*.myapp/*</code>,
> +     * <code>*</code>.
> +     * <p>
> +     * The <code>actions</code> parameter specifies the allowed action(s):
> +     * <code>read</code>, <code>publish</code>, <code>startjob</code>,
> +     * <code>reset</code>, <code>switchevents</code>, or the combination of
> +     * these separated by commas.
> +     *
> +     * @param statusVariable the identifier of the <code>StatusVariable</code>
> +     *        in [Monitorable_id]/[StatusVariable_id] format
> +     * @param actions the list of allowed actions separated by commas
> +     * @throws java.lang.IllegalArgumentException if either parameter is
> +     *         <code>null</code>, or invalid with regard to the constraints
> +     *         defined above and in the documentation of the used actions
> +     */
> +    public MonitorPermission(String statusVariable, String actions)
> +            throws IllegalArgumentException {
> +        super(statusVariable);
> +
> +        if(statusVariable == null)
> +            throw new IllegalArgumentException(
> +                    "Invalid StatusVariable path 'null'.");
> +
> +        if(actions == null)
> +            throw new IllegalArgumentException(
> +                    "Invalid actions string 'null'.");
> +
> +        int sep = statusVariable.indexOf('/');
> +        int len = statusVariable.length();
> +
> +        if (sep == -1)
> +            throw new IllegalArgumentException(
> +                    "Invalid StatusVariable path: should contain '/' separator.");
> +        if (sep == 0 || sep == statusVariable.length() - 1)
> +            throw new IllegalArgumentException(
> +                    "Invalid StatusVariable path: empty monitorable ID or StatusVariable name.");
> +
> +        prefixMonId = statusVariable.charAt(sep - 1) == '*';
> +        prefixVarId = statusVariable.charAt(len - 1) == '*';
> +
> +        monId = statusVariable.substring(0, prefixMonId ? sep - 1 : sep);
> +        varId = statusVariable.substring(sep + 1, prefixVarId ? len - 1 : len);
> +
> +        checkId(monId, "Monitorable ID part of the target");
> +        checkId(varId, "Status Variable ID part of the target");
> +
> +        mask = 0;
> +        minJobInterval = 0;
> +
> +        StringTokenizer st = new StringTokenizer(actions, ",");
> +        while (st.hasMoreTokens()) {
> +            String action = st.nextToken();
> +            if (action.equalsIgnoreCase(READ)) {
> +                addToMask(READ_FLAG, READ);
> +            } else if (action.equalsIgnoreCase(RESET)) {
> +                addToMask(RESET_FLAG, RESET);
> +            } else if (action.equalsIgnoreCase(PUBLISH)) {
> +                addToMask(PUBLISH_FLAG, PUBLISH);
> +            } else if (action.equalsIgnoreCase(SWITCHEVENTS)) {
> +                addToMask(SWITCHEVENTS_FLAG, SWITCHEVENTS);
> +            } else if (action.toLowerCase().startsWith(STARTJOB)) {
> +                minJobInterval = 0;
> +
> +                int slen = STARTJOB.length();
> +                if (action.length() != slen) {
> +                    if (action.charAt(slen) != ':')
> +                        throw new IllegalArgumentException("Invalid action '"
> +                                + action + "'.");
> +
> +                    try {
> +                        minJobInterval = Integer.parseInt(action
> +                                .substring(slen + 1));
> +                    } catch (NumberFormatException e) {
> +                        throw new IllegalArgumentException(
> +                                "Invalid parameter in startjob action '"
> +                                        + action + "'.");
> +                    }
> +                }
> +                addToMask(STARTJOB_FLAG, STARTJOB);
> +            } else
> +                throw new IllegalArgumentException("Invalid action '" + action
> +                        + "'");
> +        }
> +    }
> +
> +    private void addToMask(int action, String actionString) {
> +        if((mask & action) != 0)
> +            throw new IllegalArgumentException("Invalid action string: " +
> +                    actionString + " appears multiple times.");
> +
> +        mask |= action;
> +    }
> +
> +    private void checkId(String id, String idName)
> +            throws IllegalArgumentException {
> +
> +        if (id.length() > StatusVariable.MAX_ID_LENGTH)
> +            throw new IllegalArgumentException(idName + " is too long (over "
> +                    + StatusVariable.MAX_ID_LENGTH + " characters).");
> +
> +        if (id.equals(".") || id.equals(".."))
> +            throw new IllegalArgumentException(idName + " is invalid.");
> +
> +        char[] chars = id.toCharArray();
> +        for (int i = 0; i < chars.length; i++)
> +            if (StatusVariable.SYMBOLIC_NAME_CHARACTERS.indexOf(chars[i]) == -1)
> +                throw new IllegalArgumentException(idName
> +                        + " contains invalid characters.");
> +    }
> +
> +    /**
> +     * Create an integer hash of the object. The hash codes of
> +     * <code>MonitorPermission</code>s <code>p1</code> and <code>p2</code> are
> +     * the same if <code>p1.equals(p2)</code>.
> +     *
> +     * @return the hash of the object
> +     */
> +    public int hashCode() {
> +        return new Integer(mask).hashCode()
> +                ^ new Integer(minJobInterval).hashCode() ^ monId.hashCode()
> +                ^ new Boolean(prefixMonId).hashCode()
> +                ^ varId.hashCode()
> +                ^ new Boolean(prefixVarId).hashCode();
> +    }
> +
> +    /**
> +     * Determines the equality of two <code>MonitorPermission</code> objects.
> +     * Two <code>MonitorPermission</code> objects are equal if their target
> +     * strings are equal and the same set of actions are listed in their action
> +     * strings.
> +     *
> +     * @param o the object being compared for equality with this object
> +     * @return <code>true</code> if the two permissions are equal
> +     */
> +    public boolean equals(Object o) {
> +        if (!(o instanceof MonitorPermission))
> +            return false;
> +
> +        MonitorPermission other = (MonitorPermission) o;
> +
> +        return mask == other.mask && minJobInterval == other.minJobInterval
> +                && monId.equals(other.monId)
> +                && prefixMonId == other.prefixMonId
> +                && varId.equals(other.varId)
> +                && prefixVarId == other.prefixVarId;
> +    }
> +
> +    /**
> +     * Get the action string associated with this permission.
> +     *
> +     * @return the allowed actions separated by commas, cannot be
> +     *         <code>null</code>
> +     */
> +    public String getActions() {
> +        StringBuffer sb = new StringBuffer();
> +
> +        appendAction(sb, READ_FLAG,         READ);
> +        appendAction(sb, RESET_FLAG,        RESET);
> +        appendAction(sb, PUBLISH_FLAG,      PUBLISH);
> +        appendAction(sb, STARTJOB_FLAG,     STARTJOB);
> +        appendAction(sb, SWITCHEVENTS_FLAG, SWITCHEVENTS);
> +
> +        return sb.toString();
> +    }
> +
> +    private void appendAction(StringBuffer sb, int flag, String actionName) {
> +        if ((mask & flag) != 0) {
> +            if(sb.length() != 0)
> +                sb.append(',');
> +            sb.append(actionName);
> +
> +            if(flag == STARTJOB_FLAG && minJobInterval != 0)
> +                sb.append(':').append(minJobInterval);
> +        }
> +    }
> +
> +    /**
> +     * Determines if the specified permission is implied by this permission.
> +     * <p>
> +     * This method returns <code>false</code> if and only if at least one of the
> +     * following conditions are fulfilled for the specified permission:
> +     * <li>it is not a <code>MonitorPermission</code>
> +     * <li>it has a broader set of actions allowed than this one
> +     * <li>it allows initiating time based monitoring jobs with a lower minimal
> +     * sampling interval
> +     * <li>the target set of <code>Monitorable</code>s is not the same nor a
> +     * subset of the target set of <code>Monitorable</code>s of this permission
> +     * <li>the target set of <code>StatusVariable</code>s is not the same
> +     * nor a subset of the target set of <code>StatusVariable</code>s of this
> +     * permission
> +     *
> +     * @param p the permission to be checked
> +     * @return <code>true</code> if the given permission is implied by this
> +     *         permission
> +     */
> +    public boolean implies(Permission p) {
> +        if (!(p instanceof MonitorPermission))
> +            return false;
> +
> +        MonitorPermission other = (MonitorPermission) p;
> +
> +        if ((mask & other.mask) != other.mask)
> +            return false;
> +
> +        if ((other.mask & STARTJOB_FLAG) != 0
> +                && minJobInterval > other.minJobInterval)
> +            return false;
> +
> +        return implies(monId, prefixMonId, other.monId, other.prefixMonId)
> +                && implies(varId, prefixVarId, other.varId, other.prefixVarId);
> +    }
> +
> +    private boolean implies(String id, boolean prefix, String oid,
> +            boolean oprefix) {
> +
> +        return prefix ? oid.startsWith(id) : !oprefix && id.equals(oid);
> +    }
> +}
>
> Propchange: felix/sandbox/donsez/monitoradmin/src/main/java/org/osgi/service/monitor/MonitorPermission.java
> ------------------------------------------------------------------------------
>     svn:eol-style = native
>
>
>


-- 
Karl Pauls
karlpauls@gmail.com

Re: svn commit: r554318 [1/2] - in /felix/sandbox/donsez/monitoradmin: ./ doc/ src/ src/main/ src/main/java/ src/main/java/org/ src/main/java/org/apache/ src/main/java/org/apache/felix/ src/main/java/org/apache/felix/monitor/ src/main/java/org/osgi/

Posted by "Richard S. Hall" <he...@ungoverned.org>.
Marcel Offermans wrote:
> On Jul 11, 2007, at 16:45 , Richard S. Hall wrote:
>
>> Niclas Hedhman wrote:
>>> On Tuesday 10 July 2007 01:52, Richard S. Hall wrote:
>>>
>>>> Should we have an sandbox package name space?
>>>>
>>>
>>> Agree.
>>
>> Well, it looks like we have Niclas and myself as +1 and Marcel as 
>> -1/0...can we come to a consensus about this?
>
> Whilst I don't see much benefit from using the sandbox package 
> namespace (whenever possible) I would not go so far as to "-1" the 
> proposal. As far as I'm concerned we can agree to use that namespace.

Karl also says that he isn't against the idea, so I propose that we 
enact this convention:

    If you are creating something new (i.e., not a branch) in your
    sandbox, then you should use the "org.apache.felix.sandbox" package
    space.

If we don't hear any objections in a couple of days, then we can 
considered this resolved.

-> richard

Re: svn commit: r554318 [1/2] - in /felix/sandbox/donsez/monitoradmin: ./ doc/ src/ src/main/ src/main/java/ src/main/java/org/ src/main/java/org/apache/ src/main/java/org/apache/felix/ src/main/java/org/apache/felix/monitor/ src/main/java/org/osgi/

Posted by Marcel Offermans <ma...@luminis.nl>.
On Jul 11, 2007, at 16:45 , Richard S. Hall wrote:

> Niclas Hedhman wrote:
>> On Tuesday 10 July 2007 01:52, Richard S. Hall wrote:
>>
>>> Should we have an sandbox package name space?
>>>
>>
>> Agree.
>
> Well, it looks like we have Niclas and myself as +1 and Marcel as  
> -1/0...can we come to a consensus about this?

Whilst I don't see much benefit from using the sandbox package  
namespace (whenever possible) I would not go so far as to "-1" the  
proposal. As far as I'm concerned we can agree to use that namespace.

Greetings, Marcel


Re: svn commit: r554318 [1/2] - in /felix/sandbox/donsez/monitoradmin: ./ doc/ src/ src/main/ src/main/java/ src/main/java/org/ src/main/java/org/apache/ src/main/java/org/apache/felix/ src/main/java/org/apache/felix/monitor/ src/main/java/org/osgi/

Posted by "Richard S. Hall" <he...@ungoverned.org>.
Niclas Hedhman wrote:
> On Tuesday 10 July 2007 01:52, Richard S. Hall wrote:
>   
>> Should we have an sandbox package name space?
>>     
>
> Agree.
>   

Well, it looks like we have Niclas and myself as +1 and Marcel as 
-1/0...can we come to a consensus about this?

-> richard

Re: svn commit: r554318 [1/2] - in /felix/sandbox/donsez/monitoradmin: ./ doc/ src/ src/main/ src/main/java/ src/main/java/org/ src/main/java/org/apache/ src/main/java/org/apache/felix/ src/main/java/org/apache/felix/monitor/ src/main/java/org/osgi/

Posted by Niclas Hedhman <ni...@hedhman.org>.
On Tuesday 10 July 2007 01:52, Richard S. Hall wrote:
> Should we have an sandbox package name space?

Agree.

Cheers
-- 
Niclas Hedhman, Software Developer

I  live here; http://tinyurl.com/2qq9er
I  work here; http://tinyurl.com/2ymelc
I relax here; http://tinyurl.com/2cgsug

Re: svn commit: r554318 [1/2] - in /felix/sandbox/donsez/monitoradmin: ./ doc/ src/ src/main/ src/main/java/ src/main/java/org/ src/main/java/org/apache/ src/main/java/org/apache/felix/ src/main/java/org/apache/felix/monitor/ src/main/java/org/osgi/

Posted by "Richard S. Hall" <he...@ungoverned.org>.
Marcel Offermans wrote:
> On Jul 9, 2007, at 19:52 , Richard S. Hall wrote:
>
>> Since the sandbox is for conducting experiments on code that might 
>> never be officially released into the trunk, perhaps we shouldn't be 
>> using the official package space...for example, we could use 
>> something like "org.apache.felix.sandbox.*" or something.
>
>> Of course, if you are experimenting with a branch of something that 
>> is already in the trunk, then this wouldn't be necessary, but for 
>> unbranched experiments it seems like we are opening up the potential 
>> for naming clashes.
>
> You say yourself that we cannot always use this convention, so I'd say 
> it's not necessary to have it. I think we should just agree that code 
> in the sandbox can never by released officially (neither as snapshots, 
> nor as parts of official releases). That eliminates most problems if 
> you ask me.

Well, it won't be possible to really enforce this since any arbitrary 
person could make it available. And I view branching an existing project 
for experimentation differently than a completely new experiment (i.e, 
it doesn't violate the convention since it is a branch)...

However, if the consensus is that this is not an issue, then I can live 
with it.

-> richard

>
>> Further, we need to have some overall agreement when assigning 
>> official package names, so this probably shouldn't be done in 
>> someone's sandbox. If an experiment moves from someone's sandbox into 
>> the trunk, then we should decide what its official package name 
>> should be.
>
> Yes, I agree, that is the time to formally review the code and package 
> naming is one of the issues that should be reviewed.
>
> Greetings, Marcel
>

Re: svn commit: r554318 [1/2] - in /felix/sandbox/donsez/monitoradmin: ./ doc/ src/ src/main/ src/main/java/ src/main/java/org/ src/main/java/org/apache/ src/main/java/org/apache/felix/ src/main/java/org/apache/felix/monitor/ src/main/java/org/osgi/

Posted by Marcel Offermans <ma...@luminis.nl>.
On Jul 9, 2007, at 19:52 , Richard S. Hall wrote:

> Since the sandbox is for conducting experiments on code that might  
> never be officially released into the trunk, perhaps we shouldn't  
> be using the official package space...for example, we could use  
> something like "org.apache.felix.sandbox.*" or something.

> Of course, if you are experimenting with a branch of something that  
> is already in the trunk, then this wouldn't be necessary, but for  
> unbranched experiments it seems like we are opening up the  
> potential for naming clashes.

You say yourself that we cannot always use this convention, so I'd  
say it's not necessary to have it. I think we should just agree that  
code in the sandbox can never by released officially (neither as  
snapshots, nor as parts of official releases). That eliminates most  
problems if you ask me.

> Further, we need to have some overall agreement when assigning  
> official package names, so this probably shouldn't be done in  
> someone's sandbox. If an experiment moves from someone's sandbox  
> into the trunk, then we should decide what its official package  
> name should be.

Yes, I agree, that is the time to formally review the code and  
package naming is one of the issues that should be reviewed.

Greetings, Marcel


Re: svn commit: r554318 [1/2] - in /felix/sandbox/donsez/monitoradmin: ./ doc/ src/ src/main/ src/main/java/ src/main/java/org/ src/main/java/org/apache/ src/main/java/org/apache/felix/ src/main/java/org/apache/felix/monitor/ src/main/java/org/osgi/

Posted by "Richard S. Hall" <he...@ungoverned.org>.
Another thing I was wondering about...

I notice that your sandbox experiments use the "org.apache.felix.*" 
package space for naming your packages. I wonder if this is what we 
should be using?

Since the sandbox is for conducting experiments on code that might never 
be officially released into the trunk, perhaps we shouldn't be using the 
official package space...for example, we could use something like 
"org.apache.felix.sandbox.*" or something.

Of course, if you are experimenting with a branch of something that is 
already in the trunk, then this wouldn't be necessary, but for 
unbranched experiments it seems like we are opening up the potential for 
naming clashes. Further, we need to have some overall agreement when 
assigning official package names, so this probably shouldn't be done in 
someone's sandbox. If an experiment moves from someone's sandbox into 
the trunk, then we should decide what its official package name should be.

What do other people think? Should we have an sandbox package name space?

-> richard

Karl Pauls wrote:
> I see that this commit contains EPL licensed code. This should change
> as soon as possible. I assume there is an ASL version available (since
> this are files from OSGi)?
>
> Other then that, I'd love to see somebody look into this since we
> don't have an implementation of the MonitorAdmin atm.... Thanks for
> making it available :-)
>
> regards,
>
> Karl
>
> p.s.: do we have any convention regarding packages names for stuff in
> the sandboxes? This one claims the org.apache.felix.monitor namespace
> ...
>
> On 7/8/07, donsez@apache.org <do...@apache.org> wrote:
>> Author: donsez
>> Date: Sat Jul  7 22:49:38 2007
>> New Revision: 554318
>>
>> URL: http://svn.apache.org/viewvc?view=rev&rev=554318
>> Log:
>> creation of the monitor bundle, an implementation of the monitor 
>> admin bundle
>>
>> Added:
>>     felix/sandbox/donsez/monitoradmin/
>>     felix/sandbox/donsez/monitoradmin/doc/
>>     felix/sandbox/donsez/monitoradmin/doc/readme.html   (with props)
>>     felix/sandbox/donsez/monitoradmin/pom.xml   (with props)
>>     felix/sandbox/donsez/monitoradmin/src/
>>     felix/sandbox/donsez/monitoradmin/src/main/
>>     felix/sandbox/donsez/monitoradmin/src/main/java/
>>     felix/sandbox/donsez/monitoradmin/src/main/java/org/
>>     felix/sandbox/donsez/monitoradmin/src/main/java/org/apache/
>>     felix/sandbox/donsez/monitoradmin/src/main/java/org/apache/felix/
>>     
>> felix/sandbox/donsez/monitoradmin/src/main/java/org/apache/felix/monitor/ 
>>
>>     
>> felix/sandbox/donsez/monitoradmin/src/main/java/org/apache/felix/monitor/Constants.java   
>> (with props)
>>     
>> felix/sandbox/donsez/monitoradmin/src/main/java/org/apache/felix/monitor/MonitorAdminImpl.java   
>> (with props)
>>     felix/sandbox/donsez/monitoradmin/src/main/java/org/osgi/
>>     felix/sandbox/donsez/monitoradmin/src/main/java/org/osgi/service/
>>     
>> felix/sandbox/donsez/monitoradmin/src/main/java/org/osgi/service/monitor/ 
>>
>>     
>> felix/sandbox/donsez/monitoradmin/src/main/java/org/osgi/service/monitor/MonitorAdmin.java   
>> (with props)
>>     
>> felix/sandbox/donsez/monitoradmin/src/main/java/org/osgi/service/monitor/MonitorListener.java   
>> (with props)
>>     
>> felix/sandbox/donsez/monitoradmin/src/main/java/org/osgi/service/monitor/MonitorPermission.java   
>> (with props)
>>     
>> felix/sandbox/donsez/monitoradmin/src/main/java/org/osgi/service/monitor/Monitorable.java   
>> (with props)
>>     
>> felix/sandbox/donsez/monitoradmin/src/main/java/org/osgi/service/monitor/MonitoringJob.java   
>> (with props)
>>     
>> felix/sandbox/donsez/monitoradmin/src/main/java/org/osgi/service/monitor/StatusVariable.java   
>> (with props)
>>     
>> felix/sandbox/donsez/monitoradmin/src/main/java/org/osgi/service/monitor/package.html   
>> (with props)
>>
>> Added: felix/sandbox/donsez/monitoradmin/doc/readme.html
>> URL: 
>> http://svn.apache.org/viewvc/felix/sandbox/donsez/monitoradmin/doc/readme.html?view=auto&rev=554318 
>>
>> ============================================================================== 
>>
>> --- felix/sandbox/donsez/monitoradmin/doc/readme.html (added)
>> +++ felix/sandbox/donsez/monitoradmin/doc/readme.html Sat Jul  7 
>> 22:49:38 2007
>> @@ -0,0 +1,71 @@
>> +<!DOCTYPE doctype PUBLIC "-//w3c//dtd html 4.0 transitional//en">
>> +<html>
>> +<head>
>> +  <meta http-equiv="Content-Type"
>> + content="text/html; charset=iso-8859-1">
>> +  <title>Monitor</title>
>> +</head>
>> +<body alink="#ff0000" vlink="#551a8b" link="#0000ee" bgcolor="#ffffff"
>> + text="#000000">
>> +<h1><i>Monitor</i></h1>
>> +
>> +<p><b>Description</b><br>
>> +This bundle provides a MonitorAdmin service (Chapter 119 Monitor 
>> Admin Service Specification Version 1.0)
>> +</p>
>> +</font>
>> +
>> +<p><b>Contributor(s)</b><br>
>> +Apache Felix Project Team</p>
>> +
>> +<p><b>License</b><br>
>> +ASL2
>> +</p>
>> +
>> +<p><b>Services</b><br>
>> +<ul>
>> +<li>org.osgi.service.monitor.MonitorAdmin</li>
>> +<li>org.osgi.service.monitor.MonitorListener</li>
>> +</ul>
>> +</p>
>> +
>> +
>> +<p><b>Provisions</b><br>
>> +None
>> +</p>
>> +
>> +<p id="doc"><b>Documentation</b><br>
>> +<ul>
>> +<li><a href=".">general</a></li>
>> +<li><a href="api">JavaDoc</a></li>
>> +</ul>
>> +</p>
>> +
>> +<p><b>Demo</b><br>
>> +run commands in <a 
>> href="http://www.apache.org/~donsez/dev/osgi/script/monitor.txt">http://www.apache.org/~donsez/dev/osgi/script/monitor.txt</a>. 
>>
>> +</p>
>> +
>> +
>> +
>> +<p id="history"><b>History</b><br>
>> +<ul>
>> +<li>0.1.0 : first draft implementation from the chapter 119 OSGi 
>> Mobile (Draft November 7, 2005 8:36 pm)</li>
>> +</ul>
>> +</p>
>> +
>> +
>> +
>> +<p id="todolist"><b>TODOLIST</b><br>
>> +<ul>
>> +<li>security: check permissions (MonitorPermission)</li>
>> +<li>complete monitoring job requester removal</li>
>> +</ul>
>> +</p>
>> +
>> +<p id="link"><b>Links</b><br>
>> +<ul>
>> +</ul>
>> +</p>
>> +
>> +
>> +</body>
>> +</html>
>>
>> Propchange: felix/sandbox/donsez/monitoradmin/doc/readme.html
>> ------------------------------------------------------------------------------ 
>>
>>     svn:eol-style = native
>>
>> Added: felix/sandbox/donsez/monitoradmin/pom.xml
>> URL: 
>> http://svn.apache.org/viewvc/felix/sandbox/donsez/monitoradmin/pom.xml?view=auto&rev=554318 
>>
>> ============================================================================== 
>>
>> --- felix/sandbox/donsez/monitoradmin/pom.xml (added)
>> +++ felix/sandbox/donsez/monitoradmin/pom.xml Sat Jul  7 22:49:38 2007
>> @@ -0,0 +1,116 @@
>> +<!--
>> + Licensed to the Apache Software Foundation (ASF) under one
>> + or more contributor license agreements.  See the NOTICE file
>> + distributed with this work for additional information
>> + regarding copyright ownership.  The ASF licenses this file
>> + to you 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.
>> +-->
>> +<project>
>> +
>> +       <properties>
>> +               
>> <repositoryLocation>http://www.apache.org/~donsez/dev/osgi/</repositoryLocation> 
>>
>> +               <description>provides an implementation of Monitor 
>> Admin.</description>
>> +       </properties>
>> +
>> +  <parent>
>> +    <groupId>org.apache.felix</groupId>
>> +    <artifactId>felix</artifactId>
>> +    <version>0.9.0-incubator-SNAPSHOT</version>
>> +  </parent>
>> +
>> +  <modelVersion>4.0.0</modelVersion>
>> +  <packaging>bundle</packaging>
>> +  <name>Apache Felix Monitor Admin</name>
>> +  <artifactId>org.apache.felix.monitor</artifactId>
>> +  <description>${description}</description>
>> +
>> +  <dependencies>
>> +    <dependency>
>> +      <groupId>${pom.groupId}</groupId>
>> +      <artifactId>org.osgi.core</artifactId>
>> +      <version>${pom.version}</version>
>> +    </dependency>
>> +    <dependency>
>> +      <groupId>${pom.groupId}</groupId>
>> +      <artifactId>org.osgi.compendium</artifactId>
>> +      <version>${pom.version}</version>
>> +    </dependency>
>> +  </dependencies>
>> +  <build>
>> +    <plugins>
>> +      <plugin>
>> +        <groupId>org.apache.felix</groupId>
>> +        <artifactId>maven-bundle-plugin</artifactId>
>> +        <extensions>true</extensions>
>> +        <configuration>
>> +          <instructions>
>> +
>> +               <!-- docs in 
>> http://cwiki.apache.org/FELIX/bundle-plugin-for-maven-bnd.html and 
>> http://cwiki.apache.org/FELIX/osgi-plugin-for-maven-2.html -->
>> +
>> +            <Export-Service>
>> +               org.osgi.service.monitor.MonitorAdmin,
>> +               org.osgi.service.monitor.MonitorListener
>> +            </Export-Service>
>> +
>> +                       <Import-Service>
>> +                               org.osgi.service.monitor.Monitorable,
>> +                               org.osgi.service.event.EventAdmin
>> +                       </Import-Service>
>> +
>> +            <Private-Package>${pom.artifactId}.*</Private-Package>
>> +            <Import-Package>*</Import-Package>
>> +            <!--
>> +               org.osgi.framework;specification-version=1.3.0,
>> +                               
>> org.osgi.util.tracker;specification-version=1.3.0,
>> +                               
>> org.osgi.service.event;specification-version=1.0.0
>> +                       -->
>> +
>> +            <Export-Package>org.osgi.service.monitor</Export-Package>
>> +
>> +            
>> <Bundle-Activator>${pom.artifactId}.MonitorAdminImpl</Bundle-Activator>
>> +
>> +            <!--
>> +            
>> <Bundle-DocURL>${repositoryLocation}${pom.artifactId}/index.html</Bundle-DocURL> 
>>
>> +            
>> <Bundle-Url>${repositoryLocation}${pom.artifactId}/${pom.artifactId}-${pom.version}.jar</Bundle-Url> 
>>
>> +            
>> <Bundle-Source>${repositoryLocation}${pom.artifactId}/${pom.artifactId}-${pom.version}-src.jar</Bundle-Source> 
>>
>> +                       -->
>> +
>> +            <!--
>> +            
>> <Bundle-SymbolicName>${pom.artifactId}</Bundle-SymbolicName>
>> +            <Bundle-Description>${description}</Bundle-Description>
>> +            <Bundle-Vendor>Apache Software Foundation</Bundle-Vendor>
>> +                       -->
>> +
>> +          </instructions>
>> +        </configuration>
>> +      </plugin>
>> +    </plugins>
>> +  </build>
>> +  <!--
>> +  <repositories>
>> +    <repository>
>> +      <id>apache.m2.incubator</id>
>> +      <name>Apache M2 Incubator Repository</name>
>> +      
>> <url>http://people.apache.org/repo/m2-incubating-repository/</url>
>> +    </repository>
>> +  </repositories>
>> +  <pluginRepositories>
>> +    <pluginRepository>
>> +      <id>apache.m2.incubator</id>
>> +      <name>Apache M2 Incubator Repository</name>
>> +      
>> <url>http://people.apache.org/repo/m2-incubating-repository/</url>
>> +    </pluginRepository>
>> +  </pluginRepositories>
>> +  -->
>> +</project>
>>
>> Propchange: felix/sandbox/donsez/monitoradmin/pom.xml
>> ------------------------------------------------------------------------------ 
>>
>>     svn:eol-style = native
>>
>> Added: 
>> felix/sandbox/donsez/monitoradmin/src/main/java/org/apache/felix/monitor/Constants.java 
>>
>> URL: 
>> http://svn.apache.org/viewvc/felix/sandbox/donsez/monitoradmin/src/main/java/org/apache/felix/monitor/Constants.java?view=auto&rev=554318 
>>
>> ============================================================================== 
>>
>> --- 
>> felix/sandbox/donsez/monitoradmin/src/main/java/org/apache/felix/monitor/Constants.java 
>> (added)
>> +++ 
>> felix/sandbox/donsez/monitoradmin/src/main/java/org/apache/felix/monitor/Constants.java 
>> Sat Jul  7 22:49:38 2007
>> @@ -0,0 +1,37 @@
>> +/*
>> + * Licensed to the Apache Software Foundation (ASF) under one
>> + * or more contributor license agreements.  See the NOTICE file
>> + * distributed with this work for additional information
>> + * regarding copyright ownership.  The ASF licenses this file
>> + * to you 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.monitor;
>> +
>> +/**
>> + * this interface provides constants related to the Monitor Admin.
>> + * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
>> + */
>> +
>> +public interface Constants {
>> +       // The events posted by MonitorAdmin contain the following 
>> properties:
>> +       public final static String TOPIC = "org/osgi/service/monitor";
>> +       // The identifier of the Monitorable
>> +       public final static String 
>> MON_MONITORABLE_PID="mon.monitorable.pid";
>> +       // The identifier of the StatusVariable within the given 
>> Monitorable
>> +       public final static String 
>> MON_STATUSVARIABLE_NAME="mon.statusvariable.name";
>> +       // The value of the StatusVariable, represented as a String
>> +       public final static String 
>> MON_STATUSVARIABLE_VALUE="mon.statusvariable.value";
>> +       // The identifier of the initiator of the monitoring job 
>> (only present if the event was generated due to a monitoring job)
>> +       public final static String MON_LISTENER_ID="mon.listener.id";
>> +}
>>
>> Propchange: 
>> felix/sandbox/donsez/monitoradmin/src/main/java/org/apache/felix/monitor/Constants.java 
>>
>> ------------------------------------------------------------------------------ 
>>
>>     svn:eol-style = native
>>
>> Added: 
>> felix/sandbox/donsez/monitoradmin/src/main/java/org/apache/felix/monitor/MonitorAdminImpl.java 
>>
>> URL: 
>> http://svn.apache.org/viewvc/felix/sandbox/donsez/monitoradmin/src/main/java/org/apache/felix/monitor/MonitorAdminImpl.java?view=auto&rev=554318 
>>
>> ============================================================================== 
>>
>> --- 
>> felix/sandbox/donsez/monitoradmin/src/main/java/org/apache/felix/monitor/MonitorAdminImpl.java 
>> (added)
>> +++ 
>> felix/sandbox/donsez/monitoradmin/src/main/java/org/apache/felix/monitor/MonitorAdminImpl.java 
>> Sat Jul  7 22:49:38 2007
>> @@ -0,0 +1,904 @@
>> +/*
>> + * Licensed to the Apache Software Foundation (ASF) under one
>> + * or more contributor license agreements.  See the NOTICE file
>> + * distributed with this work for additional information
>> + * regarding copyright ownership.  The ASF licenses this file
>> + * to you 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.monitor;
>> +
>> +import java.util.ArrayList;
>> +import java.util.Dictionary;
>> +import java.util.HashMap;
>> +import java.util.Hashtable;
>> +import java.util.Iterator;
>> +import java.util.LinkedList;
>> +import java.util.List;
>> +import java.util.Map;
>> +import java.util.SortedSet;
>> +import java.util.TreeSet;
>> +
>> +import org.osgi.framework.Bundle;
>> +import org.osgi.framework.BundleActivator;
>> +import org.osgi.framework.BundleContext;
>> +import org.osgi.framework.Constants;
>> +import org.osgi.framework.ServiceFactory;
>> +import org.osgi.framework.ServiceReference;
>> +import org.osgi.framework.ServiceRegistration;
>> +import org.osgi.service.event.Event;
>> +import org.osgi.service.event.EventAdmin;
>> +import org.osgi.service.monitor.MonitorAdmin;
>> +import org.osgi.service.monitor.MonitorListener;
>> +import org.osgi.service.monitor.Monitorable;
>> +import org.osgi.service.monitor.MonitoringJob;
>> +import org.osgi.service.monitor.StatusVariable;
>> +import org.osgi.util.tracker.ServiceTracker;
>> +import org.osgi.util.tracker.ServiceTrackerCustomizer;
>> +
>> +
>> +/**
>> + * this class provides an implementation of the Monitor Admin.
>> + * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
>> + */
>> +
>> +public class MonitorAdminImpl implements BundleActivator, 
>> org.apache.felix.monitor.Constants {
>> +
>> +       class MonitoringJobImpl implements MonitoringJob, 
>> MonitorListener {
>> +
>> +               private MonitorAdminProxy monitorAdminProxy;
>> +
>> +               private String initiator;
>> +
>> +               private String[] statusVariables;
>> +
>> +               private int schedule;
>> +
>> +               private int count;
>> +
>> +               private boolean isStopped=false;
>> +
>> +               private int currentCounter=0;
>> +
>> +               private Thread thread;
>> +
>> +               /**
>> +                * @param monitorAdminProxy
>> +                *            the monitorAdminProxy which start the job
>> +                * @param initiator
>> +                *            the identifier of the entity that 
>> initiated the job
>> +                * @param statusVariables
>> +                *            the list of StatusVariables to be 
>> monitored, with each
>> +                *            StatusVariable name given in
>> +                *            [Monitorable_PID]/[StatusVariable_ID] 
>> format
>> +                * @param count
>> +                *            the number of changes that must happen 
>> to a StatusVariable
>> +                *            before a new notification is sent
>> +                * @throws IllegalArgumentException
>> +                * @throws SecurityException
>> +                */
>> +               public MonitoringJobImpl(
>> +                               MonitorAdminProxy monitorAdminProxy, 
>> String initiator,
>> +                               String[] statusVariables, int count)
>> +                               throws IllegalArgumentException, 
>> SecurityException {
>> +                       this.monitorAdminProxy = monitorAdminProxy;
>> +                       this.initiator = initiator;
>> +                       this.statusVariables = statusVariables;
>> +                       this.count = count;
>> +                       this.schedule = 0;
>> +
>> +                       subscribeStatusVariables();
>> +               }
>> +
>> +
>> +               /**
>> +                * @param monitorAdminProxy
>> +                *            the monitorAdminProxy which start the job
>> +                * @param initiator
>> +                *            the identifier of the entity that 
>> initiated the job
>> +                * @param statusVariables
>> +                *            the list of StatusVariables to be 
>> monitored, with each
>> +                *            StatusVariable name given in
>> +                *            [Monitorable_PID]/[StatusVariable_ID] 
>> format
>> +                * @param schedule
>> +                *            the time in seconds between two 
>> measurements
>> +                * @param count
>> +                *            the number of measurements to be taken, 
>> or 0 for the
>> +                *            measurement to run until explicitely 
>> stopped
>> +                *
>> +                * @throws IllegalArgumentException
>> +                * @throws SecurityException
>> +                */
>> +               public MonitoringJobImpl(
>> +                               MonitorAdminProxy monitorAdminProxy, 
>> String initiator,
>> +                               String[] statusVariables, int 
>> schedule, int count)
>> +                               throws IllegalArgumentException, 
>> SecurityException {
>> +                       this.monitorAdminProxy = monitorAdminProxy;
>> +                       this.initiator = initiator;
>> +                       this.statusVariables = statusVariables;
>> +                       this.count = count;
>> +                       this.schedule = schedule;
>> +
>> +                       thread=new Thread(new MyRunnable());
>> +                       thread.start();
>> +               }
>> +
>> +               class MyRunnable implements Runnable {
>> +
>> +                       public void run() {
>> +                               while(!isStopped){ // TODO check if 
>> notification is before or after the sleep ?
>> +                                       for(int 
>> i=0;i<statusVariables.length;i++){
>> +                                               String 
>> path=statusVariables[i];
>> +                                               StatusVariable 
>> statusVariable=monitorAdminProxy.getStatusVariable(path);
>> +                                               
>> updated(path.substring(0,path.indexOf('/')),statusVariable);
>> +                                       }
>> +
>> +                                       if(--count>0){
>> +                                               isStopped=true;
>> +                                       }
>> +
>> +                                       try {
>> +                                               
>> Thread.sleep(schedule*1000);
>> +                                       } catch (InterruptedException 
>> e) {
>> +                                       }
>> +                                       // if(isStopped) break;
>> +
>> +                               }
>> +                       }
>> +               }
>> +
>> +               public void stop() {
>> +                       isStopped=true;
>> +                       unsubscribeStatusVariables();
>> +                       monitorAdminProxy.monitoringJobs.remove(this);
>> +               }
>> +
>> +               private void subscribeStatusVariables() {
>> +                       for(int i=0;i<statusVariables.length;i++){
>> +                               String 
>> statusVariableName=statusVariables[i];
>> +                               List 
>> list=(List)subscriptions.get(statusVariableName);
>> +                               if(list==null) {
>> +                                       list=new LinkedList();
>> +                                       
>> subscriptions.put(statusVariableName,list);
>> +                               }
>> +                               list.add(this);
>> +                       }
>> +               }
>> +
>> +               private void unsubscribeStatusVariables() {
>> +                       for(int i=0;i<statusVariables.length;i++){
>> +                               String 
>> statusVariableName=statusVariables[i];
>> +                               List 
>> list=(List)subscriptions.get(statusVariableName);
>> +                               if(list!=null) {
>> +                                       list.remove(this);
>> +                               } // else never occurs
>> +                               if(list.isEmpty())
>> +                                       
>> subscriptions.remove(statusVariableName);
>> +                       }
>> +               }
>> +
>> +               public String getInitiator() {
>> +                       return initiator;
>> +               }
>> +
>> +               public String[] getStatusVariableNames() {
>> +                       return statusVariables;
>> +               }
>> +
>> +               public long getSchedule() {
>> +                       return schedule;
>> +               }
>> +
>> +               public int getReportCount() {
>> +                       return count;
>> +               }
>> +
>> +               public boolean isLocal() {
>> +                       return true;
>> +               }
>> +
>> +               public void updated(String monitorableId, 
>> StatusVariable statusVariable)
>> +                               throws IllegalArgumentException {
>> +                       if(isStopped) return;
>> +                       if(schedule==0){
>> +                               if((++currentCounter)<count) return;
>> +                               currentCounter=0;
>> +                       } else {
>> +                               // TODO
>> +
>> +                       }
>> +
>> +                       if (monitorableId == null)
>> +                               throw new 
>> IllegalArgumentException("null monitorableId");
>> +                       if (statusVariable == null)
>> +                               throw new 
>> IllegalArgumentException("null statusVariable");
>> +                       String topic = TOPIC;
>> +                       Dictionary properties = new Hashtable();
>> +                       properties.put("mon.monitorable.pid", 
>> monitorableId);
>> +                       properties.put("mon.statusvariable.name", 
>> statusVariable.getID());
>> +
>> +                       Object value = null;
>> +                       switch (statusVariable.getType()) { // TODO 
>> float->double, int->long
>> +                       case StatusVariable.TYPE_BOOLEAN:
>> +                               value = new 
>> Boolean(statusVariable.getBoolean());
>> +                               break;
>> +                       case StatusVariable.TYPE_FLOAT:
>> +                               value = new 
>> Float(statusVariable.getFloat());
>> +                               break;
>> +                       case StatusVariable.TYPE_INTEGER:
>> +                               value = new 
>> Integer(statusVariable.getInteger());
>> +                               break;
>> +                       case StatusVariable.TYPE_STRING:
>> +                               value = statusVariable.getString();
>> +                               break;
>> +                       }
>> +                       properties.put(MON_STATUSVARIABLE_VALUE, value);
>> +                       properties.put(MON_LISTENER_ID, initiator);
>> +                       Event event = new Event(topic, properties);
>> +                       EventAdmin eventAdmin = (EventAdmin) 
>> eventAdminServiceTracker
>> +                                       .getService();
>> +                       if (eventAdmin != null)
>> +                               eventAdmin.sendEvent(event);
>> +               }
>> +       }
>> +
>> +       class MonitorAdminServiceFactory implements ServiceFactory {
>> +
>> +               List monitorAdminProxies = new ArrayList();
>> +
>> +               MonitorAdminImpl monitorAdminImpl;
>> +
>> +               MonitorAdminServiceFactory(MonitorAdminImpl 
>> monitorAdminImpl) {
>> +                       this.monitorAdminImpl = monitorAdminImpl;
>> +               }
>> +
>> +               public Object getService(Bundle bundle,
>> +                               ServiceRegistration 
>> serviceRegistration) {
>> +                       MonitorAdminProxy monitorAdminProxy = new 
>> MonitorAdminProxy(bundle,
>> +                                       monitorAdminImpl);
>> +                       monitorAdminProxies.add(monitorAdminProxy);
>> +                       return monitorAdminProxy;
>> +               }
>> +
>> +               public void ungetService(Bundle bundle,
>> +                               ServiceRegistration 
>> serviceRegistration, Object object) {
>> +                       monitorAdminProxies.remove(object);
>> +               }
>> +       }
>> +
>> +       class MonitorAdminProxy implements MonitorAdmin {
>> +               Bundle bundle;
>> +
>> +               MonitorAdminImpl monitorAdminImpl;
>> +
>> +               List monitoringJobs = new ArrayList();
>> +
>> +               MonitorAdminProxy(Bundle bundle, MonitorAdminImpl 
>> monitorAdminImpl) {
>> +                       this.bundle = bundle;
>> +                       this.monitorAdminImpl = monitorAdminImpl;
>> +               }
>> +
>> +               /**
>> +                * ? Returns a StatusVariable addressed by its full 
>> path. The entity
>> +                * which queries a StatusVariable needs to hold 
>> MonitorPermission for
>> +                * the given target with the read action present.
>> +                *
>> +                * @param path
>> +                *            the full path of the StatusVariable in
>> +                *            [Monitorable_ID]/[StatusVariable_ID] 
>> format
>> +                * @return the StatusVariable object
>> +                * @throws IllegalArgumentException –
>> +                *             if path is null or otherwise invalid, 
>> or points to a
>> +                *             non-existing StatusVariable
>> +                * @throws SecurityException –
>> +                *             if the caller does not hold a 
>> MonitorPermission for the
>> +                *             StatusVariable specified by path with 
>> the read action
>> +                *             present
>> +                */
>> +               public StatusVariable getStatusVariable(String path)
>> +                               throws IllegalArgumentException, 
>> SecurityException {
>> +                       checkPermissions();
>> +
>> +                       if (path == null)
>> +                               throw new 
>> IllegalArgumentException("null path");
>> +                       int pos = path.indexOf('/');
>> +                       if (pos <= 0 || pos == path.length() - 1)
>> +                               throw new 
>> IllegalArgumentException("invalid path");
>> +                       String pid = path.substring(0, pos);
>> +                       String name = path.substring(pos + 1);
>> +                       MonitorableEntry monitorableEntry = 
>> (MonitorableEntry) monitorables
>> +                                       .get(pid);
>> +                       if (monitorableEntry == null)
>> +                               throw new IllegalArgumentException(
>> +                                               "no such monitorable 
>> service for this pid");
>> +                       return 
>> monitorableEntry.monitorable.getStatusVariable(name);
>> +               }
>> +
>> +               /**
>> +                * The Monitorable instances are not accessible 
>> through the
>> +                * MonitorAdmin, so that requests to individual 
>> status variables can be
>> +                * filtered with respect to the publishing rights of 
>> the Monitorable and
>> +                * the reading rights of the caller. The returned 
>> array contains the
>> +                * names in alphabetical order. It cannot be null, an 
>> empty array is
>> +                * returned if no Monitorable services are 
>> registered. Returns the array
>> +                * of Monitorable names
>> +                *
>> +                * @return the names of the Monitorable services that 
>> are currently
>> +                *         registered.
>> +                */
>> +               public String[] getMonitorableNames() {
>> +                       SortedSet pids = new TreeSet();
>> +                       Iterator iterator = 
>> monitorables.keySet().iterator();
>> +                       while (iterator.hasNext()) {
>> +                               String pid = (String) iterator.next();
>> +                               pids.add(pid);
>> +                       }
>> +                       return (String[]) pids.toArray(new 
>> String[pids.size()]);
>> +               }
>> +
>> +               /**
>> +                * The StatusVariables will hold the values taken at 
>> the time of this
>> +                * method call. Only those status variables are 
>> returned where the
>> +                * following two conditions are met: • the specified 
>> Monitorable holds a
>> +                * MonitorPermission for the status variable with the 
>> publish action
>> +                * present • the caller holds a MonitorPermission 
>> for the status
>> +                * variable with the read action present
>> +                * <p>
>> +                * The elements in the returned array are in no 
>> particular order. The
>> +                * return value cannot be null, an empty array is 
>> returned if no
>> +                * (authorized and readable) Status Variables are 
>> provided by the given
>> +                * Monitorable. Returns a list of StatusVariable 
>> objects published by
>> +                * the specified Monitorable
>> +                *
>> +                * @param monitorableId
>> +                *            the identifier of a Monitorable instance
>> +                * @return the StatusVariable objects published by a 
>> Monitorable
>> +                *         instance.
>> +                * @throws IllegalArgumentException –
>> +                *             if monitorableId is null or otherwise 
>> invalid, or points
>> +                *             to a non-existing Monitorable
>> +                */
>> +               public StatusVariable[] getStatusVariables(String 
>> monitorableId)
>> +                               throws IllegalArgumentException {
>> +                       checkPermissions();
>> +                       if (monitorableId == null)
>> +                               throw new 
>> IllegalArgumentException("null monitorableId");
>> +                       MonitorableEntry monitorableEntry = 
>> (MonitorableEntry) monitorables
>> +                                       .get(monitorableId);
>> +                       if (monitorableEntry == null)
>> +                               throw new IllegalArgumentException(
>> +                                               "no such monitorable 
>> service for this pid");
>> +                       Monitorable monitorable = 
>> monitorableEntry.monitorable;
>> +                       String[] statusVariableNames = 
>> monitorableEntry.statusVariableNames;
>> +                       StatusVariable[] statusVariables = new 
>> StatusVariable[statusVariableNames.length];
>> +                       for (int i = 0; i < 
>> statusVariableNames.length; i++) {
>> +                               statusVariables[i] = monitorable
>> +                                               
>> .getStatusVariable(statusVariableNames[i]);
>> +                       }
>> +                       return statusVariables;
>> +               }
>> +
>> +               /**
>> +                * ? Returns the list of StatusVariable names 
>> published by a
>> +                * Monitorable instance. Only those status variables 
>> are listed where
>> +                * the following two conditions are met: • the 
>> specified Monitorable
>> +                * holds a MonitorPermission for the status variable 
>> with the publish
>> +                * action present • the caller holds a 
>> MonitorPermission for the status
>> +                * variable with the read action present The returned 
>> array does not
>> +                * contain duplicates, and the elements are in 
>> alphabetical order. It
>> +                * cannot be null, an empty array is returned if no 
>> (authorized and
>> +                * readable) Status Variables are provided by the 
>> given Monitorable.
>> +                *
>> +                * @param monitorableId
>> +                *            the identifier of a Monitorable instance
>> +                * @return a list of StatusVariable objects names 
>> published by the
>> +                *         specified Monitorable
>> +                * @throws IllegalArgumentException –
>> +                *             if monitorableId is null or otherwise 
>> invalid, or points
>> +                *             to a non-existing Monitorable
>> +                */
>> +               public String[] getStatusVariableNames(String 
>> monitorableId)
>> +                               throws IllegalArgumentException {
>> +                       checkPermissions();
>> +                       if (monitorableId == null)
>> +                               throw new 
>> IllegalArgumentException("null monitorableId");
>> +                       MonitorableEntry monitorableEntry = 
>> (MonitorableEntry) monitorables
>> +                                       .get(monitorableId);
>> +                       if (monitorableEntry == null)
>> +                               throw new IllegalArgumentException(
>> +                                               "no such monitorable 
>> service for this pid");
>> +                       return monitorableEntry.statusVariableNames;
>> +               }
>> +
>> +               /**
>> +                * ? Switches event sending on or off for the specified
>> +                * StatusVariables. When the MonitorAdmin is notified 
>> about a
>> +                * StatusVariable being updated it sends an event 
>> unless this feature is
>> +                * switched off. Note that events within a monitoring 
>> job can not be
>> +                * switched off. The event sending state of the 
>> StatusVariables must not
>> +                * be persistently stored. When a StatusVariable is 
>> registered for the
>> +                * first time in a framework session, its event 
>> sending state is set to
>> +                * ON by default.
>> +                * <p>
>> +                * Usage of the Â"*Â" wildcard is allowed in the path 
>> argument of this
>> +                * method as a convenience feature. The wildcard can 
>> be used in either
>> +                * or both path fragments, but only at the end of the 
>> fragments. The
>> +                * semantics of the wildcard is that it stands for 
>> any matching
>> +                * StatusVariable at the time of the method call, it 
>> does not affect the
>> +                * event sending status of StatusVariables which are 
>> not yet registered.
>> +                * As an example, when the 
>> switchEvents(Â"MyMonitorable/ Â", false) method
>> +                * is executed, event sending from all 
>> StatusVariables of the
>> +                * MyMonitorable service are switched off. However, 
>> if the MyMonitorable
>> +                * service starts to publish a new StatusVariable 
>> later, itÂ's event
>> +                * sending status is on by default.
>> +                *
>> +                * @param path
>> +                *            the identifier of the StatusVariable(s) in
>> +                *            [Monitorable_id]/ [StatusVariable_id] 
>> format, possibly
>> +                *            with the Â"*Â" wildcard at the end of 
>> either path fragment
>> +                * @param on
>> +                *            false if event sending should be 
>> switched off, true if it
>> +                *            should be switched on for the given path
>> +                * @throws SecurityException –
>> +                *             if the caller does not hold 
>> MonitorPermission with the
>> +                *             switchevents action or if there is any 
>> StatusVariable in
>> +                *             the path field for which it is not 
>> allowed to switch
>> +                *             event sending on or off as per the 
>> target field of the
>> +                *             permission
>> +                * @throws IllegalArgumentException –
>> +                *             if path is null or otherwise invalid, 
>> or points to a
>> +                *             non-existing StatusVariable
>> +                * @see 
>> org.osgi.service.monitor.MonitorAdmin#switchEvents(java.lang.String,
>> +                *      boolean)
>> +                */
>> +               public void switchEvents(String path, boolean on)
>> +                               throws IllegalArgumentException, 
>> SecurityException {
>> +                       checkPermissions();
>> +                       // TODO
>> +                       throw new IllegalArgumentException("not 
>> implemented");
>> +               }
>> +
>> +               /**
>> +                * ? Issues a request to reset a given 
>> StatusVariable. Depending on the
>> +                * semantics of the StatusVariable this call may or 
>> may not succeed: it
>> +                * makes sense to reset a counter to its starting 
>> value, but e.g. a
>> +                * StatusVariable of type String might not have a 
>> meaningful default
>> +                * value. Note that for numeric Status- Variables the 
>> starting value may
>> +                * not necessarily be 0. Resetting a StatusVariable 
>> triggers a monitor
>> +                * event if the StatusVariable supports update 
>> notifications.
>> +                * <p>
>> +                * The entity that wants to reset the StatusVariable 
>> needs to hold
>> +                * MonitorPermission with the reset action present. 
>> The target field of
>> +                * the permission must match the StatusVariable name 
>> to be reset.
>> +                *
>> +                * @param path
>> +                *            the identifier of the StatusVariable in
>> +                *            [Monitorable_id]/[StatusVariable_id] 
>> format
>> +                * @return true if the Monitorable could successfully 
>> reset the given
>> +                *         StatusVariable, false otherwise
>> +                * @throws IllegalArgumentException –
>> +                *             if path is null or otherwise invalid, 
>> or points to a
>> +                *             non-existing StatusVariable
>> +                * @throws SecurityException –
>> +                *             if the caller does not hold 
>> MonitorPermission with the
>> +                *             reset action or if the specified 
>> StatusVariable is not
>> +                *             allowed to be reset as per the target 
>> field of the
>> +                *             permission
>> +                * @see 
>> org.osgi.service.monitor.MonitorAdmin#resetStatusVariable(java.lang.String) 
>>
>> +                */
>> +               public boolean resetStatusVariable(String path)
>> +                               throws IllegalArgumentException, 
>> SecurityException {
>> +                       checkPermissions();
>> +                       if (path == null)
>> +                               throw new 
>> IllegalArgumentException("null path");
>> +                       int pos = path.indexOf('/');
>> +                       if (pos <= 0 || pos == path.length() - 1)
>> +                               throw new 
>> IllegalArgumentException("invalid path");
>> +                       String pid = path.substring(0, pos);
>> +                       String name = path.substring(pos + 1);
>> +                       MonitorableEntry monitorableEntry = 
>> (MonitorableEntry) monitorables
>> +                                       .get(pid);
>> +                       if (monitorableEntry == null)
>> +                               throw new IllegalArgumentException(
>> +                                               "no such monitorable 
>> service for this pid");
>> +                       return 
>> monitorableEntry.monitorable.resetStatusVariable(name);
>> +               }
>> +
>> +               /**
>> +                * The entity that queries a StatusVariable needs to 
>> hold
>> +                * MonitorPermission for the given target with the 
>> read action present.
>> +                *
>> +                * @param path
>> +                *            the full path of the StatusVariable in
>> +                *            [Monitorable_ID]/[StatusVariable_ID] 
>> format ?return a
>> +                *            human readable description of the given 
>> StatusVariable.
>> +                *            The null value may be returned if there 
>> is no description
>> +                *            for the given StatusVariable.
>> +                * @eturn the human readable description of this 
>> StatusVariable or null
>> +                *        if it is not set
>> +                * @throws IllegalArgumentException –
>> +                *             if path is null or otherwise invalid, 
>> or points to a
>> +                *             non-existing StatusVariable
>> +                * @throwsSecurityException – if the caller does not 
>> hold a
>> +                *                          MonitorPermission for the 
>> StatusVariable
>> +                *                          specified by path with 
>> the read action
>> +                *                          present *
>> +                * @see 
>> org.osgi.service.monitor.MonitorAdmin#getDescription(java.lang.String)
>> +                */
>> +               public String getDescription(String path)
>> +                               throws IllegalArgumentException, 
>> SecurityException {
>> +                       checkPermissions();
>> +                       if (path == null)
>> +                               throw new 
>> IllegalArgumentException("null path");
>> +                       int pos = path.indexOf('/');
>> +                       if (pos <= 0 || pos == path.length() - 1)
>> +                               throw new 
>> IllegalArgumentException("invalid path");
>> +                       String pid = path.substring(0, pos);
>> +                       String name = path.substring(pos + 1);
>> +                       MonitorableEntry monitorableEntry = 
>> (MonitorableEntry) monitorables
>> +                                       .get(pid);
>> +                       if (monitorableEntry == null)
>> +                               throw new IllegalArgumentException(
>> +                                               "no such monitorable 
>> service for this pid");
>> +                       return 
>> monitorableEntry.monitorable.getDescription(name);
>> +               }
>> +
>> +               /**
>> +                * ? Starts a time based MonitoringJob with the 
>> parameters provided.
>> +                * Monitoring events will be sent according to the 
>> specified schedule.
>> +                * All specified StatusVariables must exist when the 
>> job is started. The
>> +                * initiator string is used in the mon.listener.id 
>> field of all events
>> +                * triggered by the job, to allow filtering the 
>> events based on the
>> +                * initiator.
>> +                * <p>
>> +                * The schedule parameter specifies the time in 
>> seconds between two
>> +                * measurements, it must be greater than 0. The first 
>> measurement will
>> +                * be taken when the timer expires for the first 
>> time, not when this
>> +                * method is called.
>> +                * <p>
>> +                * The count parameter defines the number of 
>> measurements to be taken,
>> +                * and must either be a positive integer, or 0 if the 
>> measurement is to
>> +                * run until explicitely stopped.
>> +                * <p>
>> +                * The entity which initiates a MonitoringJob needs 
>> to hold
>> +                * MonitorPermission for all the specified target 
>> StatusVariables with
>> +                * the startjob action present. If the permissionÂ's 
>> action string
>> +                * specifies a minimal sampling interval then the 
>> schedule parameter
>> +                * should be at least as great as the value in the 
>> action string.
>> +                *
>> +                * @param initiator
>> +                *            the identifier of the entity that 
>> initiated the job
>> +                * @param statusVariables
>> +                *            the list of StatusVariables to be 
>> monitored, with each
>> +                *            StatusVariable name given in
>> +                *            [Monitorable_PID]/[StatusVariable_ID] 
>> format
>> +                * @param schedule
>> +                *            the time in seconds between two 
>> measurements
>> +                * @param count
>> +                *            the number of measurements to be taken, 
>> or 0 for the
>> +                *            measurement to run until explicitely 
>> stopped
>> +                *
>> +                * @return the successfully started job object, 
>> cannot be null
>> +                * @throws IllegalArgumentException
>> +                *             if the list of StatusVariable names 
>> contains an invalid
>> +                *             or non-existing StatusVariable; if 
>> initiator is null or
>> +                *             empty; or if the schedule or count 
>> parameters are invalid
>> +                * @throws SecurityException –
>> +                *             if the caller does not hold 
>> MonitorPermission for all the
>> +                *             specified StatusVariables, with the 
>> startjob action
>> +                *             present, or if the permission does not 
>> allow starting the
>> +                *             job with the given frequency
>> +                * @see 
>> org.osgi.service.monitor.MonitorAdmin#startScheduledJob(java.lang.String, 
>>
>> +                *      java.lang.String[], int, int)
>> +                */
>> +               public MonitoringJob startScheduledJob(String initiator,
>> +                               String[] statusVariables, int 
>> schedule, int count)
>> +                               throws IllegalArgumentException, 
>> SecurityException {
>> +                       checkPermissions();
>> +                       MonitoringJob monitoringJob = new 
>> MonitoringJobImpl(this,
>> +                                       initiator, statusVariables, 
>> schedule, count);
>> +                       monitoringJobs.add(monitoringJob);
>> +                       return monitoringJob;
>> +               }
>> +
>> +               /**
>> +                * Starts a change based MonitoringJob with the 
>> parameters provided.
>> +                * Monitoring events will be sent when the 
>> StatusVariables of this job
>> +                * are updated. All specified StatusVariables must 
>> exist when the job is
>> +                * started, and all must support update 
>> notifications. The initiator
>> +                * string is used in the mon.listener. id field of 
>> all events triggered
>> +                * by the job, to allow filtering the events based on 
>> the initiator.
>> +                * <p>
>> +                * The count parameter specifies the number of 
>> changes that must happen
>> +                * to a StatusVariable before a new notification is 
>> sent, this must be a
>> +                * positive integer.
>> +                * <p>
>> +                * The entity which initiates a MonitoringJob needs 
>> to hold
>> +                * MonitorPermission for all the specified target 
>> StatusVariables with
>> +                * the startjob action present.
>> +                *
>> +                * @param initiator
>> +                *            the identifier of the entity that 
>> initiated the job
>> +                * @param statusVariables
>> +                *            the list of StatusVariables to be 
>> monitored, with each
>> +                *            StatusVariable name given in
>> +                *            [Monitorable_PID]/[StatusVariable_ID] 
>> format
>> +                * @param count
>> +                *            the number of changes that must happen 
>> to a StatusVariable
>> +                *            before a new notification is sent
>> +                *
>> +                * @return the successfully started job object, 
>> cannot be null
>> +                * @throws IllegalArgumentException –
>> +                *             if the list of StatusVariable names 
>> contains an invalid
>> +                *             or non-existing StatusVariable, or one 
>> that does not
>> +                *             support notifications; if the 
>> initiator is null or empty;
>> +                *             or if count is invalid
>> +                * @throws SecurityException –
>> +                *             if the caller does not hold 
>> MonitorPermission for all the
>> +                *             specified StatusVariables, with the 
>> startjob action
>> +                *             present
>> +                * @see 
>> org.osgi.service.monitor.MonitorAdmin#startJob(java.lang.String,
>> +                *      java.lang.String[], int)
>> +                */
>> +               public MonitoringJob startJob(String initiator,
>> +                               String[] statusVariables, int count)
>> +                               throws IllegalArgumentException, 
>> SecurityException {
>> +                       checkPermissions();
>> +                       MonitoringJob monitoringJob = new 
>> MonitoringJobImpl(this,
>> +                                       initiator, statusVariables, 
>> count);
>> +                       monitoringJobs.add(monitoringJob);
>> +                       return monitoringJob;
>> +               }
>> +
>> +               /*
>> +                * Returns the list of currently running 
>> MonitoringJobs. Jobs are only
>> +                * visible to callers that have the necessary 
>> permissions: to receive a
>> +                * Monitoring Job in the returned list, the caller 
>> must hold all
>> +                * permissions required for starting the job. This 
>> means that if the
>> +                * caller does not have MonitorPermission with the 
>> proper startjob
>> +                * action for all the Status Variables monitored by a 
>> job, then that job
>> +                * will be silently omitted from the results. The 
>> returned array cannot
>> +                * be null, an empty array is returned if there are 
>> no running jobs
>> +                * visible to the caller at the time of the call. 
>> Returns the list of
>> +                * running jobs visible to the caller
>> +                *
>> +                * @see 
>> org.osgi.service.monitor.MonitorAdmin#getRunningJobs()
>> +                */
>> +               public MonitoringJob[] getRunningJobs() {
>> +                       return (MonitoringJob[]) monitoringJobs
>> +                                       .toArray(new 
>> MonitoringJob[monitoringJobs.size()]);
>> +               }
>> +
>> +               private void checkPermissions() throws 
>> SecurityException {
>> +                       // TODO
>> +
>> +               }
>> +       }
>> +
>> +       class MonitorListenerServiceFactory implements ServiceFactory {
>> +
>> +               List monitorListenerProxies = new ArrayList();
>> +
>> +               MonitorAdminImpl monitorAdminImpl;
>> +
>> +               MonitorListenerServiceFactory(MonitorAdminImpl 
>> monitorAdminImpl) {
>> +                       this.monitorAdminImpl = monitorAdminImpl;
>> +               }
>> +
>> +               public Object getService(Bundle bundle,
>> +                               ServiceRegistration 
>> serviceRegistration) {
>> +                       MonitorListenerProxy monitorListenerProxy = 
>> new MonitorListenerProxy(
>> +                                       bundle, monitorAdminImpl);
>> +                       
>> monitorListenerProxies.add(monitorListenerProxy);
>> +                       return monitorListenerProxy;
>> +               }
>> +
>> +               public void ungetService(Bundle bundle,
>> +                               ServiceRegistration 
>> serviceRegistration, Object object) {
>> +                       monitorListenerProxies.remove(object);
>> +               }
>> +       }
>> +
>> +       class MonitorListenerProxy implements MonitorListener {
>> +               Bundle bundle;
>> +
>> +               MonitorAdminImpl monitorAdminImpl;
>> +
>> +               MonitorListenerProxy(Bundle bundle, MonitorAdminImpl 
>> monitorAdminImpl) {
>> +                       this.bundle = bundle;
>> +                       this.monitorAdminImpl = monitorAdminImpl;
>> +               }
>> +
>> +               /**
>> +                * ? Callback for notification of a StatusVariable 
>> change.
>> +                *
>> +                * @param monitorableId
>> +                *            the identifier of the Monitorable 
>> instance reporting the
>> +                *            change
>> +                * @param statusVariable
>> +                *            the StatusVariable that has changed
>> +                * @throws IllegalArgumentException –
>> +                *             if the specified monitorable ID is 
>> invalid (null, empty,
>> +                *             or contains illegal characters), or if 
>> statusVariable is
>> +                *             null
>> +                * @see 
>> org.osgi.service.monitor.MonitorListener#updated(java.lang.String,
>> +                *      org.osgi.service.monitor.StatusVariable)
>> +                */
>> +               public void updated(String monitorableId, 
>> StatusVariable statusVariable)
>> +                               throws IllegalArgumentException {
>> +                       if (monitorableId == null)
>> +                               throw new 
>> IllegalArgumentException("null monitorableId");
>> +                       if (statusVariable == null)
>> +                               throw new 
>> IllegalArgumentException("null statusVariable");
>> +                       String topic = TOPIC;
>> +                       Dictionary properties = new Hashtable();
>> +                       properties.put(MON_MONITORABLE_PID, 
>> monitorableId);
>> +                       properties.put(MON_STATUSVARIABLE_NAME, 
>> statusVariable.getID());
>> +
>> +                       Object value = null;
>> +                       switch (statusVariable.getType()) { // TODO 
>> float->double, int->long
>> +                       case StatusVariable.TYPE_BOOLEAN:
>> +                               value = new 
>> Boolean(statusVariable.getBoolean());
>> +                               break;
>> +                       case StatusVariable.TYPE_FLOAT:
>> +                               value = new 
>> Float(statusVariable.getFloat());
>> +                               break;
>> +                       case StatusVariable.TYPE_INTEGER:
>> +                               value = new 
>> Integer(statusVariable.getInteger());
>> +                               break;
>> +                       case StatusVariable.TYPE_STRING:
>> +                               value = statusVariable.getString();
>> +                               break;
>> +                       }
>> +                       properties.put(MON_STATUSVARIABLE_VALUE, value);
>> +                       // mon.listener.id: The identifier of the 
>> initiator of the
>> +                       // monitoring job (only present if the event 
>> was generated due to a
>> +                       // monitoring job))
>> +                       Event event = new Event(topic, properties);
>> +                       EventAdmin eventAdmin = (EventAdmin) 
>> eventAdminServiceTracker
>> +                                       .getService();
>> +                       if (eventAdmin != null)
>> +                               eventAdmin.sendEvent(event);
>> +
>> +                       // broadcast to MonitoringJob
>> +                       StringBuffer sb=new StringBuffer(monitorableId);
>> +                       sb.append('/').append(statusVariable.getID());
>> +                       String path=sb.toString();
>> +                       List list=(List)subscriptions.get(path);
>> +                       if(list!=null) {
>> +                               Iterator iterator=list.iterator();
>> +                               while(iterator.hasNext()){
>> +                                       MonitoringJobImpl 
>> monitoringJobImpl=(MonitoringJobImpl)iterator.next();
>> +                                       
>> monitoringJobImpl.updated(monitorableId,statusVariable);
>> +                               }
>> +                       }
>> +               }
>> +       }
>> +
>> +       class MonitorableEntry {
>> +               Monitorable monitorable;
>> +
>> +               String pid;
>> +
>> +               String[] statusVariableNames;
>> +
>> +               MonitorableEntry(Monitorable monitorable, String pid,
>> +                               String[] statusVariableNames) {
>> +                       this.monitorable = monitorable;
>> +                       this.pid = pid;
>> +                       this.statusVariableNames = statusVariableNames;
>> +               }
>> +       }
>> +
>> +       class MyServiceTrackerCustomizerForMonitorable implements
>> +                       ServiceTrackerCustomizer {
>> +
>> +               public Object addingService(ServiceReference 
>> serviceReference) {
>> +                       String pid = (String) serviceReference
>> +                                       
>> .getProperty(Constants.SERVICE_PID);
>> +                       if (pid == null) {
>> +                               System.err.println("Warning: The 
>> "+Constants.SERVICE_PID+" of service "+Constants.SERVICE_ID+ " is not 
>> setted");
>> +                               return null;
>> +                       }
>> +
>> +                       if(monitorables.containsKey(pid)){
>> +                               // TODO change for logger
>> +                               System.err.println("Warning: The 
>> "+Constants.SERVICE_PID+"(="+pid+") of service 
>> "+Constants.SERVICE_ID+ " is already registered by another bundle");
>> +                               return null;
>> +                       }
>> +
>> +                       Monitorable monitorable = (Monitorable) 
>> bundleContext
>> +                                       .getService(serviceReference);
>> +                       if (monitorable == null)
>> +                               return null;
>> +                       String[] statusVariableNames = 
>> monitorable.getStatusVariableNames();
>> +                       if (statusVariableNames == null || 
>> statusVariableNames.length == 0) {
>> +                               
>> bundleContext.ungetService(serviceReference);
>> +                               return null;
>> +                       }
>> +                       monitorables.put(pid, new 
>> MonitorableEntry(monitorable, pid,
>> +                                       statusVariableNames));
>> +                       return monitorable;
>> +               }
>> +
>> +               public void modifiedService(ServiceReference 
>> serviceReference,
>> +                               Object object) {
>> +                       // TODO
>> +               }
>> +
>> +               public void removedService(ServiceReference 
>> serviceReference,
>> +                               Object object) {
>> +                       Monitorable monitorable = (Monitorable) object;
>> +                       Iterator iterator = 
>> monitorables.entrySet().iterator();
>> +                       while (iterator.hasNext()) {
>> +                               Map.Entry mapEntry = (Map.Entry) 
>> iterator.next();
>> +                               MonitorableEntry monitorableEntry = 
>> (MonitorableEntry) mapEntry
>> +                                               .getValue();
>> +                               if 
>> (monitorableEntry.monitorable.equals(monitorable)) {
>> +                                       iterator.remove();
>> +                                       break;
>> +                               }
>> +                       }
>> +                       bundleContext.ungetService(serviceReference);
>> +               }
>> +       }
>> +
>> +       private BundleContext bundleContext;
>> +
>> +       private ServiceTracker eventAdminServiceTracker;
>> +
>> +       private ServiceTracker monitorableServiceTracker;
>> +
>> +       private Map monitorables = new HashMap();
>> +
>> +       /**
>> +        * path -> list of MonitoringJobImpl
>> +        */
>> +       private Map subscriptions = new HashMap();
>> +
>> +
>> +       public void start(BundleContext bundleContext) throws 
>> Exception {
>> +               this.bundleContext = bundleContext;
>> +               eventAdminServiceTracker = new 
>> ServiceTracker(bundleContext,
>> +                               EventAdmin.class.getName(), null);
>> +               eventAdminServiceTracker.open();
>> +
>> +               monitorableServiceTracker = new 
>> ServiceTracker(bundleContext,
>> +                               Monitorable.class.getName(),
>> +                               new 
>> MyServiceTrackerCustomizerForMonitorable());
>> +               monitorableServiceTracker.open();
>> +
>> +               
>> bundleContext.registerService(MonitorAdmin.class.getName(),
>> +                               new MonitorAdminServiceFactory(this), 
>> null);
>> +               
>> bundleContext.registerService(MonitorListener.class.getName(),
>> +                               new 
>> MonitorListenerServiceFactory(this), null);
>> +       }
>> +
>> +       public void stop(BundleContext context) throws Exception {
>> +               stopAllMonitoringJobs();
>> +               monitorableServiceTracker.close(); // unget all 
>> services ???
>> +               Iterator iterator = monitorables.keySet().iterator();
>> +               while (iterator.hasNext()) {
>> +                       ServiceReference serviceReference = 
>> (ServiceReference) iterator
>> +                                       .next();
>> +                       bundleContext.ungetService(serviceReference);
>> +               }
>> +               eventAdminServiceTracker.close();
>> +       }
>> +
>> +       private void stopAllMonitoringJobs() {
>> +               // TODO
>> +
>> +       }
>> +
>> +}
>>
>> Propchange: 
>> felix/sandbox/donsez/monitoradmin/src/main/java/org/apache/felix/monitor/MonitorAdminImpl.java 
>>
>> ------------------------------------------------------------------------------ 
>>
>>     svn:eol-style = native
>>
>> Added: 
>> felix/sandbox/donsez/monitoradmin/src/main/java/org/osgi/service/monitor/MonitorAdmin.java 
>>
>> URL: 
>> http://svn.apache.org/viewvc/felix/sandbox/donsez/monitoradmin/src/main/java/org/osgi/service/monitor/MonitorAdmin.java?view=auto&rev=554318 
>>
>> ============================================================================== 
>>
>> --- 
>> felix/sandbox/donsez/monitoradmin/src/main/java/org/osgi/service/monitor/MonitorAdmin.java 
>> (added)
>> +++ 
>> felix/sandbox/donsez/monitoradmin/src/main/java/org/osgi/service/monitor/MonitorAdmin.java 
>> Sat Jul  7 22:49:38 2007
>> @@ -0,0 +1,344 @@
>> +/*
>> + * $Header: 
>> /cvshome/build/org.osgi.service.monitor/src/org/osgi/service/monitor/MonitorAdmin.java,v 
>> 1.20 2005/07/29 18:03:09 tszeredi Exp $
>> + *
>> + * Copyright (c) OSGi Alliance (2004, 2005). All Rights Reserved.
>> + *
>> + * This program and the accompanying materials are made available 
>> under the
>> + * terms of the Eclipse Public License v1.0 which accompanies this
>> + * distribution, and is available at 
>> http://www.eclipse.org/legal/epl-v10.html.
>> + */
>> +
>> +package org.osgi.service.monitor;
>> +
>> +/**
>> + * A <code>MonitorAdmin</code> implementation handles
>> + * <code>StatusVariable</code> query requests and measurement job 
>> control
>> + * requests.
>> + * <p>
>> + * Note that an alternative but not recommended way of obtaining
>> + * <code>StatusVariable</code>s is that applications having the 
>> required
>> + * <code>ServicePermissions</code> can query the list of
>> + * <code>Monitorable</code> services from the service registry and 
>> then query
>> + * the list of <code>StatusVariable</code> names from the
>> + * <code>Monitorable</code> services. This way all services which 
>> publish
>> + * <code>StatusVariable</code>s will be returned regardless of 
>> whether they
>> + * do or do not hold the necessary <code>MonitorPermission</code> for
>> + * publishing <code>StatusVariable</code>s. By using the
>> + * <code>MonitorAdmin</code> to obtain the 
>> <code>StatusVariable</code>s it
>> + * is guaranteed that only those <code>Monitorable</code> services 
>> will be
>> + * accessed who are authorized to publish 
>> <code>StatusVariable</code>s. It is
>> + * the responsibility of the <code>MonitorAdmin</code> 
>> implementation to check
>> + * the required permissions and show only those variables which pass 
>> this check.
>> + * <p>
>> + * The events posted by <code>MonitorAdmin</code> contain the following
>> + * properties:
>> + * <ul>
>> + * <li><code>mon.monitorable.pid</code>: The identifier of the
>> + * <code>Monitorable</code>
>> + * <li><code>mon.statusvariable.name</code>: The identifier of the
>> + * <code>StatusVariable</code> within the given 
>> <code>Monitorable</code>
>> + * <li><code>mon.statusvariable.value</code>: The value of the
>> + * <code>StatusVariable</code>, represented as a <code>String</code>
>> + * <li><code>mon.listener.id</code>: The identifier of the initiator 
>> of the
>> + * monitoring job (only present if the event was generated due to a 
>> monitoring
>> + * job)
>> + * </ul>
>> + * <p>
>> + * Most of the methods require either a Monitorable ID or a Status 
>> Variable path
>> + * parameter, the latter in [Monitorable_ID]/[StatusVariable_ID] 
>> format.  These
>> + * parameters must not be <code>null</code>, and the IDs they 
>> contain must
>> + * conform to their respective definitions in {@link Monitorable} and
>> + * {@link StatusVariable}.  If any of the restrictions are violated, 
>> the method
>> + * must throw an <code>IllegalArgumentException</code>.
>> + */
>> +public interface MonitorAdmin {
>> +
>> +    /**
>> +     * Returns a <code>StatusVariable</code> addressed by its full 
>> path.
>> +     * The entity which queries a <code>StatusVariable</code> needs 
>> to hold
>> +     * <code>MonitorPermission</code> for the given target with the
>> +     * <code>read</code> action present.
>> +     *
>> +     * @param path the full path of the <code>StatusVariable</code> in
>> +     *        [Monitorable_ID]/[StatusVariable_ID] format
>> +     * @return the <code>StatusVariable</code> object
>> +     * @throws java.lang.IllegalArgumentException if 
>> <code>path</code> is
>> +     *         <code>null</code> or otherwise invalid, or points to a
>> +     *         non-existing <code>StatusVariable</code>
>> +     * @throws java.lang.SecurityException if the caller does not 
>> hold a
>> +     *         <code>MonitorPermission</code> for the
>> +     *         <code>StatusVariable</code> specified by 
>> <code>path</code>
>> +     *         with the <code>read</code> action present
>> +     */
>> +    public StatusVariable getStatusVariable(String path)
>> +            throws IllegalArgumentException, SecurityException;
>> +
>> +    /**
>> +     * Returns the names of the <code>Monitorable</code> services 
>> that are
>> +     * currently registered. The <code>Monitorable</code> instances 
>> are not
>> +     * accessible through the <code>MonitorAdmin</code>, so that 
>> requests to
>> +     * individual status variables can be filtered with respect to the
>> +     * publishing rights of the <code>Monitorable</code> and the 
>> reading
>> +     * rights of the caller.
>> +     * <p>
>> +     * The returned array contains the names in alphabetical order. 
>> It cannot be
>> +     * <code>null</code>, an empty array is returned if no
>> +     * <code>Monitorable</code> services are registered.
>> +     *
>> +     * @return the array of <code>Monitorable</code> names
>> +     */
>> +    public String[] getMonitorableNames();
>> +
>> +    /**
>> +     * Returns the <code>StatusVariable</code> objects published by a
>> +     * <code>Monitorable</code> instance. The 
>> <code>StatusVariables</code>
>> +     * will hold the values taken at the time of this method call. 
>> Only those
>> +     * status variables are returned where the following two 
>> conditions are met:
>> +     * <ul>
>> +     * <li>the specified <code>Monitorable</code> holds a
>> +     * <code>MonitorPermission</code> for the status variable with the
>> +     * <code>publish</code> action present
>> +     * <li>the caller holds a <code>MonitorPermission</code> for the 
>> status
>> +     * variable with the <code>read</code> action present
>> +     * </ul>
>> +     * All other status variables are silently ignored, they are 
>> omitted from
>> +     * the result.
>> +     * <p>
>> +     * The returned array does not contain duplicates, and the 
>> elements are in
>> +     * no particular order. It cannot be <code>null</code>, an empty 
>> array is
>> +     * returned if no (authorized and readable) Status Variables are 
>> provided
>> +     * by the given <code>Monitorable</code>.
>> +     *
>> +     * @param monitorableId the identifier of a 
>> <code>Monitorable</code>
>> +     *        instance
>> +     * @return a list of <code>StatusVariable</code> objects published
>> +     *         by the specified <code>Monitorable</code>
>> +     * @throws java.lang.IllegalArgumentException if 
>> <code>monitorableId</code>
>> +     *         is <code>null</code> or otherwise invalid, or points 
>> to a
>> +     *         non-existing <code>Monitorable</code>
>> +     */
>> +    public StatusVariable[] getStatusVariables(String monitorableId)
>> +            throws IllegalArgumentException;
>> +
>> +    /**
>> +     * Returns the list of <code>StatusVariable</code> names 
>> published by a
>> +     * <code>Monitorable</code> instance. Only those status 
>> variables are
>> +     * listed where the following two conditions are met:
>> +     * <ul>
>> +     * <li>the specified <code>Monitorable</code> holds a
>> +     * <code>MonitorPermission</code> for the status variable with the
>> +     * <code>publish</code> action present
>> +     * <li>the caller holds a <code>MonitorPermission</code> for
>> +     * the status variable with the <code>read</code> action present
>> +     * </ul>
>> +     * All other status variables are silently ignored, their names 
>> are omitted
>> +     * from the list.
>> +     * <p>
>> +     * The returned array does not contain duplicates, and the 
>> elements are in
>> +     * alphabetical order. It cannot be <code>null</code>, an empty 
>> array is
>> +     * returned if no (authorized and readable) Status Variables are 
>> provided
>> +     * by the given <code>Monitorable</code>.
>> +     *
>> +     * @param monitorableId the identifier of a 
>> <code>Monitorable</code>
>> +     *        instance
>> +     * @return a list of <code>StatusVariable</code> objects names
>> +     *         published by the specified <code>Monitorable</code>
>> +     * @throws java.lang.IllegalArgumentException if 
>> <code>monitorableId</code>
>> +     *         is <code>null</code> or otherwise invalid, or points 
>> to a
>> +     *         non-existing <code>Monitorable</code>
>> +     */
>> +    public String[] getStatusVariableNames(String monitorableId)
>> +            throws IllegalArgumentException;
>> +
>> +    /**
>> +     * Switches event sending on or off for the specified
>> +     * <code>StatusVariable</code>s. When the 
>> <code>MonitorAdmin</code> is
>> +     * notified about a <code>StatusVariable</code> being updated it 
>> sends an
>> +     * event unless this feature is switched off. Note that events 
>> within a
>> +     * monitoring job can not be switched off. The event sending 
>> state of the
>> +     * <code>StatusVariables</code> must not be persistently stored. 
>> When a
>> +     * <code>StatusVariable</code> is registered for the first time 
>> in a
>> +     * framework session, its event sending state is set to ON by 
>> default.
>> +     * <p>
>> +     * Usage of the "*" wildcard is allowed in the path argument of 
>> this method
>> +     * as a convenience feature. The wildcard can be used in either 
>> or both path
>> +     * fragments, but only at the end of the fragments.  The 
>> semantics of the
>> +     * wildcard is that it stands for any matching 
>> <code>StatusVariable</code>
>> +     * at the time of the method call, it does not affect the event 
>> sending
>> +     * status of <code>StatusVariable</code>s which are not yet 
>> registered. As
>> +     * an example, when the <code>switchEvents("MyMonitorable/*", 
>> false)</code>
>> +     * method is executed, event sending from all 
>> <code>StatusVariables</code>
>> +     * of the MyMonitorable service are switched off. However, if the
>> +     * MyMonitorable service starts to publish a new 
>> <code>StatusVariable</code>
>> +     * later, it's event sending status is on by default.
>> +     *
>> +     * @param path the identifier of the 
>> <code>StatusVariable</code>(s) in
>> +     *        [Monitorable_id]/[StatusVariable_id] format, possibly 
>> with the
>> +     *        "*" wildcard at the end of either path fragment
>> +     * @param on <code>false</code> if event sending should be 
>> switched off,
>> +     *        <code>true</code> if it should be switched on for the 
>> given path
>> +     * @throws java.lang.SecurityException if the caller does not hold
>> +     *         <code>MonitorPermission</code> with the
>> +     *         <code>switchevents</code> action or if there is any
>> +     *         <code>StatusVariable</code> in the <code>path</code> 
>> field for
>> +     *         which it is not allowed to switch event sending on or 
>> off as per
>> +     *         the target field of the permission
>> +     * @throws java.lang.IllegalArgumentException if 
>> <code>path</code> is
>> +     *         <code>null</code> or otherwise invalid, or points to a
>> +     *         non-existing <code>StatusVariable</code>
>> +     */
>> +    public void switchEvents(String path, boolean on)
>> +        throws IllegalArgumentException, SecurityException;
>> +
>> +    /**
>> +     * Issues a request to reset a given <code>StatusVariable</code>.
>> +     * Depending on the semantics of the <code>StatusVariable</code> 
>> this call
>> +     * may or may not succeed: it makes sense to reset a counter to 
>> its starting
>> +     * value, but e.g. a <code>StatusVariable</code> of type String 
>> might not
>> +     * have a meaningful default value. Note that for numeric
>> +     * <code>StatusVariable</code>s the starting value may not 
>> necessarily be
>> +     * 0. Resetting a <code>StatusVariable</code> triggers a monitor 
>> event if
>> +     * the <code>StatusVariable</code> supports update notifications.
>> +     * <p>
>> +     * The entity that wants to reset the 
>> <code>StatusVariable</code> needs to
>> +     * hold <code>MonitorPermission</code> with the <code>reset</code>
>> +     * action present. The target field of the permission must match 
>> the
>> +     * <code>StatusVariable</code> name to be reset.
>> +     *
>> +     * @param path the identifier of the <code>StatusVariable</code> in
>> +     *        [Monitorable_id]/[StatusVariable_id] format
>> +     * @return <code>true</code> if the <code>Monitorable</code> could
>> +     *         successfully reset the given 
>> <code>StatusVariable</code>,
>> +     *         <code>false</code> otherwise
>> +     * @throws java.lang.IllegalArgumentException if 
>> <code>path</code> is
>> +     *         <code>null</code> or otherwise invalid, or points to a
>> +     *         non-existing <code>StatusVariable</code>
>> +     * @throws java.lang.SecurityException if the caller does not hold
>> +     *         <code>MonitorPermission</code> with the 
>> <code>reset</code>
>> +     *         action or if the specified 
>> <code>StatusVariable</code> is not
>> +     *         allowed to be reset as per the target field of the 
>> permission
>> +     */
>> +    public boolean resetStatusVariable(String path)
>> +            throws IllegalArgumentException, SecurityException;
>> +
>> +    /**
>> +     * Returns a human readable description of the given
>> +     * <code>StatusVariable</code>. The <code>null</code> value may 
>> be returned
>> +     * if there is no description for the given 
>> <code>StatusVariable</code>.
>> +     * <p>
>> +     * The entity that queries a <code>StatusVariable</code> needs 
>> to hold
>> +     * <code>MonitorPermission</code> for the given target with the
>> +     * <code>read</code> action present.
>> +     *
>> +     * @param path the full path of the <code>StatusVariable</code> in
>> +     *        [Monitorable_ID]/[StatusVariable_ID] format
>> +     * @return the human readable description of this
>> +     *         <code>StatusVariable</code> or <code>null</code> if 
>> it is not
>> +     *         set
>> +     * @throws java.lang.IllegalArgumentException if 
>> <code>path</code> is
>> +     *         <code>null</code> or otherwise invalid, or points to a
>> +     *         non-existing <code>StatusVariable</code>
>> +     * @throws java.lang.SecurityException if the caller does not 
>> hold a
>> +     *         <code>MonitorPermission</code> for the
>> +     *         <code>StatusVariable</code> specified by 
>> <code>path</code>
>> +     *         with the <code>read</code> action present
>> +     */
>> +    public String getDescription(String path)
>> +            throws IllegalArgumentException, SecurityException;
>> +
>> +    /**
>> +     * Starts a time based <code>MonitoringJob</code> with the 
>> parameters
>> +     * provided. Monitoring events will be sent according to the 
>> specified
>> +     * schedule. All specified <code>StatusVariable</code>s must 
>> exist when the
>> +     * job is started. The initiator string is used in the
>> +     * <code>mon.listener.id</code> field of all events triggered by 
>> the job,
>> +     * to allow filtering the events based on the initiator.
>> +     * <p>
>> +     * The <code>schedule</code> parameter specifies the time in 
>> seconds
>> +     * between two measurements, it must be greater than 0.  The first
>> +     * measurement will be taken when the timer expires for the 
>> first time, not
>> +     * when this method is called.
>> +     * <p>
>> +     * The <code>count</code> parameter defines the number of 
>> measurements to be
>> +     * taken, and must either be a positive integer, or 0 if the 
>> measurement is
>> +     * to run indefinitely.
>> +     * <p>
>> +     * The entity which initiates a <code>MonitoringJob</code> needs 
>> to hold
>> +     * <code>MonitorPermission</code> for all the specified target
>> +     * <code>StatusVariable</code>s with the <code>startjob</code> 
>> action
>> +     * present. If the permission's action string specifies a 
>> minimal sampling
>> +     * interval then the <code>schedule</code> parameter should be 
>> at least as
>> +     * great as the value in the action string.
>> +     *
>> +     * @param initiator the identifier of the entity that initiated 
>> the job
>> +     * @param statusVariables the list of 
>> <code>StatusVariable</code>s to be
>> +     *        monitored, with each <code>StatusVariable</code> name 
>> given in
>> +     *        [Monitorable_PID]/[StatusVariable_ID] format
>> +     * @param schedule the time in seconds between two measurements
>> +     * @param count the number of measurements to be taken, or 0 for 
>> the
>> +     *        measurement to run indefinitely
>> +     * @return the successfully started job object, cannot be 
>> <code>null</code>
>> +     * @throws java.lang.IllegalArgumentException if the list of
>> +     *         <code>StatusVariable</code> names contains an invalid or
>> +     *         non-existing <code>StatusVariable</code>; if
>> +     *         <code>initiator</code> is <code>null</code> or empty; 
>> or if the
>> +     *         <code>schedule</code> or <code>count</code> 
>> parameters are
>> +     *         invalid
>> +     * @throws java.lang.SecurityException if the caller does not hold
>> +     *         <code>MonitorPermission</code> for all the specified
>> +     *         <code>StatusVariable</code>s, with the 
>> <code>startjob</code>
>> +     *         action present, or if the permission does not allow 
>> starting the
>> +     *         job with the given frequency
>> +     */
>> +    public MonitoringJob startScheduledJob(String initiator,
>> +            String[] statusVariables, int schedule, int count)
>> +            throws IllegalArgumentException, SecurityException;
>> +
>> +    /**
>> +     * Starts a change based <code>MonitoringJob</code> with the 
>> parameters
>> +     * provided. Monitoring events will be sent when the
>> +     * <code>StatusVariable</code>s of this job are updated. All 
>> specified
>> +     * <code>StatusVariable</code>s must exist when the job is 
>> started, and
>> +     * all must support update notifications. The initiator string 
>> is used in
>> +     * the <code>mon.listener.id</code> field of all events 
>> triggered by the
>> +     * job, to allow filtering the events based on the initiator.
>> +     * <p>
>> +     * The <code>count</code> parameter specifies the number of 
>> changes that
>> +     * must happen to a <code>StatusVariable</code> before a new 
>> notification is
>> +     * sent, this must be a positive integer.
>> +     * <p>
>> +     * The entity which initiates a <code>MonitoringJob</code> needs 
>> to hold
>> +     * <code>MonitorPermission</code> for all the specified target
>> +     * <code>StatusVariable</code>s with the <code>startjob</code> 
>> action
>> +     * present.
>> +     *
>> +     * @param initiator the identifier of the entity that initiated 
>> the job
>> +     * @param statusVariables the list of 
>> <code>StatusVariable</code>s to be
>> +     *        monitored, with each <code>StatusVariable</code> name 
>> given in
>> +     *        [Monitorable_PID]/[StatusVariable_ID] format
>> +     * @param count the number of changes that must happen to a
>> +     *        <code>StatusVariable</code> before a new notification 
>> is sent
>> +     * @return the successfully started job object, cannot be 
>> <code>null</code>
>> +     * @throws java.lang.IllegalArgumentException if the list of
>> +     *         <code>StatusVariable</code> names contains an invalid or
>> +     *         non-existing <code>StatusVariable</code>, or one that 
>> does not
>> +     *         support notifications; if the <code>initiator</code> is
>> +     *         <code>null</code> or empty; or if <code>count</code> 
>> is invalid
>> +     * @throws java.lang.SecurityException if the caller does not hold
>> +     *         <code>MonitorPermission</code> for all the specified
>> +     *         <code>StatusVariable</code>s, with the 
>> <code>startjob</code>
>> +     *         action present
>> +     */
>> +    public MonitoringJob startJob(String initiator, String[] 
>> statusVariables,
>> +            int count) throws IllegalArgumentException, 
>> SecurityException;
>> +
>> +    /**
>> +     * Returns the list of currently running 
>> <code>MonitoringJob</code>s.
>> +     * <p>
>> +     * The returned array cannot be <code>null</code>, an empty 
>> array is
>> +     * returned if there are no running jobs at the time of the call.
>> +     *
>> +     * @return the list of running jobs
>> +     */
>> +    public MonitoringJob[] getRunningJobs();
>> +}
>> \ No newline at end of file
>>
>> Propchange: 
>> felix/sandbox/donsez/monitoradmin/src/main/java/org/osgi/service/monitor/MonitorAdmin.java 
>>
>> ------------------------------------------------------------------------------ 
>>
>>     svn:eol-style = native
>>
>> Added: 
>> felix/sandbox/donsez/monitoradmin/src/main/java/org/osgi/service/monitor/MonitorListener.java 
>>
>> URL: 
>> http://svn.apache.org/viewvc/felix/sandbox/donsez/monitoradmin/src/main/java/org/osgi/service/monitor/MonitorListener.java?view=auto&rev=554318 
>>
>> ============================================================================== 
>>
>> --- 
>> felix/sandbox/donsez/monitoradmin/src/main/java/org/osgi/service/monitor/MonitorListener.java 
>> (added)
>> +++ 
>> felix/sandbox/donsez/monitoradmin/src/main/java/org/osgi/service/monitor/MonitorListener.java 
>> Sat Jul  7 22:49:38 2007
>> @@ -0,0 +1,34 @@
>> +/*
>> + * $Header: 
>> /cvshome/build/org.osgi.service.monitor/src/org/osgi/service/monitor/MonitorListener.java,v 
>> 1.7 2005/06/17 14:35:17 tszeredi Exp $
>> + *
>> + * Copyright (c) OSGi Alliance (2004, 2005). All Rights Reserved.
>> + *
>> + * This program and the accompanying materials are made available 
>> under the
>> + * terms of the Eclipse Public License v1.0 which accompanies this
>> + * distribution, and is available at 
>> http://www.eclipse.org/legal/epl-v10.html.
>> + */
>> +
>> +package org.osgi.service.monitor;
>> +
>> +/**
>> + * The <code>MonitorListener</code> is used by <code>Monitorable</code>
>> + * services to send notifications when a <code>StatusVariable</code> 
>> value is
>> + * changed. The <code>MonitorListener</code> should register itself 
>> as a
>> + * service at the OSGi Service Registry. This interface is 
>> implemented by the
>> + * Monitor Admin component.
>> + */
>> +public interface MonitorListener {
>> +    /**
>> +     * Callback for notification of a <code>StatusVariable</code> 
>> change.
>> +     *
>> +     * @param monitorableId the identifier of the 
>> <code>Monitorable</code>
>> +     *        instance reporting the change
>> +     * @param statusVariable the <code>StatusVariable</code> that 
>> has changed
>> +     * @throws java.lang.IllegalArgumentException if the specified 
>> monitorable
>> +     *         ID is invalid (<code>null</code>, empty, or contains 
>> illegal
>> +     *         characters), or if <code>statusVariable</code> is
>> +     *         <code>null</code>
>> +     */
>> +    public void updated(String monitorableId, StatusVariable 
>> statusVariable)
>> +            throws IllegalArgumentException;
>> +}
>>
>> Propchange: 
>> felix/sandbox/donsez/monitoradmin/src/main/java/org/osgi/service/monitor/MonitorListener.java 
>>
>> ------------------------------------------------------------------------------ 
>>
>>     svn:eol-style = native
>>
>> Added: 
>> felix/sandbox/donsez/monitoradmin/src/main/java/org/osgi/service/monitor/MonitorPermission.java 
>>
>> URL: 
>> http://svn.apache.org/viewvc/felix/sandbox/donsez/monitoradmin/src/main/java/org/osgi/service/monitor/MonitorPermission.java?view=auto&rev=554318 
>>
>> ============================================================================== 
>>
>> --- 
>> felix/sandbox/donsez/monitoradmin/src/main/java/org/osgi/service/monitor/MonitorPermission.java 
>> (added)
>> +++ 
>> felix/sandbox/donsez/monitoradmin/src/main/java/org/osgi/service/monitor/MonitorPermission.java 
>> Sat Jul  7 22:49:38 2007
>> @@ -0,0 +1,325 @@
>> +/*
>> + * $Header: 
>> /cvshome/build/org.osgi.service.monitor/src/org/osgi/service/monitor/MonitorPermission.java,v 
>> 1.9 2005/06/24 20:27:16 tszeredi Exp $
>> + *
>> + * Copyright (c) OSGi Alliance (2005). All Rights Reserved.
>> + *
>> + * This program and the accompanying materials are made available 
>> under the
>> + * terms of the Eclipse Public License v1.0 which accompanies this
>> + * distribution, and is available at 
>> http://www.eclipse.org/legal/epl-v10.html.
>> + */
>> +
>> +package org.osgi.service.monitor;
>> +
>> +import java.security.Permission;
>> +import java.util.StringTokenizer;
>> +
>> +/**
>> + * Indicates the callers authority to publish, read or reset
>> + * <code>StatusVariable</code>s, to switch event sending on or off 
>> or to
>> + * start monitoring jobs. The target of the permission is the 
>> identifier of the
>> + * <code>StatusVariable</code>, the action can be <code>read</code>,
>> + * <code>publish</code>,<code>reset</code>,<code>startjob</code>,
>> + * <code>switchevents</code>, or the combination of these separated by
>> + * commas.
>> + */
>> +public class MonitorPermission extends Permission {
>> +    // TODO add static final serialVersionUID
>> +
>> +    /**
>> +     * Holders of <code>MonitorPermission</code> with the 
>> <code>read</code>
>> +     * action present are allowed to read the value of the
>> +     * <code>StatusVariable</code>s specified in the permission's 
>> target field.
>> +     */
>> +    public static final String READ = "read";
>> +
>> +    /**
>> +     * Holders of <code>MonitorPermission</code> with the 
>> <code>reset</code>
>> +     * action present are allowed to reset the value of the
>> +     * <code>StatusVariable</code>s specified in the permission's 
>> target field.
>> +     */
>> +    public static final String RESET = "reset";
>> +
>> +    /**
>> +     * Holders of <code>MonitorPermission</code> with the 
>> <code>publish</code>
>> +     * action present are <code>Monitorable</code> services that are 
>> allowed
>> +     * to publish the <code>StatusVariable</code>s specified in the
>> +     * permission's target field.  Note, that this permission cannot 
>> be enforced
>> +     * when a <code>Monitorable</code> registers to the framework, 
>> because the
>> +     * Service Registry does not know about this permission.  
>> Instead, any
>> +     * <code>StatusVariable</code>s published by a 
>> <code>Monitorable</code>
>> +     * without the corresponding <code>publish</code> permission are 
>> silently
>> +     * ignored by <code>MonitorAdmin</code>, and are therefore 
>> invisible to the
>> +     * users of the monitoring service.
>> +     */
>> +    public static final String PUBLISH = "publish";
>> +
>> +    /**
>> +     * Holders of <code>MonitorPermission</code> with the 
>> <code>startjob</code>
>> +     * action present are allowed to initiate monitoring jobs 
>> involving the
>> +     * <code>StatusVariable</code>s specified in the permission's 
>> target field.
>> +     * <p>
>> +     * A minimal sampling interval can be optionally defined in the 
>> following
>> +     * form: <code>startjob:n</code>.  This allows the holder of the 
>> permission
>> +     * to initiate time based jobs with a measurement interval of at 
>> least
>> +     * <code>n</code> seconds. If <code>n</code> is not specified or 
>> 0 then the
>> +     * holder of this permission is allowed to start monitoring jobs 
>> specifying
>> +     * any frequency.
>> +     */
>> +    public static final String STARTJOB = "startjob";
>> +
>> +    /**
>> +     * Holders of <code>MonitorPermission</code> with the
>> +     * <code>switchevents</code> action present are allowed to 
>> switch event
>> +     * sending on or off for the value of the 
>> <code>StatusVariable</code>s
>> +     * specified in the permission's target field.
>> +     */
>> +    public static final String SWITCHEVENTS = "switchevents";
>> +
>> +    private static final int READ_FLAG         = 0x1;
>> +    private static final int RESET_FLAG        = 0x2;
>> +    private static final int PUBLISH_FLAG      = 0x4;
>> +    private static final int STARTJOB_FLAG     = 0x8;
>> +    private static final int SWITCHEVENTS_FLAG = 0x10;
>> +
>> +    private String monId;
>> +    private String varId;
>> +    private boolean prefixMonId;
>> +    private boolean prefixVarId;
>> +    private int mask;
>> +    private int minJobInterval;
>> +
>> +    /**
>> +     * Create a <code>MonitorPermission</code> object, specifying 
>> the target
>> +     * and actions.
>> +     * <p>
>> +     * The meaning of the <code>statusVariable</code> parameter is 
>> slightly
>> +     * different depending on the <code>action</code> field, see the
>> +     * descriptions of the individual actions.  In general, the 
>> wildcard
>> +     * <code>*</code> is allowed in both fragments of the target 
>> string, but
>> +     * only at the end of the fragments.
>> +     * <p>
>> +     * The following targets are valid:
>> +     * <code>com.mycomp.myapp/queue_length</code>,
>> +     * <code>com.mycomp.myapp/*</code>, 
>> <code>com.mycomp.&#42;/*</code>,
>> +     * <code>&#42;/*</code>, <code>&#42;/queue_length</code>,
>> +     * <code>&#42;/queue*</code>.
>> +     * <p>
>> +     * The following targets are invalid:
>> +     * <code>*.myapp/queue_length</code>, <code>com.*.myapp/*</code>,
>> +     * <code>*</code>.
>> +     * <p>
>> +     * The <code>actions</code> parameter specifies the allowed 
>> action(s):
>> +     * <code>read</code>, <code>publish</code>, <code>startjob</code>,
>> +     * <code>reset</code>, <code>switchevents</code>, or the 
>> combination of
>> +     * these separated by commas.
>> +     *
>> +     * @param statusVariable the identifier of the 
>> <code>StatusVariable</code>
>> +     *        in [Monitorable_id]/[StatusVariable_id] format
>> +     * @param actions the list of allowed actions separated by commas
>> +     * @throws java.lang.IllegalArgumentException if either 
>> parameter is
>> +     *         <code>null</code>, or invalid with regard to the 
>> constraints
>> +     *         defined above and in the documentation of the used 
>> actions
>> +     */
>> +    public MonitorPermission(String statusVariable, String actions)
>> +            throws IllegalArgumentException {
>> +        super(statusVariable);
>> +
>> +        if(statusVariable == null)
>> +            throw new IllegalArgumentException(
>> +                    "Invalid StatusVariable path 'null'.");
>> +
>> +        if(actions == null)
>> +            throw new IllegalArgumentException(
>> +                    "Invalid actions string 'null'.");
>> +
>> +        int sep = statusVariable.indexOf('/');
>> +        int len = statusVariable.length();
>> +
>> +        if (sep == -1)
>> +            throw new IllegalArgumentException(
>> +                    "Invalid StatusVariable path: should contain '/' 
>> separator.");
>> +        if (sep == 0 || sep == statusVariable.length() - 1)
>> +            throw new IllegalArgumentException(
>> +                    "Invalid StatusVariable path: empty monitorable 
>> ID or StatusVariable name.");
>> +
>> +        prefixMonId = statusVariable.charAt(sep - 1) == '*';
>> +        prefixVarId = statusVariable.charAt(len - 1) == '*';
>> +
>> +        monId = statusVariable.substring(0, prefixMonId ? sep - 1 : 
>> sep);
>> +        varId = statusVariable.substring(sep + 1, prefixVarId ? len 
>> - 1 : len);
>> +
>> +        checkId(monId, "Monitorable ID part of the target");
>> +        checkId(varId, "Status Variable ID part of the target");
>> +
>> +        mask = 0;
>> +        minJobInterval = 0;
>> +
>> +        StringTokenizer st = new StringTokenizer(actions, ",");
>> +        while (st.hasMoreTokens()) {
>> +            String action = st.nextToken();
>> +            if (action.equalsIgnoreCase(READ)) {
>> +                addToMask(READ_FLAG, READ);
>> +            } else if (action.equalsIgnoreCase(RESET)) {
>> +                addToMask(RESET_FLAG, RESET);
>> +            } else if (action.equalsIgnoreCase(PUBLISH)) {
>> +                addToMask(PUBLISH_FLAG, PUBLISH);
>> +            } else if (action.equalsIgnoreCase(SWITCHEVENTS)) {
>> +                addToMask(SWITCHEVENTS_FLAG, SWITCHEVENTS);
>> +            } else if (action.toLowerCase().startsWith(STARTJOB)) {
>> +                minJobInterval = 0;
>> +
>> +                int slen = STARTJOB.length();
>> +                if (action.length() != slen) {
>> +                    if (action.charAt(slen) != ':')
>> +                        throw new IllegalArgumentException("Invalid 
>> action '"
>> +                                + action + "'.");
>> +
>> +                    try {
>> +                        minJobInterval = Integer.parseInt(action
>> +                                .substring(slen + 1));
>> +                    } catch (NumberFormatException e) {
>> +                        throw new IllegalArgumentException(
>> +                                "Invalid parameter in startjob 
>> action '"
>> +                                        + action + "'.");
>> +                    }
>> +                }
>> +                addToMask(STARTJOB_FLAG, STARTJOB);
>> +            } else
>> +                throw new IllegalArgumentException("Invalid action 
>> '" + action
>> +                        + "'");
>> +        }
>> +    }
>> +
>> +    private void addToMask(int action, String actionString) {
>> +        if((mask & action) != 0)
>> +            throw new IllegalArgumentException("Invalid action 
>> string: " +
>> +                    actionString + " appears multiple times.");
>> +
>> +        mask |= action;
>> +    }
>> +
>> +    private void checkId(String id, String idName)
>> +            throws IllegalArgumentException {
>> +
>> +        if (id.length() > StatusVariable.MAX_ID_LENGTH)
>> +            throw new IllegalArgumentException(idName + " is too 
>> long (over "
>> +                    + StatusVariable.MAX_ID_LENGTH + " characters).");
>> +
>> +        if (id.equals(".") || id.equals(".."))
>> +            throw new IllegalArgumentException(idName + " is 
>> invalid.");
>> +
>> +        char[] chars = id.toCharArray();
>> +        for (int i = 0; i < chars.length; i++)
>> +            if 
>> (StatusVariable.SYMBOLIC_NAME_CHARACTERS.indexOf(chars[i]) == -1)
>> +                throw new IllegalArgumentException(idName
>> +                        + " contains invalid characters.");
>> +    }
>> +
>> +    /**
>> +     * Create an integer hash of the object. The hash codes of
>> +     * <code>MonitorPermission</code>s <code>p1</code> and 
>> <code>p2</code> are
>> +     * the same if <code>p1.equals(p2)</code>.
>> +     *
>> +     * @return the hash of the object
>> +     */
>> +    public int hashCode() {
>> +        return new Integer(mask).hashCode()
>> +                ^ new Integer(minJobInterval).hashCode() ^ 
>> monId.hashCode()
>> +                ^ new Boolean(prefixMonId).hashCode()
>> +                ^ varId.hashCode()
>> +                ^ new Boolean(prefixVarId).hashCode();
>> +    }
>> +
>> +    /**
>> +     * Determines the equality of two <code>MonitorPermission</code> 
>> objects.
>> +     * Two <code>MonitorPermission</code> objects are equal if their 
>> target
>> +     * strings are equal and the same set of actions are listed in 
>> their action
>> +     * strings.
>> +     *
>> +     * @param o the object being compared for equality with this object
>> +     * @return <code>true</code> if the two permissions are equal
>> +     */
>> +    public boolean equals(Object o) {
>> +        if (!(o instanceof MonitorPermission))
>> +            return false;
>> +
>> +        MonitorPermission other = (MonitorPermission) o;
>> +
>> +        return mask == other.mask && minJobInterval == 
>> other.minJobInterval
>> +                && monId.equals(other.monId)
>> +                && prefixMonId == other.prefixMonId
>> +                && varId.equals(other.varId)
>> +                && prefixVarId == other.prefixVarId;
>> +    }
>> +
>> +    /**
>> +     * Get the action string associated with this permission.
>> +     *
>> +     * @return the allowed actions separated by commas, cannot be
>> +     *         <code>null</code>
>> +     */
>> +    public String getActions() {
>> +        StringBuffer sb = new StringBuffer();
>> +
>> +        appendAction(sb, READ_FLAG,         READ);
>> +        appendAction(sb, RESET_FLAG,        RESET);
>> +        appendAction(sb, PUBLISH_FLAG,      PUBLISH);
>> +        appendAction(sb, STARTJOB_FLAG,     STARTJOB);
>> +        appendAction(sb, SWITCHEVENTS_FLAG, SWITCHEVENTS);
>> +
>> +        return sb.toString();
>> +    }
>> +
>> +    private void appendAction(StringBuffer sb, int flag, String 
>> actionName) {
>> +        if ((mask & flag) != 0) {
>> +            if(sb.length() != 0)
>> +                sb.append(',');
>> +            sb.append(actionName);
>> +
>> +            if(flag == STARTJOB_FLAG && minJobInterval != 0)
>> +                sb.append(':').append(minJobInterval);
>> +        }
>> +    }
>> +
>> +    /**
>> +     * Determines if the specified permission is implied by this 
>> permission.
>> +     * <p>
>> +     * This method returns <code>false</code> if and only if at 
>> least one of the
>> +     * following conditions are fulfilled for the specified permission:
>> +     * <li>it is not a <code>MonitorPermission</code>
>> +     * <li>it has a broader set of actions allowed than this one
>> +     * <li>it allows initiating time based monitoring jobs with a 
>> lower minimal
>> +     * sampling interval
>> +     * <li>the target set of <code>Monitorable</code>s is not the 
>> same nor a
>> +     * subset of the target set of <code>Monitorable</code>s of this 
>> permission
>> +     * <li>the target set of <code>StatusVariable</code>s is not the 
>> same
>> +     * nor a subset of the target set of 
>> <code>StatusVariable</code>s of this
>> +     * permission
>> +     *
>> +     * @param p the permission to be checked
>> +     * @return <code>true</code> if the given permission is implied 
>> by this
>> +     *         permission
>> +     */
>> +    public boolean implies(Permission p) {
>> +        if (!(p instanceof MonitorPermission))
>> +            return false;
>> +
>> +        MonitorPermission other = (MonitorPermission) p;
>> +
>> +        if ((mask & other.mask) != other.mask)
>> +            return false;
>> +
>> +        if ((other.mask & STARTJOB_FLAG) != 0
>> +                && minJobInterval > other.minJobInterval)
>> +            return false;
>> +
>> +        return implies(monId, prefixMonId, other.monId, 
>> other.prefixMonId)
>> +                && implies(varId, prefixVarId, other.varId, 
>> other.prefixVarId);
>> +    }
>> +
>> +    private boolean implies(String id, boolean prefix, String oid,
>> +            boolean oprefix) {
>> +
>> +        return prefix ? oid.startsWith(id) : !oprefix && 
>> id.equals(oid);
>> +    }
>> +}
>>
>> Propchange: 
>> felix/sandbox/donsez/monitoradmin/src/main/java/org/osgi/service/monitor/MonitorPermission.java 
>>
>> ------------------------------------------------------------------------------ 
>>
>>     svn:eol-style = native
>>
>>
>>
>
>

Re: svn commit: r554318 [1/2] - in /felix/sandbox/donsez/monitoradmin: ./ doc/ src/ src/main/ src/main/java/ src/main/java/org/ src/main/java/org/apache/ src/main/java/org/apache/felix/ src/main/java/org/apache/felix/monitor/ src/main/java/org/osgi/

Posted by Karl Pauls <ka...@gmail.com>.
> > I see that this commit contains EPL licensed code. This should change
> > as soon as possible.
>
> Only the Copyright owner can change the license, unless you are
> licensed/authorized to do so through other means. I.e. we can't take the EPL
> code and change it to ALv2.

True, the issue is that we previously got the core and compendium
interface code licensed under ALv2 (from OSGi directly). I assume the
same should be possible for the mobile spec (if not already
available). So we don't need to take the EPL code and change it - we
can get it under the correct license :-)

> > I assume there is an ASL version available (since this are files from OSGi)?
>
> I don't think the Alliance requires a particular license on an RI, just for
> the specification itself. But I could be wrong.

See above. We should be able to get I under ALv2.

regards,

Karl

> Cheers
> --
> Niclas Hedhman, Software Developer
>
> I  live here; http://tinyurl.com/2qq9er
> I  work here; http://tinyurl.com/2ymelc
> I relax here; http://tinyurl.com/2cgsug
>


-- 
Karl Pauls
karlpauls@gmail.com

Re: svn commit: r554318 [1/2] - in /felix/sandbox/donsez/monitoradmin: ./ doc/ src/ src/main/ src/main/java/ src/main/java/org/ src/main/java/org/apache/ src/main/java/org/apache/felix/ src/main/java/org/apache/felix/monitor/ src/main/java/org/osgi/

Posted by Niclas Hedhman <ni...@hedhman.org>.
On Tuesday 10 July 2007 01:00, Karl Pauls wrote:

> I see that this commit contains EPL licensed code. This should change
> as soon as possible. 

Only the Copyright owner can change the license, unless you are 
licensed/authorized to do so through other means. I.e. we can't take the EPL 
code and change it to ALv2.

> I assume there is an ASL version available (since this are files from OSGi)?

I don't think the Alliance requires a particular license on an RI, just for 
the specification itself. But I could be wrong.


Cheers
-- 
Niclas Hedhman, Software Developer

I  live here; http://tinyurl.com/2qq9er
I  work here; http://tinyurl.com/2ymelc
I relax here; http://tinyurl.com/2cgsug