前不久又对opc相关代码做了优化,这里记录一下(2019-06-03)
这次主要新增或优化了以下功能:
当点位(ITEM)数量很多很多时,优化读取树型结构的效率;
根据一个枝干节点的名字获取该枝干下所有叶子节点;
判断一个名字对应节点的类型(枝干节点、叶子节点、都不是);
直接上代码
1. 树型结构
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @author ws
* @date 2019/3/12
*/
public class MapTree {
String key;
String value;
List<MapTree> children;
public MapTree() {
key = null;
value = null;
children = new ArrayList<>();
children.clear();
}
public MapTree(String key, String value) {
this.key = key;
this.value = value;
children = new ArrayList<>();
children.clear();
}
/**
* 添加子树
*/
public void addTree(MapTree mapTree) {
children.add(mapTree);
}
/**
* 根据key获取子树
*/
public MapTree getChild(String key) {
if (this.isEmpty()) {
return null;
} else {
for (MapTree child : this.children) {
if (child.key.equals(key)) {
return child;
}
}
return null;
}
}
/**
* 置空树
*/
public void clearTree() {
key = null;
value = null;
children.clear();
}
/**
* 获得树根
*/
public MapTree root() {
return this;
}
/**
* 获取根节点的数据,放入一个map中
*/
public Map<String, String> getRoot() {
Map<String, String> m = new HashMap<>(1);
m.put(key, value);
return m;
}
/**
* 判空
*/
public boolean isEmpty() {
return (this.children.isEmpty() && this.key == null && this.value == null);
}
/**
* 判断是否为叶子节点
*/
public boolean isLeaf() {
return this.children.isEmpty();
}
/**
* 返回当前子树(亦或是叶子)的孩子节点个数
*/
public int size() {
if (this.isEmpty()) {
return 0;
} else if (this.isLeaf()) {
return 1;
} else {
return this.children.size();
}
}
}
2. 类私有变量
写就行了,先别管它是什么,待会用到你就知道了。
private Server server = null;
private Group group = null;
private List<String> leavesList = new ArrayList<>();
public List<String> getLeavesList() {
return leavesList;
}
3. 判断节点类型
// 不存在则返回-1
// 是枝干但是该枝干下叶子数为0则返回0
// 是叶子则返回1
// 是枝干且有叶子节点则返回2,所有叶子节点通过该类的getLeavesList()方法获取
public Integer getAllLeaves(String istr) throws Exception {
List<String> list = new ArrayList<>();
TreeBrowser treeBrowser = server.getTreeBrowser();
Branch curBranch = treeBrowser.browseBranches();
String[] branch = istr.replace(".", ",").split(",");
for (int index = 0; index < branch.length; index++) {
treeBrowser.fillBranches(curBranch);
if (curBranch.getBranches().size() > 0) {
// 当前分支是否有这个子分支
boolean hasBranch = false;
for (Branch b : curBranch.getBranches()) {
if (b.getName().equals(branch[index])) {
hasBranch = true;
curBranch = b;
break;
}
}
if (!hasBranch) {
treeBrowser.fillLeaves(curBranch);
if (curBranch.getLeaves().size() > 0) {
// 当前分支是否有这个叶子
boolean hasLeaf = false;
for (Leaf lf : curBranch.getLeaves()) {
if (lf.getName().equals(branch[index])) {
hasLeaf = true;
break;
}
}
return hasLeaf ? 1 : -1;
} else {
// 也没这个叶子
return -1;
}
}
} else {
// 如果遍历到了传进来分支的最后一个节点且当前分支叶子节点数>0
if (index != branch.length - 1) {
return -1;
}
treeBrowser.fillLeaves(curBranch);
if (curBranch.getLeaves().size() > 0) {
// 当前分支是否有这个叶子
boolean hasLeaf = false;
for (Leaf lf : curBranch.getLeaves()) {
if (lf.getName().equals(branch[index])) {
hasLeaf = true;
break;
}
}
return hasLeaf ? 1 : -1;
} else {
return -1;
}
}
}
browseSubTree(treeBrowser, list, curBranch);
if (list.size() == 0) {
return 0;
} else {
leavesList = list;
return 2;
}
}
private void browseSubTree(TreeBrowser treeBrowser, List<String> list, Branch branch) {
try {
treeBrowser.fillBranches(branch);
} catch (Exception ignored) {
}
try {
treeBrowser.fillLeaves(branch);
} catch (Exception ignored) {
}
Iterator iter = branch.getLeaves().iterator();
while (iter.hasNext()) {
Leaf leaf = (Leaf) iter.next();
list.add(leaf.getItemId());
}
iter = branch.getBranches().iterator();
while (iter.hasNext()) {
Branch subBranch = (Branch) iter.next();
//key和value都是subBranch.getName(),即群组名
browseSubTree(treeBrowser, list, subBranch);
}
}
另,如果你只是想要知道它是不是枝干节点,用下面这个
4. 获取枝干节点
// 获取一个枝干下的所有叶子,
// 如果没有或者枝干名字错误则返回大小为0的List
public List<String> getLeaves(String str) {
List<String> items = new ArrayList<>();
Collection<String> browse = null;
try {
browse = server.getFlatBrowser().browse();
} catch (UnknownHostException | JIException e) {
log.info("Failed to get flat browser of opc server " +
"while getting leaves of : {} ", str, e);
return items;
}
for (String item : browse) {
if (item.contains(str + ".")) {
try {
group.addItem(item);
items.add(item);
} catch (Exception ignored) {
}
}
}
return items;
}
5. 获取树型结构
如果点位数量不多,用这个
public MapTree getAllItems() {
MapTree tree = new MapTree();
try {
TreeBrowser treeBrowser = this.server.getTreeBrowser();
if (treeBrowser != null) {
this.browserTree(treeBrowser, new Branch(), tree);
}
} catch (Exception e) {
log.info("Get tree browser failed.", e);
}
return tree;
}
public void browserTree(TreeBrowser treeBrowser, Branch branch, MapTree tree) {
try {
treeBrowser.fillBranches(branch);
} catch (Exception ignored) {
}
try {
treeBrowser.fillLeaves(branch);
} catch (Exception ignored) {
}
Iterator iter = branch.getLeaves().iterator();
while (iter.hasNext()) {
Leaf leaf = (Leaf) iter.next();
//key是leaf.getName(),value是leaf.getItemId()
tree.addTree(new MapTree(leaf.getName(), leaf.getItemId()));
//this.itemList.put(leaf.getName(),leaf.getItemId())
}
iter = branch.getBranches().iterator();
while (iter.hasNext()) {
Branch subBranch = (Branch) iter.next();
//key和value都是subBranch.getName(),即群组名
tree.addTree(new MapTree(subBranch.getName(), subBranch.getName()));
this.browserTree(treeBrowser, subBranch, tree.getChild(subBranch.getName()));
}
}
但是如果点位数量很多,比如好几万甚至更多,需要考虑效率问题,就用下面这个
// 获取平铺的所有item
public MapTree getListItems() {
MapTree tree = new MapTree();
try {
Collection<String> items = server.getFlatBrowser().browse();
for (String s : items) {
String[] split = s.replace(".", ",").split(",");
MapTree t = tree.root();
int index = -1;
for (String i : split) {
index += i.length() + 1;
if (t.getChild(i) == null) {
String branchName = s.substring(0, index);
t.addTree(new MapTree(i, branchName));
}
t = t.getChild(i);
}
}
} catch (UnknownHostException | JIException e) {
log.info("Get flat browser failed.", e);
}
return tree;
}