Package org.knowhowlab.osgi.monitoradmin

Source Code of org.knowhowlab.osgi.monitoradmin.MonitorAdminCommon$ServiceReferencePidComparator

/*
* Copyright (c) 2010 Dmytro Pishchukhin (http://knowhowlab.org)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*        http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.knowhowlab.osgi.monitoradmin;

import org.knowhowlab.osgi.monitoradmin.job.AbstractMonitoringJob;
import org.knowhowlab.osgi.monitoradmin.job.MonitoringJobVisitor;
import org.knowhowlab.osgi.monitoradmin.util.StatusVariablePath;
import org.knowhowlab.osgi.monitoradmin.util.Utils;
import org.osgi.framework.Constants;
import org.osgi.framework.ServiceReference;
import org.osgi.service.event.Event;
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 java.io.UnsupportedEncodingException;
import java.util.*;

/**
* MonitorAdmin common actions that are not related on Permissions
*
* @author dpishchukhin
*/
public class MonitorAdminCommon implements MonitorListener, MonitoringJobVisitor {
    private static final String SYMBOLIC_NAME_CHARACTERS =
            "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" + "0123456789" +
                    "-_.";   // a subset of the characters allowed in DMT URIs

    private static final int MAX_ID_LENGTH = 32;

    public static final String PATH_PATERN = "%s/%s";

    /**
     * Set of StatusVariable paths for which events are disabled
     */
    private final Set<String> disabledPaths = new HashSet<String>();
    /**
     * List of run jobs
     */
    private final List<AbstractMonitoringJob> jobs = new ArrayList<AbstractMonitoringJob>();

    private final OsgiVisitor osgiVisitor;
    private final LogVisitor logVisitor;

    public MonitorAdminCommon(OsgiVisitor osgiVisitor, LogVisitor logVisitor) {
        this.osgiVisitor = osgiVisitor;
        this.logVisitor = logVisitor;
    }

    /**
     * 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 points to a non-existing <code>Monitorable</code>,
     *          or if <code>statusVariable</code> is <code>null</code>
     */
    public void updated(String monitorableId, StatusVariable statusVariable) throws IllegalArgumentException {
        // validate monitorableId
        findMonitorableById(monitorableId);
        if (statusVariable == null) {
            throw new IllegalArgumentException("StatusVariable is null");
        }
        StatusVariablePath path = new StatusVariablePath(monitorableId, statusVariable.getID());
        if (isEventEnabled(path.getPath())) {
            fireEvent(monitorableId, statusVariable, null);
            logVisitor.info("Fire new SV update Event: " + path.getPath(), null);
        }
        // find jobs that handle this StatusVariable update event
        if (!jobs.isEmpty()) {
            synchronized (jobs) {
                for (AbstractMonitoringJob job : jobs) {
                    if (job.isHandleUpdateEvent(path.getPath())) {
                        job.handleUpdateEvent(monitorableId, statusVariable);
                    }
                }
            }
        }
    }

    /**
     * Get array with paths that are disabled for notificatios with switchEvents() method
     *
     * @return array with StatusVariable paths
     */
    public String[] getDisabledNotificationPaths() {
        return disabledPaths.toArray(new String[disabledPaths.size()]);
    }

    /**
     * Check if events are disabled for given path
     *
     * @param path path to check
     * @return if events are disabled - <code>true</code>, otherwise - <code>false</code>
     */
    private boolean isEventEnabled(String path) {
        return !disabledPaths.contains(path);
    }

