net.solarnetwork.node.runtime.JobSettingSpecifierProvider.java Source code

Java tutorial

Introduction

Here is the source code for net.solarnetwork.node.runtime.JobSettingSpecifierProvider.java

Source

/* ==================================================================
 * JobSettingSpecifierProvider.java - Mar 20, 2012 9:10:44 PM
 * 
 * Copyright 2007-2012 SolarNetwork.net Dev Team
 * 
 * This program is free software; you can redistribute it and/or 
 * modify it under the terms of the GNU General Public License as 
 * published by the Free Software Foundation; either version 2 of 
 * the License, or (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful, 
 * but WITHOUT ANY WARRANTY; without even the implied warranty of 
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 
 * General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License 
 * along with this program; if not, write to the Free Software 
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 
 * 02111-1307 USA
 * ==================================================================
 */

package net.solarnetwork.node.runtime;

import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import net.solarnetwork.node.job.TriggerAndJobDetail;
import net.solarnetwork.node.settings.SettingSpecifier;
import net.solarnetwork.node.settings.SettingSpecifierProvider;
import net.solarnetwork.node.settings.TextFieldSettingSpecifier;
import net.solarnetwork.node.settings.support.BasicTextFieldSettingSpecifier;
import org.quartz.CronTrigger;
import org.quartz.Trigger;
import org.springframework.context.MessageSource;
import org.springframework.context.NoSuchMessageException;
import org.springframework.context.support.AbstractMessageSource;
import org.springframework.util.StringUtils;

/**
 * {@link SettingSpecifierProvider} for Quartz job triggers.
 * 
 * <p>
 * This class allows a set of related Quartz Trigger instances to be exposed as
 * a {@link SettingSpecifierProvider} and managed by the node's setting UI. For
 * example the triggers might be grouped by the bundle they were published from.
 * It works with {@link TriggerAndJobDetail} services. Call
 * {@link #addSpecifier(TriggerAndJobDetail)} and
 * {@link #removeSpecifier(TriggerAndJobDetail)} as {@link TriggerAndJobDetail}
 * services are registered/unregistered with the system.
 * </p>
 * 
 * <p>
 * Currently only {@link CronTrigger} triggers are supported. Localized messages
 * are not supported.
 * </p>
 * 
 * @author matt
 * @version 1.0
 */
public class JobSettingSpecifierProvider implements SettingSpecifierProvider {

    /** The suffix added to display titles. */
    public static final String TITLE_SUFFIX = " Jobs";

    /** The suffix to remove from display titles in setting UIDs. */
    public static final String JOBS_PID_SUFFIX = ".JOBS";

    /** The prefix to remove for display titles in setting UIDs. */
    public static final String SN_NODE_PREFIX = "net.solarnetwork.node.";

    private String settingUID;
    private MessageSource messageSource = null;
    private List<SettingSpecifier> specifiers = new ArrayList<SettingSpecifier>();
    private final Map<String, MessageFormat> messages = new HashMap<String, MessageFormat>();

    /**
     * Construct with settings UID.
     * 
     * @param settingUID
     *        the setting UID
     */
    public JobSettingSpecifierProvider(String settingUID) {
        this(settingUID, null);
    }

    /**
     * Construct with settings UID.
     * 
     * @param settingUID
     *        the setting UID
     * @param source
     *        a message source
     */
    public JobSettingSpecifierProvider(String settingUID, MessageSource source) {
        super();
        this.settingUID = settingUID;
        this.messageSource = source;
        if (source == null || !hasMessage(source, "title")) {
            messages.put("title", new MessageFormat(titleValue(settingUID)));
        }

        AbstractMessageSource msgSource = new AbstractMessageSource() {

            @Override
            protected MessageFormat resolveCode(String code, Locale locale) {
                return messages.get(code);
            }
        };
        msgSource.setParentMessageSource(source);
        this.messageSource = msgSource;
    }

    private static boolean hasMessage(MessageSource source, String key) {
        if (source == null) {
            return false;
        }
        try {
            source.getMessage(key, null, Locale.getDefault());
            return true;
        } catch (NoSuchMessageException e) {
            return false;
        }
    }

