19 | */
20 | public class OPCBrowseServerAddressSpace extends BaseCOMObject {
21 | public OPCBrowseServerAddressSpace(final IJIComObject opcServer) throws IllegalArgumentException, UnknownHostException, JIException {
22 | super(opcServer.queryInterface(Constants.IOPCBrowseServerAddressSpace_IID));
23 | }
24 |
25 | /**
26 | * Get the information how the namespace is organized
27 | *
28 | * @return the organization of the namespace
29 | * @throws JIException
30 | */
31 | public OpcNamespaceType queryOrganization() throws JIException {
32 | JICallBuilder callObject = new JICallBuilder(true);
33 | callObject.setOpnum(0);
34 |
35 | callObject.addOutParamAsType(Short.class, JIFlags.FLAG_NULL);
36 |
37 | Object result[] = getCOMObject().call(callObject);
38 |
39 | return OpcNamespaceType.fromID((Short) result[0]);
40 | }
41 |
42 | /**
43 | * Direct the browser to another position
44 | *
45 | * Depending on the direction the new position will be set based on the provided
46 | * position information. If the direction is {@link OpcBrowseDirection#OPC_BROWSE_TO} then
47 | * the position is the item to go to. If the direction is {@link OpcBrowseDirection#OPC_BROWSE_DOWN}
48 | * the browser will descent into the tree down (not to) the branch item in position.
49 | * Passing {@link OpcBrowseDirection#OPC_BROWSE_UP} won't need a position (pass null)
50 | * and will ascent in the tree one level.
51 | *
52 | * Passing {@link OpcBrowseDirection#OPC_BROWSE_TO} and null as position will
53 | * go to the first root entry of the namespace.
54 | *
55 | * @param position The item position reference for the direction
56 | * @param direction The direction to go based on the position
57 | * @throws JIException
58 | */
59 | public void changePosition(final String position, final OpcBrowseDirection direction) throws JIException {
60 | JICallBuilder callObject = new JICallBuilder(true);
61 | callObject.setOpnum(1);
62 |
63 | callObject.addInParamAsShort((short) direction.id(), JIFlags.FLAG_NULL);
64 | callObject.addInParamAsString(position, JIFlags.FLAG_REPRESENTATION_STRING_LPWSTR);
65 |
66 | getCOMObject().call(callObject);
67 |
68 | }
69 |
70 | public EnumString browse(final OpcBrowseType browseType, final String filterCriteria, final int accessRights, final int dataType) throws JIException, IllegalArgumentException, UnknownHostException {
71 | JICallBuilder callObject = new JICallBuilder(true);
72 | callObject.setOpnum(2);
73 |
74 | callObject.addInParamAsShort((short) browseType.id(), JIFlags.FLAG_NULL);
75 | callObject.addInParamAsString(filterCriteria, JIFlags.FLAG_REPRESENTATION_STRING_LPWSTR);
76 | callObject.addInParamAsShort((short) dataType, JIFlags.FLAG_NULL);
77 | callObject.addInParamAsInt(accessRights, JIFlags.FLAG_NULL);
78 | callObject.addOutParamAsType(IJIComObject.class, JIFlags.FLAG_NULL);
79 |
80 | Object result[] = Helper.callRespectSFALSE(getCOMObject(), callObject);
81 |
82 | return new EnumString((IJIComObject) result[0]);
83 | }
84 |
85 | /**
86 | * Return the possible access paths for an item
87 | *
88 | * @param itemID the item to query
89 | * @return A string enumerator for the possible access paths
90 | * @throws JIException
91 | * @throws IllegalArgumentException
92 | * @throws UnknownHostException
93 | */
94 | public EnumString browseAccessPaths(final String itemID) throws JIException, IllegalArgumentException, UnknownHostException {
95 | JICallBuilder callObject = new JICallBuilder(true);
96 | callObject.setOpnum(4);
97 |
98 | callObject.addInParamAsString(itemID, JIFlags.FLAG_REPRESENTATION_STRING_LPWSTR);
99 | callObject.addOutParamAsType(IJIComObject.class, JIFlags.FLAG_NULL);
100 |
101 | Object[] result = Helper.callRespectSFALSE(getCOMObject(), callObject);
102 |
103 | return new EnumString((IJIComObject) result[0]);
104 | }
105 |
106 | /**
107 | * Get the complete item id from an item at the local position.
108 | *
109 | * Browsing a hierarchical namespace the browse method will return items based on the
110 | * local level in the namespace. So actually only the last part of the item ID hierarchy
111 | * is returned. In order to convert this to the full item ID one can use this method. It
112 | * will only work if the browser is still at the position in question.
113 | *
114 | * @param item the local item
115 | * @return the complete item ID
116 | * @throws JIException
117 | */
118 | public String getItemID(final String item) throws JIException {
119 | JICallBuilder callObject = new JICallBuilder(true);
120 | callObject.setOpnum(3);
121 |
122 | callObject.addInParamAsString(item, JIFlags.FLAG_REPRESENTATION_STRING_LPWSTR);
123 | callObject.addOutParamAsObject(new JIPointer(new JIString(JIFlags.FLAG_REPRESENTATION_STRING_LPWSTR)), JIFlags.FLAG_NULL);
124 |
125 | Object[] result = getCOMObject().call(callObject);
126 |
127 | return ((JIString) ((JIPointer) result[0]).getReferent()).getString();
128 | }
129 | }
130 |
--------------------------------------------------------------------------------
/opc-core-dcom/src/main/java/cn/com/sgcc/gdt/opc/core/dcom/da/impl/OPCItemIO.java:
--------------------------------------------------------------------------------
1 | package cn.com.sgcc.gdt.opc.core.dcom.da.impl;
2 |
3 | import cn.com.sgcc.gdt.opc.core.dcom.common.bean.FILETIME;
4 | import cn.com.sgcc.gdt.opc.core.dcom.common.impl.BaseCOMObject;
5 | import cn.com.sgcc.gdt.opc.core.dcom.da.bean.Constants;
6 | import cn.com.sgcc.gdt.opc.core.dcom.da.bean.IORequest;
7 | import org.jinterop.dcom.common.JIException;
8 | import org.jinterop.dcom.core.*;
9 |
10 | import java.net.UnknownHostException;
11 |
12 | /**
13 | * OPC数据项传输
14 | * @author ck.yang
15 | */
16 | public class OPCItemIO extends BaseCOMObject {
17 |
18 | public OPCItemIO(final IJIComObject opcItemIO) throws IllegalArgumentException, UnknownHostException, JIException {
19 | super(opcItemIO.queryInterface(Constants.IOPCItemIO_IID));
20 | }
21 |
22 | /**
23 | * 读取数据
24 | * @param requests
25 | * @throws JIException
26 | */
27 | public void read(final IORequest[] requests) throws JIException {
28 | if (requests.length == 0) {
29 | return;
30 | }
31 |
32 | JICallBuilder callObject = new JICallBuilder(true);
33 | callObject.setOpnum(0);
34 |
35 | JIString itemIDs[] = new JIString[requests.length];
36 | Integer maxAges[] = new Integer[requests.length];
37 | for (int i = 0; i < requests.length; i++) {
38 | itemIDs[i] = new JIString(requests[i].getItemID(), JIFlags.FLAG_REPRESENTATION_STRING_LPWSTR);
39 | maxAges[i] = new Integer(requests[i].getMaxAge());
40 | }
41 |
42 | callObject.addInParamAsInt(requests.length, JIFlags.FLAG_NULL);
43 | callObject.addInParamAsArray(new JIArray(itemIDs, true), JIFlags.FLAG_NULL);
44 | callObject.addInParamAsArray(new JIArray(maxAges, true), JIFlags.FLAG_NULL);
45 |
46 | callObject.addOutParamAsObject(new JIPointer(new JIArray(JIVariant.class, null, 1, true)), JIFlags.FLAG_NULL);
47 | callObject.addOutParamAsObject(new JIPointer(new JIArray(Integer.class, null, 1, true)), JIFlags.FLAG_NULL);
48 | callObject.addOutParamAsObject(new JIPointer(new JIArray(FILETIME.getStruct(), null, 1, true)), JIFlags.FLAG_NULL);
49 | callObject.addOutParamAsObject(new JIPointer(new JIArray(Integer.class, null, 1, true)), JIFlags.FLAG_NULL);
50 |
51 | getCOMObject().call(callObject);
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/opc-core-dcom/src/main/java/cn/com/sgcc/gdt/opc/core/dcom/da/impl/OPCItemProperties.java:
--------------------------------------------------------------------------------
1 | package cn.com.sgcc.gdt.opc.core.dcom.da.impl;
2 |
3 | import cn.com.sgcc.gdt.opc.core.dcom.common.bean.KeyedResult;
4 | import cn.com.sgcc.gdt.opc.core.dcom.common.bean.KeyedResultSet;
5 | import cn.com.sgcc.gdt.opc.core.dcom.common.impl.BaseCOMObject;
6 | import cn.com.sgcc.gdt.opc.core.dcom.common.impl.Helper;
7 | import cn.com.sgcc.gdt.opc.core.dcom.da.bean.Constants;
8 | import cn.com.sgcc.gdt.opc.core.dcom.da.bean.PropertyDescription;
9 | import org.jinterop.dcom.common.JIException;
10 | import org.jinterop.dcom.core.*;
11 |
12 | import java.net.UnknownHostException;
13 | import java.util.Collection;
14 | import java.util.LinkedList;
15 | import java.util.List;
16 |
17 | /**
18 | * OPC数据项属性
19 | * @author ck.yang
20 | */
21 | public class OPCItemProperties extends BaseCOMObject {
22 |
23 | public OPCItemProperties(final IJIComObject opcItemProperties) throws IllegalArgumentException, UnknownHostException, JIException {
24 | super(opcItemProperties.queryInterface(Constants.IOPCItemProperties_IID));
25 | }
26 |
27 | /**
28 | * 查询可用的属性
29 | * @param itemID
30 | * @return
31 | * @throws JIException
32 | */
33 | public Collection queryAvailableProperties(final String itemID) throws JIException {
34 | JICallBuilder callObject = new JICallBuilder(true);
35 | callObject.setOpnum(0);
36 |
37 | callObject.addInParamAsString(itemID, JIFlags.FLAG_REPRESENTATION_STRING_LPWSTR);
38 |
39 | callObject.addOutParamAsType(Integer.class, JIFlags.FLAG_NULL);
40 |
41 | callObject.addOutParamAsObject(new JIPointer(new JIArray(Integer.class, null, 1, true)), JIFlags.FLAG_NULL);
42 | callObject.addOutParamAsObject(new JIPointer(new JIArray(new JIString(JIFlags.FLAG_REPRESENTATION_STRING_BSTR), null, 1, true)), JIFlags.FLAG_NULL);
43 | callObject.addOutParamAsObject(new JIPointer(new JIArray(Short.class, null, 1, true)), JIFlags.FLAG_NULL);
44 |
45 | Object result[] = getCOMObject().call(callObject);
46 |
47 | List properties = new LinkedList();
48 |
49 | int len = (Integer) result[0];
50 | Integer[] ids = (Integer[]) ((JIArray) ((JIPointer) result[1]).getReferent()).getArrayInstance();
51 | JIString[] descriptions = (JIString[]) ((JIArray) ((JIPointer) result[2]).getReferent()).getArrayInstance();
52 | Short[] variableTypes = (Short[]) ((JIArray) ((JIPointer) result[3]).getReferent()).getArrayInstance();
53 |
54 | for (int i = 0; i < len; i++) {
55 | PropertyDescription pd = new PropertyDescription();
56 | pd.setId(ids[i]);
57 | pd.setDescription(descriptions[i].getString());
58 | pd.setVarType(variableTypes[i]);
59 | properties.add(pd);
60 | }
61 | return properties;
62 | }
63 |
64 | /**
65 | * 获取指定的属性
66 | * @param itemID
67 | * @param properties
68 | * @return
69 | * @throws JIException
70 | */
71 | public KeyedResultSet getItemProperties(final String itemID, final int... properties) throws JIException {
72 | if (properties.length == 0) {
73 | return new KeyedResultSet();
74 | }
75 |
76 | Integer[] ids = new Integer[properties.length];
77 | for (int i = 0; i < properties.length; i++) {
78 | ids[i] = properties[i];
79 | }
80 |
81 | JICallBuilder callObject = new JICallBuilder(true);
82 | callObject.setOpnum(1);
83 |
84 | callObject.addInParamAsString(itemID, JIFlags.FLAG_REPRESENTATION_STRING_LPWSTR);
85 | callObject.addInParamAsInt(properties.length, JIFlags.FLAG_NULL);
86 | callObject.addInParamAsArray(new JIArray(ids, true), JIFlags.FLAG_NULL);
87 |
88 | callObject.addOutParamAsObject(new JIPointer(new JIArray(JIVariant.class, null, 1, true)), JIFlags.FLAG_NULL);
89 | callObject.addOutParamAsObject(new JIPointer(new JIArray(Integer.class, null, 1, true)), JIFlags.FLAG_NULL);
90 |
91 | Object result[] = Helper.callRespectSFALSE(getCOMObject(), callObject);
92 |
93 | JIVariant[] values = (JIVariant[]) ((JIArray) ((JIPointer) result[0]).getReferent()).getArrayInstance();
94 | Integer[] errorCodes = (Integer[]) ((JIArray) ((JIPointer) result[1]).getReferent()).getArrayInstance();
95 |
96 | KeyedResultSet results = new KeyedResultSet();
97 | for (int i = 0; i < properties.length; i++) {
98 | results.add(new KeyedResult(properties[i], values[i], errorCodes[i]));
99 | }
100 | return results;
101 | }
102 |
103 | /**
104 | * 浏览数据项编号
105 | * @param itemID
106 | * @param properties
107 | * @return
108 | * @throws JIException
109 | */
110 | public KeyedResultSet lookupItemIDs(final String itemID, final int... properties) throws JIException {
111 | if (properties.length == 0) {
112 | return new KeyedResultSet();
113 | }
114 |
115 | Integer[] ids = new Integer[properties.length];
116 | for (int i = 0; i < properties.length; i++) {
117 | ids[i] = properties[i];
118 | }
119 |
120 | JICallBuilder callObject = new JICallBuilder(true);
121 | callObject.setOpnum(2);
122 |
123 | callObject.addInParamAsString(itemID, JIFlags.FLAG_REPRESENTATION_STRING_LPWSTR);
124 | callObject.addInParamAsInt(properties.length, JIFlags.FLAG_NULL);
125 | callObject.addInParamAsArray(new JIArray(ids, true), JIFlags.FLAG_NULL);
126 |
127 | callObject.addOutParamAsObject(new JIPointer(new JIArray(new JIPointer(new JIString(JIFlags.FLAG_REPRESENTATION_STRING_LPWSTR)), null, 1, true)), JIFlags.FLAG_NULL);
128 | callObject.addOutParamAsObject(new JIPointer(new JIArray(Integer.class, null, 1, true)), JIFlags.FLAG_NULL);
129 |
130 | Object result[] = Helper.callRespectSFALSE(getCOMObject(), callObject);
131 |
132 | JIPointer[] itemIDs = (JIPointer[]) ((JIArray) ((JIPointer) result[0]).getReferent()).getArrayInstance();
133 | Integer[] errorCodes = (Integer[]) ((JIArray) ((JIPointer) result[1]).getReferent()).getArrayInstance();
134 |
135 | KeyedResultSet results = new KeyedResultSet();
136 |
137 | for (int i = 0; i < properties.length; i++) {
138 | results.add(new KeyedResult(properties[i], ((JIString) itemIDs[i].getReferent()).getString(), errorCodes[i]));
139 | }
140 | return results;
141 | }
142 | }
143 |
--------------------------------------------------------------------------------
/opc-core-dcom/src/main/java/cn/com/sgcc/gdt/opc/core/dcom/da/impl/OPCSyncIO.java:
--------------------------------------------------------------------------------
1 | package cn.com.sgcc.gdt.opc.core.dcom.da.impl;
2 |
3 | import cn.com.sgcc.gdt.opc.core.dcom.common.bean.KeyedResult;
4 | import cn.com.sgcc.gdt.opc.core.dcom.common.bean.KeyedResultSet;
5 | import cn.com.sgcc.gdt.opc.core.dcom.common.bean.Result;
6 | import cn.com.sgcc.gdt.opc.core.dcom.common.bean.ResultSet;
7 | import cn.com.sgcc.gdt.opc.core.dcom.common.impl.BaseCOMObject;
8 | import cn.com.sgcc.gdt.opc.core.dcom.common.impl.Helper;
9 | import cn.com.sgcc.gdt.opc.core.dcom.da.bean.Constants;
10 | import cn.com.sgcc.gdt.opc.core.dcom.da.bean.OpcDatasource;
11 | import cn.com.sgcc.gdt.opc.core.dcom.da.bean.OpcItemState;
12 | import cn.com.sgcc.gdt.opc.core.dcom.da.bean.WriteRequest;
13 | import org.jinterop.dcom.common.JIException;
14 | import org.jinterop.dcom.core.*;
15 |
16 | /**
17 | * OPC同步访问通道
18 | * @author ck.yang
19 | */
20 | public class OPCSyncIO extends BaseCOMObject {
21 | public OPCSyncIO(final IJIComObject opcSyncIO) throws JIException {
22 | super(opcSyncIO.queryInterface(Constants.IOPCSyncIO_IID));
23 | }
24 |
25 | /**
26 | * 读取
27 | * @param source
28 | * @param serverHandles
29 | * @return
30 | * @throws JIException
31 | */
32 | public KeyedResultSet read(final OpcDatasource source, final Integer... serverHandles) throws JIException {
33 | if (serverHandles == null || serverHandles.length == 0) {
34 | return new KeyedResultSet();
35 | }
36 |
37 | JICallBuilder callObject = new JICallBuilder(true);
38 | callObject.setOpnum(0);
39 |
40 | callObject.addInParamAsShort((short) source.id(), JIFlags.FLAG_NULL);
41 | callObject.addInParamAsInt(serverHandles.length, JIFlags.FLAG_NULL);
42 | callObject.addInParamAsArray(new JIArray(serverHandles, true), JIFlags.FLAG_NULL);
43 |
44 | callObject.addOutParamAsObject(new JIPointer(new JIArray(OpcItemState.getStruct(), null, 1, true)), JIFlags.FLAG_NULL);
45 | callObject.addOutParamAsObject(new JIPointer(new JIArray(Integer.class, null, 1, true)), JIFlags.FLAG_NULL);
46 |
47 | Object result[] = Helper.callRespectSFALSE(getCOMObject(), callObject);
48 |
49 | KeyedResultSet results = new KeyedResultSet();
50 | JIStruct[] states = (JIStruct[]) ((JIArray) ((JIPointer) result[0]).getReferent()).getArrayInstance();
51 | Integer[] errorCodes = (Integer[]) ((JIArray) ((JIPointer) result[1]).getReferent()).getArrayInstance();
52 |
53 | for (int i = 0; i < serverHandles.length; i++) {
54 | results.add(new KeyedResult(serverHandles[i], OpcItemState.fromStruct(states[i]), errorCodes[i]));
55 | }
56 |
57 | return results;
58 | }
59 |
60 | /**
61 | * 写入
62 | * @param requests
63 | * @return
64 | * @throws JIException
65 | */
66 | public ResultSet write(final WriteRequest... requests) throws JIException {
67 | if (requests.length == 0) {
68 | return new ResultSet<>();
69 | }
70 |
71 | Integer[] items = new Integer[requests.length];
72 | JIVariant[] values = new JIVariant[requests.length];
73 | for (int i = 0; i < requests.length; i++) {
74 | items[i] = requests[i].getServerHandle();
75 | values[i] = Helper.fixVariant(requests[i].getValue());
76 | }
77 |
78 | JICallBuilder callObject = new JICallBuilder(true);
79 | callObject.setOpnum(1);
80 |
81 | callObject.addInParamAsInt(requests.length, JIFlags.FLAG_NULL);
82 | callObject.addInParamAsArray(new JIArray(items, true), JIFlags.FLAG_NULL);
83 | callObject.addInParamAsArray(new JIArray(values, true), JIFlags.FLAG_NULL);
84 | callObject.addOutParamAsObject(new JIPointer(new JIArray(Integer.class, null, 1, true)), JIFlags.FLAG_NULL);
85 |
86 | Object result[] = Helper.callRespectSFALSE(getCOMObject(), callObject);
87 |
88 | Integer[] errorCodes = (Integer[]) ((JIArray) ((JIPointer) result[0]).getReferent()).getArrayInstance();
89 |
90 | ResultSet results = new ResultSet<>();
91 | for (int i = 0; i < requests.length; i++) {
92 | results.add(new Result<>(requests[i], errorCodes[i]));
93 | }
94 | return results;
95 | }
96 | }
97 |
--------------------------------------------------------------------------------
/opc-core-dcom/src/main/java/cn/com/sgcc/gdt/opc/core/dcom/list/ClassDetails.java:
--------------------------------------------------------------------------------
1 | package cn.com.sgcc.gdt.opc.core.dcom.list;
2 |
3 | import lombok.Data;
4 | import lombok.EqualsAndHashCode;
5 | import lombok.ToString;
6 |
7 | /**
8 | * OPC服务软件的信息
9 | * @author ck.yang
10 | */
11 | @Data
12 | @ToString
13 | @EqualsAndHashCode
14 | public class ClassDetails {
15 | /** 服务器软件clsId */
16 | private String clsId;
17 | /** 服务器软件progId */
18 | private String progId;
19 | /** 服务器软件描述 */
20 | private String description;
21 |
22 | }
23 |
--------------------------------------------------------------------------------
/opc-core-dcom/src/main/java/cn/com/sgcc/gdt/opc/core/dcom/list/Constants.java:
--------------------------------------------------------------------------------
1 | package cn.com.sgcc.gdt.opc.core.dcom.list;
2 |
3 | /**
4 | * 常量
5 | */
6 | public interface Constants extends cn.com.sgcc.gdt.opc.core.dcom.common.bean.Constants {
7 | public static final String IOPCServerList_IID = "13486D50-4821-11D2-A494-3CB306C10000";
8 |
9 | public static final String OPCServerList_CLSID = "13486D51-4821-11D2-A494-3CB306C10000";
10 | }
11 |
--------------------------------------------------------------------------------
/opc-core-dcom/src/main/java/cn/com/sgcc/gdt/opc/core/dcom/list/impl/OPCServerList.java:
--------------------------------------------------------------------------------
1 | package cn.com.sgcc.gdt.opc.core.dcom.list.impl;
2 |
3 | import java.net.UnknownHostException;
4 |
5 | import cn.com.sgcc.gdt.opc.core.dcom.common.impl.BaseCOMObject;
6 | import cn.com.sgcc.gdt.opc.core.dcom.common.impl.EnumGUID;
7 | import cn.com.sgcc.gdt.opc.core.dcom.common.impl.Helper;
8 | import cn.com.sgcc.gdt.opc.core.dcom.list.ClassDetails;
9 | import cn.com.sgcc.gdt.opc.core.dcom.list.Constants;
10 | import org.jinterop.dcom.common.JIException;
11 | import org.jinterop.dcom.core.IJIComObject;
12 | import org.jinterop.dcom.core.JIArray;
13 | import org.jinterop.dcom.core.JICallBuilder;
14 | import org.jinterop.dcom.core.JIClsid;
15 | import org.jinterop.dcom.core.JIFlags;
16 | import org.jinterop.dcom.core.JIPointer;
17 | import org.jinterop.dcom.core.JIString;
18 |
19 | import rpc.core.UUID;
20 |
21 | /**
22 | * OPC服务列表
23 | * @author ck.yang
24 | */
25 | public class OPCServerList extends BaseCOMObject {
26 | /**
27 | * 获取服务列表
28 | * @param listObject
29 | * @throws JIException
30 | */
31 | public OPCServerList(final IJIComObject listObject) throws JIException {
32 | super(listObject.queryInterface(Constants.IOPCServerList_IID));
33 | }
34 |
35 | /**
36 | * 根据progId获取clsId
37 | * @param progId
38 | * @return
39 | * @throws JIException
40 | */
41 | public JIClsid getCLSIDFromProgID(final String progId) throws JIException {
42 | JICallBuilder callObject = new JICallBuilder(true);
43 | callObject.setOpnum(2);
44 |
45 | callObject.addInParamAsString(progId, JIFlags.FLAG_REPRESENTATION_STRING_LPWSTR);
46 | callObject.addOutParamAsType(UUID.class, JIFlags.FLAG_NULL);
47 |
48 | try {
49 | Object[] result = getCOMObject().call(callObject);
50 | return JIClsid.valueOf(((UUID) result[0]).toString());
51 | } catch (JIException e) {
52 | if (e.getErrorCode() == 0x800401F3) {
53 | return null;
54 | }
55 | throw e;
56 | }
57 | }
58 |
59 | /**
60 | * 返回服务器软件的信息
61 | *
62 | * @param clsId A server class
63 | * @throws JIException
64 | */
65 | public ClassDetails getClassDetails(final JIClsid clsId) throws JIException {
66 | if (clsId == null) {
67 | return null;
68 | }
69 |
70 | JICallBuilder callObject = new JICallBuilder(true);
71 | callObject.setOpnum(1);
72 |
73 | callObject.addInParamAsUUID(clsId.getCLSID(), JIFlags.FLAG_NULL);
74 |
75 | callObject.addOutParamAsObject(new JIPointer(new JIString(JIFlags.FLAG_REPRESENTATION_STRING_LPWSTR)), JIFlags.FLAG_NULL);
76 | callObject.addOutParamAsObject(new JIPointer(new JIString(JIFlags.FLAG_REPRESENTATION_STRING_LPWSTR)), JIFlags.FLAG_NULL);
77 |
78 | Object[] result = Helper.callRespectSFALSE(getCOMObject(), callObject);
79 |
80 | ClassDetails cd = new ClassDetails();
81 | cd.setClsId(clsId.getCLSID());
82 | cd.setProgId(((JIString) ((JIPointer) result[0]).getReferent()).getString());
83 | cd.setDescription(((JIString) ((JIPointer) result[1]).getReferent()).getString());
84 |
85 | return cd;
86 | }
87 |
88 | /*
89 | HRESULT EnumClassesOfCategories(
90 | [in] ULONG cImplemented,
91 | [in,size_is(cImplemented)] CATID rgcatidImpl[],
92 | [in] ULONG cRequired,
93 | [in,size_is(cRequired)] CATID rgcatidReq[],
94 | [out] IEnumGUID ** ppenumClsid
95 | );
96 | */
97 |
98 | public EnumGUID enumClassesOfCategories(final String[] implemented, final String[] required) throws IllegalArgumentException, UnknownHostException, JIException {
99 | UUID[] u1 = new UUID[implemented.length];
100 | UUID[] u2 = new UUID[required.length];
101 |
102 | for (int i = 0; i < implemented.length; i++) {
103 | u1[i] = new UUID(implemented[i]);
104 | }
105 |
106 | for (int i = 0; i < required.length; i++) {
107 | u2[i] = new UUID(required[i]);
108 | }
109 |
110 | return enumClassesOfCategories(u1, u2);
111 | }
112 |
113 | public EnumGUID enumClassesOfCategories(final UUID[] implemented, final UUID[] required) throws IllegalArgumentException, UnknownHostException, JIException {
114 | // ** CALL
115 | JICallBuilder callObject = new JICallBuilder(true);
116 | callObject.setOpnum(0);
117 |
118 | // ** IN
119 | callObject.addInParamAsInt(implemented.length, JIFlags.FLAG_NULL);
120 | if (implemented.length == 0) {
121 | callObject.addInParamAsPointer(new JIPointer(null), JIFlags.FLAG_NULL);
122 | } else {
123 | callObject.addInParamAsArray(new JIArray(implemented, true), JIFlags.FLAG_NULL);
124 | }
125 |
126 | callObject.addInParamAsInt(required.length, JIFlags.FLAG_NULL);
127 | if (required.length == 0) {
128 | callObject.addInParamAsPointer(new JIPointer(null), JIFlags.FLAG_NULL);
129 | } else {
130 | callObject.addInParamAsArray(new JIArray(required, true), JIFlags.FLAG_NULL);
131 | }
132 |
133 | // ** OUT
134 | callObject.addOutParamAsType(IJIComObject.class, JIFlags.FLAG_NULL);
135 |
136 | // ** RESULT
137 | Object result[] = Helper.callRespectSFALSE(getCOMObject(), callObject);
138 |
139 | return new EnumGUID((IJIComObject) result[0]);
140 | }
141 | }
142 |
--------------------------------------------------------------------------------
/opc-core-dcom/src/main/resources/progIdVsClsidDB.properties:
--------------------------------------------------------------------------------
1 | #progId Vs ClsidDB
2 | #Tue Nov 28 21:56:16 IST 2006
3 | Word.Application=000209ff-0000-0000-c000-000000000046
4 | TestCOM123.TestServer2=92a065a9-106a-4cc3-8d67-43e3a1e73df3
5 | SYSINFO.SysInfo=6fba474b-43ac-11ce-9a0e-00aa0062bb4c
6 | ADODB.Connection=00000514-0000-0010-8000-00aa006d2ea4
7 | TestJavaServer.TestServer2=617d5a31-a3bf-440f-a58f-1f57f6ac7527
8 | TestJavaServer.TestServer1=56bad610-0fcb-418a-b25e-174159a4adce
9 | InternetExplorer.Application=0002df01-0000-0000-c000-000000000046
10 | Excel.Application=00024500-0000-0000-c000-000000000046
11 | StdCollection.VBCollection=4b738074-ea47-11d2-b25a-00105a022091
12 | WbemScripting.SWbemLocator=76a64158-cb41-11d1-8b02-00600806d9b6
13 | PowerPoint.Application=91493441-5a91-11cf-8700-00aa0060263b
14 |
--------------------------------------------------------------------------------
/opc-core-lib/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 | opc-da
7 | cn.com.sgcc.gdt
8 | 0.0.1-SNAPSHOT
9 |
10 | 4.0.0
11 |
12 | opc-core-lib
13 |
14 |
15 |
16 |
17 | org.slf4j
18 | slf4j-log4j12
19 | 1.7.25
20 |
21 |
22 | commons-logging
23 | commons-logging
24 | 1.2
25 |
26 |
27 |
28 | org.kohsuke.jinterop
29 | j-interop
30 | 2.0.5
31 |
32 |
33 |
34 | cn.com.sgcc.gdt
35 | opc-core-dcom
36 | 0.0.1-SNAPSHOT
37 |
38 |
39 |
--------------------------------------------------------------------------------
/opc-core-lib/src/main/java/cn/com/sgcc/gdt/opc/lib/common/AlreadyConnectedException.java:
--------------------------------------------------------------------------------
1 | package cn.com.sgcc.gdt.opc.lib.common;
2 |
3 | public class AlreadyConnectedException extends Exception {
4 |
5 | /**
6 | *
7 | */
8 | private static final long serialVersionUID = -6494637563117314114L;
9 |
10 | }
11 |
--------------------------------------------------------------------------------
/opc-core-lib/src/main/java/cn/com/sgcc/gdt/opc/lib/common/ConnectionInformation.java:
--------------------------------------------------------------------------------
1 | package cn.com.sgcc.gdt.opc.lib.common;
2 |
3 | import lombok.AllArgsConstructor;
4 | import lombok.Data;
5 | import lombok.NoArgsConstructor;
6 | import lombok.ToString;
7 |
8 | @Data
9 | @ToString
10 | @AllArgsConstructor
11 | @NoArgsConstructor
12 | public class ConnectionInformation {
13 | private String host = "localhost";
14 |
15 | private String domain = "localhost";
16 |
17 | private String user = "";
18 |
19 | private String password = "";
20 |
21 | private String clsId = null;
22 |
23 | private String progId = null;
24 |
25 | public ConnectionInformation(final String user, final String password) {
26 | super();
27 | this.user = user;
28 | this.password = password;
29 | }
30 |
31 | public ConnectionInformation(String host, String user, String password, String clsId){
32 | super();
33 | this.host = host;
34 | this.user = user;
35 | this.password = password;
36 | this.clsId = clsId;
37 | }
38 |
39 | public ConnectionInformation(final ConnectionInformation arg0) {
40 | super();
41 | this.user = arg0.user;
42 | this.password = arg0.password;
43 | this.domain = arg0.domain;
44 | this.host = arg0.host;
45 | this.progId = arg0.progId;
46 | this.clsId = arg0.clsId;
47 | }
48 |
49 | public String getClsOrProgId() {
50 | if (this.clsId != null) {
51 | return this.clsId;
52 | } else if (this.progId != null) {
53 | return this.progId;
54 | } else {
55 | return null;
56 | }
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/opc-core-lib/src/main/java/cn/com/sgcc/gdt/opc/lib/common/NotConnectedException.java:
--------------------------------------------------------------------------------
1 | package cn.com.sgcc.gdt.opc.lib.common;
2 |
3 | public class NotConnectedException extends Exception {
4 |
5 | /**
6 | *
7 | */
8 | private static final long serialVersionUID = -3745147771605524635L;
9 |
10 | }
11 |
--------------------------------------------------------------------------------
/opc-core-lib/src/main/java/cn/com/sgcc/gdt/opc/lib/da/AccessStateListener.java:
--------------------------------------------------------------------------------
1 | package cn.com.sgcc.gdt.opc.lib.da;
2 |
3 | /**
4 | * 通道状态监听器
5 | * @author: ck.yang
6 | */
7 | public interface AccessStateListener {
8 | public abstract void stateChanged(boolean state);
9 |
10 | public abstract void errorOccured(Throwable t);
11 | }
12 |
--------------------------------------------------------------------------------
/opc-core-lib/src/main/java/cn/com/sgcc/gdt/opc/lib/da/Async20Access.java:
--------------------------------------------------------------------------------
1 | package cn.com.sgcc.gdt.opc.lib.da;
2 |
3 | import cn.com.sgcc.gdt.opc.core.dcom.common.EventHandler;
4 | import cn.com.sgcc.gdt.opc.core.dcom.common.bean.KeyedResult;
5 | import cn.com.sgcc.gdt.opc.core.dcom.common.bean.KeyedResultSet;
6 | import cn.com.sgcc.gdt.opc.core.dcom.common.bean.ResultSet;
7 | import cn.com.sgcc.gdt.opc.core.dcom.da.IOPCDataCallback;
8 | import cn.com.sgcc.gdt.opc.core.dcom.da.bean.OpcDatasource;
9 | import cn.com.sgcc.gdt.opc.core.dcom.da.bean.ValueData;
10 | import cn.com.sgcc.gdt.opc.core.dcom.da.impl.OPCAsyncIO2;
11 | import cn.com.sgcc.gdt.opc.lib.common.NotConnectedException;
12 | import cn.com.sgcc.gdt.opc.lib.da.exception.DuplicateGroupException;
13 | import org.jinterop.dcom.common.JIException;
14 | import org.slf4j.Logger;
15 | import org.slf4j.LoggerFactory;
16 |
17 | import java.net.UnknownHostException;
18 |
19 | /**
20 | * 异步访问通道
21 | * @author ck.yang
22 | */
23 | public class Async20Access extends AccessBase implements IOPCDataCallback {
24 | private static Logger logger = LoggerFactory.getLogger(Async20Access.class);
25 |
26 | private EventHandler eventHandler = null;
27 |
28 | private boolean initialRefresh = false;
29 |
30 | public Async20Access(final Server server, final int period, final boolean initialRefresh) throws IllegalArgumentException, UnknownHostException, NotConnectedException, JIException, DuplicateGroupException {
31 | super(server, period);
32 | this.initialRefresh = initialRefresh;
33 | }
34 |
35 | public Async20Access(final Server server, final int period, final boolean initialRefresh, final String logTag) throws IllegalArgumentException, UnknownHostException, NotConnectedException, JIException, DuplicateGroupException {
36 | super(server, period, logTag);
37 | this.initialRefresh = initialRefresh;
38 | }
39 |
40 | @Override
41 | protected synchronized void start() throws JIException, IllegalArgumentException, UnknownHostException, NotConnectedException, DuplicateGroupException {
42 | if (isActive()) {
43 | return;
44 | }
45 |
46 | super.start();
47 |
48 | this.eventHandler = this.group.attach(this);
49 | if (!this.items.isEmpty() && this.initialRefresh) {
50 | final OPCAsyncIO2 async20 = this.group.getAsyncIO20();
51 | if (async20 == null) {
52 | throw new NotConnectedException();
53 | }
54 |
55 | this.group.getAsyncIO20().refresh(OpcDatasource.OPC_DS_CACHE, 0);
56 | }
57 | }
58 |
59 | @Override
60 | protected synchronized void stop() throws JIException {
61 | if (!isActive()) {
62 | return;
63 | }
64 |
65 | if (this.eventHandler != null) {
66 | try {
67 | this.eventHandler.detach();
68 | } catch (final Throwable e) {
69 | logger.warn("Failed to detach group", e);
70 | }
71 |
72 | this.eventHandler = null;
73 | }
74 |
75 | super.stop();
76 | }
77 |
78 | @Override
79 | public void cancelComplete(final int transactionId, final int serverGroupHandle) {
80 | }
81 |
82 | @Override
83 | public void dataChange(final int transactionId, final int serverGroupHandle, final int masterQuality, final int masterErrorCode, final KeyedResultSet result) {
84 | logger.debug("dataChange - transId {}, items: {}", transactionId, result.size());
85 |
86 | final Group group = this.group;
87 | if (group == null) {
88 | return;
89 | }
90 |
91 | for (final KeyedResult entry : result) {
92 | final Item item = group.findItemByClientHandle(entry.getKey());
93 | logger.debug("Update for '{}'", item.getId());
94 | updateItem(item, new ItemState(entry.getErrorCode(), entry.getValue().getValue(), entry.getValue().getTimestamp(), entry.getValue().getQuality()));
95 | }
96 | }
97 |
98 | @Override
99 | public void readComplete(final int transactionId, final int serverGroupHandle, final int masterQuality, final int masterErrorCode, final KeyedResultSet result) {
100 | logger.debug("readComplete - transId {}", transactionId);
101 | }
102 |
103 | @Override
104 | public void writeComplete(final int transactionId, final int serverGroupHandle, final int masterErrorCode, final ResultSet result) {
105 | logger.debug("writeComplete - transId {}", transactionId);
106 | }
107 | }
108 |
--------------------------------------------------------------------------------
/opc-core-lib/src/main/java/cn/com/sgcc/gdt/opc/lib/da/AutoReconnectController.java:
--------------------------------------------------------------------------------
1 | package cn.com.sgcc.gdt.opc.lib.da;
2 |
3 | import lombok.extern.slf4j.Slf4j;
4 |
5 | import java.util.Set;
6 | import java.util.concurrent.CopyOnWriteArraySet;
7 |
8 | /**
9 | * 自动重连控制器
10 | * @author ck.yang
11 | */
12 | @Slf4j
13 | public class AutoReconnectController implements ServerConnectionStateListener {
14 | /** 默认重连的间隔时间:5000 ms */
15 | private static final int DEFAULT_DELAY = 5 * 1000;
16 | /** 重连延时 */
17 | private int delay;
18 |
19 | private final Server server;
20 |
21 | private final Set listeners = new CopyOnWriteArraySet();
22 |
23 | /** 原子性:状态,默认为不可用 */
24 | private AutoReconnectState state = AutoReconnectState.DISABLED;
25 |
26 | private Thread connectTask = null;
27 |
28 | public AutoReconnectController(final Server server) {
29 | this(server, DEFAULT_DELAY);
30 | }
31 |
32 | public AutoReconnectController(final Server server, final int delay) {
33 | super();
34 | setDelay(delay);
35 |
36 | this.server = server;
37 | this.server.addStateListener(this);
38 | }
39 |
40 | /**
41 | * 添加监听
42 | * @param listener
43 | */
44 | public void addListener(final AutoReconnectListener listener) {
45 | if (listener != null) {
46 | this.listeners.add(listener);
47 | listener.stateChanged(this.state);
48 | }
49 | }
50 |
51 | /**
52 | * 移除监听
53 | * @param listener
54 | */
55 | public void removeListener(final AutoReconnectListener listener) {
56 | this.listeners.remove(listener);
57 | }
58 |
59 | /**
60 | * 通知客户端改变状态
61 | * @param state
62 | */
63 | protected void notifyStateChange(final AutoReconnectState state) {
64 | this.state = state;
65 | for (AutoReconnectListener listener : this.listeners) {
66 | listener.stateChanged(state);
67 | }
68 | }
69 |
70 | /**
71 | * 获取延迟
72 | * @return
73 | */
74 | public int getDelay() {
75 | return this.delay;
76 | }
77 |
78 | /**
79 | * 如果延迟时间小于0,则使用默认的延迟时间
80 | *
81 | * @param delay The delay to use
82 | */
83 | public void setDelay(int delay) {
84 | if (delay <= 0) {
85 | delay = DEFAULT_DELAY;
86 | }
87 | this.delay = delay;
88 | }
89 |
90 | /**
91 | * 连接服务器
92 | */
93 | public synchronized void connect() {
94 | if (isRequested()) {
95 | return;
96 | }
97 | log.debug("Requesting connection");
98 | notifyStateChange(AutoReconnectState.DISCONNECTED);
99 |
100 | triggerReconnect(false);
101 | }
102 |
103 | /**
104 | * 断开服务器
105 | */
106 | public synchronized void disconnect() {
107 | if (!isRequested()) {
108 | return;
109 | }
110 |
111 | log.debug("Un-Requesting connection");
112 |
113 | notifyStateChange(AutoReconnectState.DISABLED);
114 | this.server.disconnect();
115 | }
116 |
117 | /**
118 | * 判断状态是否可用
119 | * @return
120 | */
121 | public boolean isRequested() {
122 | return this.state != AutoReconnectState.DISABLED;
123 | }
124 |
125 | @Override
126 | public synchronized void connectionStateChanged(final boolean connected) {
127 | log.info("连接状态改变: {}", connected);
128 |
129 | if (!connected) {
130 | if (isRequested()) {
131 | notifyStateChange(AutoReconnectState.DISCONNECTED);
132 | triggerReconnect(true);
133 | }
134 | } else {
135 | if (!isRequested()) {
136 | this.server.disconnect();
137 | } else {
138 | notifyStateChange(AutoReconnectState.CONNECTED);
139 | }
140 | }
141 | }
142 |
143 | /**
144 | * 触发重连
145 | * @param wait
146 | */
147 | private synchronized void triggerReconnect(final boolean wait) {
148 | if (this.connectTask != null) {
149 | log.info("服务器已经连接,无需重连!");
150 | return;
151 | }
152 |
153 | log.info("触发服务重连");
154 | this.connectTask = new Thread(new Runnable() {
155 |
156 | @Override
157 | public void run() {
158 | boolean result = false;
159 | try {
160 | result = performReconnect(wait);
161 | } finally {
162 | AutoReconnectController.this.connectTask = null;
163 | log.info("已完成服务重连:{}", result);
164 | if (!result) {
165 | triggerReconnect(true);
166 | }
167 | }
168 | }
169 | }, "客户端监听-OPC自动重连");
170 | this.connectTask.setDaemon(true);
171 | this.connectTask.start();
172 | }
173 |
174 | /**
175 | * 执行重连
176 | * @param wait
177 | * @return
178 | */
179 | private boolean performReconnect(final boolean wait) {
180 | try {
181 | if (wait) {
182 | notifyStateChange(AutoReconnectState.WAITING);
183 | log.info("推迟 {}...", this.delay);
184 | Thread.sleep(this.delay);
185 | }
186 | } catch (InterruptedException e) {
187 | }
188 |
189 | if (!isRequested()) {
190 | log.debug("Request canceled during delay");
191 | return true;
192 | }
193 |
194 | try {
195 | log.debug("连接到服务器");
196 | notifyStateChange(AutoReconnectState.CONNECTING);
197 | synchronized (this) {
198 | this.server.connect();
199 | return true;
200 | }
201 | // CONNECTED state will be set by server callback
202 | } catch (Throwable e) {
203 | log.error("服务重连失败!", e);
204 | notifyStateChange(AutoReconnectState.DISCONNECTED);
205 | return false;
206 | }
207 | }
208 |
209 | }
210 |
--------------------------------------------------------------------------------
/opc-core-lib/src/main/java/cn/com/sgcc/gdt/opc/lib/da/AutoReconnectListener.java:
--------------------------------------------------------------------------------
1 |
2 | package cn.com.sgcc.gdt.opc.lib.da;
3 |
4 | public interface AutoReconnectListener {
5 | public abstract void stateChanged(AutoReconnectState state);
6 | }
7 |
--------------------------------------------------------------------------------
/opc-core-lib/src/main/java/cn/com/sgcc/gdt/opc/lib/da/AutoReconnectState.java:
--------------------------------------------------------------------------------
1 | package cn.com.sgcc.gdt.opc.lib.da;
2 |
3 | /**
4 | * 自动重连的状态
5 | * @author ck.yang
6 | */
7 | public enum AutoReconnectState {
8 | /**
9 | * 自动重连不可用
10 | */
11 | DISABLED,
12 | /**
13 | * 自动重连已激活,但是当前未建立连接
14 | */
15 | DISCONNECTED,
16 | /**
17 | * 自动重连已激活,当前未建立连接,重连控制器在等待一段延时后将会重连
18 | */
19 | WAITING,
20 | /**
21 | * 自动重连已激活,当前为建立连接,但是重连控制器正在尝试连接
22 | */
23 | CONNECTING,
24 | /**
25 | * 自动重连已激活,当前已建立建立
26 | */
27 | CONNECTED
28 | }
--------------------------------------------------------------------------------
/opc-core-lib/src/main/java/cn/com/sgcc/gdt/opc/lib/da/DataCallback.java:
--------------------------------------------------------------------------------
1 | package cn.com.sgcc.gdt.opc.lib.da;
2 |
3 | public interface DataCallback {
4 | void changed(Item item, ItemState itemState);
5 | }
6 |
--------------------------------------------------------------------------------
/opc-core-lib/src/main/java/cn/com/sgcc/gdt/opc/lib/da/ErrorMessageResolver.java:
--------------------------------------------------------------------------------
1 | package cn.com.sgcc.gdt.opc.lib.da;
2 |
3 | import java.util.HashMap;
4 | import java.util.Map;
5 |
6 | import cn.com.sgcc.gdt.opc.core.dcom.common.impl.OPCCommon;
7 | import org.jinterop.dcom.common.JIException;
8 | import org.slf4j.Logger;
9 | import org.slf4j.LoggerFactory;
10 |
11 | /**
12 | * An error message resolver that will lookup the error code using the
13 | * server interface and will cache the result locally.
14 | *
15 | * @author Jens Reimann
16 | */
17 | public class ErrorMessageResolver {
18 | private static Logger _log = LoggerFactory.getLogger(ErrorMessageResolver.class);
19 |
20 | private OPCCommon _opcCommon = null;
21 |
22 | private final Map _messageCache = new HashMap();
23 |
24 | private int _localeId = 0;
25 |
26 | public ErrorMessageResolver(final OPCCommon opcCommon, final int localeId) {
27 | super();
28 | this._opcCommon = opcCommon;
29 | this._localeId = localeId;
30 | }
31 |
32 | /**
33 | * Get an error message from an error code
34 | *
35 | * @param errorCode The error code to look up
36 | * @return the error message or null if no message could be looked up
37 | */
38 | public synchronized String getMessage(final int errorCode) {
39 | String message = this._messageCache.get(Integer.valueOf(errorCode));
40 |
41 | if (message == null) {
42 | try {
43 | message = this._opcCommon.getErrorString(errorCode, this._localeId);
44 | _log.info(String.format("Resolved %08X to '%s'", errorCode, message));
45 | } catch (JIException e) {
46 | _log.warn(String.format("Failed to resolve error code for %08X", errorCode), e);
47 | }
48 | if (message != null) {
49 | this._messageCache.put(errorCode, message);
50 | }
51 | }
52 | return message;
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/opc-core-lib/src/main/java/cn/com/sgcc/gdt/opc/lib/da/Item.java:
--------------------------------------------------------------------------------
1 | package cn.com.sgcc.gdt.opc.lib.da;
2 |
3 | import lombok.AllArgsConstructor;
4 | import lombok.Getter;
5 | import lombok.extern.slf4j.Slf4j;
6 | import org.jinterop.dcom.common.JIException;
7 | import org.jinterop.dcom.core.JIVariant;
8 |
9 | /**
10 | * 数据项
11 | * @author: ck.yang
12 | */
13 | @Slf4j
14 | @AllArgsConstructor
15 | @Getter
16 | public class Item {
17 | /** 组 */
18 | private Group group = null;
19 | /** 服务处理编号 */
20 | private int serverHandle = 0;
21 | /** 客户端处理编号 */
22 | private int clientHandle = 0;
23 | /** 项 编号 */
24 | private String id = null;
25 |
26 | /**
27 | * 切换激活状态
28 | * @param state
29 | * @throws JIException
30 | */
31 | public void setActive(final boolean state) throws JIException {
32 | this.group.setActive(state, this);
33 | }
34 |
35 | /**
36 | * 读取
37 | * @param device
38 | * @return
39 | * @throws JIException
40 | */
41 | public ItemState read(final boolean device) throws JIException {
42 | return this.group.read(device, this).get(this);
43 | }
44 |
45 | /**
46 | * 写入
47 | * @param value
48 | * @return
49 | * @throws JIException
50 | */
51 | public Integer write(final JIVariant value) throws JIException {
52 | return this.group.write(new WriteRequest[]{new WriteRequest(this, value)}).get(this);
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/opc-core-lib/src/main/java/cn/com/sgcc/gdt/opc/lib/da/ItemState.java:
--------------------------------------------------------------------------------
1 | package cn.com.sgcc.gdt.opc.lib.da;
2 |
3 | import lombok.*;
4 | import org.jinterop.dcom.core.JIVariant;
5 |
6 | import java.util.Calendar;
7 |
8 | /**
9 | * 数据项状态信息
10 | * @author: ck.yang
11 | */
12 | @Data
13 | @ToString
14 | @NoArgsConstructor
15 | @AllArgsConstructor
16 | public class ItemState {
17 | /** 错误码 */
18 | private int errorCode = 0;
19 | /** 值 */
20 | private JIVariant value = null;
21 | /** 时间 */
22 | private Calendar timestamp = null;
23 | /** 质量 */
24 | private Short quality = null;
25 |
26 | @Override
27 | public int hashCode() {
28 | final int PRIME = 31;
29 | int result = 1;
30 | result = PRIME * result + this.errorCode;
31 | result = PRIME * result + (this.quality == null ? 0 : this.quality.hashCode());
32 | result = PRIME * result + (this.timestamp == null ? 0 : this.timestamp.hashCode());
33 | result = PRIME * result + (this.value == null ? 0 : this.value.hashCode());
34 | return result;
35 | }
36 |
37 | @Override
38 | public boolean equals(final Object obj) {
39 | if (this == obj) {
40 | return true;
41 | }
42 | if (obj == null) {
43 | return false;
44 | }
45 | if (getClass() != obj.getClass()) {
46 | return false;
47 | }
48 | final ItemState other = (ItemState) obj;
49 | if (this.errorCode != other.errorCode) {
50 | return false;
51 | }
52 | if (this.quality == null) {
53 | if (other.quality != null) {
54 | return false;
55 | }
56 | } else if (!this.quality.equals(other.quality)) {
57 | return false;
58 | }
59 | if (this.timestamp == null) {
60 | if (other.timestamp != null) {
61 | return false;
62 | }
63 | } else if (!this.timestamp.equals(other.timestamp)) {
64 | return false;
65 | }
66 | if (this.value == null) {
67 | if (other.value != null) {
68 | return false;
69 | }
70 | } else if (!this.value.equals(other.value)) {
71 | return false;
72 | }
73 | return true;
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/opc-core-lib/src/main/java/cn/com/sgcc/gdt/opc/lib/da/ServerConnectionStateListener.java:
--------------------------------------------------------------------------------
1 | package cn.com.sgcc.gdt.opc.lib.da;
2 |
3 | public interface ServerConnectionStateListener {
4 | public abstract void connectionStateChanged(boolean connected);
5 | }
6 |
--------------------------------------------------------------------------------
/opc-core-lib/src/main/java/cn/com/sgcc/gdt/opc/lib/da/ServerStateListener.java:
--------------------------------------------------------------------------------
1 | package cn.com.sgcc.gdt.opc.lib.da;
2 |
3 | import cn.com.sgcc.gdt.opc.core.dcom.da.bean.OpcServerStatus;
4 |
5 | public interface ServerStateListener {
6 | public void stateUpdate(OpcServerStatus state);
7 | }
8 |
--------------------------------------------------------------------------------
/opc-core-lib/src/main/java/cn/com/sgcc/gdt/opc/lib/da/ServerStateOperation.java:
--------------------------------------------------------------------------------
1 | package cn.com.sgcc.gdt.opc.lib.da;
2 |
3 | import cn.com.sgcc.gdt.opc.core.dcom.da.bean.OpcServerStatus;
4 | import cn.com.sgcc.gdt.opc.core.dcom.da.impl.OPCServer;
5 | import lombok.extern.slf4j.Slf4j;
6 |
7 | /**
8 | * A server state operation which can be interruped
9 | *
10 | * @author Jens Reimann
11 | */
12 | @Slf4j
13 | public class ServerStateOperation implements Runnable {
14 |
15 | public OpcServerStatus _serverStatus = null;
16 |
17 | public OPCServer _server;
18 |
19 | public Throwable _error;
20 |
21 | public Object _lock = new Object();
22 |
23 | public boolean _running = false;
24 |
25 | public ServerStateOperation(final OPCServer server) {
26 | super();
27 | this._server = server;
28 | }
29 |
30 | /**
31 | * Perform the operation.
32 | *
33 | * This method will block until either the serve state has been aquired or the
34 | * timeout triggers cancels the call.
35 | *
36 | */
37 | @Override
38 | public void run() {
39 | synchronized (this._lock) {
40 | this._running = true;
41 | }
42 | try {
43 | this._serverStatus = this._server.getStatus();
44 | synchronized (this._lock) {
45 | this._running = false;
46 | this._lock.notify();
47 | }
48 | } catch (Throwable e) {
49 | log.info("无法获取服务状态", e);
50 | this._error = e;
51 | this._running = false;
52 | synchronized (this._lock) {
53 | this._lock.notify();
54 | }
55 | }
56 |
57 | }
58 |
59 | /**
60 | * Get the server state with a timeout.
61 | *
62 | * @param timeout the timeout in ms
63 | * @return the server state or null if the server is not set.
64 | * @throws Throwable any error that occurred
65 | */
66 | public OpcServerStatus getServerState(final int timeout) throws Throwable {
67 | if (this._server == null) {
68 | log.debug("服务器未连接,跳过操作...");
69 | return null;
70 | }
71 |
72 | Thread t = new Thread(this, "客户端任务-读取服务器状态");
73 |
74 | synchronized (this._lock) {
75 | t.start();
76 | this._lock.wait(timeout);
77 | if (this._running) {
78 | log.warn("State operation still running. Interrupting...");
79 | t.interrupt();
80 | throw new InterruptedException("Interrupted getting server state");
81 | }
82 | }
83 | if (this._error != null) {
84 | log.warn("An error occurred while getting server state", this._error);
85 | throw this._error;
86 | }
87 |
88 | return this._serverStatus;
89 | }
90 |
91 | }
92 |
--------------------------------------------------------------------------------
/opc-core-lib/src/main/java/cn/com/sgcc/gdt/opc/lib/da/ServerStateReader.java:
--------------------------------------------------------------------------------
1 | package cn.com.sgcc.gdt.opc.lib.da;
2 |
3 | import java.util.ArrayList;
4 | import java.util.List;
5 | import java.util.concurrent.CopyOnWriteArrayList;
6 | import java.util.concurrent.ScheduledExecutorService;
7 | import java.util.concurrent.ScheduledFuture;
8 | import java.util.concurrent.TimeUnit;
9 |
10 | import cn.com.sgcc.gdt.opc.core.dcom.da.bean.OpcServerStatus;
11 | import org.slf4j.Logger;
12 | import org.slf4j.LoggerFactory;
13 |
14 | public class ServerStateReader {
15 | private static Logger _log = LoggerFactory.getLogger(ServerStateReader.class);
16 |
17 | private Server _server = null;
18 |
19 | private ScheduledExecutorService _scheduler = null;
20 |
21 | private final List _listeners = new CopyOnWriteArrayList();
22 |
23 | private ScheduledFuture> _job = null;
24 |
25 | public ServerStateReader(final Server server) {
26 | super();
27 | this._server = server;
28 | this._scheduler = this._server.getScheduler();
29 | }
30 |
31 | /**
32 | * Create a new server state reader. Please note that the scheduler might get
33 | * blocked for a short period of time in case of a connection failure!
34 | *
35 | * @param server the server to check
36 | * @param scheduler the scheduler to use
37 | */
38 | public ServerStateReader(final Server server, final ScheduledExecutorService scheduler) {
39 | super();
40 | this._server = server;
41 | this._scheduler = scheduler;
42 | }
43 |
44 | public synchronized void start() {
45 | if (this._job != null) {
46 | return;
47 | }
48 |
49 | this._job = this._scheduler.scheduleAtFixedRate(new Runnable() {
50 |
51 | public void run() {
52 | once();
53 | }
54 | }, 1000, 1000, TimeUnit.MILLISECONDS);
55 | }
56 |
57 | public synchronized void stop() {
58 | this._job.cancel(false);
59 | this._job = null;
60 | }
61 |
62 | protected void once() {
63 | _log.debug("Reading server state");
64 |
65 | final OpcServerStatus state = this._server.getServerState();
66 |
67 | for (final ServerStateListener listener : new ArrayList(this._listeners)) {
68 | listener.stateUpdate(state);
69 | }
70 | }
71 |
72 | public void addListener(final ServerStateListener listener) {
73 | this._listeners.add(listener);
74 | }
75 |
76 | public void removeListener(final ServerStateListener listener) {
77 | this._listeners.remove(listener);
78 | }
79 | }
80 |
--------------------------------------------------------------------------------
/opc-core-lib/src/main/java/cn/com/sgcc/gdt/opc/lib/da/SyncAccess.java:
--------------------------------------------------------------------------------
1 | package cn.com.sgcc.gdt.opc.lib.da;
2 |
3 | import java.net.UnknownHostException;
4 | import java.util.Map;
5 |
6 | import cn.com.sgcc.gdt.opc.lib.common.NotConnectedException;
7 | import cn.com.sgcc.gdt.opc.lib.da.exception.DuplicateGroupException;
8 | import lombok.extern.slf4j.Slf4j;
9 | import org.jinterop.dcom.common.JIException;
10 | import org.slf4j.Logger;
11 | import org.slf4j.LoggerFactory;
12 |
13 | /**
14 | * 同步访问通道
15 | * @author: ck.yang
16 | */
17 | @Slf4j
18 | public class SyncAccess extends AccessBase implements Runnable {
19 |
20 | private Thread runner = null;
21 |
22 | private Throwable lastError = null;
23 |
24 | /**
25 | *
26 | * @param server 服务
27 | * @param period 刷新时间
28 | * @throws IllegalArgumentException 错误参数异常
29 | * @throws UnknownHostException 未知主机异常
30 | * @throws NotConnectedException 未连接服务异常
31 | * @throws JIException 连接异常
32 | * @throws DuplicateGroupException 重复组异常
33 | */
34 | public SyncAccess(final Server server, final int period) throws IllegalArgumentException, UnknownHostException, NotConnectedException, JIException, DuplicateGroupException {
35 | super(server, period);
36 | }
37 |
38 | /**
39 | *
40 | * @param server 服务
41 | * @param period 刷新时间
42 | * @param logTag 日志标签
43 | * @throws IllegalArgumentException 错误参数异常
44 | * @throws UnknownHostException 未知主机异常
45 | * @throws NotConnectedException 未连接服务异常
46 | * @throws JIException 连接异常
47 | * @throws DuplicateGroupException 重复组异常
48 | */
49 | public SyncAccess(final Server server, final int period, final String logTag) throws IllegalArgumentException, UnknownHostException, NotConnectedException, JIException, DuplicateGroupException {
50 | super(server, period, logTag);
51 | }
52 |
53 | @Override
54 | public void run() {
55 | while (this.active) {
56 | try {
57 | runOnce();
58 | if (this.lastError != null) {
59 | this.lastError = null;
60 | handleError(null);
61 | }
62 | } catch (Throwable e) {
63 | log.error("同步读取失败!", e);
64 | handleError(e);
65 | this.server.disconnect();
66 | }
67 |
68 | try {
69 | Thread.sleep(getPeriod());
70 | } catch (InterruptedException e) {
71 | }
72 | }
73 | }
74 |
75 | protected void runOnce() throws JIException {
76 | if (!this.active || this.group == null) {
77 | return;
78 | }
79 |
80 | Map- result;
81 |
82 | // lock only this section since we could get into a deadlock otherwise
83 | // calling updateItem
84 | synchronized (this) {
85 | Item[] items = this.items.keySet().toArray(new Item[this.items.size()]);
86 | result = this.group.read(false, items);
87 | }
88 |
89 | for (Map.Entry
- entry : result.entrySet()) {
90 | updateItem(entry.getKey(), entry.getValue());
91 | }
92 |
93 | }
94 |
95 | @Override
96 | protected synchronized void start() throws JIException, IllegalArgumentException, UnknownHostException, NotConnectedException, DuplicateGroupException {
97 | super.start();
98 |
99 | this.runner = new Thread(this, "UtgardSyncReader");
100 | this.runner.setDaemon(true);
101 | this.runner.start();
102 | }
103 |
104 | @Override
105 | protected synchronized void stop() throws JIException {
106 | super.stop();
107 |
108 | this.runner = null;
109 | this.items.clear();
110 | }
111 | }
112 |
--------------------------------------------------------------------------------
/opc-core-lib/src/main/java/cn/com/sgcc/gdt/opc/lib/da/WriteRequest.java:
--------------------------------------------------------------------------------
1 | package cn.com.sgcc.gdt.opc.lib.da;
2 |
3 | import lombok.AllArgsConstructor;
4 | import lombok.Getter;
5 | import org.jinterop.dcom.core.JIVariant;
6 |
7 | /**
8 | * 写入请求
9 | * @author: ck.yang
10 | */
11 | @Getter
12 | @AllArgsConstructor
13 | public class WriteRequest {
14 | /** 数据项 */
15 | private Item item = null;
16 | /** 值 */
17 | private JIVariant value = null;
18 |
19 | }
20 |
--------------------------------------------------------------------------------
/opc-core-lib/src/main/java/cn/com/sgcc/gdt/opc/lib/da/browser/Access.java:
--------------------------------------------------------------------------------
1 | package cn.com.sgcc.gdt.opc.lib.da.browser;
2 |
3 | public enum Access {
4 | READ(1),
5 | WRITE(2);
6 |
7 | private int _code = 0;
8 |
9 | private Access(final int code) {
10 | this._code = code;
11 | }
12 |
13 | public int getCode() {
14 | return this._code;
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/opc-core-lib/src/main/java/cn/com/sgcc/gdt/opc/lib/da/browser/BaseBrowser.java:
--------------------------------------------------------------------------------
1 | package cn.com.sgcc.gdt.opc.lib.da.browser;
2 |
3 | import java.net.UnknownHostException;
4 | import java.util.Collection;
5 | import java.util.EnumSet;
6 |
7 | import cn.com.sgcc.gdt.opc.core.dcom.common.impl.EnumString;
8 | import cn.com.sgcc.gdt.opc.core.dcom.da.bean.OpcBrowseType;
9 | import cn.com.sgcc.gdt.opc.core.dcom.da.impl.OPCBrowseServerAddressSpace;
10 | import org.jinterop.dcom.common.JIException;
11 | import org.slf4j.Logger;
12 | import org.slf4j.LoggerFactory;
13 |
14 | /**
15 | * A class implementing base browsing
16 | *
17 | * @author Jens Reimann
18 | */
19 | public class BaseBrowser {
20 | private static Logger _log = LoggerFactory.getLogger(BaseBrowser.class);
21 |
22 | protected OPCBrowseServerAddressSpace _browser;
23 |
24 | /**
25 | * The batch size is the number of entries that will be requested with one call
26 | * from the server. Sometimes too big batch sizes will cause an exception. And
27 | * smaller batch sizes degrade perfomance. The default is set by {@link EnumString#DEFAULT_BATCH_SIZE}
28 | * and can be overridden by the java property
openscada.dcom.enum-batch-size
.
29 | */
30 | protected int _batchSize;
31 |
32 | public BaseBrowser(final OPCBrowseServerAddressSpace browser) {
33 | this(browser, EnumString.DEFAULT_BATCH_SIZE);
34 | }
35 |
36 | public BaseBrowser(final OPCBrowseServerAddressSpace browser, final int batchSize) {
37 | super();
38 | this._browser = browser;
39 | this._batchSize = batchSize;
40 | }
41 |
42 | /**
43 | * Set the batch size
44 | *
45 | * @param batchSize The new batch size
46 | */
47 | public void setBatchSize(final int batchSize) {
48 | this._batchSize = batchSize;
49 | }
50 |
51 | /**
52 | * Get the batch size
53 | *
54 | * @return the current batch size
55 | */
56 | public int getBatchSize() {
57 | return this._batchSize;
58 | }
59 |
60 | /**
61 | * Perform the browse operation.
62 | *
63 | * @param type
64 | * @param filterCriteria
65 | * @param accessMask
66 | * @param variantType
67 | * @return The browse result
68 | * @throws IllegalArgumentException
69 | * @throws UnknownHostException
70 | * @throws JIException
71 | */
72 | protected Collection browse(final OpcBrowseType type, final String filterCriteria, final EnumSet accessMask, final int variantType) throws IllegalArgumentException, UnknownHostException, JIException {
73 | int accessMaskValue = 0;
74 |
75 | if (accessMask.contains(Access.READ)) {
76 | accessMaskValue |= Access.READ.getCode();
77 | }
78 | if (accessMask.contains(Access.WRITE)) {
79 | accessMaskValue |= Access.WRITE.getCode();
80 | }
81 |
82 | _log.debug("Browsing with a batch size of " + this._batchSize);
83 |
84 | return this._browser.browse(type, filterCriteria, accessMaskValue, variantType).asCollection(this._batchSize);
85 | }
86 |
87 | /**
88 | * Browse the access paths for one item.
89 | *
90 | * @param itemId The item ID to look up the access paths
91 | * @return The collection of the access paths
92 | * @throws JIException
93 | * @throws UnknownHostException
94 | * @throws IllegalArgumentException
95 | */
96 | public Collection getAccessPaths(final String itemId) throws IllegalArgumentException, UnknownHostException, JIException {
97 | return this._browser.browseAccessPaths(itemId).asCollection(this._batchSize);
98 | }
99 |
100 | }
--------------------------------------------------------------------------------
/opc-core-lib/src/main/java/cn/com/sgcc/gdt/opc/lib/da/browser/Branch.java:
--------------------------------------------------------------------------------
1 | package cn.com.sgcc.gdt.opc.lib.da.browser;
2 |
3 | import java.util.Collection;
4 | import java.util.Collections;
5 | import java.util.LinkedList;
6 |
7 | public class Branch {
8 | private Branch parent = null;
9 |
10 | private String name = null;
11 |
12 | private Collection branches = new LinkedList();
13 |
14 | private Collection leaves = new LinkedList();
15 |
16 | /**
17 | * Create a branch to the virtual root folder
18 | */
19 | public Branch() {
20 | super();
21 | }
22 |
23 | /**
24 | * Create a branch with a parent branch and a name of this branch.
25 | *
26 | * @param parent The parent of this branch
27 | * @param name The name of this branch
28 | */
29 | public Branch(final Branch parent, final String name) {
30 | super();
31 | this.name = name;
32 | this.parent = parent;
33 | }
34 |
35 | /**
36 | * Get all branches.
37 | *
38 | * They must be filled first with a fill method from the {@link TreeBrowser}
39 | *
40 | * @return The list of branches
41 | */
42 | public Collection getBranches() {
43 | return this.branches;
44 | }
45 |
46 | public void setBranches(final Collection branches) {
47 | this.branches = branches;
48 | }
49 |
50 | /**
51 | * Get all leaves.
52 | *
53 | * They must be filled first with a fill method from the {@link TreeBrowser}
54 | *
55 | * @return The list of leaves
56 | */
57 | public Collection getLeaves() {
58 | return this.leaves;
59 | }
60 |
61 | public void setLeaves(final Collection leaves) {
62 | this.leaves = leaves;
63 | }
64 |
65 | public String getName() {
66 | return this.name;
67 | }
68 |
69 | public void setName(final String name) {
70 | this.name = name;
71 | }
72 |
73 | public Branch getParent() {
74 | return this.parent;
75 | }
76 |
77 | /**
78 | * Get the list of names from the parent up to this branch
79 | *
80 | * @return The stack of branch names from the parent up this one
81 | */
82 | public Collection getBranchStack() {
83 | LinkedList branches = new LinkedList();
84 |
85 | Branch currentBranch = this;
86 | while (currentBranch.getParent() != null) {
87 | branches.add(currentBranch.getName());
88 | currentBranch = currentBranch.getParent();
89 | }
90 |
91 | Collections.reverse(branches);
92 | return branches;
93 | }
94 |
95 | }
96 |
--------------------------------------------------------------------------------
/opc-core-lib/src/main/java/cn/com/sgcc/gdt/opc/lib/da/browser/FlatBrowser.java:
--------------------------------------------------------------------------------
1 | package cn.com.sgcc.gdt.opc.lib.da.browser;
2 |
3 | import cn.com.sgcc.gdt.opc.core.dcom.da.bean.OpcBrowseType;
4 | import cn.com.sgcc.gdt.opc.core.dcom.da.impl.OPCBrowseServerAddressSpace;
5 | import org.jinterop.dcom.common.JIException;
6 | import org.jinterop.dcom.core.JIVariant;
7 |
8 | import java.net.UnknownHostException;
9 | import java.util.Collection;
10 | import java.util.EnumSet;
11 |
12 | /**
13 | * Browse through the flat server namespace
14 | *
15 | * @author Jens Reimann
16 | */
17 | public class FlatBrowser extends BaseBrowser {
18 | public FlatBrowser(final OPCBrowseServerAddressSpace browser) {
19 | super(browser);
20 | }
21 |
22 | public FlatBrowser(final OPCBrowseServerAddressSpace browser, final int batchSize) {
23 | super(browser, batchSize);
24 | }
25 |
26 | /**
27 | * Perform a flat browse operation
28 | *
29 | * @param filterCriteria The filter criteria. Use an empty string if you don't need one.
30 | * @param accessMask The access mask. An empty set will search for all.
31 | * @param variantType The variant type. Must be one of the VT_ constants of {@link JIVariant}. Use {@link JIVariant#VT_EMPTY} if you want to browse for all.
32 | * @return The list of entries
33 | * @throws IllegalArgumentException
34 | * @throws UnknownHostException
35 | * @throws JIException
36 | */
37 | public Collection browse(final String filterCriteria, final EnumSet accessMask, final int variantType) throws IllegalArgumentException, UnknownHostException, JIException {
38 | return browse(OpcBrowseType.OPC_FLAT, filterCriteria, accessMask, variantType);
39 | }
40 |
41 | public Collection browse(final String filterCriteria) throws IllegalArgumentException, UnknownHostException, JIException {
42 | return browse(filterCriteria, EnumSet.noneOf(Access.class), JIVariant.VT_EMPTY);
43 | }
44 |
45 | public Collection browse() throws IllegalArgumentException, UnknownHostException, JIException {
46 | return browse("", EnumSet.noneOf(Access.class), JIVariant.VT_EMPTY);
47 | }
48 |
49 | public Collection browse(final EnumSet accessMask) throws IllegalArgumentException, UnknownHostException, JIException {
50 | return browse("", accessMask, JIVariant.VT_EMPTY);
51 | }
52 |
53 | }
54 |
--------------------------------------------------------------------------------
/opc-core-lib/src/main/java/cn/com/sgcc/gdt/opc/lib/da/browser/Leaf.java:
--------------------------------------------------------------------------------
1 | package cn.com.sgcc.gdt.opc.lib.da.browser;
2 |
3 | import lombok.AllArgsConstructor;
4 | import lombok.Data;
5 | import lombok.NoArgsConstructor;
6 | import lombok.ToString;
7 |
8 | @AllArgsConstructor
9 | @NoArgsConstructor
10 | @ToString
11 | @Data
12 | public class Leaf {
13 | private Branch parent = null;
14 |
15 | private String name = "";
16 |
17 | private String itemId = null;
18 |
19 | public Leaf(final Branch parent, final String name) {
20 | this.parent = parent;
21 | this.name = name;
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/opc-core-lib/src/main/java/cn/com/sgcc/gdt/opc/lib/da/exception/AddFailedException.java:
--------------------------------------------------------------------------------
1 | package cn.com.sgcc.gdt.opc.lib.da.exception;
2 |
3 | import cn.com.sgcc.gdt.opc.lib.da.Item;
4 | import lombok.Data;
5 | import lombok.ToString;
6 |
7 | import java.util.HashMap;
8 | import java.util.Map;
9 |
10 | /**
11 | * 添加失败异常
12 | * @author: ck.yang
13 | */
14 | @Data
15 | @ToString
16 | public class AddFailedException extends Exception {
17 |
18 | /** 错误信息 */
19 | private Map error = new HashMap<>();
20 |
21 | /** 失败的数据项 */
22 | private Map items = new HashMap<>();
23 |
24 | public AddFailedException(final Map errors, final Map items) {
25 | super();
26 | this.error = errors;
27 | this.items = items;
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/opc-core-lib/src/main/java/cn/com/sgcc/gdt/opc/lib/da/exception/DuplicateGroupException.java:
--------------------------------------------------------------------------------
1 | package cn.com.sgcc.gdt.opc.lib.da.exception;
2 |
3 | import lombok.Data;
4 | import lombok.ToString;
5 |
6 | /**
7 | * 重复的Group异常
8 | * @author: ck.yang
9 | */
10 | @Data
11 | @ToString
12 | public class DuplicateGroupException extends Exception {
13 |
14 | private String name = null;
15 |
16 | public DuplicateGroupException(final String name) {
17 | super();
18 | this.name = name;
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/opc-core-lib/src/main/java/cn/com/sgcc/gdt/opc/lib/da/exception/UnknownGroupException.java:
--------------------------------------------------------------------------------
1 | package cn.com.sgcc.gdt.opc.lib.da.exception;
2 |
3 | import lombok.Data;
4 | import lombok.ToString;
5 |
6 | /**
7 | * 未知的Group异常
8 | * @author: ck.yang
9 | */
10 | @Data
11 | @ToString
12 | public class UnknownGroupException extends Exception {
13 | private String name = null;
14 |
15 | public UnknownGroupException(final String name) {
16 | super();
17 | this.name = name;
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/opc-core-lib/src/main/java/cn/com/sgcc/gdt/opc/lib/list/Categories.java:
--------------------------------------------------------------------------------
1 |
2 | package cn.com.sgcc.gdt.opc.lib.list;
3 |
4 | public interface Categories {
5 | /**
6 | * Category of the OPC DA 1.0 Servers
7 | */
8 | public final static Category OPCDAServer10 = new Category(cn.com.sgcc.gdt.opc.core.dcom.common.Categories.OPCDAServer10);
9 |
10 | /**
11 | * Category of the OPC DA 2.0 Servers
12 | */
13 | public final static Category OPCDAServer20 = new Category(cn.com.sgcc.gdt.opc.core.dcom.common.Categories.OPCDAServer20);
14 |
15 | /**
16 | * Category of the OPC DA 3.0 Servers
17 | */
18 | public final static Category OPCDAServer30 = new Category(cn.com.sgcc.gdt.opc.core.dcom.common.Categories.OPCDAServer30);
19 |
20 | /**
21 | * Category of the XML DA 1.0 Servers
22 | */
23 | public final static Category XMLDAServer10 = new Category(cn.com.sgcc.gdt.opc.core.dcom.common.Categories.XMLDAServer10);
24 | }
25 |
--------------------------------------------------------------------------------
/opc-core-lib/src/main/java/cn/com/sgcc/gdt/opc/lib/list/Category.java:
--------------------------------------------------------------------------------
1 | package cn.com.sgcc.gdt.opc.lib.list;
2 |
3 | public class Category {
4 | private String _catId = null;
5 |
6 | public Category(final String catId) {
7 | this._catId = catId;
8 | }
9 |
10 | @Override
11 | public String toString() {
12 | return this._catId;
13 | }
14 |
15 | @Override
16 | public int hashCode() {
17 | final int PRIME = 31;
18 | int result = 1;
19 | result = PRIME * result + (this._catId == null ? 0 : this._catId.hashCode());
20 | return result;
21 | }
22 |
23 | @Override
24 | public boolean equals(final Object obj) {
25 | if (this == obj) {
26 | return true;
27 | }
28 | if (obj == null) {
29 | return false;
30 | }
31 | if (getClass() != obj.getClass()) {
32 | return false;
33 | }
34 | final Category other = (Category) obj;
35 | if (this._catId == null) {
36 | if (other._catId != null) {
37 | return false;
38 | }
39 | } else if (!this._catId.equals(other._catId)) {
40 | return false;
41 | }
42 | return true;
43 | }
44 |
45 | }
46 |
--------------------------------------------------------------------------------
/opc-core-lib/src/main/java/cn/com/sgcc/gdt/opc/lib/list/ServerList.java:
--------------------------------------------------------------------------------
1 | package cn.com.sgcc.gdt.opc.lib.list;
2 |
3 | import cn.com.sgcc.gdt.opc.core.dcom.list.ClassDetails;
4 | import cn.com.sgcc.gdt.opc.core.dcom.list.Constants;
5 | import cn.com.sgcc.gdt.opc.core.dcom.list.impl.OPCServerList;
6 | import org.jinterop.dcom.common.JIException;
7 | import org.jinterop.dcom.core.JIClsid;
8 | import org.jinterop.dcom.core.JIComServer;
9 | import org.jinterop.dcom.core.JISession;
10 | import rpc.core.UUID;
11 |
12 | import java.net.UnknownHostException;
13 | import java.util.ArrayList;
14 | import java.util.Collection;
15 | import java.util.List;
16 |
17 | /**
18 | * 服务列表
19 | */
20 | public class ServerList {
21 | private final JISession session;
22 |
23 | private final OPCServerList serverList;
24 |
25 | /**
26 | * Create a new instance with an already existing session
27 | *
28 | * @param session the DCOM session
29 | * @param host the host to query
30 | * @throws IllegalArgumentException
31 | * @throws UnknownHostException
32 | * @throws JIException
33 | */
34 | public ServerList(final JISession session, final String host) throws IllegalArgumentException, UnknownHostException, JIException {
35 | this.session = session;
36 | JIComServer comServer = new JIComServer(JIClsid.valueOf(Constants.OPCServerList_CLSID), host, this.session);
37 | this.serverList = new OPCServerList(comServer.createInstance());
38 | }
39 |
40 | /**
41 | * Create a new instance and a new DCOM session
42 | *
43 | * @param host the host to contact
44 | * @param user the user to use for authentication
45 | * @param password the password to use for authentication
46 | * @throws IllegalArgumentException
47 | * @throws UnknownHostException
48 | * @throws JIException
49 | */
50 | public ServerList(final String host, final String user, final String password) throws IllegalArgumentException, UnknownHostException, JIException {
51 | this(host, user, password, null);
52 | }
53 |
54 | /**
55 | * Create a new instance and a new DCOM session
56 | *
57 | * @param host the host to contact
58 | * @param user the user to use for authentication
59 | * @param password the password to use for authentication
60 | * @param domain The domain to use for authentication
61 | * @throws IllegalArgumentException
62 | * @throws UnknownHostException
63 | * @throws JIException
64 | */
65 | public ServerList(final String host, final String user, final String password, final String domain) throws IllegalArgumentException, UnknownHostException, JIException {
66 | this(JISession.createSession(domain, user, password), host);
67 | }
68 |
69 | /**
70 | * Get the details of a opc class
71 | *
72 | * @param clsId the class to request details for
73 | * @return The class details
74 | * @throws JIException
75 | */
76 | public ClassDetails getDetails(final String clsId) throws JIException {
77 | return this.serverList.getClassDetails(JIClsid.valueOf(clsId));
78 | }
79 |
80 | /**
81 | * Fetch the class id of a prog id
82 | *
83 | * @param progId The prog id to look up
84 | * @return the class id or null if none could be found.
85 | * @throws JIException
86 | */
87 | public String getClsIdFromProgId(final String progId) throws JIException {
88 | JIClsid cls = this.serverList.getCLSIDFromProgID(progId);
89 | if (cls == null) {
90 | return null;
91 | }
92 | return cls.getCLSID();
93 | }
94 |
95 | /**
96 | * List all servers that match the requirements
97 | *
98 | * @param implemented All implemented categories
99 | * @param required All required categories
100 | * @return A collection of class ids
101 | * @throws IllegalArgumentException
102 | * @throws UnknownHostException
103 | * @throws JIException
104 | */
105 | public Collection listServers(final Category[] implemented, final Category[] required) throws IllegalArgumentException, UnknownHostException, JIException {
106 | // convert the type safe categories to plain UUIDs
107 | UUID[] u1 = new UUID[implemented.length];
108 | UUID[] u2 = new UUID[required.length];
109 |
110 | for (int i = 0; i < implemented.length; i++) {
111 | u1[i] = new UUID(implemented[i].toString());
112 | }
113 |
114 | for (int i = 0; i < required.length; i++) {
115 | u2[i] = new UUID(required[i].toString());
116 | }
117 |
118 | // get them as UUIDs
119 | Collection resultU = this.serverList.enumClassesOfCategories(u1, u2).asCollection();
120 |
121 | // and convert to easier usable strings
122 | Collection result = new ArrayList(resultU.size());
123 | for (UUID uuid : resultU) {
124 | result.add(uuid.toString());
125 | }
126 | return result;
127 | }
128 |
129 | /**
130 | * List all servers that match the requirements and return the class details
131 | *
132 | * @param implemented All implemented categories
133 | * @param required All required categories
134 | * @return a collection of matching server and their class information
135 | * @throws IllegalArgumentException
136 | * @throws UnknownHostException
137 | * @throws JIException
138 | */
139 | public Collection listServersWithDetails(final Category[] implemented, final Category[] required) throws IllegalArgumentException, UnknownHostException, JIException {
140 | Collection resultString = listServers(implemented, required);
141 |
142 | List result = new ArrayList(resultString.size());
143 |
144 | for (String clsId : resultString) {
145 | result.add(getDetails(clsId));
146 | }
147 |
148 | return result;
149 | }
150 | }
151 |
--------------------------------------------------------------------------------
/opc-core-lib/src/test/java/cn/com/sgcc/gdt/opc/lib/da/ServerTest.java:
--------------------------------------------------------------------------------
1 | package cn.com.sgcc.gdt.opc.lib.da;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.*;
6 |
7 | /**
8 | * TODO
9 | *
10 | * @author ck.yang
11 | */
12 | public class ServerTest {
13 | @Test
14 | public void test() throws Exception {
15 | Integer socketTimeout = Integer.getInteger("rpc.socketTimeout", 0);
16 | System.out.println(socketTimeout);
17 | }
18 | }
--------------------------------------------------------------------------------
/opc-core-lib/src/test/java/cn/com/sgcc/gdt/opc/lib/da/demo/BaseInfo.java:
--------------------------------------------------------------------------------
1 | package cn.com.sgcc.gdt.opc.lib.da.demo;
2 |
3 | import cn.com.sgcc.gdt.opc.lib.common.ConnectionInformation;
4 |
5 | /**
6 | * TODO
7 | *
8 | * @author ck.yang
9 | */
10 | public class BaseInfo {
11 |
12 | /**
13 | * 连接信息
14 | * @return
15 | */
16 | public static ConnectionInformation getConnInfo(){
17 | ConnectionInformation connInfo = new ConnectionInformation();
18 | connInfo.setDomain("192.168.2.254");
19 | connInfo.setHost("192.168.2.254");
20 | connInfo.setClsId("7BC0CC8E-482C-47CA-ABDC-0FE7F9C6E729");//kepware
21 | // connInfo.setClsId("B57C679B-665D-4BB0-9848-C5F2C4A6A280");//ksDemo
22 | connInfo.setUser("Administrator");
23 | connInfo.setPassword("GDTvm6.5");
24 | return connInfo;
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/opc-core-lib/src/test/java/cn/com/sgcc/gdt/opc/lib/da/demo/DataCallbackDumper.java:
--------------------------------------------------------------------------------
1 | package cn.com.sgcc.gdt.opc.lib.da.demo;
2 |
3 | import cn.com.sgcc.gdt.opc.lib.da.DataCallback;
4 | import cn.com.sgcc.gdt.opc.lib.da.Item;
5 | import cn.com.sgcc.gdt.opc.lib.da.ItemState;
6 | import org.jinterop.dcom.common.JIException;
7 |
8 | public class DataCallbackDumper implements DataCallback {
9 |
10 | public void changed(final Item item, final ItemState itemState) {
11 | System.out.println(String.format("Item: %s, Value: %s, Timestamp: %tc, Quality: %d", item.getId(), itemState.getValue(), itemState.getTimestamp(), itemState.getQuality()));
12 |
13 | try {
14 | VariantDumper.dumpValue("\t", itemState.getValue());
15 | } catch (final JIException e) {
16 | e.printStackTrace();
17 | }
18 |
19 | }
20 |
21 | }
22 |
--------------------------------------------------------------------------------
/opc-core-lib/src/test/java/cn/com/sgcc/gdt/opc/lib/da/demo/OPCTest1.java:
--------------------------------------------------------------------------------
1 | package cn.com.sgcc.gdt.opc.lib.da.demo;
2 |
3 | import cn.com.sgcc.gdt.opc.lib.common.ConnectionInformation;
4 | import cn.com.sgcc.gdt.opc.lib.da.Group;
5 | import cn.com.sgcc.gdt.opc.lib.da.Item;
6 | import cn.com.sgcc.gdt.opc.lib.da.ItemState;
7 | import cn.com.sgcc.gdt.opc.lib.da.Server;
8 | import cn.com.sgcc.gdt.opc.lib.da.browser.Branch;
9 | import cn.com.sgcc.gdt.opc.lib.da.browser.Leaf;
10 | import org.jinterop.dcom.common.JIException;
11 | import org.junit.Test;
12 |
13 | import java.util.Map;
14 | import java.util.concurrent.Executors;
15 |
16 | public class OPCTest1 {
17 | public static void dumpItemState(final Item item, final ItemState state) {
18 | System.out.println(String.format("Item: %s, Value: %s, Timestamp: %tc, Quality: %d", item.getId(), state.getValue(), state.getTimestamp(), state.getQuality()));
19 | }
20 |
21 | public static void dumpTree(final Branch branch, final int level) {
22 | final StringBuilder sb = new StringBuilder();
23 | for (int i = 0; i < level; i++) {
24 | sb.append(" ");
25 | }
26 | final String indent = sb.toString();
27 |
28 | for (final Leaf leaf : branch.getLeaves()) {
29 | System.out.println(indent + "Leaf: " + leaf.getName() + " [" + leaf.getItemId() + "]");
30 | }
31 | for (final Branch subBranch : branch.getBranches()) {
32 | System.out.println(indent + "Branch: " + subBranch.getName());
33 | dumpTree(subBranch, level + 1);
34 | }
35 | }
36 |
37 | @Test
38 | public void testRead() throws Exception {
39 | ConnectionInformation connInfo = BaseInfo.getConnInfo();
40 |
41 | // create a new server
42 | final Server server = new Server(connInfo, Executors.newSingleThreadScheduledExecutor());
43 | try {
44 | // connect to server
45 | server.connect();
46 |
47 | // browse
48 | dumpTree(server.getTreeBrowser().browse(), 0);
49 |
50 | // add sync reader
51 |
52 | // Add a new group
53 | Group group = server.addGroup("test");
54 | // group is initially active ... just for demonstration
55 | group.setActive(true);
56 |
57 | // We already have our group ... just for demonstration
58 | group = server.findGroup("test");
59 |
60 | // Add a new item to the group
61 | final Item item = group.addItem("testChannel1.device1.tag1");
62 | // Items are initially active ... just for demonstration
63 | item.setActive(true);
64 |
65 | // Add some more items ... including one that is already existing
66 | final Map items = group.addItems("testChannel1.device1.tag1", "testChannel1.device1.tag2");
67 |
68 | // sync-read some values
69 | for (int i = 0; i < 10; i++) {
70 | Thread.sleep(100);
71 | dumpItemState(item, item.read(false));
72 | }
73 | } catch (final JIException e) {
74 | System.out.println(String.format("%08X: %s", e.getErrorCode(), server.getErrorMessage(e.getErrorCode())));
75 | }
76 | }
77 |
78 | }
79 |
--------------------------------------------------------------------------------
/opc-core-lib/src/test/java/cn/com/sgcc/gdt/opc/lib/da/demo/OPCTest2.java:
--------------------------------------------------------------------------------
1 | package cn.com.sgcc.gdt.opc.lib.da.demo;
2 |
3 | import cn.com.sgcc.gdt.opc.lib.common.ConnectionInformation;
4 | import cn.com.sgcc.gdt.opc.lib.da.AccessBase;
5 | import cn.com.sgcc.gdt.opc.lib.da.Server;
6 | import cn.com.sgcc.gdt.opc.lib.da.SyncAccess;
7 | import org.jinterop.dcom.common.JIException;
8 | import org.junit.Test;
9 |
10 | import java.util.concurrent.Executors;
11 |
12 | public class OPCTest2 {
13 |
14 | /**
15 | * 同步读取测试
16 | * @throws Exception
17 | */
18 | @Test
19 | public void testSync() throws Exception {
20 | // create connection information
21 | ConnectionInformation connInfo = BaseInfo.getConnInfo();
22 | String itemId = "testChannel1.device1.tag1";
23 |
24 | // create a new server
25 | final Server server = new Server(connInfo, Executors.newSingleThreadScheduledExecutor());
26 | try {
27 | // connect to server
28 | server.connect();
29 |
30 | // add sync access
31 |
32 | final AccessBase access = new SyncAccess(server, 100);
33 | access.addItem(itemId, new DataCallbackDumper());
34 |
35 | // start reading
36 | access.bind();
37 |
38 | // wait a little bit
39 | Thread.sleep(10 * 1000);
40 |
41 | // stop reading
42 | access.unbind();
43 | } catch (final JIException e) {
44 | System.out.println(String.format("%08X: %s", e.getErrorCode(), server.getErrorMessage(e.getErrorCode())));
45 | }
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/opc-core-lib/src/test/java/cn/com/sgcc/gdt/opc/lib/da/demo/OPCTest3.java:
--------------------------------------------------------------------------------
1 | package cn.com.sgcc.gdt.opc.lib.da.demo;
2 |
3 | import cn.com.sgcc.gdt.opc.lib.common.ConnectionInformation;
4 | import cn.com.sgcc.gdt.opc.lib.da.Server;
5 | import cn.com.sgcc.gdt.opc.lib.da.browser.BaseBrowser;
6 | import cn.com.sgcc.gdt.opc.lib.da.browser.Branch;
7 | import cn.com.sgcc.gdt.opc.lib.da.browser.Leaf;
8 | import cn.com.sgcc.gdt.opc.lib.da.browser.TreeBrowser;
9 | import org.jinterop.dcom.common.JIException;
10 |
11 | import java.net.UnknownHostException;
12 | import java.util.concurrent.Executors;
13 |
14 | public class OPCTest3 {
15 |
16 | private static void dumpLeaf(final String prefix, final Leaf leaf) {
17 | System.out.println(prefix + "Leaf: " + leaf.getName() + " [" + leaf.getItemId() + "]");
18 | }
19 |
20 | private static void dumpBranch(final String prefix, final Branch branch) {
21 | System.out.println(prefix + "Branch: " + branch.getName());
22 | }
23 |
24 | public static void dumpTree(final Branch branch, final int level) {
25 | final StringBuilder sb = new StringBuilder();
26 | for (int i = 0; i < level; i++) {
27 | sb.append(" ");
28 | }
29 | final String indent = sb.toString();
30 |
31 | for (final Leaf leaf : branch.getLeaves()) {
32 | dumpLeaf(indent, leaf);
33 | }
34 | for (final Branch subBranch : branch.getBranches()) {
35 | dumpBranch(indent, subBranch);
36 | dumpTree(subBranch, level + 1);
37 | }
38 | }
39 |
40 | public static void main(final String[] args) throws Throwable {
41 | // create connection information
42 | final ConnectionInformation ci = new ConnectionInformation();
43 | ci.setHost(args[0]);
44 | ci.setDomain(args[1]);
45 | ci.setUser(args[2]);
46 | ci.setPassword(args[3]);
47 | ci.setClsId(args[4]);
48 |
49 | // create a new server
50 | final Server server = new Server(ci, Executors.newSingleThreadScheduledExecutor());
51 | try {
52 | // connect to server
53 | server.connect();
54 |
55 | // browse flat
56 | final BaseBrowser flatBrowser = server.getFlatBrowser();
57 | if (flatBrowser != null) {
58 | for (final String item : server.getFlatBrowser().browse("")) {
59 | System.out.println(item);
60 | }
61 | }
62 |
63 | // browse tree
64 | final TreeBrowser treeBrowser = server.getTreeBrowser();
65 | if (treeBrowser != null) {
66 | dumpTree(treeBrowser.browse(), 0);
67 | }
68 |
69 | // browse tree manually
70 | browseTree("", treeBrowser, new Branch());
71 | } catch (final JIException e) {
72 | e.printStackTrace();
73 | System.out.println(String.format("%08X: %s", e.getErrorCode(), server.getErrorMessage(e.getErrorCode())));
74 | }
75 | }
76 |
77 | private static void browseTree(final String prefix, final TreeBrowser treeBrowser, final Branch branch) throws IllegalArgumentException, UnknownHostException, JIException {
78 | treeBrowser.fillLeaves(branch);
79 | treeBrowser.fillBranches(branch);
80 |
81 | for (final Leaf leaf : branch.getLeaves()) {
82 | dumpLeaf("M - " + prefix + " ", leaf);
83 | }
84 | for (final Branch subBranch : branch.getBranches()) {
85 | dumpBranch("M - " + prefix + " ", subBranch);
86 | browseTree(prefix + " ", treeBrowser, subBranch);
87 | }
88 | }
89 | }
90 |
--------------------------------------------------------------------------------
/opc-core-lib/src/test/java/cn/com/sgcc/gdt/opc/lib/da/demo/OPCTest4.java:
--------------------------------------------------------------------------------
1 | package cn.com.sgcc.gdt.opc.lib.da.demo;
2 |
3 | import cn.com.sgcc.gdt.opc.lib.common.ConnectionInformation;
4 | import cn.com.sgcc.gdt.opc.lib.da.AccessBase;
5 | import cn.com.sgcc.gdt.opc.lib.da.Async20Access;
6 | import cn.com.sgcc.gdt.opc.lib.da.Server;
7 | import org.jinterop.dcom.common.JIException;
8 | import org.slf4j.Logger;
9 | import org.slf4j.LoggerFactory;
10 |
11 | import java.util.HashSet;
12 | import java.util.Set;
13 | import java.util.concurrent.Executors;
14 |
15 | public class OPCTest4 {
16 | private static Logger _log = LoggerFactory.getLogger(OPCTest4.class);
17 |
18 | public static void main(final String[] args) throws Throwable {
19 | // create connection information
20 | final ConnectionInformation ci = new ConnectionInformation();
21 | ci.setHost(args[0]);
22 | ci.setDomain(args[1]);
23 | ci.setUser(args[2]);
24 | ci.setPassword(args[3]);
25 | ci.setClsId(args[4]);
26 |
27 | final Set items = new HashSet();
28 | for (int i = 5; i < args.length; i++) {
29 | items.add(args[i]);
30 | }
31 | if (items.isEmpty()) {
32 | items.add("Saw-toothed Waves.Int2");
33 | }
34 |
35 | // create a new server
36 | final Server server = new Server(ci, Executors.newSingleThreadScheduledExecutor());
37 | try {
38 | // connect to server
39 | server.connect();
40 |
41 | // add sync access
42 | final AccessBase access = new Async20Access(server, 100, false);
43 | for (final String itemId : items) {
44 | access.addItem(itemId, new DataCallbackDumper());
45 | }
46 |
47 | // start reading
48 | access.bind();
49 |
50 | // wait a little bit
51 | _log.info("Sleep for some seconds to give events a chance...");
52 | Thread.sleep(10 * 1000);
53 | _log.info("Returned from sleep");
54 |
55 | // stop reading
56 | access.unbind();
57 | } catch (final JIException e) {
58 | System.out.println(String.format("%08X: %s", e.getErrorCode(), server.getErrorMessage(e.getErrorCode())));
59 | }
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/opc-core-lib/src/test/java/cn/com/sgcc/gdt/opc/lib/da/demo/OPCTest5.java:
--------------------------------------------------------------------------------
1 | package cn.com.sgcc.gdt.opc.lib.da.demo;
2 |
3 | import cn.com.sgcc.gdt.opc.lib.common.ConnectionInformation;
4 | import cn.com.sgcc.gdt.opc.lib.da.Async20Access;
5 | import cn.com.sgcc.gdt.opc.lib.da.Server;
6 | import org.jinterop.dcom.common.JIException;
7 |
8 | import java.util.LinkedList;
9 | import java.util.List;
10 | import java.util.concurrent.Executors;
11 |
12 | public class OPCTest5 {
13 | public static void main(final String[] args) throws Throwable {
14 | // create connection information
15 | final ConnectionInformation baseInfo = new ConnectionInformation();
16 | baseInfo.setHost(args[0]);
17 | baseInfo.setDomain(args[1]);
18 | baseInfo.setUser(args[2]);
19 | baseInfo.setPassword(args[3]);
20 |
21 | final List testInfo = new LinkedList();
22 | int i = 0;
23 |
24 | try {
25 |
26 | while (args.length > i * 2 + 4) {
27 | final ConnectionInformation ci = new ConnectionInformation(baseInfo);
28 | ci.setClsId(args[i * 2 + 4]);
29 | final OPCTestInfo ti = new OPCTestInfo();
30 | ti._info = ci;
31 | ti._itemId = args[i * 2 + 5];
32 | ti._server = new Server(ci, Executors.newSingleThreadScheduledExecutor());
33 |
34 | ti._server.connect();
35 | ti._access = new Async20Access(ti._server, 100, false);
36 | ti._access.addItem(ti._itemId, new DataCallbackDumper());
37 | ti._access.bind();
38 |
39 | testInfo.add(ti);
40 | i++;
41 | }
42 |
43 | // wait a little bit
44 | Thread.sleep(10 * 1000);
45 | } catch (final JIException e) {
46 | System.out.println(String.format("%08X", e.getErrorCode()));
47 | }
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/opc-core-lib/src/test/java/cn/com/sgcc/gdt/opc/lib/da/demo/OPCTest6.java:
--------------------------------------------------------------------------------
1 | package cn.com.sgcc.gdt.opc.lib.da.demo;
2 |
3 | import cn.com.sgcc.gdt.opc.lib.common.ConnectionInformation;
4 | import cn.com.sgcc.gdt.opc.lib.da.AccessBase;
5 | import cn.com.sgcc.gdt.opc.lib.da.AutoReconnectController;
6 | import cn.com.sgcc.gdt.opc.lib.da.Server;
7 | import cn.com.sgcc.gdt.opc.lib.da.SyncAccess;
8 | import org.jinterop.dcom.common.JIException;
9 |
10 | import java.util.concurrent.Executors;
11 |
12 | public class OPCTest6 {
13 | public static void main(final String[] args) throws Throwable {
14 | // create connection information
15 | final ConnectionInformation ci = new ConnectionInformation();
16 | ci.setHost(args[0]);
17 | ci.setDomain(args[1]);
18 | ci.setUser(args[2]);
19 | ci.setPassword(args[3]);
20 | ci.setClsId(args[4]);
21 |
22 | String itemId = "Saw-toothed Waves.Int2";
23 | if (args.length >= 6) {
24 | itemId = args[5];
25 | }
26 |
27 | // create a new server
28 | final Server server = new Server(ci, Executors.newSingleThreadScheduledExecutor());
29 | final AutoReconnectController autoReconnectController = new AutoReconnectController(server);
30 | try {
31 | // connect to server
32 | autoReconnectController.connect();
33 |
34 | // add sync access
35 |
36 | final AccessBase access = new SyncAccess(server, 100);
37 | access.addItem(itemId, new DataCallbackDumper());
38 |
39 | // start reading
40 | access.bind();
41 |
42 | // run forever
43 | final boolean running = true;
44 | while (running) {
45 | Thread.sleep(10 * 1000);
46 | }
47 |
48 | /*
49 | // stop reading
50 | access.unbind ();
51 |
52 | // disconnect
53 | autoReconnectController.disconnect ();
54 | */
55 | } catch (final JIException e) {
56 | System.out.println(String.format("%08X: %s", e.getErrorCode(), server.getErrorMessage(e.getErrorCode())));
57 | }
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/opc-core-lib/src/test/java/cn/com/sgcc/gdt/opc/lib/da/demo/OPCTest7.java:
--------------------------------------------------------------------------------
1 | package cn.com.sgcc.gdt.opc.lib.da.demo;
2 |
3 | import cn.com.sgcc.gdt.opc.lib.common.ConnectionInformation;
4 | import cn.com.sgcc.gdt.opc.lib.da.Group;
5 | import cn.com.sgcc.gdt.opc.lib.da.Item;
6 | import cn.com.sgcc.gdt.opc.lib.da.ItemState;
7 | import cn.com.sgcc.gdt.opc.lib.da.Server;
8 | import org.jinterop.dcom.common.JIException;
9 | import org.jinterop.dcom.core.JIArray;
10 | import org.jinterop.dcom.core.JIFlags;
11 | import org.jinterop.dcom.core.JIString;
12 | import org.jinterop.dcom.core.JIVariant;
13 |
14 | import java.util.concurrent.Executors;
15 |
16 | public class OPCTest7 {
17 | @SuppressWarnings("unused")
18 | public static void main(final String[] args) throws Throwable {
19 | // create connection information
20 | final ConnectionInformation ci = new ConnectionInformation();
21 | ci.setHost(args[0]);
22 | ci.setDomain(args[1]);
23 | ci.setUser(args[2]);
24 | ci.setPassword(args[3]);
25 | ci.setClsId(args[4]);
26 |
27 | final String itemName = args[5];
28 |
29 | // create a new server
30 | final Server server = new Server(ci, Executors.newSingleThreadScheduledExecutor());
31 | try {
32 | // connect to server
33 | server.connect();
34 |
35 | // Add a new group
36 | final Group group = server.addGroup("test");
37 |
38 | // Add a new item to the group
39 | final Item item = group.addItem(itemName);
40 |
41 | final JIString[] sdata = new JIString[]{new JIString("ab", JIFlags.FLAG_REPRESENTATION_STRING_BSTR), new JIString("cd", JIFlags.FLAG_REPRESENTATION_STRING_BSTR), new JIString("ef", JIFlags.FLAG_REPRESENTATION_STRING_BSTR)};
42 | final Double[] ddata = new Double[]{1.1, 2.2, 3.3};
43 | final Boolean[] bdata = new Boolean[]{true, false, true, false};
44 | final Integer[] idata = new Integer[]{1202, 1203, 1204};
45 | final Long[] ldata = new Long[]{12020001L, 12030001L, 12040001L};
46 | final Float[] fdata = new Float[]{1.1f, 1.2f, 1.3f};
47 | final Byte[] bydata = new Byte[]{1, 2, 3};
48 | final Character[] cdata = new Character[]{'A', 'B', 'C'};
49 |
50 | final JIArray array = new JIArray(ddata, true);
51 | final JIVariant value = new JIVariant(array);
52 |
53 | System.out.println("============= PHASE 1 ============= ");
54 |
55 | // dump the value
56 | VariantDumper.dumpValue(value);
57 |
58 | System.out.println("============= PHASE 2 ============= ");
59 |
60 | // now write it to the item
61 | item.write(value);
62 | Thread.sleep(2500);
63 |
64 | System.out.println("============= PHASE 3 ============= ");
65 |
66 | // now read the value back and dump it
67 | final ItemState itemState = item.read(true);
68 | VariantDumper.dumpValue(itemState.getValue());
69 |
70 | System.out.println("============= PHASE 4 ============= ");
71 |
72 | // and write the value just read in
73 | item.write(itemState.getValue());
74 |
75 | System.out.println("============= COMPLETE ============= ");
76 | } catch (final JIException e) {
77 | System.out.println(String.format("%08X: %s", e.getErrorCode(), server.getErrorMessage(e.getErrorCode())));
78 | }
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/opc-core-lib/src/test/java/cn/com/sgcc/gdt/opc/lib/da/demo/OPCTest8.java:
--------------------------------------------------------------------------------
1 | package cn.com.sgcc.gdt.opc.lib.da.demo;
2 |
3 | import cn.com.sgcc.gdt.opc.core.dcom.list.ClassDetails;
4 | import cn.com.sgcc.gdt.opc.lib.list.Categories;
5 | import cn.com.sgcc.gdt.opc.lib.list.Category;
6 | import cn.com.sgcc.gdt.opc.lib.list.ServerList;
7 | import org.jinterop.dcom.common.JIException;
8 |
9 | import java.util.Collection;
10 |
11 | public class OPCTest8 {
12 | protected static void showDetails(final ServerList serverList, final String clsid) throws JIException {
13 | final ClassDetails cd = serverList.getDetails(clsid);
14 | if (cd != null) {
15 | System.out.println(cd.getProgId() + " = " + cd.getDescription());
16 | } else {
17 | System.out.println("unknown");
18 | }
19 | }
20 |
21 | public static void main(final String[] args) throws Throwable {
22 | final ServerList serverList = new ServerList(args[0], args[2], args[3], args[1]);
23 |
24 | final String cls = serverList.getClsIdFromProgId("Matrikon.OPC.Simulation.1");
25 | System.out.println("Matrikon OPC Simulation Server: " + cls);
26 | showDetails(serverList, cls);
27 |
28 | final Collection detailsList = serverList.listServersWithDetails(new Category[]{Categories.OPCDAServer20}, new Category[]{});
29 |
30 | for (final ClassDetails details : detailsList) {
31 | System.out.println(String.format("Found: %s", details.getClsId()));
32 | System.out.println(String.format("\tProgID: %s", details.getProgId()));
33 | System.out.println(String.format("\tDescription: %s", details.getDescription()));
34 | }
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/opc-core-lib/src/test/java/cn/com/sgcc/gdt/opc/lib/da/demo/OPCTestInfo.java:
--------------------------------------------------------------------------------
1 | package cn.com.sgcc.gdt.opc.lib.da.demo;
2 |
3 | import cn.com.sgcc.gdt.opc.lib.common.ConnectionInformation;
4 | import cn.com.sgcc.gdt.opc.lib.da.AccessBase;
5 | import cn.com.sgcc.gdt.opc.lib.da.Server;
6 |
7 | class OPCTestInfo {
8 | ConnectionInformation _info = null;
9 |
10 | String _itemId = null;
11 |
12 | Server _server = null;
13 |
14 | AccessBase _access = null;
15 | }
16 |
--------------------------------------------------------------------------------
/opc-core-lib/src/test/java/cn/com/sgcc/gdt/opc/lib/da/demo/VariantDumper.java:
--------------------------------------------------------------------------------
1 | package cn.com.sgcc.gdt.opc.lib.da.demo;
2 |
3 | import org.jinterop.dcom.common.JIException;
4 | import org.jinterop.dcom.core.JIArray;
5 | import org.jinterop.dcom.core.JIFlags;
6 | import org.jinterop.dcom.core.JIString;
7 | import org.jinterop.dcom.core.JIVariant;
8 |
9 | public class VariantDumper {
10 |
11 | static protected void dumpArray(final String prefix, final JIArray array) throws JIException {
12 | System.out.println(prefix + String.format("IsConformant: %s, IsVarying: %s", array.isConformant() ? "yes" : "no", array.isVarying() ? "yes" : "no"));
13 | System.out.println(prefix + String.format("Dimensions: %d", array.getDimensions()));
14 | for (int i = 0; i < array.getDimensions(); i++) {
15 | System.out.println(prefix + String.format("Dimension #%d: Upper Bound: %d", i, array.getUpperBounds()[i]));
16 | }
17 |
18 | final Object o = array.getArrayInstance();
19 | System.out.println(prefix + "Array Instance: " + o.getClass());
20 | final Object[] a = (Object[]) o;
21 | System.out.println(prefix + "Array Size: " + a.length);
22 |
23 | for (final Object value : a) {
24 | dumpValue(prefix + "\t", value);
25 | }
26 | }
27 |
28 | static public void dumpValue(final Object value) throws JIException {
29 | dumpValue("", value);
30 | }
31 |
32 | static protected void dumpValue(final String prefix, final Object value) throws JIException {
33 | if (value instanceof JIVariant) {
34 | System.out.println(prefix + "JIVariant");
35 | final JIVariant variant = (JIVariant) value;
36 | System.out.println(prefix + String.format("IsArray: %s, IsByRef: %s, IsNull: %s", variant.isArray() ? "yes" : "no", variant.isByRefFlagSet() ? "yes" : "no", variant.isNull() ? "yes" : "no"));
37 |
38 | if (variant.isArray()) {
39 | dumpArray(prefix, variant.getObjectAsArray());
40 | } else {
41 | dumpValue(prefix + "\t", variant.getObject());
42 | }
43 | } else if (value instanceof JIString) {
44 | final JIString string = (JIString) value;
45 |
46 | String strType;
47 | switch (string.getType()) {
48 | case JIFlags.FLAG_REPRESENTATION_STRING_BSTR:
49 | strType = "BSTR";
50 | break;
51 | case JIFlags.FLAG_REPRESENTATION_STRING_LPCTSTR:
52 | strType = "LPCSTR";
53 | break;
54 | case JIFlags.FLAG_REPRESENTATION_STRING_LPWSTR:
55 | strType = "LPWSTR";
56 | break;
57 | default:
58 | strType = "unknown";
59 | break;
60 | }
61 | System.out.println(prefix + String.format("JIString: '%s' (%s)", string.getString(), strType));
62 | } else if (value instanceof Double) {
63 | System.out.println(prefix + "Double: " + value);
64 | } else if (value instanceof Float) {
65 | System.out.println(prefix + "Float: " + value);
66 | } else if (value instanceof Byte) {
67 | System.out.println(prefix + "Byte: " + value);
68 | } else if (value instanceof Character) {
69 | System.out.println(prefix + "Character: " + value);
70 | } else if (value instanceof Integer) {
71 | System.out.println(prefix + "Integer: " + value);
72 | } else if (value instanceof Short) {
73 | System.out.println(prefix + "Short: " + value);
74 | } else if (value instanceof Long) {
75 | System.out.println(prefix + "Long: " + value);
76 | } else if (value instanceof Boolean) {
77 | System.out.println(prefix + "Boolean: " + value);
78 | } else {
79 | System.out.println(prefix + String.format("Unknown value type (%s): %s", value.getClass(), value.toString()));
80 | }
81 | }
82 |
83 | }
84 |
--------------------------------------------------------------------------------
/opc-da-client/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 | opc-da
7 | cn.com.sgcc.gdt
8 | 0.0.1-SNAPSHOT
9 |
10 | 4.0.0
11 |
12 | opc-da-client
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 | cn.com.sgcc.gdt
42 | opc-core-dcom
43 | 0.0.1-SNAPSHOT
44 |
45 |
46 |
47 | cn.com.sgcc.gdt
48 | opc-core-lib
49 | 0.0.1-SNAPSHOT
50 |
51 |
52 |
53 |
54 | com.alibaba
55 | fastjson
56 | 1.2.39
57 |
58 |
59 |
60 | org.slf4j
61 | slf4j-api
62 | 1.7.25
63 |
64 |
65 |
--------------------------------------------------------------------------------
/opc-da-client/src/main/java/cn/com/sgcc/gdt/opc/client/Browser.java:
--------------------------------------------------------------------------------
1 | package cn.com.sgcc.gdt.opc.client;
2 |
3 | import cn.com.sgcc.gdt.opc.client.bean.DataItem;
4 | import cn.com.sgcc.gdt.opc.client.bean.ServerInfo;
5 | import cn.com.sgcc.gdt.opc.client.utils.DateUtil;
6 | import cn.com.sgcc.gdt.opc.client.utils.JiVariantUtil;
7 | import cn.com.sgcc.gdt.opc.core.dcom.list.ClassDetails;
8 | import cn.com.sgcc.gdt.opc.lib.common.NotConnectedException;
9 | import cn.com.sgcc.gdt.opc.lib.da.Group;
10 | import cn.com.sgcc.gdt.opc.lib.da.Item;
11 | import cn.com.sgcc.gdt.opc.lib.da.ItemState;
12 | import cn.com.sgcc.gdt.opc.lib.da.Server;
13 | import cn.com.sgcc.gdt.opc.lib.da.exception.AddFailedException;
14 | import cn.com.sgcc.gdt.opc.lib.da.exception.DuplicateGroupException;
15 | import cn.com.sgcc.gdt.opc.lib.list.Categories;
16 | import cn.com.sgcc.gdt.opc.lib.list.Category;
17 | import cn.com.sgcc.gdt.opc.lib.list.ServerList;
18 | import lombok.extern.slf4j.Slf4j;
19 | import org.jinterop.dcom.common.JIException;
20 | import org.jinterop.dcom.core.JIVariant;
21 |
22 | import java.net.UnknownHostException;
23 | import java.util.*;
24 | import java.util.concurrent.ScheduledExecutorService;
25 | import java.util.concurrent.TimeUnit;
26 |
27 | /**
28 | * 客户端浏览
29 | *
30 | * @author ck.yang
31 | */
32 | @Slf4j
33 | public class Browser {
34 |
35 | private Browser(){}
36 |
37 | public static List readSync(Server server, Collection itemIds){
38 | //TODO 同步读取数据
39 | try {
40 | Group group = server.addGroup();
41 | Map itemMap = group.addItems(itemIds.toArray(new String[0]));
42 | List result = new ArrayList<>();
43 | for(Map.Entry entry: itemMap.entrySet()){
44 | Item item = entry.getValue();
45 | ItemState itemState = item.read(false);
46 | DataItem dataItem = JiVariantUtil.parseValue(item.getId(), itemState);
47 | result.add(dataItem);
48 | }
49 | // group.clear();
50 | // server.removeGroup(group,false);
51 | return result;
52 | } catch (Exception e) {
53 | log.error("同步读取失败!", e);
54 | return null;
55 | }
56 | }
57 |
58 | public static List readSync(Server server){
59 | try {
60 | return readSync(server, browseItemIds(server));
61 | } catch (Throwable throwable) {
62 | log.error("同步读取失败!", throwable);
63 | return null;
64 | }
65 | }
66 | /**
67 | * 异步读取数据(可指定节点)
68 | * @param server OPC服务
69 | * @param itemIds 节点编号集合
70 | * @param threadPool 线程池
71 | * @param heartBeat 心跳时间:小于0表示只接收一次,大于0则表示循环接收
72 | * @param dataCallback 数据接收后的回调处理
73 | * @throws Throwable
74 | */
75 | public static void readAsyn(Server server, Collection itemIds, ScheduledExecutorService threadPool, long heartBeat,DataCallback dataCallback) throws Throwable {
76 | Group group = server.addGroup();
77 | Map items = group.addItems(itemIds.toArray(new String[0]));
78 |
79 | Runnable runnable = ()->{
80 | try {
81 | List dataList = new ArrayList<>();
82 | for(Map.Entry entry: items.entrySet()){
83 | ItemState read = entry.getValue().read(false);
84 | //转换格式并添加到结果
85 | dataList.add(JiVariantUtil.parseValue(entry.getKey(), read));
86 | }
87 | //数据处理器回调
88 | dataCallback.process(dataList);
89 | } catch (Throwable e) {
90 | log.error("读取数据时发生异常!", e);
91 | }
92 |
93 | };
94 | //如果心跳时间为 -1,则表示不循环查询
95 | if(heartBeat <= 0L){
96 | threadPool.submit(runnable);
97 | }else{
98 | threadPool.scheduleAtFixedRate(runnable, 1,heartBeat, TimeUnit.MILLISECONDS);
99 | }
100 |
101 | }
102 |
103 | /**
104 | * 异步读取数据(查询所有节点,重复查询)
105 | * 该方法仅调用 {@link Browser#readAsyn(Server, Collection, ScheduledExecutorService, long, DataCallback)}
106 | * @param server OPC服务
107 | * @param threadPool 线程池
108 | * @param heartBeat 重复查询的心跳时间
109 | * @param dataCallback 接收到数据后的回调处理
110 | * @throws Throwable
111 | */
112 | public static void readAsyn(Server server, ScheduledExecutorService threadPool,long heartBeat, DataCallback dataCallback) throws Throwable {
113 | readAsyn(server, browseItemIds(server), threadPool, heartBeat, dataCallback);
114 | }
115 |
116 | /**
117 | * 异步读取数据(查询所有节点,只查询一次)
118 | * 该方法仅调用 {@link Browser#readAsyn(Server, Collection, ScheduledExecutorService, long, DataCallback)}
119 | * @param server OPC服务
120 | * @param threadPool 线程池
121 | * @param dataCallback 接收到数据后的回调处理
122 | * @throws Throwable
123 | */
124 | public static void readAsyn(Server server, ScheduledExecutorService threadPool, DataCallback dataCallback) throws Throwable {
125 | readAsyn(server, browseItemIds(server), threadPool, -1L, dataCallback);
126 | }
127 |
128 | public static void subscibe(Server server){
129 | //TODO 订阅指定数据,只有数据改变才会触发
130 |
131 | }
132 |
133 | /**
134 | * 获取所有节点的编号
135 | * @param server
136 | * @return
137 | * @throws Throwable
138 | */
139 | public static Collection browseItemIds(Server server) throws Throwable{
140 | Collection nodeIds = server.getFlatBrowser().browse();
141 | return nodeIds;
142 | }
143 |
144 | /**
145 | * 罗列出目标主机上的OPC服务器软件
146 | * @param host
147 | * @param domain
148 | * @param userName
149 | * @param password
150 | * @return
151 | * @throws Throwable
152 | */
153 | public static List listServer(String host, String domain, String userName, String password) throws Throwable {
154 | ServerList serverList = new ServerList(host, userName, password, domain);
155 | Collection classDetails = serverList.listServersWithDetails(new Category[]{Categories.OPCDAServer20}, new Category[]{});
156 | List serverInfos = new ArrayList<>();
157 | System.out.println("在目标主机上发现如下OPC服务器:");
158 | for(ClassDetails details: classDetails){
159 | serverInfos.add(new ServerInfo(details.getProgId(), details.getClsId(), details.getDescription()));
160 | System.out.format("\tprogId: '%s' \r\n\tclsId:'%s' \r\n\tdescription:'%s' \r\n\r\n", details.getProgId(), details.getClsId(), details.getClsId());
161 | }
162 | return serverInfos;
163 | }
164 |
165 | public static void browserServer(){
166 | //TODO 获取服务器的基本信息
167 | }
168 |
169 | /**
170 | * 处理结果数据的回调
171 | */
172 | public interface DataCallback{
173 | /**
174 | * 数据处理
175 | * @param dataItems
176 | * @throws Throwable
177 | */
178 | void process(List dataItems) throws Throwable;
179 | }
180 | }
181 |
--------------------------------------------------------------------------------
/opc-da-client/src/main/java/cn/com/sgcc/gdt/opc/client/Connecter.java:
--------------------------------------------------------------------------------
1 | package cn.com.sgcc.gdt.opc.client;
2 |
3 | import cn.com.sgcc.gdt.opc.core.dcom.da.bean.OpcServerState;
4 | import cn.com.sgcc.gdt.opc.lib.common.ConnectionInformation;
5 | import cn.com.sgcc.gdt.opc.lib.da.AutoReconnectController;
6 | import cn.com.sgcc.gdt.opc.lib.da.Server;
7 | import cn.com.sgcc.gdt.opc.lib.da.ServerConnectionStateListener;
8 | import lombok.extern.slf4j.Slf4j;
9 |
10 | import java.util.Optional;
11 | import java.util.concurrent.ScheduledExecutorService;
12 | import java.util.concurrent.TimeUnit;
13 |
14 | /**
15 | * 服务器连接
16 | *
17 | * @author ck.yang
18 | */
19 | @Slf4j
20 | public class Connecter {
21 |
22 | public final String name;
23 |
24 | private final Server server;
25 |
26 | private AutoReconnectController controller;
27 |
28 | private ServerConnectionStateListener listener;
29 |
30 | /**
31 | * 构造函数
32 | * @param connInfo 连接信息
33 | * @param scheduledExecutorService 任务线程池
34 | */
35 | public Connecter(ConnectionInformation connInfo, ScheduledExecutorService scheduledExecutorService) {
36 | //TODO 需要添加名称,以便区别不同的服务器
37 | name = "";
38 | server = new Server(connInfo, scheduledExecutorService);
39 | listener = connected -> {
40 | if(!connected){
41 | try {
42 | server.connect();
43 | } catch (Exception e) {
44 | log.error("监听到连接断开,尝试重连失败!");
45 | }
46 | }
47 | };
48 | }
49 |
50 | /**
51 | * 连接
52 | * @return
53 | * @throws Throwable
54 | */
55 | public Server connect() throws Throwable {
56 | server.connect();
57 | long connectTime = 10;
58 |
59 | while (connectTime-- >0){
60 | if(server!=null && server.getServerState()!=null && server.getServerState().getServerState()!=null){
61 | server.addStateListener(listener);
62 | return server;
63 | }else{
64 | TimeUnit.SECONDS.sleep(2);
65 | log.warn("尝试重新连接!");
66 | }
67 | }
68 | throw new NullPointerException("服务器连接失败!");
69 | }
70 |
71 | public Optional getServer() {
72 | return Optional.of(this.server);
73 | }
74 |
75 | /**
76 | * 断开连接
77 | */
78 | public void disconnect(){
79 | server.removeStateListener(listener);
80 | if(controller!=null){
81 | controller.disconnect();
82 | }
83 | if(server!=null){
84 | server.dispose();
85 | }
86 | }
87 |
88 | /**
89 | * 是否连接
90 | * @return
91 | */
92 | public boolean isConnect(){
93 | OpcServerState serverState = server.getServerState().getServerState();
94 | return OpcServerState.OPC_STATUS_RUNNING.equals(serverState) ? true : false;
95 | }
96 |
97 | @Override
98 | protected void finalize() throws Throwable {
99 | super.finalize();
100 | this.disconnect();
101 | System.out.println("已销毁连接!");
102 | }
103 | }
104 |
--------------------------------------------------------------------------------
/opc-da-client/src/main/java/cn/com/sgcc/gdt/opc/client/Writer.java:
--------------------------------------------------------------------------------
1 | package cn.com.sgcc.gdt.opc.client;
2 |
3 | /**
4 | * TODO
5 | *
6 | * @author ck.yang
7 | */
8 | public class Writer {
9 | }
10 |
--------------------------------------------------------------------------------
/opc-da-client/src/main/java/cn/com/sgcc/gdt/opc/client/bean/DataItem.java:
--------------------------------------------------------------------------------
1 | package cn.com.sgcc.gdt.opc.client.bean;
2 |
3 | import lombok.AllArgsConstructor;
4 | import lombok.Data;
5 | import lombok.NoArgsConstructor;
6 | import lombok.ToString;
7 |
8 | import java.io.Serializable;
9 | import java.util.Date;
10 |
11 | /**
12 | * 数据项
13 | * @author ck.yang
14 | */
15 | @Data
16 | @ToString
17 | @NoArgsConstructor
18 | @AllArgsConstructor
19 | public class DataItem implements Serializable {
20 | /** 数据主键 */
21 | private String itemId;
22 | /** 数据类型 */
23 | private String dataType;
24 | /** 数据值 */
25 | private Object value;
26 | /** 数据质量 */
27 | private Short quality;
28 | /** 数据时间 */
29 | private Date dataTime;
30 | /** 最近时刻 */
31 | private Date currMonment;
32 | }
33 |
--------------------------------------------------------------------------------
/opc-da-client/src/main/java/cn/com/sgcc/gdt/opc/client/bean/ServerInfo.java:
--------------------------------------------------------------------------------
1 | package cn.com.sgcc.gdt.opc.client.bean;
2 |
3 | import cn.com.sgcc.gdt.opc.core.dcom.list.ClassDetails;
4 | import lombok.*;
5 |
6 | import java.io.Serializable;
7 |
8 | /**
9 | * 服务器信息
10 | *
11 | * @author ck.yang
12 | */
13 | @Data
14 | @AllArgsConstructor
15 | @ToString
16 | @NoArgsConstructor
17 | @EqualsAndHashCode
18 | public class ServerInfo extends ClassDetails implements Serializable {
19 | private String progId;
20 | private String clsId;
21 | private String description;
22 | }
23 |
--------------------------------------------------------------------------------
/opc-da-client/src/main/java/cn/com/sgcc/gdt/opc/client/utils/DateFmt.java:
--------------------------------------------------------------------------------
1 | package cn.com.sgcc.gdt.opc.client.utils;
2 |
3 | import java.text.ParseException;
4 | import java.text.SimpleDateFormat;
5 | import java.util.Calendar;
6 | import java.util.Date;
7 |
8 | /**
9 | * 日期转换工具类
10 | *
11 | * @author Joy
12 | */
13 | public class DateFmt {
14 |
15 | public static final String date_long = "yyyy-MM-dd HH:mm:ss";
16 | public static final String date_short = "yyyy-MM-dd";
17 | public static final String date_minute = "yyyyMMddHHmm";
18 |
19 |
20 | public static SimpleDateFormat sdfDay = new SimpleDateFormat(date_short);
21 | public static SimpleDateFormat sdfSecond = new SimpleDateFormat(date_long);
22 |
23 | public static String getCountDate(String date, String patton) {
24 | SimpleDateFormat sdf = new SimpleDateFormat(patton);
25 | Calendar cal = Calendar.getInstance();
26 | if (date != null) {
27 | try {
28 | cal.setTime(sdf.parse(date));
29 | } catch (ParseException e) {
30 | e.printStackTrace();
31 | }
32 | }
33 | return sdf.format(cal.getTime());
34 | }
35 |
36 | /**
37 | * 格式化为:年-月-日 小时:分钟:秒
38 | * @param date
39 | * @return
40 | */
41 | public static String formateTime(Date date){
42 | return sdfSecond.format(date);
43 | }
44 |
45 | public static String getCountDate(String date, String patton, int step) {
46 | SimpleDateFormat sdf = new SimpleDateFormat(patton);
47 | Calendar cal = Calendar.getInstance();
48 | if (date != null) {
49 | try {
50 | cal.setTime(sdf.parse(date));
51 | } catch (ParseException e) {
52 | e.printStackTrace();
53 | }
54 | }
55 | cal.add(Calendar.DAY_OF_MONTH, step);
56 | return sdf.format(cal.getTime());
57 | }
58 |
59 | public static Date parseDate(String dateStr) throws Exception {
60 | try {
61 | return sdfDay.parse(dateStr);
62 | } catch (Exception e) {
63 | Calendar calendar = Calendar.getInstance();
64 | calendar.setTimeInMillis(Long.valueOf(dateStr));
65 | return calendar.getTime();
66 | }
67 | }
68 |
69 | public static void main(String[] args) throws Exception {
70 |
71 | // System.out.println(DateFmt.getCountDate("2014-03-01 12:13:14", DateFmt.date_short));
72 | System.out.println(parseDate("2014-05-02").after(parseDate("2014-05-01")));
73 | }
74 |
75 | /**
76 | * 将秒以下单位值为零
77 | * @param date
78 | * @return
79 | */
80 | public static Date resetSecond(Date date){
81 | Calendar calendar = Calendar.getInstance();
82 | calendar.setTime(date);
83 | calendar.set(Calendar.SECOND, 0);
84 | calendar.set(Calendar.MILLISECOND, 0);
85 | return calendar.getTime();
86 | }
87 | }
88 |
--------------------------------------------------------------------------------
/opc-da-client/src/main/java/cn/com/sgcc/gdt/opc/client/utils/DateUtil.java:
--------------------------------------------------------------------------------
1 | package cn.com.sgcc.gdt.opc.client.utils;
2 |
3 | import java.math.BigDecimal;
4 | import java.util.Calendar;
5 | import java.util.Date;
6 |
7 | /**
8 | * TODO
9 | *
10 | * @author ck
11 | */
12 | public class DateUtil {
13 |
14 | /**
15 | * 生成最近的时刻,即分钟是15的倍数
16 | * 如
17 | * 1. 当前9:22,则返回9:15
18 | * 2. 当前9:23,则返回9:30
19 | *
20 | * @return
21 | */
22 | public static Date getRecentMoment() {
23 | Calendar calendar = Calendar.getInstance();
24 | BigDecimal minute = BigDecimal.valueOf(calendar.get(Calendar.MINUTE));
25 | BigDecimal tag = BigDecimal.valueOf(15);
26 | BigDecimal resultMinute = minute.divide(tag, 0, BigDecimal.ROUND_HALF_UP).multiply(tag);
27 | calendar.set(Calendar.MINUTE, resultMinute.intValue());
28 | calendar.set(Calendar.SECOND, 0);
29 | calendar.set(Calendar.MILLISECOND, 0);
30 | return calendar.getTime();
31 | }
32 |
33 | /**
34 | * 获取当前时间
35 | * @return
36 | */
37 | public static String getCurrentTime(){
38 | return DateFmt.formateTime(Calendar.getInstance().getTime());
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/opc-da-client/src/main/java/cn/com/sgcc/gdt/opc/client/utils/JiVariantUtil.java:
--------------------------------------------------------------------------------
1 | package cn.com.sgcc.gdt.opc.client.utils;
2 |
3 | import cn.com.sgcc.gdt.opc.client.bean.DataItem;
4 | import cn.com.sgcc.gdt.opc.lib.da.ItemState;
5 | import lombok.extern.slf4j.Slf4j;
6 | import org.jinterop.dcom.core.*;
7 |
8 | import java.util.HashMap;
9 | import java.util.Map;
10 |
11 | /**
12 | * 格式数据转换工具
13 | *
14 | * @author ck.yang
15 | */
16 | @Slf4j
17 | public class JiVariantUtil {
18 | /** java的数值、对象、字符类型的前缀 */
19 | public static final String BASE_TYPE_PRDFIX = "java.lang";
20 | /** 时间类型的前缀 */
21 | public static final String DATE_TYPE_PRDFIX = "java.util";
22 |
23 | /**
24 | * 解析服务器返回的数据,转换为客户端格式的数据
25 | * @param itemId 数据主键
26 | * @param itemState
27 | * @return
28 | * @throws Exception
29 | */
30 | public static DataItem parseValue(String itemId, ItemState itemState) throws Exception{
31 | Map value = getValue(itemState.getValue());
32 | return new DataItem(
33 | itemId,
34 | value.get("type").toString(),
35 | value.get("value"),
36 | itemState.getQuality(),
37 | itemState.getTimestamp().getTime(),
38 | DateUtil.getRecentMoment()
39 | );
40 | }
41 |
42 | /**
43 | * 提取JIVariant的值,转换为java.lang下的对象
44 | *
45 | * JIVariant有如下的返回格式:
46 | * JIArray objectAsArray = jiVariant.getObjectAsArray();
47 | * IJIUnsigned objectAsUnsigned = jiVariant.getObjectAsUnsigned();
48 | * IJIComObject objectAsComObject = jiVariant.getObjectAsComObject();
49 | * JIVariant objectAsVariant = jiVariant.getObjectAsVariant();
50 | * JIString objectAsString = jiVariant.getObjectAsString();
51 | * @param jiVariant
52 | * @return
53 | * @throws Exception
54 | */
55 | public static Map getValue(JIVariant jiVariant) throws Exception{
56 | Object newValue ;
57 | Object oldValue = jiVariant.getObject();
58 | String typeName = oldValue.getClass().getTypeName();
59 | if(typeName.startsWith(BASE_TYPE_PRDFIX) || typeName.startsWith(DATE_TYPE_PRDFIX)){
60 | newValue = jiVariant.getObject();
61 | }else if(oldValue instanceof JIArray){
62 | newValue = jiVariant.getObjectAsArray();
63 | }else if(oldValue instanceof IJIUnsigned){
64 | newValue = jiVariant.getObjectAsUnsigned().getValue();
65 | }else if(oldValue instanceof IJIComObject){
66 | newValue = jiVariant.getObjectAsComObject();
67 | }else if(oldValue instanceof JIString){
68 | newValue = jiVariant.getObjectAsString().getString();
69 | }else if(oldValue instanceof JIVariant){
70 | newValue = jiVariant.getObjectAsVariant();
71 | }else{
72 | newValue = oldValue;
73 | log.error("无法解析服务器的数据类型'{}'!原始数据:{}", typeName, oldValue.toString());
74 | }
75 |
76 | HashMap result = new HashMap<>(2);
77 | result.put("type", newValue.getClass().getSimpleName());
78 | result.put("value", newValue);
79 | return result;
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/opc-da-client/src/test/java/cn/com/sgcc/gdt/opc/client/BrowserTest.java:
--------------------------------------------------------------------------------
1 | package cn.com.sgcc.gdt.opc.client;
2 |
3 | import cn.com.sgcc.gdt.opc.client.bean.ServerInfo;
4 | import org.junit.Assert;
5 | import org.junit.Test;
6 |
7 | import java.util.List;
8 |
9 | import static org.junit.Assert.*;
10 |
11 | /**
12 | * TODO
13 | *
14 | * @author ck
15 | */
16 | public class BrowserTest {
17 | @Test
18 | public void readAsyn() throws Exception {
19 | }
20 |
21 | @Test
22 | public void subscibe() throws Exception {
23 | }
24 |
25 | @Test
26 | public void browseItemIds() throws Exception {
27 | }
28 |
29 | @Test
30 | public void listServer() throws Throwable {
31 | List infos = Browser.listServer("192.168.2.254", "192.168.2.254", "Administrator", "GDTvm6.5");
32 | // for (ServerInfo info : infos) {
33 | // System.out.println(info);
34 | // }
35 | Assert.assertNotNull(infos);
36 | }
37 |
38 | @Test
39 | public void browserServer() throws Exception {
40 | }
41 |
42 | }
--------------------------------------------------------------------------------
/opc-da-client/src/test/java/cn/com/sgcc/gdt/opc/client/ConnecterTest.java:
--------------------------------------------------------------------------------
1 | package cn.com.sgcc.gdt.opc.client;
2 |
3 | import cn.com.sgcc.gdt.opc.lib.common.ConnectionInformation;
4 | import cn.com.sgcc.gdt.opc.lib.da.Server;
5 | import lombok.extern.slf4j.Slf4j;
6 | import org.junit.After;
7 | import org.junit.Before;
8 | import org.junit.Test;
9 |
10 | import java.util.concurrent.ScheduledExecutorService;
11 | import java.util.concurrent.ScheduledThreadPoolExecutor;
12 | import java.util.concurrent.TimeUnit;
13 |
14 | /**
15 | * TODO
16 | *
17 | * @author ck.yang
18 | */
19 | @Slf4j
20 | public class ConnecterTest {
21 | ScheduledExecutorService threadPool;
22 | ConnectionInformation connInfo;
23 | Connecter connecter;
24 | @Before
25 | public void before() throws Exception {
26 | threadPool = new ScheduledThreadPoolExecutor(5, r->{
27 | Thread thread = new Thread(r);
28 | thread.setDaemon(true);
29 | thread.setName("客户端-任务-" + thread.getId());
30 | thread.setUncaughtExceptionHandler((Thread t, Throwable e)->{
31 | log.error("'{}'发生异常!", t.getName(), e);
32 | });
33 | return thread;
34 | });
35 |
36 | connInfo = new ConnectionInformation();
37 | connInfo.setHost("192.168.2.254");
38 | connInfo.setUser("Administrator");
39 | connInfo.setPassword("GDTvm6.5");
40 |
41 | //kepware
42 | connInfo.setClsId("7BC0CC8E-482C-47CA-ABDC-0FE7F9C6E729");
43 | //ks.demo
44 | // connInfo.setClsid("B57C679B-665D-4BB0-9848-C5F2C4A6A280");
45 | //simulator
46 | // connInfo.setClsid("A879768C-7387-11D4-B0D8-009027242C59");
47 |
48 | // connInfo.setProgId("ICONICS.SimulatorOPCDA.2");//simulator
49 | }
50 |
51 | @After
52 | public void after() throws Exception {
53 | connecter.disconnect();
54 | threadPool.awaitTermination(5, TimeUnit.SECONDS);
55 | }
56 |
57 | @Test
58 | public void testRead() throws Exception {
59 | threadPool.submit(()->{
60 | try {
61 | connecter = new Connecter(connInfo, threadPool);
62 | Server server = connecter.connect();
63 |
64 | Browser.readAsyn(server, threadPool, 3000L, dataItems ->{
65 | System.out.println("读取结果:"+ dataItems);
66 | });
67 | } catch (Throwable t){
68 | log.error("客户端运行失败!", t);
69 | }
70 | }).get();
71 | }
72 | }
--------------------------------------------------------------------------------
/opc-da-client/src/test/java/cn/com/sgcc/gdt/opc/client/JITest.java:
--------------------------------------------------------------------------------
1 | package cn.com.sgcc.gdt.opc.client;
2 |
3 | import cn.com.sgcc.gdt.opc.core.dcom.common.impl.EnumString;
4 | import cn.com.sgcc.gdt.opc.core.dcom.da.bean.OpcEnumScope;
5 | import cn.com.sgcc.gdt.opc.core.dcom.da.impl.OPCGroupStateMgt;
6 | import cn.com.sgcc.gdt.opc.core.dcom.da.impl.OPCServer;
7 | import org.jinterop.dcom.common.JISystem;
8 | import org.jinterop.dcom.core.IJIComObject;
9 | import org.jinterop.dcom.core.JIClsid;
10 | import org.jinterop.dcom.core.JIComServer;
11 | import org.jinterop.dcom.core.JISession;
12 | import org.junit.Test;
13 |
14 | import java.util.concurrent.TimeUnit;
15 |
16 | /**
17 | * TODO
18 | *
19 | * @author ck
20 | */
21 | public class JITest {
22 |
23 | @Test
24 | public void testConnect() throws Exception {
25 | JISystem.setAutoRegisteration(true);
26 |
27 | /**
28 | * Session获取
29 | */
30 | JISession session = JISession.createSession("192.168.2.254", "Administrator","GDTvm6.5");
31 |
32 | // final JIComServer comServer = new JIComServer(JIClsid.valueOf("7bc0cc8e-482c-47ca-abdc-0fe7f9c6e729"), "192.168.2.254",session);
33 | final JIComServer comServer = new JIComServer(JIClsid.valueOf("b57c679b-665d-4bb0-9848-c5f2c4a6a280"), "192.168.2.254",session);
34 | // final JIComServer comServer = new JIComServer(JIClsid.valueOf("a879768a-7387-11d4-b0d8-009027242c59"), "192.168.2.254",session);
35 |
36 | final IJIComObject serverObject = comServer.createInstance();
37 |
38 | OPCServer server = new OPCServer(serverObject);
39 |
40 | /**
41 | * 添加一个Group的信息
42 | */
43 | OPCGroupStateMgt group = server.addGroup("test", true, 100, 1234, 60,
44 | 0.0f, 1033);
45 |
46 | EnumString groups = server.getGroups(OpcEnumScope.OPC_ENUM_ALL);
47 | for (final String s : groups.asCollection()) {
48 | System.out.println("Group: " + s);
49 | }
50 |
51 | TimeUnit.SECONDS.sleep(3);
52 |
53 | // clean up
54 | server.removeGroup(group, true);
55 | JISession.destroySession(session);
56 | TimeUnit.SECONDS.sleep(3);
57 | group=null;
58 | server=null;
59 | session = null;
60 | System.gc();
61 |
62 |
63 | }
64 |
65 | @Test
66 | public void TestWMI() throws Exception {
67 | }
68 |
69 | /**
70 | * 通过Scope查找并遍历Groups的信息
71 | *
72 | * @param server
73 | * @param scope
74 | */
75 | // public static void enumerateGroups(OPCServer server,
76 | // OPCENUMSCOPE scope) throws Throwable{
77 | // System.out.println("Enum Groups: " + scope.toString());
78 | //
79 | // for (final String group : server.getGroups(scope).asCollection()) {
80 | // System.out.println("Group: " + group);
81 | // }
82 | // }
83 | }
84 |
--------------------------------------------------------------------------------
/opc-da-console/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 | opc-da
7 | cn.com.sgcc.gdt
8 | 0.0.1-SNAPSHOT
9 |
10 | 4.0.0
11 |
12 | opc-da-console
13 |
14 |
15 | UTF-8
16 | UTF-8
17 | 1.8
18 |
19 |
20 |
21 |
22 |
23 | org.springframework.boot
24 | spring-boot-dependencies
25 | ${spring.version}
26 | pom
27 | import
28 |
29 |
30 |
31 | org.springframework.boot
32 | spring-boot-starter
33 | ${spring.version}
34 |
35 |
36 |
37 | org.springframework.boot
38 | spring-boot-starter-tomcat
39 |
40 |
41 |
42 |
43 |
44 | org.springframework.boot
45 | spring-boot-starter-test
46 | ${spring.version}
47 | test
48 |
49 |
50 | org.springframework.kafka
51 | spring-kafka
52 | 2.1.4.RELEASE
53 |
54 |
55 |
56 | cn.com.sgcc.gdt
57 | opc-da-client
58 | 0.0.1-SNAPSHOT
59 |
60 |
61 |
62 |
63 |
64 |
65 | org.springframework.boot
66 | spring-boot-maven-plugin
67 | 2.0.0.RELEASE
68 |
69 | true
70 | cn.com.sgcc.gdt.opc.console.OpcDaApplication
71 |
72 |
73 |
74 |
75 | repackage
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
--------------------------------------------------------------------------------
/opc-da-console/src/main/java/cn/com/sgcc/gdt/opc/console/ClientRunner.java:
--------------------------------------------------------------------------------
1 | package cn.com.sgcc.gdt.opc.console;
2 |
3 | import cn.com.sgcc.gdt.opc.client.Browser;
4 | import cn.com.sgcc.gdt.opc.client.Connecter;
5 | import cn.com.sgcc.gdt.opc.client.bean.DataItem;
6 | import cn.com.sgcc.gdt.opc.console.bean.ConnectInfo;
7 | import cn.com.sgcc.gdt.opc.console.config.ClientConfig;
8 | import cn.com.sgcc.gdt.opc.lib.da.Server;
9 | import com.alibaba.fastjson.JSONArray;
10 | import lombok.extern.slf4j.Slf4j;
11 | import org.springframework.beans.factory.annotation.Autowired;
12 | import org.springframework.kafka.core.KafkaTemplate;
13 | import org.springframework.scheduling.annotation.Scheduled;
14 | import org.springframework.stereotype.Component;
15 | import org.springframework.util.StringUtils;
16 |
17 | import javax.annotation.PostConstruct;
18 | import javax.annotation.PreDestroy;
19 | import java.util.Collection;
20 | import java.util.List;
21 | import java.util.Map;
22 | import java.util.Optional;
23 | import java.util.concurrent.ConcurrentHashMap;
24 | import java.util.concurrent.ConcurrentMap;
25 | import java.util.concurrent.ScheduledExecutorService;
26 | import java.util.stream.Collectors;
27 | import java.util.stream.Stream;
28 |
29 | /**
30 | * TODO
31 | *
32 | * @author ck.yang
33 | */
34 | @Component
35 | @Slf4j
36 | public class ClientRunner {
37 | /** 客户端所有操作的线程池 */
38 | @Autowired
39 | ScheduledExecutorService scheduledPool;
40 |
41 | /** 配置文件中的信息 */
42 | @Autowired
43 | ClientConfig clientConfig;
44 |
45 | /** 并发的Map,key为连接的编号(即类ServerInfo中的id),存储客户端连接,以便逐个连接与释放 */
46 | ConcurrentMap connecterMap = new ConcurrentHashMap<>();
47 |
48 | @Autowired
49 | KafkaTemplate kafkaTemplate;
50 |
51 | // @PostConstruct
52 | public void init() throws Throwable {
53 | for(String runId : clientConfig.getRunServerId()){
54 | this.connect(runId);
55 | // this.read(runId);
56 | }
57 | }
58 |
59 | /**
60 | * 获取指定的服务器连接
61 | * @param serverId 服务器唯一标识
62 | * @return
63 | */
64 | private ConnectInfo getServerInfo(String serverId){
65 | for(ConnectInfo info: clientConfig.getServers()){
66 | if(info.getId().equals(serverId)){
67 | return info;
68 | }
69 | }
70 | return new ConnectInfo();
71 | }
72 |
73 | /**
74 | * 连接服务器
75 | * @param serverId 服务器唯一标识
76 | * @throws Throwable
77 | */
78 | public void connect(String serverId) throws Throwable {
79 | if(connecterMap.containsKey(serverId) && connecterMap.get(serverId).isConnect()){
80 | log.info("服务器似乎正常运行,无需重连!");
81 | return;
82 | }else {
83 | connecterMap.remove(serverId);
84 | }
85 | Optional serverInfo = Optional.of(getServerInfo(serverId));
86 | Connecter connecter = new Connecter(serverInfo.get(), scheduledPool);
87 | connecter.connect();
88 | connecterMap.put(serverId, connecter);
89 | log.info("服务器已连接!");
90 | }
91 |
92 | /**
93 | * 断开指定的服务器
94 | * @param serverId 服务器唯一标识
95 | */
96 | public void disconnect(String serverId){
97 | Optional connecter = Optional.of(connecterMap.get(serverId));
98 | connecter.get().disconnect();
99 | connecterMap.remove(serverId);
100 | log.info("开始断开连接...");
101 | }
102 |
103 | /**
104 | * 到指定的服务器上读取节点数据
105 | * @param serverId 服务器唯一标识
106 | * @throws Throwable
107 | */
108 | public void read(String serverId) throws Throwable {
109 | Optional connecter = Optional.of(connecterMap.get(serverId));
110 | Server server = connecter.get().getServer().get();
111 | ConnectInfo serverInfo = this.getServerInfo(serverId);
112 | String topic = serverInfo.getTopic();
113 | Browser.readAsyn(server, scheduledPool, serverInfo.getHeartbeat(), (List dataItems)->{
114 | String data = JSONArray.toJSON(dataItems).toString();
115 | kafkaTemplate.send(topic, data).get();
116 | log.info("主题'{}'已发送!,详情:{}", topic, data);
117 | });
118 |
119 | }
120 |
121 | @Scheduled(cron = "0 0,15,30,45 * ? * *")
122 | public void regularSend(){
123 |
124 | try {
125 |
126 | for(ConcurrentMap.Entry entry: connecterMap.entrySet()){
127 | String serverId = entry.getKey();
128 | Connecter connecter = entry.getValue();
129 | Server server = connecter.getServer().get();
130 | ConnectInfo serverInfo = this.getServerInfo(serverId);
131 | String topic = serverInfo.getTopic();
132 | //过滤数据
133 | List itemIds = Browser.browseItemIds(server).stream().filter(item -> {
134 | String profix = clientConfig.getItems().getOrDefault("profix", "");
135 | String exclusion = clientConfig.getItems().get("exclusion");
136 | if(StringUtils.isEmpty(exclusion)){
137 | return item.startsWith(profix);
138 | }else{
139 | return item.startsWith(profix)&&!item.contains(exclusion);
140 | }
141 | }).collect(Collectors.toList());
142 |
143 | List dataItems = Browser.readSync(server, itemIds);
144 | if(dataItems!=null && dataItems.size()>0){
145 | String data = JSONArray.toJSON(dataItems).toString();
146 | kafkaTemplate.send(topic, data);
147 | log.info("主题'{}'已发送{}条!", topic,dataItems.size());
148 | } else {
149 | log.warn("主题'{}'无数据!", topic);
150 | }
151 | }
152 | } catch (Throwable throwable) {
153 | throwable.printStackTrace();
154 | }
155 |
156 |
157 | }
158 |
159 | /**
160 | * 关闭连接
161 | */
162 | @PreDestroy
163 | public void preDestory() {
164 | if(!connecterMap.isEmpty()){
165 | connecterMap.forEach((id, connecter)->{
166 | connecter.disconnect();
167 | });
168 | }
169 | }
170 | }
171 |
--------------------------------------------------------------------------------
/opc-da-console/src/main/java/cn/com/sgcc/gdt/opc/console/OpcDaApplication.java:
--------------------------------------------------------------------------------
1 | package cn.com.sgcc.gdt.opc.console;
2 |
3 | import cn.com.sgcc.gdt.opc.client.Browser;
4 | import cn.com.sgcc.gdt.opc.console.config.BeanTools;
5 | import cn.com.sgcc.gdt.opc.console.config.ClientConfig;
6 | import org.springframework.boot.SpringApplication;
7 | import org.springframework.boot.autoconfigure.SpringBootApplication;
8 | import org.springframework.scheduling.annotation.EnableScheduling;
9 |
10 | import java.util.concurrent.ExecutionException;
11 | import java.util.concurrent.TimeUnit;
12 |
13 | /**
14 | * 程序入口
15 | * @author ck
16 | */
17 | @SpringBootApplication
18 | @EnableScheduling
19 | public class OpcDaApplication {
20 |
21 | public static void main(String[] args) throws Throwable {
22 | SpringApplication.run(OpcDaApplication.class, args);
23 | //列出目标主机上的所有服务
24 | ClientConfig clientConfig = BeanTools.getBean(ClientConfig.class);
25 | Browser.listServer(clientConfig.getServers().get(0).getHost(), clientConfig.getServers().get(0).getHost(), clientConfig.getServers().get(0).getUser(), clientConfig.getServers().get(0).getPassword());
26 | ClientRunner runner = BeanTools.getBean(ClientRunner.class);
27 | runner.init();
28 | Browser.browserServer();
29 | TimeUnit.DAYS.sleep(999999999L);
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/opc-da-console/src/main/java/cn/com/sgcc/gdt/opc/console/bean/ConnectInfo.java:
--------------------------------------------------------------------------------
1 | package cn.com.sgcc.gdt.opc.console.bean;
2 |
3 | import cn.com.sgcc.gdt.opc.lib.common.ConnectionInformation;
4 | import lombok.AllArgsConstructor;
5 | import lombok.Data;
6 | import lombok.NoArgsConstructor;
7 | import lombok.ToString;
8 |
9 | /**
10 | * 连接服务器的信息
11 | *
12 | * @author ck.yang
13 | */
14 | @Data
15 | @ToString
16 | @NoArgsConstructor
17 | @AllArgsConstructor
18 | public class ConnectInfo extends ConnectionInformation {
19 | private String id;
20 | /**服务器IP地址:默认为 localhost*/
21 | private String host = "localhost";
22 | /** 服务器主机所在域:默认为localhost*/
23 | private String domain = "localhost";
24 | /** 服务器主机密码:默认为 Administrator */
25 | private String user = "Administrator";
26 | /** 服务器的密码:默认为 null */
27 | private String password;
28 | /** 服务器软件唯一标识:默认为null */
29 | private String clsId;
30 | /** 服务器软件id:默认为null */
31 | private String progId;
32 | /** 数据刷新超时时间:默认为1000L ms */
33 | private Long timeout = 1000L;
34 | /** 数据刷新时间:默认为1000L ms */
35 | private Long heartbeat = 1000L;
36 | /** kafka消息队列的主题 */
37 | private String topic;
38 | }
39 |
--------------------------------------------------------------------------------
/opc-da-console/src/main/java/cn/com/sgcc/gdt/opc/console/bean/ResultData.java:
--------------------------------------------------------------------------------
1 | package cn.com.sgcc.gdt.opc.console.bean;
2 |
3 | import lombok.AllArgsConstructor;
4 | import lombok.Data;
5 | import lombok.NoArgsConstructor;
6 | import lombok.ToString;
7 |
8 | import java.io.Serializable;
9 | import java.util.Date;
10 |
11 | /**
12 | * TODO
13 | *
14 | * @author ck
15 | */
16 | @Data
17 | @ToString
18 | @AllArgsConstructor
19 | @NoArgsConstructor
20 | public class ResultData implements Serializable {
21 | private String msNo;
22 | private String indi;
23 | private Double rval;
24 | private Date dataDate;
25 |
26 | }
27 |
--------------------------------------------------------------------------------
/opc-da-console/src/main/java/cn/com/sgcc/gdt/opc/console/config/BeanTools.java:
--------------------------------------------------------------------------------
1 | package cn.com.sgcc.gdt.opc.console.config;
2 |
3 | import org.springframework.context.ApplicationContext;
4 | import org.springframework.context.ApplicationContextAware;
5 | import org.springframework.context.annotation.Configuration;
6 |
7 | /**
8 | * TODO
9 | *
10 | * @author ck
11 | */
12 | @Configuration
13 | public class BeanTools implements ApplicationContextAware {
14 | private static ApplicationContext applicationContext;
15 |
16 | @Override
17 | public void setApplicationContext(ApplicationContext context) {
18 | applicationContext = context;
19 | }
20 |
21 | public static T getBean(Class classname) {
22 | return applicationContext.getBean(classname);
23 | }
24 |
25 | public static void setApplicationContext1(ApplicationContext context) {
26 | applicationContext = context;
27 | }
28 | }
--------------------------------------------------------------------------------
/opc-da-console/src/main/java/cn/com/sgcc/gdt/opc/console/config/ClientConfig.java:
--------------------------------------------------------------------------------
1 | package cn.com.sgcc.gdt.opc.console.config;
2 |
3 | import cn.com.sgcc.gdt.opc.console.bean.ConnectInfo;
4 | import lombok.Data;
5 | import lombok.extern.slf4j.Slf4j;
6 | import org.springframework.boot.context.properties.ConfigurationProperties;
7 | import org.springframework.context.annotation.Bean;
8 | import org.springframework.context.annotation.Configuration;
9 | import org.springframework.dao.DuplicateKeyException;
10 |
11 | import java.util.ArrayList;
12 | import java.util.List;
13 | import java.util.Map;
14 | import java.util.concurrent.ScheduledExecutorService;
15 | import java.util.concurrent.ScheduledThreadPoolExecutor;
16 |
17 | /**
18 | * TODO
19 | *
20 | * @author ck.yang
21 | */
22 | @Configuration
23 | @ConfigurationProperties(prefix = "opc")
24 | @Slf4j
25 | @Data
26 | public class ClientConfig {
27 |
28 | /** 配置文件中的服务器信息 */
29 | private List servers;
30 | /** 开机即连接的服务 */
31 | private List runServerId;
32 |
33 | private Map items;
34 |
35 | public void setServers(List servers) {
36 | List ids = new ArrayList<>();
37 | servers.forEach(serverConfig -> {
38 | if(serverConfig.getId()==null || ids.contains(serverConfig.getId())){
39 | //duplicate
40 | throw new DuplicateKeyException("OPC配置文件中的'id'不能为空,也不可重复!");
41 | }else {
42 | ids.add(serverConfig.getId());
43 | }
44 | });
45 | this.servers = servers;
46 | }
47 |
48 | @Bean
49 | public ScheduledExecutorService getScheduledExecutorService(){
50 |
51 | return new ScheduledThreadPoolExecutor(5, (r) -> {
52 | Thread thread = new Thread(r);
53 | thread.setDaemon(true);
54 | thread.setName("客户端任务-" + thread.getId());
55 | thread.setUncaughtExceptionHandler((Thread t, Throwable e) -> {
56 | log.error("'{}'发生异常!", t.getName(), e);
57 | });
58 | return thread;
59 | });
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/opc-da-console/src/main/java/cn/com/sgcc/gdt/opc/console/utils/ParserUtil.java:
--------------------------------------------------------------------------------
1 | package cn.com.sgcc.gdt.opc.console.utils;
2 |
3 | /**
4 | * TODO
5 | *
6 | * @author ck
7 | */
8 | public class ParserUtil {
9 |
10 | }
11 |
--------------------------------------------------------------------------------
/opc-da-console/src/main/resources/application-dev.yml:
--------------------------------------------------------------------------------
1 | # OPC 连接服务的配置
2 | # 配置progId与clsid可参考以下内容:
3 | #
4 | # 1、Knight.OPC.Server.Demo
5 | # progId: Knight.OPC.Server.Demo
6 | # clsid: B57C679B-665D-4BB0-9848-C5F2C4A6A280
7 | #
8 | # 2、Kepware
9 | # progId: Kepware.KEPServerEX.V6
10 | # clsid: 7BC0CC8E-482C-47CA-ABDC-0FE7F9C6E729
11 | #
12 | # 3、Simulator
13 | # progId: ICONICS.SimulatorOPCDA.2
14 | # clsid: a879768a-7387-11d4-b0d8-009027242c59
15 |
16 | opc:
17 | runServerId: [2]
18 | items:
19 | #前缀
20 | profix:
21 | #排除内容
22 | exclusion: _
23 | servers:
24 | - id: 1
25 | host: 192.168.2.254
26 | domain: 192.168.2.254
27 | user: Administrator
28 | password: GDTvm6.5
29 | progId: Knight.OPC.Server.Demo
30 | clsId: B57C679B-665D-4BB0-9848-C5F2C4A6A280
31 | timeout: 5000
32 | heartbeat: 900000
33 | topic: opc
34 |
35 | - id: 2
36 | host: 192.168.2.254
37 | domain: 192.168.2.254
38 | user: Administrator
39 | password: GDTvm6.5
40 | progId: Kepware.KEPServerEX.V6
41 | clsId: 7BC0CC8E-482C-47CA-ABDC-0FE7F9C6E729
42 | timeout: 5000
43 | heartbeat: 900000
44 | topic: opc
45 |
46 | - id: 3
47 | host: 192.168.2.254
48 | domain: 192.168.2.254
49 | user: Administrator
50 | password: GDTvm6.5
51 | progId: ICONICS.SimulatorOPCDA.2
52 | clsId: a879768a-7387-11d4-b0d8-009027242c59
53 | timeout: 5000
54 | heartbeat: 3000
55 | topic: opc
56 |
57 | # kafka生产者配置
58 | spring:
59 | kafka:
60 | bootstrap-servers: 192.168.2.147:9092,192.168.2.148:9092,192.168.2.149:9092
61 | producer:
62 | # key和消息体的编/解码方式
63 | key-serializer: org.apache.kafka.common.serialization.StringSerializer
64 | value-serializer: org.apache.kafka.common.serialization.StringSerializer
--------------------------------------------------------------------------------
/opc-da-console/src/main/resources/application-pro.yml:
--------------------------------------------------------------------------------
1 | opc:
2 | server:
3 | host: 192.168.xxx.xxx
4 | #domain:
5 | username: user
6 | password: GDTvm6.5
7 | # kepware的CLSID
8 | clsId: 7BC0CC8E-482C-47CA-ABDC-0FE7F9C6E729
9 | #prgId:
10 | # 采集间隔时间 ms
11 | heartbeat: 1000
--------------------------------------------------------------------------------
/opc-da-console/src/main/resources/application.yml:
--------------------------------------------------------------------------------
1 | spring:
2 | profiles:
3 | # 切换开发/生产环境: dev/pro
4 | active: dev
5 |
6 |
--------------------------------------------------------------------------------
/opc-da-console/src/main/resources/banner.txt:
--------------------------------------------------------------------------------
1 | ________ ________ ___________ ________ __________ _________
2 | / _____/ \______ \ \__ ___/ \_____ \ \______ \ \_ ___ \
3 | / \ ___ | | \ | | ______ / | \ | ___/ / \ \/
4 | \ \_\ \ | ` \ | | /_____/ / | \ | | \ \____
5 | \______ / /_______ / |____| \_______ / |____| \______ /
6 | \/ \/ \/ \/
--------------------------------------------------------------------------------
/opc-da-console/src/test/java/cn/com/sgcc/gdt/opc/console/ClientRunnerTest.java:
--------------------------------------------------------------------------------
1 | package cn.com.sgcc.gdt.opc.console;
2 |
3 | import org.junit.After;
4 | import org.junit.Before;
5 | import org.junit.Test;
6 | import org.junit.runner.RunWith;
7 | import org.springframework.beans.factory.annotation.Autowired;
8 | import org.springframework.boot.test.context.SpringBootTest;
9 | import org.springframework.test.context.junit4.SpringRunner;
10 |
11 | /**
12 | * TODO
13 | *
14 | * @author ck.yang
15 | */
16 | @RunWith(SpringRunner.class)
17 | @SpringBootTest
18 | public class ClientRunnerTest {
19 |
20 | @Autowired
21 | ClientRunner clientRunner;
22 | String serverId = "2";
23 | @Before
24 | public void init() throws Throwable{
25 | clientRunner.connect(serverId);
26 | }
27 |
28 | @After
29 | public void destroy() throws Throwable{
30 | clientRunner.disconnect(serverId);
31 | }
32 |
33 | @Test
34 | public void testRead() throws Throwable{
35 | clientRunner.read(serverId);
36 | }
37 | }
--------------------------------------------------------------------------------
/opc-da-simple-reader/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 | opc-da
7 | cn.com.sgcc.gdt
8 | 0.0.1-SNAPSHOT
9 |
10 | 4.0.0
11 |
12 | opc-da-simple-reader
13 |
14 |
15 |
16 |
17 |
18 | org.projectlombok
19 | lombok
20 | 1.16.20
21 | provided
22 |
23 |
24 |
25 | cn.com.sgcc.gdt
26 | opc-core-dcom
27 | 0.0.1-SNAPSHOT
28 |
29 |
30 |
31 | cn.com.sgcc.gdt
32 | opc-core-lib
33 | 0.0.1-SNAPSHOT
34 |
35 |
36 |
37 |
38 | com.alibaba
39 | fastjson
40 | 1.2.39
41 |
42 |
43 |
44 |
45 | org.quartz-scheduler
46 | quartz
47 | 2.2.1
48 |
49 |
50 | org.quartz-scheduler
51 | quartz-jobs
52 | 2.2.1
53 |
54 |
55 |
--------------------------------------------------------------------------------
/opc-da-simple-reader/src/main/java/cn/com/sgcc/gdt/opc/da/simple/reader/MainApplication.java:
--------------------------------------------------------------------------------
1 | package cn.com.sgcc.gdt.opc.da.simple.reader;
2 | import cn.com.sgcc.gdt.opc.lib.common.ConnectionInformation;
3 | import cn.com.sgcc.gdt.opc.lib.da.Server;
4 | import org.quartz.*;
5 | import org.quartz.impl.StdSchedulerFactory;
6 |
7 | import java.util.Calendar;
8 | import java.util.List;
9 | import java.util.Properties;
10 |
11 | /**
12 | * TODO
13 | *
14 | * @author ck
15 | */
16 | public class MainApplication {
17 |
18 | public static void main(String[] ars) throws Throwable{
19 |
20 |
21 | List opcConfig = PropertiesUtil.getOpcConfig();
22 |
23 |
24 | //1.创建Scheduler的工厂
25 | StdSchedulerFactory schedulerFactory = new StdSchedulerFactory();
26 | //2.从工厂中获取调度器实例
27 | Scheduler scheduler = schedulerFactory.getScheduler();
28 | //3.创建JobDetail
29 | JobDetail jobDetail = JobBuilder.newJob(ReaderJob.class)
30 | .withDescription("OPC客户端读取任务")
31 | .withIdentity("readJob", "ReaderJobGroup").build();
32 | //4.创建Trigger
33 | //使用SimpleScheduleBuilder或者CronScheduleBuilder
34 | Trigger t = TriggerBuilder.newTrigger()
35 | .withDescription("")
36 | .withIdentity("readTrigger", "readerTriggerGroup")
37 | //.withSchedule(SimpleScheduleBuilder.simpleSchedule())
38 | //默认当前时间启动
39 | .startAt(Calendar.getInstance().getTime())
40 | //两秒执行一次
41 | .withSchedule(CronScheduleBuilder.cronSchedule("0/2 * * * * ?"))
42 | .build();
43 | //5.注册任务和定时器
44 | scheduler.scheduleJob(jobDetail, t);
45 | //6.启动 调度器
46 | scheduler.start();
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/opc-da-simple-reader/src/main/java/cn/com/sgcc/gdt/opc/da/simple/reader/PropertiesUtil.java:
--------------------------------------------------------------------------------
1 | package cn.com.sgcc.gdt.opc.da.simple.reader;
2 |
3 | import cn.com.sgcc.gdt.opc.lib.common.ConnectionInformation;
4 |
5 | import java.io.IOException;
6 | import java.io.InputStream;
7 | import java.util.ArrayList;
8 | import java.util.List;
9 | import java.util.Map;
10 | import java.util.Properties;
11 |
12 | /**
13 | * TODO
14 | *
15 | * @author ck
16 | */
17 | public class PropertiesUtil {
18 |
19 | /**
20 | * 加载配置文件
21 | * @param fileName 文件名
22 | * @return
23 | * @throws IOException
24 | */
25 | public static Properties loadProperties(String fileName) throws IOException {
26 | InputStream stream = PropertiesUtil.class.getClassLoader().getResourceAsStream(fileName);
27 | Properties properties = new Properties();
28 | properties.load(stream);
29 | return properties;
30 | }
31 |
32 | /**
33 | * 加载opc配置
34 | * @return
35 | */
36 | public static List getOpcConfig() throws IOException {
37 | Properties properties = loadProperties("opc.properties");
38 | String[] runProfixes = properties.getProperty("runProfix").split(",");
39 | List result = new ArrayList<>();
40 | for (String profix: runProfixes){
41 | String host = properties.getProperty(profix + "-host");
42 | String user = properties.getProperty(profix + "-user");
43 | String password = properties.getProperty(profix + "-password");
44 | String domain = properties.getProperty(profix + "-domain", host);
45 | String clsId = properties.getProperty(profix + "-clsId");
46 | String progId = properties.getProperty(profix + "-progId");
47 |
48 | ConnectionInformation connInfo = new ConnectionInformation(host, domain, user, password, clsId, progId);
49 | result.add(connInfo);
50 | }
51 | return result;
52 | }
53 |
54 | // dashi-host=192.168.2.254
55 | // dashi-user=Administrator
56 | // dashi-domain=192.168.2.254
57 | // dashi-clsId=7BC0CC8E-482C-47CA-ABDC-0FE7F9C6E729
58 | // dashi-progId=Kepware.KEPServerEX.V6
59 | // dashi-kafkaHost=192.168.2.254
60 | // dashi-kafkaTopic=opc
61 | }
62 |
--------------------------------------------------------------------------------
/opc-da-simple-reader/src/main/java/cn/com/sgcc/gdt/opc/da/simple/reader/ReaderJob.java:
--------------------------------------------------------------------------------
1 | package cn.com.sgcc.gdt.opc.da.simple.reader;
2 |
3 | import lombok.extern.slf4j.Slf4j;
4 | import org.quartz.Job;
5 | import org.quartz.JobExecutionContext;
6 | import org.quartz.JobExecutionException;
7 |
8 | /**
9 | * 读取数据的任务
10 | * @author ck
11 | */
12 | @Slf4j
13 | public class ReaderJob implements Job {
14 | @Override
15 | public void execute(JobExecutionContext context) throws JobExecutionException {
16 | log.info("执行定时任务!");
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/opc-da-simple-reader/src/main/java/cn/com/sgcc/gdt/opc/da/simple/reader/ScheduleUtil.java:
--------------------------------------------------------------------------------
1 | package cn.com.sgcc.gdt.opc.da.simple.reader;
2 |
3 | /**
4 | * TODO
5 | *
6 | * @author ck
7 | */
8 | public class ScheduleUtil {
9 |
10 | }
11 |
--------------------------------------------------------------------------------
/opc-da-simple-reader/src/main/resources/log4j.properties:
--------------------------------------------------------------------------------
1 | # Configure logging for testing: optionally with log file
2 |
3 | #log4j.rootLogger=debug,appender
4 | log4j.rootLogger=info,appender
5 | #log4j.rootLogger=error,appender
6 |
7 | #\u8F93\u51FA\u5230\u63A7\u5236\u53F0
8 | log4j.appender.appender=org.apache.log4j.ConsoleAppender
9 | #\u6837\u5F0F\u4E3ATTCCLayout
10 | log4j.appender.appender.layout=org.apache.log4j.TTCCLayout
--------------------------------------------------------------------------------
/opc-da-simple-reader/src/main/resources/opc.properties:
--------------------------------------------------------------------------------
1 | runProfix=dashi
2 |
3 | # ip地址
4 | dashi-host=192.168.2.254
5 | dashi-user=Administrator
6 | dashi-domain=192.168.2.254
7 | dashi-clsId=7BC0CC8E-482C-47CA-ABDC-0FE7F9C6E729
8 | dashi-progId=Kepware.KEPServerEX.V6
9 |
10 |
11 | kafkaHost=192.168.2.254
12 | kafkaTopic=opc
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 |
6 | cn.com.sgcc.gdt
7 | opc-da
8 | 0.0.1-SNAPSHOT
9 |
10 | opc-da-console
11 | opc-da-client
12 | opc-core-dcom
13 | opc-core-lib
14 | opc-da-simple-reader
15 |
16 | pom
17 |
18 | opc-da
19 | Demo project for Spring Boot
20 |
21 |
22 | UTF-8
23 | UTF-8
24 | 1.8
25 | 2.0.0.RELEASE
26 |
27 |
28 |
29 |
30 | aliyun
31 | http://maven.aliyun.com/nexus/content/groups/public
32 |
33 |
34 |
35 |
36 | utgard
37 | utgard releases
38 | http://repo.openscada.org/maven/releases/
39 |
40 |
41 |
42 |
43 |
44 | junit
45 | junit
46 | 4.12
47 | test
48 |
49 |
50 |
51 | org.projectlombok
52 | lombok
53 | 1.16.20
54 | provided
55 |
56 |
57 |
58 |
59 |
60 |
61 | org.slf4j
62 | slf4j-api
63 | 1.7.25
64 |
65 |
66 |
67 | com.alibaba
68 | fastjson
69 | 1.2.39
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 | org.springframework.boot
78 | spring-boot-maven-plugin
79 | 2.0.0.RELEASE
80 |
81 |
82 |
83 |
84 |
85 |
86 |
--------------------------------------------------------------------------------