1、概念阐述
ScadaCloud是一个分布式、跨平台、跨网络的实时在线平台,让您够方便地使用PC、iPhone、iPad终端在任何时间、任何地点监控您关心的设备当前运行状况。ScadaCloud提供了从端到云的完整的解决方案,向用户提供SAAS(SoftwareAs A Service,软件即服务)。
ScadaCloud把传统C/S架构的信息平台,发展为以Cloud为平台的服务中心,充分共享有效的公共资源。B/S架构在分布式系统中也成为主流架构。ScadaCloud主要以Web和中间件作为基础支撑技术。
ScadaCloud智能技术帮助用户在先进的基础设施和系统集成基础上,采用可持续、可靠、经济的方式便捷管理运营需求。同时,在用户重点基础设施中也处于指挥中心的地位,可以掌控电力、水和热力的供应,以及楼宇、基础设施自动化都等所有重点领域的运营。
本文以将Ajax(Asynchronous JavaScript and XML)模式引入ScadaCloud中,并结合Ajax、SVG(ScableVectorGraphics)和Corba等多项技术,实现了异步交互机制。
2、ScadaCloud的技术与优势
1)、基础技术组成
- WEB:HTML/Ajax/javascript;
- 中间件:Corba;
- 图形:SVG;
- 开发语言:C++/C#/java。
2)、优势
- 所有工作都在WEB浏览器上完成该,没有插件,工作站无需安装软件;
- 丰富精美的基于SVG的可视化界面;
- 跨平台、跨语言;
- 完整的从端到云的解决方案;
- 每个用户都相当于一套功能强大、全面的SCADA平台。
实时监控系统中厂站视图中配置好的图形是一张简要的厂站单线图,后台系统需要这样一张图。因此,绘图工具提供了对矢量图形SVG的支持,可以将厂站视图导出为SVG图形文件,后台系统可以导入该图形直接利用。
3、SVG模块
1)、什么是SVG?
- SVG 指可伸缩矢量图形(Scalable Vector Graphics);
- SVG 用来定义用于网络的基于矢量的图形;
- SVG 使用XML格式定义图形;
- SVG 图像在放大或改变尺寸的情况下其图形质量不会有所损失;
- SVG 是万维网联盟的标准;
- SVG 与诸如DOM和XSL之类的W3C标准是一个整体。
2)、SVG 的历史和优势
在2003年1月,SVG1.1被确立为W3C标准。参与定义SVG的组织有:太阳微系统、Adobe、苹果公司、IBM 以及柯达。与其他图像格式相比,使用SVG的优势在于:
- SVG可被非常多的工具读取和修改(比如记事本);
- SVG与JPEG和GIF图像比起来,尺寸更小,且可压缩性更强;
- SVG是可伸缩的;
- SVG 图像可在任何的分辨率下被高质量地打印;
- SVG可在图像质量不下降的情况下被放大;
- SVG图像中的文本是可选的,同时也是可搜索的(很适合制作地图);
- SVG可以与Java技术一起运行;
- SVG是开放的标准;
- SVG文件是纯粹的XML。
SVG的主要竞争者是Flash。与Flash相比,SVG最大的优势是与其他标准(比如XSL和DOM)相兼容。而Flash则是未开源的私有技术。今天,所有浏览器均支持SVG文件,不过需要安装插件的Internet Explorer 除外。插件是免费的,比如Adobe SVG Viewer。
3)、SVG 实例
下面的例子是一个简单的SVG文件的例子。SVG文件必须使用.svg后缀来保存:
<?xml version="1.0"standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="100%" height="100%"version="1.1"
xmlns="http://www.w3.org/2000/svg">
<circle cx="100" cy="50"r="40" stroke="black"
stroke-width="2" fill="red"/>
</svg>
代码解释:
第一行包含了XML声明。请注意standalone属性!该属性规定此SVG文件是否是“独立的”,或含有对外部文件的引用。standalone="no"意味着SVG文档会引用一个外部文件-在这里是DTD文件。第2和 3行引用了这个外部的SVG-DTD。
该DTD位于“http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd”。该DTD位于W3C,含有所有允许的SVG元素。
SVG代码以<svg>元素开始,包括开启标签<svg>和关闭标签</svg>。这是根元素。width和height属性可设置此SVG文档的宽度和高度。version属性可定义所使用的SVG版本,xmlns属性可定义SVG命名空间。
SVG的<circle>用来创建一个圆。cx和cy属性定义圆中心的x和y 坐标。如果忽略这两个属性,那么圆点会被设置为(0, 0)。r属性定义圆的半径。stroke和 stroke-width 属性控制如何显示形状的轮廓。我们把圆的轮廓设置为2px宽,黑边框。fill属性设置形状内的颜色。我们把填充颜色设置为红色。关闭标签的作用是关闭 SVG 元素和文档本身。
注释:所有的开启标签必须有关闭标签!
4)、HTML 页面中的 SVG
<embed>标签被所有主流的浏览器支持,并允许使用脚本。当在HTML页面中嵌入SVG时使用<embed>标签是Adobe SVG Viewer推荐的方法!然而,如果需要创建合法的 XHTML,就不能使用<embed>。任何HTML规范中都没有<embed>标签。
语法:
<embed src="rect.svg"width="300" height="100" type="image/svg+xml"
pluginspage="http://www.adobe.com/svg/viewer/install/"/>
4、图符库实现
图4.1 有轨电车监控图
1)、SVG图符库原理
如图4.1信号系统图形所示,动态图形主要包括信号机、轨道和道岔等设备。如我们可以把信号机的状态枚举,生成图符中的多状态图元。
2)、信号机图符
图4.2 信号机状态0
<symbolid="SIGNAL0">
<circle fill="#999999"r="9.73177" id="svg_0" cx="10" cy="10"stroke="#000000"/>
<circle fill="#999999"r="9.73047" id="svg_1" cx="10" cy="30"stroke="#000000"/>
<circle fill="#999999"r="9.73047" id="svg_2" cx="10" cy="50"stroke="#000000"/>
<rect x="4.00002"stroke-linecap="null" y="26.66667"transform="rotate(45, 10, 29.668)" fill="#b2b2b2"
width="12"stroke-linejoin="null" stroke-dasharray="null"height="6" id="svg_3" stroke="#000000"/>
<rect x="4.00132"stroke-linecap="null" y="47.0013"transform="rotate(90, 10, 50)" fill="#b2b2b2"width="12"
stroke-linejoin="null" stroke-dasharray="null"height="6" id="svg_4" stroke="#000000"/>
</symbol>
图4.3 信号机状态1
<symbolid="SIGNAL1">
<circle fill="#ff0000"r="9.73177" id="svg_5" cx="10" cy="10"stroke="#000000"/>
<circle fill="#999999"r="9.73047" id="svg_6" cx="10" cy="30"stroke="#000000"/>
<circle fill="#999999"r="9.73047" id="svg_7" cx="10" cy="50"stroke="#000000"/>
<rect x="4.00002"stroke-linecap="null" y="26.66667"transform="rotate(45, 10, 29.668)" fill="#b2b2b2"
width="12"stroke-linejoin="null" stroke-dasharray="null"height="6" id="svg_8" stroke="#000000"/>
<rect x="4.00132"stroke-linecap="null" y="47.0013"transform="rotate(90, 10, 50)" fill="#b2b2b2"width="12"
stroke-linejoin="null" stroke-dasharray="null"height="6" id="svg_9" stroke="#000000"/>
</symbol>
图4.4 信号机状态2
<symbolid="SIGNAL2">
<circle fill="#999999"r="9.73177" id="svg_10" cx="10" cy="10"stroke="#000000"/>
<circle fill="#ffff00"r="9.73047" id="svg_11" cx="10" cy="30"stroke="#000000"/>
<circle fill="#999999"r="9.73047" id="svg_12" cx="10" cy="50"stroke="#000000"/>
<rect x="4.00002"stroke-linecap="null" y="26.66667"transform="rotate(45, 10, 29.668)" fill="#ffffff"
width="12"stroke-linejoin="null" stroke-dasharray="null"height="6" id="svg_13" stroke="#000000"/>
<rect x="4.00132"stroke-linecap="null" y="47.0013"transform="rotate(90, 10, 50)" fill="#b2b2b2"width="12"
stroke-linejoin="null" stroke-dasharray="null"height="6" id="svg_14" stroke="#000000"/>
</symbol>
图4.5 信号机状态3
<symbolid="SIGNAL3">
<circle fill="#999999"r="9.73177" id="svg_15" cx="10" cy="10"stroke="#000000"/>
<circle fill="#999999"r="9.73047" id="svg_16" cx="10" cy="30"stroke="#000000"/>
<circle fill="#00ff00"r="9.73047" id="svg_17" cx="10" cy="50"stroke="#000000"/>
<rect x="4.00002"stroke-linecap="null" y="26.66667"transform="rotate(45, 10, 29.668)" fill="#b2b2b2"
width="12"stroke-linejoin="null" stroke-dasharray="null"height="6" id="svg_18" stroke="#000000"/>
<rect x="4.00132"stroke-linecap="null" y="47.0013"transform="rotate(90, 10, 50)" fill="#ffffff"width="12"
stroke-linejoin="null" stroke-dasharray="null"height="6" id="svg_19" stroke="#000000"/>
</symbol>
3)、图符引用说明
<usex="33.00015" y="174.33333" symbol_name="#SIGNAL"width="80" xlink:href="#SIGNAL0"
symbol_maxindex="3" id="ZXL_DT08_DN001_V01"height="100"/>
本案例中增加两个私有属性:symbol_name和symbol_maxindex,symbol_name表示图元属于何种图符(所有名称要唯一定义),symbol_maxindex表示当前图符的最大状态索引值(从0开始)。id号也就是图符对应的实时数据库“点”值,后面章节会详细描述怎么操作图符,产生不同动态切换的效果。
4、中间件实现
这一节主要讲述java与c++两种语言实现过程,本文只简述通用方法描述不同服务器之间的数据流处理过程,更复杂的业务处理,请您根据实际用户要求设计。
Web服务器作为客户端与实时服务器交互数据,过程如下:
- 初始化: 第一连接成功后,Web服务从实时服务器获取全数据;
- 接收通知:当实时服务器有变化数据或告警,通知Web服务器;
- 汲取数据:Web服务器根据通知的消息,从实时服务器获取最新的数据;
- 心跳: 为防止网络中断等情况影响,使用alive或hello函数进行心跳探测。
实时服务器作为服务端与Web服务器交互数据,过程如下:
- 监听: 实时服务器监听管理所有连接的用户;
- 数据接口:为Web服务器提供必要的接口;
- 数据处理:与实时库交换,处理变化的数据,并及时各个连接的用户;
- 心跳: 为防止网络中断等情况影响,使用alive或hello函数进行心跳探测。
1)、COBRA原理
省略。
2)、接口文件定义(CloudDaqService.idl)
// **********************************************************************
//
// Copyright (c) 2014
// XXXXX有限公司
// 2014.05.07
// liuxuezong, PSD, Shanghai, China
// All Rights Reserved
//
//**********************************************************************
#ifndef _CLOUDDAQSERVICE_IDL_
#define _CLOUDDAQSERVICE_IDL_
//
// version 1.0.0
//
module CloudDaqService
{
struct point_stream
{
stringpointcode;
octettype;
floatvalue;
};
typedefsequence <point_stream> pointStreamSeq;
struct event_stream
{
octet type;
sequence<octet>value;
};
// Thisexception is raised every time a failure or error is
//detected in a treatment.
exception GeneralException
{
stringerror_msg;
};
interface EventHandler
{
void onNotify(in event_stream event);
//@interface: EventHandler
//@method : alive
//@purpose : test is the EventHandler isagain instantiate and
// so if daq communication part isrunning
// if the call of the method pass,EventHandler is alive;
// else CORBA send an exceptionStateClosed.
void alive();
};
interface RegAgent
{
void hello() raises(GeneralException);
boolean write(in point_stream data) raises(GeneralException);
boolean bulkWrite(in pointStreamSeq datum) raises(GeneralException);
pointStreamSeq getPointsValue() raises(GeneralException);
void setEventHandler(in EventHandler handler) raises(GeneralException);
};
interface RegManager
{
RegAgent createInterface(in string user) raises(GeneralException);
void deleteInterface(in string user) raises(GeneralException);
};
};
#endif
//
// EOF clouddaqservice.idl
//
3)、Web服务器作为Corba客户端
3.1)MeterRemote .java(Dwr定义的接口,后面将描述)
package com.test.ajax;
import org.directwebremoting.ScriptBuffer;
import org.directwebremoting.ScriptSession;
importorg.directwebremoting.ServerContextFactory;
import org.directwebremoting.Browser;
import org.directwebremoting.WebContextFactory;
import org.directwebremoting.ui.dwr.Util;
import java.util.Collection;
import java.util.List;
importjava.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
public class MeterRemote implements Runnable
{
static CloudService daqnsrv = null;
protected transient boolean active = false;
int nToggleNum = 0;
static int nCount = 0;
public MeterRemote()
{
ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(1);
executor.scheduleAtFixedRate(this,1, 1, TimeUnit.SECONDS);
}
public void run()
{
if (active)
{
pageProc();
}
}
public synchronized void toggle()
{
nToggleNum++;
active= !active;
System.out.println("toggleclicked!" + nToggleNum);
System.out.println("active:"+ active);
if (active)
{
pageProc();
}
}
public void pageProc()
{
Stringpage = ServerContextFactory.get().getContextPath() + "/index.jsp";
Browser.withPage(page,new Runnable()
{
publicvoid run()
{
if (daqnsrv != null && daqnsrv.isRunning())
{
ScriptBufferscript = new ScriptBuffer();
intValue = nCount;
StringstrPointCode = "ZXL_DT08_DN001_V01";
List<pointdata>points = daqnsrv.peekDaqService();
if(!points.isEmpty())
{
for(pointdata data : points)
{
strPointCode= data.getPointCode();
Value = (int)data.getValue();
script.appendCall("setObjectValue",strPointCode, Value);
}
Collection<ScriptSession>mySessions = Browser.getTargetSessions();
for(ScriptSession scriptSession:mySessions)
{
scriptSession.addScript(script);
}
}
nCount++;
}
}
});
if (daqnsrv == null)
{
daqnsrv= new CloudService();
daqnsrv.startCorba();
}
}
}
3.2)、CloudService.java
package com.test.ajax;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Properties;
import java.io.UnsupportedEncodingException;
import org.omg.CosNaming.*;
import org.omg.CORBA.*;
import org.omg.PortableServer.IdAssignmentPolicyValue;
import org.omg.PortableServer.ImplicitActivationPolicyValue;
import org.omg.PortableServer.LifespanPolicyValue;
import org.omg.PortableServer.POA;
import org.omg.PortableServer.POAHelper;
import CloudDaqService.EventHandler;
import CloudDaqService.EventHandlerHelper;
import CloudDaqService.RegAgent;
import CloudDaqService.RegManager;
import CloudDaqService.RegManagerHelper;
import CloudDaqService.point_stream;
public class CloudService
{
privatestatic String lpArgs[];
privatestatic RegAgent regAgent_;
privatestatic RegManager regManager_;
privatestatic DaqEventHandler eventhandler;
privatestatic boolean bStartFlag = true;
privatestatic boolean bExceptionFlag = true;
classCorbaProc implements Runnable
{
public void run()
{
System.out.println("CloudService的CorbaProc线程runstart!");
while (bStartFlag)
{
try
{
org.omg.CORBA.Object managerObj;
// 创建并初始化ORB
//String nameservice ="corbaloc::localhost:10003/NameService";
// 生成一个ORB,并初始化,这个和Server端一样
// Properties props = newProperties();
//props.put("org.omg.CORBA.ORBInitialPort", "10003");
//props.put("org.omg.CORBA.ORBInitialHost","10.35.95.100");
// ORB orb = ORB.init(lpArgs,props);
ORB orb = ORB.init(lpArgs, null);
// 得到一个NameComponent类型的对象
// get the root naming context
org.omg.CORBA.Object objRef = orb.resolve_initial_references("NameService");
// Use NamingContextExt instead ofNamingContext,
// part of the Interoperablenaming Service.
// NamingContextExt ncRef =NamingContextExtHelper.narrow(objRef);
NamingContextExt ncRef =NamingContextExtHelper.narrow(orb
.string_to_object("corbaloc::localhost:10003/NameService"));
// nc的id域为FirstTimeSevice,kind域为空字符串
NameComponent name = newNameComponent("CloudDaqService", "");
NameComponent path[] = { name };
// 从命名服务上下文中获得特定的命名服务对象
managerObj = ncRef.resolve(path);
// Instantiate Servant and createreference
POA rootPOA =POAHelper.narrow(orb.resolve_initial_references("RootPOA"));
DaqEventHandler handler = newDaqEventHandler();
rootPOA.activate_object(handler);
EventHandler ref =EventHandlerHelper.narrow(
rootPOA.servant_to_reference(handler));
// Narrow the previous object toobtain the correct type
regManager_ =RegManagerHelper.narrow(managerObj);
regAgent_ =regManager_.createInterface("admin");
regAgent_.setEventHandler(ref);
rootPOA.the_POAManager().activate();
bExceptionFlag= false;
orb.run();
}
catch (Exception e)
{
System.out.println("ERROR :" + e);
bExceptionFlag = true;
}
}
System.out.println("CloudService的CorbaProc线程runstop!");
}
}
public CloudService()
{
}
public boolean isRunning()
{
return (bExceptionFlag == false);
}
public void startCorba()
{
CorbaProc dataid = new CorbaProc();
Thread threadDataProc = new Thread(dataid);
threadDataProc.start();
}
public List<pointdata> peekDaqService()
{
try
{
if (regAgent_ == null)
{
returnnull;
}
List<pointdata>list = new ArrayList<pointdata>();
point_stream[]streamSeq = regAgent_.getPointsValue();
inti, nCount = streamSeq.length;
for (i = 0; i < nCount; i++)
{
pointdatapt = new pointdata();
pt.setPointCode(streamSeq[i].pointcode);
pt.setValue(streamSeq[i].value);
list.add(pt);
}
returnlist;
}
catch (Exception e)
{
e.printStackTrace();
bExceptionFlag= true;
}
returnnull;
}
}
3.3)、DaqEventHandler.java
package com.test.ajax;
import CloudDaqService.EventHandlerPOA;
import CloudDaqService.event_stream;
public class DaqEventHandler extendsEventHandlerPOA
{
private static final long serialVersionUID = 1L;
public DaqEventHandler()
{
}
public void alive() {
//TODO Auto-generated method stub
intn = 0;
n= 1;
}
public void onNotify(event_stream event) {
//TODO Auto-generated method stub
}
}
3.4)、pointdata.java
package com.test.ajax;
import java.io.Serializable;
@SuppressWarnings("serial")
public class pointdata implements Serializable{
private String pointcode;
private int type;
private float value;
public float getValue() {
returnvalue;
}
public void setValue(float value) {
this.value= value;
}
public String getPointCode() {
returnpointcode;
}
public void setPointCode(String pointcode) {
this.pointcode= pointcode;
}
public int getType() {
returntype;
}
public void setType(int type) {
this.type= type;
}
}
4)、实时服务器作为Corba服务端
3.1)RegAgent_impl
RegAgent _impl.h定义
#ifndef _REGAGENT_IMPL_H_
#define _REGAGENT_IMPL_H_
#include <OB/CORBA.h>
#if defined(_MSC_VER)
#pragma warning (disable : 4786)
#endif
#include <string.h>
#include <map>
#include <list>
#ifdef HAVE_STDLIB_H
# include<stdlib.h>
#endif
#if defined(HAVE_STD_IOSTREAM) ||defined(HAVE_STD_STL)
using namespace std;
#endif
#include "clouddaqservice_skel.h"
using namespace CloudDaqService;
typedef map<int, int> StationStatusMap;
class RegAgent_impl : virtual publicPOA_CloudDaqService::RegAgent,
publicPortableServer::RefCountServantBase
{
PortableServer::POA_varpoa_;
public:
RegAgent_impl(PortableServer::POA_ptrpoa);
virtual ~RegAgent_impl();
virtual PortableServer::POA_ptr
_default_POA()
{
return PortableServer::POA::_duplicate(poa_);
}
virtual void hello()
throw(GeneralException, CORBA::SystemException);
virtualCORBA::Boolean write(const point_stream& data)
throw(GeneralException, CORBA::SystemException);
virtualCORBA::Boolean bulkWrite(const pointStreamSeq& datum)
throw(GeneralException, CORBA::SystemException);
virtual pointStreamSeq* getPointsValue()
throw(GeneralException, CORBA::SystemException);
virtual void setEventHandler(EventHandler_ptr handler)
throw(GeneralException, CORBA::SystemException);
public:
void onNotify(const event_stream &event);
void alive();
void destroy(void);
bool checkException();
private:
JTCMutex mutex_;
EventHandler_ptr Controller_;
bool bException_;
};
#endif // _REGAGENT_IMPL_H_
RegAgent _impl.cpp实现
#include "regagent_impl.h"
using namespace std;
RegAgent_impl::RegAgent_impl(PortableServer::POA_ptrpoa)
:poa_(PortableServer::POA::_duplicate(poa))
{
bException_= false;
}
RegAgent_impl::~RegAgent_impl()
{
}
void RegAgent_impl::hello()
throw(GeneralException, CORBA::SystemException)
{
}
CORBA::Boolean RegAgent_impl::write(constpoint_stream &data)
throw(GeneralException, CORBA::SystemException)
{
return 0;
}
CORBA::Boolean RegAgent_impl::bulkWrite(constpointStreamSeq &datum)
throw(GeneralException, CORBA::SystemException)
{
CORBA::ULong nCount = datum.length();
for (CORBA::ULong i = 0; i < nCount; i++)
{
point_stream data = datum[i];
write(data);
}
return 0;
}
pointStreamSeq* RegAgent_impl::getPointsValue()
throw(GeneralException, CORBA::SystemException)
{
static intnCount = 0;
pointStreamSeq_var lstRecord = new pointStreamSeq;
long nSize= 1;
lstRecord->length(nSize);
point_stream data;
data.type =1;
data.pointcode = CORBA::string_dup("ZXL_DT08_DN001_V01");
data.value = nCount++ % 5;
lstRecord[0] = data;
returnlstRecord._retn();
}
void RegAgent_impl::setEventHandler(EventHandler_ptrhandler)
throw(GeneralException, CORBA::SystemException)
{
Controller_ = EventHandler::_duplicate(handler);
}
void RegAgent_impl::onNotify(const event_stream&event)
{
try
{
Controller_->onNotify(event);
}
catch (const CORBA::Exception &ex)
{
cerr<< ex << endl;
bException_ = true;
}
}
void RegAgent_impl::alive()
{
try
{
Controller_->alive();
}
catch (const CORBA::Exception &ex)
{
cerr<< ex << endl;
bException_ = true;
}
}
void RegAgent_impl::destroy()
{
// Get thePOA used when activating the Content_Iterator object.
PortableServer::POA_var poa = this->_default_POA();
// Get theobject ID associated with this servant.
PortableServer::ObjectId_varoid = poa->servant_to_id(this);
// Nowdeactivate the iterator object.
poa->deactivate_object(oid.in());
// Decreasethe reference count on our selves.
_remove_ref();
}
bool RegAgent_impl::checkException()
{
returnbException_;
}
3.2)RegManager_impl
RegManager_impl.h定义
#ifndef _REGMANAGER_IMPL_H_
#define _REGMANAGER_IMPL_H_
#include "regagent_impl.h"
typedef map<std::string, RegAgent_impl *>RegAgentMap;
class Worker;
class RegManager_impl : virtual public POA_CloudDaqService::RegManager,
publicPortableServer::RefCountServantBase
{
PortableServer::POA_varpoa_;
public:
RegManager_impl(PortableServer::POA_ptrpoa);
Virtual ~RegManager_impl();
virtual PortableServer::POA_ptr
_default_POA()
{
returnPortableServer::POA::_duplicate(poa_);
}
RegAgent_ptr createInterface(const char* user)
throw(GeneralException, CORBA::SystemException);
void deleteInterface(const char* user)
throw(GeneralException, CORBA::SystemException);
public:
void OnNotify(const event_stream &event);
void alive();
bool checkAgent();
const int getAgentSize();
private:
JTCHandleT<Worker> workThread_;
RegAgentMap RegagentMap_;
JTCMutex mutex_;
};
#endif //
#include "regmanager_impl.h"
class Worker : public JTCThread
{
//
//Has this thread been stopped?
//
boolstop_;
public:
Worker(RegManager_impl *regManager)
:regManager_(regManager), stop_(false)
{
}
public:
voidrun(void)
{
while (!stop_)
{
if (regManager_->getAgentSize())
{
if (1)
{
event_stream event;
event.type = 1;
event.value.length(32);
unsigned char *pData =event.value.get_buffer();
for (int i = 0; i < 32;i++)
{
pData[i] = i;
}
memcpy(event.value.get_buffer(), pData, 32);
//regManager_->OnNotify(event);
}
//else
{
regManager_->alive();
}
regManager_->checkAgent();
}
sleep(1000);
}
}
voidstop()
{
stop_ = true;
}
private:
RegManager_impl *regManager_;
};
RegManager_impl.cpp实现
RegManager_impl::RegManager_impl(PortableServer::POA_ptrpoa)
:poa_(PortableServer::POA::_duplicate(poa))
{
workThread_ = new Worker(this);
workThread_->start();
}
RegManager_impl::~RegManager_impl()
{
//
// Wait for all other threads to be finished
//
while (workThread_->isAlive())
{
try
{
workThread_->stop();
workThread_->join();
}
catch (const JTCInterruptedException &)
{
}
}
}
RegAgent_ptr RegManager_impl::createInterface(constchar *user)
throw(GeneralException, CORBA::SystemException)
{
/*
*Create a new RegAgent (which is never deleted)
*/
assert(user != NULL && strlen(user) > 0);
JTCSynchronized guard(mutex_);
RegAgentMap::iterator i;
if ((i = RegagentMap_.find(user)) != RegagentMap_.end())
{
const std::string key = (*i).first;
RegAgent_impl *pAgent = (*i).second;
RegAgent_ptr aref = pAgent->_this();
return aref;
}
RegAgent_impl *AgentIf = new RegAgent_impl(poa_);
/*
*Obtain a reference using _this. This implicitely activates the
*RegAgent servant (the RootPOA, which is the object's _default_POA,
* hasthe IMPLICIT_ACTIVATION policy)
*/
RegAgent_ptr aref = AgentIf->_this();
assert (!CORBA::is_nil (aref));
RegagentMap_[user] = AgentIf;
/*
*Return the reference
*/
return aref;
}
void RegManager_impl::deleteInterface(constchar *user)
throw(GeneralException, CORBA::SystemException)
{
assert(user != NULL);
JTCSynchronized guard(mutex_);
RegAgentMap::iterator i;
for (i = RegagentMap_.begin(); i != RegagentMap_.end(); i++)
{
const std::string key = (*i).first;
const char *val = (const char *)key.c_str();
RegAgent_impl *pAgent = (*i).second;
if (strcmp(val, user) == 0)
{
pAgent->destroy();
RegagentMap_.erase(i);
return;
}
}
}
void RegManager_impl::OnNotify(constevent_stream &event)
{
JTCSynchronized guard(mutex_);
RegAgentMap::iterator i;
if (getAgentSize() <= 0)
{
return;
}
for (i = RegagentMap_.begin(); i != RegagentMap_.end(); i++)
{
const std::string key = (*i).first;
RegAgent_impl *pAgent = (*i).second;
if (pAgent && !pAgent->checkException())
{
pAgent->onNotify(event);
}
}
}
void RegManager_impl::alive()
{
JTCSynchronized guard(mutex_);
RegAgentMap::iterator i;
if (getAgentSize() <= 0)
{
return;
}
for (i = RegagentMap_.begin(); i != RegagentMap_.end(); i++)
{
const std::string key = (*i).first;
RegAgent_impl *pAgent = (*i).second;
if (pAgent && !pAgent->checkException())
{
pAgent->alive();
}
}
}
bool RegManager_impl::checkAgent()
{
JTCSynchronized guard(mutex_);
boolbRet = false;
if (getAgentSize() <= 0)
{
return bRet;
}
RegAgentMap::iterator j = RegagentMap_.begin();
RegAgentMap::iterator last = RegagentMap_.end();
while (j != last)
{
const std::string key = (*j).first;
RegAgent_impl *pAgent = (*j).second;
if (pAgent && pAgent->checkException())
{
pAgent->destroy();
RegagentMap_.erase(j);
bRet = true;
break;
}
++j;
}
return bRet;
}
const int RegManager_impl::getAgentSize()
{
return RegagentMap_.size();
}
3.3)main.cpp
#include "stdafx.h"
#include <OB/CORBA.h>
#include <OB/CosNaming.h>
#include <OB/Properties.h>
#include "regmanager_impl.h"
#ifdef WIN32
#pragma comment(linker,"/subsystem:windows /entry:mainCRTStartup")
#endif
using namespace std;
int Initialize()
{
return 0;
}
void unInitialize()
{
}
//
// Signal handler for singal_com shutdown
//
#ifdef WIN32
BOOL handler(DWORD fdwCtrlType)
{
switch (fdwCtrlType)
{
caseCTRL_C_EVENT:
break;
caseCTRL_CLOSE_EVENT:
break;
caseCTRL_BREAK_EVENT:
break;
caseCTRL_LOGOFF_EVENT:
break;
caseCTRL_SHUTDOWN_EVENT:
break;
}
//
//Terminate singal_com event loop
//
try
{
unInitialize();
}
catch(...)
{
// Can't throw here...
}
return TRUE;
}
#else
extern "C" void handler(int)
{
//
//Ignore further signals
//
struct sigaction ignore;
ignore.sa_handler = SIG_IGN;
sigemptyset(&ignore.sa_mask);
ignore.sa_flags = 0;
if (sigaction(SIGINT, &ignore, (structsigaction *)0) == -1)
abort();
if(sigaction(SIGTERM, &ignore, (struct sigaction *)0) == -1)
abort();
if(sigaction(SIGHUP, &ignore, (struct sigaction *)0) == -1)
abort();
//
// Terminate signal_comc event loop
//
try
{
unInitialize();
}
catch(...)
{
// Can't throw here...
}
}
#endif
//
// Install signal handler for signal_comshutdown
//
void install_signal_handler()
{
//
// Install signal handler for cleanup
//
#ifdef WIN32
BOOL rc = SetConsoleCtrlHandler((PHANDLER_ROUTINE)handler, TRUE);
if (!rc)
{
abort();
}
#else
struct sigaction sa; //New signal state
sa.sa_handler = handler; //Set handler function
sigfillset(&sa.sa_mask); // Mask all other signals while handler runs
sa.sa_flags = 0 | SA_RESTART; // Restart interrupted system calls
if (sigaction(SIGINT, &sa, (struct sigaction *)0) == -1)
abort();
if (sigaction(SIGHUP, &sa, (struct sigaction *)0) == -1)
abort();
if (sigaction(SIGTERM, &sa, (struct sigaction *)0) == -1)
abort();
#endif
}
int main(int argc, char *argv[])
{
#ifdef WIN32
HANDLE hMutex = ::CreateMutex(NULL, FALSE, "CloudDaqService");
if (::GetLastError() == ERROR_ALREADY_EXISTS)
{
return 0;
}
#endif
//
//Install signal handler for signal_com shutdown
//
install_signal_handler();
Initialize();
CORBA::ORB_var orb;
try
{
// ORB initialization
orb = CORBA::ORB_init(argc, argv);
/*
*Obtain a reference to the RootPOA and its Manager
*/
CORBA::Object_var poaobj = orb->resolve_initial_references("RootPOA");
PortableServer::POA_var root = PortableServer::POA::_narrow(poaobj);
PortableServer::POAManager_var manager = root->the_POAManager();
/*
*Create a RegManager
*/
RegManager_impl *regmgr = new RegManager_impl(root);
/*
*Activate the RegManager
*/
PortableServer::ObjectId_var oid = root->activate_object(regmgr);
CORBA::Object_var ref = root->id_to_reference(oid.in());
/*
*Acquire a reference to the Naming Service
*/
CORBA::Object_var nsobj =
orb->resolve_initial_references("NameService");
CosNaming::NamingContext_var nc =
CosNaming::NamingContext::_narrow(nsobj);
if (CORBA::is_nil(nc))
{
cerr << "oops, I cannot access the Naming Service!"<< endl;
exit (1);
}
/*
*Construct Naming Service name for our SignalCommucation
*/
CosNaming::Name name;
name.length(1);
name[0].id = CORBA::string_dup("CloudDaqService");
name[0].kind = CORBA::string_dup("");
/*
*Store a reference to our Bank in the Naming Service. We use 'rebind'
*here instead of 'bind', because rebind does not complain if the desired
*name "CloudDaqService" is already registered, but silently overwritesit (the
*existing reference is probably from an old incarnation of this server).
*/
cout << "Binding CloudDaqService in the Naming Service ..." << flush;
nc->rebind(name, ref);
cout << "done." << endl;
//regmgr->_remove_ref();
/*
*Activate the POA and start serving requests
*/
printf("Running.\n");
manager->activate();
orb->run();
/*
*Shutdown(never reached)
*/
CORBA::release(manager);
CORBA::release(root);
}
catch (const CORBA::Exception &ex)
{
cerr << ex << endl;
}
if (!CORBA::is_nil(orb))
{
try
{
orb->destroy();
}
catch (const CORBA::Exception &ex)
{
cerr << ex << endl;
}
}
unInitialize();
return 0;
}
5、Ajax实现
1)AJAX概念
AJAX即“Asynchronous JavaScript and XML”(异步的JavaScript与XML技术),指的是一套综合了多项技术的浏览器端网页开发技术。Ajax的概念由Jesse James Garrett所提出。
传统的Web应用允许用户端填写表单(form),当提交表单时就向Web服务器发送一个请求。服务器接收并处理传来的表单,然后送回一个新的网页,但这个做法浪费了许多带宽,因为在前后两个页面中的大部分HTML码往往是相同的。由于每次应用的沟通都需要向服务器发送请求,应用的回应时间依赖于服务器的回应时间。这导致了用户界面的回应比本机应用慢得多。
与此不同,AJAX应用可以仅向服务器发送并取回必须的数据,并在客户端采用JavaScript处理来自服务器的回应。因为在服务器和浏览器之间交换的数据大量减少(大约只有原来的5%)[来源请求],服务器回应更快了。同时,很多的处理工作可以在发出请求的客户端机器上完成,因此Web服务器的负荷也减少了。
2)Dwr与SVG动态数据
DWR(DirectWeb Remoting)是一个WEB远程调用框架。利用这个框架可以让AJAX开发变得很简单。客户端利用JavaScript直接调用服务端的Java方法,并返回值给JavaScript函数,就好像直接本地客户端调用一样。
2.1)index.jsp
<%@ pagelanguage="java" contentType="text/html; charset=utf-8"
pageEncoding="utf-8"%>
<!DOCTYPEHTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<%
String path = request.getContextPath();
%>
<metahttp-equiv="Content-Type" content="text/html;charset=utf-8">
<scripttype='text/javascript' src='dwr/engine.js'></script>
<scripttype='text/javascript' src='dwr/util.js'></script>
<scripttype='text/javascript' src='dwr/interface/MeterRemote.js'></script>
<scriptlanguage="javascript">
functionInit()
{
dwr.engine.setActiveReverseAjax(true);
}
functionsetObjectValue(pointcode, value)
{
var svgDocument = window.tramway.getSVGDocument();
var Shape =svgDocument.getElementById(pointcode);
var symbolname = Shape.getAttribute("symbol_name");
var maxindex =parseInt(Shape.getAttribute("symbol_maxindex"));
value = value % (maxindex + 1);
var urlSymbol = symbolname +value.toString();
Shape.setAttribute("xlink:href",urlSymbol);
}
</script>
</head>
<bodyonLoad="Init()" >
<buttonοnclick="MeterRemote.toggle();">启动/button>
<embedid="tramway" src="symbols.svg" width="1366"height="600" type="image/svg+xml" >
</body>
</html>
SVG文件为symboles.svg,该文件放在“D:\MyEclipse 8.6\testAjax\WebRoot”目录下。MeterRemote为java的类,该对象会主动调用脚本函数“setObjectValue”。
SVG多状态图符根据传递的参数pointcode,利用svg的getAttribute函数获取当前图元对象(注意对象为null处理),再使用setAttribute函数修改xlink:herf的对象引用,从而产生图形显示的动态效果。
2.2)web.xml
<?xml version="1.0"encoding="UTF-8"?>
<web-appversion="3.0"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
<display-name></display-name>
<servlet>
<servlet-name>dwr-invoker</servlet-name>
<servlet-class>org.directwebremoting.servlet.DwrServlet</servlet-class>
<init-param>
<param-name>debug</param-name>
<param-value>true</param-value>
</init-param>
<init-param>
<description>是否激活反向Ajax</description>
<param-name>activeReverseAjaxEnabled</param-name>
<param-value>true</param-value>
</init-param>
<init-param>
<description>在WEB启动时是否创建范围为application的creator</description>
<param-name>initApplicationScopeCreatorsAtStartup</param-name>
<param-value>true</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dwr-invoker</servlet-name>
<url-pattern>/dwr/*</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
</web-app>
2.3)dwr.xml
<?xml version="1.0"encoding="UTF-8"?>
<!DOCTYPE dwr PUBLIC"-//GetAhead Limited//DTD Direct Web Remoting 3.0//EN" "http://getahead.org/dwr/dwr30.dtd">
<dwr>
<allow>
<create creator="new"javascript="MeterRemote" scope="application">
<param name="class"value="com.test.ajax.MeterRemote"></param>
</create>
</allow>
</dwr>
图5.1 “com.test.ajax.MeterRemote”目录
<create creator="new"javascript="MeterRemote" scope="application">
MeterRemote即3.1节的类MeterRemote.java。
<param name="class"value="com.test.ajax.MeterRemote"></param>
com.test.ajax.MeterRemote即Value目录与图5.1源文件MeterRemote.java目录一致。
6、ScadaCloud结构图
省略。
7、结论
省略。