    /**
     * Construct a display title based on a setting UID.
     * 
     * <p>
     * The display title is generated from the setting UID itself, by first
     * removing the {@link #SN_NODE_PREFIX} prefix and {@link #JOBS_PID_SUFFIX}
     * suffix, capitalizing the remaining value, and appending
     * {@link #TITLE_SUFFIX}. For example, the UID
     * <code>net.solarnetwork.node.power.JOBS</code> will result in
     * <code>Power Jobs</code>.
     * </p>
     * 
     * 
     * @param settingUID
     *        the setting UID value
     * @return the generated title value
     */
    private static String titleValue(String settingUID) {
        if (settingUID.startsWith(SN_NODE_PREFIX) && settingUID.length() > SN_NODE_PREFIX.length()) {
            String subPackage = settingUID.substring(SN_NODE_PREFIX.length());
            if (subPackage.endsWith(JOBS_PID_SUFFIX) && subPackage.length() > JOBS_PID_SUFFIX.length()) {
                subPackage = subPackage.substring(0, subPackage.length() - JOBS_PID_SUFFIX.length());
            }
            if (subPackage.indexOf('.') < 0) {
                // capitalize first letter
                subPackage = Character.toUpperCase(subPackage.charAt(0)) + subPackage.substring(1) + TITLE_SUFFIX;
                return subPackage;
            }
            return subPackage;
        }
        return settingUID;
    }

    /**
     * Create appropriate {@link SettingSpecifier} instances for a given
     * {@link TriggerAndJobDetail}.
     * 
     * <p>
     * Call this method for every {@link TriggerAndJobDetail} published in the
     * system.
     * </p>
     * 
     * @param trigJob
     *        the service to generate specifiers for
     */
    public void addSpecifier(TriggerAndJobDetail trigJob) {
        Trigger trig = trigJob.getTrigger();
        if (trig instanceof CronTrigger) {
            CronTrigger ct = (CronTrigger) trig;
            final String key = JobUtils.triggerKey(ct);
            BasicTextFieldSettingSpecifier tf = new BasicTextFieldSettingSpecifier(key, ct.getCronExpression());
            tf.setTitle(ct.getName());
            final String labelKey = key + ".key";
            final String descKey = key + ".desc";
            if (!hasMessage(this.messageSource, labelKey)) {
                if (hasMessage(trigJob.getMessageSource(), labelKey)) {
                    messages.put(labelKey, new MessageFormat(
                            trigJob.getMessageSource().getMessage(labelKey, null, Locale.getDefault())));
                } else {
                    messages.put(labelKey, new MessageFormat(ct.getName()));
                }
            }
            if (!hasMessage(this.messageSource, descKey)) {
                if (hasMessage(trigJob.getMessageSource(), labelKey)) {
                    messages.put(descKey, new MessageFormat(
                            trigJob.getMessageSource().getMessage(descKey, null, Locale.getDefault())));
                } else {
                    messages.put(descKey,
                            new MessageFormat(StringUtils.hasText(ct.getDescription()) ? ct.getDescription() : ""));
                }
            }
            synchronized (specifiers) {
                specifiers.add(tf);
            }
        }
    }

    /**
     * Remove {@link SettingSpecifier} instances previously registered via
     * {@link #addSpecifier(TriggerAndJobDetail)} for a given
     * {@link TriggerAndJobDetail}.
     * 
     * <p>
     * Call this method for every {@link TriggerAndJobDetail} unregistered in
     * the system.
     * </p>
     * 
     * @param trigJob
     *        the service to generate specifiers for
     */
    public void removeSpecifier(TriggerAndJobDetail trigJob) {
        Trigger trig = trigJob.getTrigger();
        if (trig instanceof CronTrigger) {
            CronTrigger ct = (CronTrigger) trig;
            final String key = JobUtils.triggerKey(ct);
            synchronized (specifiers) {
                for (Iterator<SettingSpecifier> itr = specifiers.iterator(); itr.hasNext();) {
                    TextFieldSettingSpecifier tf = (TextFieldSettingSpecifier) itr.next();
                    if (tf.getKey().equals(key)) {
                        itr.remove();
                        break;
                    }
                }
            }
        }
    }

    @Override
    public String getSettingUID() {
        return settingUID;
    }

    @Override
    public String getDisplayName() {
        return settingUID;
    }

    @Override
    public MessageSource getMessageSource() {
        return messageSource;
    }

    @Override
    public List<SettingSpecifier> getSettingSpecifiers() {
        synchronized (specifiers) {
            return Collections.unmodifiableList(specifiers);
        }
    }

    public List<SettingSpecifier> getSpecifiers() {
        return specifiers;
    }

    public void setSpecifiers(List<SettingSpecifier> specifiers) {
        this.specifiers = specifiers;
    }

}