    /**
     * Find Monitorable service by monitorable Id. Returns Monitorable service or
     * throws exception.
     * If multiple services exist for the same monitorableId,
     * the service with the highest ranking (as specified in its Constants.SERVICE_RANKING property)
     * is returned.
     * If there is a tie in ranking, the service with the lowest service ID (as specified
     * in its Constants.SERVICE_ID property); that is, the service that was regis-
     * tered first is returned.
     *
     * @param monitorableId id that is userd to filter services
     * @return Monitorable service with specified monitorableId.
     * @throws IllegalArgumentException monitorableId is <code>null</code> or monitorableId points
     *                                  to non-existing service or monitorableId is invalid
     */
    private Monitorable findMonitorableById(String monitorableId) throws IllegalArgumentException {
        if (monitorableId == null) {
            throw new IllegalArgumentException("MonitorableId is null");
        }

        if (!Utils.validatePathId(monitorableId)) {
            throw new IllegalArgumentException("MonitorableId is invalid");
        }

        ServiceReference mostSuitableMonitorable = null;
        ServiceReference[] serviceReferences = osgiVisitor.findMonitorableReferences(monitorableId);

        if (serviceReferences != null) {
            for (ServiceReference serviceReference : serviceReferences) {
                if (mostSuitableMonitorable == null ||
                        mostSuitableMonitorable.compareTo(serviceReference) < 0) {
                    mostSuitableMonitorable = serviceReference;
                }
            }
        }
        if (mostSuitableMonitorable == null) {
            throw new IllegalArgumentException("Monitorable ID: " + monitorableId + " points to non-existing service");
        }
        return osgiVisitor.getService(mostSuitableMonitorable);
    }

    /**
     * Find Monitorable service reference by monitorable Id. Returns Monitorable service reference or
     * throws exception.
     * If multiple services exist for the same monitorableId,
     * the service with the highest ranking (as specified in its Constants.SERVICE_RANKING property)
     * is returned.
     * If there is a tie in ranking, the service with the lowest service ID (as specified
     * in its Constants.SERVICE_ID property); that is, the service that was regis-
     * tered first is returned.
     *
     * @param monitorableId id that is userd to filter services
     * @return Monitorable service reference with specified monitorableId.
     * @throws IllegalArgumentException monitorableId is <code>null</code> or monitorableId points
     *                                  to non-existing service or monitorableId is invalid
     */
    public ServiceReference findMonitorableReferenceById(String monitorableId) throws IllegalArgumentException {
        if (monitorableId == null) {
            throw new IllegalArgumentException("MonitorableId is null");
        }

        if (!Utils.validatePathId(monitorableId)) {
            throw new IllegalArgumentException("MonitorableId is invalid");
        }

        ServiceReference mostSuitableMonitorable = null;
        ServiceReference[] serviceReferences = osgiVisitor.findMonitorableReferences(monitorableId);

        if (serviceReferences != null) {
            for (ServiceReference serviceReference : serviceReferences) {
                if (mostSuitableMonitorable == null ||
                        mostSuitableMonitorable.compareTo(serviceReference) < 0) {
                    mostSuitableMonitorable = serviceReference;
                }
            }
        }
        if (mostSuitableMonitorable == null) {
            throw new IllegalArgumentException("Monitorable ID: " + monitorableId + " points to non-existing service");
        }
        return mostSuitableMonitorable;
    }

    /**
     * Returns array of the <code>Monitorable</code> <code>ServiceReference</code>s that are
     * currently registered.
     * <p/>
     * The returned array contains the <code>ServiceTeference</code>s in alphabetical order by service PID.
     * 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 ServiceReference[] getMonitorableReferences() {
        return getMonitorableReferences(null);
    }

    /**
     * Returns array of the <code>Monitorable</code> <code>ServiceReference</code>s that are
     * currently registered.
     * <p/>
     * The returned array contains the <code>ServiceTeference</code>s in alphabetical order by service PID.
     * It cannot be <code>null</code>, an empty array is returned if no
     * <code>Monitorable</code> services are registered.
     *
     * @param monitorableIdFilter <code>Monitorable</code> SERVICE_PID filter
     * @return the array of <code>Monitorable</code> names
     */
    public ServiceReference[] getMonitorableReferences(String monitorableIdFilter) {
        // sorted set that contains Monitorable ServiceReferences
        SortedSet<ServiceReference> names = new TreeSet<ServiceReference>(new ServiceReferencePidComparator());
        ServiceReference[] serviceReferences = osgiVisitor.findMonitorableReferences(monitorableIdFilter);
        if (serviceReferences != null) {
            for (ServiceReference serviceReference : serviceReferences) {
                String pid = (String) serviceReference.getProperty(Constants.SERVICE_PID);
                if (pid != null && isValidId(pid)) {
                    names.add(serviceReference);
                }
            }
        }
        return names.toArray(new ServiceReference[names.size()]);
    }

