2011年3月9日 星期三

Alfresco內設定排程作業(Scheduled Actions)

真實世界的資料處理,例如:申請、收單、審核與決行,很少是一氣呵成的同步作業(Synchronous Transaction),通常需要不同的角色(Actor)於不特定時間的接力處理。其實非同步(Asynchronous Transaction)的設計模式正好可以把複雜的流程拆解成較小的段落,讓開發者得專注在個別的問題領域,降低程式錯誤機率,以及最寶貴的設計原則:提高系統變動彈性。

Alfresco本身非常適合非同步的資料處理,藉由存放區(Space)、規則引擎(Rule Engine)、排程作業(Scheduled Action)以及自動流程引擎(Workflow Engine)等機制,讓企業的日常工作變得井然有序。本篇就來介紹如何定義一個新的排程。延續前幾篇文章的費用申請場景;員工將費用申請憑證以及相關屬性存入『費用申請』檔案夾後,Alfresco每隔五分鐘來巡視是否有申請單進來,申請單如果符合必要條件;以本例來說:就是檔案內含ExpenseDetails這個屬性集,則將申請單移至『費用審核』檔案夾等待審核。

一個排程作業是由三個部分組成:
  • 排程引擎Cron的描述
  • 處理對象的檢索樣板(Query Template)
  • 動作的樣板(Action Template)
