All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.tango.server.ServerManager Maven / Gradle / Ivy

There is a newer version: 10.0.0
Show newest version
/**
 * Copyright (C) :     2012
 *
 * 	Synchrotron Soleil
 * 	L'Orme des merisiers
 * 	Saint Aubin
 * 	BP48
 * 	91192 GIF-SUR-YVETTE CEDEX
 *
 * This file is part of Tango.
 *
 * Tango is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Tango 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 Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with Tango.  If not, see .
 */
package org.tango.server;

import java.io.File;
import java.lang.management.ManagementFactory;
import java.lang.management.RuntimeMXBean;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicBoolean;

import org.apache.commons.lang3.ArrayUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.MDC;
import org.slf4j.ext.XLogger;
import org.slf4j.ext.XLoggerFactory;
import org.tango.client.database.DatabaseFactory;
import org.tango.logging.LoggingManager;
import org.tango.orb.ORBManager;
import org.tango.server.annotation.Device;
import org.tango.server.annotation.TransactionType;
import org.tango.server.cache.TangoCacheManager;
import org.tango.server.events.EventManager;
import org.tango.server.export.TangoExporter;
import org.tango.server.monitoring.MonitoringService;
import org.tango.utils.DevFailedUtils;

import fr.esrf.Tango.DevFailed;

/**
 * Manage a tango server.
 *
 * @author ABEILLE
 *
 */
public final class ServerManager {
    public static final String SERVER_NAME_LOGGING = "serverName";
    private static final String NODB = "-nodb";
    /**
     * maximun length for device server name (255 characters)
     */
    public static final int SERVER_NAME_MAX_LENGTH = 255;
    private static final String INIT_ERROR = "INIT_ERROR";
    private final Logger logger = LoggerFactory.getLogger(ServerManager.class);
    private final XLogger xlogger = XLoggerFactory.getXLogger(ServerManager.class);
    private boolean useDb;
    private final AtomicBoolean isStarted = new AtomicBoolean();

    private static final ServerManager INSTANCE = new ServerManager();
    /**
     * The name of the executable
     */
    private String execName;
    /**
     * The name of the instance
     */
    private String instanceName;
    /**
     * execName/instanceName
     */
    private String serverName;
    private String hostName;
    private String pid = "0";

    private final Map> tangoClasses = new LinkedHashMap>();

    private TangoExporter tangoExporter;
    private String lastClass;
    private TransactionType transactionType;
    private MonitoringService monitoring;

    private ServerManager() {
        Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
            /**
             * shutdown hook
             */
            @Override
            public void run() {
                MDC.put(SERVER_NAME_LOGGING, serverName);
                logger.debug("Shutdown hook unregister " + serverName);
                try {
                    ServerManager.getInstance().stop();
                } catch (final DevFailed e) {
                }
            }
        }));
    }

    /**
     * Get a ServerManager
     *
     * @return the server manager
     */
    public static ServerManager getInstance() {
        return INSTANCE;
    }

    /**
     * Add a class to the server.
     *
     * @param tangoClass
     *            The class name as defined in the tango database
     * @param deviceClass
     *            The class that define a device with {@link Device}
     */
    public void addClass(final String tangoClass, final Class deviceClass) {
        lastClass = tangoClass;
        tangoClasses.put(tangoClass, deviceClass);
    }

    public void startDevice(final String deviceName, final Class deviceClass) throws DevFailed {
        if (!isStarted.get()) {
            throw DevFailedUtils.newDevFailed("the server must be started");
        }
        if (tangoExporter != null) {
            if (tangoClasses.containsValue(deviceClass)) {
                tangoExporter.buildDevice(deviceName, deviceClass);
            }
        }
    }

    public void stopDevice(final String deviceName) throws DevFailed {
        if (!isStarted.get()) {
            throw DevFailedUtils.newDevFailed("the server must be started");
        }
        if (tangoExporter != null) {
            tangoExporter.unexportDevice(deviceName);
        }
    }

    /**
     * Starts a Tango server. The system property TANGO_HOST is mandatory if
     * using the tango database. If the tango db is not used, the system
     * property OAPort(for jacorb) must be set. The errors occurred will be only
     * logged.
     *
     * 
     * ServerManager.getInstance().addClass(JTangoTest.class.getCanonicalName(), JTangoTest.class);
     * ServerManager.getInstance().start(new String[] { "1" }, "JTangoTest");
     * 
* * @param args * The arguments to pass. instanceName [-v[trace level]] [-nodb * [-dlist ]] * @param execName * The name of the server as defined by Tango. * @see ServerManager#addClass(String, Class) */ public synchronized void start(final String[] args, final String execName) { if (!isStarted.get()) { try { init(args, execName); } catch (final DevFailed e) { DevFailedUtils.printDevFailed(e); } } } /** * Idem as start but throw exceptions. @see ServerManager#start(String[], * String) * * @param args * @param execName * @throws DevFailed */ public synchronized void startError(final String[] args, final String execName) throws DevFailed { if (isStarted.get()) { throw DevFailedUtils.newDevFailed("this server is already started"); } init(args, execName); } /** * Starts a Tango server. The system property TANGO_HOST is mandatory if * using the tango database. If the tango db is not used the system property * OAPort(for jacorb) must be set. The errors occurred will be only logged. * *
     * ServerManager.getInstance().start(new String[] { "1" }, JTangoTest.class);
     * 
* * @param args * The arguments to pass. instanceName [-v[trace level]] [-nodb * [-dlist ]] * @param deviceClass * The class of the device. The server name and class name must * be defined in tango db with deviceClass.getSimpleName to be * started with this method. * @see ServerManager#addClass(String, Class) */ public synchronized void start(final String[] args, final Class deviceClass) { if (!isStarted.get()) { addClass(deviceClass.getSimpleName(), deviceClass); try { init(args, deviceClass.getSimpleName()); } catch (final DevFailed e) { DevFailedUtils.printDevFailed(e); } } } private void init(final String[] args, final String execName) throws DevFailed { xlogger.entry(); // assume SLF4J is bound to logback in the current environment // final LoggerContext lc = (LoggerContext) // LoggerFactory.getILoggerFactory(); // // print logback's internal status // StatusPrinter.print(lc); // a server does not need graphics System.setProperty("java.awt.headless", "true"); this.execName = execName; // Manage command line option checkArgs(args); serverName = this.execName + "/" + instanceName; MDC.put(SERVER_NAME_LOGGING, serverName); logger.debug("Starting server {}", serverName); final StringBuilder tmp = new StringBuilder(serverName); // Check that the server name is not too long if (tmp.length() > SERVER_NAME_MAX_LENGTH) { throw DevFailedUtils.newDevFailed(INIT_ERROR, "The device server name is too long! Max length is " + SERVER_NAME_MAX_LENGTH + " characters."); } isStarted.set(true); initPIDAndHostName(); final String toBeImported = Constants.ADMIN_DEVICE_DOMAIN + "/" + serverName; ORBManager.init(useDb, toBeImported); tangoExporter = new TangoExporter(hostName, serverName, pid, tangoClasses); tangoExporter.exportAll(); // start tango monitoring monitoring = new MonitoringService(serverName); monitoring.start(); logger.info("TANGO server {} started", serverName); // start the ORB ORBManager.startDetached(); xlogger.exit(); } /** * Stop the server and clear all * * @throws DevFailed */ public void stop() throws DevFailed { try { if (isStarted.get()) { tangoClasses.clear(); if (tangoExporter != null) { tangoExporter.clearClass(); tangoExporter.unexportAll(); } TangoCacheManager.shutdown(); EventManager.getInstance().close(); if (monitoring != null) { monitoring.stop(); } } } finally { ORBManager.shutdown(); logger.info("everything has been shutdown normally"); isStarted.set(false); } } /** * Get main argurments * * @return The usage */ private String getUsage() { return "usage : java -DTANGO_HOST=$TANGO_HOST " + execName + " instance_name [-v[trace level]] [-nodb [-dlist ] [-file=fileName]]"; } /** * Check the command line arguments. The first one is mandatory and is the * server name. A -v option is authorized with an optional argument. * * @param argv * @throws DevFailed */ private void checkArgs(final String[] argv) throws DevFailed { if (argv.length < 1) { throw DevFailedUtils.newDevFailed(INIT_ERROR, getUsage()); } instanceName = argv[0]; useDb = true; DatabaseFactory.setUseDb(true); List noDbDevices = new ArrayList(); for (int i = 1; i < argv.length; i++) { final String arg = argv[i]; if (arg.startsWith("-h")) { // trace instance name System.out.println("instance list for server " + execName + ": " + Arrays.toString(DatabaseFactory.getDatabase().getInstanceNameList(execName))); } else if (arg.startsWith("-v")) { // logging level try { final int level = Integer.parseInt(arg.substring(arg.lastIndexOf('v') + 1)); LoggingManager.getInstance().setLoggingLevel(level, tangoClasses.values().toArray(new Class[0])); } catch (final NumberFormatException e) { throw DevFailedUtils.newDevFailed("Logging level error. Must be a number"); } } else if (arg.startsWith("-dlist")) { noDbDevices = configureNoDB(argv, i); useDb = false; } else if (arg.startsWith("-file")) { configureNoDBFile(argv, arg, noDbDevices); useDb = false; } } } /** * Configure {@link DatabaseFactory} without a tango db * * @param argv * @param currentIdx * @return The list of no db devices * @throws DevFailed */ private List configureNoDB(final String argv[], final int currentIdx) throws DevFailed { final List noDbDevices = new ArrayList(); if (!ArrayUtils.contains(argv, NODB)) { throw DevFailedUtils.newDevFailed(INIT_ERROR, getUsage()); } else { for (int j = currentIdx + 1; j < argv.length; j++) { if (!argv[j].startsWith("-")) { // several devices separated by commons final String[] devices = argv[j].split(","); if (devices.length > 1) { Collections.addAll(noDbDevices, devices); } else { noDbDevices.add(argv[j]); } logger.warn("Device with no db: " + argv[j]); } else { break; } } // only one class can be loaded with no db (the last one) DatabaseFactory.setNoDbDevices(noDbDevices.toArray(new String[0]), lastClass); } return noDbDevices; } /** * Configure {@link DatabaseFactory} without a tango db and a file for * properties * * @param argv * @param arg * @param noDbDevices * @throws DevFailed */ private void configureNoDBFile(final String argv[], final String arg, final List noDbDevices) throws DevFailed { if (!ArrayUtils.contains(argv, NODB)) { throw DevFailedUtils.newDevFailed(INIT_ERROR, getUsage()); } else { final String name = arg.split("=")[1]; final File file = new File(name); if (!file.exists() && !file.isFile()) { throw DevFailedUtils.newDevFailed(INIT_ERROR, name + " does not exists or is not a file"); } logger.warn("Tango Database is not used - with file {} ", file.getPath()); DatabaseFactory.setDbFile(file, noDbDevices.toArray(new String[0]), lastClass); } } /** * Set the transaction type for all server. Overrides {@link Device#transactionType()} * * @param transactionType */ public void setTransactionType(final TransactionType transactionType) { this.transactionType = transactionType; } public TransactionType getTransactionType() { return transactionType; } /** * WARNING: it is jvm dependent (works for sun') * * @throws DevFailed */ private void initPIDAndHostName() throws DevFailed { final RuntimeMXBean rmxb = ManagementFactory.getRuntimeMXBean(); final String pidAndHost = rmxb.getName(); final String[] splitted = pidAndHost.split("@"); if (splitted.length > 1) { pid = splitted[0]; } try { final InetAddress addr; if (ORBManager.OAI_ADDR != null && !ORBManager.OAI_ADDR.isEmpty()) { addr = InetAddress.getByName(ORBManager.OAI_ADDR); } else { addr = InetAddress.getLocalHost(); } hostName = addr.getCanonicalHostName(); } catch (final UnknownHostException e) { throw DevFailedUtils.newDevFailed(e); } logger.debug("pid: " + pid); logger.debug("hostName: " + hostName); } /** * The host on which this server is running * * @return the host name */ public String getHostName() { return hostName; } /** * The pid of this server * * @return the pid */ public String getPid() { return pid; } /** * execName/instanceName * * @return execName/instanceName */ public String getExecName() { return execName; } /** * The instance name * * @return The instance name */ public String getInstanceName() { return instanceName; } /** * The server name * * @return The server name */ public String getServerName() { return serverName; } /** * Get the started devices of this server. WARNING: result is filled after * server has been started * * @param tangoClass * @return The devices * @throws DevFailed */ public String[] getDevicesOfClass(final String tangoClass) throws DevFailed { return tangoExporter.getDevicesOfClass(tangoClass); } public String getAdminDeviceName() { return Constants.ADMIN_DEVICE_DOMAIN + "/" + serverName; } /** * * @return true is the server is running */ public boolean isStarted() { return isStarted.get(); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy