mirror of
https://github.com/luoyan35714/OPC_Client.git
synced 2026-04-18 00:01:30 +08:00
Add the Utgard resources
This commit is contained in:
@@ -0,0 +1,16 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<classpath>
|
||||
<classpathentry kind="src" path="src"/>
|
||||
<classpathentry combineaccessrules="false" kind="src" path="/org.openscada.opc.dcom"/>
|
||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER">
|
||||
<attributes>
|
||||
<attribute name="maven.pomderived" value="true"/>
|
||||
</attributes>
|
||||
</classpathentry>
|
||||
<classpathentry kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER">
|
||||
<attributes>
|
||||
<attribute name="maven.pomderived" value="true"/>
|
||||
</attributes>
|
||||
</classpathentry>
|
||||
<classpathentry kind="output" path="target/classes"/>
|
||||
</classpath>
|
||||
@@ -0,0 +1,2 @@
|
||||
bin/
|
||||
/target
|
||||
@@ -0,0 +1,46 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>org.openscada.opc.lib</name>
|
||||
<comment></comment>
|
||||
<projects>
|
||||
</projects>
|
||||
<buildSpec>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.jdt.core.javabuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.pde.ManifestBuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.pde.SchemaBuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.babel.editor.rbeBuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.pde.api.tools.apiAnalysisBuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.m2e.core.maven2Builder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
</buildSpec>
|
||||
<natures>
|
||||
<nature>org.eclipse.m2e.core.maven2Nature</nature>
|
||||
<nature>org.eclipse.jdt.core.javanature</nature>
|
||||
<nature>org.eclipse.pde.PluginNature</nature>
|
||||
<nature>org.eclipse.babel.editor.rbeNature</nature>
|
||||
<nature>org.eclipse.pde.api.tools.apiAnalysisNature</nature>
|
||||
</natures>
|
||||
</projectDescription>
|
||||
@@ -0,0 +1,165 @@
|
||||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
|
||||
This version of the GNU Lesser General Public License incorporates
|
||||
the terms and conditions of version 3 of the GNU General Public
|
||||
License, supplemented by the additional permissions listed below.
|
||||
|
||||
0. Additional Definitions.
|
||||
|
||||
As used herein, "this License" refers to version 3 of the GNU Lesser
|
||||
General Public License, and the "GNU GPL" refers to version 3 of the GNU
|
||||
General Public License.
|
||||
|
||||
"The Library" refers to a covered work governed by this License,
|
||||
other than an Application or a Combined Work as defined below.
|
||||
|
||||
An "Application" is any work that makes use of an interface provided
|
||||
by the Library, but which is not otherwise based on the Library.
|
||||
Defining a subclass of a class defined by the Library is deemed a mode
|
||||
of using an interface provided by the Library.
|
||||
|
||||
A "Combined Work" is a work produced by combining or linking an
|
||||
Application with the Library. The particular version of the Library
|
||||
with which the Combined Work was made is also called the "Linked
|
||||
Version".
|
||||
|
||||
The "Minimal Corresponding Source" for a Combined Work means the
|
||||
Corresponding Source for the Combined Work, excluding any source code
|
||||
for portions of the Combined Work that, considered in isolation, are
|
||||
based on the Application, and not on the Linked Version.
|
||||
|
||||
The "Corresponding Application Code" for a Combined Work means the
|
||||
object code and/or source code for the Application, including any data
|
||||
and utility programs needed for reproducing the Combined Work from the
|
||||
Application, but excluding the System Libraries of the Combined Work.
|
||||
|
||||
1. Exception to Section 3 of the GNU GPL.
|
||||
|
||||
You may convey a covered work under sections 3 and 4 of this License
|
||||
without being bound by section 3 of the GNU GPL.
|
||||
|
||||
2. Conveying Modified Versions.
|
||||
|
||||
If you modify a copy of the Library, and, in your modifications, a
|
||||
facility refers to a function or data to be supplied by an Application
|
||||
that uses the facility (other than as an argument passed when the
|
||||
facility is invoked), then you may convey a copy of the modified
|
||||
version:
|
||||
|
||||
a) under this License, provided that you make a good faith effort to
|
||||
ensure that, in the event an Application does not supply the
|
||||
function or data, the facility still operates, and performs
|
||||
whatever part of its purpose remains meaningful, or
|
||||
|
||||
b) under the GNU GPL, with none of the additional permissions of
|
||||
this License applicable to that copy.
|
||||
|
||||
3. Object Code Incorporating Material from Library Header Files.
|
||||
|
||||
The object code form of an Application may incorporate material from
|
||||
a header file that is part of the Library. You may convey such object
|
||||
code under terms of your choice, provided that, if the incorporated
|
||||
material is not limited to numerical parameters, data structure
|
||||
layouts and accessors, or small macros, inline functions and templates
|
||||
(ten or fewer lines in length), you do both of the following:
|
||||
|
||||
a) Give prominent notice with each copy of the object code that the
|
||||
Library is used in it and that the Library and its use are
|
||||
covered by this License.
|
||||
|
||||
b) Accompany the object code with a copy of the GNU GPL and this license
|
||||
document.
|
||||
|
||||
4. Combined Works.
|
||||
|
||||
You may convey a Combined Work under terms of your choice that,
|
||||
taken together, effectively do not restrict modification of the
|
||||
portions of the Library contained in the Combined Work and reverse
|
||||
engineering for debugging such modifications, if you also do each of
|
||||
the following:
|
||||
|
||||
a) Give prominent notice with each copy of the Combined Work that
|
||||
the Library is used in it and that the Library and its use are
|
||||
covered by this License.
|
||||
|
||||
b) Accompany the Combined Work with a copy of the GNU GPL and this license
|
||||
document.
|
||||
|
||||
c) For a Combined Work that displays copyright notices during
|
||||
execution, include the copyright notice for the Library among
|
||||
these notices, as well as a reference directing the user to the
|
||||
copies of the GNU GPL and this license document.
|
||||
|
||||
d) Do one of the following:
|
||||
|
||||
0) Convey the Minimal Corresponding Source under the terms of this
|
||||
License, and the Corresponding Application Code in a form
|
||||
suitable for, and under terms that permit, the user to
|
||||
recombine or relink the Application with a modified version of
|
||||
the Linked Version to produce a modified Combined Work, in the
|
||||
manner specified by section 6 of the GNU GPL for conveying
|
||||
Corresponding Source.
|
||||
|
||||
1) Use a suitable shared library mechanism for linking with the
|
||||
Library. A suitable mechanism is one that (a) uses at run time
|
||||
a copy of the Library already present on the user's computer
|
||||
system, and (b) will operate properly with a modified version
|
||||
of the Library that is interface-compatible with the Linked
|
||||
Version.
|
||||
|
||||
e) Provide Installation Information, but only if you would otherwise
|
||||
be required to provide such information under section 6 of the
|
||||
GNU GPL, and only to the extent that such information is
|
||||
necessary to install and execute a modified version of the
|
||||
Combined Work produced by recombining or relinking the
|
||||
Application with a modified version of the Linked Version. (If
|
||||
you use option 4d0, the Installation Information must accompany
|
||||
the Minimal Corresponding Source and Corresponding Application
|
||||
Code. If you use option 4d1, you must provide the Installation
|
||||
Information in the manner specified by section 6 of the GNU GPL
|
||||
for conveying Corresponding Source.)
|
||||
|
||||
5. Combined Libraries.
|
||||
|
||||
You may place library facilities that are a work based on the
|
||||
Library side by side in a single library together with other library
|
||||
facilities that are not Applications and are not covered by this
|
||||
License, and convey such a combined library under terms of your
|
||||
choice, if you do both of the following:
|
||||
|
||||
a) Accompany the combined library with a copy of the same work based
|
||||
on the Library, uncombined with any other library facilities,
|
||||
conveyed under the terms of this License.
|
||||
|
||||
b) Give prominent notice with the combined library that part of it
|
||||
is a work based on the Library, and explaining where to find the
|
||||
accompanying uncombined form of the same work.
|
||||
|
||||
6. Revised Versions of the GNU Lesser General Public License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions
|
||||
of the GNU Lesser General Public License from time to time. Such new
|
||||
versions will be similar in spirit to the present version, but may
|
||||
differ in detail to address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the
|
||||
Library as you received it specifies that a certain numbered version
|
||||
of the GNU Lesser General Public License "or any later version"
|
||||
applies to it, you have the option of following the terms and
|
||||
conditions either of that published version or of any later version
|
||||
published by the Free Software Foundation. If the Library as you
|
||||
received it does not specify a version number of the GNU Lesser
|
||||
General Public License, you may choose any version of the GNU Lesser
|
||||
General Public License ever published by the Free Software Foundation.
|
||||
|
||||
If the Library as you received it specifies that a proxy can decide
|
||||
whether future versions of the GNU Lesser General Public License shall
|
||||
apply, that proxy's public statement of acceptance of any version is
|
||||
permanent authorization for you to choose that version for the
|
||||
Library.
|
||||
@@ -0,0 +1 @@
|
||||
source.. = src
|
||||
@@ -0,0 +1,33 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>org.openscada.utgard</groupId>
|
||||
<artifactId>org.openscada.opc.lib</artifactId>
|
||||
<version>1.1.0.v20130529</version>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-log4j12</artifactId>
|
||||
<version>1.7.2</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>commons-logging</groupId>
|
||||
<artifactId>commons-logging</artifactId>
|
||||
<version>1.2</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.kohsuke.jinterop</groupId>
|
||||
<artifactId>j-interop</artifactId>
|
||||
<version>2.0.5</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.openscada.opc.dcom</groupId>
|
||||
<artifactId>org.openscada.opc.dcom</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* This file is part of the OpenSCADA project
|
||||
* Copyright (C) 2006-2010 TH4 SYSTEMS GmbH (http://th4-systems.com)
|
||||
*
|
||||
* OpenSCADA is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License version 3
|
||||
* only, as published by the Free Software Foundation.
|
||||
*
|
||||
* OpenSCADA is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License version 3 for more details
|
||||
* (a copy is included in the LICENSE file that accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* version 3 along with OpenSCADA. If not, see
|
||||
* <http://opensource.org/licenses/lgpl-3.0.html> for a copy of the LGPLv3 License.
|
||||
*/
|
||||
|
||||
package org.openscada.opc.lib.common;
|
||||
|
||||
public class AlreadyConnectedException extends Exception
|
||||
{
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static final long serialVersionUID = -6494637563117314114L;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,149 @@
|
||||
/*
|
||||
* This file is part of the OpenSCADA project
|
||||
* Copyright (C) 2006-2010 TH4 SYSTEMS GmbH (http://th4-systems.com)
|
||||
*
|
||||
* OpenSCADA is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License version 3
|
||||
* only, as published by the Free Software Foundation.
|
||||
*
|
||||
* OpenSCADA is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License version 3 for more details
|
||||
* (a copy is included in the LICENSE file that accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* version 3 along with OpenSCADA. If not, see
|
||||
* <http://opensource.org/licenses/lgpl-3.0.html> for a copy of the LGPLv3 License.
|
||||
*/
|
||||
|
||||
package org.openscada.opc.lib.common;
|
||||
|
||||
/**
|
||||
* Holds the connection information
|
||||
* @author Jens Reimann <jens.reimann@th4-systems.com>
|
||||
*
|
||||
* If both <code>clsId</code> and <code>progId</code> are set then <code>clsId</code>
|
||||
* has priority!
|
||||
*/
|
||||
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 ()
|
||||
{
|
||||
super ();
|
||||
}
|
||||
|
||||
public ConnectionInformation ( final String user, final String password )
|
||||
{
|
||||
super ();
|
||||
this._user = user;
|
||||
this._password = password;
|
||||
}
|
||||
|
||||
public ConnectionInformation ( final ConnectionInformation arg0 )
|
||||
{
|
||||
super ();
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the domain of the user used for logging on
|
||||
* @param domain
|
||||
*/
|
||||
public void setDomain ( final String domain )
|
||||
{
|
||||
this._domain = domain;
|
||||
}
|
||||
|
||||
public String getHost ()
|
||||
{
|
||||
return this._host;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the host on which the server is located
|
||||
* @param host The host to use, either an IP address oder hostname
|
||||
*/
|
||||
public void setHost ( final String host )
|
||||
{
|
||||
this._host = host;
|
||||
}
|
||||
|
||||
public String getPassword ()
|
||||
{
|
||||
return this._password;
|
||||
}
|
||||
|
||||
public void setPassword ( final String password )
|
||||
{
|
||||
this._password = password;
|
||||
}
|
||||
|
||||
public String getUser ()
|
||||
{
|
||||
return this._user;
|
||||
}
|
||||
|
||||
public void setUser ( final String user )
|
||||
{
|
||||
this._user = user;
|
||||
}
|
||||
|
||||
public String getClsid ()
|
||||
{
|
||||
return this._clsid;
|
||||
}
|
||||
|
||||
public void setClsid ( final String clsid )
|
||||
{
|
||||
this._clsid = clsid;
|
||||
}
|
||||
|
||||
public String getProgId ()
|
||||
{
|
||||
return this._progId;
|
||||
}
|
||||
|
||||
public void setProgId ( final String progId )
|
||||
{
|
||||
this._progId = progId;
|
||||
}
|
||||
|
||||
public String getClsOrProgId ()
|
||||
{
|
||||
if ( this._clsid != null )
|
||||
{
|
||||
return this._clsid;
|
||||
}
|
||||
else if ( this._progId != null )
|
||||
{
|
||||
return this._progId;
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* This file is part of the OpenSCADA project
|
||||
* Copyright (C) 2006-2010 TH4 SYSTEMS GmbH (http://th4-systems.com)
|
||||
*
|
||||
* OpenSCADA is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License version 3
|
||||
* only, as published by the Free Software Foundation.
|
||||
*
|
||||
* OpenSCADA is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License version 3 for more details
|
||||
* (a copy is included in the LICENSE file that accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* version 3 along with OpenSCADA. If not, see
|
||||
* <http://opensource.org/licenses/lgpl-3.0.html> for a copy of the LGPLv3 License.
|
||||
*/
|
||||
|
||||
package org.openscada.opc.lib.common;
|
||||
|
||||
public class NotConnectedException extends Exception
|
||||
{
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static final long serialVersionUID = -3745147771605524635L;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,359 @@
|
||||
/*
|
||||
* This file is part of the OpenSCADA project
|
||||
* Copyright (C) 2006-2010 TH4 SYSTEMS GmbH (http://th4-systems.com)
|
||||
*
|
||||
* OpenSCADA is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License version 3
|
||||
* only, as published by the Free Software Foundation.
|
||||
*
|
||||
* OpenSCADA is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License version 3 for more details
|
||||
* (a copy is included in the LICENSE file that accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* version 3 along with OpenSCADA. If not, see
|
||||
* <http://opensource.org/licenses/lgpl-3.0.html> for a copy of the LGPLv3 License.
|
||||
*/
|
||||
|
||||
package org.openscada.opc.lib.da;
|
||||
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
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 = null;
|
||||
|
||||
protected Group group = null;
|
||||
|
||||
protected boolean active = false;
|
||||
|
||||
private final List<AccessStateListener> stateListeners = new CopyOnWriteArrayList<AccessStateListener> ();
|
||||
|
||||
private boolean bound = false;
|
||||
|
||||
/**
|
||||
* Holds the item to callback assignment
|
||||
*/
|
||||
protected Map<Item, DataCallback> items = new HashMap<Item, DataCallback> ();
|
||||
|
||||
protected Map<String, Item> itemMap = new HashMap<String, Item> ();
|
||||
|
||||
protected Map<Item, ItemState> itemCache = new HashMap<Item, ItemState> ();
|
||||
|
||||
private int period = 0;
|
||||
|
||||
protected Map<String, DataCallback> itemSet = new HashMap<String, DataCallback> ();
|
||||
|
||||
protected String logTag = null;
|
||||
|
||||
protected Logger dataLogger = null;
|
||||
|
||||
public AccessBase ( final Server server, final int period ) throws IllegalArgumentException, UnknownHostException, NotConnectedException, JIException, DuplicateGroupException
|
||||
{
|
||||
super ();
|
||||
this.server = server;
|
||||
this.period = period;
|
||||
}
|
||||
|
||||
public AccessBase ( final Server server, final int period, final String logTag )
|
||||
{
|
||||
super ();
|
||||
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 ( isBound () )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
this.server.addStateListener ( this );
|
||||
this.bound = true;
|
||||
}
|
||||
|
||||
public synchronized void unbind () throws JIException
|
||||
{
|
||||
if ( !isBound () )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
this.server.removeStateListener ( this );
|
||||
this.bound = false;
|
||||
|
||||
stop ();
|
||||
}
|
||||
|
||||
public boolean isActive ()
|
||||
{
|
||||
return this.active;
|
||||
}
|
||||
|
||||
public void addStateListener ( final AccessStateListener listener )
|
||||
{
|
||||
this.stateListeners.add ( listener );
|
||||
listener.stateChanged ( isActive () );
|
||||
}
|
||||
|
||||
public void removeStateListener ( final AccessStateListener listener )
|
||||
{
|
||||
this.stateListeners.remove ( listener );
|
||||
}
|
||||
|
||||
protected void notifyStateListenersState ( final boolean state )
|
||||
{
|
||||
final List<AccessStateListener> list = new ArrayList<AccessStateListener> ( this.stateListeners );
|
||||
|
||||
for ( final AccessStateListener listener : list )
|
||||
{
|
||||
listener.stateChanged ( state );
|
||||
}
|
||||
}
|
||||
|
||||
protected void notifyStateListenersError ( final Throwable t )
|
||||
{
|
||||
final List<AccessStateListener> list = new ArrayList<AccessStateListener> ( this.stateListeners );
|
||||
|
||||
for ( final AccessStateListener listener : list )
|
||||
{
|
||||
listener.errorOccured ( t );
|
||||
}
|
||||
}
|
||||
|
||||
public int getPeriod ()
|
||||
{
|
||||
return this.period;
|
||||
}
|
||||
|
||||
public synchronized void addItem ( final String itemId, final DataCallback dataCallback ) throws JIException, AddFailedException
|
||||
{
|
||||
if ( this.itemSet.containsKey ( itemId ) )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
this.itemSet.put ( itemId, dataCallback );
|
||||
|
||||
if ( isActive () )
|
||||
{
|
||||
realizeItem ( itemId );
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized void removeItem ( final String itemId )
|
||||
{
|
||||
if ( !this.itemSet.containsKey ( itemId ) )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
this.itemSet.remove ( itemId );
|
||||
|
||||
if ( isActive () )
|
||||
{
|
||||
unrealizeItem ( itemId );
|
||||
}
|
||||
}
|
||||
|
||||
public void connectionStateChanged ( final boolean connected )
|
||||
{
|
||||
try
|
||||
{
|
||||
if ( connected )
|
||||
{
|
||||
start ();
|
||||
}
|
||||
else
|
||||
{
|
||||
stop ();
|
||||
}
|
||||
}
|
||||
catch ( final Exception e )
|
||||
{
|
||||
logger.error ( String.format ( "Failed to change state (%s)", connected ), e );
|
||||
}
|
||||
}
|
||||
|
||||
protected synchronized void start () throws JIException, IllegalArgumentException, UnknownHostException, NotConnectedException, DuplicateGroupException
|
||||
{
|
||||
if ( isActive () )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
logger.debug ( "Create a new group" );
|
||||
this.group = this.server.addGroup ();
|
||||
this.group.setActive ( true );
|
||||
this.active = true;
|
||||
|
||||
notifyStateListenersState ( true );
|
||||
|
||||
realizeAll ();
|
||||
}
|
||||
|
||||
protected void realizeItem ( final String itemId ) throws JIException, AddFailedException
|
||||
{
|
||||
logger.debug ( "Realizing item: {}", itemId );
|
||||
|
||||
final DataCallback dataCallback = this.itemSet.get ( itemId );
|
||||
if ( dataCallback == null )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
final Item item = this.group.addItem ( itemId );
|
||||
this.items.put ( item, dataCallback );
|
||||
this.itemMap.put ( itemId, item );
|
||||
}
|
||||
|
||||
protected void unrealizeItem ( final String itemId )
|
||||
{
|
||||
final Item item = this.itemMap.remove ( itemId );
|
||||
this.items.remove ( item );
|
||||
this.itemCache.remove ( item );
|
||||
|
||||
try
|
||||
{
|
||||
this.group.removeItem ( itemId );
|
||||
}
|
||||
catch ( final Throwable e )
|
||||
{
|
||||
logger.error ( String.format ( "Failed to unrealize item '%s'", itemId ), e );
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* FIXME: need some perfomance boost: subscribe all in one call
|
||||
*/
|
||||
protected void realizeAll ()
|
||||
{
|
||||
for ( final String itemId : this.itemSet.keySet () )
|
||||
{
|
||||
try
|
||||
{
|
||||
realizeItem ( itemId );
|
||||
}
|
||||
catch ( final AddFailedException e )
|
||||
{
|
||||
Integer rc = e.getErrors ().get ( itemId );
|
||||
if ( rc == null )
|
||||
{
|
||||
rc = -1;
|
||||
}
|
||||
logger.warn ( String.format ( "Failed to add item: %s (%08X)", itemId, rc ) );
|
||||
|
||||
}
|
||||
catch ( final Exception e )
|
||||
{
|
||||
logger.warn ( "Failed to realize item: " + itemId, e );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void unrealizeAll ()
|
||||
{
|
||||
this.items.clear ();
|
||||
this.itemCache.clear ();
|
||||
try
|
||||
{
|
||||
this.group.clear ();
|
||||
}
|
||||
catch ( final JIException e )
|
||||
{
|
||||
logger.info ( "Failed to clear group. No problem if we already lost the connection", e );
|
||||
}
|
||||
}
|
||||
|
||||
protected synchronized void stop () throws JIException
|
||||
{
|
||||
if ( !isActive () )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
unrealizeAll ();
|
||||
|
||||
this.active = false;
|
||||
notifyStateListenersState ( false );
|
||||
|
||||
try
|
||||
{
|
||||
this.group.remove ();
|
||||
}
|
||||
catch ( final Throwable t )
|
||||
{
|
||||
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 ( final Item item, final ItemState itemState )
|
||||
{
|
||||
if ( this.dataLogger != null )
|
||||
{
|
||||
this.dataLogger.debug ( "Update item: {}, {}", item.getId (), itemState );
|
||||
}
|
||||
|
||||
final DataCallback dataCallback = this.items.get ( item );
|
||||
if ( dataCallback == null )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
final ItemState cachedState = 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 ( final Throwable e )
|
||||
{
|
||||
notifyStateListenersError ( e );
|
||||
this.server.dispose ();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* This file is part of the OpenSCADA project
|
||||
* Copyright (C) 2006-2010 TH4 SYSTEMS GmbH (http://th4-systems.com)
|
||||
*
|
||||
* OpenSCADA is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License version 3
|
||||
* only, as published by the Free Software Foundation.
|
||||
*
|
||||
* OpenSCADA is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License version 3 for more details
|
||||
* (a copy is included in the LICENSE file that accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* version 3 along with OpenSCADA. If not, see
|
||||
* <http://opensource.org/licenses/lgpl-3.0.html> for a copy of the LGPLv3 License.
|
||||
*/
|
||||
|
||||
package org.openscada.opc.lib.da;
|
||||
|
||||
public interface AccessStateListener
|
||||
{
|
||||
public abstract void stateChanged ( boolean state );
|
||||
|
||||
public abstract void errorOccured ( Throwable t );
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* This file is part of the OpenSCADA project
|
||||
* Copyright (C) 2006-2010 TH4 SYSTEMS GmbH (http://th4-systems.com)
|
||||
*
|
||||
* OpenSCADA is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License version 3
|
||||
* only, as published by the Free Software Foundation.
|
||||
*
|
||||
* OpenSCADA is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License version 3 for more details
|
||||
* (a copy is included in the LICENSE file that accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* version 3 along with OpenSCADA. If not, see
|
||||
* <http://opensource.org/licenses/lgpl-3.0.html> for a copy of the LGPLv3 License.
|
||||
*/
|
||||
|
||||
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<String, Integer> ();
|
||||
|
||||
private Map<String, Item> _items = new HashMap<String, Item> ();
|
||||
|
||||
public AddFailedException ( final Map<String, Integer> errors, final Map<String, Item> items )
|
||||
{
|
||||
super ();
|
||||
this._errors = errors;
|
||||
this._items = items;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the map of item id to error code
|
||||
* @return the result map containing the failed items
|
||||
*/
|
||||
public Map<String, Integer> getErrors ()
|
||||
{
|
||||
return this._errors;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the map of item it to item object
|
||||
* @return the result map containing the succeeded items
|
||||
*/
|
||||
public Map<String, Item> getItems ()
|
||||
{
|
||||
return this._items;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,136 @@
|
||||
/*
|
||||
* This file is part of the OpenSCADA project
|
||||
* Copyright (C) 2006-2010 TH4 SYSTEMS GmbH (http://th4-systems.com)
|
||||
*
|
||||
* OpenSCADA is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License version 3
|
||||
* only, as published by the Free Software Foundation.
|
||||
*
|
||||
* OpenSCADA is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License version 3 for more details
|
||||
* (a copy is included in the LICENSE file that accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* version 3 along with OpenSCADA. If not, see
|
||||
* <http://opensource.org/licenses/lgpl-3.0.html> for a copy of the LGPLv3 License.
|
||||
*/
|
||||
|
||||
package org.openscada.opc.lib.da;
|
||||
|
||||
import java.net.UnknownHostException;
|
||||
|
||||
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 ( final Server server, final int period, final boolean initialRefresh ) throws IllegalArgumentException, UnknownHostException, NotConnectedException, JIException, DuplicateGroupException
|
||||
{
|
||||
super ( server, period );
|
||||
this.initialRefresh = initialRefresh;
|
||||
}
|
||||
|
||||
public Async20Access ( final Server server, final int period, final boolean initialRefresh, final String logTag ) throws IllegalArgumentException, UnknownHostException, NotConnectedException, JIException, DuplicateGroupException
|
||||
{
|
||||
super ( server, period, logTag );
|
||||
this.initialRefresh = initialRefresh;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected synchronized void start () throws JIException, IllegalArgumentException, UnknownHostException, NotConnectedException, DuplicateGroupException
|
||||
{
|
||||
if ( isActive () )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
super.start ();
|
||||
|
||||
this.eventHandler = this.group.attach ( this );
|
||||
if ( !this.items.isEmpty () && this.initialRefresh )
|
||||
{
|
||||
final OPCAsyncIO2 async20 = this.group.getAsyncIO20 ();
|
||||
if ( async20 == null )
|
||||
{
|
||||
throw new NotConnectedException ();
|
||||
}
|
||||
|
||||
this.group.getAsyncIO20 ().refresh ( OPCDATASOURCE.OPC_DS_CACHE, 0 );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected synchronized void stop () throws JIException
|
||||
{
|
||||
if ( !isActive () )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if ( this.eventHandler != null )
|
||||
{
|
||||
try
|
||||
{
|
||||
this.eventHandler.detach ();
|
||||
}
|
||||
catch ( final Throwable e )
|
||||
{
|
||||
logger.warn ( "Failed to detach group", e );
|
||||
}
|
||||
|
||||
this.eventHandler = null;
|
||||
}
|
||||
|
||||
super.stop ();
|
||||
}
|
||||
|
||||
public void cancelComplete ( final int transactionId, final int serverGroupHandle )
|
||||
{
|
||||
}
|
||||
|
||||
public void dataChange ( final int transactionId, final int serverGroupHandle, final int masterQuality, final int masterErrorCode, final KeyedResultSet<Integer, ValueData> result )
|
||||
{
|
||||
logger.debug ( "dataChange - transId {}, items: {}", transactionId, result.size () );
|
||||
|
||||
final Group group = this.group;
|
||||
if ( group == null )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for ( final KeyedResult<Integer, ValueData> entry : result )
|
||||
{
|
||||
final Item item = group.findItemByClientHandle ( entry.getKey () );
|
||||
logger.debug ( "Update for '{}'", item.getId () );
|
||||
updateItem ( item, new ItemState ( entry.getErrorCode (), entry.getValue ().getValue (), entry.getValue ().getTimestamp (), entry.getValue ().getQuality () ) );
|
||||
}
|
||||
}
|
||||
|
||||
public void readComplete ( final int transactionId, final int serverGroupHandle, final int masterQuality, final int masterErrorCode, final KeyedResultSet<Integer, ValueData> result )
|
||||
{
|
||||
logger.debug ( "readComplete - transId {}", transactionId );
|
||||
}
|
||||
|
||||
public void writeComplete ( final int transactionId, final int serverGroupHandle, final int masterErrorCode, final ResultSet<Integer> result )
|
||||
{
|
||||
logger.debug ( "writeComplete - transId {}", transactionId );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,230 @@
|
||||
/*
|
||||
* This file is part of the OpenSCADA project
|
||||
* Copyright (C) 2006-2010 TH4 SYSTEMS GmbH (http://th4-systems.com)
|
||||
*
|
||||
* OpenSCADA is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License version 3
|
||||
* only, as published by the Free Software Foundation.
|
||||
*
|
||||
* OpenSCADA is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License version 3 for more details
|
||||
* (a copy is included in the LICENSE file that accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* version 3 along with OpenSCADA. If not, see
|
||||
* <http://opensource.org/licenses/lgpl-3.0.html> for a copy of the LGPLv3 License.
|
||||
*/
|
||||
|
||||
package org.openscada.opc.lib.da;
|
||||
|
||||
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 = 5 * 1000;
|
||||
|
||||
private int _delay;
|
||||
|
||||
private final Server _server;
|
||||
|
||||
private final Set<AutoReconnectListener> _listeners = new CopyOnWriteArraySet<AutoReconnectListener> ();
|
||||
|
||||
private AutoReconnectState _state = AutoReconnectState.DISABLED;
|
||||
|
||||
private Thread _connectTask = null;
|
||||
|
||||
public AutoReconnectController ( final Server server )
|
||||
{
|
||||
this ( server, DEFAULT_DELAY );
|
||||
}
|
||||
|
||||
public AutoReconnectController ( final Server server, final int delay )
|
||||
{
|
||||
super ();
|
||||
setDelay ( delay );
|
||||
|
||||
this._server = server;
|
||||
this._server.addStateListener ( this );
|
||||
}
|
||||
|
||||
public void addListener ( final AutoReconnectListener listener )
|
||||
{
|
||||
if ( listener != null )
|
||||
{
|
||||
this._listeners.add ( listener );
|
||||
listener.stateChanged ( this._state );
|
||||
}
|
||||
}
|
||||
|
||||
public void removeListener ( final AutoReconnectListener listener )
|
||||
{
|
||||
this._listeners.remove ( listener );
|
||||
}
|
||||
|
||||
protected void notifyStateChange ( final AutoReconnectState state )
|
||||
{
|
||||
this._state = state;
|
||||
for ( AutoReconnectListener listener : this._listeners )
|
||||
{
|
||||
listener.stateChanged ( state );
|
||||
}
|
||||
}
|
||||
|
||||
public int getDelay ()
|
||||
{
|
||||
return this._delay;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the reconnect delay. If the delay less than or equal to zero it will be
|
||||
* the default delay time.
|
||||
* @param delay The delay to use
|
||||
*/
|
||||
public void setDelay ( int delay )
|
||||
{
|
||||
if ( delay <= 0 )
|
||||
{
|
||||
delay = DEFAULT_DELAY;
|
||||
}
|
||||
this._delay = delay;
|
||||
}
|
||||
|
||||
public synchronized void connect ()
|
||||
{
|
||||
if ( isRequested () )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_log.debug ( "Requesting connection" );
|
||||
notifyStateChange ( AutoReconnectState.DISCONNECTED );
|
||||
|
||||
triggerReconnect ( false );
|
||||
}
|
||||
|
||||
public synchronized void disconnect ()
|
||||
{
|
||||
if ( !isRequested () )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_log.debug ( "Un-Requesting connection" );
|
||||
|
||||
notifyStateChange ( AutoReconnectState.DISABLED );
|
||||
this._server.disconnect ();
|
||||
}
|
||||
|
||||
public boolean isRequested ()
|
||||
{
|
||||
return this._state != AutoReconnectState.DISABLED;
|
||||
}
|
||||
|
||||
public synchronized void connectionStateChanged ( final boolean connected )
|
||||
{
|
||||
_log.debug ( "Connection state changed: " + connected );
|
||||
|
||||
if ( !connected )
|
||||
{
|
||||
if ( isRequested () )
|
||||
{
|
||||
notifyStateChange ( AutoReconnectState.DISCONNECTED );
|
||||
triggerReconnect ( true );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( !isRequested () )
|
||||
{
|
||||
this._server.disconnect ();
|
||||
}
|
||||
else
|
||||
{
|
||||
notifyStateChange ( AutoReconnectState.CONNECTED );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private synchronized void triggerReconnect ( final boolean wait )
|
||||
{
|
||||
if ( this._connectTask != null )
|
||||
{
|
||||
_log.info ( "Connect thread already running" );
|
||||
return;
|
||||
}
|
||||
|
||||
_log.debug ( "Trigger reconnect" );
|
||||
|
||||
this._connectTask = new Thread ( new Runnable () {
|
||||
|
||||
public void run ()
|
||||
{
|
||||
boolean result = false;
|
||||
try
|
||||
{
|
||||
result = performReconnect ( wait );
|
||||
}
|
||||
finally
|
||||
{
|
||||
AutoReconnectController.this._connectTask = null;
|
||||
_log.debug ( String.format ( "performReconnect completed : %s", result ) );
|
||||
if ( !result )
|
||||
{
|
||||
triggerReconnect ( true );
|
||||
}
|
||||
}
|
||||
}
|
||||
}, "OPCReconnectThread" );
|
||||
this._connectTask.setDaemon ( true );
|
||||
this._connectTask.start ();
|
||||
}
|
||||
|
||||
private boolean performReconnect ( final boolean wait )
|
||||
{
|
||||
try
|
||||
{
|
||||
if ( wait )
|
||||
{
|
||||
notifyStateChange ( AutoReconnectState.WAITING );
|
||||
_log.debug ( String.format ( "Delaying (%s)...", this._delay ) );
|
||||
Thread.sleep ( this._delay );
|
||||
}
|
||||
}
|
||||
catch ( InterruptedException e )
|
||||
{
|
||||
}
|
||||
|
||||
if ( !isRequested () )
|
||||
{
|
||||
_log.debug ( "Request canceled during delay" );
|
||||
return true;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
_log.debug ( "Connecting to server" );
|
||||
notifyStateChange ( AutoReconnectState.CONNECTING );
|
||||
synchronized ( this )
|
||||
{
|
||||
this._server.connect ();
|
||||
return true;
|
||||
}
|
||||
// CONNECTED state will be set by server callback
|
||||
}
|
||||
catch ( Throwable e )
|
||||
{
|
||||
_log.info ( "Re-connect failed", e );
|
||||
notifyStateChange ( AutoReconnectState.DISCONNECTED );
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* This file is part of the OpenSCADA project
|
||||
* Copyright (C) 2006-2010 TH4 SYSTEMS GmbH (http://th4-systems.com)
|
||||
*
|
||||
* OpenSCADA is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License version 3
|
||||
* only, as published by the Free Software Foundation.
|
||||
*
|
||||
* OpenSCADA is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License version 3 for more details
|
||||
* (a copy is included in the LICENSE file that accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* version 3 along with OpenSCADA. If not, see
|
||||
* <http://opensource.org/licenses/lgpl-3.0.html> for a copy of the LGPLv3 License.
|
||||
*/
|
||||
|
||||
package org.openscada.opc.lib.da;
|
||||
|
||||
public interface AutoReconnectListener
|
||||
{
|
||||
public abstract void stateChanged ( AutoReconnectState state );
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* This file is part of the OpenSCADA project
|
||||
* Copyright (C) 2006-2010 TH4 SYSTEMS GmbH (http://th4-systems.com)
|
||||
*
|
||||
* OpenSCADA is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License version 3
|
||||
* only, as published by the Free Software Foundation.
|
||||
*
|
||||
* OpenSCADA is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License version 3 for more details
|
||||
* (a copy is included in the LICENSE file that accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* version 3 along with OpenSCADA. If not, see
|
||||
* <http://opensource.org/licenses/lgpl-3.0.html> for a copy of the LGPLv3 License.
|
||||
*/
|
||||
|
||||
package org.openscada.opc.lib.da;
|
||||
|
||||
/**
|
||||
* A state for the auto-reconnect controller
|
||||
* @author Jens Reimann
|
||||
*
|
||||
*/
|
||||
public enum AutoReconnectState
|
||||
{
|
||||
/**
|
||||
* Auto reconnect is disabled.
|
||||
*/
|
||||
DISABLED,
|
||||
/**
|
||||
* Auto reconnect is enabled, but the connection is currently not established.
|
||||
*/
|
||||
DISCONNECTED,
|
||||
/**
|
||||
* Auto reconnect is enabled, the connection is not established and the controller
|
||||
* is currently waiting the delay until it will reconnect.
|
||||
*/
|
||||
WAITING,
|
||||
/**
|
||||
* Auto reconnect is enabled, the connection is not established but the controller
|
||||
* currently tries to establish the connection.
|
||||
*/
|
||||
CONNECTING,
|
||||
/**
|
||||
* Auto reconnect is enabled and the connection is established.
|
||||
*/
|
||||
CONNECTED
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* This file is part of the OpenSCADA project
|
||||
* Copyright (C) 2006-2010 TH4 SYSTEMS GmbH (http://th4-systems.com)
|
||||
*
|
||||
* OpenSCADA is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License version 3
|
||||
* only, as published by the Free Software Foundation.
|
||||
*
|
||||
* OpenSCADA is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License version 3 for more details
|
||||
* (a copy is included in the LICENSE file that accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* version 3 along with OpenSCADA. If not, see
|
||||
* <http://opensource.org/licenses/lgpl-3.0.html> for a copy of the LGPLv3 License.
|
||||
*/
|
||||
|
||||
package org.openscada.opc.lib.da;
|
||||
|
||||
public interface DataCallback
|
||||
{
|
||||
void changed ( Item item, ItemState itemState );
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* This file is part of the OpenSCADA project
|
||||
* Copyright (C) 2006-2010 TH4 SYSTEMS GmbH (http://th4-systems.com)
|
||||
*
|
||||
* OpenSCADA is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License version 3
|
||||
* only, as published by the Free Software Foundation.
|
||||
*
|
||||
* OpenSCADA is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License version 3 for more details
|
||||
* (a copy is included in the LICENSE file that accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* version 3 along with OpenSCADA. If not, see
|
||||
* <http://opensource.org/licenses/lgpl-3.0.html> for a copy of the LGPLv3 License.
|
||||
*/
|
||||
|
||||
package org.openscada.opc.lib.da;
|
||||
|
||||
public class DuplicateGroupException extends Exception
|
||||
{
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static final long serialVersionUID = 826553520690295478L;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* This file is part of the OpenSCADA project
|
||||
* Copyright (C) 2006-2010 TH4 SYSTEMS GmbH (http://th4-systems.com)
|
||||
*
|
||||
* OpenSCADA is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License version 3
|
||||
* only, as published by the Free Software Foundation.
|
||||
*
|
||||
* OpenSCADA is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License version 3 for more details
|
||||
* (a copy is included in the LICENSE file that accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* version 3 along with OpenSCADA. If not, see
|
||||
* <http://opensource.org/licenses/lgpl-3.0.html> for a copy of the LGPLv3 License.
|
||||
*/
|
||||
|
||||
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;
|
||||
|
||||
/**
|
||||
* An error message resolver that will lookup the error code using the
|
||||
* server interface and will cache the result locally.
|
||||
* @author Jens Reimann
|
||||
*
|
||||
*/
|
||||
public class ErrorMessageResolver
|
||||
{
|
||||
private static Logger _log = LoggerFactory.getLogger ( ErrorMessageResolver.class );
|
||||
|
||||
private OPCCommon _opcCommon = null;
|
||||
|
||||
private final Map<Integer, String> _messageCache = new HashMap<Integer, String> ();
|
||||
|
||||
private int _localeId = 0;
|
||||
|
||||
public ErrorMessageResolver ( final OPCCommon opcCommon, final int localeId )
|
||||
{
|
||||
super ();
|
||||
this._opcCommon = opcCommon;
|
||||
this._localeId = localeId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an error message from an error code
|
||||
* @param errorCode The error code to look up
|
||||
* @return the error message or <code>null</code> if no message could be looked up
|
||||
*/
|
||||
public synchronized String getMessage ( final int errorCode )
|
||||
{
|
||||
String message = this._messageCache.get ( Integer.valueOf ( errorCode ) );
|
||||
|
||||
if ( message == null )
|
||||
{
|
||||
try
|
||||
{
|
||||
message = this._opcCommon.getErrorString ( errorCode, this._localeId );
|
||||
_log.info ( String.format ( "Resolved %08X to '%s'", errorCode, message ) );
|
||||
}
|
||||
catch ( JIException e )
|
||||
{
|
||||
_log.warn ( String.format ( "Failed to resolve error code for %08X", errorCode ), e );
|
||||
}
|
||||
if ( message != null )
|
||||
{
|
||||
this._messageCache.put ( errorCode, message );
|
||||
}
|
||||
}
|
||||
return message;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,437 @@
|
||||
/*
|
||||
* This file is part of the OpenSCADA project
|
||||
* Copyright (C) 2006-2010 TH4 SYSTEMS GmbH (http://th4-systems.com)
|
||||
*
|
||||
* OpenSCADA is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License version 3
|
||||
* only, as published by the Free Software Foundation.
|
||||
*
|
||||
* OpenSCADA is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License version 3 for more details
|
||||
* (a copy is included in the LICENSE file that accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* version 3 along with OpenSCADA. If not, see
|
||||
* <http://opensource.org/licenses/lgpl-3.0.html> for a copy of the LGPLv3 License.
|
||||
*/
|
||||
|
||||
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.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<String, Integer> ();
|
||||
|
||||
private final Map<Integer, Item> _itemMap = new HashMap<Integer, Item> ();
|
||||
|
||||
private final Map<Integer, Item> _itemClientMap = new HashMap<Integer, Item> ();
|
||||
|
||||
Group ( final Server server, final int serverHandle, final 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 ( final boolean state ) throws JIException
|
||||
{
|
||||
this._group.setState ( null, state, null, null, null, null );
|
||||
}
|
||||
|
||||
/**
|
||||
* remove the group from the server
|
||||
* @throws JIException
|
||||
*
|
||||
*/
|
||||
public void remove () throws JIException
|
||||
{
|
||||
this._server.removeGroup ( this, true );
|
||||
}
|
||||
|
||||
public boolean isActive () throws JIException
|
||||
{
|
||||
return this._group.getState ().isActive ();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the group name from the server
|
||||
* @return The group name fetched from the server
|
||||
* @throws JIException
|
||||
*/
|
||||
public String getName () throws JIException
|
||||
{
|
||||
return this._group.getState ().getName ();
|
||||
}
|
||||
|
||||
/**
|
||||
* Change the group name
|
||||
* @param name the new name of the group
|
||||
* @throws JIException
|
||||
*/
|
||||
public void setName ( final String name ) throws JIException
|
||||
{
|
||||
this._group.setName ( name );
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a single item. Actually calls {@link #addItems(String[])} with only
|
||||
* one paraemter
|
||||
* @param item The item to add
|
||||
* @return The added item
|
||||
* @throws JIException The add operation failed
|
||||
* @throws AddFailedException The item was not added due to an error
|
||||
*/
|
||||
public Item addItem ( final String item ) throws JIException, AddFailedException
|
||||
{
|
||||
Map<String, Item> items = addItems ( item );
|
||||
return items.get ( item );
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate item ids and get additional information to them.
|
||||
* <br>
|
||||
* According to the OPC specification you should first <em>validate</em>
|
||||
* the items and the <em>add</em> them. The spec also says that when a server
|
||||
* lets the item pass validation it must also let them pass the add operation.
|
||||
* @param items The items to validate
|
||||
* @return A result map of item id to result information (including error code).
|
||||
* @throws JIException
|
||||
*/
|
||||
public synchronized Map<String, Result<OPCITEMRESULT>> validateItems ( final 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<String, Result<OPCITEMRESULT>> ();
|
||||
for ( KeyedResult<OPCITEMDEF, OPCITEMRESULT> resultEntry : result )
|
||||
{
|
||||
resultMap.put ( resultEntry.getKey ().getItemID (), new Result<OPCITEMRESULT> ( resultEntry.getValue (), resultEntry.getErrorCode () ) );
|
||||
}
|
||||
|
||||
return resultMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add new items to the group
|
||||
* @param items The items (by string id) to add
|
||||
* @return A result map of id to item object
|
||||
* @throws JIException The add operation completely failed. No item was added.
|
||||
* @throws AddFailedException If one or more item could not be added. Item without error where added.
|
||||
*/
|
||||
public synchronized Map<String, Item> addItems ( final String... items ) throws JIException, AddFailedException
|
||||
{
|
||||
// Find which items we already have
|
||||
Map<String, Integer> handles = findItems ( items );
|
||||
|
||||
List<Integer> foundItems = new ArrayList<Integer> ( items.length );
|
||||
List<String> missingItems = new ArrayList<String> ();
|
||||
|
||||
// separate missing items from the found ones
|
||||
for ( Map.Entry<String, Integer> entry : handles.entrySet () )
|
||||
{
|
||||
if ( entry.getValue () == null )
|
||||
{
|
||||
missingItems.add ( entry.getKey () );
|
||||
}
|
||||
else
|
||||
{
|
||||
foundItems.add ( entry.getValue () );
|
||||
}
|
||||
}
|
||||
|
||||
// now fetch missing items from OPC server
|
||||
Set<Integer> newClientHandles = new HashSet<Integer> ();
|
||||
OPCITEMDEF[] itemDef = new OPCITEMDEF[missingItems.size ()];
|
||||
for ( int i = 0; i < missingItems.size (); i++ )
|
||||
{
|
||||
OPCITEMDEF def = new OPCITEMDEF ();
|
||||
def.setItemID ( 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;
|
||||
}
|
||||
|
||||
// check the result and add new items
|
||||
Map<String, Integer> failedItems = new HashMap<String, Integer> ();
|
||||
KeyedResultSet<OPCITEMDEF, OPCITEMRESULT> result = this._items.add ( itemDef );
|
||||
int i = 0;
|
||||
for ( KeyedResult<OPCITEMDEF, OPCITEMRESULT> entry : result )
|
||||
{
|
||||
if ( entry.getErrorCode () == 0 )
|
||||
{
|
||||
Item item = new Item ( this, entry.getValue ().getServerHandle (), itemDef[i].getClientHandle (), entry.getKey ().getItemID () );
|
||||
addItem ( item );
|
||||
foundItems.add ( item.getServerHandle () );
|
||||
}
|
||||
else
|
||||
{
|
||||
failedItems.put ( entry.getKey ().getItemID (), entry.getErrorCode () );
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
// if we have failed items then throw an exception with the result
|
||||
if ( failedItems.size () != 0 )
|
||||
{
|
||||
throw new AddFailedException ( failedItems, findItems ( foundItems ) );
|
||||
}
|
||||
|
||||
// simply return the result in case of success
|
||||
return findItems ( foundItems );
|
||||
}
|
||||
|
||||
private synchronized void addItem ( final 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 ( final Item item )
|
||||
{
|
||||
this._itemHandleMap.remove ( item.getId () );
|
||||
this._itemMap.remove ( item.getServerHandle () );
|
||||
this._itemClientMap.remove ( item.getClientHandle () );
|
||||
}
|
||||
|
||||
protected Item getItemByOPCItemId ( final String opcItemId )
|
||||
{
|
||||
Integer serverHandle = this._itemHandleMap.get ( opcItemId );
|
||||
if ( serverHandle == null )
|
||||
{
|
||||
_log.debug ( String.format ( "Failed to locate item with id '%s'", opcItemId ) );
|
||||
return null;
|
||||
}
|
||||
_log.debug ( String.format ( "Item '%s' has server id '%d'", opcItemId, serverHandle ) );
|
||||
return this._itemMap.get ( serverHandle );
|
||||
}
|
||||
|
||||
private synchronized Map<String, Integer> findItems ( final String[] items )
|
||||
{
|
||||
Map<String, Integer> data = new HashMap<String, Integer> ();
|
||||
|
||||
for ( int i = 0; i < items.length; i++ )
|
||||
{
|
||||
data.put ( items[i], this._itemHandleMap.get ( items[i] ) );
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
private synchronized Map<String, Item> findItems ( final Collection<Integer> handles )
|
||||
{
|
||||
Map<String, Item> itemMap = new HashMap<String, Item> ();
|
||||
for ( Integer i : handles )
|
||||
{
|
||||
Item item = this._itemMap.get ( i );
|
||||
if ( item != null )
|
||||
{
|
||||
itemMap.put ( item.getId (), item );
|
||||
}
|
||||
}
|
||||
return itemMap;
|
||||
}
|
||||
|
||||
protected void checkItems ( final Item[] items )
|
||||
{
|
||||
for ( Item item : items )
|
||||
{
|
||||
if ( item.getGroup () != this )
|
||||
{
|
||||
throw new IllegalArgumentException ( "Item does not belong to this group" );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void setActive ( final boolean state, final Item... items ) throws JIException
|
||||
{
|
||||
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 ( final Item[] items )
|
||||
{
|
||||
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 ( final 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 = 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<Item, Integer> ();
|
||||
for ( int i = 0; i < requests.length; i++ )
|
||||
{
|
||||
Result<org.openscada.opc.dcom.da.WriteRequest> entry = resultSet.get ( i );
|
||||
result.put ( requests[i].getItem (), entry.getErrorCode () );
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public synchronized Map<Item, ItemState> read ( final boolean device, final Item... items ) throws JIException
|
||||
{
|
||||
Integer[] handles = 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<Item, ItemState> ();
|
||||
for ( KeyedResult<Integer, OPCITEMSTATE> entry : states )
|
||||
{
|
||||
Item item = this._itemMap.get ( entry.getKey () );
|
||||
ItemState state = new ItemState ( entry.getErrorCode (), entry.getValue ().getValue (), entry.getValue ().getTimestamp ().asCalendar (), entry.getValue ().getQuality () );
|
||||
data.put ( item, state );
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
public Server getServer ()
|
||||
{
|
||||
return this._server;
|
||||
}
|
||||
|
||||
public synchronized void clear () throws JIException
|
||||
{
|
||||
Integer[] handles = this._itemMap.keySet ().toArray ( new Integer[0] );
|
||||
try
|
||||
{
|
||||
this._items.remove ( handles );
|
||||
}
|
||||
finally
|
||||
{
|
||||
// in any case clear our maps
|
||||
this._itemHandleMap.clear ();
|
||||
this._itemMap.clear ();
|
||||
this._itemClientMap.clear ();
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized OPCAsyncIO2 getAsyncIO20 ()
|
||||
{
|
||||
return this._group.getAsyncIO2 ();
|
||||
}
|
||||
|
||||
public synchronized EventHandler attach ( final IOPCDataCallback dataCallback ) throws JIException
|
||||
{
|
||||
return this._group.attach ( dataCallback );
|
||||
}
|
||||
|
||||
public Item findItemByClientHandle ( final int clientHandle )
|
||||
{
|
||||
return this._itemClientMap.get ( clientHandle );
|
||||
}
|
||||
|
||||
public int getServerHandle ()
|
||||
{
|
||||
return this._serverHandle;
|
||||
}
|
||||
|
||||
public synchronized void removeItem ( final String opcItemId ) throws IllegalArgumentException, UnknownHostException, JIException
|
||||
{
|
||||
_log.debug ( String.format ( "Removing item '%s'", opcItemId ) );
|
||||
Item item = getItemByOPCItemId ( opcItemId );
|
||||
if ( item != null )
|
||||
{
|
||||
this._group.getItemManagement ().remove ( item.getServerHandle () );
|
||||
removeItem ( item );
|
||||
_log.debug ( String.format ( "Removed item '%s'", opcItemId ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
_log.warn ( String.format ( "Unable to find item '%s'", opcItemId ) );
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* This file is part of the OpenSCADA project
|
||||
* Copyright (C) 2006-2010 TH4 SYSTEMS GmbH (http://th4-systems.com)
|
||||
*
|
||||
* OpenSCADA is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License version 3
|
||||
* only, as published by the Free Software Foundation.
|
||||
*
|
||||
* OpenSCADA is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License version 3 for more details
|
||||
* (a copy is included in the LICENSE file that accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* version 3 along with OpenSCADA. If not, see
|
||||
* <http://opensource.org/licenses/lgpl-3.0.html> for a copy of the LGPLv3 License.
|
||||
*/
|
||||
|
||||
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 ( final Group group, final int serverHandle, final int clientHandle, final String id )
|
||||
{
|
||||
super ();
|
||||
_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 ( final boolean state ) throws JIException
|
||||
{
|
||||
this._group.setActive ( state, this );
|
||||
}
|
||||
|
||||
public ItemState read ( final boolean device ) throws JIException
|
||||
{
|
||||
return this._group.read ( device, this ).get ( this );
|
||||
}
|
||||
|
||||
public Integer write ( final JIVariant value ) throws JIException
|
||||
{
|
||||
return this._group.write ( new WriteRequest[] { new WriteRequest ( this, value ) } ).get ( this );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,163 @@
|
||||
/*
|
||||
* This file is part of the OpenSCADA project
|
||||
* Copyright (C) 2006-2010 TH4 SYSTEMS GmbH (http://th4-systems.com)
|
||||
*
|
||||
* OpenSCADA is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License version 3
|
||||
* only, as published by the Free Software Foundation.
|
||||
*
|
||||
* OpenSCADA is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License version 3 for more details
|
||||
* (a copy is included in the LICENSE file that accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* version 3 along with OpenSCADA. If not, see
|
||||
* <http://opensource.org/licenses/lgpl-3.0.html> for a copy of the LGPLv3 License.
|
||||
*/
|
||||
|
||||
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 ( final int errorCode, final JIVariant value, final Calendar timestamp, final Short quality )
|
||||
{
|
||||
super ();
|
||||
this._errorCode = errorCode;
|
||||
this._value = value;
|
||||
this._timestamp = timestamp;
|
||||
this._quality = quality;
|
||||
}
|
||||
|
||||
public ItemState ()
|
||||
{
|
||||
super ();
|
||||
}
|
||||
|
||||
@Override
|
||||
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 ( final Short quality )
|
||||
{
|
||||
this._quality = quality;
|
||||
}
|
||||
|
||||
public Calendar getTimestamp ()
|
||||
{
|
||||
return this._timestamp;
|
||||
}
|
||||
|
||||
public void setTimestamp ( final Calendar timestamp )
|
||||
{
|
||||
this._timestamp = timestamp;
|
||||
}
|
||||
|
||||
public JIVariant getValue ()
|
||||
{
|
||||
return this._value;
|
||||
}
|
||||
|
||||
public void setValue ( final JIVariant value )
|
||||
{
|
||||
this._value = value;
|
||||
}
|
||||
|
||||
public int getErrorCode ()
|
||||
{
|
||||
return this._errorCode;
|
||||
}
|
||||
|
||||
public void setErrorCode ( final int errorCode )
|
||||
{
|
||||
this._errorCode = errorCode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode ()
|
||||
{
|
||||
final 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;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals ( final Object obj )
|
||||
{
|
||||
if ( this == obj )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if ( obj == null )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if ( getClass () != obj.getClass () )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
final ItemState other = (ItemState)obj;
|
||||
if ( this._errorCode != other._errorCode )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,445 @@
|
||||
/*
|
||||
* This file is part of the openSCADA project
|
||||
* Copyright (C) 2006-2011 TH4 SYSTEMS GmbH (http://th4-systems.com)
|
||||
*
|
||||
* openSCADA is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License version 3
|
||||
* only, as published by the Free Software Foundation.
|
||||
*
|
||||
* openSCADA is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License version 3 for more details
|
||||
* (a copy is included in the LICENSE file that accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* version 3 along with openSCADA. If not, see
|
||||
* <http://opensource.org/licenses/lgpl-3.0.html> for a copy of the LGPLv3 License.
|
||||
*/
|
||||
|
||||
package org.openscada.opc.lib.da;
|
||||
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
|
||||
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.openscada.opc.lib.da.browser.FlatBrowser;
|
||||
import org.openscada.opc.lib.da.browser.TreeBrowser;
|
||||
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<Integer, Group>();
|
||||
|
||||
private final List<ServerConnectionStateListener> stateListeners = new CopyOnWriteArrayList<ServerConnectionStateListener>();
|
||||
|
||||
private final ScheduledExecutorService scheduler;
|
||||
|
||||
public Server(final ConnectionInformation connectionInformation,
|
||||
final ScheduledExecutorService scheduler) {
|
||||
super();
|
||||
this.connectionInformation = connectionInformation;
|
||||
this.scheduler = scheduler;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the scheduler for the server. Note that this scheduler might get
|
||||
* blocked for a short time if the connection breaks. It should not be used
|
||||
* for time critical operations.
|
||||
*
|
||||
* @return the scheduler for the server
|
||||
*/
|
||||
public ScheduledExecutorService getScheduler() {
|
||||
return this.scheduler;
|
||||
}
|
||||
|
||||
protected synchronized boolean isConnected() {
|
||||
return this.session != null;
|
||||
}
|
||||
|
||||
public synchronized void connect() throws IllegalArgumentException,
|
||||
UnknownHostException, JIException, AlreadyConnectedException {
|
||||
if (isConnected()) {
|
||||
throw new AlreadyConnectedException();
|
||||
}
|
||||
|
||||
final 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);
|
||||
} else if (this.connectionInformation.getProgId() != null) {
|
||||
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);
|
||||
} else {
|
||||
throw new IllegalArgumentException(
|
||||
"Neither clsid nor progid is valid!");
|
||||
}
|
||||
|
||||
this.server = new OPCServer(this.comServer.createInstance());
|
||||
this.errorMessageResolver = new ErrorMessageResolver(
|
||||
this.server.getCommon(), this.defaultLocaleID);
|
||||
} catch (final UnknownHostException e) {
|
||||
logger.info("Unknown host when connecting to server", e);
|
||||
cleanup();
|
||||
throw e;
|
||||
} catch (final JIException e) {
|
||||
logger.info("Failed to connect to server", e);
|
||||
cleanup();
|
||||
throw e;
|
||||
} catch (final Throwable e) {
|
||||
logger.warn("Unknown error", e);
|
||||
cleanup();
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
notifyConnectionStateChange(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* cleanup after the connection is closed
|
||||
*/
|
||||
protected void cleanup() {
|
||||
logger.info("Destroying DCOM session...");
|
||||
final JISession destructSession = this.session;
|
||||
final Thread destructor = new Thread(new Runnable() {
|
||||
|
||||
public void run() {
|
||||
final long ts = System.currentTimeMillis();
|
||||
try {
|
||||
logger.debug("Starting destruction of DCOM session");
|
||||
JISession.destroySession(destructSession);
|
||||
logger.info("Destructed DCOM session");
|
||||
} catch (final Throwable e) {
|
||||
logger.warn("Failed to destruct DCOM session", e);
|
||||
} finally {
|
||||
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();
|
||||
}
|
||||
|
||||
/**
|
||||
* Disconnect the connection if it is connected
|
||||
*/
|
||||
public synchronized void disconnect() {
|
||||
if (!isConnected()) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
notifyConnectionStateChange(false);
|
||||
} catch (final Throwable t) {
|
||||
}
|
||||
|
||||
cleanup();
|
||||
}
|
||||
|
||||
/**
|
||||
* Dispose the connection in the case of an error
|
||||
*/
|
||||
public void dispose() {
|
||||
disconnect();
|
||||
}
|
||||
|
||||
protected synchronized Group getGroup(final OPCGroupStateMgt groupMgt)
|
||||
throws JIException, IllegalArgumentException, UnknownHostException {
|
||||
final Integer serverHandle = groupMgt.getState().getServerHandle();
|
||||
if (this.groups.containsKey(serverHandle)) {
|
||||
return this.groups.get(serverHandle);
|
||||
} else {
|
||||
final Group group = new Group(this, serverHandle, groupMgt);
|
||||
this.groups.put(serverHandle, group);
|
||||
return group;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new named group to the server
|
||||
*
|
||||
* @param name
|
||||
* The name of the group to use. Must be unique or
|
||||
* <code>null</code> so that the server creates a unique name.
|
||||
* @return The new group
|
||||
* @throws NotConnectedException
|
||||
* If the server is not connected using {@link Server#connect()}
|
||||
* @throws IllegalArgumentException
|
||||
* @throws UnknownHostException
|
||||
* @throws JIException
|
||||
* @throws DuplicateGroupException
|
||||
* If a group with this name already exists
|
||||
*/
|
||||
public synchronized Group addGroup(final String name)
|
||||
throws NotConnectedException, IllegalArgumentException,
|
||||
UnknownHostException, JIException, DuplicateGroupException {
|
||||
if (!isConnected()) {
|
||||
throw new NotConnectedException();
|
||||
}
|
||||
|
||||
try {
|
||||
final OPCGroupStateMgt groupMgt = this.server.addGroup(name,
|
||||
this.defaultActive, this.defaultUpdateRate, 0,
|
||||
this.defaultTimeBias, this.defaultPercentDeadband,
|
||||
this.defaultLocaleID);
|
||||
return getGroup(groupMgt);
|
||||
} catch (final JIException e) {
|
||||
switch (e.getErrorCode()) {
|
||||
case 0xC004000C:
|
||||
throw new DuplicateGroupException();
|
||||
default:
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new group and let the server generate a group name
|
||||
*
|
||||
* Actually this method only calls {@link Server#addGroup(String)} with
|
||||
* <code>null</code> as parameter.
|
||||
*
|
||||
* @return the new group
|
||||
* @throws IllegalArgumentException
|
||||
* @throws UnknownHostException
|
||||
* @throws NotConnectedException
|
||||
* @throws JIException
|
||||
* @throws DuplicateGroupException
|
||||
*/
|
||||
public Group addGroup() throws IllegalArgumentException,
|
||||
UnknownHostException, NotConnectedException, JIException,
|
||||
DuplicateGroupException {
|
||||
return addGroup(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Find a group by its name
|
||||
*
|
||||
* @param name
|
||||
* The name to look for
|
||||
* @return The group
|
||||
* @throws IllegalArgumentException
|
||||
* @throws UnknownHostException
|
||||
* @throws JIException
|
||||
* @throws UnknownGroupException
|
||||
* If the group was not found
|
||||
* @throws NotConnectedException
|
||||
* If the server is not connected
|
||||
*/
|
||||
public Group findGroup(final String name) throws IllegalArgumentException,
|
||||
UnknownHostException, JIException, UnknownGroupException,
|
||||
NotConnectedException {
|
||||
if (!isConnected()) {
|
||||
throw new NotConnectedException();
|
||||
}
|
||||
|
||||
try {
|
||||
final OPCGroupStateMgt groupMgt = this.server.getGroupByName(name);
|
||||
return getGroup(groupMgt);
|
||||
} catch (final JIException e) {
|
||||
switch (e.getErrorCode()) {
|
||||
case 0x80070057:
|
||||
throw new UnknownGroupException(name);
|
||||
default:
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public int getDefaultLocaleID() {
|
||||
return this.defaultLocaleID;
|
||||
}
|
||||
|
||||
public void setDefaultLocaleID(final int defaultLocaleID) {
|
||||
this.defaultLocaleID = defaultLocaleID;
|
||||
}
|
||||
|
||||
public Float getDefaultPercentDeadband() {
|
||||
return this.defaultPercentDeadband;
|
||||
}
|
||||
|
||||
public void setDefaultPercentDeadband(final Float defaultPercentDeadband) {
|
||||
this.defaultPercentDeadband = defaultPercentDeadband;
|
||||
}
|
||||
|
||||
public Integer getDefaultTimeBias() {
|
||||
return this.defaultTimeBias;
|
||||
}
|
||||
|
||||
public void setDefaultTimeBias(final Integer defaultTimeBias) {
|
||||
this.defaultTimeBias = defaultTimeBias;
|
||||
}
|
||||
|
||||
public int getDefaultUpdateRate() {
|
||||
return this.defaultUpdateRate;
|
||||
}
|
||||
|
||||
public void setDefaultUpdateRate(final int defaultUpdateRate) {
|
||||
this.defaultUpdateRate = defaultUpdateRate;
|
||||
}
|
||||
|
||||
public boolean isDefaultActive() {
|
||||
return this.defaultActive;
|
||||
}
|
||||
|
||||
public void setDefaultActive(final boolean defaultActive) {
|
||||
this.defaultActive = defaultActive;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the flat browser
|
||||
*
|
||||
* @return The flat browser or <code>null</code> if the functionality is not
|
||||
* supported
|
||||
*/
|
||||
public FlatBrowser getFlatBrowser() {
|
||||
final OPCBrowseServerAddressSpace browser = this.server.getBrowser();
|
||||
if (browser == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return new FlatBrowser(browser);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the tree browser
|
||||
*
|
||||
* @return The tree browser or <code>null</code> if the functionality is not
|
||||
* supported
|
||||
* @throws JIException
|
||||
*/
|
||||
public TreeBrowser getTreeBrowser() throws JIException {
|
||||
final OPCBrowseServerAddressSpace browser = this.server.getBrowser();
|
||||
if (browser == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (browser.queryOrganization() != OPCNAMESPACETYPE.OPC_NS_HIERARCHIAL) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return new TreeBrowser(browser);
|
||||
}
|
||||
|
||||
public synchronized String getErrorMessage(final int errorCode) {
|
||||
if (this.errorMessageResolver == null) {
|
||||
return String.format("Unknown error (%08X)", errorCode);
|
||||
}
|
||||
|
||||
// resolve message
|
||||
final String message = this.errorMessageResolver.getMessage(errorCode);
|
||||
|
||||
// and return if successfull
|
||||
if (message != null) {
|
||||
return message;
|
||||
}
|
||||
|
||||
// return default message
|
||||
return String.format("Unknown error (%08X)", errorCode);
|
||||
}
|
||||
|
||||
public synchronized void addStateListener(
|
||||
final ServerConnectionStateListener listener) {
|
||||
this.stateListeners.add(listener);
|
||||
listener.connectionStateChanged(isConnected());
|
||||
}
|
||||
|
||||
public synchronized void removeStateListener(
|
||||
final ServerConnectionStateListener listener) {
|
||||
this.stateListeners.remove(listener);
|
||||
}
|
||||
|
||||
protected void notifyConnectionStateChange(final boolean connected) {
|
||||
final List<ServerConnectionStateListener> list = new ArrayList<ServerConnectionStateListener>(
|
||||
this.stateListeners);
|
||||
for (final ServerConnectionStateListener listener : list) {
|
||||
listener.connectionStateChanged(connected);
|
||||
}
|
||||
}
|
||||
|
||||
public OPCSERVERSTATUS getServerState(final int timeout) throws Throwable {
|
||||
return new ServerStateOperation(this.server).getServerState(timeout);
|
||||
}
|
||||
|
||||
public OPCSERVERSTATUS getServerState() {
|
||||
try {
|
||||
return getServerState(2500);
|
||||
} catch (final Throwable e) {
|
||||
logger.info("Server connection failed", e);
|
||||
dispose();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public void removeGroup(final Group group, final boolean force)
|
||||
throws JIException {
|
||||
if (this.groups.containsKey(group.getServerHandle())) {
|
||||
this.server.removeGroup(group.getServerHandle(), force);
|
||||
this.groups.remove(group.getServerHandle());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* This file is part of the OpenSCADA project
|
||||
* Copyright (C) 2006-2010 TH4 SYSTEMS GmbH (http://th4-systems.com)
|
||||
*
|
||||
* OpenSCADA is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License version 3
|
||||
* only, as published by the Free Software Foundation.
|
||||
*
|
||||
* OpenSCADA is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License version 3 for more details
|
||||
* (a copy is included in the LICENSE file that accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* version 3 along with OpenSCADA. If not, see
|
||||
* <http://opensource.org/licenses/lgpl-3.0.html> for a copy of the LGPLv3 License.
|
||||
*/
|
||||
|
||||
package org.openscada.opc.lib.da;
|
||||
|
||||
public interface ServerConnectionStateListener
|
||||
{
|
||||
public abstract void connectionStateChanged ( boolean connected );
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* This file is part of the OpenSCADA project
|
||||
* Copyright (C) 2006-2010 TH4 SYSTEMS GmbH (http://th4-systems.com)
|
||||
*
|
||||
* OpenSCADA is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License version 3
|
||||
* only, as published by the Free Software Foundation.
|
||||
*
|
||||
* OpenSCADA is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License version 3 for more details
|
||||
* (a copy is included in the LICENSE file that accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* version 3 along with OpenSCADA. If not, see
|
||||
* <http://opensource.org/licenses/lgpl-3.0.html> for a copy of the LGPLv3 License.
|
||||
*/
|
||||
|
||||
package org.openscada.opc.lib.da;
|
||||
|
||||
import org.openscada.opc.dcom.da.OPCSERVERSTATUS;
|
||||
|
||||
public interface ServerStateListener
|
||||
{
|
||||
public void stateUpdate ( OPCSERVERSTATUS state );
|
||||
}
|
||||
@@ -0,0 +1,123 @@
|
||||
/*
|
||||
* This file is part of the OpenSCADA project
|
||||
* Copyright (C) 2006-2010 TH4 SYSTEMS GmbH (http://th4-systems.com)
|
||||
*
|
||||
* OpenSCADA is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License version 3
|
||||
* only, as published by the Free Software Foundation.
|
||||
*
|
||||
* OpenSCADA is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License version 3 for more details
|
||||
* (a copy is included in the LICENSE file that accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* version 3 along with OpenSCADA. If not, see
|
||||
* <http://opensource.org/licenses/lgpl-3.0.html> for a copy of the LGPLv3 License.
|
||||
*/
|
||||
|
||||
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;
|
||||
|
||||
/**
|
||||
* A server state operation which can be interruped
|
||||
* @author Jens Reimann
|
||||
*
|
||||
*/
|
||||
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 ( final OPCServer server )
|
||||
{
|
||||
super ();
|
||||
this._server = server;
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform the operation.
|
||||
* <p>
|
||||
* This method will block until either the serve state has been aquired or the
|
||||
* timeout triggers cancels the call.
|
||||
* </p>
|
||||
*/
|
||||
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 e )
|
||||
{
|
||||
_log.info ( "Failed to get server state", e );
|
||||
this._error = e;
|
||||
this._running = false;
|
||||
synchronized ( this._lock )
|
||||
{
|
||||
this._lock.notify ();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the server state with a timeout.
|
||||
* @return the server state or <code>null</code> if the server is not set.
|
||||
* @param timeout the timeout in ms
|
||||
* @throws Throwable any error that occurred
|
||||
*/
|
||||
public OPCSERVERSTATUS getServerState ( final int timeout ) throws Throwable
|
||||
{
|
||||
if ( this._server == null )
|
||||
{
|
||||
_log.debug ( "No connection to server. Skipping..." );
|
||||
return null;
|
||||
}
|
||||
|
||||
Thread t = new Thread ( this, "OPCServerStateReader" );
|
||||
|
||||
synchronized ( this._lock )
|
||||
{
|
||||
t.start ();
|
||||
this._lock.wait ( 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;
|
||||
}
|
||||
|
||||
return this._serverStatus;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
/*
|
||||
* This file is part of the OpenSCADA project
|
||||
* Copyright (C) 2006-2010 TH4 SYSTEMS GmbH (http://th4-systems.com)
|
||||
*
|
||||
* OpenSCADA is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License version 3
|
||||
* only, as published by the Free Software Foundation.
|
||||
*
|
||||
* OpenSCADA is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License version 3 for more details
|
||||
* (a copy is included in the LICENSE file that accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* version 3 along with OpenSCADA. If not, see
|
||||
* <http://opensource.org/licenses/lgpl-3.0.html> for a copy of the LGPLv3 License.
|
||||
*/
|
||||
|
||||
package org.openscada.opc.lib.da;
|
||||
|
||||
import java.util.ArrayList;
|
||||
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<ServerStateListener> ();
|
||||
|
||||
private ScheduledFuture<?> _job = null;
|
||||
|
||||
public ServerStateReader ( final Server server )
|
||||
{
|
||||
super ();
|
||||
this._server = server;
|
||||
this._scheduler = this._server.getScheduler ();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new server state reader. Please note that the scheduler might get
|
||||
* blocked for a short period of time in case of a connection failure!
|
||||
* @param server the server to check
|
||||
* @param scheduler the scheduler to use
|
||||
*/
|
||||
public ServerStateReader ( final Server server, final ScheduledExecutorService scheduler )
|
||||
{
|
||||
super ();
|
||||
this._server = server;
|
||||
this._scheduler = scheduler;
|
||||
}
|
||||
|
||||
public synchronized void start ()
|
||||
{
|
||||
if ( this._job != null )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
this._job = this._scheduler.scheduleAtFixedRate ( new Runnable () {
|
||||
|
||||
public void run ()
|
||||
{
|
||||
once ();
|
||||
}
|
||||
}, 1000, 1000, TimeUnit.MILLISECONDS );
|
||||
}
|
||||
|
||||
public synchronized void stop ()
|
||||
{
|
||||
this._job.cancel ( false );
|
||||
this._job = null;
|
||||
}
|
||||
|
||||
protected void once ()
|
||||
{
|
||||
_log.debug ( "Reading server state" );
|
||||
|
||||
final OPCSERVERSTATUS state = this._server.getServerState ();
|
||||
|
||||
for ( final ServerStateListener listener : new ArrayList<ServerStateListener> ( this._listeners ) )
|
||||
{
|
||||
listener.stateUpdate ( state );
|
||||
}
|
||||
}
|
||||
|
||||
public void addListener ( final ServerStateListener listener )
|
||||
{
|
||||
this._listeners.add ( listener );
|
||||
}
|
||||
|
||||
public void removeListener ( final ServerStateListener listener )
|
||||
{
|
||||
this._listeners.remove ( listener );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,120 @@
|
||||
/*
|
||||
* This file is part of the OpenSCADA project
|
||||
* Copyright (C) 2006-2010 TH4 SYSTEMS GmbH (http://th4-systems.com)
|
||||
*
|
||||
* OpenSCADA is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License version 3
|
||||
* only, as published by the Free Software Foundation.
|
||||
*
|
||||
* OpenSCADA is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License version 3 for more details
|
||||
* (a copy is included in the LICENSE file that accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* version 3 along with OpenSCADA. If not, see
|
||||
* <http://opensource.org/licenses/lgpl-3.0.html> for a copy of the LGPLv3 License.
|
||||
*/
|
||||
|
||||
package org.openscada.opc.lib.da;
|
||||
|
||||
import java.net.UnknownHostException;
|
||||
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 ( final Server server, final int period ) throws IllegalArgumentException, UnknownHostException, NotConnectedException, JIException, DuplicateGroupException
|
||||
{
|
||||
super ( server, period );
|
||||
}
|
||||
|
||||
public SyncAccess ( final Server server, final int period, final String logTag ) throws IllegalArgumentException, UnknownHostException, NotConnectedException, JIException, DuplicateGroupException
|
||||
{
|
||||
super ( server, period, logTag );
|
||||
}
|
||||
|
||||
public void run ()
|
||||
{
|
||||
while ( this.active )
|
||||
{
|
||||
try
|
||||
{
|
||||
runOnce ();
|
||||
if ( this.lastError != null )
|
||||
{
|
||||
this.lastError = null;
|
||||
handleError ( null );
|
||||
}
|
||||
}
|
||||
catch ( Throwable e )
|
||||
{
|
||||
logger.error ( "Sync read failed", e );
|
||||
handleError ( e );
|
||||
this.server.disconnect ();
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
Thread.sleep ( getPeriod () );
|
||||
}
|
||||
catch ( InterruptedException e )
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void runOnce () throws JIException
|
||||
{
|
||||
if ( !this.active || this.group == null )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Map<Item, ItemState> result;
|
||||
|
||||
// lock only this section since we could get into a deadlock otherwise
|
||||
// calling updateItem
|
||||
synchronized ( this )
|
||||
{
|
||||
Item[] items = this.items.keySet ().toArray ( new Item[this.items.size ()] );
|
||||
result = this.group.read ( false, items );
|
||||
}
|
||||
|
||||
for ( Map.Entry<Item, ItemState> entry : result.entrySet () )
|
||||
{
|
||||
updateItem ( entry.getKey (), entry.getValue () );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
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 ();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected synchronized void stop () throws JIException
|
||||
{
|
||||
super.stop ();
|
||||
|
||||
this.runner = null;
|
||||
this.items.clear ();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* This file is part of the OpenSCADA project
|
||||
* Copyright (C) 2006-2010 TH4 SYSTEMS GmbH (http://th4-systems.com)
|
||||
*
|
||||
* OpenSCADA is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License version 3
|
||||
* only, as published by the Free Software Foundation.
|
||||
*
|
||||
* OpenSCADA is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License version 3 for more details
|
||||
* (a copy is included in the LICENSE file that accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* version 3 along with OpenSCADA. If not, see
|
||||
* <http://opensource.org/licenses/lgpl-3.0.html> for a copy of the LGPLv3 License.
|
||||
*/
|
||||
|
||||
package org.openscada.opc.lib.da;
|
||||
|
||||
public class UnknownGroupException extends Exception
|
||||
{
|
||||
private String _name = null;
|
||||
|
||||
public UnknownGroupException ( final String name )
|
||||
{
|
||||
super ();
|
||||
this._name = name;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static final long serialVersionUID = 1771564928794033075L;
|
||||
|
||||
public String getName ()
|
||||
{
|
||||
return this._name;
|
||||
}
|
||||
|
||||
public void setName ( final String name )
|
||||
{
|
||||
this._name = name;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* This file is part of the OpenSCADA project
|
||||
* Copyright (C) 2006-2010 TH4 SYSTEMS GmbH (http://th4-systems.com)
|
||||
*
|
||||
* OpenSCADA is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License version 3
|
||||
* only, as published by the Free Software Foundation.
|
||||
*
|
||||
* OpenSCADA is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License version 3 for more details
|
||||
* (a copy is included in the LICENSE file that accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* version 3 along with OpenSCADA. If not, see
|
||||
* <http://opensource.org/licenses/lgpl-3.0.html> for a copy of the LGPLv3 License.
|
||||
*/
|
||||
|
||||
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 ( final Item item, final JIVariant value )
|
||||
{
|
||||
super ();
|
||||
this._item = item;
|
||||
this._value = value;
|
||||
}
|
||||
|
||||
public Item getItem ()
|
||||
{
|
||||
return this._item;
|
||||
}
|
||||
|
||||
public JIVariant getValue ()
|
||||
{
|
||||
return this._value;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* This file is part of the OpenSCADA project
|
||||
* Copyright (C) 2006-2010 TH4 SYSTEMS GmbH (http://th4-systems.com)
|
||||
*
|
||||
* OpenSCADA is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License version 3
|
||||
* only, as published by the Free Software Foundation.
|
||||
*
|
||||
* OpenSCADA is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License version 3 for more details
|
||||
* (a copy is included in the LICENSE file that accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* version 3 along with OpenSCADA. If not, see
|
||||
* <http://opensource.org/licenses/lgpl-3.0.html> for a copy of the LGPLv3 License.
|
||||
*/
|
||||
|
||||
package org.openscada.opc.lib.da.browser;
|
||||
|
||||
public enum Access
|
||||
{
|
||||
READ ( 1 ),
|
||||
WRITE ( 2 );
|
||||
|
||||
private int _code = 0;
|
||||
|
||||
private Access ( final int code )
|
||||
{
|
||||
this._code = code;
|
||||
}
|
||||
|
||||
public int getCode ()
|
||||
{
|
||||
return this._code;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,124 @@
|
||||
/*
|
||||
* This file is part of the OpenSCADA project
|
||||
* Copyright (C) 2006-2010 TH4 SYSTEMS GmbH (http://th4-systems.com)
|
||||
*
|
||||
* OpenSCADA is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License version 3
|
||||
* only, as published by the Free Software Foundation.
|
||||
*
|
||||
* OpenSCADA is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License version 3 for more details
|
||||
* (a copy is included in the LICENSE file that accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* version 3 along with OpenSCADA. If not, see
|
||||
* <http://opensource.org/licenses/lgpl-3.0.html> for a copy of the LGPLv3 License.
|
||||
*/
|
||||
|
||||
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;
|
||||
|
||||
/**
|
||||
* A class implementing base browsing
|
||||
* @author Jens Reimann
|
||||
*
|
||||
*/
|
||||
public class BaseBrowser
|
||||
{
|
||||
private static Logger _log = LoggerFactory.getLogger ( BaseBrowser.class );
|
||||
|
||||
protected OPCBrowseServerAddressSpace _browser;
|
||||
|
||||
/**
|
||||
* The batch size is the number of entries that will be requested with one call
|
||||
* from the server. Sometimes too big batch sizes will cause an exception. And
|
||||
* smaller batch sizes degrade perfomance. The default is set by {@link EnumString#DEFAULT_BATCH_SIZE}
|
||||
* and can be overridden by the java property <q>openscada.dcom.enum-batch-size</q>.
|
||||
*/
|
||||
protected int _batchSize;
|
||||
|
||||
public BaseBrowser ( final OPCBrowseServerAddressSpace browser )
|
||||
{
|
||||
this ( browser, EnumString.DEFAULT_BATCH_SIZE );
|
||||
}
|
||||
|
||||
public BaseBrowser ( final OPCBrowseServerAddressSpace browser, final int batchSize )
|
||||
{
|
||||
super ();
|
||||
this._browser = browser;
|
||||
this._batchSize = batchSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the batch size
|
||||
* @param batchSize The new batch size
|
||||
*/
|
||||
public void setBatchSize ( final int batchSize )
|
||||
{
|
||||
this._batchSize = batchSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the batch size
|
||||
* @return the current batch size
|
||||
*/
|
||||
public int getBatchSize ()
|
||||
{
|
||||
return this._batchSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform the browse operation.
|
||||
* @param type
|
||||
* @param filterCriteria
|
||||
* @param accessMask
|
||||
* @param variantType
|
||||
* @return The browse result
|
||||
* @throws IllegalArgumentException
|
||||
* @throws UnknownHostException
|
||||
* @throws JIException
|
||||
*/
|
||||
protected Collection<String> browse ( final OPCBROWSETYPE type, final String filterCriteria, final EnumSet<Access> accessMask, final 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 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Browse the access paths for one item.
|
||||
* @param itemId The item ID to look up the access paths
|
||||
* @return The collection of the access paths
|
||||
* @throws JIException
|
||||
* @throws UnknownHostException
|
||||
* @throws IllegalArgumentException
|
||||
*/
|
||||
public Collection<String> getAccessPaths ( final String itemId ) throws IllegalArgumentException, UnknownHostException, JIException
|
||||
{
|
||||
return this._browser.browseAccessPaths ( itemId ).asCollection ( this._batchSize );
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,123 @@
|
||||
/*
|
||||
* This file is part of the OpenSCADA project
|
||||
* Copyright (C) 2006-2010 TH4 SYSTEMS GmbH (http://th4-systems.com)
|
||||
*
|
||||
* OpenSCADA is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License version 3
|
||||
* only, as published by the Free Software Foundation.
|
||||
*
|
||||
* OpenSCADA is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License version 3 for more details
|
||||
* (a copy is included in the LICENSE file that accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* version 3 along with OpenSCADA. If not, see
|
||||
* <http://opensource.org/licenses/lgpl-3.0.html> for a copy of the LGPLv3 License.
|
||||
*/
|
||||
|
||||
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<Branch> ();
|
||||
|
||||
private Collection<Leaf> _leaves = new LinkedList<Leaf> ();
|
||||
|
||||
/**
|
||||
* Create a branch to the virtual root folder
|
||||
*
|
||||
*/
|
||||
public Branch ()
|
||||
{
|
||||
super ();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a branch with a parent branch and a name of this branch.
|
||||
* @param parent The parent of this branch
|
||||
* @param name The name of this branch
|
||||
*/
|
||||
public Branch ( final Branch parent, final String name )
|
||||
{
|
||||
super ();
|
||||
this._name = name;
|
||||
this._parent = parent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all branches.
|
||||
* <br/>
|
||||
* They must be filled first with a fill method from the {@link TreeBrowser}
|
||||
* @return The list of branches
|
||||
*/
|
||||
public Collection<Branch> getBranches ()
|
||||
{
|
||||
return this._branches;
|
||||
}
|
||||
|
||||
public void setBranches ( final Collection<Branch> branches )
|
||||
{
|
||||
this._branches = branches;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all leaves.
|
||||
* <br/>
|
||||
* They must be filled first with a fill method from the {@link TreeBrowser}
|
||||
* @return The list of leaves
|
||||
*/
|
||||
public Collection<Leaf> getLeaves ()
|
||||
{
|
||||
return this._leaves;
|
||||
}
|
||||
|
||||
public void setLeaves ( final Collection<Leaf> leaves )
|
||||
{
|
||||
this._leaves = leaves;
|
||||
}
|
||||
|
||||
public String getName ()
|
||||
{
|
||||
return this._name;
|
||||
}
|
||||
|
||||
public void setName ( final String name )
|
||||
{
|
||||
this._name = name;
|
||||
}
|
||||
|
||||
public Branch getParent ()
|
||||
{
|
||||
return this._parent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the list of names from the parent up to this branch
|
||||
* @return The stack of branch names from the parent up this one
|
||||
*/
|
||||
public Collection<String> getBranchStack ()
|
||||
{
|
||||
LinkedList<String> branches = new LinkedList<String> ();
|
||||
|
||||
Branch currentBranch = this;
|
||||
while ( currentBranch.getParent () != null )
|
||||
{
|
||||
branches.add ( currentBranch.getName () );
|
||||
currentBranch = currentBranch.getParent ();
|
||||
}
|
||||
|
||||
Collections.reverse ( branches );
|
||||
return branches;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* This file is part of the OpenSCADA project
|
||||
* Copyright (C) 2006-2010 TH4 SYSTEMS GmbH (http://th4-systems.com)
|
||||
*
|
||||
* OpenSCADA is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License version 3
|
||||
* only, as published by the Free Software Foundation.
|
||||
*
|
||||
* OpenSCADA is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License version 3 for more details
|
||||
* (a copy is included in the LICENSE file that accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* version 3 along with OpenSCADA. If not, see
|
||||
* <http://opensource.org/licenses/lgpl-3.0.html> for a copy of the LGPLv3 License.
|
||||
*/
|
||||
|
||||
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.jinterop.dcom.core.JIVariant;
|
||||
import org.openscada.opc.dcom.da.OPCBROWSETYPE;
|
||||
import org.openscada.opc.dcom.da.impl.OPCBrowseServerAddressSpace;
|
||||
|
||||
/**
|
||||
* Browse through the flat server namespace
|
||||
* @author Jens Reimann <jens.reimann@th4-systems.com>
|
||||
*
|
||||
*/
|
||||
public class FlatBrowser extends BaseBrowser
|
||||
{
|
||||
public FlatBrowser ( final OPCBrowseServerAddressSpace browser )
|
||||
{
|
||||
super ( browser );
|
||||
}
|
||||
|
||||
public FlatBrowser ( final OPCBrowseServerAddressSpace browser, final int batchSize )
|
||||
{
|
||||
super ( browser, batchSize );
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform a flat browse operation
|
||||
* @param filterCriteria The filter criteria. Use an empty string if you don't need one.
|
||||
* @param accessMask The access mask. An empty set will search for all.
|
||||
* @param variantType The variant type. Must be one of the <code>VT_</code> constants of {@link JIVariant}. Use {@link JIVariant#VT_EMPTY} if you want to browse for all.
|
||||
* @return The list of entries
|
||||
* @throws IllegalArgumentException
|
||||
* @throws UnknownHostException
|
||||
* @throws JIException
|
||||
*/
|
||||
public Collection<String> browse ( final String filterCriteria, final EnumSet<Access> accessMask, final int variantType ) throws IllegalArgumentException, UnknownHostException, JIException
|
||||
{
|
||||
return browse ( OPCBROWSETYPE.OPC_FLAT, filterCriteria, accessMask, variantType );
|
||||
}
|
||||
|
||||
public Collection<String> browse ( final String filterCriteria ) throws IllegalArgumentException, UnknownHostException, JIException
|
||||
{
|
||||
return browse ( filterCriteria, EnumSet.noneOf ( Access.class ), JIVariant.VT_EMPTY );
|
||||
}
|
||||
|
||||
public Collection<String> browse () throws IllegalArgumentException, UnknownHostException, JIException
|
||||
{
|
||||
return browse ( "", EnumSet.noneOf ( Access.class ), JIVariant.VT_EMPTY );
|
||||
}
|
||||
|
||||
public Collection<String> browse ( final EnumSet<Access> accessMask ) throws IllegalArgumentException, UnknownHostException, JIException
|
||||
{
|
||||
return browse ( "", accessMask, JIVariant.VT_EMPTY );
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* This file is part of the OpenSCADA project
|
||||
* Copyright (C) 2006-2010 TH4 SYSTEMS GmbH (http://th4-systems.com)
|
||||
*
|
||||
* OpenSCADA is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License version 3
|
||||
* only, as published by the Free Software Foundation.
|
||||
*
|
||||
* OpenSCADA is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License version 3 for more details
|
||||
* (a copy is included in the LICENSE file that accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* version 3 along with OpenSCADA. If not, see
|
||||
* <http://opensource.org/licenses/lgpl-3.0.html> for a copy of the LGPLv3 License.
|
||||
*/
|
||||
|
||||
package org.openscada.opc.lib.da.browser;
|
||||
|
||||
public class Leaf
|
||||
{
|
||||
private Branch _parent = null;
|
||||
|
||||
private String _name = "";
|
||||
|
||||
private String _itemId = null;
|
||||
|
||||
public Leaf ( final Branch parent, final String name )
|
||||
{
|
||||
this._parent = parent;
|
||||
this._name = name;
|
||||
}
|
||||
|
||||
public Leaf ( final Branch parent, final String name, final String itemId )
|
||||
{
|
||||
this._parent = parent;
|
||||
this._name = name;
|
||||
this._itemId = itemId;
|
||||
}
|
||||
|
||||
public String getItemId ()
|
||||
{
|
||||
return this._itemId;
|
||||
}
|
||||
|
||||
public void setItemId ( final String itemId )
|
||||
{
|
||||
this._itemId = itemId;
|
||||
}
|
||||
|
||||
public String getName ()
|
||||
{
|
||||
return this._name;
|
||||
}
|
||||
|
||||
public void setName ( final String name )
|
||||
{
|
||||
this._name = name;
|
||||
}
|
||||
|
||||
public Branch getParent ()
|
||||
{
|
||||
return this._parent;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,240 @@
|
||||
/*
|
||||
* This file is part of the OpenSCADA project
|
||||
* Copyright (C) 2006-2010 TH4 SYSTEMS GmbH (http://th4-systems.com)
|
||||
*
|
||||
* OpenSCADA is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License version 3
|
||||
* only, as published by the Free Software Foundation.
|
||||
*
|
||||
* OpenSCADA is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License version 3 for more details
|
||||
* (a copy is included in the LICENSE file that accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* version 3 along with OpenSCADA. If not, see
|
||||
* <http://opensource.org/licenses/lgpl-3.0.html> for a copy of the LGPLv3 License.
|
||||
*/
|
||||
|
||||
package org.openscada.opc.lib.da.browser;
|
||||
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.Collection;
|
||||
import java.util.EnumSet;
|
||||
import java.util.LinkedList;
|
||||
|
||||
import org.jinterop.dcom.common.JIException;
|
||||
import org.jinterop.dcom.core.JIVariant;
|
||||
import org.openscada.opc.dcom.da.OPCBROWSEDIRECTION;
|
||||
import org.openscada.opc.dcom.da.OPCBROWSETYPE;
|
||||
import org.openscada.opc.dcom.da.impl.OPCBrowseServerAddressSpace;
|
||||
|
||||
/**
|
||||
* Browse through the hierarchical server namespace.
|
||||
* <br/>
|
||||
* The operations on the address space browser browser are not synchronized
|
||||
* as is the TreeBrowser itself. The user must take care of preventing
|
||||
* simultanious access to this instance and the server address space browser.
|
||||
* @author Jens Reimann <jens.reimann@th4-systems.com>
|
||||
*
|
||||
*/
|
||||
public class TreeBrowser extends BaseBrowser
|
||||
{
|
||||
|
||||
private String _filterCriteria = "";
|
||||
|
||||
private EnumSet<Access> _accessMask = EnumSet.noneOf ( Access.class );
|
||||
|
||||
private int _variantType = JIVariant.VT_EMPTY;
|
||||
|
||||
/**
|
||||
* Browse for all items without search parameters.
|
||||
* <br/>
|
||||
* This will actually call:
|
||||
* <br/>
|
||||
* <code>
|
||||
* TreeBrowser ( browser, "", EnumSet.noneOf ( Access.class ), JIVariant.VT_EMPTY );
|
||||
* </code>
|
||||
* @param browser The browser to use for browsing
|
||||
*/
|
||||
public TreeBrowser ( final OPCBrowseServerAddressSpace browser )
|
||||
{
|
||||
super ( browser );
|
||||
}
|
||||
|
||||
/**
|
||||
* Browse for items with search parameters.
|
||||
* @param browser The browser to use
|
||||
* @param filterCriteria The filter criteria. It is specific to the server you use.
|
||||
* @param accessMask The access mask (use <code>EnumSet.noneOf ( Access.class )</code> for all)
|
||||
* @param variantType The variant type (use <code>JIVariant.VT_EMPTY</code> for all)
|
||||
*/
|
||||
public TreeBrowser ( final OPCBrowseServerAddressSpace browser, final String filterCriteria, final EnumSet<Access> accessMask, final int variantType )
|
||||
{
|
||||
super ( browser );
|
||||
this._filterCriteria = filterCriteria;
|
||||
this._accessMask = accessMask;
|
||||
this._variantType = variantType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Move the tree browser to the root folder
|
||||
* @throws JIException
|
||||
*/
|
||||
protected void moveToRoot () throws JIException
|
||||
{
|
||||
this._browser.changePosition ( null, OPCBROWSEDIRECTION.OPC_BROWSE_TO );
|
||||
}
|
||||
|
||||
/**
|
||||
* Move the tree browser to a branch
|
||||
* @param branch The branch to move to
|
||||
* @throws JIException
|
||||
*/
|
||||
protected void moveToBranch ( final Branch branch ) throws JIException
|
||||
{
|
||||
Collection<String> branchStack = branch.getBranchStack ();
|
||||
|
||||
moveToRoot ();
|
||||
for ( String branchName : branchStack )
|
||||
{
|
||||
this._browser.changePosition ( branchName, OPCBROWSEDIRECTION.OPC_BROWSE_DOWN );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Browse the root branch for its sub-branches.
|
||||
* @return The list of sub branches
|
||||
* @throws JIException
|
||||
* @throws IllegalArgumentException
|
||||
* @throws UnknownHostException
|
||||
*/
|
||||
public Branch browseBranches () throws JIException, IllegalArgumentException, UnknownHostException
|
||||
{
|
||||
Branch branch = new Branch ();
|
||||
fillBranches ( branch );
|
||||
return branch;
|
||||
}
|
||||
|
||||
/**
|
||||
* Browse the root branch for this leaves.
|
||||
* @return The list of leaves
|
||||
* @throws IllegalArgumentException
|
||||
* @throws UnknownHostException
|
||||
* @throws JIException
|
||||
*/
|
||||
public Branch browseLeaves () throws IllegalArgumentException, UnknownHostException, JIException
|
||||
{
|
||||
Branch branch = new Branch ();
|
||||
fillLeaves ( branch );
|
||||
return branch;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fill the branch list of the provided branch.
|
||||
* @param branch The branch to fill.
|
||||
* @throws JIException
|
||||
* @throws IllegalArgumentException
|
||||
* @throws UnknownHostException
|
||||
*/
|
||||
public void fillBranches ( final Branch branch ) throws JIException, IllegalArgumentException, UnknownHostException
|
||||
{
|
||||
moveToBranch ( branch );
|
||||
browse ( branch, false, true, false );
|
||||
}
|
||||
|
||||
/**
|
||||
* Fill the leaf list of the provided branch.
|
||||
* @param branch The branch to fill.
|
||||
* @throws IllegalArgumentException
|
||||
* @throws UnknownHostException
|
||||
* @throws JIException
|
||||
*/
|
||||
public void fillLeaves ( final Branch branch ) throws IllegalArgumentException, UnknownHostException, JIException
|
||||
{
|
||||
moveToBranch ( branch );
|
||||
browse ( branch, true, false, false );
|
||||
}
|
||||
|
||||
/**
|
||||
* Browse through all levels of the tree browser.
|
||||
* @return The whole expanded server address space
|
||||
* @throws JIException
|
||||
* @throws IllegalArgumentException
|
||||
* @throws UnknownHostException
|
||||
*/
|
||||
public Branch browse () throws JIException, IllegalArgumentException, UnknownHostException
|
||||
{
|
||||
Branch branch = new Branch ();
|
||||
fill ( branch );
|
||||
return branch;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fill the leaves and branches of the branch provided branches including
|
||||
* alls sub-branches.
|
||||
* @param branch The branch to fill.
|
||||
* @throws IllegalArgumentException
|
||||
* @throws UnknownHostException
|
||||
* @throws JIException
|
||||
*/
|
||||
public void fill ( final Branch branch ) throws IllegalArgumentException, UnknownHostException, JIException
|
||||
{
|
||||
moveToBranch ( branch );
|
||||
browse ( branch, true, true, true );
|
||||
}
|
||||
|
||||
/**
|
||||
* Fill the branch object with the leaves of this currently selected branch.
|
||||
* <br/>
|
||||
* The server object is not located to the branch before browsing!
|
||||
* @param branch The branch to fill
|
||||
* @throws IllegalArgumentException
|
||||
* @throws UnknownHostException
|
||||
* @throws JIException
|
||||
*/
|
||||
protected void browseLeaves ( final Branch branch ) throws IllegalArgumentException, UnknownHostException, JIException
|
||||
{
|
||||
branch.setLeaves ( new LinkedList<Leaf> () );
|
||||
|
||||
for ( String item : browse ( OPCBROWSETYPE.OPC_LEAF, this._filterCriteria, this._accessMask, this._variantType ) )
|
||||
{
|
||||
Leaf leaf = new Leaf ( branch, item, this._browser.getItemID ( item ) );
|
||||
branch.getLeaves ().add ( leaf );
|
||||
}
|
||||
}
|
||||
|
||||
protected void browseBranches ( final Branch branch, final boolean leaves, final boolean descend ) throws IllegalArgumentException, UnknownHostException, JIException
|
||||
{
|
||||
branch.setBranches ( new LinkedList<Branch> () );
|
||||
|
||||
for ( String item : browse ( OPCBROWSETYPE.OPC_BRANCH, this._filterCriteria, this._accessMask, this._variantType ) )
|
||||
{
|
||||
Branch subBranch = new Branch ( branch, item );
|
||||
// descend only if we should
|
||||
if ( descend )
|
||||
{
|
||||
this._browser.changePosition ( item, OPCBROWSEDIRECTION.OPC_BROWSE_DOWN );
|
||||
browse ( subBranch, leaves, true, true );
|
||||
this._browser.changePosition ( null, OPCBROWSEDIRECTION.OPC_BROWSE_UP );
|
||||
}
|
||||
branch.getBranches ().add ( subBranch );
|
||||
}
|
||||
}
|
||||
|
||||
protected void browse ( final Branch branch, final boolean leaves, final boolean branches, final boolean descend ) throws IllegalArgumentException, UnknownHostException, JIException
|
||||
{
|
||||
// process leaves
|
||||
if ( leaves )
|
||||
{
|
||||
browseLeaves ( branch );
|
||||
}
|
||||
|
||||
// process branches
|
||||
if ( branches )
|
||||
{
|
||||
browseBranches ( branch, leaves, descend );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* This file is part of the OpenSCADA project
|
||||
* Copyright (C) 2006-2010 TH4 SYSTEMS GmbH (http://th4-systems.com)
|
||||
*
|
||||
* OpenSCADA is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License version 3
|
||||
* only, as published by the Free Software Foundation.
|
||||
*
|
||||
* OpenSCADA is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License version 3 for more details
|
||||
* (a copy is included in the LICENSE file that accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* version 3 along with OpenSCADA. If not, see
|
||||
* <http://opensource.org/licenses/lgpl-3.0.html> for a copy of the LGPLv3 License.
|
||||
*/
|
||||
|
||||
package org.openscada.opc.lib.list;
|
||||
|
||||
public interface Categories
|
||||
{
|
||||
/**
|
||||
* Category of the OPC DA 1.0 Servers
|
||||
*/
|
||||
public final static Category OPCDAServer10 = new Category ( org.openscada.opc.dcom.common.Categories.OPCDAServer10 );
|
||||
|
||||
/**
|
||||
* Category of the OPC DA 2.0 Servers
|
||||
*/
|
||||
public final static Category OPCDAServer20 = new Category ( org.openscada.opc.dcom.common.Categories.OPCDAServer20 );
|
||||
|
||||
/**
|
||||
* Category of the OPC DA 3.0 Servers
|
||||
*/
|
||||
public final static Category OPCDAServer30 = new Category ( org.openscada.opc.dcom.common.Categories.OPCDAServer30 );
|
||||
|
||||
/**
|
||||
* Category of the XML DA 1.0 Servers
|
||||
*/
|
||||
public final static Category XMLDAServer10 = new Category ( org.openscada.opc.dcom.common.Categories.XMLDAServer10 );
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* This file is part of the OpenSCADA project
|
||||
* Copyright (C) 2006-2010 TH4 SYSTEMS GmbH (http://th4-systems.com)
|
||||
*
|
||||
* OpenSCADA is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License version 3
|
||||
* only, as published by the Free Software Foundation.
|
||||
*
|
||||
* OpenSCADA is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License version 3 for more details
|
||||
* (a copy is included in the LICENSE file that accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* version 3 along with OpenSCADA. If not, see
|
||||
* <http://opensource.org/licenses/lgpl-3.0.html> for a copy of the LGPLv3 License.
|
||||
*/
|
||||
|
||||
package org.openscada.opc.lib.list;
|
||||
|
||||
public class Category
|
||||
{
|
||||
private String _catId = null;
|
||||
|
||||
public Category ( final String catId )
|
||||
{
|
||||
this._catId = catId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString ()
|
||||
{
|
||||
return this._catId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode ()
|
||||
{
|
||||
final int PRIME = 31;
|
||||
int result = 1;
|
||||
result = PRIME * result + ( this._catId == null ? 0 : this._catId.hashCode () );
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals ( final Object obj )
|
||||
{
|
||||
if ( this == obj )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if ( obj == null )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if ( getClass () != obj.getClass () )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
final 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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,179 @@
|
||||
/*
|
||||
* This file is part of the OpenSCADA project
|
||||
* Copyright (C) 2006-2010 TH4 SYSTEMS GmbH (http://th4-systems.com)
|
||||
*
|
||||
* OpenSCADA is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License version 3
|
||||
* only, as published by the Free Software Foundation.
|
||||
*
|
||||
* OpenSCADA is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License version 3 for more details
|
||||
* (a copy is included in the LICENSE file that accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* version 3 along with OpenSCADA. If not, see
|
||||
* <http://opensource.org/licenses/lgpl-3.0.html> for a copy of the LGPLv3 License.
|
||||
*/
|
||||
|
||||
package org.openscada.opc.lib.list;
|
||||
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
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.Constants;
|
||||
import org.openscada.opc.dcom.list.impl.OPCServerList;
|
||||
|
||||
import rpc.core.UUID;
|
||||
|
||||
/**
|
||||
* A wrapper around the {@link OPCServerList} class which makes the handling somewhat easier.
|
||||
* @author Jens Reimann <jens.reimann@th4-systems.com>
|
||||
* @since 0.1.8
|
||||
*
|
||||
*/
|
||||
public class ServerList
|
||||
{
|
||||
private final JISession _session;
|
||||
|
||||
private final OPCServerList _serverList;
|
||||
|
||||
/**
|
||||
* Create a new instance with an already existing session
|
||||
* @param session the DCOM session
|
||||
* @param host the host to query
|
||||
* @throws IllegalArgumentException
|
||||
* @throws UnknownHostException
|
||||
* @throws JIException
|
||||
*/
|
||||
public ServerList ( final JISession session, final String host ) throws IllegalArgumentException, UnknownHostException, JIException
|
||||
{
|
||||
this._session = session;
|
||||
JIComServer comServer = new JIComServer ( JIClsid.valueOf ( Constants.OPCServerList_CLSID ), host, this._session );
|
||||
this._serverList = new OPCServerList ( comServer.createInstance () );
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new instance and a new DCOM session
|
||||
* @param host the host to contact
|
||||
* @param user the user to use for authentication
|
||||
* @param password the password to use for authentication
|
||||
* @throws IllegalArgumentException
|
||||
* @throws UnknownHostException
|
||||
* @throws JIException
|
||||
*/
|
||||
public ServerList ( final String host, final String user, final String password ) throws IllegalArgumentException, UnknownHostException, JIException
|
||||
{
|
||||
this ( host, user, password, null );
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new instance and a new DCOM session
|
||||
* @param host the host to contact
|
||||
* @param user the user to use for authentication
|
||||
* @param password the password to use for authentication
|
||||
* @param domain The domain to use for authentication
|
||||
* @throws IllegalArgumentException
|
||||
* @throws UnknownHostException
|
||||
* @throws JIException
|
||||
*/
|
||||
public ServerList ( final String host, final String user, final String password, final String domain ) throws IllegalArgumentException, UnknownHostException, JIException
|
||||
{
|
||||
this ( JISession.createSession ( domain, user, password ), host );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the details of a opc class
|
||||
* @param clsId the class to request details for
|
||||
* @return The class details
|
||||
* @throws JIException
|
||||
*/
|
||||
public ClassDetails getDetails ( final String clsId ) throws JIException
|
||||
{
|
||||
return this._serverList.getClassDetails ( JIClsid.valueOf ( clsId ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch the class id of a prog id
|
||||
* @param progId The prog id to look up
|
||||
* @return the class id or <code>null</code> if none could be found.
|
||||
* @throws JIException
|
||||
*/
|
||||
public String getClsIdFromProgId ( final String progId ) throws JIException
|
||||
{
|
||||
JIClsid cls = this._serverList.getCLSIDFromProgID ( progId );
|
||||
if ( cls == null )
|
||||
{
|
||||
return null;
|
||||
}
|
||||
return cls.getCLSID ();
|
||||
}
|
||||
|
||||
/**
|
||||
* List all servers that match the requirements
|
||||
* @param implemented All implemented categories
|
||||
* @param required All required categories
|
||||
* @return A collection of <q>class ids</q>
|
||||
* @throws IllegalArgumentException
|
||||
* @throws UnknownHostException
|
||||
* @throws JIException
|
||||
*/
|
||||
public Collection<String> listServers ( final Category[] implemented, final Category[] required ) throws IllegalArgumentException, UnknownHostException, JIException
|
||||
{
|
||||
// convert the type safe categories to plain UUIDs
|
||||
UUID[] u1 = new UUID[implemented.length];
|
||||
UUID[] u2 = new UUID[required.length];
|
||||
|
||||
for ( int i = 0; i < implemented.length; i++ )
|
||||
{
|
||||
u1[i] = new UUID ( implemented[i].toString () );
|
||||
}
|
||||
|
||||
for ( int i = 0; i < required.length; i++ )
|
||||
{
|
||||
u2[i] = new UUID ( required[i].toString () );
|
||||
}
|
||||
|
||||
// get them as UUIDs
|
||||
Collection<UUID> resultU = this._serverList.enumClassesOfCategories ( u1, u2 ).asCollection ();
|
||||
|
||||
// and convert to easier usable strings
|
||||
Collection<String> result = new ArrayList<String> ( resultU.size () );
|
||||
for ( UUID uuid : resultU )
|
||||
{
|
||||
result.add ( uuid.toString () );
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* List all servers that match the requirements and return the class details
|
||||
* @param implemented All implemented categories
|
||||
* @param required All required categories
|
||||
* @return a collection of matching server and their class information
|
||||
* @throws IllegalArgumentException
|
||||
* @throws UnknownHostException
|
||||
* @throws JIException
|
||||
*/
|
||||
public Collection<ClassDetails> listServersWithDetails ( final Category[] implemented, final Category[] required ) throws IllegalArgumentException, UnknownHostException, JIException
|
||||
{
|
||||
Collection<String> resultString = listServers ( implemented, required );
|
||||
|
||||
List<ClassDetails> result = new ArrayList<ClassDetails> ( resultString.size () );
|
||||
|
||||
for ( String clsId : resultString )
|
||||
{
|
||||
result.add ( getDetails ( clsId ) );
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user