org.paxle.core.impl.MWComponent.java Source code

Java tutorial

Introduction

Here is the source code for org.paxle.core.impl.MWComponent.java

Source

/**
 * This file is part of the Paxle project.
 * Visit http://www.paxle.net for more information.
 * Copyright 2007-2010 the original author or authors.
 *
 * Licensed under the terms of the Common Public License 1.0 ("CPL 1.0").
 * Any use, reproduction or distribution of this program constitutes the recipient's acceptance of this agreement.
 * The full license text is available under http://www.opensource.org/licenses/cpl1.0.txt
 * or in the file LICENSE.txt in the root directory of the Paxle distribution.
 *
 * Unless required by applicable law or agreed to in writing, this software is distributed
 * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 */

package org.paxle.core.impl;

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Dictionary;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.List;
import java.util.Locale;
import java.util.ResourceBundle;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.osgi.framework.Constants;
import org.osgi.service.cm.Configuration;
import org.osgi.service.cm.ConfigurationException;
import org.osgi.service.cm.ManagedService;
import org.osgi.service.event.Event;
import org.osgi.service.event.EventHandler;
import org.osgi.service.metatype.AttributeDefinition;
import org.osgi.service.metatype.MetaTypeProvider;
import org.osgi.service.metatype.ObjectClassDefinition;
import org.osgi.service.monitor.Monitorable;
import org.osgi.service.monitor.StatusVariable;
import org.paxle.core.IMWComponent;
import org.paxle.core.MWComponentEvent;
import org.paxle.core.data.IDataSink;
import org.paxle.core.data.IDataSource;
import org.paxle.core.queue.InputQueue;
import org.paxle.core.queue.OutputQueue;
import org.paxle.core.threading.IMaster;
import org.paxle.core.threading.IPool;
import org.paxle.core.threading.impl.Pool;

/**
 * @see IMWComponent
 */
