前言:
一般,廢話都寫在前面,最近由於加班比較多,對於技術延伸的路上有點滯待,希望大家多多包含。好東西一定要留一份,也要和大家分享,這個Drools腳本,有其獨特的地方——相對於其他腳本,對於java項目來說,簡潔且兼容性比較好。有興趣的話可以研究一下,話不多說,轉!
由於不知道原作者,在這裏謝謝紅領巾~
2.2.3 Drools Expert
2.2.3.1 非對稱Rete算法實現
不再需要影子代理。影子代理保護引擎免受有關實事的信息變化的影響,如果發生在引擎控件的外部,它可能不會被修改或撤消。
2.2.3.2 包構建器現在可以構建多個命名空間
你不再需要對一個包命名空間構建一個PackageBuilder 。只要保持爲所有命名空間增加你的DRLs,並且getPackages()爲每個使用的命名空間返加一個包數組。
例子 2.26 獲得多個包
Package[] packages = pkgBuilder.getPackages();
2.2.3.3 規則庫連接包構建器
現在可以連接一個 RuleBase到一個 PackageBuilder,這意味着規則被構建,並且同時被添加到規則庫。PackageBuilder使用現行的RuleBase的Package實例作爲它的資源,取消了發生在現有方法中的Package創造和融合。
例子 2.27 連接規則庫(RuleBase)到包構建器(PackageBuilder)
RuleBase ruleBase = RuleBaseFactory.newRuleBase();
PackageBuilder pkgBuilder = new PackageBuilder( ruleBase, null );
2.2.3.4 有狀態會話的二進制編碼
有狀態會話現在可以保存,並可在以後的日期中恢復。預加載數據會話現在可以被創建。對用戶對象的持久化可使用可插式策略,例如,hibernate或特徵(identity)映射。
2.2.3.5 類型聲明
Drools現在支持一種新的基礎結構,稱爲類型聲明。這個結構達到兩個目的:能夠聲明實事元數據,以及能夠爲規則引擎動態地產生局部的新的事實類型。Guvnor模擬工具在底層使用了它。下面是該結構的一個例子:
例子 2.28 聲明StockTick
declare StockTick
@role( event )
@timestamp( timestampAttr )
companySymbol : String
stockPrice : double
timestampAttr : long
end
2.2.3.6 聲明實事元數據
要聲明和關聯事實的元數據,只需要對你想聲明的每個元數據ID使用@符號。例子:
例子 2.29 聲明元數據
declare StockTick
@role( event )
end
2.2.3.7 觸發Bean產生
要激活動態bean產生,僅爲你的類型聲明添加字段和類型。
例子 2.30 聲明Person
declare Person
name : String
age : int
end
2.2.3.8 DSL的改進
一系列DSL的改進被實現,包括一個完善的新解析器,並且能夠爲匹配的變量聲明匹配的掩碼(mask)。例如,它可限定一個電話號碼字段爲2位數的國家代碼+ 3位區號+ 8位數字電話號碼,所有連接以“ - ”(破折號)連接,通過象這樣聲明DSL映射:電話號碼爲{number:/d{2}-/d{3}-/d{8}},所有有效的Java正則表達式可以用於變量的掩碼中。
2.2.3.9 fireUntilHalt()
Drools現在支持fireUntilHalt()功能,它以一種被動模式啓動引擎,在那兒規則會被連續引發,直到調用了halt()。這尤其對CEP(complex event processing)場景有用,CEP場景需要俗稱的“活動查詢”。
2.2.3.10 規則庫分區和多線程傳播
Drools ReteOO算法現在支持一個選項,用於以多線程模式啓動規則庫,在那兒Drools ReteOO網絡被劃分爲多個部分,然後規則被多個線程併發計算。對通常有幾個獨立規則併發運行的CEP,它也有一個要求,接近實時性能/吞吐量的要求,並且一個計算不能干擾其他的計算。
2.2.3.11 XSD模式支持
Drools現在支持XSD模式。記住雖然XSD模式以用於Drools類加載器的本地POJO類生成。在包構建器中存在有一個幫助類用於模式的產生。一旦數據模式被生成,你通常使用JAXB數據加載器插入數據。
2.2.3.12 數據加載器
Drools現在支持兩種數據加載器,Smooks和JAXB。Smooks是一個用於ETL的開源數據轉換工具,JAXB是一個標準的Sun數據映射工具。單元測試顯示Smooks和JAXB均可在這裏找到。
2.2.3.13 類型安全配置
在Drools中,除了能夠通過配置文件配置選項外,也可用系統屬性配置,通過API的 setProperty()方法設置屬性,Drools-API現在支持類型安全配置。我們不希望爲每個可能的配置方法增加特殊的方法,有兩個原因:它污染了API,並且每次都有一個新選項增加到Drools,API將不得不改變。而這種方式,我們遵循模塊化,類基於配置,在此處爲每個可能的配置,一個新的選項類增加到了API,除了靈活之外,也維持了API的穩定。所以,現在爲了設置配置選項,你只需要使用枚舉或者提供每個選項的工廠。例如,如果你希望爲斷言行爲"equality" 配置知識庫,並且自動從模式匹配中刪除特徵(identities),你只需要使用下面的枚舉:
例子2.31 配置
KnowledgeBaseConfiguration config = KnowledgeBaseFactory.newKnowledgeBaseConfiguration();
config.setOption( AssertBehaviorOption.EQUALITY );
config.setOption( RemoveIdentitiesOption.YES );
對於選項,我們不需要預定義約束,或者可以假設多個值,提供一個工廠方法。例如,配置alpha值爲5,只使用get()工廠方法:
例子 2.32 配置alpha值
config.setOption( AlphaThresholdOption.get(5) );
正如你所見,爲每個不同的可能配置,使用了相同的setOption()方法,然而它們仍然是類型安全的。
2.2.3.14 新的累積函數:collectSet和collectList
有時候,有必要收集來自實事屬性的值的集合或列表,而不是實事本身。在這種情況下,不可能使用collect CE。所以對這種情況,現在Drools有兩個新的累積函數:collectSet用於收集值的集合(即,無重複的值),collectList用於收集值的列表(即,允許重複的值):
例子 2.33 新的累積函數
# collect the set of unique names in the working memory
$names : Set() from accumulate( Person( $n : name, $s : surname ),
collectSet( $n + " " + $s ) )
# collect the list of alarm codes from the alarms in the working memory
$codes : List() from accumulate( Alarm( $c : code, $s : severity ),
collectList( $c + $s ) )
2.2.3.15 用於類型聲明的新元數據:@propertyChangeSupport
事實實現了象定義在Javabean(tm)規範中的屬性改變的支持。現在可以註釋,讓引擎註冊自身來偵聽事實屬性的變化。在Drools 4 API的insert()方法中使用的布爾參數已過時,並且不存在於drools-aip模塊中了。
例子 2.34 @propertyChangeSupport
declare Person
@propertyChangeSupport
end
2.2.3.16 批處理器
批處理器允許一個知識會話使用命令腳本,此外,無論是StatelessKnowledgeSession 還是 StatefulKnowledgeSession實現都可以使用CommandFactory創建這個接口命令,且使用"execute" 方法執行,如下所示:
例子 2.35 使用CommandFactory
ksession.execute( CommandFactory.newInsert( person ) );
儘管這樣,你通常會希望執行一個批處理命令,通過組合命令 BatchExecution可以完成它。BatchExecutionResults現在用來處理結果,某些命令可以使用"out"標識符,用它來添加結果到BatchExecutionResult。現在可以輕鬆地執行查詢,並把結果添加到BatchExecutionResult。這個結果進一步被限定到這個執行調用,並且通過BatchExecutionResults返回。
例子 2.36 使用BatchExecutionResult
List<Command> cmds = new ArrayList<Command>();
cmds.add( CommandFactory.newSetGlobal( "list1", new ArrayList(), true ) );
cmds.add( CommandFactory.newInsert( new Person( "jon", 102 ), "person" ) );
cmds.add( CommandFactory.newQuery( "Get People" "getPeople" );
BatchExecutionResults results = ksession.execute( CommandFactory.newBatchExecution( cmds ) );
results.getValue( "list1" ); // returns the ArrayList
results.getValue( "person" ); // returns the inserted fact Person
results.getValue( "Get People" );// returns the query as a QueryResults instance.
End
CommandFactory詳細描述支持的命令,它們所有都可以使用XStream和BatchExecutionHelper進行編碼。可以使用管道組合它們來自動化會話腳本。
例子 2.37 使用PipelineFactory
Action executeResultHandler = PipelineFactory.newExecuteResultHandler();
Action assignResult = PipelineFactory.newAssignObjectAsResult();
assignResult.setReceiver( executeResultHandler );
Transformer outTransformer = PipelineFactory.newXStreamToXmlTransformer( BatchExecutionHelper.newXStreamMarshaller() );
outTransformer.setReceiver( assignResult );
KnowledgeRuntimeCommand batchExecution = PipelineFactory.newBatchExecutor();
batchExecution.setReceiver( outTransformer );
Transformer inTransformer = PipelineFactory.newXStreamFromXmlTransformer( BatchExecutionHelper.newXStreamMarshaller() );
inTransformer.setReceiver( batchExecution );
Pipeline pipeline = PipelineFactory.newStatelessKnowledgeSessionPipeline( ksession );
pipeline.setReceiver( inTransformer );
對一個規則集使用上面所述的,會更新一個Cheese事實的價格,下面給定的xml會插入一個使用了輸出標識符(out-identifier)的Cheese實例。
例子 2.38 更新Cheese實事
<batch-execution>
<insert out-identifier='outStilton'>
<org.drools.Cheese>
<type>stilton</type>
<price>25</price>
<oldPrice>0</oldPrice>
</org.drools.Cheese>
</insert>
</batch-execution>
然後我們會得到BatchExecutionResults:
例子 2.39 更新Cheese實事
<batch-execution-results>
<result identifier='outStilton'>
<org.drools.Cheese>
<type>stilton</type>
<oldPrice>0</oldPrice>
<price>30</price>
</org.drools.Cheese>
</result>
</batch-execution-results>
2.2.3.17 編碼
MarshallerFactory被用來編碼和解碼StatefulKnowledgeSessions。最簡單的,它可以象下面這樣使用:
例子 2.40 使用MarshallerFactory
// ksession is the StatefulKnowledgeSession
// kbase is the KnowledgeBase
ByteArrayOutputStream baos = new ByteArrayOutputStream();
Marshaller marshaller = MarshallerFactory.newMarshaller( kbase );
marshaller.marshall( baos, ksession );
baos.close();
然而,在處理引用的用戶數據時,你需要更有彈性地使用編碼。要達成它,我們有一個ObjectMarshallingStrategy接口。我們提供了兩個實現,但是用戶可以自己實現它。提供的兩個是IdentityMarshallingStrategy和SerializeMarshallingStrategy。默認爲SerializeMarshallingStrategy,如上例所示,它只在一個用戶實例上調用Serializable或Externalizable方法。而IdentityMarshallingStrategy爲每個用戶對象創建了一個整數id,並存儲它們在一個映射中,該id被寫入到該流中。在解碼時,它只簡單地查看IdentityMarshallingStrategy映射,取回該實例。這意味着,如果你使用IdentityMarshallingStrategy,它對編碼實例的生命週期是有狀態的,並且會創建ids,保持它企圖編碼的所有對象的引用。
例子 2.41 使用IdentityMarshallingStrategy編碼
ByteArrayOutputStream baos = new ByteArrayOutputStream();
Marshaller marshaller = MarshallerFactory.newMarshaller( kbase, new ObjectMarshallingStrategy[] { MarshallerFactory.newIdentityMarshallingStrategy() } );
marshaller.marshall( baos, ksession );
baos.close();
爲增加彈性,我們不能想當然地認爲單策略更合適,所以我們增加了一個ObjectMarshallingStrategyAcceptor 接口,每個ObjectMarshallingStrategy都有。編碼器有一個策略鏈,並且當它企圖讀或寫一個用戶對象時,它遍歷策略,詢問它們是否承擔負責編碼用戶對象。提供了一個實現爲ClassFilterAcceptor。它允許使用字符和通匹符匹配類名。默認爲"*.*",所以在上面使用的IdentityMarshallingStrategy,它有一個默認的"*.*"接收器。然而,比方說,我們希望序列化所有類,一個給定的包除外,這種情況,我們會使用身份查詢,如下所示:
例子 2.42 使用身份查詢
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectMarshallingStrategyAcceptor identityAceceptor = MarshallerFactory.newClassFilterAcceptor( new String[] { "org.domain.pkg1.*" } );
ObjectMarshallingStrategy identityStratetgy = MarshallerFactory.newIdentityMarshallingStrategy( identityAceceptor );
Marshaller marshaller = MarshallerFactory.newMarshaller( kbase, new ObjectMarshallingStrategy[] { identityStratetgy, MarshallerFactory.newSerializeMarshallingStrategy() } );
marshaller.marshall( baos, ksession );
baos.close();
2.2.3.18 知識代理
KnowlegeAgent由 KnowlegeAgentFactory創建。KnowlegeAgent提供自動加載、緩存和重新加載資源,並且根據一個屬性文件配置它。當KnowlegeBase使用的資源更改時,KnowlegeAgent可以更新或重構KnowlegeBase。通過給定工廠的配置確定KnowlegeAgent的策略,但通常使用基於標準輪詢的拉策略。我們希望增加基於推的更新,並在將來的版本中重構它。下面的例子,構建了一個代理,它根據在路徑字符串中指定的文件構建了一個新的KnowledgeBase。它會每30秒拉這些文件,而不是更新存在的一個,因爲 "newInstance" 設置爲了"true" (然而,目前只支持"true" 值,並且很難編碼到引擎中)。
例子 2.43 構建一個代理
// Set the interval on the ResourceChangeScannerService if you are to use it and default of 60s is not desirable.
ResourceChangeScannerConfiguration sconf = ResourceFactory.getResourceChangeScannerService().newResourceChangeScannerConfiguration();
sconf.setProperty( "drools.resource.scanner.interval",
"30" ); // set the disk scanning interval to 30s, default is 60s
ResourceFactory.getResourceChangeScannerService().configure( sconf );
KnowledgeBase kbase = KnowledgeBaseFactory.newKnowledgeBase();
KnowledgeAgentConfiguration aconf = KnowledgeAgentFactory.newKnowledgeAgentConfiguration();
aconf.setProperty( "drools.agent.scanDirectories",
"true" ); // we want to scan directories, not just files, turning this on turns on file scanning
aconf.setProperty( "drools.agent.newInstance",
"true" ); // resource changes results in a new instance of the KnowledgeBase being built,
// this cannot currently be set to false for incremental building
KnowledgeAgent kagent = KnowledgeAgentFactory.newKnowledgeAgent( "test agent", // the name of the agent
kbase, // the KnowledgeBase to use, the Agent will also monitor any exist knowledge definitions
aconf );
kagent.applyChangeSet( ResourceFactory.newUrlResource( url ) ); // resource to the change-set xml for the resources to add
KnowledgeAgents可以使用一個空的 KnowledgeBase或植入的一個。如果提供了一個植入的KnowledgeBase,KnowledgeAgent會遍歷KnowledgeBase,並訂閱它發現的資源。雖然KnowledgeBuilder可以構建在一個目錄中發現的所有資源,但信息會被KnowledgeBuilder丟棄,因些那些目錄不會繼續被掃描。只有作爲applyChangeSet(Resource)方法的一部分指定的目錄纔會被監控。
2.2.4 Drools Flow
Drools 4.0有簡單的 "RuleFlow"用於組織規則 。Drools 5.0引入了一個強大(可擴大)的工作流引擎。它允許用戶使用規則和流程(流程和規則的強力交互是可能的)指定他們的業務邏輯,並提供了一個統一的環境。
2.2.4.1 在一個特殊斷點的流程實例視圖
圖2.31 規則流屬性
圖2.32 在一個工作流中的一個特殊斷點中的當前活動節點
2.2.4.2 新節點
計時器:
可以增加一個計時器節點,它導致執行的節點等待一個特定時期。目前只使用JDK默認的初始延遲和重複延遲,更復雜的計時器可以會用於將來的里程碑中。
人類任務:
流程可以包括需要人類參與者來執行的任務。人類任務包括諸如任務名字、優先權、描述、參與者id等等參數。流程引擎可以使用我們的可插式工作項目(見後)方便地與存在的人類任務組件整合(例如,一個WS-HumanTask實現)。泳道和分配 (Swimlanes and assignment )規則也被支持。
在調色板的截圖中顯示了兩個新組件,並且工作流本身顯示了使用的人類任務。也顯示了兩個"work items",在下一節會被解釋。
圖2.33 人類任務
2.2.4.3 域特殊工作項目
域特殊工作項目是用戶創建的有助於定製任務執行的可插式節點。它們提供了一個api用於在調色板中指定一個新的圖標,以及用於該任務屬性的gui編輯器。如果沒有提供gui編輯器,那麼則默認爲基於鍵值對錶單的一個文本。然後api允許執行那些指定的工作項目的行爲。默認提供了Email 和Log 工作項目。有關如何實現它們,在Drools flow中已被更新。
下圖顯示了用於一個工作流中的三個不同的工作項目,"Blood Pressure", "BP Medication", "Notify GP":
圖 2.34 工作項目
還有一個新的"Notification"工作項目
圖 2.35 Notification
2.2.4.4 可擴展流程定義語言(ePDL)
Drools 4.0使用XStream存儲它的內容,這是不容易人爲編寫的。Drools 5.0引入了ePDL,它是一個用於我們流程語言的特殊XML,它也允許域特殊擴展,在博客帖子“Drools的可擴展流程定義語言(ePDL)和語義模塊框架(SMF)”中已被詳細談及。如下所示,XML語言的一個例子,使用了DSL擴展。
<process name="process name" id="process name" package-name="org.domain" xmlns="http://drools.org/drools-4.0/process" xmlns:mydsl="http://domain/org/mydsl" xmlns:xs="http://www.w3.org/2001/XMLSchema-instance" xs:schemaLocation="http://drools.org/drools-4.0/process drools-processes-4.0.xsd" > <nodes> <start id="0" />
<action id="1" dialect="java"> list.add( "action node was here" ); </action>
<mydsl:logger id="2" type="warn"> This is my message <mydsl:logger>
<end id="3" /> </nodes>
<connections> <connection from="0 to="1" /> <connection from="1" to="2" /> <connection from="2" to="3" /> </connections>
</process>
2.2.4.5 可插式節點
用於該框架的基本節點完全是可插式的,使它易於擴展和實現其他執行模式。我們已經有一個OSWorkflow的局部實現,並正和Deigo一起完成它,爲OSWorkflow用戶提供一個移值路徑。其他的增強,包括異常域、在各種節點上包括進入和退出(on-entry and on-exit)行爲的能力、集成了我們的用於長期運行流程的狀態持久化的二進制持久化機制等等。瞭解更多內容請看Drools flow文檔。
2.2.4.6 人類任務
在流程的上下文中人類任務的管理是十分重要的。因爲我們允許用戶插入他們喜歡的任何任務組件,所以我們開發了一個人類任務管理組件,用於支持基於WS - HumanTask規範的人類任務的整個生命週期。
2.2.4.7 Drools flow語言的新功能
n 事件節點允許一個流程響應一個外部事件。
n 異常處理器和異常處理器域用於處理可能被拋出的異常。
n ForEach節點允許你多次實例化你的流程段,爲一個集合中的每個元素。
n 數據類型的支持已得到擴展。
n 普通的節點類型集成了定時器。
因此,新的節點類型和屬性已被增加到了Eclipse中的Drools Flow 編輯器。在集成測試中,你可以發現這些新功能的例子(例如ProcessExceptionHandlerTest,ProcessTimerTest等)。
2.2.4.8 工作項目
我們的可插式工作項目方法,允許你以一個聲明的方式,把域特殊(domain-specific )工作插入到你的流程中。我們計劃構建一個普通工作項目的庫,並且已經提供了用於發送電子郵件、查找文件、歸檔、執行系統命令、日誌和人類任務的實現。
2.2.4.9 JPA
改進了對持久化(JPA)和事務(JTA)的支持。
例子 2..45 如何使用持久化和事件與流程結合的例子
// create a new JPA-based session and specify the JPA entity manager factory
Environment env = KnowledgeBaseFactory.newEnvironment();
env.set( EnvironmentName.ENTITY_MANAGER_FACTORY, Persistence.createEntityManagerFactory( "emf-name" ) );
env.set( EnvironmentName.TRANSACTION_MANAGER, TransactionManagerServices.getTransactionManager() );
StatefulKnowledgeSession ksession = JPAKnowledgeService.newStatefulKnowledgeSession( kbase, null, env ); // KnowledgeSessionConfiguration may be null, and a default will be used
int sessionId = ksession.getId();
// if no transaction boundary is specified, the method invocation is executed in a new transaction automatically
ProcessInstance processInstance = ksession.startProcess( "org.drools.test.TestProcess" );
// the users can also specify the transaction boundary themselves
UserTransaction ut = (UserTransaction) new InitialContext().lookup( "java:comp/UserTransaction" );
ut.begin();
ksession.insert( new Person( "John Doe" ) );
ksession.startProcess( "org.drools.test.TestProcess" );
ksession.fireAllRules();
ut.commit();
2.2.4.10 變量注入
支持在代碼約束和動作中,在MVEL和Java中,直接訪問流程變量,所以,在你的流程中有一個變量名爲"person" ,你現在可以如下這樣描述約束:
例子 2.46 變量注入例子
* [Java code constraint] return person.getAge() > 20;
* [MVEL action] System.out.println(person.name);
2.2.4.11 雜項改進
n 流程實例現在可以通過標記事件節點屬性"external" 爲ture,偵聽外部事件。外部事件使用session.signalEvent(type, eventData)單獨發送給引擎。在你的流程中如何使用事件,詳情請看Drools Flow :https://hudson.jboss.org/hudson/job/drools/lastSuccessfulBuild/artifact/trunk/target/docs/drools-flow/html/ch03.html#d0e917
n 流程實例對多線程是安全的(因爲多線程被阻止在相同的流程實例上工作)。
n 流程持久化/事務的支持已被進一步改進。詳情請查看 drools-process/drools-process-enterprise項目
n 人類任務組件已被擴展來支持在任務執行期間的輸入/輸出/異常的各種數據。
例子 2.47 因此,任務客戶端的生命週期的方法已經擴展爲允許內容的數據
taskClient.addTask(task, contentData, responseHandler)
taskClient.complete(taskId, userId, outputData,responseHandler)
taskFail.complete(taskId, userId, outputData,responseHandler)
long contentId = task.getTaskData().getDocumentContentId();
taskClient.getContent(contentId, responseHandler);
ContentData content = responseHandler.getContent();
n 現在在編輯期間,可以移植老的Drools4 RuleFlows (使用xstream格式的) 到 Drools5 流程 (使用可讀式的xml)。當以下系統屬性設置:drools.ruleflow.port = ture時,在添加RuleFlow到KnowledgeBase時,移植會自動被執行。
n 增加了一個新類型的結合點(join),它將等待直到它的n中的m個連接已被完成。這個n既可以是在流程中的硬編碼,也可以是基於該過程中的一個變量的值。
n 已做了改進,使持久化配置更容易。持久化方法是基於一個命令服務,確保了客戶端的調用在一個事務內部被執行,並且在命令成功執行之後狀態被存儲在數據庫中。雖然在M4版中已經可以直接使用該命令,我們還是擴展了它,目的在於除了可以簡單地使用配置文件配置持久化外,人們可以使用標準的 StatefulKnowledgeSession接口。詳情請查看Drools Flow 文檔中有關持久化的部分。