├── .gitignore ├── README.MD ├── opc-core-dcom ├── pom.xml └── src │ └── main │ ├── java │ └── cn │ │ └── com │ │ └── sgcc │ │ └── gdt │ │ └── opc │ │ └── core │ │ └── dcom │ │ ├── common │ │ ├── Categories.java │ │ ├── EventHandler.java │ │ ├── bean │ │ │ ├── Constants.java │ │ │ ├── FILETIME.java │ │ │ ├── KeyedResult.java │ │ │ ├── KeyedResultSet.java │ │ │ ├── Result.java │ │ │ └── ResultSet.java │ │ └── impl │ │ │ ├── BaseCOMObject.java │ │ │ ├── EnumGUID.java │ │ │ ├── EnumString.java │ │ │ ├── EventHandlerImpl.java │ │ │ ├── Helper.java │ │ │ └── OPCCommon.java │ │ ├── da │ │ ├── IOPCDataCallback.java │ │ ├── bean │ │ │ ├── Constants.java │ │ │ ├── IORequest.java │ │ │ ├── OpcBrowseDirection.java │ │ │ ├── OpcBrowseType.java │ │ │ ├── OpcDatasource.java │ │ │ ├── OpcEnumScope.java │ │ │ ├── OpcGroupState.java │ │ │ ├── OpcItemDef.java │ │ │ ├── OpcItemResult.java │ │ │ ├── OpcItemState.java │ │ │ ├── OpcNamespaceType.java │ │ │ ├── OpcServerState.java │ │ │ ├── OpcServerStatus.java │ │ │ ├── PropertyDescription.java │ │ │ ├── ValueData.java │ │ │ └── WriteRequest.java │ │ └── impl │ │ │ ├── OPCAsyncIO2.java │ │ │ ├── OPCBrowse.java │ │ │ ├── OPCBrowseServerAddressSpace.java │ │ │ ├── OPCDataCallback.java │ │ │ ├── OPCGroupStateMgt.java │ │ │ ├── OPCItemIO.java │ │ │ ├── OPCItemMgt.java │ │ │ ├── OPCItemProperties.java │ │ │ ├── OPCServer.java │ │ │ └── OPCSyncIO.java │ │ └── list │ │ ├── ClassDetails.java │ │ ├── Constants.java │ │ └── impl │ │ └── OPCServerList.java │ └── resources │ └── progIdVsClsidDB.properties ├── opc-core-lib ├── pom.xml └── src │ ├── main │ └── java │ │ └── cn │ │ └── com │ │ └── sgcc │ │ └── gdt │ │ └── opc │ │ └── lib │ │ ├── common │ │ ├── AlreadyConnectedException.java │ │ ├── ConnectionInformation.java │ │ └── NotConnectedException.java │ │ ├── da │ │ ├── AccessBase.java │ │ ├── AccessStateListener.java │ │ ├── Async20Access.java │ │ ├── AutoReconnectController.java │ │ ├── AutoReconnectListener.java │ │ ├── AutoReconnectState.java │ │ ├── DataCallback.java │ │ ├── ErrorMessageResolver.java │ │ ├── Group.java │ │ ├── Item.java │ │ ├── ItemState.java │ │ ├── Server.java │ │ ├── ServerConnectionStateListener.java │ │ ├── ServerStateListener.java │ │ ├── ServerStateOperation.java │ │ ├── ServerStateReader.java │ │ ├── SyncAccess.java │ │ ├── WriteRequest.java │ │ ├── browser │ │ │ ├── Access.java │ │ │ ├── BaseBrowser.java │ │ │ ├── Branch.java │ │ │ ├── FlatBrowser.java │ │ │ ├── Leaf.java │ │ │ └── TreeBrowser.java │ │ └── exception │ │ │ ├── AddFailedException.java │ │ │ ├── DuplicateGroupException.java │ │ │ └── UnknownGroupException.java │ │ └── list │ │ ├── Categories.java │ │ ├── Category.java │ │ └── ServerList.java │ └── test │ └── java │ └── cn │ └── com │ └── sgcc │ └── gdt │ └── opc │ └── lib │ └── da │ ├── ServerTest.java │ └── demo │ ├── BaseInfo.java │ ├── DataCallbackDumper.java │ ├── OPCTest1.java │ ├── OPCTest2.java │ ├── OPCTest3.java │ ├── OPCTest4.java │ ├── OPCTest5.java │ ├── OPCTest6.java │ ├── OPCTest7.java │ ├── OPCTest8.java │ ├── OPCTestInfo.java │ └── VariantDumper.java ├── opc-da-client ├── pom.xml └── src │ ├── main │ └── java │ │ └── cn │ │ └── com │ │ └── sgcc │ │ └── gdt │ │ └── opc │ │ └── client │ │ ├── Browser.java │ │ ├── Connecter.java │ │ ├── Writer.java │ │ ├── bean │ │ ├── DataItem.java │ │ └── ServerInfo.java │ │ └── utils │ │ ├── DateFmt.java │ │ ├── DateUtil.java │ │ └── JiVariantUtil.java │ └── test │ └── java │ └── cn │ └── com │ └── sgcc │ └── gdt │ └── opc │ └── client │ ├── BrowserTest.java │ ├── ConnecterTest.java │ ├── DemoTest.java │ └── JITest.java ├── opc-da-console ├── pom.xml └── src │ ├── main │ ├── java │ │ └── cn │ │ │ └── com │ │ │ └── sgcc │ │ │ └── gdt │ │ │ └── opc │ │ │ └── console │ │ │ ├── ClientRunner.java │ │ │ ├── OpcDaApplication.java │ │ │ ├── bean │ │ │ ├── ConnectInfo.java │ │ │ └── ResultData.java │ │ │ ├── config │ │ │ ├── BeanTools.java │ │ │ └── ClientConfig.java │ │ │ └── utils │ │ │ └── ParserUtil.java │ └── resources │ │ ├── application-dev.yml │ │ ├── application-pro.yml │ │ ├── application.yml │ │ └── banner.txt │ └── test │ └── java │ └── cn │ └── com │ └── sgcc │ └── gdt │ └── opc │ └── console │ └── ClientRunnerTest.java ├── opc-da-simple-reader ├── pom.xml └── src │ └── main │ ├── java │ └── cn │ │ └── com │ │ └── sgcc │ │ └── gdt │ │ └── opc │ │ └── da │ │ └── simple │ │ └── reader │ │ ├── MainApplication.java │ │ ├── PropertiesUtil.java │ │ ├── ReaderJob.java │ │ └── ScheduleUtil.java │ └── resources │ ├── log4j.properties │ └── opc.properties └── pom.xml /.gitignore: -------------------------------------------------------------------------------- 1 | target/ 2 | 3 | ### STS ### 4 | .apt_generated 5 | .classpath 6 | .factorypath 7 | .project 8 | .settings 9 | .springBeans 10 | 11 | ### IntelliJ IDEA ### 12 | .idea 13 | *.iws 14 | *.iml 15 | *.ipr 16 | 17 | ### NetBeans ### 18 | nbproject/private/ 19 | build/ 20 | nbbuild/ 21 | dist/ 22 | nbdist/ 23 | .nb-gradle/ 24 | 25 | ### mac system file ### 26 | .DS_Store 27 | 28 | -------------------------------------------------------------------------------- /README.MD: -------------------------------------------------------------------------------- 1 | ### 基于Utgard的OPC-DA客户端 2 | 3 | #### 1. opc-core-dcom 4 | 5 | #### 2. opc-core-lib 6 | 7 | #### 3. opc-da-client 8 | 9 | #### 4. opc-da-console 10 | 11 | -------------------------------------------------------------------------------- /opc-core-dcom/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-dcom 13 | 14 | 15 | 16 | openscada-repo 17 | http://repo.openscada.org/maven/releases 18 | 19 | 20 | 21 | 22 | org.slf4j 23 | slf4j-log4j12 24 | 1.7.25 25 | 26 | 27 | 28 | commons-logging 29 | commons-logging 30 | 1.2 31 | 32 | 33 | 34 | org.kohsuke.jinterop 35 | j-interop 36 | 2.0.5 37 | 38 | 39 | 40 | 41 | 42 | 43 | org.springframework.boot 44 | spring-boot-maven-plugin 45 | 2.0.0.RELEASE 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /opc-core-dcom/src/main/java/cn/com/sgcc/gdt/opc/core/dcom/common/Categories.java: -------------------------------------------------------------------------------- 1 | package cn.com.sgcc.gdt.opc.core.dcom.common; 2 | 3 | /** 4 | * 服务器类比 5 | * @author ck.yang 6 | */ 7 | public interface Categories { 8 | public static final String OPCDAServer10 = "63D5F430-CFE4-11d1-B2C8-0060083BA1FB"; 9 | 10 | public static final String OPCDAServer20 = "63D5F432-CFE4-11d1-B2C8-0060083BA1FB"; 11 | 12 | public static final String OPCDAServer30 = "CC603642-66D7-48f1-B69A-B625E73652D7"; 13 | 14 | public static final String XMLDAServer10 = "3098EDA4-A006-48b2-A27F-247453959408"; 15 | 16 | } 17 | -------------------------------------------------------------------------------- /opc-core-dcom/src/main/java/cn/com/sgcc/gdt/opc/core/dcom/common/EventHandler.java: -------------------------------------------------------------------------------- 1 | package cn.com.sgcc.gdt.opc.core.dcom.common; 2 | 3 | import org.jinterop.dcom.common.JIException; 4 | import org.jinterop.dcom.core.IJIComObject; 5 | 6 | /** 7 | * 时间处理器 8 | * @author ck.yang 9 | */ 10 | public interface EventHandler { 11 | public String getIdentifier(); 12 | 13 | public IJIComObject getObject(); 14 | 15 | public void detach() throws JIException; 16 | } 17 | -------------------------------------------------------------------------------- /opc-core-dcom/src/main/java/cn/com/sgcc/gdt/opc/core/dcom/common/bean/Constants.java: -------------------------------------------------------------------------------- 1 | package cn.com.sgcc.gdt.opc.core.dcom.common.bean; 2 | 3 | /** 4 | * 常量 5 | */ 6 | public interface Constants { 7 | public static final String IConnectionPointContainer_IID = "B196B284-BAB4-101A-B69C-00AA00341D07"; 8 | 9 | public static final String IConnectionPoint_IID = "B196B286-BAB4-101A-B69C-00AA00341D07"; 10 | 11 | public static final String IOPCCommon_IID = "F31DFDE2-07B6-11D2-B2D8-0060083BA1FB"; 12 | 13 | public static final String IEnumString_IID = "00000101-0000-0000-C000-000000000046"; 14 | 15 | public static final String IEnumGUID_IID = "0002E000-0000-0000-C000-000000000046"; 16 | 17 | public static final int S_OK = 0; 18 | 19 | public static final int S_FALSE = 1; 20 | } 21 | -------------------------------------------------------------------------------- /opc-core-dcom/src/main/java/cn/com/sgcc/gdt/opc/core/dcom/common/bean/FILETIME.java: -------------------------------------------------------------------------------- 1 | package cn.com.sgcc.gdt.opc.core.dcom.common.bean; 2 | 3 | import java.math.BigDecimal; 4 | import java.util.Calendar; 5 | 6 | import org.jinterop.dcom.common.JIException; 7 | import org.jinterop.dcom.core.JIStruct; 8 | 9 | public class FILETIME { 10 | private int high = 0; 11 | 12 | private int low = 0; 13 | 14 | public FILETIME() { 15 | } 16 | 17 | public FILETIME(final FILETIME arg0) { 18 | this.high = arg0.high; 19 | this.low = arg0.low; 20 | } 21 | 22 | public FILETIME(final int high, final int low) { 23 | this.high = high; 24 | this.low = low; 25 | } 26 | 27 | public int getHigh() { 28 | return this.high; 29 | } 30 | 31 | public void setHigh(final int high) { 32 | this.high = high; 33 | } 34 | 35 | public int getLow() { 36 | return this.low; 37 | } 38 | 39 | public void setLow(final int low) { 40 | this.low = low; 41 | } 42 | 43 | @Override 44 | public int hashCode() { 45 | final int PRIME = 31; 46 | int result = 1; 47 | result = PRIME * result + this.high; 48 | result = PRIME * result + this.low; 49 | return result; 50 | } 51 | 52 | @Override 53 | public boolean equals(final Object obj) { 54 | if (this == obj) { 55 | return true; 56 | } 57 | if (obj == null) { 58 | return false; 59 | } 60 | if (getClass() != obj.getClass()) { 61 | return false; 62 | } 63 | final FILETIME other = (FILETIME) obj; 64 | if (this.high != other.high) { 65 | return false; 66 | } 67 | if (this.low != other.low) { 68 | return false; 69 | } 70 | return true; 71 | } 72 | 73 | public static JIStruct getStruct() throws JIException { 74 | final JIStruct struct = new JIStruct(); 75 | 76 | struct.addMember(Integer.class); 77 | struct.addMember(Integer.class); 78 | 79 | return struct; 80 | } 81 | 82 | public static FILETIME fromStruct(final JIStruct struct) { 83 | final FILETIME ft = new FILETIME(); 84 | 85 | ft.setLow((Integer) struct.getMember(0)); 86 | ft.setHigh((Integer) struct.getMember(1)); 87 | 88 | return ft; 89 | } 90 | 91 | public Calendar asCalendar() { 92 | final Calendar c = Calendar.getInstance(); 93 | 94 | /* 95 | * The following "strange" stuff is needed since we miss a ulong type 96 | */ 97 | long i = 0xFFFFFFFFL & this.high; 98 | i = i << 32; 99 | long j = 0xFFFFFFFFFFFFFFFFL & i; 100 | 101 | i = 0xFFFFFFFFL & this.low; 102 | j += i; 103 | j /= 10000L; 104 | j -= 11644473600000L; 105 | 106 | c.setTimeInMillis(j); 107 | 108 | return c; 109 | } 110 | 111 | public Calendar asBigDecimalCalendar() { 112 | final Calendar c = Calendar.getInstance(); 113 | 114 | /* 115 | * The following "strange" stuff is needed since we miss a ulong type 116 | */ 117 | long i = 0xFFFFFFFFL & this.high; 118 | i = i << 32; 119 | BigDecimal d1 = new BigDecimal(0xFFFFFFFFFFFFFFFFL & i); 120 | 121 | i = 0xFFFFFFFFL & this.low; 122 | d1 = d1.add(new BigDecimal(i)); 123 | d1 = d1.divide(new BigDecimal(10000L)); 124 | d1 = d1.subtract(new BigDecimal(11644473600000L)); 125 | 126 | c.setTimeInMillis(d1.longValue()); 127 | 128 | return c; 129 | } 130 | 131 | @Override 132 | public String toString() { 133 | return String.format("%s/%s", this.high, this.low); 134 | } 135 | } 136 | -------------------------------------------------------------------------------- /opc-core-dcom/src/main/java/cn/com/sgcc/gdt/opc/core/dcom/common/bean/KeyedResult.java: -------------------------------------------------------------------------------- 1 | package cn.com.sgcc.gdt.opc.core.dcom.common.bean; 2 | 3 | /** 4 | * 带键的结果 5 | * @author ck.yang 6 | */ 7 | public class KeyedResult extends Result { 8 | private K key; 9 | 10 | public KeyedResult() { 11 | super(); 12 | } 13 | 14 | public KeyedResult(final K key, final V value, final int errorCode) { 15 | super(value, errorCode); 16 | this.key = key; 17 | } 18 | 19 | public K getKey() { 20 | return this.key; 21 | } 22 | 23 | public void setKey(final K key) { 24 | this.key = key; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /opc-core-dcom/src/main/java/cn/com/sgcc/gdt/opc/core/dcom/common/bean/KeyedResultSet.java: -------------------------------------------------------------------------------- 1 | package cn.com.sgcc.gdt.opc.core.dcom.common.bean; 2 | 3 | import java.util.ArrayList; 4 | 5 | /** 6 | * 带主键的结果集 7 | * @author ck.yang 8 | */ 9 | public class KeyedResultSet extends ArrayList> { 10 | private static final long serialVersionUID = 1L; 11 | 12 | public KeyedResultSet() { 13 | super(); 14 | } 15 | 16 | public KeyedResultSet(final int size) { 17 | super(size); // me 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /opc-core-dcom/src/main/java/cn/com/sgcc/gdt/opc/core/dcom/common/bean/Result.java: -------------------------------------------------------------------------------- 1 | package cn.com.sgcc.gdt.opc.core.dcom.common.bean; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | 7 | /** 8 | * 结果 9 | * @author ck.yang 10 | */ 11 | @Data 12 | @NoArgsConstructor 13 | @AllArgsConstructor 14 | public class Result { 15 | /** 值 */ 16 | private T value; 17 | /** 错误码 */ 18 | private int errorCode; 19 | /** 是否失败 */ 20 | public boolean isFailed() { 21 | return this.errorCode != 0; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /opc-core-dcom/src/main/java/cn/com/sgcc/gdt/opc/core/dcom/common/bean/ResultSet.java: -------------------------------------------------------------------------------- 1 | package cn.com.sgcc.gdt.opc.core.dcom.common.bean; 2 | 3 | import java.util.ArrayList; 4 | 5 | /** 6 | * 结果集合 7 | * @author ck.yang 8 | */ 9 | public class ResultSet extends ArrayList> { 10 | 11 | private static final long serialVersionUID = 6392417310208978252L; 12 | 13 | public ResultSet() { 14 | super(); 15 | } 16 | 17 | public ResultSet(final int size) { 18 | super(size); // me 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /opc-core-dcom/src/main/java/cn/com/sgcc/gdt/opc/core/dcom/common/impl/BaseCOMObject.java: -------------------------------------------------------------------------------- 1 | package cn.com.sgcc.gdt.opc.core.dcom.common.impl; 2 | 3 | import org.jinterop.dcom.core.IJIComObject; 4 | 5 | /** 6 | * 基本的COM对象 7 | * @author ck.yang 8 | */ 9 | public class BaseCOMObject { 10 | private IJIComObject comObject = null; 11 | 12 | /** 13 | * Create a new base COM object 14 | * 15 | * @param comObject The COM object to wrap but be addRef'ed 16 | */ 17 | public BaseCOMObject(final IJIComObject comObject) { 18 | this.comObject = comObject; 19 | } 20 | 21 | protected synchronized IJIComObject getCOMObject() { 22 | return this.comObject; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /opc-core-dcom/src/main/java/cn/com/sgcc/gdt/opc/core/dcom/common/impl/EnumGUID.java: -------------------------------------------------------------------------------- 1 | package cn.com.sgcc.gdt.opc.core.dcom.common.impl; 2 | 3 | import java.net.UnknownHostException; 4 | import java.util.ArrayList; 5 | import java.util.Collection; 6 | import java.util.List; 7 | 8 | import cn.com.sgcc.gdt.opc.core.dcom.common.bean.Constants; 9 | import org.jinterop.dcom.common.JIException; 10 | import org.jinterop.dcom.core.IJIComObject; 11 | import org.jinterop.dcom.core.JIArray; 12 | import org.jinterop.dcom.core.JICallBuilder; 13 | import org.jinterop.dcom.core.JIFlags; 14 | 15 | import rpc.core.UUID; 16 | 17 | /** 18 | * 枚举全局唯一标识符 19 | * @author ck.yang 20 | */ 21 | public class EnumGUID extends BaseCOMObject { 22 | public static final int DEFAULT_BATCH_SIZE = Integer.getInteger("openscada.dcom.enum-batch-size", 10); 23 | 24 | public EnumGUID(final IJIComObject enumStringObject) throws IllegalArgumentException, UnknownHostException, JIException { 25 | super(enumStringObject.queryInterface(Constants.IEnumGUID_IID)); 26 | } 27 | 28 | public int next(final List list, final int num) throws JIException { 29 | if (num <= 0) { 30 | return 0; 31 | } 32 | 33 | JICallBuilder callObject = new JICallBuilder(true); 34 | callObject.setOpnum(0); 35 | 36 | callObject.addInParamAsInt(num, JIFlags.FLAG_NULL); 37 | callObject.addInParamAsInt(num, JIFlags.FLAG_NULL); 38 | callObject.addOutParamAsObject(new JIArray(UUID.class, null, 1, true, true), JIFlags.FLAG_NULL); 39 | callObject.addOutParamAsType(Integer.class, JIFlags.FLAG_NULL); 40 | 41 | Object[] result = Helper.callRespectSFALSE(getCOMObject(), callObject); 42 | 43 | UUID[] resultData = (UUID[]) ((JIArray) result[0]).getArrayInstance(); 44 | Integer cnt = (Integer) result[1]; 45 | 46 | for (int i = 0; i < cnt; i++) { 47 | list.add(resultData[i]); 48 | } 49 | return cnt; 50 | } 51 | 52 | public Collection next(final int num) throws JIException { 53 | List list = new ArrayList(num); 54 | next(list, num); 55 | return list; 56 | } 57 | 58 | public void skip(final int num) throws JIException { 59 | if (num <= 0) { 60 | return; 61 | } 62 | 63 | JICallBuilder callObject = new JICallBuilder(true); 64 | callObject.setOpnum(1); 65 | 66 | callObject.addInParamAsInt(num, JIFlags.FLAG_NULL); 67 | 68 | getCOMObject().call(callObject); 69 | } 70 | 71 | public void reset() throws JIException { 72 | JICallBuilder callObject = new JICallBuilder(true); 73 | callObject.setOpnum(2); 74 | 75 | getCOMObject().call(callObject); 76 | } 77 | 78 | public EnumGUID cloneObject() throws JIException, IllegalArgumentException, UnknownHostException { 79 | JICallBuilder callObject = new JICallBuilder(true); 80 | callObject.setOpnum(3); 81 | 82 | callObject.addOutParamAsType(IJIComObject.class, JIFlags.FLAG_NULL); 83 | 84 | Object[] result = getCOMObject().call(callObject); 85 | 86 | IJIComObject object = (IJIComObject) result[0]; 87 | 88 | return new EnumGUID(object); 89 | } 90 | 91 | public Collection asCollection(final int batchSize) throws JIException { 92 | reset(); 93 | 94 | List data = new ArrayList(); 95 | int i = 0; 96 | do { 97 | i = next(data, batchSize); 98 | } while (i == batchSize); 99 | 100 | return data; 101 | } 102 | 103 | public Collection asCollection() throws JIException { 104 | return asCollection(DEFAULT_BATCH_SIZE); 105 | } 106 | 107 | } 108 | -------------------------------------------------------------------------------- /opc-core-dcom/src/main/java/cn/com/sgcc/gdt/opc/core/dcom/common/impl/EnumString.java: -------------------------------------------------------------------------------- 1 | package cn.com.sgcc.gdt.opc.core.dcom.common.impl; 2 | 3 | import java.net.UnknownHostException; 4 | import java.util.ArrayList; 5 | import java.util.Collection; 6 | import java.util.List; 7 | 8 | import cn.com.sgcc.gdt.opc.core.dcom.common.bean.Constants; 9 | import org.jinterop.dcom.common.JIException; 10 | import org.jinterop.dcom.core.IJIComObject; 11 | import org.jinterop.dcom.core.JIArray; 12 | import org.jinterop.dcom.core.JICallBuilder; 13 | import org.jinterop.dcom.core.JIFlags; 14 | import org.jinterop.dcom.core.JIString; 15 | 16 | /** 17 | * 枚举字符串 18 | * @author ck.yang 19 | */ 20 | public class EnumString extends BaseCOMObject { 21 | public static final int DEFAULT_BATCH_SIZE = Integer.getInteger("openscada.dcom.enum-batch-size", 10); 22 | 23 | public EnumString(final IJIComObject enumStringObject) throws IllegalArgumentException, UnknownHostException, JIException { 24 | super(enumStringObject.queryInterface(Constants.IEnumString_IID)); 25 | } 26 | 27 | public Integer next(final List list, final Integer num) throws JIException { 28 | if (num <= 0) { 29 | return 0; 30 | } 31 | 32 | JICallBuilder callObject = new JICallBuilder(true); 33 | callObject.setOpnum(0); 34 | 35 | callObject.addInParamAsInt(num, JIFlags.FLAG_NULL); 36 | //callObject.addInParamAsInt ( num, JIFlags.FLAG_NULL ); 37 | //callObject.addOutParamAsObject ( new JIArray ( new JIPointer ( new JIString ( 38 | // JIFlags.FLAG_REPRESENTATION_STRING_LPWSTR ) ), null, 1, true, true ), JIFlags.FLAG_NULL ); 39 | callObject.addOutParamAsObject(new JIArray(new JIString(JIFlags.FLAG_REPRESENTATION_STRING_LPWSTR), null, 1, true, true), JIFlags.FLAG_NULL); 40 | callObject.addOutParamAsType(Integer.class, JIFlags.FLAG_NULL); 41 | 42 | Object[] result = Helper.callRespectSFALSE(getCOMObject(), callObject); 43 | 44 | //JIPointer[] resultData = (JIPointer[]) ( (JIArray) ( result[0] ) ).getArrayInstance (); 45 | JIString[] resultData = (JIString[]) ((JIArray) result[0]).getArrayInstance(); 46 | Integer cnt = (Integer) result[1]; 47 | 48 | for (int i = 0; i < cnt; i++) { 49 | //list.add ( ( (JIString)resultData[i].getReferent () ).getString () ); 50 | list.add(resultData[i].getString()); 51 | } 52 | return cnt; 53 | } 54 | 55 | public Collection next(final int num) throws JIException { 56 | List list = new ArrayList<>(num); 57 | next(list, num); 58 | return list; 59 | } 60 | 61 | public void skip(final int num) throws JIException { 62 | if (num <= 0) { 63 | return; 64 | } 65 | 66 | JICallBuilder callObject = new JICallBuilder(true); 67 | callObject.setOpnum(1); 68 | 69 | callObject.addInParamAsInt(num, JIFlags.FLAG_NULL); 70 | 71 | getCOMObject().call(callObject); 72 | } 73 | 74 | public void reset() throws JIException { 75 | JICallBuilder callObject = new JICallBuilder(true); 76 | callObject.setOpnum(2); 77 | 78 | getCOMObject().call(callObject); 79 | } 80 | 81 | public EnumString cloneObject() throws JIException, IllegalArgumentException, UnknownHostException { 82 | JICallBuilder callObject = new JICallBuilder(true); 83 | callObject.setOpnum(3); 84 | 85 | callObject.addOutParamAsType(IJIComObject.class, JIFlags.FLAG_NULL); 86 | 87 | Object[] result = getCOMObject().call(callObject); 88 | 89 | IJIComObject object = (IJIComObject) result[0]; 90 | return new EnumString(object); 91 | } 92 | 93 | public Collection asCollection(final int batchSize) throws JIException { 94 | reset(); 95 | 96 | List data = new ArrayList(); 97 | int i = 0; 98 | do { 99 | i = next(data, batchSize); 100 | } while (i == batchSize); 101 | 102 | return data; 103 | } 104 | 105 | public Collection asCollection() throws JIException { 106 | return asCollection(DEFAULT_BATCH_SIZE); 107 | } 108 | 109 | } 110 | -------------------------------------------------------------------------------- /opc-core-dcom/src/main/java/cn/com/sgcc/gdt/opc/core/dcom/common/impl/EventHandlerImpl.java: -------------------------------------------------------------------------------- 1 | package cn.com.sgcc.gdt.opc.core.dcom.common.impl; 2 | 3 | import cn.com.sgcc.gdt.opc.core.dcom.common.EventHandler; 4 | import org.jinterop.dcom.common.JIException; 5 | import org.jinterop.dcom.core.IJIComObject; 6 | import org.jinterop.dcom.core.JIFrameworkHelper; 7 | 8 | /** 9 | * 事件处理器 10 | * @author ck.yang 11 | */ 12 | public class EventHandlerImpl implements EventHandler { 13 | private String identifier = null; 14 | 15 | private IJIComObject object = null; 16 | 17 | /** 18 | * 获取主键 19 | * @return 20 | */ 21 | @Override 22 | public String getIdentifier() { 23 | return this.identifier; 24 | } 25 | 26 | @Override 27 | public synchronized IJIComObject getObject() { 28 | return this.object; 29 | } 30 | 31 | /** 32 | * 设置信息 33 | * @param object 34 | * @param identifier 35 | */ 36 | public synchronized void setInfo(final IJIComObject object, final String identifier) { 37 | this.object = object; 38 | this.identifier = identifier; 39 | } 40 | 41 | /** 42 | * 分离 43 | * @throws JIException 44 | */ 45 | @Override 46 | public synchronized void detach() throws JIException { 47 | if (this.object != null && this.identifier != null) { 48 | try { 49 | JIFrameworkHelper.detachEventHandler(this.object, this.identifier); 50 | } finally { 51 | this.object = null; 52 | this.identifier = null; 53 | } 54 | } 55 | } 56 | 57 | } 58 | -------------------------------------------------------------------------------- /opc-core-dcom/src/main/java/cn/com/sgcc/gdt/opc/core/dcom/common/impl/Helper.java: -------------------------------------------------------------------------------- 1 | package cn.com.sgcc.gdt.opc.core.dcom.common.impl; 2 | 3 | import cn.com.sgcc.gdt.opc.core.dcom.common.bean.Constants; 4 | import org.jinterop.dcom.common.JIException; 5 | import org.jinterop.dcom.core.IJIComObject; 6 | import org.jinterop.dcom.core.JICallBuilder; 7 | import org.jinterop.dcom.core.JIFlags; 8 | import org.jinterop.dcom.core.JIVariant; 9 | 10 | /** 11 | * 工具类 12 | * @author ck.yang 13 | */ 14 | public class Helper { 15 | /** 16 | * Make the COM call but do not treat S_FALSE as error condition for the whole call 17 | * 18 | * @param object the object to make to call on 19 | * @param callObject the call object 20 | * @return the result of the call 21 | * @throws JIException 22 | */ 23 | public static Object[] callRespectSFALSE(final IJIComObject object, final JICallBuilder callObject) throws JIException { 24 | try { 25 | return object.call(callObject); 26 | } catch (JIException e) { 27 | if (e.getErrorCode() != Constants.S_FALSE) { 28 | throw e; 29 | } 30 | return callObject.getResultsInCaseOfException(); 31 | } 32 | } 33 | 34 | /** 35 | * Perform some fixes on the variant when writing it to OPC items. This method 36 | * only changes control information on the variant and not the value itself! 37 | * 38 | * @param value the value to fix 39 | * @return the fixed value 40 | * @throws JIException In case something goes wrong 41 | */ 42 | public static JIVariant fixVariant(final JIVariant value) throws JIException { 43 | if (value.isArray()) { 44 | if (value.getObjectAsArray().getArrayInstance() instanceof Boolean[]) { 45 | value.setFlag(JIFlags.FLAG_REPRESENTATION_VARIANT_BOOL); 46 | } 47 | } 48 | return value; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /opc-core-dcom/src/main/java/cn/com/sgcc/gdt/opc/core/dcom/common/impl/OPCCommon.java: -------------------------------------------------------------------------------- 1 | package cn.com.sgcc.gdt.opc.core.dcom.common.impl; 2 | 3 | import java.net.UnknownHostException; 4 | import java.util.Arrays; 5 | import java.util.Collection; 6 | 7 | import cn.com.sgcc.gdt.opc.core.dcom.common.bean.Constants; 8 | import org.jinterop.dcom.common.JIException; 9 | import org.jinterop.dcom.core.IJIComObject; 10 | import org.jinterop.dcom.core.JIArray; 11 | import org.jinterop.dcom.core.JICallBuilder; 12 | import org.jinterop.dcom.core.JIFlags; 13 | import org.jinterop.dcom.core.JIPointer; 14 | import org.jinterop.dcom.core.JIString; 15 | 16 | /** 17 | * OPC公共组件 18 | * @author ck.yang 19 | */ 20 | public class OPCCommon extends BaseCOMObject { 21 | public OPCCommon(final IJIComObject opcObject) throws IllegalArgumentException, UnknownHostException, JIException { 22 | super(opcObject.queryInterface(Constants.IOPCCommon_IID)); 23 | } 24 | 25 | /** 26 | * 设置本地id 27 | * @param localeID 28 | * @throws JIException 29 | */ 30 | public void setLocaleID(final int localeID) throws JIException { 31 | JICallBuilder callObject = new JICallBuilder(true); 32 | callObject.setOpnum(0); 33 | 34 | callObject.addInParamAsInt(localeID, JIFlags.FLAG_NULL); 35 | 36 | getCOMObject().call(callObject); 37 | } 38 | 39 | /** 40 | * 获取本地id 41 | * @return 42 | * @throws JIException 43 | */ 44 | public int getLocaleID() throws JIException { 45 | JICallBuilder callObject = new JICallBuilder(true); 46 | callObject.setOpnum(1); 47 | 48 | callObject.addOutParamAsObject(Integer.class, JIFlags.FLAG_NULL); 49 | 50 | Object[] result = getCOMObject().call(callObject); 51 | return (Integer) result[0]; 52 | } 53 | 54 | /** 55 | * 获取错误信息 56 | * @param errorCode 57 | * @param localeID 58 | * @return 59 | * @throws JIException 60 | */ 61 | public String getErrorString(final int errorCode, final int localeID) throws JIException { 62 | JICallBuilder callObject = new JICallBuilder(true); 63 | callObject.setOpnum(3); 64 | 65 | callObject.addInParamAsInt(errorCode, JIFlags.FLAG_NULL); 66 | callObject.addInParamAsInt(localeID, JIFlags.FLAG_NULL); 67 | callObject.addOutParamAsObject(new JIPointer(new JIString(JIFlags.FLAG_REPRESENTATION_STRING_LPWSTR)), JIFlags.FLAG_NULL); 68 | 69 | Object[] result = getCOMObject().call(callObject); 70 | return ((JIString) ((JIPointer) result[0]).getReferent()).getString(); 71 | } 72 | 73 | /** 74 | * 设置客户端名称 75 | * @param clientName 76 | * @throws JIException 77 | */ 78 | public void setClientName(final String clientName) throws JIException { 79 | JICallBuilder callObject = new JICallBuilder(true); 80 | callObject.setOpnum(4); 81 | 82 | callObject.addInParamAsString(clientName, JIFlags.FLAG_REPRESENTATION_STRING_LPWSTR); 83 | 84 | getCOMObject().call(callObject); 85 | } 86 | 87 | /** 88 | * 查询可用的本地id 89 | * @return 90 | * @throws JIException 91 | */ 92 | public Collection queryAvailableLocaleIDs() throws JIException { 93 | JICallBuilder callObject = new JICallBuilder(true); 94 | callObject.setOpnum(2); 95 | 96 | callObject.addOutParamAsType(Integer.class, JIFlags.FLAG_NULL); 97 | callObject.addOutParamAsObject(new JIPointer(new JIArray(Integer.class, null, 1, true)), JIFlags.FLAG_NULL); 98 | 99 | Object[] result = getCOMObject().call(callObject); 100 | 101 | JIArray resultArray = (JIArray) ((JIPointer) result[1]).getReferent(); 102 | Integer[] intArray = (Integer[]) resultArray.getArrayInstance(); 103 | 104 | return Arrays.asList(intArray); 105 | } 106 | 107 | } 108 | -------------------------------------------------------------------------------- /opc-core-dcom/src/main/java/cn/com/sgcc/gdt/opc/core/dcom/da/IOPCDataCallback.java: -------------------------------------------------------------------------------- 1 | package cn.com.sgcc.gdt.opc.core.dcom.da; 2 | 3 | import cn.com.sgcc.gdt.opc.core.dcom.common.bean.KeyedResultSet; 4 | import cn.com.sgcc.gdt.opc.core.dcom.common.bean.ResultSet; 5 | import cn.com.sgcc.gdt.opc.core.dcom.da.bean.ValueData; 6 | 7 | /** 8 | * OPC数据回调函数 9 | * @author ck.yang 10 | */ 11 | public interface IOPCDataCallback { 12 | public void dataChange(int transactionId, int serverGroupHandle, int masterQuality, int masterErrorCode, KeyedResultSet result); 13 | 14 | public void readComplete(int transactionId, int serverGroupHandle, int masterQuality, int masterErrorCode, KeyedResultSet result); 15 | 16 | public void writeComplete(int transactionId, int serverGroupHandle, int masterErrorCode, ResultSet result); 17 | 18 | public void cancelComplete(int transactionId, int serverGroupHandle); 19 | } 20 | -------------------------------------------------------------------------------- /opc-core-dcom/src/main/java/cn/com/sgcc/gdt/opc/core/dcom/da/bean/Constants.java: -------------------------------------------------------------------------------- 1 | package cn.com.sgcc.gdt.opc.core.dcom.da.bean; 2 | 3 | /** 4 | * 常量 5 | * @author ck.yang 6 | */ 7 | public interface Constants extends cn.com.sgcc.gdt.opc.core.dcom.common.bean.Constants { 8 | public static final String IOPCServer_IID = "39C13A4D-011E-11D0-9675-0020AFD8ADB3"; 9 | 10 | public static final String IOPCGroupStateMgt_IID = "39C13A50-011E-11D0-9675-0020AFD8ADB3"; 11 | 12 | public static final String IOPCBrowse_IID = "39227004-A18F-4B57-8B0A-5235670F4468"; 13 | 14 | public static final String IOPCBrowseServerAddressSpace_IID = "39C13A4F-011E-11D0-9675-0020AFD8ADB3"; 15 | 16 | public static final String IOPCItemMgt_IID = "39C13A54-011E-11D0-9675-0020AFD8ADB3"; 17 | 18 | public static final String IOPCItemProperties_IID = "39C13A72-011E-11D0-9675-0020AFD8ADB3"; 19 | 20 | public static final String IOPCItemIO_IID = "85C0B427-2893-4CBC-BD78-E5FC5146F08F"; 21 | 22 | public static final String IOPCDataCallback_IID = "39C13A70-011E-11D0-9675-0020AFD8ADB3"; 23 | 24 | public static final String IOPCAsyncIO2_IID = "39C13A71-011E-11D0-9675-0020AFD8ADB3"; 25 | 26 | public static final String IOPCSyncIO_IID = "39C13A52-011E-11D0-9675-0020AFD8ADB3"; 27 | } 28 | -------------------------------------------------------------------------------- /opc-core-dcom/src/main/java/cn/com/sgcc/gdt/opc/core/dcom/da/bean/IORequest.java: -------------------------------------------------------------------------------- 1 | package cn.com.sgcc.gdt.opc.core.dcom.da.bean; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | import lombok.ToString; 7 | 8 | /** 9 | * 传输请求 10 | */ 11 | @Data 12 | @AllArgsConstructor 13 | @NoArgsConstructor 14 | @ToString 15 | public class IORequest { 16 | /** 数据项编号 */ 17 | private String itemID; 18 | /** 最大生存时间 */ 19 | private int maxAge; 20 | 21 | } -------------------------------------------------------------------------------- /opc-core-dcom/src/main/java/cn/com/sgcc/gdt/opc/core/dcom/da/bean/OpcBrowseDirection.java: -------------------------------------------------------------------------------- 1 | package cn.com.sgcc.gdt.opc.core.dcom.da.bean; 2 | 3 | /** 4 | * OPC浏览方向 5 | * @author ck.yang 6 | */ 7 | public enum OpcBrowseDirection { 8 | /** 向上 */ 9 | OPC_BROWSE_UP(1), 10 | /** 向下 */ 11 | OPC_BROWSE_DOWN(2), 12 | /** */ 13 | OPC_BROWSE_TO(3), 14 | /** 未知 */ 15 | OPC_BROWSE_UNKNOWN(0); 16 | 17 | private int _id; 18 | 19 | private OpcBrowseDirection(final int id) { 20 | this._id = id; 21 | } 22 | 23 | public int id() { 24 | return this._id; 25 | } 26 | 27 | public static OpcBrowseDirection fromID(final int id) { 28 | switch (id) { 29 | case 1: 30 | return OPC_BROWSE_UP; 31 | case 2: 32 | return OPC_BROWSE_DOWN; 33 | case 3: 34 | return OPC_BROWSE_TO; 35 | default: 36 | return OPC_BROWSE_UNKNOWN; 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /opc-core-dcom/src/main/java/cn/com/sgcc/gdt/opc/core/dcom/da/bean/OpcBrowseType.java: -------------------------------------------------------------------------------- 1 | package cn.com.sgcc.gdt.opc.core.dcom.da.bean; 2 | 3 | /** 4 | * OPC浏览类型 5 | * @author ck.yang 6 | */ 7 | public enum OpcBrowseType { 8 | /** 分支 */ 9 | OPC_BRANCH(1), 10 | /** 叶子 */ 11 | OPC_LEAF(2), 12 | /** 平行 */ 13 | OPC_FLAT(3), 14 | /** 未知类型 */ 15 | OPC_UNKNOWN(0); 16 | 17 | private int _id; 18 | 19 | private OpcBrowseType(final int id) { 20 | this._id = id; 21 | } 22 | 23 | public int id() { 24 | return this._id; 25 | } 26 | 27 | /** 28 | * 根据编号获取类型 29 | * @param id 30 | * @return 31 | */ 32 | public static OpcBrowseType fromID(final int id) { 33 | switch (id) { 34 | case 1: return OPC_BRANCH; 35 | case 2: return OPC_LEAF; 36 | case 3: return OPC_FLAT; 37 | default: return OPC_UNKNOWN; 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /opc-core-dcom/src/main/java/cn/com/sgcc/gdt/opc/core/dcom/da/bean/OpcDatasource.java: -------------------------------------------------------------------------------- 1 | package cn.com.sgcc.gdt.opc.core.dcom.da.bean; 2 | 3 | /** 4 | * OPC数据源 5 | * @author ck.yang 6 | */ 7 | public enum OpcDatasource { 8 | /** 9 | * 缓存数据源 10 | */ 11 | OPC_DS_CACHE(1), 12 | /** 13 | * 设备/驱动数据源 14 | */ 15 | OPC_DS_DEVICE(2), 16 | /** 17 | * 未知数据源 18 | */ 19 | OPC_DS_UNKNOWN(0); 20 | 21 | private int _id; 22 | 23 | private OpcDatasource(final int id) { 24 | this._id = id; 25 | } 26 | 27 | public int id() { 28 | return this._id; 29 | } 30 | 31 | /** 32 | * 根据编号获取数据类型 33 | * @param id 34 | * @return 35 | */ 36 | public static OpcDatasource fromID(final int id) { 37 | switch (id){ 38 | case 1: return OPC_DS_CACHE; 39 | case 2: return OPC_DS_DEVICE; 40 | default: return OPC_DS_UNKNOWN; 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /opc-core-dcom/src/main/java/cn/com/sgcc/gdt/opc/core/dcom/da/bean/OpcEnumScope.java: -------------------------------------------------------------------------------- 1 | package cn.com.sgcc.gdt.opc.core.dcom.da.bean; 2 | 3 | /** 4 | * OPC枚举范围 5 | * @author ck.yang 6 | */ 7 | public enum OpcEnumScope { 8 | /** 私有连接 */ 9 | OPC_ENUM_PRIVATE_CONNECTIONS(1), 10 | /** 公开连接 */ 11 | OPC_ENUM_PUBLIC_CONNECTIONS(2), 12 | /** 全部连接 */ 13 | OPC_ENUM_ALL_CONNECTIONS(3), 14 | /** 私有 */ 15 | OPC_ENUM_PRIVATE(4), 16 | /** 公开 */ 17 | OPC_ENUM_PUBLIC(5), 18 | /** 全部 */ 19 | OPC_ENUM_ALL(6), 20 | /** 未知 */ 21 | OPC_ENUM_UNKNOWN(0); 22 | 23 | private int _id; 24 | 25 | private OpcEnumScope(final int id) { 26 | this._id = id; 27 | } 28 | 29 | public int id() { 30 | return this._id; 31 | } 32 | 33 | public static OpcEnumScope fromID(final int id) { 34 | switch (id) { 35 | case 1: 36 | return OPC_ENUM_PRIVATE_CONNECTIONS; 37 | case 2: 38 | return OPC_ENUM_PUBLIC_CONNECTIONS; 39 | case 3: 40 | return OPC_ENUM_ALL_CONNECTIONS; 41 | case 4: 42 | return OPC_ENUM_PRIVATE; 43 | case 5: 44 | return OPC_ENUM_PUBLIC; 45 | case 6: 46 | return OPC_ENUM_ALL; 47 | default: 48 | return OPC_ENUM_UNKNOWN; 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /opc-core-dcom/src/main/java/cn/com/sgcc/gdt/opc/core/dcom/da/bean/OpcGroupState.java: -------------------------------------------------------------------------------- 1 | package cn.com.sgcc.gdt.opc.core.dcom.da.bean; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | import lombok.ToString; 7 | 8 | /** 9 | * OPC组状态 10 | * @author ck.yang 11 | */ 12 | @Data 13 | @AllArgsConstructor 14 | @NoArgsConstructor 15 | @ToString 16 | public class OpcGroupState { 17 | /** 更新频率 */ 18 | private int updateRate = 1000; 19 | /** 激活状态 */ 20 | private boolean active = true; 21 | /** 名称 */ 22 | private String name = ""; 23 | /** 时间偏差 */ 24 | private int timeBias = 0; 25 | /** 死亡百分比 FIXME 不理解 */ 26 | private float percentDeadband = 0.0f; 27 | /** 本地编号 */ 28 | private int localeID = 0; 29 | /** 客户端处理器编号 */ 30 | private int clientHandle = 0; 31 | /** 服务器处理编号 */ 32 | private int serverHandle = 0; 33 | 34 | 35 | } 36 | -------------------------------------------------------------------------------- /opc-core-dcom/src/main/java/cn/com/sgcc/gdt/opc/core/dcom/da/bean/OpcItemDef.java: -------------------------------------------------------------------------------- 1 | package cn.com.sgcc.gdt.opc.core.dcom.da.bean; 2 | 3 | import lombok.Data; 4 | import lombok.ToString; 5 | import org.jinterop.dcom.common.JIException; 6 | import org.jinterop.dcom.core.JIFlags; 7 | import org.jinterop.dcom.core.JIPointer; 8 | import org.jinterop.dcom.core.JIString; 9 | import org.jinterop.dcom.core.JIStruct; 10 | import org.jinterop.dcom.core.JIVariant; 11 | 12 | /** 13 | * OPC数据项定义 14 | * @author ck.yang 15 | */ 16 | @Data 17 | @ToString 18 | public class OpcItemDef { 19 | 20 | /** 通道路径 */ 21 | private String accessPath = ""; 22 | /** 数据项编号 */ 23 | private String itemID = ""; 24 | /** 激活状态 */ 25 | private boolean active = true; 26 | /** 客户端操作编号 */ 27 | private int clientHandle; 28 | /** 请求数据类型 */ 29 | private short requestedDataType = JIVariant.VT_EMPTY; 30 | /** 保留 */ 31 | private short reserved; 32 | 33 | 34 | /** 35 | * 格式化为J-Interop的JIStruct类型 36 | * 37 | * @return the j-interop structe 38 | * @throws JIException 39 | */ 40 | public JIStruct toStruct() throws JIException { 41 | final JIStruct struct = new JIStruct(); 42 | struct.addMember(new JIString(getAccessPath(), JIFlags.FLAG_REPRESENTATION_STRING_LPWSTR)); 43 | struct.addMember(new JIString(getItemID(), JIFlags.FLAG_REPRESENTATION_STRING_LPWSTR)); 44 | struct.addMember(new Integer(isActive() ? 1 : 0)); 45 | struct.addMember(Integer.valueOf(getClientHandle())); 46 | 47 | struct.addMember(Integer.valueOf(0)); // blob size 48 | struct.addMember(new JIPointer(null)); // blob 49 | 50 | struct.addMember(Short.valueOf(getRequestedDataType())); 51 | struct.addMember(Short.valueOf(getReserved())); 52 | return struct; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /opc-core-dcom/src/main/java/cn/com/sgcc/gdt/opc/core/dcom/da/bean/OpcItemResult.java: -------------------------------------------------------------------------------- 1 | package cn.com.sgcc.gdt.opc.core.dcom.da.bean; 2 | 3 | import lombok.Data; 4 | import lombok.ToString; 5 | import org.jinterop.dcom.common.JIException; 6 | import org.jinterop.dcom.core.JIArray; 7 | import org.jinterop.dcom.core.JIPointer; 8 | import org.jinterop.dcom.core.JIStruct; 9 | import org.jinterop.dcom.core.JIVariant; 10 | 11 | /** 12 | * OPC数据项结果 13 | * @author ck.yang 14 | */ 15 | @Data 16 | @ToString 17 | public class OpcItemResult { 18 | /** 服务处理器编号 */ 19 | private int serverHandle = 0; 20 | /** 规范的数据类型 */ 21 | private short canonicalDataType = JIVariant.VT_EMPTY; 22 | /** 保留 */ 23 | private short reserved = 0; 24 | /** 访问权限 */ 25 | private int accessRights = 0; 26 | 27 | /** 28 | * 格式化为JIStruct 29 | * @return 30 | * @throws JIException 31 | */ 32 | public static JIStruct getStruct() throws JIException { 33 | JIStruct struct = new JIStruct(); 34 | 35 | struct.addMember(Integer.class); // Server handle 36 | struct.addMember(Short.class); // data type 37 | struct.addMember(Short.class); // reserved 38 | struct.addMember(Integer.class); // access rights 39 | struct.addMember(Integer.class); // blob size 40 | // grab the normally unused byte array 41 | struct.addMember(new JIPointer(new JIArray(Byte.class, null, 1, true, false))); 42 | 43 | return struct; 44 | } 45 | 46 | /** 47 | * 将JIStruct转换为OpcItemResult 48 | * @param struct 49 | * @return 50 | */ 51 | public static OpcItemResult fromStruct(final JIStruct struct) { 52 | OpcItemResult result = new OpcItemResult(); 53 | 54 | result.setServerHandle(new Integer((Integer) struct.getMember(0))); 55 | result.setCanonicalDataType(new Short((Short) struct.getMember(1))); 56 | result.setReserved(new Short((Short) struct.getMember(2))); 57 | result.setAccessRights(new Integer((Integer) struct.getMember(3))); 58 | 59 | return result; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /opc-core-dcom/src/main/java/cn/com/sgcc/gdt/opc/core/dcom/da/bean/OpcItemState.java: -------------------------------------------------------------------------------- 1 | package cn.com.sgcc.gdt.opc.core.dcom.da.bean; 2 | 3 | import cn.com.sgcc.gdt.opc.core.dcom.common.bean.FILETIME; 4 | import lombok.Data; 5 | import lombok.ToString; 6 | import org.jinterop.dcom.common.JIException; 7 | import org.jinterop.dcom.core.JIStruct; 8 | import org.jinterop.dcom.core.JIVariant; 9 | 10 | /** 11 | * OPC数据项状态 12 | * @author ck.yang 13 | */ 14 | @Data 15 | @ToString 16 | public class OpcItemState { 17 | private int clientHandle = 0; 18 | 19 | private FILETIME timestamp = null; 20 | 21 | private short quality = 0; 22 | 23 | private short reserved = 0; 24 | 25 | private JIVariant value = null; 26 | 27 | 28 | /** 29 | * 转换为JIStruct 30 | * @return 31 | * @throws JIException 32 | */ 33 | public static JIStruct getStruct() throws JIException { 34 | JIStruct struct = new JIStruct(); 35 | 36 | struct.addMember(Integer.class); 37 | struct.addMember(FILETIME.getStruct()); 38 | struct.addMember(Short.class); 39 | struct.addMember(Short.class); 40 | struct.addMember(JIVariant.class); 41 | 42 | return struct; 43 | } 44 | 45 | /** 46 | * 从JIStruct获取 47 | * @param struct 48 | * @return 49 | */ 50 | public static OpcItemState fromStruct(final JIStruct struct) { 51 | OpcItemState itemState = new OpcItemState(); 52 | 53 | itemState.setClientHandle((Integer) struct.getMember(0)); 54 | itemState.setTimestamp(FILETIME.fromStruct((JIStruct) struct.getMember(1))); 55 | itemState.setQuality((Short) struct.getMember(2)); 56 | itemState.setReserved((Short) struct.getMember(3)); 57 | itemState.setValue((JIVariant) struct.getMember(4)); 58 | 59 | return itemState; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /opc-core-dcom/src/main/java/cn/com/sgcc/gdt/opc/core/dcom/da/bean/OpcNamespaceType.java: -------------------------------------------------------------------------------- 1 | package cn.com.sgcc.gdt.opc.core.dcom.da.bean; 2 | 3 | /** 4 | * OPC命名空间类型 5 | * @author ck.yang 6 | */ 7 | public enum OpcNamespaceType { 8 | /** 分级 */ 9 | OPC_NS_HIERARCHIAL(1), 10 | /** 平级 */ 11 | OPC_NS_FLAT(2), 12 | /** 未知 */ 13 | OPC_NS_UNKNOWN(0); 14 | 15 | private int _id; 16 | 17 | private OpcNamespaceType(final int id) { 18 | this._id = id; 19 | } 20 | 21 | public int id() { 22 | return this._id; 23 | } 24 | 25 | public static OpcNamespaceType fromID(final int id) { 26 | switch (id) { 27 | case 1: 28 | return OPC_NS_HIERARCHIAL; 29 | case 2: 30 | return OPC_NS_FLAT; 31 | default: 32 | return OPC_NS_UNKNOWN; 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /opc-core-dcom/src/main/java/cn/com/sgcc/gdt/opc/core/dcom/da/bean/OpcServerState.java: -------------------------------------------------------------------------------- 1 | package cn.com.sgcc.gdt.opc.core.dcom.da.bean; 2 | 3 | /** 4 | * OPC服务状态 5 | * @author ck.yang 6 | */ 7 | public enum OpcServerState { 8 | /** 运行 */ 9 | OPC_STATUS_RUNNING(1), 10 | /** 失败 */ 11 | OPC_STATUS_FAILED(2), 12 | /** 未配置 */ 13 | OPC_STATUS_NOCONFIG(3), 14 | /** 暂停 */ 15 | OPC_STATUS_SUSPENDED(4), 16 | /** 测试 */ 17 | OPC_STATUS_TEST(5), 18 | /** 提交失败 */ 19 | OPC_STATUS_COMM_FAULT(6), 20 | /** 未知 */ 21 | OPC_STATUS_UNKNOWN(0); 22 | 23 | 24 | private int _id; 25 | 26 | private OpcServerState(final int id) { 27 | this._id = id; 28 | } 29 | 30 | public int id() { 31 | return this._id; 32 | } 33 | 34 | public static OpcServerState fromID(final int id) { 35 | switch (id) { 36 | case 1: 37 | return OPC_STATUS_RUNNING; 38 | case 2: 39 | return OPC_STATUS_FAILED; 40 | case 3: 41 | return OPC_STATUS_NOCONFIG; 42 | case 4: 43 | return OPC_STATUS_SUSPENDED; 44 | case 5: 45 | return OPC_STATUS_TEST; 46 | case 6: 47 | return OPC_STATUS_COMM_FAULT; 48 | default: 49 | return OPC_STATUS_UNKNOWN; 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /opc-core-dcom/src/main/java/cn/com/sgcc/gdt/opc/core/dcom/da/bean/OpcServerStatus.java: -------------------------------------------------------------------------------- 1 | package cn.com.sgcc.gdt.opc.core.dcom.da.bean; 2 | 3 | import cn.com.sgcc.gdt.opc.core.dcom.common.bean.FILETIME; 4 | import lombok.Data; 5 | import lombok.ToString; 6 | import org.jinterop.dcom.common.JIException; 7 | import org.jinterop.dcom.core.JIFlags; 8 | import org.jinterop.dcom.core.JIPointer; 9 | import org.jinterop.dcom.core.JIString; 10 | import org.jinterop.dcom.core.JIStruct; 11 | 12 | /** 13 | * OPC服务状态 14 | * @author ck.yang 15 | */ 16 | @Data 17 | @ToString 18 | public class OpcServerStatus { 19 | private FILETIME startTime = null; 20 | 21 | private FILETIME currentTime = null; 22 | 23 | private FILETIME lastUpdateTime = null; 24 | 25 | private OpcServerState serverState = null; 26 | 27 | private int groupCount = -1; 28 | 29 | private int bandWidth = -1; 30 | 31 | private short majorVersion = -1; 32 | 33 | private short minorVersion = -1; 34 | 35 | private short buildNumber = -1; 36 | 37 | private short reserved = 0; 38 | 39 | private String vendorInfo = null; 40 | 41 | 42 | /** 43 | * 转换为JIStruct 44 | * @return 45 | * @throws JIException 46 | */ 47 | public static JIStruct getStruct() throws JIException { 48 | JIStruct struct = new JIStruct(); 49 | 50 | struct.addMember(FILETIME.getStruct()); 51 | struct.addMember(FILETIME.getStruct()); 52 | struct.addMember(FILETIME.getStruct()); 53 | struct.addMember(Short.class); // enum: OpcServerState 54 | struct.addMember(Integer.class); 55 | struct.addMember(Integer.class); 56 | struct.addMember(Short.class); 57 | struct.addMember(Short.class); 58 | struct.addMember(Short.class); 59 | struct.addMember(Short.class); 60 | struct.addMember(new JIPointer(new JIString(JIFlags.FLAG_REPRESENTATION_STRING_LPWSTR))); 61 | 62 | return struct; 63 | } 64 | 65 | /** 66 | * 从JIStruct中取值 67 | * @param struct 68 | * @return 69 | */ 70 | public static OpcServerStatus fromStruct(final JIStruct struct) { 71 | OpcServerStatus status = new OpcServerStatus(); 72 | 73 | status.startTime = FILETIME.fromStruct((JIStruct) struct.getMember(0)); 74 | status.currentTime = FILETIME.fromStruct((JIStruct) struct.getMember(1)); 75 | status.lastUpdateTime = FILETIME.fromStruct((JIStruct) struct.getMember(2)); 76 | 77 | status.serverState = OpcServerState.fromID((Short) struct.getMember(3)); 78 | status.groupCount = (Integer) struct.getMember(4); 79 | status.bandWidth = (Integer) struct.getMember(5); 80 | status.majorVersion = (Short) struct.getMember(6); 81 | status.minorVersion = (Short) struct.getMember(7); 82 | status.buildNumber = (Short) struct.getMember(8); 83 | status.reserved = (Short) struct.getMember(9); 84 | status.vendorInfo = ((JIString) ((JIPointer) struct.getMember(10)).getReferent()).getString(); 85 | 86 | return status; 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /opc-core-dcom/src/main/java/cn/com/sgcc/gdt/opc/core/dcom/da/bean/PropertyDescription.java: -------------------------------------------------------------------------------- 1 | package cn.com.sgcc.gdt.opc.core.dcom.da.bean; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | import lombok.ToString; 7 | 8 | /** 9 | * 属性描述 10 | * @author ck.yang 11 | */ 12 | @Data 13 | @ToString 14 | @NoArgsConstructor 15 | @AllArgsConstructor 16 | public class PropertyDescription { 17 | 18 | private int id = -1; 19 | 20 | private String description = ""; 21 | 22 | private short varType = 0; 23 | 24 | } 25 | -------------------------------------------------------------------------------- /opc-core-dcom/src/main/java/cn/com/sgcc/gdt/opc/core/dcom/da/bean/ValueData.java: -------------------------------------------------------------------------------- 1 | package cn.com.sgcc.gdt.opc.core.dcom.da.bean; 2 | 3 | import java.util.Calendar; 4 | 5 | import lombok.AllArgsConstructor; 6 | import lombok.Data; 7 | import lombok.NoArgsConstructor; 8 | import lombok.ToString; 9 | import org.jinterop.dcom.core.JIVariant; 10 | 11 | /** 12 | * 数据值 13 | * @author ck.yang 14 | */ 15 | @Data 16 | @ToString 17 | @NoArgsConstructor 18 | @AllArgsConstructor 19 | public class ValueData { 20 | /** 值 */ 21 | private JIVariant value; 22 | /** 质量 */ 23 | private short quality; 24 | /** 时间戳 */ 25 | private Calendar timestamp; 26 | 27 | } 28 | -------------------------------------------------------------------------------- /opc-core-dcom/src/main/java/cn/com/sgcc/gdt/opc/core/dcom/da/bean/WriteRequest.java: -------------------------------------------------------------------------------- 1 | package cn.com.sgcc.gdt.opc.core.dcom.da.bean; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | import lombok.ToString; 7 | import org.jinterop.dcom.core.JIVariant; 8 | 9 | /** 10 | * 写入请求 11 | * @author ck.yang 12 | */ 13 | @AllArgsConstructor 14 | @NoArgsConstructor 15 | @Data 16 | @ToString 17 | public class WriteRequest { 18 | 19 | private int serverHandle = 0; 20 | 21 | private JIVariant value = JIVariant.EMPTY(); 22 | 23 | } 24 | -------------------------------------------------------------------------------- /opc-core-dcom/src/main/java/cn/com/sgcc/gdt/opc/core/dcom/da/impl/OPCAsyncIO2.java: -------------------------------------------------------------------------------- 1 | package cn.com.sgcc.gdt.opc.core.dcom.da.impl; 2 | 3 | import cn.com.sgcc.gdt.opc.core.dcom.common.bean.Result; 4 | import cn.com.sgcc.gdt.opc.core.dcom.common.bean.ResultSet; 5 | import cn.com.sgcc.gdt.opc.core.dcom.common.impl.BaseCOMObject; 6 | import cn.com.sgcc.gdt.opc.core.dcom.da.bean.Constants; 7 | import cn.com.sgcc.gdt.opc.core.dcom.da.bean.OpcDatasource; 8 | import org.jinterop.dcom.common.JIException; 9 | import org.jinterop.dcom.core.*; 10 | 11 | import java.net.UnknownHostException; 12 | 13 | /** 14 | * OPC异步访问通道 15 | * @author ck.yang 16 | */ 17 | public class OPCAsyncIO2 extends BaseCOMObject { 18 | 19 | /** 20 | * 异步结果集 21 | * @author ck.yang 22 | */ 23 | public class AsyncResult { 24 | /** 结果集 */ 25 | private final ResultSet result; 26 | /** 取消id */ 27 | private final Integer cancelId; 28 | 29 | public AsyncResult() { 30 | super(); 31 | this.result = new ResultSet(); 32 | this.cancelId = null; 33 | } 34 | 35 | public AsyncResult(final ResultSet result, final Integer cancelId) { 36 | super(); 37 | this.result = result; 38 | this.cancelId = cancelId; 39 | } 40 | 41 | public Integer getCancelId() { 42 | return this.cancelId; 43 | } 44 | 45 | public ResultSet getResult() { 46 | return this.result; 47 | } 48 | } 49 | 50 | public OPCAsyncIO2(final IJIComObject opcAsyncIO2) throws IllegalArgumentException, UnknownHostException, JIException { 51 | super(opcAsyncIO2.queryInterface(Constants.IOPCAsyncIO2_IID)); 52 | } 53 | 54 | public void setEnable(final boolean state) throws JIException { 55 | final JICallBuilder callObject = new JICallBuilder(true); 56 | callObject.setOpnum(4); 57 | 58 | callObject.addInParamAsInt(state ? 1 : 0, JIFlags.FLAG_NULL); 59 | 60 | getCOMObject().call(callObject); 61 | } 62 | 63 | public int refresh(final OpcDatasource dataSource, final int transactionID) throws JIException { 64 | final JICallBuilder callObject = new JICallBuilder(true); 65 | callObject.setOpnum(2); 66 | 67 | callObject.addInParamAsShort((short) dataSource.id(), JIFlags.FLAG_NULL); 68 | callObject.addInParamAsInt(transactionID, JIFlags.FLAG_NULL); 69 | callObject.addOutParamAsType(Integer.class, JIFlags.FLAG_NULL); 70 | 71 | final Object result[] = getCOMObject().call(callObject); 72 | 73 | return (Integer) result[0]; 74 | } 75 | 76 | public void cancel(final int cancelId) throws JIException { 77 | final JICallBuilder callObject = new JICallBuilder(true); 78 | callObject.setOpnum(3); 79 | 80 | callObject.addInParamAsInt(cancelId, JIFlags.FLAG_NULL); 81 | 82 | getCOMObject().call(callObject); 83 | } 84 | 85 | public AsyncResult read(final int transactionId, final Integer... serverHandles) throws JIException { 86 | if (serverHandles == null || serverHandles.length == 0) { 87 | return new AsyncResult(); 88 | } 89 | 90 | final JICallBuilder callObject = new JICallBuilder(true); 91 | callObject.setOpnum(0); 92 | 93 | callObject.addInParamAsInt(serverHandles.length, JIFlags.FLAG_NULL); 94 | callObject.addInParamAsArray(new JIArray(serverHandles, true), JIFlags.FLAG_NULL); 95 | callObject.addInParamAsInt(transactionId, JIFlags.FLAG_NULL); 96 | 97 | callObject.addOutParamAsType(Integer.class, JIFlags.FLAG_NULL); 98 | callObject.addOutParamAsObject(new JIPointer(new JIArray(Integer.class, null, 1, true)), JIFlags.FLAG_NULL); 99 | 100 | final Object[] result = getCOMObject().call(callObject); 101 | 102 | final Integer cancelId = (Integer) result[0]; 103 | final Integer[] errorCodes = (Integer[]) ((JIArray) ((JIPointer) result[1]).getReferent()).getArrayInstance(); 104 | 105 | final ResultSet resultSet = new ResultSet(); 106 | 107 | for (int i = 0; i < serverHandles.length; i++) { 108 | resultSet.add(new Result(serverHandles[i], errorCodes[i])); 109 | } 110 | 111 | return new AsyncResult(resultSet, cancelId); 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /opc-core-dcom/src/main/java/cn/com/sgcc/gdt/opc/core/dcom/da/impl/OPCBrowse.java: -------------------------------------------------------------------------------- 1 | package cn.com.sgcc.gdt.opc.core.dcom.da.impl; 2 | 3 | import cn.com.sgcc.gdt.opc.core.dcom.common.impl.BaseCOMObject; 4 | import cn.com.sgcc.gdt.opc.core.dcom.da.bean.Constants; 5 | import org.jinterop.dcom.common.JIException; 6 | import org.jinterop.dcom.core.IJIComObject; 7 | 8 | import java.net.UnknownHostException; 9 | 10 | /** 11 | * OPC浏览 12 | * @author ck.yang 13 | */ 14 | public class OPCBrowse extends BaseCOMObject { 15 | public OPCBrowse(final IJIComObject opcServer) throws IllegalArgumentException, UnknownHostException, JIException { 16 | super(opcServer.queryInterface(Constants.IOPCBrowse_IID)); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /opc-core-dcom/src/main/java/cn/com/sgcc/gdt/opc/core/dcom/da/impl/OPCBrowseServerAddressSpace.java: -------------------------------------------------------------------------------- 1 | package cn.com.sgcc.gdt.opc.core.dcom.da.impl; 2 | 3 | import cn.com.sgcc.gdt.opc.core.dcom.common.impl.BaseCOMObject; 4 | import cn.com.sgcc.gdt.opc.core.dcom.common.impl.EnumString; 5 | import cn.com.sgcc.gdt.opc.core.dcom.common.impl.Helper; 6 | import cn.com.sgcc.gdt.opc.core.dcom.da.bean.Constants; 7 | import cn.com.sgcc.gdt.opc.core.dcom.da.bean.OpcBrowseDirection; 8 | import cn.com.sgcc.gdt.opc.core.dcom.da.bean.OpcBrowseType; 9 | import cn.com.sgcc.gdt.opc.core.dcom.da.bean.OpcNamespaceType; 10 | import org.jinterop.dcom.common.JIException; 11 | import org.jinterop.dcom.core.*; 12 | 13 | import java.net.UnknownHostException; 14 | 15 | /** 16 | * Implementation for IOPCBrowseServerAddressSpace 17 | * 18 | * @author Jens Reimann 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 | --------------------------------------------------------------------------------