org.globus.workspace.client.modes.Subscribe.java Source code

Java tutorial

Introduction

Here is the source code for org.globus.workspace.client.modes.Subscribe.java

Source

/*
 * Copyright 1999-2008 University of Chicago
 *
 * 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.globus.workspace.client.modes;

import org.globus.workspace.common.print.Print;
import org.globus.workspace.client_core.print.PrCodes;
import org.globus.workspace.client_core.ParameterProblem;
import org.globus.workspace.client_core.ExecutionProblem;
import org.globus.workspace.client_core.ExitNow;
import org.globus.workspace.client_core.StubConfigurator;
import org.globus.workspace.client_core.utils.EPRUtils;
import org.globus.workspace.client_core.subscribe_tools.ListeningSubscriptionMaster;
import org.globus.workspace.client_core.subscribe_tools.PollingSubscriptionMaster;
import org.globus.workspace.client_core.subscribe_tools.SubscriptionMaster;
import org.globus.workspace.client_core.subscribe_tools.NotificationImplementationException;
import org.globus.workspace.client_core.subscribe_tools.SubscriptionMasterFactory;
import org.globus.workspace.client_core.repr.State;
import org.globus.workspace.client_core.repr.Workspace;
import org.globus.workspace.client.AllArguments;
import org.globus.workspace.client.modes.aux.SubscribeLaunch;
import org.globus.workspace.client.modes.aux.CommonLogs;
import org.nimbustools.messaging.gt4_0.common.CommonUtil;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.axis.message.addressing.EndpointReferenceType;
import edu.emory.mathcs.backport.java.util.concurrent.ExecutorService;

import java.net.URL;
import java.net.MalformedURLException;

public class Subscribe extends Mode {

    // -------------------------------------------------------------------------
    // STATIC VARIABLES
    // -------------------------------------------------------------------------

    private static final Log logger = LogFactory.getLog(Subscribe.class.getName());

    // -------------------------------------------------------------------------
    // INSTANCE VARIABLES
    // -------------------------------------------------------------------------

    EndpointReferenceType epr;
    boolean dryrun;
    boolean autodestroy;
    boolean isGroupRequest;
    String nameToPrint;
    String shortName;
    Workspace[] workspaces;

    // note that "subscribe" has same meaning here whether polling or not
    boolean pollDontListen; // true: poll, false: async listen
    State exitState;
    State veryTerseNotifyState;
    SubscribeLaunch subscribeLaunch;
    ListeningSubscriptionMaster listeningSubscriptionMaster;
    PollingSubscriptionMaster pollingSubscriptionMaster;
    SubscriptionMaster eitherSubscriptionMaster;
    String notificationListenerOverride_IPorHost;
    Integer notificationListenerOverride_Port;
    long pollMS = -1;
    int pollMaxThreads = -1;

    // -------------------------------------------------------------------------
    // CONSTRUCTOR
    // -------------------------------------------------------------------------

    public Subscribe(Print print, AllArguments arguments, StubConfigurator stubConfigurator) {
        super(print, arguments, stubConfigurator);
    }

    // -------------------------------------------------------------------------
    // GENERAL
    // -------------------------------------------------------------------------

    public String name() {
        return "Subscribe";
    }

    // -------------------------------------------------------------------------
    // VALIDATE
    // -------------------------------------------------------------------------

    public void validateOptionsImpl() throws ParameterProblem {
        this.validateEndpoint();
        this.validateName();
        this._handleExitState();
        this._handleVeryTerseNotifyState();
        this._handlePollDelay();
        this._handlePollMaxThreads();
        this._handleListenerOverride();

        this.dryrun = this.args.dryrun;
        CommonLogs.logBoolean(this.dryrun, "dryrun mode", this.pr, logger);

        this.autodestroy = this.args.autodestroy;
        CommonLogs.logBoolean(this.autodestroy, "autodestroy mode", this.pr, logger);

        this._logSubscribeStatus();

        if (this.pollDontListen) {
            this._handleSubscribeWithPoll();
        } else {
            this._handleSubscribeWithListen();
        }

        this._handleWorkspaces();
    }

    protected void validateEndpoint() throws ParameterProblem {

        this.epr = this.stubConf.getEPR();

        if (this.epr == null) {
            throw new ParameterProblem(name() + " requires EPR");
        }

        final String eprStr;
        try {
            eprStr = EPRUtils.eprToString(this.epr);
        } catch (Exception e) {
            final String err = CommonUtil.genericExceptionMessageWrapper(e);
            throw new ParameterProblem(err, e);
        }

        if (this.pr.enabled()) {
            // xml print
            final String dbg = "\nGiven EPR:\n----------\n" + eprStr + "----------\n";

            if (this.pr.useThis()) {
                this.pr.dbg(dbg);
            } else if (this.pr.useLogging()) {
                logger.debug(dbg);
            }
        }

        final String kind;
        if (EPRUtils.isInstanceEPR(this.epr)) {
            this.isGroupRequest = false;
            kind = "an instance";
        } else if (EPRUtils.isGroupEPR(this.epr)) {
            this.isGroupRequest = true;
            kind = "a group";
        } else {
            throw new ParameterProblem(name() + " requires a valid EPR.");
        }

        if (this.pr.enabled()) {
            final String dbg = "Given EPR is " + kind + " EPR";
            if (this.pr.useThis()) {
                this.pr.dbg(dbg);
            } else if (this.pr.useLogging()) {
                logger.debug(dbg);
            }
        }

        if (this.isGroupRequest) {
            throw new ParameterProblem(
                    name() + " can not handle group " + "subscribe yet (only after deploying).  Stay tuned.");
        }
    }

    protected void validateName() throws ParameterProblem {

        String eprName;
        if (this.isGroupRequest) {
            eprName = EPRUtils.getGroupIdFromEPR(this.epr);
            eprName = "group-" + eprName;
        } else {
            eprName = Integer.toString(EPRUtils.getIdFromEPR(this.epr));
            eprName = "workspace-" + eprName;
        }

        this.shortName = this.args.shortName;
        if (this.pr.enabled()) {
            final String dbg;
            if (this.shortName == null) {
                dbg = "Given display name is null";
            } else {
                dbg = "Given display name: " + this.shortName + "'";
            }
            if (this.pr.useThis()) {
                this.pr.dbg(dbg);
            } else if (this.pr.useLogging()) {
                logger.debug(dbg);
            }
        }

        if (this.shortName != null) {
            this.nameToPrint = this.shortName;
        } else {
            this.nameToPrint = eprName;
        }
    }

    protected void _handleExitState() throws ParameterProblem {

        if (this.args.exitStateString == null) {
            return; // *** EARLY RETURN ***
        }

        if (!State.testValidState(this.args.exitStateString)) {
            throw new ParameterProblem(
                    "Provided exit string is not a " + "valid state: '" + this.args.exitStateString + "'");
        }

        this.exitState = new State(this.args.exitStateString);
        if (this.pr.enabled()) {
            final String dbg = "Exit state: " + this.exitState.toString();
            if (this.pr.useThis()) {
                this.pr.dbg(dbg);
            } else if (this.pr.useLogging()) {
                logger.debug(dbg);
            }
        }
    }

    protected void _handleVeryTerseNotifyState() throws ParameterProblem {

        if (this.args.veryTerseNotifyStateString == null) {
            return; // *** EARLY RETURN ***
        }

        if (!State.testValidState(this.args.veryTerseNotifyStateString)) {
            throw new ParameterProblem("Provided very-terse-notify state string is not a " + "valid state: '"
                    + this.args.veryTerseNotifyStateString + "'");
        }

        this.veryTerseNotifyState = new State(this.args.veryTerseNotifyStateString);
        if (this.pr.enabled()) {
            final String dbg = "very-terse-notify state: " + this.veryTerseNotifyState.toString();
            if (this.pr.useThis()) {
                this.pr.dbg(dbg);
            } else if (this.pr.useLogging()) {
                logger.debug(dbg);
            }
        }
    }

    protected void _handlePollDelay() throws ParameterProblem {

        if (this.args.pollDelayString == null) {
            return; // *** EARLY RETURN ***
        }

        // default subscription mode is notification listener
        // setting the poll delay sets the subscription mode to poll
        this.pollDontListen = true;

        try {
            this.pollMS = Long.parseLong(this.args.pollDelayString);
        } catch (NumberFormatException e) {
            throw new ParameterProblem(
                    "Given poll delay is not valid: '" + this.args.pollDelayString + "': " + e.getMessage(), e);
        }

        if (this.pollMS < 1) {
            throw new ParameterProblem("Given poll delay is less than 1ms: " + this.pollMS + "ms");
        }
    }

    protected void _handlePollMaxThreads() throws ParameterProblem {

        if (this.args.pollMaxThreadsString == null) {
            return; // *** EARLY RETURN ***
        }

        try {
            this.pollMaxThreads = Integer.parseInt(this.args.pollMaxThreadsString);
        } catch (NumberFormatException e) {
            throw new ParameterProblem("Given poll max-threads number is not valid: '"
                    + this.args.pollMaxThreadsString + "': " + e.getMessage(), e);
        }

        if (this.pollMaxThreads < 1) {
            throw new ParameterProblem(
                    "Given poll max-threads is invalid, " + "it is less than 1: " + this.pollMaxThreads);
        }
    }

    protected void _handleListenerOverride() throws ParameterProblem {

        final String given = this.args.listenerOverride;
        if (given == null) {
            return; // *** EARLY RETURN ***
        }

        if (given.indexOf('/') >= 0) {
            throw new ParameterProblem(
                    "Listener override address has a '/' " + "in it, use just a host or IP, not an URL");
        }

        final int splt = given.indexOf(':'); // first occurence only
        final String host;
        final String port;
        if (splt >= 0) {
            host = given.substring(0, splt).trim();
            port = given.substring(splt).trim();
        } else {
            host = given.trim();
            port = null;
        }

        if (host.length() == 0) {
            throw new ParameterProblem(
                    "Listener override address " + "has zero-length hostname, given: \"" + given + "\"");
        }

        if (port != null && port.length() == 0) {
            throw new ParameterProblem(
                    "Listener override address " + "has zero-length port, given: \"" + given + "\"");
        }

        final String urlString;
        if (port == null) {
            urlString = "http://" + host;
        } else {
            urlString = "http://" + host + ":" + port;
        }

        final String usingHost;
        int usingPort = -1;
        try {
            final URL url = new URL(urlString);
            usingHost = url.getHost();
            if (port != null) {
                usingPort = url.getPort();
            }
        } catch (MalformedURLException e) {
            throw new ParameterProblem(
                    "Falied to test validity of listener " + "override address using given input '" + given + "', "
                            + "testing with URL constructed from '" + urlString + "': " + e.getMessage(),
                    e);
        }

        this.notificationListenerOverride_IPorHost = usingHost;
        if (usingPort > 0) {
            this.notificationListenerOverride_Port = new Integer(usingPort);
        }
    }

    protected void _logSubscribeStatus() {

        if (!this.pr.enabled()) {
            return; // *** EARLY RETURN ***
        }

        String listenTail = "";
        if (this.notificationListenerOverride_IPorHost != null && this.notificationListenerOverride_Port != null) {

            final String addr = this.notificationListenerOverride_IPorHost + ":"
                    + this.notificationListenerOverride_Port.intValue();

            listenTail = " (listener override host+port: '" + addr + "')";

        } else if (this.notificationListenerOverride_IPorHost != null) {

            listenTail = " (listener override host: '" + this.notificationListenerOverride_IPorHost + "')";

        }

        final String dbg;
        if (this.pollDontListen) {
            dbg = "subscription mode: POLL (" + this.pollMS + "ms delay)";
        } else {
            dbg = "subscription mode: LISTENER" + listenTail;
        }
        if (this.pr.useThis()) {
            this.pr.dbg(dbg);
        } else if (this.pr.useLogging()) {
            logger.debug(dbg);
        }
    }

    protected void _handleSubscribeWithListen() throws ParameterProblem {

        if (this.eitherSubscriptionMaster != null) {
            throw new IllegalStateException("you may only make one "
                    + "subscription master non-null (and copy its reference " + "to 'either' variable)");
        }

        this.listeningSubscriptionMaster = SubscriptionMasterFactory.newListeningMaster(null, this.pr);

        this.eitherSubscriptionMaster = this.listeningSubscriptionMaster;

        if (this.dryrun) {
            final String dbg = "Dryrun, not starting to listen for notifications.";
            if (this.pr.useThis()) {
                this.pr.info(PrCodes.CREATE__DRYRUN, dbg);
            } else if (this.pr.useLogging()) {
                logger.info(dbg);
            }

            return; // *** EARLY RETURN ***
        }

        final String errPrefix = "Problem starting to listen for notifications: ";
        try {
            this.listeningSubscriptionMaster.listen(this.notificationListenerOverride_IPorHost,
                    this.notificationListenerOverride_Port);
        } catch (IllegalStateException e) {
            throw new ParameterProblem(errPrefix + e.getMessage(), e);
        } catch (IllegalArgumentException e) {
            throw new ParameterProblem(errPrefix + e.getMessage(), e);
        } catch (Exception e) {
            throw new ParameterProblem(errPrefix + e.getMessage(), e);
        }

        this.subscribeLaunch = new SubscribeLaunch(this.listeningSubscriptionMaster, this.nameToPrint, this.pr,
                this.stubConf, null);
    }

    protected void _handleSubscribeWithPoll() throws ParameterProblem {

        if (this.eitherSubscriptionMaster != null) {
            throw new IllegalStateException("you may only make one "
                    + "subscription master non-null (and copy its reference " + "to 'either' variable)");
        }

        final long ms = this.pollMS;
        final int thrNum = this.pollMaxThreads;
        final ExecutorService execService = null;
        final StubConfigurator conf = this.stubConf;

        final PollingSubscriptionMaster master;

        if (thrNum < 1) {
            // default maxThreads
            master = SubscriptionMasterFactory.newPollingMaster(ms, conf, execService, this.pr);
        } else {
            // cap the maxThreads
            master = SubscriptionMasterFactory.newPollingMaster(ms, thrNum, conf, execService, this.pr);
        }

        this.pollingSubscriptionMaster = master;
        this.eitherSubscriptionMaster = master;

        this.subscribeLaunch = new SubscribeLaunch(master, this.nameToPrint, this.pr, this.stubConf, null);
    }

    protected void _handleWorkspaces() {

        if (this.isGroupRequest) {
            throw new IllegalStateException("group requests should have been rejected already");
        }

        final Workspace workspace = new Workspace();

        workspace.setEpr(this.epr);
        workspace.setCurrentState(new State());

        this.workspaces = new Workspace[1];
        this.workspaces[0] = workspace;
    }

    // -------------------------------------------------------------------------
    // EXECUTE
    // -------------------------------------------------------------------------

    public void runImpl() throws ParameterProblem, ExecutionProblem, ExitNow {
        try {
            _runImpl();
        } finally {
            this.doneCleanupSubscriptions();
        }
    }

    private void _runImpl() throws ParameterProblem, ExecutionProblem, ExitNow {
        this.subscribeLaunch.subscribe(this.workspaces, this.exitState, this.veryTerseNotifyState, this.autodestroy,
                false, false);
    }

    protected void doneCleanupSubscriptions() {

        if (this.listeningSubscriptionMaster != null) {
            try {
                this.listeningSubscriptionMaster.stopListening();
            } catch (NotificationImplementationException e) {

                if (this.pr.enabled()) {

                    final String err = "Problem stopping notification listener: " + e.getMessage();

                    if (this.pr.useThis()) {
                        this.pr.errln(PrCodes.ANY_ERROR_CATCH_ALL, err);
                    } else if (this.pr.useLogging()) {
                        if (logger.isDebugEnabled()) {
                            logger.error(err, e);
                        } else {
                            logger.error(err);
                        }
                    }
                }
            }
        }

        if (this.pollingSubscriptionMaster != null) {
            this.pollingSubscriptionMaster.stopPolling();
        }
    }

}