    /**
     * Add a new <code>MonitoringJob</code> to the list
     *
     * @param job MonitoringJob
     */
    public void addJob(AbstractMonitoringJob job) {
        synchronized (jobs) {
            jobs.add(job);
        }
    }

    /**
     * Get list of all running <code>MonitoringJob</code>s
     *
     * @return list of running jobs
     */
    public List<MonitoringJob> getRunningJobs() {
        List<MonitoringJob> runningJobs = new ArrayList<MonitoringJob>();
        synchronized (jobs) {
            for (AbstractMonitoringJob job : jobs) {
                if (job.isRunning()) {
                    runningJobs.add(job);
                }
            }
        }
        return runningJobs;
    }

    /**
     * Returns a <code>StatusVariable</code> addressed by its full path.
     *
     * @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>
     */
    public StatusVariable getStatusVariable(String path)
            throws IllegalArgumentException {
        logVisitor.debug("ENTRY: getStatusVariable: " + path, null);
        try {
            StatusVariablePath statusVariablePath = new StatusVariablePath(path);
            Monitorable monitorable = findMonitorableById(statusVariablePath.getMonitorableId());

            return monitorable.getStatusVariable(statusVariablePath.getStatusVariableId());
        } finally {
            logVisitor.debug("EXIT: getStatusVariable: " + path, null);
        }
    }

    /**
     * Returns a <code>StatusVariable</code> addressed by Monitorable service reference and its id.
     *
     * @param serviceReference <code>Monitorable</code> service reference
     * @param statusVariableId <code>StatusVariable</code> id
     * @return the <code>StatusVariable</code> object
     * @throws java.lang.IllegalArgumentException
     *          if points to a
     *          non-existing <code>StatusVariable</code>
     */
    public StatusVariable getStatusVariable(ServiceReference serviceReference, String statusVariableId) {
        return osgiVisitor.getService(serviceReference).getStatusVariable(statusVariableId);
    }

    /**
     * Returns a <code>StatusVariable</code> description addressed by
     * Monitorable service reference and its id.
     *
     * @param serviceReference <code>Monitorable</code> service reference
     * @param statusVariableId <code>StatusVariable</code> id
     * @return the <code>StatusVariable</code> description
     * @throws java.lang.IllegalArgumentException
     *          if points to a
     *          non-existing <code>StatusVariable</code>
     */
    public String getDescription(ServiceReference serviceReference, String statusVariableId) {
        return osgiVisitor.getService(serviceReference).getDescription(statusVariableId);
    }

    /**
     * Returns a <code>StatusVariable</code> notification flag addressed by
     * Monitorable service reference and its id.
     *
     * @param serviceReference <code>Monitorable</code> service reference
     * @param statusVariableId <code>StatusVariable</code> id
     * @return the <code>StatusVariable</code> notification flag
     * @throws java.lang.IllegalArgumentException
     *          if points to a
     *          non-existing <code>StatusVariable</code>
     */
    public boolean notifiesOnChange(ServiceReference serviceReference, String statusVariableId) {
        return osgiVisitor.getService(serviceReference).notifiesOnChange(statusVariableId);
    }

    /**
     * Reset <code>StatusVariable</code> description addressed by
     * Monitorable service reference and its id.
     *
     * @param serviceReference <code>Monitorable</code> service reference
     * @param statusVariableId <code>StatusVariable</code> id
     * @return the <code>StatusVariable</code> description
     * @throws java.lang.IllegalArgumentException
     *          if points to a
     *          non-existing <code>StatusVariable</code>
     */
    public boolean resetStatusVariable(ServiceReference serviceReference, String statusVariableId) {
        return osgiVisitor.getService(serviceReference).resetStatusVariable(statusVariableId);
    }


    /**
     * Cancel Job and remove it from jobs list
     *
     * @param job job to cancel
     */
    public void cancelJob(AbstractMonitoringJob job) {
        synchronized (jobs) {
            jobs.remove(job);
            job.cancel();
        }
    }

