📄 solutionlocktn.java
字号:
package org.trinet.jasi.TN;
import org.trinet.jasi.*;
import java.util.*;
import java.sql.*;
import org.trinet.jdbc.*;
import org.trinet.jdbc.datatypes.*;
import org.trinet.jdbc.table.*;
import org.trinet.util.*;
/**
* TriNet concrete implementation of SolutionLock. The dbase table that manages
* event locks is called JasiEventLock. The TriNet Oracle table definition is (see
* /home/tpp/src/eventlock):<br>
<tt>
create table JasiEventLock
(evid number NOT NULL,
hostname varchar2(40),
application varchar2(20),
username varchar2(20),
lddate date,
primary key (evid)
);
</tt>
<p>
Note that however you implement this locking scheme ALL potential users of the
common dataset must share the same locking "table" to insure that conflicts will
be managed. Because the common data is in the dbase the most obvious way to
insure this is to use a dbase table for locking. This is really a crude form of
persistent interprocess communication.<p>
Because this scheme does not use DBMS locking its success requires that all
applications that update data use this class and play by the rules. If an
application does not use this class there is no way to prevent data conflicts.<p>
Oracle row and table locking mechanisms could not be used for this task. There
were too many dependencies in the schema. Locking an event row had unexpected results
like doing a table lock and preventing anyone from writing to the dbase.
*/
/*
########################################################
Yikes! This will NOT prevent multiple instances of the same application/user/host
from accessing the same event.
Possible fixes:
1) use PID (can't see it from java)
2) use a random number (would need to add a field to the JasiEventLock table,
but I'm not sure how that would affect the replication.)
########################################################
*/
public class SolutionLockTN extends SolutionLock {
static final String ColumnNames = "EVID, HOSTNAME, APPLICATION, USERNAME, LDDATE";
/** Name of the table that manages event locks. */
static final String TableName = "JasiEventLock";
boolean debug = false;
// boolean debug = true;
/** */
public SolutionLockTN() {
// Don't do this at instantiation! If you do it will poke the dbase EVERY time
// a solution is created. Instead, check it each time a DataSource connection
// is made and set the static value of lockingWorks
// checkLockingWorks(); // force check of lock support
//long ran = (long) (Math.random()* 1000000.0);
}
/** This does not lock the solution but gets any lock info that exists for the solution. */
public SolutionLockTN(Solution sol) {
this();
setSolution(sol);
}
/** Returns true if locking is supported. */
public boolean isSupported () {
return lockingWorks;
}
/** Pokes the dbase to see if locking is supported. Sets the static flag
* 'lockingWorks' to proper value. */
public boolean checkLockingWorks () {
if (DataSource.getConnection() == null) {
// debug
if (debug) System.out.println ( "Connection == null");
lockingWorks = false;
return lockingWorks;
}
/* this doesn't work as expected
if (DataSource.isReadOnly()) {
// debug
if (debug) System.out.println ( "Dbase is read-only.");
lockingWorks = false;
return lockingWorks;
}
*/
// Try it: By attempting to lock a random event
//String sql = "select count(*) from "+ TableName;
//if (debug) System.out.println ( "check sql= "+sql);
// must set 'lockingWorks' true for doSQL to attempt the dbase query
int id = (int) Math.random() * 100;
lockingWorks = true;
setSolution(id);
if (lock()) {
unlock();
} else {
lockingWorks = false;
}
if (debug) System.out.println ( "lockingWorks = "+lockingWorks);
return lockingWorks;
}
/** Lock the object, returns true on success, false on failure.
* Either way, information on the current lock holder is set in the data members. */
public boolean lock () {
if (!lockingWorks) return true; // default behavior if no locking
String sql = "insert into "+ TableName +
" values (" + id + ", "+
"'"+requestorHost+"',"+
"'"+requestorApplication+"',"+
"'"+requestorUsername+"',"+
" SYSDATE)";
if (debug) System.out.println ( "lock sql= "+sql);
// Note: this is non-atomic so theres a slight potential here for someone else to grag
// the lock between when we check and when we request it.
if ( isLocked() ) return false; // someone else has the lock
boolean status = doSQL(sql);
if (status) { // we got a new lock
// the only way to get complete info about the lock old or new
// (especially the SYSTIME) is to retreive it from the dbase.
ArrayList list = (ArrayList) getLockInfo(id);
copyLockInfo((SolutionLock) list.get(0));
return true;
} else { // problem
return false;
}
}
private void copyLockInfo (SolutionLock locktoCopy) {
host = locktoCopy.host;
application = locktoCopy.application;
username = locktoCopy.getUsername();
datetime = locktoCopy.datetime;
}
/** Release the lock on this object. Returns true even if the lock was not held
* in the first place. */
public boolean unlock () {
if (!lockingWorks) return true; // default behavior if no locking
String sql = "Delete from "+ TableName + " where evid = "+id;
if (debug) System.out.println ( "delete sql= "+sql);
return doSQL(sql);
}
/** Returns true if the object is locked by anyone, the caller included. */
public boolean isLocked () {
if (!lockingWorks) return true; // default behavior if no locking
ArrayList list = (ArrayList) getLockInfo(id);
if (list == null || list.isEmpty()) return false;
copyLockInfo((SolutionLock) list.get(0));
return true;
}
/** Returns true if the object is locked by the caller. */
public boolean lockIsMine () {
if (!lockingWorks) return true; // default behavior if no locking
ArrayList list = (ArrayList) getLockInfo(id);
for (int i = 0; i>list.size();i++) {
if ( ((SolutionLock)list.get(i)).matches() ) {
return true;
}
}
return false;
}
/** Return an array of SolutionLock objects that represent ALL currently
* held locks on all events. */
public Collection getAllLocks () {
String sql = "Select "+ColumnNames+" from "+ TableName +
" order by lddate";
return getBySQL(sql);
}
/** Return an array of SolutionLock objects that represent ALL locks currently
* held by this user. */
public Collection getLocksByUser(String username) {
String sql = "Select "+ColumnNames+" from "+ TableName + " where "+
" username = '"+username+"' order by lddate";
return getBySQL(sql);
}
/** Return an array of SolutionLock objects that represent ALL locks currently
* held by this host. */
public Collection getLocksByHost(String host) {
String sql = "Select "+ColumnNames+" from "+ TableName + " where "+
" hostname = '"+host+"' order by lddate";
return getBySQL(sql);
}
/** Return an array of SolutionLock objects that represent ALL locks currently
* held by this application. */
public Collection getLocksByApplication(String application) {
String sql = "Select "+ColumnNames+" from "+ TableName + " where "+
" application = '"+application+"'";
return getBySQL(sql);
}
/** Return an array of SolutionLock objects that represent ALL locks currently
* held by this host/user/application. */
public Collection getAllMyLocks() {
String sql = "Select "+ColumnNames+" from "+ TableName + " where "+
" hostname = '"+requestorHost+"' and '"+
" username = '"+requestorUsername+"' and '"+
" application = '"+requestorApplication+"'";
return getBySQL(sql);
}
/** Unlock ALL currently held locks on all events. This simply deletes all rows
in the lock table. */
public boolean unlockAll() {
if (!lockingWorks) return true; // default behavior if no locking
String sql = "Delete from " + TableName;
return doSQL(sql);
}
/** Release ALL locks currently held by this host/user/application. */
public boolean unlockAllMyLocks() {
if (!lockingWorks) return true; // default behavior if no locking
String sql = "Delete from "+ TableName + " where "+
" hostname = '"+requestorHost+"' and "+
" username = '"+requestorUsername+"' and "+
" application = '"+requestorApplication+"'";
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -