Răsfoiți Sursa

Revert "删除abb解决方法"

This reverts commit e228760b5b9636ed34aba3c928da404dce0dd253.
lhy 7 luni în urmă
părinte
comite
bb905b9f2e
34 a modificat fișierele cu 2355 adăugiri și 2 ștergeri
  1. 3 2
      industry-system/industry-da/pom.xml
  2. 13 0
      industry-system/industry-da/src/main/java/org/openscada/opc/lib/common/AlreadyConnectedException.java
  3. 88 0
      industry-system/industry-da/src/main/java/org/openscada/opc/lib/common/ConnectionInformation.java
  4. 13 0
      industry-system/industry-da/src/main/java/org/openscada/opc/lib/common/NotConnectedException.java
  5. 255 0
      industry-system/industry-da/src/main/java/org/openscada/opc/lib/da/AccessBase.java
  6. 12 0
      industry-system/industry-da/src/main/java/org/openscada/opc/lib/da/AccessStateListener.java
  7. 28 0
      industry-system/industry-da/src/main/java/org/openscada/opc/lib/da/AddFailedException.java
  8. 96 0
      industry-system/industry-da/src/main/java/org/openscada/opc/lib/da/Async20Access.java
  9. 161 0
      industry-system/industry-da/src/main/java/org/openscada/opc/lib/da/AutoReconnectController.java
  10. 10 0
      industry-system/industry-da/src/main/java/org/openscada/opc/lib/da/AutoReconnectListener.java
  11. 17 0
      industry-system/industry-da/src/main/java/org/openscada/opc/lib/da/AutoReconnectState.java
  12. 10 0
      industry-system/industry-da/src/main/java/org/openscada/opc/lib/da/DataCallback.java
  13. 13 0
      industry-system/industry-da/src/main/java/org/openscada/opc/lib/da/DuplicateGroupException.java
  14. 43 0
      industry-system/industry-da/src/main/java/org/openscada/opc/lib/da/ErrorMessageResolver.java
  15. 335 0
      industry-system/industry-da/src/main/java/org/openscada/opc/lib/da/Group.java
  16. 55 0
      industry-system/industry-da/src/main/java/org/openscada/opc/lib/da/Item.java
  17. 113 0
      industry-system/industry-da/src/main/java/org/openscada/opc/lib/da/ItemState.java
  18. 308 0
      industry-system/industry-da/src/main/java/org/openscada/opc/lib/da/Server.java
  19. 10 0
      industry-system/industry-da/src/main/java/org/openscada/opc/lib/da/ServerConnectionStateListener.java
  20. 12 0
      industry-system/industry-da/src/main/java/org/openscada/opc/lib/da/ServerStateListener.java
  21. 71 0
      industry-system/industry-da/src/main/java/org/openscada/opc/lib/da/ServerStateOperation.java
  22. 70 0
      industry-system/industry-da/src/main/java/org/openscada/opc/lib/da/ServerStateReader.java
  23. 81 0
      industry-system/industry-da/src/main/java/org/openscada/opc/lib/da/SyncAccess.java
  24. 23 0
      industry-system/industry-da/src/main/java/org/openscada/opc/lib/da/UnknownGroupException.java
  25. 26 0
      industry-system/industry-da/src/main/java/org/openscada/opc/lib/da/WriteRequest.java
  26. 21 0
      industry-system/industry-da/src/main/java/org/openscada/opc/lib/da/browser/Access.java
  27. 57 0
      industry-system/industry-da/src/main/java/org/openscada/opc/lib/da/browser/BaseBrowser.java
  28. 64 0
      industry-system/industry-da/src/main/java/org/openscada/opc/lib/da/browser/Branch.java
  29. 39 0
      industry-system/industry-da/src/main/java/org/openscada/opc/lib/da/browser/FlatBrowser.java
  30. 43 0
      industry-system/industry-da/src/main/java/org/openscada/opc/lib/da/browser/Leaf.java
  31. 121 0
      industry-system/industry-da/src/main/java/org/openscada/opc/lib/da/browser/TreeBrowser.java
  32. 13 0
      industry-system/industry-da/src/main/java/org/openscada/opc/lib/list/Categories.java
  33. 46 0
      industry-system/industry-da/src/main/java/org/openscada/opc/lib/list/Category.java
  34. 85 0
      industry-system/industry-da/src/main/java/org/openscada/opc/lib/list/ServerList.java

+ 3 - 2
industry-system/industry-da/pom.xml

@@ -189,11 +189,12 @@
         <!--            <artifactId>bcprov-jdk15on</artifactId>-->
         <!--            <version>1.61</version>-->
         <!--        </dependency>-->
-        <dependency>
+        <!-- 需要改源码,直接复制代码到项目中 -->
+        <!--<dependency>
             <groupId>org.openscada.utgard</groupId>
             <artifactId>org.openscada.opc.lib</artifactId>
             <version>1.5.0</version>
-        </dependency>
+        </dependency>-->
         <dependency>
             <groupId>org.bouncycastle</groupId>
             <artifactId>bcprov-jdk15on</artifactId>

+ 13 - 0
industry-system/industry-da/src/main/java/org/openscada/opc/lib/common/AlreadyConnectedException.java

@@ -0,0 +1,13 @@
+//
+// Source code recreated from a .class file by IntelliJ IDEA
+// (powered by FernFlower decompiler)
+//
+
+package org.openscada.opc.lib.common;
+
+public class AlreadyConnectedException extends Exception {
+  private static final long serialVersionUID = -6494637563117314114L;
+
+  public AlreadyConnectedException() {
+  }
+}

+ 88 - 0
industry-system/industry-da/src/main/java/org/openscada/opc/lib/common/ConnectionInformation.java

@@ -0,0 +1,88 @@
+//
+// Source code recreated from a .class file by IntelliJ IDEA
+// (powered by FernFlower decompiler)
+//
+
+package org.openscada.opc.lib.common;
+
+public class ConnectionInformation {
+    private String _host = "localhost";
+    private String _domain = "localhost";
+    private String _user = "";
+    private String _password = "";
+    private String _clsid = null;
+    private String _progId = null;
+
+    public ConnectionInformation() {
+    }
+
+    public ConnectionInformation(String user, String password) {
+        this._user = user;
+        this._password = password;
+    }
+
+    public ConnectionInformation(ConnectionInformation arg0) {
+        this._user = arg0._user;
+        this._password = arg0._password;
+        this._domain = arg0._domain;
+        this._host = arg0._host;
+        this._progId = arg0._progId;
+        this._clsid = arg0._clsid;
+    }
+
+    public String getDomain() {
+        return this._domain;
+    }
+
+    public void setDomain(String domain) {
+        this._domain = domain;
+    }
+
+    public String getHost() {
+        return this._host;
+    }
+
+    public void setHost(String host) {
+        this._host = host;
+    }
+
+    public String getPassword() {
+        return this._password;
+    }
+
+    public void setPassword(String password) {
+        this._password = password;
+    }
+
+    public String getUser() {
+        return this._user;
+    }
+
+    public void setUser(String user) {
+        this._user = user;
+    }
+
+    public String getClsid() {
+        return this._clsid;
+    }
+
+    public void setClsid(String clsid) {
+        this._clsid = clsid;
+    }
+
+    public String getProgId() {
+        return this._progId;
+    }
+
+    public void setProgId(String progId) {
+        this._progId = progId;
+    }
+
+    public String getClsOrProgId() {
+        if (this._clsid != null) {
+            return this._clsid;
+        } else {
+            return this._progId != null ? this._progId : null;
+        }
+    }
+}

+ 13 - 0
industry-system/industry-da/src/main/java/org/openscada/opc/lib/common/NotConnectedException.java

@@ -0,0 +1,13 @@
+//
+// Source code recreated from a .class file by IntelliJ IDEA
+// (powered by FernFlower decompiler)
+//
+
+package org.openscada.opc.lib.common;
+
+public class NotConnectedException extends Exception {
+  private static final long serialVersionUID = -3745147771605524635L;
+
+  public NotConnectedException() {
+  }
+}

+ 255 - 0
industry-system/industry-da/src/main/java/org/openscada/opc/lib/da/AccessBase.java

@@ -0,0 +1,255 @@
+//
+// Source code recreated from a .class file by IntelliJ IDEA
+// (powered by FernFlower decompiler)
+//
+
+package org.openscada.opc.lib.da;
+
+import java.net.UnknownHostException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.CopyOnWriteArrayList;
+import org.jinterop.dcom.common.JIException;
+import org.openscada.opc.lib.common.NotConnectedException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public abstract class AccessBase implements ServerConnectionStateListener {
+    private static Logger logger = LoggerFactory.getLogger(AccessBase.class);
+    protected Server server;
+    protected Group group;
+    protected boolean active;
+    private final List<AccessStateListener> stateListeners = new CopyOnWriteArrayList();
+    private boolean bound;
+    protected Map<Item, DataCallback> items = new HashMap();
+    protected Map<String, Item> itemMap = new HashMap();
+    protected Map<Item, ItemState> itemCache = new HashMap();
+    private final int period;
+    protected Map<String, DataCallback> itemSet = new HashMap();
+    protected String logTag;
+    protected Logger dataLogger;
+
+    public AccessBase(Server server, int period) throws IllegalArgumentException, UnknownHostException, NotConnectedException, JIException, DuplicateGroupException {
+        this.server = server;
+        this.period = period;
+    }
+
+    public AccessBase(Server server, int period, String logTag) {
+        this.server = server;
+        this.period = period;
+        this.logTag = logTag;
+        if (this.logTag != null) {
+            this.dataLogger = LoggerFactory.getLogger("opc.data." + logTag);
+        }
+
+    }
+
+    public boolean isBound() {
+        return this.bound;
+    }
+
+    public synchronized void bind() {
+        if (!this.isBound()) {
+            this.server.addStateListener(this);
+            this.bound = true;
+        }
+    }
+
+    public synchronized void unbind() throws JIException {
+        if (this.isBound()) {
+            this.server.removeStateListener(this);
+            this.bound = false;
+            this.stop();
+        }
+    }
+
+    public boolean isActive() {
+        return this.active;
+    }
+
+    public void addStateListener(AccessStateListener listener) {
+        this.stateListeners.add(listener);
+        listener.stateChanged(this.isActive());
+    }
+
+    public void removeStateListener(AccessStateListener listener) {
+        this.stateListeners.remove(listener);
+    }
+
+    protected void notifyStateListenersState(boolean state) {
+        List<AccessStateListener> list = new ArrayList(this.stateListeners);
+        Iterator var4 = list.iterator();
+
+        while(var4.hasNext()) {
+            AccessStateListener listener = (AccessStateListener)var4.next();
+            listener.stateChanged(state);
+        }
+
+    }
+
+    protected void notifyStateListenersError(Throwable t) {
+        List<AccessStateListener> list = new ArrayList(this.stateListeners);
+        Iterator var4 = list.iterator();
+
+        while(var4.hasNext()) {
+            AccessStateListener listener = (AccessStateListener)var4.next();
+            listener.errorOccured(t);
+        }
+
+    }
+
+    public int getPeriod() {
+        return this.period;
+    }
+
+    public synchronized void addItem(String itemId, DataCallback dataCallback) throws JIException, AddFailedException {
+        if (!this.itemSet.containsKey(itemId)) {
+            this.itemSet.put(itemId, dataCallback);
+            if (this.isActive()) {
+                this.realizeItem(itemId);
+            }
+
+        }
+    }
+
+    public synchronized void removeItem(String itemId) {
+        if (this.itemSet.containsKey(itemId)) {
+            this.itemSet.remove(itemId);
+            if (this.isActive()) {
+                this.unrealizeItem(itemId);
+            }
+
+        }
+    }
+
+    public void connectionStateChanged(boolean connected) {
+        try {
+            if (connected) {
+                this.start();
+            } else {
+                this.stop();
+            }
+        } catch (Exception var3) {
+            logger.error(String.format("Failed to change state (%s)", connected), var3);
+        }
+
+    }
+
+    protected synchronized void start() throws JIException, IllegalArgumentException, UnknownHostException, NotConnectedException, DuplicateGroupException {
+        if (!this.isActive()) {
+            logger.debug("Create a new group");
+            this.group = this.server.addGroup();
+            this.group.setActive(true, this.period);
+            this.active = true;
+            this.notifyStateListenersState(true);
+            this.realizeAll();
+        }
+    }
+
+    protected void realizeItem(String itemId) throws JIException, AddFailedException {
+        logger.debug("Realizing item: {}", itemId);
+        DataCallback dataCallback = (DataCallback)this.itemSet.get(itemId);
+        if (dataCallback != null) {
+            Item item = this.group.addItem(itemId);
+            this.items.put(item, dataCallback);
+            this.itemMap.put(itemId, item);
+        }
+    }
+
+    protected void unrealizeItem(String itemId) {
+        Item item = (Item)this.itemMap.remove(itemId);
+        this.items.remove(item);
+        this.itemCache.remove(item);
+
+        try {
+            this.group.removeItem(itemId);
+        } catch (Throwable var4) {
+            logger.error(String.format("Failed to unrealize item '%s'", itemId), var4);
+        }
+
+    }
+
+    protected void realizeAll() {
+        Iterator var2 = this.itemSet.keySet().iterator();
+
+        while(var2.hasNext()) {
+            String itemId = (String)var2.next();
+
+            try {
+                this.realizeItem(itemId);
+            } catch (AddFailedException var5) {
+                Integer rc = (Integer)var5.getErrors().get(itemId);
+                if (rc == null) {
+                    rc = -1;
+                }
+
+                logger.warn(String.format("Failed to add item: %s (%08X)", itemId, rc));
+            } catch (Exception var6) {
+                logger.warn("Failed to realize item: " + itemId, var6);
+            }
+        }
+
+    }
+
+    protected void unrealizeAll() {
+        this.items.clear();
+        this.itemCache.clear();
+
+        try {
+            this.group.clear();
+        } catch (JIException var2) {
+            logger.info("Failed to clear group. No problem if we already lost the connection", var2);
+        }
+
+    }
+
+    protected synchronized void stop() throws JIException {
+        if (this.isActive()) {
+            this.unrealizeAll();
+            this.active = false;
+            this.notifyStateListenersState(false);
+
+            try {
+                this.group.remove();
+            } catch (Throwable var2) {
+                logger.warn("Failed to disable group. No problem if we already lost connection");
+            }
+
+            this.group = null;
+        }
+    }
+
+    public synchronized void clear() {
+        this.itemSet.clear();
+        this.items.clear();
+        this.itemMap.clear();
+        this.itemCache.clear();
+    }
+
+    protected void updateItem(Item item, ItemState itemState) {
+        if (this.dataLogger != null) {
+            this.dataLogger.debug("Update item: {}, {}", item.getId(), itemState);
+        }
+
+        DataCallback dataCallback = (DataCallback)this.items.get(item);
+        if (dataCallback != null) {
+            ItemState cachedState = (ItemState)this.itemCache.get(item);
+            if (cachedState == null) {
+                this.itemCache.put(item, itemState);
+                dataCallback.changed(item, itemState);
+            } else if (!cachedState.equals(itemState)) {
+                this.itemCache.put(item, itemState);
+                dataCallback.changed(item, itemState);
+            }
+
+        }
+    }
+
+    protected void handleError(Throwable e) {
+        this.notifyStateListenersError(e);
+        this.server.dispose();
+    }
+}

+ 12 - 0
industry-system/industry-da/src/main/java/org/openscada/opc/lib/da/AccessStateListener.java

@@ -0,0 +1,12 @@
+//
+// Source code recreated from a .class file by IntelliJ IDEA
+// (powered by FernFlower decompiler)
+//
+
+package org.openscada.opc.lib.da;
+
+public interface AccessStateListener {
+  void stateChanged(boolean var1);
+
+  void errorOccured(Throwable var1);
+}

+ 28 - 0
industry-system/industry-da/src/main/java/org/openscada/opc/lib/da/AddFailedException.java

@@ -0,0 +1,28 @@
+//
+// Source code recreated from a .class file by IntelliJ IDEA
+// (powered by FernFlower decompiler)
+//
+
+package org.openscada.opc.lib.da;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class AddFailedException extends Exception {
+    private static final long serialVersionUID = 5299486640366935298L;
+    private Map<String, Integer> _errors = new HashMap();
+    private Map<String, Item> _items = new HashMap();
+
+    public AddFailedException(Map<String, Integer> errors, Map<String, Item> items) {
+        this._errors = errors;
+        this._items = items;
+    }
+
+    public Map<String, Integer> getErrors() {
+        return this._errors;
+    }
+
+    public Map<String, Item> getItems() {
+        return this._items;
+    }
+}

+ 96 - 0
industry-system/industry-da/src/main/java/org/openscada/opc/lib/da/Async20Access.java

@@ -0,0 +1,96 @@
+//
+// Source code recreated from a .class file by IntelliJ IDEA
+// (powered by FernFlower decompiler)
+//
+
+package org.openscada.opc.lib.da;
+
+import java.net.UnknownHostException;
+import java.util.Iterator;
+import org.jinterop.dcom.common.JIException;
+import org.openscada.opc.dcom.common.EventHandler;
+import org.openscada.opc.dcom.common.KeyedResult;
+import org.openscada.opc.dcom.common.KeyedResultSet;
+import org.openscada.opc.dcom.common.ResultSet;
+import org.openscada.opc.dcom.da.IOPCDataCallback;
+import org.openscada.opc.dcom.da.OPCDATASOURCE;
+import org.openscada.opc.dcom.da.ValueData;
+import org.openscada.opc.dcom.da.impl.OPCAsyncIO2;
+import org.openscada.opc.lib.common.NotConnectedException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class Async20Access extends AccessBase implements IOPCDataCallback {
+    private static Logger logger = LoggerFactory.getLogger(Async20Access.class);
+    private EventHandler eventHandler = null;
+    private boolean initialRefresh = false;
+
+    public Async20Access(Server server, int period, boolean initialRefresh) throws IllegalArgumentException, UnknownHostException, NotConnectedException, JIException, DuplicateGroupException {
+        super(server, period);
+        this.initialRefresh = initialRefresh;
+    }
+
+    public Async20Access(Server server, int period, boolean initialRefresh, String logTag) throws IllegalArgumentException, UnknownHostException, NotConnectedException, JIException, DuplicateGroupException {
+        super(server, period, logTag);
+        this.initialRefresh = initialRefresh;
+    }
+
+    protected synchronized void start() throws JIException, IllegalArgumentException, UnknownHostException, NotConnectedException, DuplicateGroupException {
+        if (!this.isActive()) {
+            super.start();
+            this.eventHandler = this.group.attach(this);
+            if (!this.items.isEmpty() && this.initialRefresh) {
+                OPCAsyncIO2 async20 = this.group.getAsyncIO20();
+                if (async20 == null) {
+                    throw new NotConnectedException();
+                }
+
+                this.group.getAsyncIO20().refresh(OPCDATASOURCE.OPC_DS_CACHE, 0);
+            }
+
+        }
+    }
+
+    protected synchronized void stop() throws JIException {
+        if (this.isActive()) {
+            if (this.eventHandler != null) {
+                try {
+                    this.eventHandler.detach();
+                } catch (Throwable var2) {
+                    logger.warn("Failed to detach group", var2);
+                }
+
+                this.eventHandler = null;
+            }
+
+            super.stop();
+        }
+    }
+
+    public void cancelComplete(int transactionId, int serverGroupHandle) {
+    }
+
+    public void dataChange(int transactionId, int serverGroupHandle, int masterQuality, int masterErrorCode, KeyedResultSet<Integer, ValueData> result) {
+        logger.debug("dataChange - transId {}, items: {}", transactionId, result.size());
+        Group group = this.group;
+        if (group != null) {
+            Iterator var8 = result.iterator();
+
+            while(var8.hasNext()) {
+                KeyedResult<Integer, ValueData> entry = (KeyedResult)var8.next();
+                Item item = group.findItemByClientHandle((Integer)entry.getKey());
+                logger.debug("Update for '{}'", item.getId());
+                this.updateItem(item, new ItemState(entry.getErrorCode(), ((ValueData)entry.getValue()).getValue(), ((ValueData)entry.getValue()).getTimestamp(), ((ValueData)entry.getValue()).getQuality()));
+            }
+
+        }
+    }
+
+    public void readComplete(int transactionId, int serverGroupHandle, int masterQuality, int masterErrorCode, KeyedResultSet<Integer, ValueData> result) {
+        logger.debug("readComplete - transId {}", transactionId);
+    }
+
+    public void writeComplete(int transactionId, int serverGroupHandle, int masterErrorCode, ResultSet<Integer> result) {
+        logger.debug("writeComplete - transId {}", transactionId);
+    }
+}

+ 161 - 0
industry-system/industry-da/src/main/java/org/openscada/opc/lib/da/AutoReconnectController.java

@@ -0,0 +1,161 @@
+//
+// Source code recreated from a .class file by IntelliJ IDEA
+// (powered by FernFlower decompiler)
+//
+
+package org.openscada.opc.lib.da;
+
+import java.util.Iterator;
+import java.util.Set;
+import java.util.concurrent.CopyOnWriteArraySet;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class AutoReconnectController implements ServerConnectionStateListener {
+    private static Logger _log = LoggerFactory.getLogger(AutoReconnectController.class);
+    private static final int DEFAULT_DELAY = 5000;
+    private int _delay;
+    private final Server _server;
+    private final Set<AutoReconnectListener> _listeners;
+    private AutoReconnectState _state;
+    private Thread _connectTask;
+
+    public AutoReconnectController(Server server) {
+        this(server, 5000);
+    }
+
+    public AutoReconnectController(Server server, int delay) {
+        this._listeners = new CopyOnWriteArraySet();
+        this._state = AutoReconnectState.DISABLED;
+        this._connectTask = null;
+        this.setDelay(delay);
+        this._server = server;
+        this._server.addStateListener(this);
+    }
+
+    public void addListener(AutoReconnectListener listener) {
+        if (listener != null) {
+            this._listeners.add(listener);
+            listener.stateChanged(this._state);
+        }
+
+    }
+
+    public void removeListener(AutoReconnectListener listener) {
+        this._listeners.remove(listener);
+    }
+
+    protected void notifyStateChange(AutoReconnectState state) {
+        this._state = state;
+        Iterator var3 = this._listeners.iterator();
+
+        while(var3.hasNext()) {
+            AutoReconnectListener listener = (AutoReconnectListener)var3.next();
+            listener.stateChanged(state);
+        }
+
+    }
+
+    public int getDelay() {
+        return this._delay;
+    }
+
+    public void setDelay(int delay) {
+        if (delay <= 0) {
+            delay = 5000;
+        }
+
+        this._delay = delay;
+    }
+
+    public synchronized void connect() {
+        if (!this.isRequested()) {
+            _log.debug("Requesting connection");
+            this.notifyStateChange(AutoReconnectState.DISCONNECTED);
+            this.triggerReconnect(false);
+        }
+    }
+
+    public synchronized void disconnect() {
+        if (this.isRequested()) {
+            _log.debug("Un-Requesting connection");
+            this.notifyStateChange(AutoReconnectState.DISABLED);
+            this._server.disconnect();
+        }
+    }
+
+    public boolean isRequested() {
+        return this._state != AutoReconnectState.DISABLED;
+    }
+
+    public synchronized void connectionStateChanged(boolean connected) {
+        _log.debug("Connection state changed: " + connected);
+        if (!connected) {
+            if (this.isRequested()) {
+                this.notifyStateChange(AutoReconnectState.DISCONNECTED);
+                this.triggerReconnect(true);
+            }
+        } else if (!this.isRequested()) {
+            this._server.disconnect();
+        } else {
+            this.notifyStateChange(AutoReconnectState.CONNECTED);
+        }
+
+    }
+
+    private synchronized void triggerReconnect(final boolean wait) {
+        if (this._connectTask != null) {
+            _log.info("Connect thread already running");
+        } else {
+            _log.debug("Trigger reconnect");
+            this._connectTask = new Thread(new Runnable() {
+                public void run() {
+                    boolean result = false;
+
+                    try {
+                        result = AutoReconnectController.this.performReconnect(wait);
+                    } finally {
+                        AutoReconnectController.this._connectTask = null;
+                        AutoReconnectController._log.debug(String.format("performReconnect completed : %s", result));
+                        if (!result) {
+                            AutoReconnectController.this.triggerReconnect(true);
+                        }
+
+                    }
+
+                }
+            }, "OPCReconnectThread");
+            this._connectTask.setDaemon(true);
+            this._connectTask.start();
+        }
+    }
+
+    private boolean performReconnect(boolean wait) {
+        try {
+            if (wait) {
+                this.notifyStateChange(AutoReconnectState.WAITING);
+                _log.debug(String.format("Delaying (%s)...", this._delay));
+                Thread.sleep((long)this._delay);
+            }
+        } catch (InterruptedException var5) {
+        }
+
+        if (!this.isRequested()) {
+            _log.debug("Request canceled during delay");
+            return true;
+        } else {
+            try {
+                _log.debug("Connecting to server");
+                this.notifyStateChange(AutoReconnectState.CONNECTING);
+                synchronized(this) {
+                    this._server.connect();
+                    return true;
+                }
+            } catch (Throwable var4) {
+                _log.info("Re-connect failed", var4);
+                this.notifyStateChange(AutoReconnectState.DISCONNECTED);
+                return false;
+            }
+        }
+    }
+}

+ 10 - 0
industry-system/industry-da/src/main/java/org/openscada/opc/lib/da/AutoReconnectListener.java

@@ -0,0 +1,10 @@
+//
+// Source code recreated from a .class file by IntelliJ IDEA
+// (powered by FernFlower decompiler)
+//
+
+package org.openscada.opc.lib.da;
+
+public interface AutoReconnectListener {
+  void stateChanged(AutoReconnectState var1);
+}

+ 17 - 0
industry-system/industry-da/src/main/java/org/openscada/opc/lib/da/AutoReconnectState.java

@@ -0,0 +1,17 @@
+//
+// Source code recreated from a .class file by IntelliJ IDEA
+// (powered by FernFlower decompiler)
+//
+
+package org.openscada.opc.lib.da;
+
+public enum AutoReconnectState {
+    DISABLED,
+    DISCONNECTED,
+    WAITING,
+    CONNECTING,
+    CONNECTED;
+
+    private AutoReconnectState() {
+    }
+}

+ 10 - 0
industry-system/industry-da/src/main/java/org/openscada/opc/lib/da/DataCallback.java

@@ -0,0 +1,10 @@
+//
+// Source code recreated from a .class file by IntelliJ IDEA
+// (powered by FernFlower decompiler)
+//
+
+package org.openscada.opc.lib.da;
+
+public interface DataCallback {
+  void changed(Item var1, ItemState var2);
+}

+ 13 - 0
industry-system/industry-da/src/main/java/org/openscada/opc/lib/da/DuplicateGroupException.java

@@ -0,0 +1,13 @@
+//
+// Source code recreated from a .class file by IntelliJ IDEA
+// (powered by FernFlower decompiler)
+//
+
+package org.openscada.opc.lib.da;
+
+public class DuplicateGroupException extends Exception {
+  private static final long serialVersionUID = 826553520690295478L;
+
+  public DuplicateGroupException() {
+  }
+}

+ 43 - 0
industry-system/industry-da/src/main/java/org/openscada/opc/lib/da/ErrorMessageResolver.java

@@ -0,0 +1,43 @@
+//
+// Source code recreated from a .class file by IntelliJ IDEA
+// (powered by FernFlower decompiler)
+//
+
+package org.openscada.opc.lib.da;
+
+import java.util.HashMap;
+import java.util.Map;
+import org.jinterop.dcom.common.JIException;
+import org.openscada.opc.dcom.common.impl.OPCCommon;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class ErrorMessageResolver {
+    private static Logger _log = LoggerFactory.getLogger(ErrorMessageResolver.class);
+    private OPCCommon _opcCommon = null;
+    private final Map<Integer, String> _messageCache = new HashMap();
+    private int _localeId = 0;
+
+    public ErrorMessageResolver(OPCCommon opcCommon, int localeId) {
+        this._opcCommon = opcCommon;
+        this._localeId = localeId;
+    }
+
+    public synchronized String getMessage(int errorCode) {
+        String message = (String)this._messageCache.get(errorCode);
+        if (message == null) {
+            try {
+                message = this._opcCommon.getErrorString(errorCode, this._localeId);
+                _log.info(String.format("Resolved %08X to '%s'", errorCode, message));
+            } catch (JIException var4) {
+                _log.warn(String.format("Failed to resolve error code for %08X", errorCode), var4);
+            }
+
+            if (message != null) {
+                this._messageCache.put(errorCode, message);
+            }
+        }
+
+        return message;
+    }
+}

+ 335 - 0
industry-system/industry-da/src/main/java/org/openscada/opc/lib/da/Group.java

@@ -0,0 +1,335 @@
+//
+// Source code recreated from a .class file by IntelliJ IDEA
+// (powered by FernFlower decompiler)
+//
+
+package org.openscada.opc.lib.da;
+
+import java.net.UnknownHostException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Random;
+import java.util.Set;
+import org.jinterop.dcom.common.JIException;
+import org.openscada.opc.dcom.common.EventHandler;
+import org.openscada.opc.dcom.common.KeyedResult;
+import org.openscada.opc.dcom.common.KeyedResultSet;
+import org.openscada.opc.dcom.common.Result;
+import org.openscada.opc.dcom.common.ResultSet;
+import org.openscada.opc.dcom.da.IOPCDataCallback;
+import org.openscada.opc.dcom.da.OPCDATASOURCE;
+import org.openscada.opc.dcom.da.OPCITEMDEF;
+import org.openscada.opc.dcom.da.OPCITEMRESULT;
+import org.openscada.opc.dcom.da.OPCITEMSTATE;
+import org.openscada.opc.dcom.da.impl.OPCAsyncIO2;
+import org.openscada.opc.dcom.da.impl.OPCGroupStateMgt;
+import org.openscada.opc.dcom.da.impl.OPCItemMgt;
+import org.openscada.opc.dcom.da.impl.OPCSyncIO;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class Group {
+    private static Logger _log = LoggerFactory.getLogger(Group.class);
+    private static Random _random = new Random();
+    private Server _server = null;
+    private final int _serverHandle;
+    private OPCGroupStateMgt _group = null;
+    private OPCItemMgt _items = null;
+    private OPCSyncIO _syncIO = null;
+    private final Map<String, Integer> _itemHandleMap = new HashMap();
+    private final Map<Integer, Item> _itemMap = new HashMap();
+    private final Map<Integer, Item> _itemClientMap = new HashMap();
+
+    Group(Server server, int serverHandle, OPCGroupStateMgt group) throws IllegalArgumentException, UnknownHostException, JIException {
+        _log.debug("Creating new group instance with COM group " + group);
+        this._server = server;
+        this._serverHandle = serverHandle;
+        this._group = group;
+        this._items = group.getItemManagement();
+        this._syncIO = group.getSyncIO();
+    }
+
+    public void setActive(boolean state) throws JIException {
+        this._group.setState((Integer)null, state, (Integer)null, (Float)null, (Integer)null, (Integer)null);
+    }
+
+    public void setActive(boolean state, int period) throws JIException {
+        this._group.setState(period, state, (Integer)null, (Float)null, (Integer)null, (Integer)null);
+    }
+
+    public void remove() throws JIException {
+        this._server.removeGroup(this, true);
+    }
+
+    public boolean isActive() throws JIException {
+        return this._group.getState().isActive();
+    }
+
+    public String getName() throws JIException {
+        return this._group.getState().getName();
+    }
+
+    public void setName(String name) throws JIException {
+        this._group.setName(name);
+    }
+
+    public Item addItem(String item) throws JIException, AddFailedException {
+        Map<String, Item> items = this.addItems(item);
+        return (Item)items.get(item);
+    }
+
+    public synchronized Map<String, Result<OPCITEMRESULT>> validateItems(String... items) throws JIException {
+        OPCITEMDEF[] defs = new OPCITEMDEF[items.length];
+
+        for(int i = 0; i < items.length; ++i) {
+            defs[i] = new OPCITEMDEF();
+            defs[i].setItemID(items[i]);
+        }
+
+        KeyedResultSet<OPCITEMDEF, OPCITEMRESULT> result = this._items.validate(defs);
+        Map<String, Result<OPCITEMRESULT>> resultMap = new HashMap();
+        Iterator var6 = result.iterator();
+
+        while(var6.hasNext()) {
+            KeyedResult<OPCITEMDEF, OPCITEMRESULT> resultEntry = (KeyedResult)var6.next();
+            resultMap.put(((OPCITEMDEF)resultEntry.getKey()).getItemID(), new Result((OPCITEMRESULT)resultEntry.getValue(), resultEntry.getErrorCode()));
+        }
+
+        return resultMap;
+    }
+
+    public synchronized Map<String, Item> addItems(String... items) throws JIException, AddFailedException {
+        Map<String, Integer> handles = this.findItems(items);
+        List<Integer> foundItems = new ArrayList(items.length);
+        List<String> missingItems = new ArrayList();
+        Iterator var6 = handles.entrySet().iterator();
+
+        while(var6.hasNext()) {
+            Map.Entry<String, Integer> entry = (Map.Entry)var6.next();
+            if (entry.getValue() == null) {
+                missingItems.add((String)entry.getKey());
+            } else {
+                foundItems.add((Integer)entry.getValue());
+            }
+        }
+
+        Set<Integer> newClientHandles = new HashSet();
+        OPCITEMDEF[] itemDef = new OPCITEMDEF[missingItems.size()];
+
+        for(int i = 0; i < missingItems.size(); ++i) {
+            OPCITEMDEF def = new OPCITEMDEF();
+            def.setItemID((String)missingItems.get(i));
+            def.setActive(true);
+
+            Integer clientHandle;
+            do {
+                clientHandle = _random.nextInt();
+            } while(this._itemClientMap.containsKey(clientHandle) || newClientHandles.contains(clientHandle));
+
+            newClientHandles.add(clientHandle);
+            def.setClientHandle(clientHandle);
+            itemDef[i] = def;
+        }
+
+        Map<String, Integer> failedItems = new HashMap();
+        KeyedResultSet<OPCITEMDEF, OPCITEMRESULT> result = this._items.add(itemDef);
+        int i = 0;
+
+        for(Iterator var11 = result.iterator(); var11.hasNext(); ++i) {
+            KeyedResult<OPCITEMDEF, OPCITEMRESULT> entry = (KeyedResult)var11.next();
+            if (entry.getErrorCode() == 0) {
+                Item item = new Item(this, ((OPCITEMRESULT)entry.getValue()).getServerHandle(), itemDef[i].getClientHandle(), ((OPCITEMDEF)entry.getKey()).getItemID());
+                this.addItem(item);
+                foundItems.add(item.getServerHandle());
+            } else {
+                failedItems.put(((OPCITEMDEF)entry.getKey()).getItemID(), entry.getErrorCode());
+            }
+        }
+
+        if (failedItems.size() != 0) {
+            throw new AddFailedException(failedItems, this.findItems((Collection)foundItems));
+        } else {
+            return this.findItems((Collection)foundItems);
+        }
+    }
+
+    private synchronized void addItem(Item item) {
+        _log.debug(String.format("Adding item: '%s', %d", item.getId(), item.getServerHandle()));
+        this._itemHandleMap.put(item.getId(), item.getServerHandle());
+        this._itemMap.put(item.getServerHandle(), item);
+        this._itemClientMap.put(item.getClientHandle(), item);
+    }
+
+    private synchronized void removeItem(Item item) {
+        this._itemHandleMap.remove(item.getId());
+        this._itemMap.remove(item.getServerHandle());
+        this._itemClientMap.remove(item.getClientHandle());
+    }
+
+    protected Item getItemByOPCItemId(String opcItemId) {
+        Integer serverHandle = (Integer)this._itemHandleMap.get(opcItemId);
+        if (serverHandle == null) {
+            _log.debug(String.format("Failed to locate item with id '%s'", opcItemId));
+            return null;
+        } else {
+            _log.debug(String.format("Item '%s' has server id '%d'", opcItemId, serverHandle));
+            return (Item)this._itemMap.get(serverHandle);
+        }
+    }
+
+    private synchronized Map<String, Integer> findItems(String[] items) {
+        Map<String, Integer> data = new HashMap();
+
+        for(int i = 0; i < items.length; ++i) {
+            data.put(items[i], (Integer)this._itemHandleMap.get(items[i]));
+        }
+
+        return data;
+    }
+
+    private synchronized Map<String, Item> findItems(Collection<Integer> handles) {
+        Map<String, Item> itemMap = new HashMap();
+        Iterator var4 = handles.iterator();
+
+        while(var4.hasNext()) {
+            Integer i = (Integer)var4.next();
+            Item item = (Item)this._itemMap.get(i);
+            if (item != null) {
+                itemMap.put(item.getId(), item);
+            }
+        }
+
+        return itemMap;
+    }
+
+    protected void checkItems(Item[] items) {
+        Item[] var5 = items;
+        int var4 = items.length;
+
+        for(int var3 = 0; var3 < var4; ++var3) {
+            Item item = var5[var3];
+            if (item.getGroup() != this) {
+                throw new IllegalArgumentException("Item does not belong to this group");
+            }
+        }
+
+    }
+
+    public void setActive(boolean state, Item... items) throws JIException {
+        this.checkItems(items);
+        Integer[] handles = new Integer[items.length];
+
+        for(int i = 0; i < items.length; ++i) {
+            handles[i] = items[i].getServerHandle();
+        }
+
+        this._items.setActiveState(state, handles);
+    }
+
+    protected Integer[] getServerHandles(Item[] items) {
+        this.checkItems(items);
+        Integer[] handles = new Integer[items.length];
+
+        for(int i = 0; i < items.length; ++i) {
+            handles[i] = items[i].getServerHandle();
+        }
+
+        return handles;
+    }
+
+    public synchronized Map<Item, Integer> write(WriteRequest... requests) throws JIException {
+        Item[] items = new Item[requests.length];
+
+        for(int i = 0; i < requests.length; ++i) {
+            items[i] = requests[i].getItem();
+        }
+
+        Integer[] handles = this.getServerHandles(items);
+        org.openscada.opc.dcom.da.WriteRequest[] wr = new org.openscada.opc.dcom.da.WriteRequest[items.length];
+
+        for(int i = 0; i < items.length; ++i) {
+            wr[i] = new org.openscada.opc.dcom.da.WriteRequest(handles[i], requests[i].getValue());
+        }
+
+        ResultSet<org.openscada.opc.dcom.da.WriteRequest> resultSet = this._syncIO.write(wr);
+        Map<Item, Integer> result = new HashMap();
+
+        for(int i = 0; i < requests.length; ++i) {
+            Result<org.openscada.opc.dcom.da.WriteRequest> entry = (Result)resultSet.get(i);
+            result.put(requests[i].getItem(), entry.getErrorCode());
+        }
+
+        return result;
+    }
+
+    public synchronized Map<Item, ItemState> read(boolean device, Item... items) throws JIException {
+        Integer[] handles = this.getServerHandles(items);
+        KeyedResultSet<Integer, OPCITEMSTATE> states = this._syncIO.read(device ? OPCDATASOURCE.OPC_DS_DEVICE : OPCDATASOURCE.OPC_DS_CACHE, handles);
+        Map<Item, ItemState> data = new HashMap();
+        Iterator var7 = states.iterator();
+
+        while(var7.hasNext()) {
+            KeyedResult<Integer, OPCITEMSTATE> entry = (KeyedResult)var7.next();
+            Item item = (Item)this._itemMap.get(entry.getKey());
+            ItemState state = new ItemState(entry.getErrorCode(), ((OPCITEMSTATE)entry.getValue()).getValue(), ((OPCITEMSTATE)entry.getValue()).getTimestamp().asCalendar(), ((OPCITEMSTATE)entry.getValue()).getQuality());
+            data.put(item, state);
+        }
+
+        return data;
+    }
+
+    public Server getServer() {
+        return this._server;
+    }
+
+    public synchronized void clear() throws JIException {
+        Integer[] handles = (Integer[])this._itemMap.keySet().toArray(new Integer[0]);
+
+        try {
+            this._items.remove(handles);
+        } finally {
+            this._itemHandleMap.clear();
+            this._itemMap.clear();
+            this._itemClientMap.clear();
+        }
+
+    }
+
+    public synchronized OPCAsyncIO2 getAsyncIO20() {
+        return this._group.getAsyncIO2();
+    }
+
+    public void setGroupState(Integer requestedUpdateRate, Integer timeBias, Float percentDeadband) throws JIException {
+        this._group.setState(requestedUpdateRate, (Boolean)null, timeBias, percentDeadband, (Integer)null, (Integer)null);
+    }
+
+    public synchronized EventHandler attach(IOPCDataCallback dataCallback) throws JIException {
+        return this._group.attach(dataCallback);
+    }
+
+    public Item findItemByClientHandle(int clientHandle) {
+        return (Item)this._itemClientMap.get(clientHandle);
+    }
+
+    public int getServerHandle() {
+        return this._serverHandle;
+    }
+
+    public synchronized void removeItem(String opcItemId) throws IllegalArgumentException, UnknownHostException, JIException {
+        _log.debug(String.format("Removing item '%s'", opcItemId));
+        Item item = this.getItemByOPCItemId(opcItemId);
+        if (item != null) {
+            this._group.getItemManagement().remove(new Integer[]{item.getServerHandle()});
+            this.removeItem(item);
+            _log.debug(String.format("Removed item '%s'", opcItemId));
+        } else {
+            _log.warn(String.format("Unable to find item '%s'", opcItemId));
+        }
+
+    }
+}

+ 55 - 0
industry-system/industry-da/src/main/java/org/openscada/opc/lib/da/Item.java

@@ -0,0 +1,55 @@
+//
+// Source code recreated from a .class file by IntelliJ IDEA
+// (powered by FernFlower decompiler)
+//
+
+package org.openscada.opc.lib.da;
+
+import org.jinterop.dcom.common.JIException;
+import org.jinterop.dcom.core.JIVariant;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class Item {
+    private static Logger _log = LoggerFactory.getLogger(Item.class);
+    private Group _group = null;
+    private int _serverHandle = 0;
+    private int _clientHandle = 0;
+    private String _id = null;
+
+    Item(Group group, int serverHandle, int clientHandle, String id) {
+        _log.debug(String.format("Adding new item '%s' (0x%08X) for group %s", id, serverHandle, group.toString()));
+        this._group = group;
+        this._serverHandle = serverHandle;
+        this._clientHandle = clientHandle;
+        this._id = id;
+    }
+
+    public Group getGroup() {
+        return this._group;
+    }
+
+    public int getServerHandle() {
+        return this._serverHandle;
+    }
+
+    public int getClientHandle() {
+        return this._clientHandle;
+    }
+
+    public String getId() {
+        return this._id;
+    }
+
+    public void setActive(boolean state) throws JIException {
+        this._group.setActive(state, new Item[]{this});
+    }
+
+    public ItemState read(boolean device) throws JIException {
+        return (ItemState)this._group.read(device, new Item[]{this}).get(this);
+    }
+
+    public Integer write(JIVariant value) throws JIException {
+        return (Integer)this._group.write(new WriteRequest[]{new WriteRequest(this, value)}).get(this);
+    }
+}

+ 113 - 0
industry-system/industry-da/src/main/java/org/openscada/opc/lib/da/ItemState.java

@@ -0,0 +1,113 @@
+//
+// Source code recreated from a .class file by IntelliJ IDEA
+// (powered by FernFlower decompiler)
+//
+
+package org.openscada.opc.lib.da;
+
+import java.util.Calendar;
+import org.jinterop.dcom.core.JIVariant;
+
+public class ItemState {
+    private int _errorCode = 0;
+    private JIVariant _value = null;
+    private Calendar _timestamp = null;
+    private Short _quality = null;
+
+    public ItemState(int errorCode, JIVariant value, Calendar timestamp, Short quality) {
+        this._errorCode = errorCode;
+        this._value = value;
+        this._timestamp = timestamp;
+        this._quality = quality;
+    }
+
+    public ItemState() {
+    }
+
+    public String toString() {
+        return String.format("Value: %s, Timestamp: %tc, Quality: %s, ErrorCode: %08x", this._value, this._timestamp, this._quality, this._errorCode);
+    }
+
+    public Short getQuality() {
+        return this._quality;
+    }
+
+    public void setQuality(Short quality) {
+        this._quality = quality;
+    }
+
+    public Calendar getTimestamp() {
+        return this._timestamp;
+    }
+
+    public void setTimestamp(Calendar timestamp) {
+        this._timestamp = timestamp;
+    }
+
+    public JIVariant getValue() {
+        return this._value;
+    }
+
+    public void setValue(JIVariant value) {
+        this._value = value;
+    }
+
+    public int getErrorCode() {
+        return this._errorCode;
+    }
+
+    public void setErrorCode(int errorCode) {
+        this._errorCode = errorCode;
+    }
+
+    public int hashCode() {
+        int PRIME = 31;
+        int result = 1;
+        result = PRIME * result + this._errorCode;
+        result = PRIME * result + (this._quality == null ? 0 : this._quality.hashCode());
+        result = PRIME * result + (this._timestamp == null ? 0 : this._timestamp.hashCode());
+        result = PRIME * result + (this._value == null ? 0 : this._value.hashCode());
+        return result;
+    }
+
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        } else if (obj == null) {
+            return false;
+        } else if (this.getClass() != obj.getClass()) {
+            return false;
+        } else {
+            ItemState other = (ItemState)obj;
+            if (this._errorCode != other._errorCode) {
+                return false;
+            } else {
+                if (this._quality == null) {
+                    if (other._quality != null) {
+                        return false;
+                    }
+                } else if (!this._quality.equals(other._quality)) {
+                    return false;
+                }
+
+                if (this._timestamp == null) {
+                    if (other._timestamp != null) {
+                        return false;
+                    }
+                } else if (!this._timestamp.equals(other._timestamp)) {
+                    return false;
+                }
+
+                if (this._value == null) {
+                    if (other._value != null) {
+                        return false;
+                    }
+                } else if (!this._value.equals(other._value)) {
+                    return false;
+                }
+
+                return true;
+            }
+        }
+    }
+}

+ 308 - 0
industry-system/industry-da/src/main/java/org/openscada/opc/lib/da/Server.java

@@ -0,0 +1,308 @@
+//
+// Source code recreated from a .class file by IntelliJ IDEA
+// (powered by FernFlower decompiler)
+//
+
+package org.openscada.opc.lib.da;
+
+import java.net.UnknownHostException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.concurrent.ScheduledExecutorService;
+
+import org.openscada.opc.lib.da.browser.FlatBrowser;
+import org.openscada.opc.lib.da.browser.TreeBrowser;
+import org.jinterop.dcom.common.JIException;
+import org.jinterop.dcom.core.JIClsid;
+import org.jinterop.dcom.core.JIComServer;
+import org.jinterop.dcom.core.JIProgId;
+import org.jinterop.dcom.core.JISession;
+import org.openscada.opc.dcom.da.OPCNAMESPACETYPE;
+import org.openscada.opc.dcom.da.OPCSERVERSTATUS;
+import org.openscada.opc.dcom.da.impl.OPCBrowseServerAddressSpace;
+import org.openscada.opc.dcom.da.impl.OPCGroupStateMgt;
+import org.openscada.opc.dcom.da.impl.OPCServer;
+import org.openscada.opc.lib.common.AlreadyConnectedException;
+import org.openscada.opc.lib.common.ConnectionInformation;
+import org.openscada.opc.lib.common.NotConnectedException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class Server {
+    private static Logger logger = LoggerFactory.getLogger(Server.class);
+    private final ConnectionInformation connectionInformation;
+    private JISession session;
+    private JIComServer comServer;
+    private OPCServer server;
+    private boolean defaultActive = true;
+    private int defaultUpdateRate = 1000;
+    private Integer defaultTimeBias;
+    private Float defaultPercentDeadband;
+    private int defaultLocaleID = 0;
+    private ErrorMessageResolver errorMessageResolver;
+    private final Map<Integer, Group> groups = new HashMap();
+    private final List<ServerConnectionStateListener> stateListeners = new CopyOnWriteArrayList();
+    private final ScheduledExecutorService scheduler;
+
+    public Server(ConnectionInformation connectionInformation, ScheduledExecutorService scheduler) {
+        this.connectionInformation = connectionInformation;
+        this.scheduler = scheduler;
+    }
+
+    public ScheduledExecutorService getScheduler() {
+        return this.scheduler;
+    }
+
+    protected synchronized boolean isConnected() {
+        return this.session != null;
+    }
+
+    public synchronized void connect() throws IllegalArgumentException, UnknownHostException, JIException, AlreadyConnectedException {
+        if (this.isConnected()) {
+            throw new AlreadyConnectedException();
+        } else {
+            int socketTimeout = Integer.getInteger("rpc.socketTimeout", 0);
+            logger.info(String.format("Socket timeout: %s ", socketTimeout));
+
+            try {
+                if (this.connectionInformation.getClsid() != null) {
+                    this.session = JISession.createSession(this.connectionInformation.getDomain(), this.connectionInformation.getUser(), this.connectionInformation.getPassword());
+                    this.session.setGlobalSocketTimeout(socketTimeout);
+                    this.comServer = new JIComServer(JIClsid.valueOf(this.connectionInformation.getClsid()), this.connectionInformation.getHost(), this.session);
+                    this.session.useSessionSecurity(true);
+                } else {
+                    if (this.connectionInformation.getProgId() == null) {
+                        throw new IllegalArgumentException("Neither clsid nor progid is valid!");
+                    }
+
+                    this.session = JISession.createSession(this.connectionInformation.getDomain(), this.connectionInformation.getUser(), this.connectionInformation.getPassword());
+                    this.session.setGlobalSocketTimeout(socketTimeout);
+                    this.comServer = new JIComServer(JIProgId.valueOf(this.connectionInformation.getProgId()), this.connectionInformation.getHost(), this.session);
+                    this.session.useSessionSecurity(true);
+                }
+
+                this.server = new OPCServer(this.comServer.createInstance());
+                this.errorMessageResolver = new ErrorMessageResolver(this.server.getCommon(), this.defaultLocaleID);
+            } catch (UnknownHostException var3) {
+                logger.info("Unknown host when connecting to server", var3);
+                this.cleanup();
+                throw var3;
+            } catch (JIException var4) {
+                logger.info("Failed to connect to server", var4);
+                this.cleanup();
+                throw var4;
+            } catch (Throwable var5) {
+                logger.warn("Unknown error", var5);
+                this.cleanup();
+                throw new RuntimeException(var5);
+            }
+
+            this.notifyConnectionStateChange(true);
+        }
+    }
+
+    protected void cleanup() {
+        logger.info("Destroying DCOM session...");
+        final JISession destructSession = this.session;
+        Thread destructor = new Thread(new Runnable() {
+            public void run() {
+                long ts = System.currentTimeMillis();
+
+                try {
+                    Server.logger.debug("Starting destruction of DCOM session");
+                    JISession.destroySession(destructSession);
+                    Server.logger.info("Destructed DCOM session");
+                } catch (Throwable var7) {
+                    Server.logger.warn("Failed to destruct DCOM session", var7);
+                } finally {
+                    Server.logger.info(String.format("Session destruction took %s ms", System.currentTimeMillis() - ts));
+                }
+
+            }
+        }, "UtgardSessionDestructor");
+        destructor.setName("OPCSessionDestructor");
+        destructor.setDaemon(true);
+        destructor.start();
+        logger.info("Destroying DCOM session... forked");
+        this.errorMessageResolver = null;
+        this.session = null;
+        this.comServer = null;
+        this.server = null;
+        this.groups.clear();
+    }
+
+    public synchronized void disconnect() {
+        if (this.isConnected()) {
+            try {
+                this.notifyConnectionStateChange(false);
+            } catch (Throwable var2) {
+            }
+
+            this.cleanup();
+        }
+    }
+
+    public void dispose() {
+        this.disconnect();
+    }
+
+    protected synchronized Group getGroup(OPCGroupStateMgt groupMgt) throws JIException, IllegalArgumentException, UnknownHostException {
+        Integer serverHandle = groupMgt.getState().getServerHandle();
+        if (this.groups.containsKey(serverHandle)) {
+            return (Group)this.groups.get(serverHandle);
+        } else {
+            Group group = new Group(this, serverHandle, groupMgt);
+            this.groups.put(serverHandle, group);
+            return group;
+        }
+    }
+
+    public synchronized Group addGroup(String name) throws NotConnectedException, IllegalArgumentException, UnknownHostException, JIException, DuplicateGroupException {
+        if (!this.isConnected()) {
+            throw new NotConnectedException();
+        } else {
+            try {
+                OPCGroupStateMgt groupMgt = this.server.addGroup(name, this.defaultActive, this.defaultUpdateRate, 0, this.defaultTimeBias, this.defaultPercentDeadband, this.defaultLocaleID);
+                return this.getGroup(groupMgt);
+            } catch (JIException var3) {
+                switch (var3.getErrorCode()) {
+                    case -1073479668:
+                        throw new DuplicateGroupException();
+                    default:
+                        throw var3;
+                }
+            }
+        }
+    }
+
+    public Group addGroup() throws IllegalArgumentException, UnknownHostException, NotConnectedException, JIException, DuplicateGroupException {
+        return this.addGroup((String)null);
+    }
+
+    public Group findGroup(String name) throws IllegalArgumentException, UnknownHostException, JIException, UnknownGroupException, NotConnectedException {
+        if (!this.isConnected()) {
+            throw new NotConnectedException();
+        } else {
+            try {
+                OPCGroupStateMgt groupMgt = this.server.getGroupByName(name);
+                return this.getGroup(groupMgt);
+            } catch (JIException var3) {
+                switch (var3.getErrorCode()) {
+                    case -2147024809:
+                        throw new UnknownGroupException(name);
+                    default:
+                        throw var3;
+                }
+            }
+        }
+    }
+
+    public int getDefaultLocaleID() {
+        return this.defaultLocaleID;
+    }
+
+    public void setDefaultLocaleID(int defaultLocaleID) {
+        this.defaultLocaleID = defaultLocaleID;
+    }
+
+    public Float getDefaultPercentDeadband() {
+        return this.defaultPercentDeadband;
+    }
+
+    public void setDefaultPercentDeadband(Float defaultPercentDeadband) {
+        this.defaultPercentDeadband = defaultPercentDeadband;
+    }
+
+    public Integer getDefaultTimeBias() {
+        return this.defaultTimeBias;
+    }
+
+    public void setDefaultTimeBias(Integer defaultTimeBias) {
+        this.defaultTimeBias = defaultTimeBias;
+    }
+
+    public int getDefaultUpdateRate() {
+        return this.defaultUpdateRate;
+    }
+
+    public void setDefaultUpdateRate(int defaultUpdateRate) {
+        this.defaultUpdateRate = defaultUpdateRate;
+    }
+
+    public boolean isDefaultActive() {
+        return this.defaultActive;
+    }
+
+    public void setDefaultActive(boolean defaultActive) {
+        this.defaultActive = defaultActive;
+    }
+
+    public FlatBrowser getFlatBrowser() {
+        OPCBrowseServerAddressSpace browser = this.server.getBrowser();
+        return browser == null ? null : new FlatBrowser(browser);
+    }
+
+    public TreeBrowser getTreeBrowser() throws JIException {
+        OPCBrowseServerAddressSpace browser = this.server.getBrowser();
+        if (browser == null) {
+            return null;
+        } else {
+            return browser.queryOrganization() != OPCNAMESPACETYPE.OPC_NS_HIERARCHIAL ? null : new TreeBrowser(browser);
+        }
+    }
+
+    public synchronized String getErrorMessage(int errorCode) {
+        if (this.errorMessageResolver == null) {
+            return String.format("Unknown error (%08X)", errorCode);
+        } else {
+            String message = this.errorMessageResolver.getMessage(errorCode);
+            return message != null ? message : String.format("Unknown error (%08X)", errorCode);
+        }
+    }
+
+    public synchronized void addStateListener(ServerConnectionStateListener listener) {
+        this.stateListeners.add(listener);
+        listener.connectionStateChanged(this.isConnected());
+    }
+
+    public synchronized void removeStateListener(ServerConnectionStateListener listener) {
+        this.stateListeners.remove(listener);
+    }
+
+    protected void notifyConnectionStateChange(boolean connected) {
+        List<ServerConnectionStateListener> list = new ArrayList(this.stateListeners);
+        Iterator var4 = list.iterator();
+
+        while(var4.hasNext()) {
+            ServerConnectionStateListener listener = (ServerConnectionStateListener)var4.next();
+            listener.connectionStateChanged(connected);
+        }
+
+    }
+
+    public OPCSERVERSTATUS getServerState(int timeout) throws Throwable {
+        return (new ServerStateOperation(this.server)).getServerState(timeout);
+    }
+
+    public OPCSERVERSTATUS getServerState() {
+        try {
+            return this.getServerState(2500);
+        } catch (Throwable var2) {
+            logger.info("Server connection failed", var2);
+            this.dispose();
+            return null;
+        }
+    }
+
+    public void removeGroup(Group group, boolean force) throws JIException {
+        if (this.groups.containsKey(group.getServerHandle())) {
+            this.server.removeGroup(group.getServerHandle(), force);
+            this.groups.remove(group.getServerHandle());
+        }
+
+    }
+}

