/* * ProActive Parallel Suite(TM): * The Open Source library for parallel and distributed * Workflows & Scheduling, Orchestration, Cloud Automation * and Big Data Analysis on Enterprise Grids & Clouds. * * Copyright (c) 2007 - 2017 ActiveEon * Contact: contact@activeeon.com * * This library is free software: you can redistribute it and/or * modify it under the terms of the GNU Affero General Public License * as published by the Free Software Foundation: version 3 of * the License. * * 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 Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * * If needed, contact us to obtain a release under GPL Version 2 or 3 * or a different license than the AGPL. */ package org.ow2.proactive.jmx.provider.ro; import java.io.IOException; import java.net.MalformedURLException; import java.net.URI; import java.util.Collections; import java.util.Map; import javax.management.MBeanServer; import javax.management.remote.JMXConnectorServer; import javax.management.remote.JMXServiceURL; import org.objectweb.proactive.api.PARemoteObject; import org.objectweb.proactive.core.ProActiveException; import org.objectweb.proactive.core.remoteobject.RemoteObjectExposer; import org.ow2.proactive.jmx.provider.JMXProviderUtils; /** * <p>A JMX API connector server that creates Remote Object based connections * from remote clients. Usually, such connector servers are made * using {@link javax.management.remote.JMXConnectorServerFactory * JMXConnectorServerFactory}. However, specialized applications can * use this class directly, for example with an {@link ROServerImpl} * object.</p> * * @author The ProActive Team */ public final class ROConnectorServer extends JMXConnectorServer { private static final int CREATED = 0; private static final int STARTED = 1; private static final int STOPPED = 2; private int state = CREATED; private final JMXServiceURL address; private final Map<String, Object> env; private ROServerImpl roServerLocalRef; /** * Creates a ROConnectorServer * @param url The connector URL * @param environment the connector environment, i.e., the package location of the ServerProvider * @throws IOException */ public ROConnectorServer(final JMXServiceURL url, final Map<String, ?> environment) throws IOException { this(url, environment, (MBeanServer) null); } /** * Creates a ROConnectorServer * @param url The connector URL * @param environment the connector environment, i.e., the package location of the ServerProvider * @param mbeanServer the MBean server bound with the connector * @throws IOException */ public ROConnectorServer(final JMXServiceURL url, final Map<String, ?> environment, final MBeanServer mbeanServer) throws IOException { this(url, environment, (ROServerImpl) null, mbeanServer); } /** * Creates a ROConnectorServer * @param url The connector URL * @param environment the connector environment, i.e., the package location of the ServerProvider * @param roServer the Remote Object JMX Server * @param mbeanServer the MBean server bound with the connector * @throws IOException */ public ROConnectorServer(final JMXServiceURL url, final Map<String, ?> environment, final ROServerImpl roServer, final MBeanServer mbeanServer) throws IOException { super(mbeanServer); if (url == null) { throw new IllegalArgumentException("Null JMXService URL"); } this.address = url; if (environment == null) { this.env = Collections.emptyMap(); } else { this.env = Collections.unmodifiableMap(environment); } if (roServer == null) { final String prt = url.getProtocol(); if ((prt == null) || !(prt.equals(JMXProviderUtils.RO_PROTOCOL))) { throw new MalformedURLException("Invalid protocol type :" + prt); } } this.roServerLocalRef = roServer; } /** * Activates the connector server, that is starts listening for client connections. * Calling this method when the connector server is already active has no effect. * Calling this method when the connector server has been stopped will generate an IOException. * The behavior of this method when called for the first time depends on the parameters that were supplied at construction, as described below. * First, an object of a subclass of ROServerImpl is required, to export the connector server through Remote Objects: * If an ROServerImpl was supplied to the constructor, it is used. */ public synchronized void start() throws IOException { if (this.state == STARTED) { return; } else if (this.state == STOPPED) { throw new IOException("This connector server has been stopped"); } // Check if the connector server is attached to an MBean server final MBeanServer mbs = getMBeanServer(); if (mbs == null) { throw new IllegalStateException("This connector server is not attached with a mbean server"); } // Create an instance the server if (this.roServerLocalRef == null) { this.roServerLocalRef = new ROServerImpl(mbs, this.env); } // Extract the URI from the current address final URI uri = JMXProviderUtils.extractURI(this.address); try { // Use the exposer of the created server to expose it as a remote object final RemoteObjectExposer<ROServerImpl> roe = this.roServerLocalRef.getRemoteObjectExposer(); // Bind under the correct uri PARemoteObject.bind(roe, uri); } catch (ProActiveException e) { throw JMXProviderUtils.newIOException("Failed to create the Remote Object JMX Server " + this.address.getURLPath(), e); } this.state = STARTED; } /** * Deactivates the connector server, that is, stops listening for client connections. * Calling this method will also close all client connections that were made by this server. * After this method returns, whether normally or with an exception, the connector server will not create any new client connections. * Once a connector server has been stopped, it cannot be started again. * Calling this method when the connector server has already been stopped has no effect. * Calling this method when the connector server has not yet been started will disable the connector server object permanently. * If closing a client connection produces an exception, that exception is not thrown from this method. * A JMXConnectionNotification is emitted from this MBean with the connection ID of the connection that could not be closed. * Closing a connector server is a potentially slow operation. For example, if a client machine with an open connection has crashed, the close operation might have to wait for a network protocol timeout. * Callers that do not want to block in a close operation should do it in a separate thread. */ public synchronized void stop() throws IOException { if (this.state == STOPPED) { // Already stopped return; } this.state = STOPPED; // Close the server if (this.roServerLocalRef != null) { this.roServerLocalRef.close(); // TODO: Make the close method to emit close notif this.roServerLocalRef = null; } } /** * Determines whether the connector server is active. * A connector server starts being active when its start method returns successfully and remains active * until either its stop method is called or the connector server fails. */ public boolean isActive() { return this.state == STARTED; } /** * The address of this connector server. */ public JMXServiceURL getAddress() { return this.address; } /** * Returns the attributes of this connector. */ public Map<String, Object> getAttributes() { return this.env; } }