org.tango.server.lock.ClientLocking Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of JTangoServer Show documentation
Show all versions of JTangoServer Show documentation
Library for Tango Server (ie. Tango Device) in Java
/**
* 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.lock;
import java.util.Arrays;
import org.apache.commons.lang3.ArrayUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.tango.client.database.DatabaseFactory;
import org.tango.orb.ServerRequestInterceptor;
import org.tango.server.Chronometer;
import org.tango.server.ExceptionMessages;
import org.tango.server.servant.DeviceImpl;
import org.tango.utils.ClientIDUtil;
import org.tango.utils.DevFailedUtils;
import fr.esrf.Tango.ClntIdent;
import fr.esrf.Tango.DevFailed;
import fr.esrf.Tango.DevVarLongStringArray;
import fr.esrf.Tango.LockerLanguage;
import fr.esrf.TangoApi.DeviceData;
import fr.esrf.TangoApi.DeviceProxy;
/**
* Manage device locking with client request
*
* @author ABEILLE
*
*/
public final class ClientLocking {
private static final int _6 = 6;
private static final int _3 = 3;
private final Logger logger = LoggerFactory.getLogger(ClientLocking.class);
private final String deviceName;
/**
* Used for locking device from client
*/
private final Chronometer clientLockChrono = new Chronometer();
private ClntIdent clientIdentityLock = new ClntIdent();
private ClntIdent previousLocker = new ClntIdent();
private String lockerHost = "";
private int lockDuration;
private boolean hasBeenForced = false;
private String[] allowedCommands = new String[0];
/**
* Use for the tango concept of "Re-entrant lock". Unlock must be called several times if locked several times!
*/
private int lockingCounter;
public ClientLocking(final String deviceName, final String className) {
this.deviceName = deviceName;
lockingCounter = 0;
hasBeenForced = false;
// get command that cannot be locked
try {
final String access = DatabaseFactory.getDatabase().getAccessDeviceName();
if (!access.isEmpty()) {
final DeviceData in = new DeviceData();
in.insert(className);
allowedCommands = new DeviceProxy(access).command_inout("GetAllowedCommands", in).extractStringArray();
}
} catch (final DevFailed e) {
logger.error("failed to retrieve tango access control - {}", DevFailedUtils.toString(e));
}
}
public void init() {
lockingCounter = 0;
}
public void relock() throws DevFailed {
unLock(false);
lock(lockDuration, clientIdentityLock, lockerHost);
}
public void lock(final int validity, final ClntIdent clientIdentity, final String hostName) throws DevFailed {
logger.debug("locking for client {}- {}", hostName, ClientIDUtil.toString(clientIdentity));
clientIdentityLock = clientIdentity;
lockerHost = hostName;
lockDuration = validity;
clientLockChrono.start(validity * 1000);
lockingCounter++;
}
public void unLock(final boolean isForced) {
if (isForced) {
lockingCounter = 0;
hasBeenForced = true;
previousLocker = clientIdentityLock;
} else {
hasBeenForced = false;
if (lockingCounter > 0) {
lockingCounter--;
}
}
if (lockingCounter == 0) {
clientLockChrono.stop();
}
}
public boolean isOver() {
final boolean isOver = clientLockChrono.isOver();
if (lockingCounter > 0 && isOver) {
lockingCounter--;
}
return isOver;
}
/**
*
* @param clIdent
* @param names
* @throws DevFailed
*/
public void checkClientLocking(final ClntIdent clIdent, final String... names) throws DevFailed {
logger.debug("check for client {} - {}", ServerRequestInterceptor.getInstance().getGiopHostAddress(),
ClientIDUtil.toString(clIdent));
boolean doCheck = true;
for (final String name : names) {
if (ArrayUtils.contains(allowedCommands, name)) {
doCheck = false;
break;
}
}
if (doCheck && !ArrayUtils.contains(names, DeviceImpl.STATE_NAME)
&& !ArrayUtils.contains(names, DeviceImpl.STATUS_NAME)) {
// not locked for state and status
if (!clientLockChrono.isOver()
&& !lockerHost.equalsIgnoreCase(ServerRequestInterceptor.getInstance().getGiopHostAddress())
&& !ClientIDUtil.clientIdentEqual(clIdent, clientIdentityLock)) {
// device is locked
DevFailedUtils.throwDevFailed(ExceptionMessages.DEVICE_LOCKED, "device is locked by " + lockerHost
+ "- " + ClientIDUtil.toString(clIdent));
} else if (hasBeenForced && ClientIDUtil.clientIdentEqual(clIdent, previousLocker)) {
// if was unlock by client
hasBeenForced = false;
// lockingCounter = 0;
DevFailedUtils.throwDevFailed(ExceptionMessages.DEVICE_UNLOCKED, "device unlock was forced");
}
}
}
public DevVarLongStringArray getLockStatus() {
// The strings contain:
// 1 - The locker process hostname(like giop:tcp:[::ffff:172.28.1.114]:1897)
// 2 - The java main class (in case of Java locker)
// 0 - A string which summarizes the locking status
// The longs contain:
// 1 - A locked flag (0 means not locked, 1 means locked)
// 2 - The locker process PID (C++ client)
// 3 - The locker UUID (Java client) which needs 4 longs
final String[] strings = new String[_3];
final int[] longs = new int[_6];
if (!clientLockChrono.isOver()) {
strings[1] = lockerHost;
longs[0] = 1;
strings[0] = "Device " + deviceName + " is locked by " + lockerHost;
if (clientIdentityLock.discriminator().equals(LockerLanguage.CPP)) {
strings[2] = "Not defined";
longs[1] = clientIdentityLock.cpp_clnt();
for (int i = 2; i < longs.length; i++) {
longs[i] = 0;
}
} else {
strings[2] = clientIdentityLock.java_clnt().MainClass;
longs[1] = 0;
for (int i = 0; i < clientIdentityLock.java_clnt().uuid.length; i++) {
longs[i + 2] = (int) clientIdentityLock.java_clnt().uuid[i];
}
}
} else {
// strings[0] = "Not defined";
strings[0] = "Device " + deviceName + " is not locked";
strings[1] = "Not defined";
strings[2] = "Not defined";
Arrays.fill(longs, 0);
}
return new DevVarLongStringArray(longs, strings);
}
public boolean isHasBeenForced() {
return hasBeenForced;
}
}