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、結論
省略。