+ 10 - 0
industry-system/industry-da/src/main/java/org/openscada/opc/lib/da/ServerConnectionStateListener.java

@@ -0,0 +1,10 @@
+//
+// Source code recreated from a .class file by IntelliJ IDEA
+// (powered by FernFlower decompiler)
+//
+
+package org.openscada.opc.lib.da;
+
+public interface ServerConnectionStateListener {
+  void connectionStateChanged(boolean var1);
+}

+ 12 - 0
industry-system/industry-da/src/main/java/org/openscada/opc/lib/da/ServerStateListener.java

@@ -0,0 +1,12 @@
+//
+// Source code recreated from a .class file by IntelliJ IDEA
+// (powered by FernFlower decompiler)
+//
+
+package org.openscada.opc.lib.da;
+
+import org.openscada.opc.dcom.da.OPCSERVERSTATUS;
+
+public interface ServerStateListener {
+  void stateUpdate(OPCSERVERSTATUS var1);
+}

+ 71 - 0
industry-system/industry-da/src/main/java/org/openscada/opc/lib/da/ServerStateOperation.java

@@ -0,0 +1,71 @@
+//
+// Source code recreated from a .class file by IntelliJ IDEA
+// (powered by FernFlower decompiler)
+//
+
+package org.openscada.opc.lib.da;
+
+import org.openscada.opc.dcom.da.OPCSERVERSTATUS;
+import org.openscada.opc.dcom.da.impl.OPCServer;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class ServerStateOperation implements Runnable {
+    private static Logger _log = LoggerFactory.getLogger(ServerStateOperation.class);
+    public OPCSERVERSTATUS _serverStatus = null;
+    public OPCServer _server;
+    public Throwable _error;
+    public Object _lock = new Object();
+    public boolean _running = false;
+
+    public ServerStateOperation(OPCServer server) {
+        this._server = server;
+    }
+
+    public void run() {
+        synchronized(this._lock) {
+            this._running = true;
+        }
+
+        try {
+            this._serverStatus = this._server.getStatus();
+            synchronized(this._lock) {
+                this._running = false;
+                this._lock.notify();
+            }
+        } catch (Throwable var5) {
+            _log.info("Failed to get server state", var5);
+            this._error = var5;
+            this._running = false;
+            synchronized(this._lock) {
+                this._lock.notify();
+            }
+        }
+
+    }
+
+    public OPCSERVERSTATUS getServerState(int timeout) throws Throwable {
+        if (this._server == null) {
+            _log.debug("No connection to server. Skipping...");
+            return null;
+        } else {
+            Thread t = new Thread(this, "OPCServerStateReader");
+            synchronized(this._lock) {
+                t.start();
+                this._lock.wait((long)timeout);
+                if (this._running) {
+                    _log.warn("State operation still running. Interrupting...");
+                    t.interrupt();
+                    throw new InterruptedException("Interrupted getting server state");
+                }
+            }
+
+            if (this._error != null) {
+                _log.warn("An error occurred while getting server state", this._error);
+                throw this._error;
+            } else {
+                return this._serverStatus;
+            }
+        }
+    }
+}

+ 70 - 0
industry-system/industry-da/src/main/java/org/openscada/opc/lib/da/ServerStateReader.java

@@ -0,0 +1,70 @@
+//
+// Source code recreated from a .class file by IntelliJ IDEA
+// (powered by FernFlower decompiler)
+//
+
+package org.openscada.opc.lib.da;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.ScheduledFuture;
+import java.util.concurrent.TimeUnit;
+import org.openscada.opc.dcom.da.OPCSERVERSTATUS;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class ServerStateReader {
+    private static Logger _log = LoggerFactory.getLogger(ServerStateReader.class);
+    private Server _server = null;
+    private ScheduledExecutorService _scheduler = null;
+    private final List<ServerStateListener> _listeners = new CopyOnWriteArrayList();
+    private ScheduledFuture<?> _job = null;
+
+    public ServerStateReader(Server server) {
+        this._server = server;
+        this._scheduler = this._server.getScheduler();
+    }
+
+    public ServerStateReader(Server server, ScheduledExecutorService scheduler) {
+        this._server = server;
+        this._scheduler = scheduler;
+    }
+
+    public synchronized void start() {
+        if (this._job == null) {
+            this._job = this._scheduler.scheduleAtFixedRate(new Runnable() {
+                public void run() {
+                    ServerStateReader.this.once();
+                }
+            }, 1000L, 1000L, TimeUnit.MILLISECONDS);
+        }
+    }
+
+    public synchronized void stop() {
+        this._job.cancel(false);
+        this._job = null;
+    }
+
+    protected void once() {
+        _log.debug("Reading server state");
+        OPCSERVERSTATUS state = this._server.getServerState();
+        Iterator var3 = (new ArrayList(this._listeners)).iterator();
+
+        while(var3.hasNext()) {
+            ServerStateListener listener = (ServerStateListener)var3.next();
+            listener.stateUpdate(state);
+        }
+
+    }
+
+    public void addListener(ServerStateListener listener) {
+        this._listeners.add(listener);
+    }
+
+    public void removeListener(ServerStateListener listener) {
+        this._listeners.remove(listener);
+    }
+}

+ 81 - 0
industry-system/industry-da/src/main/java/org/openscada/opc/lib/da/SyncAccess.java

@@ -0,0 +1,81 @@
+//
+// Source code recreated from a .class file by IntelliJ IDEA
+// (powered by FernFlower decompiler)
+//
+
+package org.openscada.opc.lib.da;
+
+import java.net.UnknownHostException;
+import java.util.Iterator;
+import java.util.Map;
+import org.jinterop.dcom.common.JIException;
+import org.openscada.opc.lib.common.NotConnectedException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class SyncAccess extends AccessBase implements Runnable {
+    private static Logger logger = LoggerFactory.getLogger(SyncAccess.class);
+    private Thread runner = null;
+    private Throwable lastError = null;
+
+    public SyncAccess(Server server, int period) throws IllegalArgumentException, UnknownHostException, NotConnectedException, JIException, DuplicateGroupException {
+        super(server, period);
+    }
+
+    public SyncAccess(Server server, int period, String logTag) throws IllegalArgumentException, UnknownHostException, NotConnectedException, JIException, DuplicateGroupException {
+        super(server, period, logTag);
+    }
+
+    public void run() {
+        while(this.active) {
+            try {
+                this.runOnce();
+                if (this.lastError != null) {
+                    this.lastError = null;
+                    this.handleError((Throwable)null);
+                }
+            } catch (Throwable var3) {
+                logger.error("Sync read failed", var3);
+                this.handleError(var3);
+                this.server.disconnect();
+            }
+
+            try {
+                Thread.sleep((long)this.getPeriod());
+            } catch (InterruptedException var2) {
+            }
+        }
+
+    }
+
+    protected void runOnce() throws JIException {
+        if (this.active && this.group != null) {
+            Map result;
+            synchronized(this) {
+                Item[] items = (Item[])this.items.keySet().toArray(new Item[this.items.size()]);
+                result = this.group.read(false, items);
+            }
+
+            Iterator var5 = result.entrySet().iterator();
+
+            while(var5.hasNext()) {
+                Map.Entry<Item, ItemState> entry = (Map.Entry)var5.next();
+                this.updateItem((Item)entry.getKey(), (ItemState)entry.getValue());
+            }
+
+        }
+    }
+
+    protected synchronized void start() throws JIException, IllegalArgumentException, UnknownHostException, NotConnectedException, DuplicateGroupException {
+        super.start();
+        this.runner = new Thread(this, "UtgardSyncReader");
+        this.runner.setDaemon(true);
+        this.runner.start();
+    }
+
+    protected synchronized void stop() throws JIException {
+        super.stop();
+        this.runner = null;
+        this.items.clear();
+    }
+}

+ 23 - 0
industry-system/industry-da/src/main/java/org/openscada/opc/lib/da/UnknownGroupException.java

@@ -0,0 +1,23 @@
+//
+// Source code recreated from a .class file by IntelliJ IDEA
+// (powered by FernFlower decompiler)
+//
+
+package org.openscada.opc.lib.da;
+
+public class UnknownGroupException extends Exception {
+    private String _name = null;
+    private static final long serialVersionUID = 1771564928794033075L;
+
+    public UnknownGroupException(String name) {
+        this._name = name;
+    }
+
+    public String getName() {
+        return this._name;
+    }
+
+    public void setName(String name) {
+        this._name = name;
+    }
+}

+ 26 - 0
industry-system/industry-da/src/main/java/org/openscada/opc/lib/da/WriteRequest.java

@@ -0,0 +1,26 @@
+//
+// Source code recreated from a .class file by IntelliJ IDEA
+// (powered by FernFlower decompiler)
+//
+
+package org.openscada.opc.lib.da;
+
+import org.jinterop.dcom.core.JIVariant;
+
+public class WriteRequest {
+    private Item _item = null;
+    private JIVariant _value = null;
+
+    public WriteRequest(Item item, JIVariant value) {
+        this._item = item;
+        this._value = value;
+    }
+
+    public Item getItem() {
+        return this._item;
+    }
+
+    public JIVariant getValue() {
+        return this._value;
+    }
+}

+ 21 - 0
industry-system/industry-da/src/main/java/org/openscada/opc/lib/da/browser/Access.java

@@ -0,0 +1,21 @@
+//
+// Source code recreated from a .class file by IntelliJ IDEA
+// (powered by FernFlower decompiler)
+//
+
+package org.openscada.opc.lib.da.browser;
+
+public enum Access {
+    READ(1),
+    WRITE(2);
+
+    private int _code = 0;
+
+    private Access(int code) {
+        this._code = code;
+    }
+
+    public int getCode() {
+        return this._code;
+    }
+}

+ 57 - 0
industry-system/industry-da/src/main/java/org/openscada/opc/lib/da/browser/BaseBrowser.java

@@ -0,0 +1,57 @@
+//
+// Source code recreated from a .class file by IntelliJ IDEA
+// (powered by FernFlower decompiler)
+//
+
+package org.openscada.opc.lib.da.browser;
+
+import java.net.UnknownHostException;
+import java.util.Collection;
+import java.util.EnumSet;
+import org.jinterop.dcom.common.JIException;
+import org.openscada.opc.dcom.common.impl.EnumString;
+import org.openscada.opc.dcom.da.OPCBROWSETYPE;
+import org.openscada.opc.dcom.da.impl.OPCBrowseServerAddressSpace;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class BaseBrowser {
+    private static Logger _log = LoggerFactory.getLogger(BaseBrowser.class);
+    protected OPCBrowseServerAddressSpace _browser;
+    protected int _batchSize;
+
+    public BaseBrowser(OPCBrowseServerAddressSpace browser) {
+        this(browser, EnumString.DEFAULT_BATCH_SIZE);
+    }
+
+    public BaseBrowser(OPCBrowseServerAddressSpace browser, int batchSize) {
+        this._browser = browser;
+        this._batchSize = batchSize;
+    }
+
+    public void setBatchSize(int batchSize) {
+        this._batchSize = batchSize;
+    }
+
+    public int getBatchSize() {
+        return this._batchSize;
+    }
+
+    protected Collection<String> browse(OPCBROWSETYPE type, String filterCriteria, EnumSet<Access> accessMask, int variantType) throws IllegalArgumentException, UnknownHostException, JIException {
+        int accessMaskValue = 0;
+        if (accessMask.contains(Access.READ)) {
+            accessMaskValue |= Access.READ.getCode();
+        }
+
+        if (accessMask.contains(Access.WRITE)) {
+            accessMaskValue |= Access.WRITE.getCode();
+        }
+
+        _log.debug("Browsing with a batch size of " + this._batchSize);
+        return this._browser.browse(type, filterCriteria, accessMaskValue, variantType).asCollection(this._batchSize);
+    }
+
+    public Collection<String> getAccessPaths(String itemId) throws IllegalArgumentException, UnknownHostException, JIException {
+        return this._browser.browseAccessPaths(itemId).asCollection(this._batchSize);
+    }
+}

+ 64 - 0
industry-system/industry-da/src/main/java/org/openscada/opc/lib/da/browser/Branch.java

@@ -0,0 +1,64 @@
+//
+// Source code recreated from a .class file by IntelliJ IDEA
+// (powered by FernFlower decompiler)
+//
+
+package org.openscada.opc.lib.da.browser;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.LinkedList;
+
+public class Branch {
+    private Branch _parent = null;
+    private String _name = null;
+    private Collection<Branch> _branches = new LinkedList();
+    private Collection<Leaf> _leaves = new LinkedList();
+
+    public Branch() {
+    }
+
+    public Branch(Branch parent, String name) {
+        this._name = name;
+        this._parent = parent;
+    }
+
+    public Collection<Branch> getBranches() {
+        return this._branches;
+    }
+
+    public void setBranches(Collection<Branch> branches) {
+        this._branches = branches;
+    }
+
+    public Collection<Leaf> getLeaves() {
+        return this._leaves;
+    }
+
+    public void setLeaves(Collection<Leaf> leaves) {
+        this._leaves = leaves;
+    }
+
+    public String getName() {
+        return this._name;
+    }
+
+    public void setName(String name) {
+        this._name = name;
+    }
+
+    public Branch getParent() {
+        return this._parent;
+    }
+
+    public Collection<String> getBranchStack() {
+        LinkedList<String> branches = new LinkedList();
+
+        for(Branch currentBranch = this; currentBranch.getParent() != null; currentBranch = currentBranch.getParent()) {
+            branches.add(currentBranch.getName());
+        }
+
+        Collections.reverse(branches);
+        return branches;
+    }
+}

+ 39 - 0
industry-system/industry-da/src/main/java/org/openscada/opc/lib/da/browser/FlatBrowser.java

@@ -0,0 +1,39 @@
+//
+// Source code recreated from a .class file by IntelliJ IDEA
+// (powered by FernFlower decompiler)
+//
+
+package org.openscada.opc.lib.da.browser;
+
+import java.net.UnknownHostException;
+import java.util.Collection;
+import java.util.EnumSet;
+import org.jinterop.dcom.common.JIException;
+import org.openscada.opc.dcom.da.OPCBROWSETYPE;
+import org.openscada.opc.dcom.da.impl.OPCBrowseServerAddressSpace;
+
+public class FlatBrowser extends BaseBrowser {
+    public FlatBrowser(OPCBrowseServerAddressSpace browser) {
+        super(browser);
+    }
+
+    public FlatBrowser(OPCBrowseServerAddressSpace browser, int batchSize) {
+        super(browser, batchSize);
+    }
+
+    public Collection<String> browse(String filterCriteria, EnumSet<Access> accessMask, int variantType) throws IllegalArgumentException, UnknownHostException, JIException {
+        return this.browse(OPCBROWSETYPE.OPC_FLAT, filterCriteria, accessMask, variantType);
+    }
+
+    public Collection<String> browse(String filterCriteria) throws IllegalArgumentException, UnknownHostException, JIException {
+        return this.browse(filterCriteria, EnumSet.noneOf(Access.class), 0);
+    }
+
+    public Collection<String> browse() throws IllegalArgumentException, UnknownHostException, JIException {
+        return this.browse("", EnumSet.noneOf(Access.class), 0);
+    }
+
+    public Collection<String> browse(EnumSet<Access> accessMask) throws IllegalArgumentException, UnknownHostException, JIException {
+        return this.browse("", accessMask, 0);
+    }
+}

+ 43 - 0
industry-system/industry-da/src/main/java/org/openscada/opc/lib/da/browser/Leaf.java