public class MWComponent<Data>
        implements IMWComponent<Data>, ManagedService, MetaTypeProvider, Monitorable, EventHandler {
    /* ========================================================================
     * MONITORABLE properties
     * ======================================================================== */
    private static final String VAR_NAME_PPM = "ppm";
    private static final String VAR_NAME_PAUSED = "status.paused";
    private static final String VAR_NAME_JOBS_ENQUEUED = "jobs.enqueued";
    private static final String VAR_NAME_JOBS_ACTIVE = "jobs.active";
    private static final String VAR_NAME_JOBS_MAX = "jobs.max";
    private static final String VAR_NAME_JOBS_TOTAL = "jobs.total";
    private static final String VAR_NAME_JOB_DELAY = "job.delay";
    private static final String VAR_NAME_STAT_CODE = "state.code";

    /**
     * The names of all {@link StatusVariable status-variables} supported by this {@link Monitorable}
     */
    @SuppressWarnings("serial")
    private static final HashSet<String> VAR_NAMES = new HashSet<String>() {
        {
            add(VAR_NAME_PPM);
            add(VAR_NAME_PAUSED);
            add(VAR_NAME_JOBS_ENQUEUED);
            add(VAR_NAME_JOBS_ACTIVE);
            add(VAR_NAME_JOBS_MAX);
            add(VAR_NAME_JOBS_TOTAL);
            add(VAR_NAME_JOB_DELAY);
            add(VAR_NAME_STAT_CODE);
        }
    };

    /**
     * Descriptions of all {@link StatusVariable status-variables} supported by this {@link Monitorable}
     */
    private final ResourceBundle monitorableRb = ResourceBundle.getBundle("OSGI-INF/l10n/MWComponent");

    /* ========================================================================
     * CM properties
     * ======================================================================== */
    public static final String PROP_POOL_MIN_IDLE = "pool.minIdle";
    public static final String PROP_POOL_MAX_IDLE = "pool.maxIdle";
    public static final String PROP_POOL_MAX_ACTIVE = "pool.maxActive";
    public static final String PROP_DELAY = "master.delay";
    public static final String PROP_DELAY_DELTA = "master.delay.delta";
    public static final String PROP_ACTIVATED = "master.activated";

    private static final String PROP_STATE_ACTIVE = "state.active";
    private static final String PROP_STATE_CODE = "state.code";

    /**
     * Master thread
     */
    private final IMaster<Data> master;

    /**
     * Worker thread pool
     */
    private final Pool<Data> pool;

    /**
     * Component input-queue
     */
    private final InputQueue<Data> inQueue;

    /**
     * Component output-queue
     */
    private final OutputQueue<Data> outQueue;

    /**
     * The unique ID of this component.
     * This is needed for CM
     */
    private String componentID;

    /**
     * The name of this component instance.
     * This is needed for CM.
     */
    private String componentName;

    /**
     * A textual description of this component.
     * This is needed by CM.
     */
    private String componentDescription;

    /**
     * A class to send {@link MWComponentEvent}s
     */
    private MWComponentEventSender eventSender;

    /**
     * For logging
     */
    private Log logger = LogFactory.getLog(this.getClass());

    private Configuration configuration;

    private final String[] locales;

    private String stateCode = "OK";

    public MWComponent(IMaster<Data> master, Pool<Data> pool, InputQueue<Data> inQueue, OutputQueue<Data> outQueue,
            final String[] locales) {
        if (master == null)
            throw new NullPointerException("The master thread is null.");
        if (pool == null)
            throw new NullPointerException("The thread-pool is null");
        if (inQueue == null)
            throw new NullPointerException("The input-queue is null");
        if (outQueue == null)
            throw new NullPointerException("The output-queue is null");

        this.master = master;
        this.pool = pool;
        this.inQueue = inQueue;
        this.outQueue = outQueue;
        this.locales = locales == null ? null : locales.clone();
    }

    void setComponentID(String componentID) {
        this.componentID = componentID;
    }

    void setComponentName(String componentName) {
        this.componentName = componentName;
    }

    void setComponentDescription(String componentDescription) {
        this.componentDescription = componentDescription;
    }

    void setEventSender(MWComponentEventSender eventSender) {
        this.eventSender = eventSender;
    }

    void setConfiguration(final Configuration configuration) {
        this.configuration = configuration;
    }

    /**
     * {@inheritDoc}
     * @see IMWComponent#getDataSink()
     */
    public IDataSink<Data> getDataSink() {
        return this.inQueue;
    }

    /**
     * {@inheritDoc}
     * @see IMWComponent#getDataSource()
     */
    public IDataSource<Data> getDataSource() {
        return this.outQueue;
    }

    /**
     * {@inheritDoc}
     * @see IMWComponent#getMaster()
     */
    public IMaster<Data> getMaster() {
        return this.master;
    }

    /**
     * {@inheritDoc}
     * @see IMWComponent#getPool()
     */
    public IPool<Data> getPool() {
        return this.pool;
    }

    /**
     * {@inheritDoc}
     * @see IMWComponent#terminate()
     */
    public void terminate() {
        // terminating the master-thread (this automatically closes the worker-pool)
        this.master.terminate();

        // TODO: closing the queues
    }

    /**
     * {@inheritDoc}
     * @see IMWComponent#isPaused()
     */
    public boolean isPaused() {
        return this.master.isPaused();
    }

    /**
     * {@inheritDoc}
     * @see IMWComponent#pause()
     */
    @SuppressWarnings("unchecked")
    public void pause() {
        try {
            final Dictionary props = configuration.getProperties();
            props.put(getFullPropertyName(PROP_STATE_ACTIVE), Boolean.FALSE);
            this.configuration.update(props);
        } catch (IOException e) {
            this.logger.error(e);
        }
    }

    /**
     * {@inheritDoc}
     * @see IMWComponent#resume()
     */
    @SuppressWarnings("unchecked")
    public void resume() {
        try {
            final Dictionary props = configuration.getProperties();
            props.put(getFullPropertyName(PROP_STATE_ACTIVE), Boolean.TRUE);
            this.configuration.update(props);
        } catch (IOException e) {
            this.logger.error(e);
        }

    }

    private void setActiveState(Boolean active) {
        if (active.booleanValue()) {
            this.master.resumeMaster();
            if (this.eventSender != null) {
                this.eventSender.sendResumedEvent(this.componentID);
            }
        } else {
            this.master.pauseMaster();
            if (this.eventSender != null) {
                this.eventSender.sendPausedEvent(this.componentID);
            }
        }
    }

    /**
     * {@inheritDoc}
     * @see IMWComponent#getPPM()
     */
    public int getPPM() {
        return this.master.getPPM();
    }

    /**
     * {@inheritDoc}
     * @see IMWComponent#processNext()
     */
    public void processNext() {
        this.master.processNext();
    }

    /**
     * @see IMWComponent#getActiveJobs()
     */
    public List<Data> getActiveJobs() {
        return this.pool.getActiveJobs();
    }

    /**
     * @see IMWComponent#getActiveJobCount()
     */
    public int getActiveJobCount() {
        return this.pool.getActiveJobCount();
    }

    /**
     * @see IMWComponent#getEnqueuedJobs()
     */
    @SuppressWarnings("unchecked")
    public List<Data> getEnqueuedJobs() {
        return (List<Data>) Arrays.asList(this.inQueue.toArray());
    }

    /**
     * @see IMWComponent#getEnqueuedJobCount()
     */
    public int getEnqueuedJobCount() {
        return this.inQueue.size();
    }

    /**
     * @see IMWComponent#process(Object)
     */
    public void process(Data cmd) throws Exception {
        this.master.process(cmd);
    };

    private String getFullPropertyName(final String prop) {
        return this.componentID + '.' + prop;
    }

    /**
     * @return the default configuration of this service
     */
    public Hashtable<String, Object> getDefaults() {
        Hashtable<String, Object> defaults = new Hashtable<String, Object>();

        defaults.put(Constants.SERVICE_PID, this.componentID);
        defaults.put(getFullPropertyName(PROP_POOL_MIN_IDLE), Integer.valueOf(0));
        defaults.put(getFullPropertyName(PROP_POOL_MAX_IDLE), Integer.valueOf(8));
        defaults.put(getFullPropertyName(PROP_POOL_MAX_ACTIVE), Integer.valueOf(8));
        defaults.put(getFullPropertyName(PROP_DELAY), Integer.valueOf(-1));
        defaults.put(getFullPropertyName(PROP_STATE_ACTIVE), Boolean.TRUE);

        return defaults;
    }

    @SuppressWarnings("unchecked")
    public void updated(Dictionary configuration) throws ConfigurationException {
        if (configuration == null) {
            /*
             * Generate default configuration
             */
            configuration = this.getDefaults();
        }

        /* 
         * Thread pool configuration
         */
        Integer minIdle = (Integer) configuration.get(getFullPropertyName(PROP_POOL_MIN_IDLE));
        this.pool.setMinIdle((minIdle == null) ? 0 : minIdle.intValue());

        Integer maxIdle = (Integer) configuration.get(getFullPropertyName(PROP_POOL_MAX_IDLE));
        this.pool.setMaxIdle((maxIdle == null) ? 8 : maxIdle.intValue());

        Integer maxActive = (Integer) configuration.get(getFullPropertyName(PROP_POOL_MAX_ACTIVE));
        this.pool.setMaxActive((maxActive == null) ? 8 : maxActive.intValue());

        /*
         * Delay between job execution
         */
        Integer delay = (Integer) configuration.get(getFullPropertyName(PROP_DELAY));
        this.master.setDelay((delay == null) ? -1 : delay.intValue());

        /*
         * Component actiontion status
         */
        final Boolean active = (Boolean) configuration.get(getFullPropertyName(PROP_STATE_ACTIVE));
        if (active != null) {
            this.stateCode = "OK";
            this.setActiveState(active);
        }
    }

    /**
     * @see MetaTypeProvider#getLocales()
     */
    public String[] getLocales() {
        return this.locales == null ? null : this.locales.clone();
    }

    /**
     * @see MetaTypeProvider#getObjectClassDefinition(String, String)
     */
    public ObjectClassDefinition getObjectClassDefinition(String id, String localeStr) {
        final ArrayList<AttributeDefinition> ads = new ArrayList<AttributeDefinition>();
        final Locale locale = (localeStr == null) ? Locale.ENGLISH : new Locale(localeStr);
        final ResourceBundle rb = ResourceBundle.getBundle("OSGI-INF/l10n/" + MWComponent.class.getSimpleName(),
                locale);

        ads.add(new AD(getFullPropertyName(PROP_POOL_MIN_IDLE), rb.getString("threads.idle.min.name"),
                rb.getString("threads.idle.min.desc"), new String[] { Integer.toString(0) }));
        ads.add(new AD(getFullPropertyName(PROP_POOL_MAX_IDLE), rb.getString("threads.idle.max.name"),
                rb.getString("threads.idle.max.desc"), new String[] { Integer.toString(8) }));
        ads.add(new AD(getFullPropertyName(PROP_POOL_MAX_ACTIVE), rb.getString("threads.active.max.name"),
                rb.getString("threads.active.max.desc"), new String[] { Integer.toString(8) }));
        ads.add(new AD(getFullPropertyName(PROP_DELAY), rb.getString("threads.active.delay.name"),
                rb.getString("threads.active.delay.desc"), new String[] { Integer.toString(-1) }));
        ads.add(new AttributeDefinition() {
            public int getCardinality() {
                return 0;
            }

            public String[] getDefaultValue() {
                return new String[] { Boolean.TRUE.toString() };
            }

            public String getDescription() {
                return rb.getString("state.active.desc");
            }

            public String getID() {
                return getFullPropertyName(PROP_STATE_ACTIVE);
            }

            public String getName() {
                return rb.getString("state.active.name");
            }

            public String[] getOptionLabels() {
                return new String[] { rb.getString("state.active.running"), rb.getString("state.active.paused") };
            }

            public String[] getOptionValues() {
                return new String[] { Boolean.TRUE.toString(), Boolean.FALSE.toString() };
            }

            public int getType() {
                return AttributeDefinition.BOOLEAN;
            }

            public String validate(String value) {
                return null;
            }
        });

        final String PID = this.componentID;
        final String mame = this.componentName;
        final String descr = this.componentDescription;

        // create metadata
        ObjectClassDefinition ocd = new ObjectClassDefinition() {
            public AttributeDefinition[] getAttributeDefinitions(int filter) {
                return ads.toArray(new AttributeDefinition[ads.size()]);
            }

            public String getDescription() {
                return descr;
            }

            public String getID() {
                return PID;
            }

            public InputStream getIcon(int size) throws IOException {
                return null;
            }

            public String getName() {
                return mame;
            }
        };

        return ocd;
    }

    public class AD implements AttributeDefinition {
        private String ID;
        private String name;
        private String description;
        private String[] defaultValue = null;

        public AD(String ID, String name, String description, String[] defaultValues) {
            this.ID = ID;
            this.name = name;
            this.description = description;
            this.defaultValue = defaultValues;
        }

        public String[] getDefaultValue() {
            return this.defaultValue;
        }

        public String getDescription() {
            return this.description;
        }

        public String getID() {
            return this.ID;
        }

        public String getName() {
            return this.name;
        }

        public int getCardinality() {
            return 0;
        }

        public String[] getOptionLabels() {
            return null;
        }

        public String[] getOptionValues() {
            return null;
        }

        public int getType() {
            return AttributeDefinition.INTEGER;
        }

        public String validate(String value) {
            return null;
        }
    }

    /**
     * @see Monitorable#getStatusVariableNames()
     */
    public String[] getStatusVariableNames() {
        return VAR_NAMES.toArray(new String[VAR_NAMES.size()]);
    }

    /**
     * @see Monitorable#getDescription(String)
     */
    public String getDescription(String name) throws IllegalArgumentException {
        if (!VAR_NAMES.contains(name)) {
            throw new IllegalArgumentException("Invalid Status Variable name " + name);
        }

        return this.monitorableRb.getString(name);
    }

    /**
     * @see Monitorable#getStatusVariable(String)
     */
    public StatusVariable getStatusVariable(String name) throws IllegalArgumentException {
        if (!VAR_NAMES.contains(name)) {
            throw new IllegalArgumentException("Invalid Status Variable name " + name);
        }

        if (name.equals(VAR_NAME_PPM)) {
            return new StatusVariable(name, StatusVariable.CM_GAUGE, this.getPPM());
        } else if (name.equals(VAR_NAME_PAUSED)) {
            return new StatusVariable(name, StatusVariable.CM_GAUGE, this.isPaused());
        } else if (name.equals(VAR_NAME_JOBS_ACTIVE)) {
            return new StatusVariable(name, StatusVariable.CM_GAUGE, this.getActiveJobCount());
        } else if (name.equals(VAR_NAME_JOBS_ENQUEUED)) {
            return new StatusVariable(name, StatusVariable.CM_GAUGE, this.getEnqueuedJobCount());
        } else if (name.equals(VAR_NAME_JOBS_MAX)) {
            return new StatusVariable(name, StatusVariable.CM_GAUGE, this.getPool().getMaxActiveJobCount());
        } else if (name.equals(VAR_NAME_JOBS_TOTAL)) {
            return new StatusVariable(name, StatusVariable.CM_GAUGE, this.getMaster().processedCount());
        } else if (name.equals(VAR_NAME_JOB_DELAY)) {
            return new StatusVariable(name, StatusVariable.CM_GAUGE, this.getMaster().getDelay());
        } else if (name.equals(VAR_NAME_STAT_CODE)) {
            return new StatusVariable(name, StatusVariable.CM_SI, this.stateCode);
        }
        return null;
    }

    /**
     * @see Monitorable#notifiesOnChange(String)
     */
    public boolean notifiesOnChange(String name) throws IllegalArgumentException {
        return false;
    }

    /**
     * @see Monitorable#resetStatusVariable(String)
     */
    public boolean resetStatusVariable(String name) throws IllegalArgumentException {
        return false;
    }

    /**
     * @see EventHandler#handleEvent(Event)
     */
    public void handleEvent(Event event) {
        final String topic = event.getTopic();
        if (topic.equals("org/paxle/monitorable/observer")) {
            final Boolean active = (Boolean) event.getProperty(this.getFullPropertyName(PROP_STATE_ACTIVE));
            final String stateCode = (String) event.getProperty(this.getFullPropertyName(PROP_STATE_CODE));

            if (stateCode != null) {
                this.stateCode = stateCode;
            }

            if (active != null) {
                this.setActiveState(active);
            }

            Integer deltaDelay = (Integer) event.getProperty(this.getFullPropertyName(PROP_DELAY_DELTA));
            if (deltaDelay != null) {
                int delay = this.getMaster().getDelay();
                if (delay < 0)
                    delay = 0;
                delay += deltaDelay.intValue();
                this.master.setDelay(delay);
            }
        }
    }

}