    /**
     * Cancel all jobs and clear the list
     */
    public void cancelAllJobs() {
        logVisitor.debug("ENTRY: cancelJobs", null);
        try {
            if (!jobs.isEmpty()) {
                synchronized (jobs) {
                    Iterator<AbstractMonitoringJob> iterator = jobs.iterator();
                    while (iterator.hasNext()) {
                        AbstractMonitoringJob job = iterator.next();
                        job.cancel();
                        iterator.remove();
                    }
                }
            }
        } finally {
            logVisitor.debug("ENTRY: cancelJobs", null);
        }
    }

    /**
     * Fire StatusVariable update event
     *
     * @param monitorableId  monitorableId
     * @param statusVariable status variable
     * @param initiator      initiator. if <code>null</code> - is not added to event
     */
    public void fireEvent(String monitorableId, StatusVariable statusVariable, String initiator) {
        Dictionary<String, String> eventProperties = new Hashtable<String, String>();
        eventProperties.put(ConstantsMonitorAdmin.MON_MONITORABLE_PID, monitorableId);
        eventProperties.put(ConstantsMonitorAdmin.MON_STATUSVARIABLE_NAME, statusVariable.getID());

        String value = null;
        switch (statusVariable.getType()) {
            case StatusVariable.TYPE_BOOLEAN:
                value = Boolean.toString(statusVariable.getBoolean());
                break;
            case StatusVariable.TYPE_FLOAT:
                value = Float.toString(statusVariable.getFloat());
                break;
            case StatusVariable.TYPE_INTEGER:
                value = Integer.toString(statusVariable.getInteger());
                break;
            case StatusVariable.TYPE_STRING:
                value = statusVariable.getString();
                break;
        }
        eventProperties.put(ConstantsMonitorAdmin.MON_STATUSVARIABLE_VALUE, value);
        if (initiator != null) {
            eventProperties.put(ConstantsMonitorAdmin.MON_LISTENER_ID, initiator);
        }

        Event event = new Event(ConstantsMonitorAdmin.TOPIC, eventProperties);
        try {
            osgiVisitor.postEvent(event);
        } catch (SecurityException e) {
            logVisitor.error("MonitorAdmin bundle does not have TopicPermission", e);
        }
    }

    /**
     * Switch on/off events
     *
     * @param paths <code>StatusVariable</code> paths
     * @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
     */
    public void switchEvents(Set<String> paths, boolean on) {
        if (on) {
            disabledPaths.removeAll(paths);
        } else {
            disabledPaths.addAll(paths);
        }
    }


    /**
     * 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) {
        Monitorable monitorable = findMonitorableById(monitorableId);
        String[] statusVariableNames = monitorable.getStatusVariableNames();

        List<String> result = new ArrayList<String>();

        for (String statusVariableName : statusVariableNames) {
            if (isValidId(statusVariableName)) {
                result.add(statusVariableName);
            }
        }
        return result.toArray(new String[result.size()]);
    }

    private static class ServiceReferencePidComparator implements Comparator<ServiceReference> {
        public int compare(ServiceReference o1, ServiceReference o2) {
            String pid1 = (String) o1.getProperty(Constants.SERVICE_PID);
            String pid2 = (String) o2.getProperty(Constants.SERVICE_PID);
            return pid1.compareTo(pid2);
        }
    }

    /**
     * Validate <code>Monitorable</code> Id or <code>StatusVariable</code> name
     * @param id id
     * @return <code>false</code> - id is invalid, otherwise - <code>true</code>
     */
    public static boolean isValidId(String id) {

        byte[] nameBytes;
        try {
            nameBytes = id.getBytes("UTF-8");
        } catch (UnsupportedEncodingException e) {
            // never happens, "UTF-8" must always be supported
            return false;
        }
        if (nameBytes.length > MAX_ID_LENGTH) {
            return false;
        }


        if (id.equals(".") || id.equals("..")) {
            return false;
        }

        char[] chars = id.toCharArray();
        for (char aChar : chars) {
            if (SYMBOLIC_NAME_CHARACTERS.indexOf(aChar) == -1) {
                return false;
            }
        }
        return true;
    }

}
TOP

Related Classes of org.knowhowlab.osgi.monitoradmin.MonitorAdminCommon$ServiceReferencePidComparator

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.