@@ -0,0 +1,43 @@
+//
+// Source code recreated from a .class file by IntelliJ IDEA
+// (powered by FernFlower decompiler)
+//
+
+package org.openscada.opc.lib.da.browser;
+
+public class Leaf {
+    private Branch _parent = null;
+    private String _name = "";
+    private String _itemId = null;
+
+    public Leaf(Branch parent, String name) {
+        this._parent = parent;
+        this._name = name;
+    }
+
+    public Leaf(Branch parent, String name, String itemId) {
+        this._parent = parent;
+        this._name = name;
+        this._itemId = itemId;
+    }
+
+    public String getItemId() {
+        return this._itemId;
+    }
+
+    public void setItemId(String itemId) {
+        this._itemId = itemId;
+    }
+
+    public String getName() {
+        return this._name;
+    }
+
+    public void setName(String name) {
+        this._name = name;
+    }
+
+    public Branch getParent() {
+        return this._parent;
+    }
+}

+ 121 - 0
industry-system/industry-da/src/main/java/org/openscada/opc/lib/da/browser/TreeBrowser.java

@@ -0,0 +1,121 @@
+//
+// Source code recreated from a .class file by IntelliJ IDEA
+// (powered by FernFlower decompiler)
+//
+
+package org.openscada.opc.lib.da.browser;
+
+import java.net.UnknownHostException;
+import java.util.Collection;
+import java.util.EnumSet;
+import java.util.Iterator;
+import java.util.LinkedList;
+import org.jinterop.dcom.common.JIException;
+import org.openscada.opc.dcom.da.OPCBROWSEDIRECTION;
+import org.openscada.opc.dcom.da.OPCBROWSETYPE;
+import org.openscada.opc.dcom.da.impl.OPCBrowseServerAddressSpace;
+
+public class TreeBrowser extends BaseBrowser {
+    private String _filterCriteria = "";
+    private EnumSet<Access> _accessMask = EnumSet.noneOf(Access.class);
+    private int _variantType = 0;
+
+    public TreeBrowser(OPCBrowseServerAddressSpace browser) {
+        super(browser);
+    }
+
+    public TreeBrowser(OPCBrowseServerAddressSpace browser, String filterCriteria, EnumSet<Access> accessMask, int variantType) {
+        super(browser);
+        this._filterCriteria = filterCriteria;
+        this._accessMask = accessMask;
+        this._variantType = variantType;
+    }
+
+    protected void moveToRoot() throws JIException {
+        this._browser.changePosition((String)null, OPCBROWSEDIRECTION.OPC_BROWSE_TO);
+    }
+
+    protected void moveToBranch(Branch branch) throws JIException {
+        Collection<String> branchStack = branch.getBranchStack();
+        this.moveToRoot();
+        Iterator var4 = branchStack.iterator();
+
+        while(var4.hasNext()) {
+            String branchName = (String)var4.next();
+            this._browser.changePosition(branchName, OPCBROWSEDIRECTION.OPC_BROWSE_DOWN);
+        }
+
+    }
+
+    public Branch browseBranches() throws JIException, IllegalArgumentException, UnknownHostException {
+        Branch branch = new Branch();
+        this.fillBranches(branch);
+        return branch;
+    }
+
+    public Branch browseLeaves() throws IllegalArgumentException, UnknownHostException, JIException {
+        Branch branch = new Branch();
+        this.fillLeaves(branch);
+        return branch;
+    }
+
+    public void fillBranches(Branch branch) throws JIException, IllegalArgumentException, UnknownHostException {
+        this.moveToBranch(branch);
+        this.browse(branch, false, true, false);
+    }
+
+    public void fillLeaves(Branch branch) throws IllegalArgumentException, UnknownHostException, JIException {
+        this.moveToBranch(branch);
+        this.browse(branch, true, false, false);
+    }
+
+    public Branch browse() throws JIException, IllegalArgumentException, UnknownHostException {
+        Branch branch = new Branch();
+        this.fill(branch);
+        return branch;
+    }
+
+    public void fill(Branch branch) throws IllegalArgumentException, UnknownHostException, JIException {
+        this.moveToBranch(branch);
+        this.browse(branch, true, true, true);
+    }
+
+    protected void browseLeaves(Branch branch) throws IllegalArgumentException, UnknownHostException, JIException {
+        branch.setLeaves(new LinkedList());
+        Iterator var3 = this.browse(OPCBROWSETYPE.OPC_LEAF, this._filterCriteria, this._accessMask, this._variantType).iterator();
+
+        while(var3.hasNext()) {
+            String item = (String)var3.next();
+            Leaf leaf = new Leaf(branch, item, this._browser.getItemID(item));
+            branch.getLeaves().add(leaf);
+        }
+
+    }
+
+    protected void browseBranches(Branch branch, boolean leaves, boolean descend) throws IllegalArgumentException, UnknownHostException, JIException {
+        branch.setBranches(new LinkedList());
+
+        Branch subBranch;
+        for(Iterator var5 = this.browse(OPCBROWSETYPE.OPC_BRANCH, this._filterCriteria, this._accessMask, this._variantType).iterator(); var5.hasNext(); branch.getBranches().add(subBranch)) {
+            String item = (String)var5.next();
+            subBranch = new Branch(branch, item);
+            if (descend) {
+                this._browser.changePosition(item, OPCBROWSEDIRECTION.OPC_BROWSE_DOWN);
+                this.browse(subBranch, leaves, true, true);
+                this._browser.changePosition((String)null, OPCBROWSEDIRECTION.OPC_BROWSE_UP);
+            }
+        }
+
+    }
+
+    protected void browse(Branch branch, boolean leaves, boolean branches, boolean descend) throws IllegalArgumentException, UnknownHostException, JIException {
+        if (leaves) {
+            this.browseLeaves(branch);
+        }
+
+        if (branches) {
+            this.browseBranches(branch, leaves, descend);
+        }
+
+    }
+}

+ 13 - 0
industry-system/industry-da/src/main/java/org/openscada/opc/lib/list/Categories.java

@@ -0,0 +1,13 @@
+//
+// Source code recreated from a .class file by IntelliJ IDEA
+// (powered by FernFlower decompiler)
+//
+
+package org.openscada.opc.lib.list;
+
+public interface Categories {
+    Category OPCDAServer10 = new Category("63D5F430-CFE4-11d1-B2C8-0060083BA1FB");
+    Category OPCDAServer20 = new Category("63D5F432-CFE4-11d1-B2C8-0060083BA1FB");
+    Category OPCDAServer30 = new Category("CC603642-66D7-48f1-B69A-B625E73652D7");
+    Category XMLDAServer10 = new Category("3098EDA4-A006-48b2-A27F-247453959408");
+}

+ 46 - 0
industry-system/industry-da/src/main/java/org/openscada/opc/lib/list/Category.java

@@ -0,0 +1,46 @@
+//
+// Source code recreated from a .class file by IntelliJ IDEA
+// (powered by FernFlower decompiler)
+//
+
+package org.openscada.opc.lib.list;
+
+public class Category {
+    private String _catId = null;
+
+    public Category(String catId) {
+        this._catId = catId;
+    }
+
+    public String toString() {
+        return this._catId;
+    }
+
+    public int hashCode() {
+        int PRIME = 31;
+        int result = 1;
+        result = PRIME * result + (this._catId == null ? 0 : this._catId.hashCode());
+        return result;
+    }
+
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        } else if (obj == null) {
+            return false;
+        } else if (this.getClass() != obj.getClass()) {
+            return false;
+        } else {
+            Category other = (Category)obj;
+            if (this._catId == null) {
+                if (other._catId != null) {
+                    return false;
+                }
+            } else if (!this._catId.equals(other._catId)) {
+                return false;
+            }
+
+            return true;
+        }
+    }
+}

+ 85 - 0
industry-system/industry-da/src/main/java/org/openscada/opc/lib/list/ServerList.java

@@ -0,0 +1,85 @@
+//
+// Source code recreated from a .class file by IntelliJ IDEA
+// (powered by FernFlower decompiler)
+//
+
+package org.openscada.opc.lib.list;
+
+import java.net.UnknownHostException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+import org.jinterop.dcom.common.JIException;
+import org.jinterop.dcom.core.JIClsid;
+import org.jinterop.dcom.core.JIComServer;
+import org.jinterop.dcom.core.JISession;
+import org.openscada.opc.dcom.list.ClassDetails;
+import org.openscada.opc.dcom.list.impl.OPCServerList;
+import rpc.core.UUID;
+
+public class ServerList {
+    private final JISession _session;
+    private final OPCServerList _serverList;
+
+    public ServerList(JISession session, String host) throws IllegalArgumentException, UnknownHostException, JIException {
+        this._session = session;
+        JIComServer comServer = new JIComServer(JIClsid.valueOf("13486D51-4821-11D2-A494-3CB306C10000"), host, this._session);
+        this._serverList = new OPCServerList(comServer.createInstance());
+    }
+
+    public ServerList(String host, String user, String password) throws IllegalArgumentException, UnknownHostException, JIException {
+        this(host, user, password, (String)null);
+    }
+
+    public ServerList(String host, String user, String password, String domain) throws IllegalArgumentException, UnknownHostException, JIException {
+        this(JISession.createSession(domain, user, password), host);
+    }
+
+    public ClassDetails getDetails(String clsId) throws JIException {
+        return this._serverList.getClassDetails(JIClsid.valueOf(clsId));
+    }
+
+    public String getClsIdFromProgId(String progId) throws JIException {
+        JIClsid cls = this._serverList.getCLSIDFromProgID(progId);
+        return cls == null ? null : cls.getCLSID();
+    }
+
+    public Collection<String> listServers(Category[] implemented, Category[] required) throws IllegalArgumentException, UnknownHostException, JIException {
+        UUID[] u1 = new UUID[implemented.length];
+        UUID[] u2 = new UUID[required.length];
+
+        int i;
+        for(i = 0; i < implemented.length; ++i) {
+            u1[i] = new UUID(implemented[i].toString());
+        }
+
+        for(i = 0; i < required.length; ++i) {
+            u2[i] = new UUID(required[i].toString());
+        }
+
+        Collection<UUID> resultU = this._serverList.enumClassesOfCategories(u1, u2).asCollection();
+        Collection<String> result = new ArrayList(resultU.size());
+        Iterator var8 = resultU.iterator();
+
+        while(var8.hasNext()) {
+            UUID uuid = (UUID)var8.next();
+            result.add(uuid.toString());
+        }
+
+        return result;
+    }
+
+    public Collection<ClassDetails> listServersWithDetails(Category[] implemented, Category[] required) throws IllegalArgumentException, UnknownHostException, JIException {
+        Collection<String> resultString = this.listServers(implemented, required);
+        List<ClassDetails> result = new ArrayList(resultString.size());
+        Iterator var6 = resultString.iterator();
+
+        while(var6.hasNext()) {
+            String clsId = (String)var6.next();
+            result.add(this.getDetails(clsId));
+        }
+
+        return result;
+    }
+}