
fr.esrf.TangoApi.DevLockManager Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of JTangoCommons Show documentation
Show all versions of JTangoCommons Show documentation
Common classes for tango java API
//+======================================================================
// $Source$
//
// Project: Tango
//
// Description: java source code for the TANGO client/server API.
//
// $Author: pascal_verdier $
//
// Copyright (C) : 2004,2005,2006,2007,2008,2009,2010,2011,2012,2013,2014,
// European Synchrotron Radiation Facility
// BP 220, Grenoble 38043
// FRANCE
//
// 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 .
//
// $Revision: $
//
//-======================================================================
package fr.esrf.TangoApi;
/**
* This class is able to to generate a UUID and
* retreive the main class of this JVM to
* identify the client to use the device lock features.
* It also manage a thread class for all admin devices needed
* to relock devices.
*
* @author verdier
*/
//import java.lang.management.ManagementFactory;
//import java.lang.management.RuntimeMXBean;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.UUID;
import java.util.Vector;
import fr.esrf.Tango.ClntIdent;
import fr.esrf.Tango.DevError;
import fr.esrf.Tango.DevFailed;
import fr.esrf.Tango.DevVarLongStringArray;
import fr.esrf.Tango.JavaClntIdent;
import fr.esrf.TangoDs.Except;
import fr.esrf.TangoDs.TangoConst;
class DevLockManager {
static private DevLockManager instance = null;
static private UUID uuid;
static private long[] l_uuid;
static private String mainClass = null;
static private String host_add = null;
static private JavaClntIdent j_ident;
static private ClntIdent ident;
private static String strPID = null;
// java.lang.management.ManagementFactory and
// java.lang.management.RuntimeMXBean
// Not available on Android JVM
static private boolean hasManagementClasses = true;
// ===============================================================
// ===============================================================
static {
// Check if java.lang.management classes can be loaded
try {
//noinspection UnusedDeclaration
Class c = java.lang.management.ManagementFactory.class;
}
catch (Exception e) {
hasManagementClasses = false; // Not available
}
catch (Error e) {
hasManagementClasses = false; // Not available
}
}
// ===============================================================
/**
* Returns instance of the Object.
* @return instance of the Object.
*/
// ===============================================================
static DevLockManager getInstance() {
if (instance == null) {
instance = new DevLockManager();
}
return instance;
}
// ===============================================================
/**
* The object constrauctor
*/
// ===============================================================
private DevLockManager() {
uuid = UUID.randomUUID();
l_uuid = new long[2];
l_uuid[0] = uuid.getMostSignificantBits();
l_uuid[1] = uuid.getLeastSignificantBits();
// Try to get Process ID
if (hasManagementClasses) {
// Do it only if class available
final java.lang.management.RuntimeMXBean mx =
java.lang.management.ManagementFactory.getRuntimeMXBean();
final String str = mx.getName();
final int pos = str.indexOf('@');
if (pos > 0) {
strPID = str.substring(0, pos);
}
}
// Get stack to find main class
final StackTraceElement[] trace = Thread.currentThread().getStackTrace();
// Search main method
final String tag = ".main";
final String s = trace[trace.length - 1].toString();
final int idx = s.indexOf(tag);
if (idx > 0) {
// Main class found
mainClass = s.substring(0, idx);
if (strPID != null) {
mainClass += " - PID=" + strPID;
}
} else if (strPID != null) {
// Not found, set with PID
mainClass = "PID=" + strPID;
} else {
// Main class and pid not found,
// put the highest info in stack
mainClass = s.substring(s.lastIndexOf('('));
}
j_ident = new JavaClntIdent(mainClass, l_uuid);
ident = new ClntIdent();
ident.java_clnt(j_ident);
try {
host_add = java.net.InetAddress.getLocalHost().getHostAddress();
} catch (final java.net.UnknownHostException e) {
// Do nothing
}
}
// ===============================================================
//
// Client identification management
//
// ===============================================================
// ===============================================================
/**
*
* @return the JVM process ID if found, -1 otherwise.
*/
// ===============================================================
public int getJvmPid() {
int pid = -1;
if (strPID !=null) {
try {
pid = Integer.parseInt(strPID);
}
catch (NumberFormatException e) {/* */ }
}
return pid;
}
// ===============================================================
/**
* @return the java client identifier object
*/
// ===============================================================
@SuppressWarnings("UnusedDeclaration")
JavaClntIdent getJavaClntIdent() {
return j_ident;
}
// ===============================================================
/**
* @return the IDL client identifier object
*/
// ===============================================================
ClntIdent getClntIdent() {
return ident;
}
// ===============================================================
// ===============================================================
String getMainClass() {
return mainClass;
}
// ===============================================================
// ===============================================================
String getHost() {
return host_add;
}
// ===============================================================
// ===============================================================
UUID getUUID() {
return uuid;
}
// ===============================================================
// ===============================================================
@Override
public String toString() {
String str = mainClass + ":\n";
for (final long an_uuid : l_uuid) {
str += an_uuid + "\n";
}
return str.trim();
}
// ===============================================================
// ===============================================================
// ===============================================================
//
// Device access management
//
// ===============================================================
// ==========================================================================
/**
* Lock the device
*
* @param validity Lock validity (in seconds)
*/
// ==========================================================================
void lock(final DeviceProxy deviceProxy, final int validity) throws DevFailed {
deviceProxy.import_admin_device("lock");
final DevVarLongStringArray lsa = new DevVarLongStringArray();
lsa.svalue = new String[1];
lsa.lvalue = new int[1];
lsa.svalue[0] = deviceProxy.get_name();
lsa.lvalue[0] = validity;
final DeviceData argin = new DeviceData();
argin.insert(lsa);
deviceProxy.getAdm_dev().command_inout("LockDevice", argin);
addToRelockList(deviceProxy, validity);
}
// ==========================================================================
/**
* Unlock the device
*/
// ==========================================================================
int unlock(final DeviceProxy deviceProxy) throws DevFailed {
deviceProxy.import_admin_device("unlock");
final DevVarLongStringArray lsa = new DevVarLongStringArray();
lsa.svalue = new String[1];
lsa.lvalue = new int[1];
lsa.svalue[0] = deviceProxy.get_name();
lsa.lvalue[0] = 0; // Do not force
final DeviceData argin = new DeviceData();
argin.insert(lsa);
final DeviceData argout = deviceProxy.getAdm_dev().command_inout("UnlockDevice", argin);
// Check lock counter for the device itself (not the proxy)
final int nb = argout.extractLong();
if (nb == 0) {
removeToRelockList(deviceProxy);
}
return nb;
}
// ==========================================================================
/**
* Returns true if the device is locked
*/
// ==========================================================================
boolean isLocked(final DeviceProxy deviceProxy) throws DevFailed {
final LockerInfo info = getLockerInfo(deviceProxy);
return info.isLocked();
}
// ==========================================================================
/**
* Returns true if the device is locked by this process
*/
// ==========================================================================
boolean isLockedByMe(final DeviceProxy deviceProxy) throws DevFailed {
final LockerInfo info = getLockerInfo(deviceProxy);
return info.isMe();
}
// ==========================================================================
/**
* Returns the device lock status
*/
// ==========================================================================
String getLockerStatus(final DeviceProxy deviceProxy) throws DevFailed {
final LockerInfo info = getLockerInfo(deviceProxy);
return info.getStatus();
}
// ==========================================================================
/**
* Returns the device lock info
*/
// ==========================================================================
LockerInfo getLockerInfo(final DeviceProxy deviceProxy) throws DevFailed {
deviceProxy.import_admin_device("getLockerInfo");
final DeviceData argin = new DeviceData();
argin.insert(deviceProxy.get_name());
final DeviceData argout = deviceProxy.getAdm_dev().command_inout("DevLockStatus", argin);
return new LockerInfo(argout.extractLongStringArray());
}
// ==========================================================================
// ==========================================================================
// ===============================================================
//
// Relock vectors and threads management
//
// ===============================================================
private static Hashtable relockMap = null;
private static final long VALIDITY_DELAY = 500; // 500 ms before
// ===============================================================
// ===============================================================
void addToRelockList(final DeviceProxy dev, final int validity) throws DevFailed {
// Check if it is the first relock
if (relockMap == null) {
// Create hash table for admin devices object
relockMap = new Hashtable();
// Create a thread to unlock all devices at exit
Runtime.getRuntime().addShutdownHook(new ShutdownThread());
// Create thread fo garbage callector call preiodicaly
new GarbageThread().start();
}
// Check if admin device already exists.
String adm;
try {
adm = dev.adm_name();
} catch (final DevFailed e) {
// Give up
return;
}
final LockedDevice ld = new LockedDevice(dev.get_name(), validity);
LockedDeviceAmin lda;
if (!relockMap.containsKey(adm)) {
// if not, crate and add th the list
lda = new LockedDeviceAmin(adm, ld);
lda.start();
relockMap.put(adm, lda);
} else {
lda = relockMap.get(adm);
lda.add(ld);
}
}
// ===============================================================
// ===============================================================
void removeToRelockList(final DeviceProxy dev) {
// Check if admin device already exists.
String adm;
try {
adm = dev.adm_name();
} catch (final DevFailed e) {
// Give up
return;
}
if (relockMap.containsKey(adm)) {
final LockedDeviceAmin lda = relockMap.get(adm);
lda.remove(dev.get_name());
}
}
// ===============================================================
// ===============================================================
// ===============================================================
/**
* A thread to unlock all devices at exit
*/
// ===============================================================
private class ShutdownThread extends Thread {
@Override
public void run() {
System.out.println("exiting.....");
final Enumeration keys = relockMap.keys();
while (keys.hasMoreElements()) {
final String key = (String) keys.nextElement();
final LockedDeviceAmin lda = relockMap.get(key);
lda.cleanUp();
}
}
}
// ===============================================================
/**
* A thread to activate the garbage collector to do not re-lock the unsuded
* devices (finalize() will be called).
*/
// ===============================================================
private class GarbageThread extends Thread {
@Override
public void run() {
final long period = 1000 * TangoConst.DEFAULT_LOCK_VALIDITY - VALIDITY_DELAY;
// noinspection InfiniteLoopStatement
while (true) {
// Call GC only if any device to re lock
if (relockMap.size() > 0) {
System.gc();
}
try {
sleep(period);
} catch (final InterruptedException e) {
// Do nothing
}
}
}
}
// ===============================================================
/**
* Loccked device object to relocked periodicaly
*/
// ===============================================================
private class LockedDevice {
private final String name;
private final int validity;
// ===========================================================
LockedDevice(final String devname, final int valid) {
name = devname;
validity = valid;
}
}
// ===============================================================
/**
* One thread class for each admin device, to ReLock devices.
*/
// ===============================================================
private class LockedDeviceAmin extends Thread {
private DeviceProxy device = null;
private final String name;
private long t_relock;
private final Vector devices;
// ==========================================================
LockedDeviceAmin(final String name, final LockedDevice ld) throws DevFailed {
device = DeviceProxyFactory.get(name);
this.name = name;
devices = new Vector();
devices.add(ld);
t_relock = System.currentTimeMillis();
}
// ==========================================================
private void add(final LockedDevice ld_in) {
// Check if Already exists.
for (final LockedDevice ld_tmp : devices) {
if (ld_tmp.name.equals(ld_in.name)) {
return; // if yes -> do not relock more than once
}
}
devices.add(ld_in);
wakeUp();
}
// ==========================================================
private String[] getDeviceNames() {
final String[] array = new String[devices.size()];
for (int i = 0; i < devices.size(); i++) {
array[i] = devices.get(i).name;
}
return array;
}
// ==========================================================
private void remove(final String devname) {
for (int i = 0; i < devices.size(); i++) {
final LockedDevice ld = devices.get(i);
if (ld.name.equals(devname)) {
//System.out.println("------- >removing " + devname);
devices.remove(ld);
}
}
// If no device any more remove itself.
if (devices.size() == 0) {
relockMap.remove(name);
}
wakeUp();
}
// ==========================================================
private void cleanUp() {
// Unlock and remove all devices.
try {
final DevVarLongStringArray lsa = new DevVarLongStringArray();
lsa.svalue = new String[devices.size()];
for (int i = 0; i < devices.size(); i++) {
lsa.svalue[i] = devices.get(0).name;
}
lsa.lvalue = new int[1];
lsa.lvalue[0] = 1; // Forced
final DeviceData argin = new DeviceData();
argin.insert(lsa);
final DeviceProxy dev = DeviceProxyFactory.get(name);
dev.import_admin_device("CleanUp");
dev.getAdm_dev().command_inout("UnlockDevice", argin);
System.out.println("all devices unlocked.");
} catch (final DevFailed e) {
Except.print_exception(e);
}
}
// ===========================================================
/*
* Compute the minimum value to sleep for all devices
*/
// ==========================================================
private int getMinValidity() {
int min = 0xFFFFFFF;
for (final LockedDevice dev : devices) {
if (min > dev.validity) {
min = dev.validity;
}
}
if (min == 0xFFFFFFF) {
min = 1;
}
return min;
}
// ===========================================================
private void traceRelock(final String[] devnames) {
System.out.print(name + ": RelockDevices for ");
for (final String devname : devnames) {
System.out.print(" " + devname);
}
System.out.println();
}
// ===========================================================
private void relock() {
final String[] devnames = getDeviceNames();
traceRelock(devnames);
try {
final DeviceData argin = new DeviceData();
argin.insert(devnames);
device.command_inout("RelockDevices", argin);
} catch (final DevFailed e) {
// Check exception for special cases
for (final DevError error : e.errors) {
final String reason = error.reason;
if (reason.equals("TangoApi_DEVICE_NOT_EXPORTED")) {
// If admin device not exported,
// remove alle devices.
for (final String devname : devnames) {
remove(devname);
}
} else if (reason.equals("API_DeviceNotLocked") || // Server
// could
// have
// been
// restarted.
reason.equals("API_DeviceLocked")) // Another client
// has lokced (Is
// it possible
// ??)
{
// Parse for device name
final String desc = error.desc;
final int idx = desc.indexOf(':');
if (idx > 0) {
final String devname = desc.substring(0, idx).trim();
remove(devname);
}
}
}
}
}
// ==========================================================
private synchronized void wakeUp() {
notify();
}
// ===========================================================
private long getTimeToSleep() {
final long now = System.currentTimeMillis();
final int minValidity = getMinValidity() * 1000;
return minValidity - (now - t_relock) - VALIDITY_DELAY; // few ms
// before
}
// ===========================================================
private synchronized void waitNext() {
long t_sleep = getTimeToSleep();
while (t_sleep > VALIDITY_DELAY && devices.size() > 0) {
try { wait(t_sleep); } catch (final InterruptedException e) { /* */ }
t_sleep = getTimeToSleep();
}
}
// ===========================================================
@Override
public void run() {
while (devices.size() > 0) {
// RE lock will be done later
waitNext();
if (devices.size() > 0) {
relock();
t_relock = System.currentTimeMillis();
}
}
System.out.println("thread for " + name + " exiting....");
}
// ===========================================================
}
// ===============================================================
// ===============================================================
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy