最近采用JNI来实现访问PI和eDNA的组件。
PI和EDNA都是实时数据库,提供C++的API,遂采用JNI来调用这些函数。开发中发现,通过JNI封装的API,无法并发访问实时数据库,必须在api上加上同步。这样导致访问性能很低。
像Oracle等数据库的JDBC驱动,在Oracle服务端是不是也是采用JNI来实现的?
查了大量的资料,有用的实在寥寥无几。
以下对PI的API封装类源码:
import java.util.Date;
import org.xvolks.jnative.JNative;
import org.xvolks.jnative.Type;
import org.xvolks.jnative.exceptions.NativeException;
import org.xvolks.jnative.pointers.Pointer;
import org.xvolks.jnative.pointers.memory.HeapMemoryBlock;
import com.hrnt.rdbc.exception.RealDBException;
import com.hrnt.util.DateUtil;
/**
* 实现PI数据库的部分API
*
* @author bruce
*
*/
public class PIAPI {
/**
*
*/
private PIAPI() {
}
private static PIAPI _instance = new PIAPI();
public static PIAPI getInstance() {
return _instance;
}
public static final int ARCCOUNT = 149000;
public static final int ARCTOTAL = 0;// 累计值
public static final int ARCMINNUM = 1;// 最小值
public static final int ARCMAXNUM = 2;// 最大值
public static final int ARCCSTDEV = 3;//
public static final int ARCRANGE = 4;// 随机范围
public static final int ARCAVERAGE = 5;// 时间加权平均值
public static final int ARCMEAN = 6;// 算术平均值
// 获取瞬时值的mode
public static final int ARCVALUEBEFORE = 1;
public static final int ARCVALUEAFTER = 2;
public static final int ARCVALUEINTERP = 3;
public static final int ARCVALUECODE = 4;
// 操作状态
public static final long STAT_SUC = 0;// 成功
public static final long STAT_120 = -120;
public static final long STAT_1 = -1;
public static final long STAT_105 = -105;
public static final long STAT_106 = -106;
// 获得digStart的错误标示
public static final int DIG_START_ERR = -10;
// 数据百分比
public static final float PACGOOD = 0.85f;
// 系统错误状态最小值
public static final int PI_SYSERR_MINNUM = -314;
public static final int PI_SYSERR_MAXNUM = -1;
/**
* 设置服务器地址
*
* @author bruce
* @param 服务器地址或者名称
* @return 返回操作状态,0为成功
*/
public synchronized native int piut_setservernode(String servername);
/**
* 关闭连接
*
* @author bruce
* @return 是否关闭成功,0为成功
*/
public synchronized native int piut_disconnect();
/**
* 登录PI数据库
*
* @author bruce
* @param 用户
* @param 密码
* @param 登录模式
* 1为只读,2为可读可写
* @return 登录是否成功,0为登录成功
*/
public synchronized native int piut_login(String username, String passwd,
int[] valid);
/**
* 获得标签的pointId
*
* @author bruce
* @param 标签名称
* @param 标签Id(输入输出参数)
* @return 是否成功,0为成功状态
*/
public synchronized native int pipt_findpoint(String tagname, int[] tagpoint);
/**
* @author brucepang
* @param sum
* 参数对象
* @return 0 成功,非0失败
*/
public synchronized native int piar_summary(PIAR_Summary sum);
/**
* 获得标签的类型
*
* @author bruce
* @param 测点在实时数据库的Id
* @param 测点类型(返回R是模拟量
* I是开关量 D是数字状态 )
* @return 如果空
* @throws RealDBException
*/
public String pipt_pointtype(int pt) throws RealDBException {
JNative j = null;
try {
j = new JNative("piapi32.dll", "pipt_pointtype");
j.setRetVal(Type.INT);
j.setParameter(0, pt);
Pointer p = new Pointer(new HeapMemoryBlock(1024));
j.setParameter(1, p);
j.invoke();
int isSuc = j.getRetValAsInt();
if (isSuc == 0) {
return p.getAsString();
} else if (isSuc == -1) {
throw new RealDBException("Point does not exist");
} else {
throw new RealDBException("System error:" + isSuc);
}
} catch (NativeException e) {
throw new RealDBException(e);
} catch (IllegalAccessException e) {
throw new RealDBException(e);
}
}
/**
* 获得某个标签的实时数据
*
* @author bruce
* @param 标签Id
* @param 值数
* @param 状态
* @param 时间
* @return 0为成功,-1是标签不存在,>0是系统错误
*/
public synchronized native int pisn_getsnapshot(PISN_Getsnapshot snap);
/**
* 获得某个标签的在一段时间的历史数据
*
* @author bruce
* @param 标签Id
* @param 要获得的数量
* @param 时间段
* 在传入时times[0]为开始时间,times[count-1]是结束时间。在返回时是返回的rvals[]值对应的时间数组
* @param 值数组
* @param 状态数组
* @param 0代表向前搜索,非0代表向后搜索
* @return 0为成功,>0是系统错误,-1是错误的pt,-101是开始时间小于结束时间,-103是该测点在这段时间没有数据,-105是时间格式错误
* -121是错误的count参数,-996是消息负载超出PINET协议,-998是内存地址出错
*/
public synchronized native int piar_compvalues(PIAR_Compvalues v);
/**
* 根据digcode来获取digstate
*
* @author bruce
* @param digcode
* 系统状态标示
* @param digstate
* 系统状态字符串(输入输出参数)
* @param len
* 返回的digstate字符串长度
* @return 0为成功,>0是系统错误,-11是digcode out of range
* @throws RealDBException
*/
// public synchronized native int pipt_digstate(PIPT_Digstate state);
public String pipt_digstate(int digCode) throws RealDBException {
JNative j = null;
try {
j = new JNative("piapi32.dll", "pipt_digstate");
j.setRetVal(Type.INT);
j.setParameter(0, digCode);
Pointer p = new Pointer(new HeapMemoryBlock(1024));
j.setParameter(1, p);
j.setParameter(2, 12);
j.invoke();
int isSuc = j.getRetValAsInt();
if (isSuc == 0) {
return p.getAsString();
} else if (isSuc == -11) {
throw new RealDBException("Digital state code out of range");
} else {
throw new RealDBException("System error:" + isSuc);
}
} catch (NativeException e) {
throw new RealDBException(e);
} catch (IllegalAccessException e) {
throw new RealDBException(e);
}
}
/**
* 获取测点的瞬时值
*
* @author bruce
* @param 标签
* @param 时间戳(输入时是要获得数据的时间)(输出时是数据库中该数据的实际时间)
* @param
* 获取数据的模式(1是数据时间在要求时间的之前)(2是数据时间在要求时间之后)(3是精确时间如果没有则内插值)(4是综合1、2、3的结果)
* @param 值
* @param 状态
* @return 0是成功,>0是系统错误,-1是错误的pt,-101是非在线时间,-103是没有数据,-105是错误的时间格式
*/
public synchronized native int piar_value(PIAR_Value pv);
/**
* 将PI时间转化为常规时间数组 timearray[0] month (1-12) timearray[1] day (1-31)
* timearray[2] year (four digit) timearray[3] hour (0-23) timearray[4] min
* (0-59) timearray[5] sec (0-59)
*/
public synchronized native void pitm_secint(Pitmsecint tm);
/**
* 将时间数组转化为PI识别的时间格式 timearray [0] month (1-12) timearray [1] day (1-31)
* timearray [2] year (four digit) timearray [3] hour (0-23) timearray [4]
* minute (0-59) timearray [5] second (0-59)
*
* @return 返回經轉化的時間數值 t
*/
public synchronized native void pitm_intsec(PITM_Intsec pic);
/**
* 获取系统错误的状态码信息
*
* @throws RealDBException
*/
public String piut_strerror(int stat) throws RealDBException {
JNative j = null;
try {
j = new JNative("piapi32.dll", "piut_strerror");
j.setRetVal(Type.INT);
j.setParameter(0, stat);
Pointer p = new Pointer(new HeapMemoryBlock(1024));
j.setParameter(1, p);
Pointer p2 = new Pointer(new HeapMemoryBlock(1024));
p2.setIntAt(0, 100);
j.setParameter(2, p2);
Pointer p3 = new Pointer(new HeapMemoryBlock(1024));
j.setParameter(3, p3);
j.invoke();
int isSuc = j.getRetValAsInt();
if (isSuc == 0) {
return p.getAsString();
} else if (isSuc == 100) {
throw new RealDBException(
"No more messages for this errornumber.(PI_NOMOREVALUES)");
} else if (isSuc == -411) {
throw new RealDBException("String truncated");
} else if (isSuc == -993) {
throw new RealDBException(
"Length specified for buffer is too small");
} else if (isSuc == -10007) {
throw new RealDBException("Null pointer passed for arguments");
} else {
throw new RealDBException("System error:" + isSuc);
}
} catch (NativeException e) {
throw new RealDBException(e);
} catch (IllegalAccessException e) {
throw new RealDBException(e);
}
}
/**
* 将普通时间转化为PI的时间 将这里改造成不需要PI来解析的方式
*/
public int getPITimestamp(Date date) {
long time = (date.getTime() + 8 * 3600 * 1000) / 1000;
return (int) time;
}
/**
* 计算开关量状态的起点
*
* @author bruce
* @param pt
* 测点Id
* @param digcode
* 状态
* @param 该开关量的digcode个数
* @return 0代表成功,-1代表pt不存在,
*/
public synchronized native int pipt_digpointers(PIPT_Digpointers dg);
/**
* 得到时间函数
*
* @param reltime
* @return
*/
public Date getTimedate(int time) {
long t = time;
t = t * 1000 - (8 * 3600 * 1000);
return new Date(t);
}
static {
System.loadLibrary("pijni");
}
/**
* 写入实时值或历史值
*
* @author brucepang
* @param pt
* 测点Id
* @param rval
* 数值
* @param istat
* 状态
* @param timedate
* PI的时间量
* @return 成功返回0,失败则返回非0
*/
public synchronized native int pisn_putsnapshot(PISN_Putsnapshot para);
/**
* 组合写入数据。该函数是组合函数。使用请注意参数说明 可以写入开关量、整型量、实型量以及字符串等格式的数据。
*
* @author brucepang
* @param ptnum
* 测点Id
* @param drval
* 浮点型数值,如果要写入该数组,bval必须为NULL
* @param ival
* 整型数值,如果要写入该数组,drval和bval必须为NULL
* @param bval
* 字节数组,如果为NON-NULL,则写入PI数据库
* @param bsize
* 字节数组长度。可以不设,PI会调用C的strlen来判断每个字符串的长度
* @param istat
* 开关量的状态值
* @param flags
* 数据质量标识数组
* @param timestamp
* 时间
*/
public synchronized native int pisn_putsnapshotx(int ptnum, int year,
int month, int day, int hour, int minute, int second, byte[] str);
public int pisn_putsnapshotx2(PISN_Putsnapshotx para)
throws RealDBException {
JNative j = null;
try {
j = new JNative("piapi32.dll", "pisn_putsnapshotx");
j.setRetVal(Type.INT);
j.setParameter(0, para.getPtnum());
Pointer p = new Pointer(new HeapMemoryBlock(1024));
p.setFloatAt(0, para.getDrval() == null ? 0 : para.getDrval()[0]);
j.setParameter(1, p);
Pointer p2 = new Pointer(new HeapMemoryBlock(1024));
p.setIntAt(0, para.getIval() == null ? 0 : para.getIval()[0]);
j.setParameter(2, p2);
Pointer p3 = new Pointer(new HeapMemoryBlock(1024));
p.setByteAt(0, para.getBval() == null ? null : para.getBval()[0]);
j.setParameter(3, p3);
Pointer p4 = new Pointer(new HeapMemoryBlock(1024));
p
.setShortAt(0, para.getBsize() == null ? null : para
.getBsize()[0]);
j.setParameter(4, p4);
Pointer p5 = new Pointer(new HeapMemoryBlock(1024));
p.setIntAt(0, para.getIstat() == null ? 0 : para.getIstat()[0]);
j.setParameter(5, p5);
Pointer p6 = new Pointer(new HeapMemoryBlock(1024));
p2.setIntAt(0, para.getFlags() == null ? null : para.getFlags()[0]);
j.setParameter(6, p6);
Pointer p7 = new Pointer(new HeapMemoryBlock(1024));
p2.setIntAt(0, para.getTimestamp() == null ? null : para
.getTimestamp()[0]);
j.setParameter(7, p7);
j.invoke();
int ret = j.getRetValAsInt();
System.out.println("返回状态:" + ret);
return ret;
} catch (NativeException e) {
throw new RealDBException(e);
} catch (IllegalAccessException e) {
throw new RealDBException(e);
}
}
/**
* 批量写入实时值或历史值
*
* @author brucepang
* @param pt
* 测点数组
* @param rval
* 数值数组
* @param istat
* 状态数组
* @param timedate
* PI的时间量数组
* @param error
* 错误码状态集
* @param count
* 写入的测点数据个数
* @return 0代表成功,非0失败
*/
public synchronized native int pisn_putsnapshots(int[] pt, float[] rval,
int[] istat, int[] timedate, int[] error, int count);
public static void main(String args[]) {
PIAPI api = new PIAPI();
Date date = new Date();
int time = api.getPITimestamp(date);
long time2 = (date.getTime() + 8 * 3600 * 1000) / 1000;
System.out.println("time:" + time + " time2:" + time2);
int isSuc = api.piut_setservernode("172.16.109.248");
System.out.println("isSuc:" + isSuc);
int[] vald = { 2 };
isSuc = api.piut_login("piadmin", "", vald);
System.out.println("isSuc:" + isSuc);
isSuc = api.pipt_findpoint("CDM158", vald);
System.out.println("isSuc:" + isSuc + " pt:" + vald[0]);
PIAR_Summary sum = new PIAR_Summary();
sum.setCode(PIAPI.ARCMAXNUM);
sum.setEndTime(api.getPITimestamp(DateUtil
.parseDate("2008-10-15 10:00:00")));
sum.setStartTime(api.getPITimestamp(DateUtil
.parseDate("2008-10-15 00:00:00")));
sum.setPt(vald[0]);
isSuc = api.piar_summary(sum);
System.out.println("isSuc:" + isSuc + " value:" + sum.getRval()
+ " pct:" + sum.getPctgood());
String t;
try {
t = api.pipt_pointtype(vald[0]);
System.out.println("isSuc:" + isSuc + " type:" + t);
} catch (RealDBException e1) {
e1.printStackTrace();
}
PISN_Getsnapshot shot = new PISN_Getsnapshot();
shot.setPt(vald[0]);
isSuc = api.pisn_getsnapshot(shot);
System.out.println("isSuc:"
+ isSuc
+ " value:"
+ shot.getRval()
+ " time:"
+ DateUtil.format(api.getTimedate(shot.getTimedate()),
DateUtil.DTRANS_EXTEND_FORMAT) + " istat:"
+ shot.getIstat());
PIAR_Compvalues c = new PIAR_Compvalues();
c.setCount(PIAPI.ARCCOUNT);
c.setPt(vald[0]);
int[] times = new int[c.getCount()];
times[0] = api
.getPITimestamp(DateUtil.parseDate("2008-10-15 00:00:00"));
times[times.length - 1] = api.getPITimestamp(DateUtil
.parseDate("2008-10-15 10:00:00"));
c.setTimes(times);
float[] rvals = new float[c.getCount()];
int[] istats = new int[c.getCount()];
isSuc = api.piar_compvalues(c);
System.out.println("count:" + c.getCount() + " isSuc:" + isSuc);
String state;
try {
state = api.pipt_digstate(248);
System.out.println("isSuc:" + isSuc + " desc:" + state);
} catch (RealDBException e) {
e.printStackTrace();
}
PIAR_Value pv = new PIAR_Value();
pv.setMode(3);
pv.setPt(vald[0]);
pv.setTimedate(api.getPITimestamp(DateUtil
.parseDate("2008-10-15 13:00:00")));
isSuc = api.piar_value(pv);
System.out.println("isSuc:" + isSuc + " value:" + pv.getRval()
+ " istat:" + pv.getIstat());
PIPT_Digpointers dg = new PIPT_Digpointers();
dg.setPt(vald[0]);
isSuc = api.pipt_digpointers(dg);
System.out.println("isSuc:" + isSuc + " code:" + dg.getDigcode()
+ " number:" + dg.getDignumb());
try {
String err = api.piut_strerror(5);
System.out.println("err:" + err);
} catch (RealDBException e) {
e.printStackTrace();
}
}
有些方法不知道在如何实现,遂采用JNative代理库实现的。
与大伙一起探讨探讨。