/* $Id: ServerData.java,v 1.20 2005/06/10 18:03:03 kleiner Exp $
This file is part of HBCI4Java
Copyright (C) 2001-2005 Stefan Palme
HBCI4Java is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
HBCI4Java 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package org.kapott.hbci.server;
import java.io.InputStream;
import java.lang.reflect.Constructor;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.List;
import java.util.Properties;
import java.util.Random;
import org.kapott.hbci.exceptions.HBCI_Exception;
import org.kapott.hbci.manager.HBCIKey;
import org.kapott.hbci.manager.HBCIUtils;
import org.kapott.hbci.manager.HBCIUtilsInternal;
import org.kapott.hbci.manager.MsgGen;
import org.kapott.hbci.passport.HBCIPassportInternal;
import org.kapott.hbci.server.datastore.DataStore;
import org.kapott.hbci.server.listener.ConnectionListener;
import org.kapott.hbci.structures.Konto;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
public class ServerData
{
private static ServerData _instance;
private DataStore dataStore;
private Hashtable msggens;
private Random random;
private ServerCallback callback;
private List listeners;
private boolean anonAllowed;
private int loglevel;
private Hashtable bpds; // "210" --> BPD
private Hashtable rdhKeys; // "S_1_1_PRIV" --> hbcikey
private Long sigid;
private Hashtable userdata; // "userid" --> hashtable
public static synchronized ServerData getInstance()
{
if (_instance==null)
_instance=new ServerData();
return _instance;
}
private ServerData()
{
this.random=new Random();
}
public void init(DataStore _dataStore)
{
this.dataStore=_dataStore;
initListeners();
reInitializeServerData();
}
public void reInitializeServerData()
{
this.msggens=new Hashtable();
initBasicData();
initKeyData();
initUserData();
}
public void reInitializeUserData(String userid)
{
synchronized (userdata) {
Hashtable entry=(Hashtable)userdata.get(userid);
synchronized (entry) {
entry.clear();
}
}
}
private void initListeners()
{
listeners=new ArrayList();
String[] listenerNames=dataStore.getListeners();
for (int i=0;i<listenerNames.length;i++) {
String listenerName=listenerNames[i];
HBCIUtils.log("initializing connection listener '"+listenerName+"'",
HBCIUtils.LOG_INFO);
try {
Class cl=Class.forName("org.kapott.hbci.server.listener.Listener"+listenerName);
Constructor cons=cl.getConstructor(null);
final ConnectionListener listener=(ConnectionListener)cons.newInstance(null);
listeners.add(listener);
} catch (Exception e) {
throw new HBCI_Exception(e);
}
}
}
private void initBasicData()
{
loglevel=dataStore.getLogLevel();
anonAllowed=dataStore.isAnonAllowed();
bpds=new Hashtable();
String[] suppversions=dataStore.getSuppHBCIVersions();
// eventually add "plus" to list of supported hbci versions
List versionList=new ArrayList(Arrays.asList(suppversions));
List listenerList=new ArrayList(Arrays.asList(dataStore.getListeners()));
if (versionList.contains("220") && listenerList.contains("PinTan")) {
versionList.add("plus");
suppversions=(String[])versionList.toArray(new String[0]);
}
for (int vi=0;vi<suppversions.length;vi++) {
String hversion=suppversions[vi];
HBCIUtils.log("initializing BPD for version "+hversion,HBCIUtils.LOG_DEBUG);
Properties bpd=new Properties();
// BPA
bpd.setProperty("BPA.version",Integer.toString(dataStore.getBPDVersion(hversion)));
bpd.setProperty("BPA.KIK.country",dataStore.getCountry());
bpd.setProperty("BPA.KIK.blz",dataStore.getBLZ());
bpd.setProperty("BPA.kiname",dataStore.getKIName());
bpd.setProperty("BPA.numgva",Integer.toString(dataStore.getNumOfGVsPerMsg(hversion)));
bpd.setProperty("BPA.maxmsgsize",Integer.toString(dataStore.getMaxMsgSize(hversion)));
// supported languages
String[] supplangs=dataStore.getSuppLangs(hversion);
int len=supplangs.length;
for (int i=0;i<len;i++) {
bpd.setProperty(
HBCIUtilsInternal.withCounter("BPA.SuppLangs.lang",i),
HBCISpec.mapISO2HBCILang(supplangs[i].toUpperCase()));
}
// supported hbci versions
len=suppversions.length;
for (int i=0;i<len;i++) {
if (!suppversions[i].equals("plus")) {
bpd.setProperty(HBCIUtilsInternal.withCounter("BPA.SuppVersions.version",i),suppversions[i]);
}
}
// comm-data (basic)
String header="CommListRes";
bpd.setProperty(header+".KIK.country",dataStore.getCountry());
bpd.setProperty(header+".KIK.blz",dataStore.getBLZ());
bpd.setProperty(header+".deflang",HBCISpec.mapISO2HBCILang(dataStore.getDefaultLang(hversion)));
// comm-data (access data)
String[][] commData=dataStore.getCommData(hversion);
String currentHeader;
for (int i=0;i<commData.length;i++) {
currentHeader=HBCIUtilsInternal.withCounter(header+".CommParam",i);
String[] entry=commData[i];
bpd.setProperty(currentHeader+".dienst",entry[0]);
bpd.setProperty(currentHeader+".addr",entry[1]);
if (entry[2]!=null && entry[2].length()!=0){
bpd.setProperty(currentHeader+".addr2",entry[2]);
}
if (entry[3]!=null && entry[3].length()!=0) {
bpd.setProperty(currentHeader+".filter",entry[3]);
bpd.setProperty(currentHeader+".filterversion",entry[4]);
}
}
// security methods
bpd.setProperty("SecMethod.mixing","N");
String[][] suppsecs=dataStore.getSuppSecMethods(hversion);
for (int i=0;i<suppsecs.length;i++) {
header=HBCIUtilsInternal.withCounter("SecMethod.SuppSecMethods",i);
bpd.setProperty(header+".method",suppsecs[i][0]);
bpd.setProperty(header+".version",suppsecs[i][1]);
}
// compression methods
String[][] suppcomps=dataStore.getSuppCompMethods(hversion);
if (suppcomps!=null) {
for (int i=0;i<suppcomps.length;i++) {
header=HBCIUtilsInternal.withCounter("CompMethod.SuppCompMethods",i);
bpd.setProperty(header+".func",suppcomps[i][0]);
bpd.setProperty(header+".version",suppcomps[i][1]);
}
}
// store GV-params in BPD
String[] gvnames=dataStore.getSupportedGVs(hversion);
int counter=0;
for (int i=0;i<gvnames.length;i++) {
String gvname=gvnames[i];
HBCIUtils.log("storing BPD data for job "+gvname,HBCIUtils.LOG_DEBUG);
// alle supported versions dieses gv holen
int[] versions=dataStore.getGVVersions(gvname,hversion);
for (int j=0;j<versions.length;j++) {
int version=versions[j];
String segheader=HBCIUtilsInternal.withCounter("Params",counter++)+"."+gvname+"Par"+Integer.toString(version);
// basic params fr gvname+version setzen
bpd.setProperty(segheader+".maxnum",Integer.toString(dataStore.getGVMaxNum(gvname,version)));
bpd.setProperty(segheader+".minsigs",Integer.toString(dataStore.getGVMinSigs(gvname,version)));
// parameter fr diesen gv holen
String paramheader=segheader+".Par"+gvname;
Properties params=dataStore.getGVParams(gvname,version);
if (params!=null) {
for (Enumeration e=params.keys();e.hasMoreElements();) {
// gv-parameter in bpd speichern
String parname=(String)e.nextElement();
String parvalue=params.getProperty(parname);
bpd.setProperty(paramheader+"."+parname,parvalue);
}
}
}
}
if (hversion.equals("plus")) {
// informationen hinzufgen, welche jobs via pin/tan untersttzt
// werden und welche eine tan bentigen
HBCIUtils.log("adding BPD data for PinTan support",HBCIUtils.LOG_DEBUG);
String segheader=HBCIUtilsInternal.withCounter("Params",counter++)+".PinTanPar1";
// basic params setzen
bpd.setProperty(segheader+".maxnum","1");
bpd.setProperty(segheader+".minsigs","1");
// alle jobs, die via pintan untersttzt werden, eintragen
Properties pintanJobs=dataStore.getPinTanGVs();
int jobcounter=0;
for (Enumeration e=pintanJobs.propertyNames();e.hasMoreElements();) {
String jobname=(String)e.nextElement();
String needsTan=pintanJobs.getProperty(jobname);
String jobheader=HBCIUtilsInternal.withCounter(segheader+".ParPinTan.PinTanGV",jobcounter++);
bpd.setProperty(jobheader+".segcode",getSegCodeForJob(jobname));
bpd.setProperty(jobheader+".needtan",needsTan);
}
}
bpds.put(hversion,bpd);
}
}
// TODO: die methode ist scheisse
private String getSegCodeForJob(String jobname)
{
String ret=null;
String xmlpath=HBCIUtils.getParam("kernel.kernel.xmlpath");
InputStream syntaxStream=null;
if (xmlpath==null) {
xmlpath="";
}
// inputstream fr xml-spec erzeugen
ClassLoader cl=HBCIUtils.class.getClassLoader();
String filename=xmlpath+"hbci-plus.xml";
syntaxStream=cl.getResourceAsStream(filename);
if (syntaxStream==null)
throw new HBCI_Exception("could not find syntax specification for hbciversion plus");
MsgGen msggen=new MsgGen(syntaxStream);
Document syntax=msggen.getSyntax();
NodeList segdefs=syntax.getElementsByTagName("SEGdef");
int size=segdefs.getLength();
for (int i=0;i<size;i++) {
Node segdef=segdefs.item(i);
if (segdef.getNodeType()==Node.ELEMENT_NODE) {
String id=((Element)segdef).getAttribute("id");
if (id.startsWith(jobname)) {
char digit=id.charAt(jobname.length());
if (digit>='0' && digit<='9') {
NodeList valueChilds=((Element)segdef).getElementsByTagName("value");
int size2=valueChilds.getLength();
for (int j=0;j<size2;j++) {
Node valueChild=valueChilds.item(j);
if (valueChild.getNodeType()==Node.ELEMENT_NODE) {
if (((Element)valueChild).getAttribute("path").equals("SegHead.code")) {
ret=((Element)valueChild).getFirstChild().getNodeValue();
}
}
}
}
}
}
}
return ret;
}
private void initKeyData()
{
HBCIUtils.log("initializing server keys",HBCIUtils.LOG_DEBUG);
// rdh-schlssel aus keystore einlesen
rdhKeys=new Hashtable();
for (int keytype=0;keytype<2;keytype++) { // S und V keys
HBCIKey[] loadedKeys=(keytype==0?
dataStore.getSigKeys():
dataStore.getCryptKeys());
// wenn schlssel schon vorhanden
if (loadedKeys!=null) {
HBCIUtils.log("server "+(keytype==0?"signature":"encryption")+" key loaded",
HBCIUtils.LOG_DEBUG);
// schlssel in keys-hashtable ablegen
for (int i=0;i<2;i++) {
HBCIKey key=loadedKeys[i];
rdhKeys.put((keytype==0?"S":"V")+"_"+
key.num+"_"+
key.version+"_"+
(i==0?"PUB":"PRIV"),key);
}
} else {
// schlssel noch nicht vorhanden
HBCIUtils.log("server "+(keytype==0?"signature":"encryption")+" keys not found - generating new",
HBCIUtils.LOG_INFO);
try {
// neue schlssel erzeugen
KeyPairGenerator keygen=KeyPairGenerator.getInstance("RSA");
keygen.initialize(768);
KeyPair keypair=keygen.generateKeyPair();
HBCIKey[] newKeys=new HBCIKey[2];
// hbcikey-objekte mit neuen schlsseldaten erzeugen
newKeys[0]=new HBCIKey(getCountry(),getBLZ(),getBLZ(),"1","1",keypair.getPublic());
newKeys[1]=new HBCIKey(getCountry(),getBLZ(),getBLZ(),"1","1",keypair.getPrivate());
// neue schlssel in datastore ablegen
if (keytype==0)
dataStore.setSigKeys(newKeys);
else
dataStore.setCryptKeys(newKeys);
// neue schlssel in keys-hashtable ablegen
rdhKeys.put((keytype==0?"S":"V")+"_1_1_PUB",newKeys[0]);
rdhKeys.put((keytype==0?"S":"V")+"_1_1_PRIV",newKeys[1]);
} catch (Exception e) {
throw new HBCI_Exception("error while generating new server keys",e);
}
}
}
// sigid initialisieren
sigid=dataStore.getSigId();
}
private void initUserData()
{
userdata=new Hashtable();
// get all userids from datastore
String[] userids=dataStore.getUserIds();
for (int i=0;i<userids.length;i++) {
String userid=userids[i];
HBCIUtils.log("initializing userdata for userid "+userid,HBCIUtils.LOG_DEBUG);
// creating entry for this userid
Hashtable entry=new Hashtable();
userdata.put(userid,entry);
}
}
public Hashtable getUserData()
{
return userdata;
}
private Hashtable getUserEntry(String userid)
{
Hashtable entry;
synchronized (userdata) {
entry=(Hashtable)userdata.get(userid);
}
if (entry.size()==0) {
HBCIUtils.log("loading data for user "+userid,HBCIUtils.LOG_DEBUG);
// initializing entry for userid
entry.put("customerids",dataStore.getCustomerIds(userid));
// alle gltigen system-ids holen
String[] sysids=dataStore.getSysIds(userid);
// fr jede system-id die schon eingereichten sig-ids holen und speichern
Hashtable sigids=new Hashtable();
for (int j=0;j<sysids.length;j++) {
// sigids are returned as long[] from the datastore
// and internally stored as arraylist
long[] ids_a=dataStore.getSigIds(userid,sysids[j]);
int len=ids_a.length;
ArrayList ids=new ArrayList();
for (int i=0;i<len;i++) {
ids.add(new Long(ids_a[i]));
}
sigids.put(sysids[j],ids);
}
entry.put("sigids",sigids);
// Nutzerschlssel holen
// TODO: das besser nach passportTypes differenzieren
HBCIKey[] userkeys=dataStore.getUserKeys(userid);
if (userkeys!=null) {
entry.put("key_sig",userkeys[0]);
entry.put("key_enc",userkeys[1]);
}
// PIN holen
String pin=dataStore.getUserPIN(userid);
if (pin!=null) {
entry.put("pt_pin",pin);
}
// TAN-Liste holen
String[] tans=dataStore.getUserTANList(userid);
Hashtable usertans=new Hashtable();
for (int i=0;i<tans.length;i++) {
String tan=tans[i];
int tanlen=tan.length();
usertans.put(tan.substring(0,tanlen-2),tan.substring(tanlen-1));
}
entry.put("pt_tans",usertans);
// UPD zusammenstellen
Properties upd=new Properties();
entry.put("upd",upd);
upd.setProperty("UPA.userid",userid);
upd.setProperty("UPA.version",Integer.toString(dataStore.getAccountInfoVersion(userid)));
upd.setProperty("UPA.usage","1");
// Kontoinformationen sammeln
Konto[] accounts=dataStore.getAccounts(userid);
entry.put("accounts",accounts);
for (int j=0;j<accounts.length;j++) {
Konto acc=accounts[j];
String header=HBCIUtilsInternal.withCounter("KInfo",j);
upd.setProperty(header+".KTV.KIK.country",acc.country);
upd.setProperty(header+".KTV.KIK.blz",acc.blz);
upd.setProperty(header+".KTV.number",acc.number);
upd.setProperty(header+".customerid",acc.customerid);
upd.setProperty(header+".cur",acc.curr);
upd.setProperty(header+".name1",acc.name);
if (acc.name2!=null)
upd.setProperty(header+".name2",acc.name2);
upd.setProperty(header+".konto",acc.type);
}
}
entry.put("timestamp",new Date());
return entry;
}
public List getListeners()
{
return listeners;
}
// get country code for server
public String getCountry()
{
return ((Properties)bpds.elements().nextElement()).getProperty("BPA.KIK.country");
}
// get BLZ for server
public String getBLZ()
{
return ((Properties)bpds.elements().nextElement()).getProperty("BPA.KIK.blz");
}
// server-adresse aus BPD fr typ <type> ermitteln
public String getHost(int type)
{
String ret=null;
// irgendeine BPD benutzen
String hbciversion=(String)bpds.keys().nextElement();
Properties bpd=(Properties)bpds.get(hbciversion);
String header="CommListRes";
// alle darin gespeicherten comm-daten durchlaufen
for (int i=0;;i++) {
String dataHeader=HBCIUtilsInternal.withCounter(header+".CommParam",i);
// serveradresse extrahieren
ret=bpd.getProperty(dataHeader+".addr");
if (ret==null)
break;
// wenn comm-type passt, dann fertig
if (Integer.parseInt(bpd.getProperty(dataHeader+".dienst"))==type)
break;
}
return ret;
}
public boolean isAnonAllowed()
{
return anonAllowed;
}
public int getLogLevel()
{
return loglevel;
}
public Properties getBPD(String version)
{
return (Properties)bpds.get(version);
}
public long nextRandom()
{
return random.nextLong();
}
// fr msggen-cache
public MsgGen getMsgGen(String hbciversion)
{
synchronized (msggens) {
return (MsgGen)msggens.get(hbciversion);
}
}
// fr msggen-cache
public synchronized void storeMsgGen(String hbciversion,MsgGen gen)
{
synchronized (msggens) {
msggens.put(hbciversion,gen);
}
}
private HBCIKey getInstXKey(String type,String visibility)
{
HBCIKey ret=null;
int num=0;
int version=0;
// alle gespeicherten server-schlssel durchlaufen
for (Enumeration e=rdhKeys.keys();e.hasMoreElements();) {
String name=(String)e.nextElement();
// wenn der aktuelle schlssel von der gesuchten art ist...
if (name.startsWith(type+"_") &&
name.endsWith("_"+visibility)) {
HBCIKey key=(HBCIKey)rdhKeys.get(name);
// wenn schlsselnummer/-version hher als zuletzt gefundener, dann diesen nehmen
if (Integer.parseInt(key.num)>num ||
(Integer.parseInt(key.num)==num && Integer.parseInt(key.version)>version)) {
ret=key;
}
}
}
return ret;
}
public HBCIKey getInstPublicRDHSigKey()
{
return getInstXKey("S","PUB");
}
public HBCIKey getInstPrivateRDHSigKey()
{
return getInstXKey("S","PRIV");
}
public HBCIKey getInstPublicRDHEncKey()
{
return getInstXKey("V","PUB");
}
public HBCIKey getInstPrivateRDHEncKey()
{
return getInstXKey("V","PRIV");
}
public Long getSigId()
{
synchronized (sigid) {
return sigid;
}
}
public synchronized void setSigId(Long sigid)
{
synchronized (sigid) {
if (sigid.longValue()>this.sigid.longValue()) {
this.sigid=sigid;
dataStore.setSigId(sigid);
}
}
}
public HBCIKey getUserRDHSigKey(String userid)
{
return (HBCIKey)getUserEntry(userid).get("key_sig");
}
public HBCIKey getUserRDHEncKey(String userid)
{
return (HBCIKey)getUserEntry(userid).get("key_enc");
}
public String getUserPIN(String userid)
{
return (String)getUserEntry(userid).get("pt_pin");
}
public Hashtable getUserTANList(String userid)
{
return (Hashtable)getUserEntry(userid).get("pt_tans");
}
public void removeUserTAN(String userid,String tan)
{
((Hashtable)getUserEntry(userid).get("pt_tans")).put(tan,"0");
dataStore.removeUserTAN(userid,tan);
}
public synchronized void setUserRDHSigKey(String userid,HBCIKey key)
{
Hashtable entry=getUserEntry(userid);
if (key!=null)
entry.put("key_sig",key);
else
entry.remove("key_sig");
dataStore.storeUserSigKey(userid,key);
HBCIUtils.log("removing passport data from cache because sig keys changed",HBCIUtils.LOG_DEBUG);
entry.remove("passports");
}
public synchronized void setUserRDHEncKey(String userid,HBCIKey key)
{
Hashtable entry=getUserEntry(userid);
if (key!=null)
entry.put("key_enc",key);
else
entry.remove("key_enc");
dataStore.storeUserEncKey(userid,key);
HBCIUtils.log("removing passport data from cache because enc keys changed",HBCIUtils.LOG_DEBUG);
entry.remove("passports");
}
public void addSysId(String userid,String sysid)
{
Hashtable entry=getUserEntry(userid);
((Hashtable)entry.get("sigids")).put(sysid,new ArrayList());
dataStore.addSysId(userid,sysid);
HBCIUtils.log("removing passport data from cache because there is a new valid sysid ",HBCIUtils.LOG_DEBUG);
entry.remove("passports");
}
public String[] getSysIds(String userid)
{
ArrayList ret=new ArrayList();
Hashtable sigids=(Hashtable)getUserEntry(userid).get("sigids");
for (Enumeration e=sigids.keys();e.hasMoreElements();) {
ret.add(e.nextElement());
}
return (String[])ret.toArray(new String[0]);
}
public String[] getCustomerIds(String userid)
{
return (String[])getUserEntry(userid).get("customerids");
}
public Properties getUPD(String userid)
{
Properties ret=new Properties();
// anonymous user
if (userid==null) {
ret.setProperty("UPA.userid","9999999999");
ret.setProperty("UPA.usage","1");
ret.setProperty("UPA.version","1");
} else {
// lokal gespeicherte UPD zurckgeben
ret=(Properties)getUserEntry(userid).get("upd");
}
return ret;
}
public Konto[] getAccounts(String userid,String customerid)
{
Konto[] accounts=(Konto[])getUserEntry(userid).get("accounts");
ArrayList ret=new ArrayList();
for (int i=0;i<accounts.length;i++) {
Konto acc=accounts[i];
if (acc.customerid.equals(customerid))
ret.add(acc);
}
return (Konto[])ret.toArray(new Konto[0]);
}
public Konto[] getAllAccounts()
{
ArrayList result=new ArrayList();
for (Enumeration e=userdata.keys();e.hasMoreElements();) {
String userid=(String)e.nextElement();
String[] customerids=getCustomerIds(userid);
for (int i=0;i<customerids.length;i++) {
result.addAll(Arrays.asList(getAccounts(userid,customerids[i])));
}
}
return (Konto[])result.toArray(new Konto[0]);
}
public HBCIPassportInternal getPassport(Dialog dialog)
{
String userid=dialog.getUserId();
String passportType=dialog.getPassportType();
Hashtable passports=(Hashtable)getUserEntry(userid).get("passports");
if (passports==null) {
passports=new Hashtable();
getUserEntry(userid).put("passports",passports);
}
String passportID=passportType+"_"+dialog.getSysId();
HBCIPassportInternal ret=(HBCIPassportInternal)passports.get(passportID);
// wenn es noch kein lokal gespeichertes passport gibt
if (ret==null) {
try {
// neues passport fr diese userid erzeugen
Class cl=Class.forName("org.kapott.hbci.server.passport.LocalPassport"+passportType);
Constructor cons=cl.getConstructor(new Class[] {Dialog.class});
ret=(HBCIPassportInternal)cons.newInstance(new Object[] {dialog});
} catch (Exception e) {
throw new HBCI_Exception(e);
}
passports.put(passportID,ret);
}
return ret;
}
public boolean existsUserId(String userid)
{
return userdata.get(userid)!=null;
}
public boolean existUserSigKeys(Dialog dialog)
{
// *** TODO changed this, does it work???
// return getUserSigKey(userid)!=null;
return getPassport(dialog).hasInstSigKey();
}
public boolean existsSigId(String userid,String sysid,long sigId)
{
boolean exists;
if (sysid.equals("0")) {
exists=false;
} else {
exists=((ArrayList)((Hashtable)getUserEntry(userid).get("sigids")).get(sysid)).contains(new Long(sigId));
}
return exists;
}
public long getLastSigId(String userid,String sysid)
{
long ret;
if (sysid.equals("0")) {
ret=0;
} else {
Long[] ids=(Long[])((ArrayList)((Hashtable)getUserEntry(userid).get("sigids")).get(sysid)).toArray(new Long[0]);
if (ids.length==0) {
ret=0;
} else {
Arrays.sort(ids);
ret=ids[ids.length-1].longValue();
}
}
return ret;
}
public void clearSigIds(String userid,String sysid)
{
if (!sysid.equals("0")) {
((ArrayList)((Hashtable)getUserEntry(userid).get("sigids")).get(sysid)).clear();
dataStore.clearSigIds(userid,sysid);
}
}
public void addSigId(String userid,String sysid,long sigId)
{
if (!sysid.equals("0")) {
((ArrayList)((Hashtable)getUserEntry(userid).get("sigids")).get(sysid)).add(new Long(sigId));
dataStore.addSigId(userid,sysid,sigId);
}
}
public void setCallbackObject(ServerCallback callback)
{
this.callback=callback;
}
public void handleGVCallback(JobContext context)
{
callback.handleGV(context);
}
public void log(String msg,int level,Date date,StackTraceElement trace)
{
callback.log(msg,level,date,trace);
}
public void addToStatusProt(String userid,StatusProtEntry entry)
{
if (userid!=null) {
dataStore.addToStatusProt(userid,entry);
}
}
}