以上三個部分都定義在Alfresco延伸路徑內的scheduled-action-services-context.xml檔案內。初次使用時,請將scheduled-action-services-context.xml.sample拷貝後更名為scheduled-action-services-context.xml,因scheduled-action-services-context.xml.sample含有許多Spring Bean的參考範例,為避免載入不必要的設定,建議建立一個全新的context檔案。請依以下步驟編輯:
  1. 在<beans>標籤內定義第一個Bean叫做templateActionModelFactory,是用來產出樣板引擎FreeMarker可以存取的資料模型,內文為:
    <bean id="templateActionModelFactory" class="org.alfresco.repo.action.scheduled.FreeMarkerWithLuceneExtensionsModelFactory">
            <property name="serviceRegistry">
                <ref bean="ServiceRegistry"/>
            </property>
    </bean>
  2. 定義動作(Action)的執行程式,本範例以Alfresco後端Script定義動作的內容。因Alfresco內嵌完整存取Repository資源的JavaScript API,以Script實作動作邏輯既彈性(不必重啟系統)又快速。請在<beans>標籤內繼續輸入以下字串:
    <bean id="expenseVoucherMoveScriptAction" class="org.alfresco.repo.action.scheduled.SimpleTemplateActionDefinition">
          <property name="actionName">
            <value>script</value>
          </property>
          <property name="parameterTemplates">
            <map>
              <entry>
                <key>
                  <value>script-ref</value>
                </key>
                <value>${selectSingleNode('workspace://SpacesStore', 'lucene', 'PATH:"/app:company_home/app:dictionary/app:scripts/cm:expenseVoucherMove.js"' )}</value>
              </entry>
            </map>
          </property>
          <property name="templateActionModelFactory">
            <ref bean="templateActionModelFactory"/>
          </property>
          <property name="dictionaryService">
            <ref bean="DictionaryService"/>
          </property>
          <property name="actionService">
            <ref bean="ActionService"/>
          </property>
          <property name="templateService">
            <ref bean="TemplateService"/>
          </property>
    </bean>
    以上是定義一個名叫expenseVoucherMoveScriptAction的執行物件,這個物件會透過Lucene搜尋位於Company Home/Data Dictionary/Scripts路徑下名叫expenseVoucherMove.js的檔案。這個後端JavaScript檔案是實際將費用憑證檔案由『費用申請』檔案夾移到『費用審核』檔案夾的執行者。
  3. 定義被動作的標的物件(檔案或檔案夾)以及Cron的執行排程。在<beans>標籤內繼續輸入以下字串:
    <bean id="expenseVoucherMoveScriptRun" class="org.alfresco.repo.action.scheduled.CronScheduledQueryBasedTemplateActionDefinition">
          <property name="transactionMode">
              <value>UNTIL_FIRST_FAILURE</value>
          </property>
          <property name="compensatingActionMode">
              <value>IGNORE</value>
          </property>
          <property name="searchService">
              <ref bean="SearchService"/>
          </property>
          <property name="templateService">
              <ref bean="TemplateService"/>
          </property>
          <property name="queryLanguage">
              <value>lucene</value>
          </property>
          <property name="stores">
              <list>
                <value>workspace://SpacesStore</value>
              </list>
          </property>
          <!-- Find nodes with ExpenseDetails aspect -->
          <property name="queryTemplate">
              <value>+PATH:"/app:company_home/cm:費用申報/*" +ASPECT:"custom:ExpenseDetails"</value>
          </property>
          <property name="cronExpression">
              <value>0 0/5 * * * ?</value>
          </property>
          <property name="jobName">
              <value>jobD</value>
          </property>
          <property name="jobGroup">
              <value>jobGroup</value>
          </property>
          <property name="triggerName">
              <value>triggerA</value>
          </property>
          <property name="triggerGroup">
              <value>triggerGroup</value>
          </property>
          <property name="scheduler">
              <ref bean="schedulerFactory"/>
          </property>
          <property name="actionService">
              <ref bean="ActionService"/>
          </property>
          <property name="templateActionModelFactory">
              <ref bean="templateActionModelFactory"/>
          </property>
          <property name="templateActionDefinition">
              <ref bean="expenseVoucherMoveScriptAction"/>
          </property>
         
    <property name="transactionService">
    <ref bean="TransactionService"/>
          </property>
          <property name="runAsUser">
              <value>System</value>
          </property>
    </bean>
    以上是定義一個名叫expenseVoucherMoveScriptRun的執行物件,這個物件會每隔五分鐘(Cron語法 0 0/5 * * * ?)搜尋Company Home底下的『費用申報』檔案夾內(PATH前面的加號表示只搜尋這個目錄)是否存有貼有ExpenseDetails屬性集的檔案,如果存在的話,則執行expenseVoucherMoveScriptAction執行物件。
  4. 撰寫自動搬檔Script: expenseVoucherMove.js。請在Company Home/Data Dictionary/Scripts目錄下建立expenseVoucherMove.js檔案,搬移邏輯可以自由發揮。以下是參考範例:
    var verifyFolder = companyhome.childByNamePath("費用審核");
    if(verifyFolder != null && verifyFolder.hasPermission("CreateChildren")){
        //change the name with time stamp     
        var dt = new Date();
        var y = dt.getFullYear();  
        var m = dt.getMonth() + 1;
        if(m < 10){
           m = "0" + m;
        }else{
           m = "" + m;
        }
        var d = dt.getDate();
        if(d < 10){
           d = "0" + d;
        }else{
           d = "" + d;
        }
        var h = dt.getHours();
        if(h < 10){
           h = "0" + h;
        }else{
           h = "" + h;
        }
        var mm = dt.getMinutes();
        if(mm < 10){
           mm = "0" + mm;
        }else{
           mm = "" + mm;
        }
        var s = dt.getSeconds();
        if(s < 10){
           s = "0" + s;
        }else{
           s = "" + s;
        }
        var stamp = "T" + y + m + d + h + mm + s;
        //
        document.name = stamp + "_" + document.name;
        document.save();
        // 
        document.move(verifyFolder);
    }
    以上程式碼的意思是:找到費用審核的檔案夾,接著在檔名前冠上時間戳記,為避免相容性問題,建議檔名不要以數字開頭,再來就是將檔案搬移到『費用審核』檔案夾。

2011年3月7日 星期一

自訂Alfresco屬性值限制

Alfresco本身提供四種基本屬性值限制(Constraint),分別是:
  1. REGEX: 字串樣式規則
  2. LIST:列表式值
  3. MINMAX:區間值
  4. LENGTH:字串長度
為便於重用Constraint,我們利用以上四種基本型別製作一個比較大顆(Coarse Grain)的Constraint。例如:上篇文章提到的費用請款自訂屬性集(Custom Aspect)裡的『歸屬部門』與『費用分類』可以LIST方式呈現,『總金額』可以MINMAX方式限制,以避免使用者的錯誤輸入。

請開啟自訂資料模型檔customModel.xml(路徑請參考here),在</namespaces>結束標籤下方加入以下文字:
<constraints>
   <constraint name="custom:DepartmentList" type="LIST">
     <parameter name="allowedValues">
        <list>
            <value>研發部</value>
            <value>業務部</value>
            <value>管理部</value>
       </list>
     </parameter>
   </constraint>
   <constraint name="custom:ExpTypeList" type="LIST">
     <parameter name="allowedValues">
        <list>
            <value>交通費</value>
            <value>誤餐費</value>
            <value>住宿費</value>
            <value>油電費</value>
            <value>影印費</value>
            <value>文具用品</value>
            <value>書報雜誌</value>
            <value>設備維修</value>
       </list>
     </parameter>
   </constraint>
   <constraint name="custom:ExpAmtMax" type="MINMAX">
     <parameter name="minValue">
        <value>10</value>
     </parameter>
     <parameter name="maxValue">
        <value>10000</value>
     </parameter>
   </constraint>
</constraints>
再將以上三個Constraint加入自訂屬性的定義內,請在同一個檔案(customModel.xml)內將游標移到aspects >> aspect >> properties 內的 custom:Department 屬性標籤,在</property>結束標籤前加上:
<constraints>
   <constraint ref="custom:DepartmentList"/>
</constraints>
在custom:ExpenseType屬性標籤的</property>結束標籤前加上:
<constraints>
   <constraint ref="custom:ExpTypeList"/>
</constraints>
在custom:TotAmount屬性標籤的</property>結束標籤前加上:
<constraints>
   <constraint ref="custom:ExpAmtMax"/>
</constraints>
以上設定就完成了。因為Cutom Model只有在Alfresco啟動時讀入,修改後需重新啟動Server才可生效。
嘗試修改已存入的費用檔案看看,總金額故意填入100000
按OK確定後,螢幕出現的輸入限制對話框

以Aspect自訂Alfresco資料屬性

通常檔案的描述資料(Meta Data)有Name、Title、Description、Author、Created Date與Last Modified Date等,Alfresco除了上述Meta Data外,可以自訂各式的資料模型(Content Model)。缺少了自訂的資料模型,Alfresco只不過是一套檔案管理系統。要滿足各類應用程式的儲存需求,甚至成為應用系統的發展平台,自訂資料屬性是必備的基礎功能。Alfresco提供兩種自訂屬性的方法,一是創建一個新的內容種類(Content Type),於檔案存入時直接指定;另一種是新增Aspect(就是屬性集合的意思),再透過規則引擎將Aspect根據條件貼在檔案上。以下是新增Aspect的步驟:
  1. 將自訂資料模型設定檔掛入Alfresco的載入清單中
    Alfresco啟動時除內定的系統路徑外,還會搜尋延伸路徑內是否含有以-context.xml結尾的檔案。這個模式讓客製化時無需修改原廠預設值,只需將新增或修改的參數寫在延伸檔案內即可覆蓋。以包覆Tomcat6的Alfresco34d為例,其延伸路徑位於$TOMCAT_HOME/shared/classes/alfresco/extension目錄內。初次使用時,請將custom-model-context.xml.sample更名為custom-model-context.xml,以及將customModel.xml.sample更名為customModel.xml。之後以文字編輯器開啟custom-model-context.xml,確定alfresco/extension/customModel.xml是否在extension.dictionaryBootstrap載入的範圍內。(當然,自訂模型檔名不一定要叫customModel.xml)
  2. 編輯customModel.xml
    在內文最底下</model>標籤之上加入自訂屬性集標籤代碼<aspects></aspects>。Aspect加S表示可以加入多個屬性集。假設我們要收集的資料為費用請款憑證,需要輸入費用的發生部門、分類、營業稅額與請款總金額;在<aspects>與</aspects>標籤內輸入以下字串:
    <aspect name="custom:ExpenseDetails">
        <title>費用明細</title>
        <properties>
           <property name="custom:Department">
              <title>歸屬部門</title>
              <type>d:text</type>
              <protected>false</protected>
              <mandatory>true</mandatory>
              <multiple>false</multiple>
           </property>    
           <property name="custom:ExpenseType">
              <title>費用分類</title>
              <type>d:text</type>
              <protected>false</protected>
              <mandatory>true</mandatory>
              <multiple>false</multiple>
           </property>    
           <property name="custom:TaxAmount">
              <title>營業稅額</title>
              <type>d:int</type>
              <protected>false</protected>
              <mandatory>true</mandatory>
              <multiple>false</multiple>
          </property>    
          <property name="custom:TotAmount">
              <title>總金額</title>
              <type>d:int</type>
              <protected>false</protected>
              <mandatory>true</mandatory>
              <multiple>false</multiple>
          </property>    
       </properties>
    </aspect>
  3. 編輯web-client-config-custom.xml
    為避免修改出廠的使用者操作介面設定值,Alfresco的延伸路徑$TOMCAT_HOME/shared/classes/alfresco/extension內同樣存在一個供開發者客製畫面的檔案web-client-config-custom.xml。如果找不到的話,請將web-client-config-custom.xml.sample更名為web-client-config-custom.xml。以文字編輯器開啟該檔案,在最後一列</alfresco-config>標籤上面將新建的Aspect告知Alfresco,鍵入的文字如下:
    <config evaluator="string-compare" condition="Action Wizards">
         <aspects>
             <aspect name="custom:ExpenseDetails"/>
         </aspects>
    </config>
    <config evaluator="aspect-name" condition="custom:ExpenseDetails">
         <property-sheet>
             <separator name="SepExpense" display-label="費用明細項目" component-generator="HeaderSeparatorGenerator"/>
             <show-property name="custom:Department"/>
             <show-property name="custom:ExpenseType"/>
             <show-property name="custom:TaxAmount"/>
             <show-property name="custom:TotAmount"/>
         </property-sheet>
    </config>
    上述第一個config標籤是將Aspect加入Alfresco規則引擎的動作(Action)選項中,第二個config標籤是帶出該Aspect畫面時,哪些屬性要顯示出來(屬性不一定要全部顯示)。
  4. 建立檔案夾規則
    Aspect可透過規則引擎貼上內容檔案;當我們將費用憑證掃描成電子檔案(PDF或TIFF),存入Alfresco某一個檔案夾(在 Alfresco通稱為Space)時,可以有條件或無條件地建立一個規則(Rule),而規則的動作(Action)可以是將ExpenseDetails這個 Aspect指定給剛存入檔案。這個效果就是擴充了這個檔案的描述資料(Meta Data),這些Meta Data也可以併入Alfresco搜尋引擎(Lucene)的檢索範圍。
  5. 驗證效果
    1.進入費用憑證存放空間
    2.指定費用憑證圖檔
    3.指定檔案類型
    4.指定自訂的屬性資料

2011年3月5日 星期六

什麼是企業內容管理系統(ECM)

根據維基百科(Wikipedia)對ECM的定義;

ECM是一個通稱名詞,意義涵蓋文件管理(Document Management)、網站內容管理(Web Content Management)、搜尋(Search)、協同作業(Collaboration)、記錄管理(Records Management)、數位資產管理(Digital Asset Management)、工作流程管理(Workflow Management)以及文件掃描與擷取(Capture and Scanning)等領域。

ECM系統主要是設計來管理所有資訊由生成、處理、歸檔到銷毀等生命週期。

ECM系統可以三種方式呈現:安裝於企業內部網路、安裝於軟體服務商(SaaS)提供網路服務、或以上兩者聯合運作的混合模式。

ECM目的是讓企業資訊在儲存(Storage)、安控(Security)、版本(Version Control)、處理流程(Process Routing)、 以及保存(Retention)等方面都得以簡化。企業導入ECM系統的效益包括工作效率的提升、更好的資訊管空以及降低營運成本。例如,許多銀行已經採用ECM系統儲存支票影像以取代原本的檔案室保存方法。過去,客戶要調閱一張支票可能要耗上幾週的時間,因為銀行行員需要透過檔案室管理人員找出原始支票,影印後寄到分行,分行行員再寄給客戶。有了ECM系統後,銀行行員只要以戶頭帳號與支票號碼就可以調出支票影像,可以立即就印出郵寄或e-mail給客戶,客戶往往還沒掛上電話,工作就已經完成了。

Alfresco ECM 使用案例

儘管非結構化文件佔了企業內容的八成,但要像ERP系統一樣的廣為採用,企業內容管理系統可能需要更多的使用案例與觀念傳播 。 以下是Alfresco(Open Source Enterprise Content Management)在無紙化辦公室的應用案例;(原本取自Techworld Australia Allianz removes walls of paper with open source ECM

雖然無紙化辦公室仍舊是遙遠的夢想,但保險巨人Allianz利用Alfresco ECM取代原有的紙本作業,成功挪出佔據辦公區大部分區域的檔案室。據Allianz(安聯集團)澳洲公司的辦公室自動化經理Tim Rynne指出,這個無紙化計畫早在18個月前已經定案,但一直苦於缺乏適當的解決方案。他說:"我們是帶了一堆文件進駐到無紙化的新辦公室,每個人的桌面仍舊充滿文件,尤其是便利貼"

Allianz 澳洲公司擁有超過兩百萬份保單以及三百多個員工,其資訊部門享有高度的自主決策權。

Rynne指出“我們有許多關於文件管理的系統,但都是各司其職,我們有Lotus Notes的內容 、紙本檔案、傳統檔案夾以及連結這些資源的儲存伺服器。”

因為許多專案都跟流程自動化(BPM)有關,都需要一套通用的 ECM (Enterprise Content Management)來填補除了儲存之外的功能,同時也要降低文件散佈與傳閱的其他問題。

另外,由紙本轉為電子化的流程處理,也將讓Allianz省去了文件的存放空間,確實地提高ECM專案的投資報酬率。

歷經三個月的評估後, Allianz選擇Open Source Alfresco ECM,並委由澳洲當地的顧問公司 Lateral Minds執行導入工作。

“我們最重要的評估標準是成本、彈性、功能、技術與整合等項指標,Alfresco除了擁有曾經待過Documentum 的熟練技術人員,廣大的社群用戶、企業與社群公用兩類版本以及方便的在地支援廠商都是勝出的因素”,Rynne指出。身為保險公司,組織本身就比較保守,開放原始程式碼並不是一項有力的誘因,但近年來Open Source專案的高人氣與企圖,讓我們決定一試。

“因為諸多的結構性問題,我們重新檢視過去已測試過的Open Source各項風險,加上最近的入口網站建置也採用Open Source專案系統,讓我們資訊部門決定 “打鐵趁熱”。

自成功上線後的12個月內,Allianz已存入將近一百萬份的文件進Alfresco ECM,總容量達500G。

“現在,文件不必再到處拷貝了,我們將文件掃描進Alfresco系統後再放入檔案室或銷毀” Rynne說,“文件對某些單位來說必須完整保存 – 例如:為符合法規,原始理賠文件在結案後需保留七年的時間,但這些文件已不必存放在主要的辦公區了。”

導入Alfresco後,Allianz正在研究如何擴展Alfresoc在BPM與作業效率方面的提升。

“我們剛導入一套用大型主機系統來列印保單與文件,再以PDF型式存入Alfresco以防止重複列印。現在,每天早上六點鐘前我們就可以取得保單以及歷史統計資料。”

整個BPM專案包括文件遞送方式,如電子郵件、傳真或掃描,以及Lotus Domino的整合。

“我們也嘗試以Alfresco改善保單簽署與處理程序的控管,以及讓分散在各地的業務人員可以隨時取得最新的保單文件”。

12個月後的效益:

電子化的效益,最簡單明顯的改變,原本文件佔據的空間還給了辦公室。

“我們擷取資料的速度提升許多,這點要感謝Alfresco的貢獻” Rynne說。

至於導入費用上, Rynne 表示 “恕難奉告”, 但他透露 “Alfresco比起其他方案省很多很多”。

Rynne對導入速度也讚賞有佳,Alfresco的部分只用了幾個星期,同時包括了壓力測試。

“導入的效益從第一天起就看得到,”他說, “使用者可以清楚看到文件處理程序,完全不用再依賴存放在檔案室的紙本文件”

Allianz 也打算將人工處理密集的理賠作業轉為自動流程處理。

文字自動辨識OCR對眾多文件是一大焦點,許多文件儘管數位化了,但並沒有建立有效的索引資料。

“我們擁有許多影像資料,並想辦法如何用以對付理賠的詐欺案件,例如,快速調出與比對照片影像,” Rynne說。

"我們還有大約百萬份的文件要處理,但這已不是什麼挑戰了,因為處理的程序方法已經在那裡了"

Allianz只有兩名開發人員負責Alfresco,不算多的資源投入, 但他們對Alfresco感到非常滿意,因為他們實際的工作是 "提升"而不是"維護" Alfrescos。

“我們看待Open Source時會覺得,它的投資不會很大,” Rynne說,“真正的投資都是在上線使用後發生的”。

“我們第一天就倒入25萬份文件,Alfresco就像網站宣稱的一樣穩定。我們很快地就建置一套ECM系統,花費不高但未來的成長潛力無限”。

Lateral Minds主管指出,採用像Alfresco這樣的Open source ECM,Allianz可以集中心力在保險事業上, 而不是內容管理上。