Total Pageviews

2017/06/03

[webMethods] 如何從 Java Service 中讀取 Property File

在 Java Service 中,有些設定值我希望不要 hard code 在程式中,要搬到 property file 供日後的設定之用,該如何從 Java Service 中讀取 Property File

property file 檔名為 opc_config.properties ,
內容如下:
opc.url=opc.tcp://192.168.1.1:49320
opc.retry.interval=5
opc.max.retries=5
opc.sleep.ms=5000

我目前的開發的目錄是在 Acme 的 package之下:


property file 就要放在 [IntegrationServer 安裝目錄]\instances\default\packages\Acme\resources 之下

值得注意的是,當我們在 load 此 property file 時,路徑規範是 packages\\[你的 package name]\\resources\\[你的 property file name],如 packages\\Acme\\resources\\opc_config.properties ,若沒按照此規範會出現 FileNotFoundException

Sample code 如下:

    /** 
     * The primary method for the Java service
     *
     * @param pipeline
     *            The IData pipeline
     * @throws ServiceException
     */
    public static final void PropertyFileUtils(IData pipeline) throws ServiceException {
        String config_file = "packages\\Acme\\resources\\opc_config.properties";
        
        try {
            Properties properties = loadProperties(config_file);
            
            String opcUrl = properties.getProperty("opc.url");
            String retryInterval = properties.getProperty("opc.retry.interval");
            String maxRetry = properties.getProperty("opc.max.retries");
            String sleepMs = properties.getProperty("opc.sleep.ms");
            
            logger("opcUrl = " + opcUrl);
            logger("retryInterval = " + retryInterval);
            logger("maxRetry = " + maxRetry);
            logger("sleepMs = " + sleepMs);
            
        } catch (IOException e) {
            throw new ServiceException(e);
        }
    }
    
    // --- <<IS-BEGIN-SHARED-SOURCE-AREA>> ---
    
    public static Properties loadProperties(String config_file) throws ServiceException, IOException{
        Properties properties = new Properties();
        InputStream inputStream = null;
        try {
            inputStream = new FileInputStream(config_file);
            properties.load(inputStream);
        } catch (IOException e) {
            throw new ServiceException(e);
        } finally {
            if (inputStream != null) {
                inputStream.close();
            }
        }
        return properties;
    } 
    
    public static void logger(String message) throws ServiceException {
        IData input = IDataFactory.create();
        
        IDataCursor inputCursor = input.getCursor();
        IDataUtil.put(inputCursor, "message", message);
        IDataUtil.put(inputCursor, "function", "customLogger");
        IDataUtil.put(inputCursor, "level", "INFO");
        inputCursor.destroy();
    
        try {
            Service.doInvoke("pub.flow", "debugLog", input);
        } catch (Exception e) {
            throw new ServiceException(e);
        }
    }
    
    // --- <<IS-END-SHARED-SOURCE-AREA>> ---

相同的,如果你有一些設定用的檔案如 csv 等,也可以放在 resources 目錄下,透過相同的方式皆可讀取得到

Reference
[1] https://goo.gl/EFbLkg

2017/06/02

[閱讀筆記] 惡魔財經辭典 (The Devil’s Financial Dictionary) [2/6]


  1. 會計事務所負責稽核客戶的財務及發行之投資商品,因此也能協助在財務、股票或債券價值上作假,也便於內線交易
  2. Blue chip (藍籌股)指的是績優股,是最大型、最多人持有的股票。blue chip 一詞出自賭場,藍色的籌碼是賭場裡最高價的籌碼
  3. 在華爾街,成功常常不只取決於能力,運氣也相同重要
  4. Book value (帳面價值)常被譏笑是衡量公司價值的爛方法,因為無法完全囊括專利、軟體、行銷創新等無形資產的潛在價值,也無法精準估計公司創造收益的潛力。只能看出所有用的之產減掉負債後所剩下的價值,話雖如此,book value仍是一個粗略的指南,可讓持股人知道若情況不對,公司還剩下多少價值
  5. 股市跌了一波以後似乎穩定下來,技術分析師就說這是在打底(form a bottom),只要開始上漲就說底部完成(complete a bottom)。若接下來不漲反跌,技術分析師又說市場在打另外一個底(bottom),底部一個一個打,打個沒完,一路往「零元」打去
  6. Broker 這是個形容某人取用(很可能榨乾)他人財富的字根,投資人應該謹記在心中
  7. 幾乎打從金融市場誕生以來,人們就明白 bubble 會在一瞬間從「興奮」、「痛快」轉為「災難」。在更近代,只要是投資人認為價格過高的資產,就一律用 bubble 來形容。然而,能準確辨識出 bubble 並且成功避開從來就不容易,很多都只是放馬後砲而已
  8. 股價上漲期間,會導致投資人認為自己的智商也走高。等到價格必然下跌後,他們才知道,這兩者的走高都只是暫時的
  9. Bond call 是指贖回債券,公司或政府提前將發行的債券贖回(pay off),通常是最不利於投資人的時間點
  10. 資本(capital)就像牲畜一樣,如果沒有好好看管的話,容易走丟、跑掉,甚至死亡
  11. Bear market 往往不在重摔巨響中結束,而是在低鳴聲中劃下句點,逐步步入麻木黑暗中。Bull market 也不是在恐慌的投資人拋售後就開始,而是絕望的投資人麻木到連賣都不賣時
  12. 投資管理人犯的錯有兩種:一是「跟著眾人一起錯」(這時候不會有人責怪他,因為大家都犯同樣的錯),二是「只有他一個人錯」(這時候他就會向個白痴一樣)
  13. 唯一可以大敗大盤的方法是「不從眾而行」
  14. 基金經理人常會交易過度頻繁、過度著眼於模仿大盤動向,卻忘了身為一個基金經理人真正該做的事情是「選出最低價的潛力股,然後長期持有」
  15. Central bank (中央銀行)跟 weathervane(風向雞)沒什麼不同,兩者都會隨風轉向,只不過,中央銀行那些人以為風往哪邊吹是他們決定的。殊不知,他們的預測從不可靠、對於通膨根本無法預防、讓失業率更加惡化
  16. 金融市場最根本的屬性就是 uncertainty,每當你自以為知道某事一定會發生,金融市場就會證明你錯了。每當混亂或動盪清晰可見,專家們就會宣稱「投資人痛恨不確定性」,可是,「不確定」是投資人面對的「確定」狀態
  17. 痛恨「不確定」是浪費時間與精力,不如乾脆去痛恨地心引力或抗議時間流逝算了。唯一的 certainty 就是 uncertainty 永遠不會消失。你要習慣他,不然就完全離開金融市場
  18. 一份好的 checklist 可以提供一種架構,迫使投資人去做仔細、獨創的研究,多多向外蒐集資料來挑戰自己的看法,以免受制於「驗證偏誤」(confirmation biasis)。飛機駕駛和醫護人員都會採用 checklist ,這麼做可以拯救人命。同樣的,一份好的投資 checklist 也可避免做出衝動決策
  19. Cigar butt (雪茄屁股)是指股價非常低廉的股票,因為低廉,所以就算該公司經營不善,股價仍會上漲。誠如巴菲特所言:「如果買一支股價夠低的股票,通常有機會以不錯的獲利出脫了結,儘管該公司長期的表現可能很糟糕。」但是,在現今的金融市場,想要找到 cigar butt 很難
  20. 當分析師使用 clearly (顯然地)這個字眼時,只有兩種狀況:
    1. 假裝他們知道接下來會發生什麼事情,但是沒有令人信服的證據
    2. 描述已經發生的事情,宣稱他們早就知道
  21. Commodities (大宗物資、原物料) 的賺賠操作有三種模式
    1. 透過市場價格的漲跌(也就是spot,現貨價)
    2. 滾動利益(roll return,轉倉收益),也就是如果你賣掉這個月期貨的價格,高於下個月期貨的買入成本
    3. 賺取抵押品(也就是你拿來擔保借款的東西)的利息
  22. 從歷史來看,Commodities (大宗物資、原物料)的長期績效要靠「滾動利益(roll return,轉倉收益)」,但由於後來大量新進投機客的熱錢湧入,扭曲了期貨市場價格,roll return 的效益逐年遞減。2008 年金融危機後,各國央行往零利率的方向走,抵押品的報酬也跟著縮水。因此大宗物資的高報酬已經不在,但還是有很多天真的投資人爭相投入
  23. 不同於債券、股票、房地產,大宗物資的現金流無法預測。所以,一旦完全要仰賴別人願意付多少錢,就比債券、股票、房地產的風險更高,只能任憑市場宰割
  24. 信心滿滿是有害的,投資人現在越有信心,日後難過的機率就越高。不過,幾乎沒有人能在當時認知到這點
  25. 每個人都會有 confirmation bias (驗證偏誤),因此投資人必須強迫自己透過 checklist 之類的程序,尋求及思考其他反面證據。詩人 Ogden Nash 曾說過:「已經有定見的腦袋就像一道只能像外打開的門,用再多的事實來推他,結果只是關得更緊而已」
  26. 恐懼的情緒會傳染,從一個投資人擴散到另外一個投資人,從一個市場擴散到另外一個市場,甚至擴散到全世界。目前已知療法只有三種:時間、隔離、耳塞
  27. 很多專業投資人都說自己是逆向操作的人(contrarian),但是幾乎沒有一個是
  28. 市場溫和下跌是指下跌幅度不超過 10% ,不過並沒有一個正式的定義。市場行為必須適當地 correct (修正),價格一路上揚本來就不對
  29. 分散投資要達到最大效果,投資組合中的標的就不可高度相關。可是,如此一來就必須持有一些績效較差的標的,而不能一味追逐當前最熱門的標的
  30. Counterparty 是指交易對手,如果你是賣方,買方就是你的 counterparty;如果你是賣方,買方就是你的 counterparty。但是,不管你是在哪一方,只要有人下單,就是券商歡呼的時刻,無論買或是賣,券商都可以收取手續費

2017/06/01

[閱讀筆記] The Black Swan: The Impact of the Highly Improbable (1/3)


  1. 黑天鵝的三大特性
    1. rarity (罕見):過去的經驗讓人不相信其出現的可能
    2. extreme impact (造成重大衝擊):只要一發生,就會造成重大的衝擊
    3. retrospective predictability (事後諸葛);一旦發生,人會因為天性使然而作出某種解釋,讓這事件成為可解釋或可預測
  2. 人們太少反思自己所相信、習以為常的事情
  3. 人類是相當膚淺的動物,我們都知道預防重於治療,但是我們通常不會去讚賞做風險預防動作的人,反而會去讚賞壞事情發生後去收尾的人
  4. 我們的世界是被極端、未知、無法預測的事物所主宰,然而人們卻聚焦在已知、重複發生的事物上
  5. 我知道誰的言論是錯誤,但是不代表另外一個言論是正確的。如果我看到一隻黑天鵝,我可以確定不是所有的天鵝都是白的。如果我看到有人殺了人,我可以幾乎確定他就是罪犯;但是如果我沒有看到他殺人,我無法確定他是無辜的。
  6. 我們總是假定歷史是是根據某種邏輯產生的,但是其實我們只有看到一連串的事件,不是邏輯,只是在猜測這一連串的事件是怎麼產生的
  7. 黑天鵝會出現是,人們聚焦於少量的不確定的來源,但是災難卻是從非聚焦的地方所產生
  8. 真實的世界是非線性的,而且會比你想得更非線性。線性的關係在真實世界是非常罕見的,你只會在教室或是教科書裡面才會看到,因為那是要讓你更容易理解
  9. 感恩節之前的火雞會因為被人類飼養對人類的信任度慢慢提高,如果你是火雞會認為自己沒有任何危險,直到感恩節那天,火雞的"黑天鵝"發生(超出它想像的事件),莫名其妙的被做成感恩節大餐
  10. 在真實世界裡,人們總是會較重視 What I did for you,較漠視 what I avoid for you。人們會看到911事件後對罹難者家屬的照顧,卻不會看到立法強制開車要繫安全帶,保護你人生安全的立法者
  11. 當你看到某個事件發生的原因是"因為"什麼樣的關係所導致,對於這個原因,請先保持懷疑的態度,小心求證
  12. 人是一個很膚淺的動物,只會注意到所看到的事物
  13. 為什麼我們會看不見黑天鵝,因為我們只擔心過去已經發生的事情,忽略了之前沒發生過的事情。這是因為人們對於沒發生過的、沒看過的事物,太過抽象,以致於忽略它、無法從中學習到教訓。
  14. 人類的知識會逐漸增加,但是威脅人們的是快速增加的自信。人類的傲慢源自於其有限的知識,人們總是高估自己所知道的,而低估不確定性
  15. 人類實際知道的知識,與自己認為自己知道的知識,常常有顯著落差
  16. 很多專家的預測並不準確,因為他們是根據不會重複發生的過去,來預測未來。我們頂多可以透過網站,預測明天戲院幾點開門
  17. 專家最大的問題是,他們不知道他們哪裡不知道
  18. 預測要正確,事情的發生要有規律性,如果沒有規律性,預測勢必失敗
  19. 人們常把成功歸因於自己的能力,把自己的失敗歸咎於外在的、無法控制的隨機事件。我們只對好的事物負責,對壞的事物卸責
  20. 因為我們不夠了解未來,所以我們無法做好妥善規劃。所以,在規畫的時候要牢記,我們規劃的限制是什麼

2017/05/31

2017/05 Travel

新店獅頭山步道
DSC01519

DSC01521

DSC01531

「印象.左岸–奧塞美術館30周年大展」 - 梵谷《午睡》
「印象.左岸–奧塞美術館30周年大展」 - 梵谷《午睡》


基隆港
IMG_6409




2017/05/13

[Mac] 使用 Safari 報稅時,一直卡在系統登入畫面

Problem
當我使用 Mac Safari 連上 https://rtn.tax.nat.gov.tw/ircweb/index.jsp 要使用自然人憑證進行報稅時,一直卡在此系統登入畫面


How-to
解決步驟如下
(1) Safari -> 偏好設定


(2) 安全性-> 外掛模組設定


(3) 點選 Java


(4) 將 rtn.tax.nat.gov.tw 此網站從關閉改為開啟,並按下完成


(5) 重新使用自然人憑證進行登入


(6) 按下繼續,即可開始報稅






2017/05/10

[webMethods] IS Package Class Loaders 順序

根據 webMethods 文件
  • IS package class loaders 順序是下圖的 1.1 ~ 1.4
  • 在 runtime 的時候,順序是下圖的 2.1 ~ 2.3
  •  要注意的是,若有一個檔案同時存在於 jars 與 classes 的 folder,位於 jars folder 內的檔案擁有優先權


以 Acme package 為例子,目錄結構如下:


Reference
[1] https://goo.gl/46NgNp

2017/05/09

[webMethods] 如何在 Java Service 中印 debug log

Problem
假設我在 Java Service 中印出 debug log 來進行程式碼的 debug,該如何印

How-to
若是同步的作業,作法如下:
    public static void logger(String message) {
    
        IData input = IDataFactory.create();
        IDataCursor inputCursor = input.getCursor();
        IDataUtil.put(inputCursor, "message", message);
        IDataUtil.put(inputCursor, "function", "customLogger");
        IDataUtil.put(inputCursor, "level", "INFO");
        inputCursor.destroy();
    
        try {
            Service.doInvoke("pub.flow", "debugLog", input);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

若是非同步的作業,作法如下:
    public static void loggerAsync(Session session, String message) {
        IData input = IDataFactory.create();
        IDataCursor inputCursor = input.getCursor();
        IDataUtil.put(inputCursor, "message", message);
        IDataUtil.put(inputCursor, "function", "customLogger");
        IDataUtil.put(inputCursor, "level", "INFO");
        inputCursor.destroy();
    
        try {
            Service.doThreadInvoke("pub.flow", "debugLog", session, input);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


以下是列印 log 的呼叫方式:
    // 非同步作業的呼叫方式
    Session session = Service.getSession();
    loggerAsync(session, "Hello~ asynch log");
    
    // 同步作業的呼叫方式
    logger("Hello~ log");







2017/05/08

[webMethods] 如何在 Java Service 中呼叫另外一個 Java Service

Problem
假設我有兩個 Java Service,一個為 Test Java Service: input 參數為 name,執行時會出現 popup window 供輸入


另外一個為 HelloWorld,input parameters 有兩個,分別是 name 與 dateTime,由Test Java Service 傳送給 HellowWorld Java Service,welcomeMessage = name + "(" + dateTime + ")"



How-to
可以使用 Service.doInvoke 來呼叫其他 Service
以下是 Test Service 中的 code snippet:
public final class Test_SVC

{

    /** 
     * The primary method for the Java service
     *
     * @param pipeline
     *            The IData pipeline
     * @throws ServiceException
     */
    public static final void Test(IData pipeline) throws ServiceException {
        IDataCursor pipelineCursor = pipeline.getCursor();
        
        // Invoke the pub.date:getCurrentDateString service to get current date time
        String currentDateString = "";
        IDataUtil.put(pipelineCursor, "pattern", "yyyy/MM/dd HH:mm:ss");
        try {
            IData data = Service.doInvoke("pub.date", "getCurrentDateString", pipeline);
            currentDateString = (String) IDataUtil.get(data.getCursor(), "value");
        } catch (Exception e) {
            throw new ServiceException(e);
        }
        
        // input name
        String name = IDataUtil.getString(pipelineCursor, "name");
        IDataUtil.put(pipelineCursor, "name", name);
        
        // get current date time via pub.date:getCurrentDateString service
        IDataUtil.put(pipelineCursor, "dateTime", currentDateString);
        
        // Invoke HelloWorld service
        try {
            Service.doInvoke("acme.albert.work", "HelloWorld", pipeline);
        } catch (Exception e) {
            throw new ServiceException(e);
        }
        
        pipelineCursor.destroy();
    }
}    


以下是 HelloWorld Service 中的 code snippet:
public final class HelloWorld_SVC

{

    /** 
     * The primary method for the Java service
     *
     * @param pipeline
     *            The IData pipeline
     * @throws ServiceException
     */
    public static final void HelloWorld(IData pipeline) throws ServiceException {
        // pipeline
        IDataCursor pipelineCursor = pipeline.getCursor();
        String name = IDataUtil.getString(pipelineCursor, "name");
        String dateTime = IDataUtil.getString(pipelineCursor, "dateTime");
        logger("dateTime = " + dateTime);
        
        pipelineCursor.destroy();
                
        // pipeline
        IDataCursor pipelineCursor_1 = pipeline.getCursor();
        String welcomeMsg = "Hello~" + name + " (" + dateTime + ")";
        logger("welcome msg = " + welcomeMsg);
        IDataUtil.put( pipelineCursor_1, "welcomeMessage", welcomeMsg );
        pipelineCursor_1.destroy();     
    }
    
    // --- <<IS-BEGIN-SHARED-SOURCE-AREA>> ---  
    public static void logger(String message) throws ServiceException {
        IData input = IDataFactory.create();
        
        IDataCursor inputCursor = input.getCursor();
        IDataUtil.put(inputCursor, "message", message);
        IDataUtil.put(inputCursor, "function", "customLogger");
        IDataUtil.put(inputCursor, "level", "INFO");
        inputCursor.destroy();
    
        try {
            Service.doInvoke("pub.flow", "debugLog", input);
        } catch (Exception e) {
            throw new ServiceException(e);
        }
    }
    
    // --- <<IS-END-SHARED-SOURCE-AREA>> ---

}

執行結果:
[9987]2016-11-16 15:52:31 TST [ISP.0090.0004I] customLogger -- welcome msg = Hello~Albert (2016/11/16 15:52:31)
[9986]2016-11-16 15:52:31 TST [ISP.0090.0004I] customLogger -- dateTime = 2016/11/16 15:52:31

上述的範例是採取 synchronous 的方式去呼叫另外一個 Java Service,若要採用 asynchronous 的方式呼叫,需要改寫如下:
    Session session = Service.getSession();
    
    IData input = IDataFactory.create();
    IDataCursor inputCursor = input.getCursor();
    IDataUtil.put(inputCursor, "input", "hello");
    inputCursor.destroy();
    
    Service.doThreadInvoke("acme.albert.work.OPC", "OPC_Heartbeat_Flow", session, input);

2017/05/07

[webMethods] 在 Flow Service 中使用 Sequence 來實現 try-catch

步驟 1. 建立一個 SequenceFlow,並建立兩個輸入參數 num1 與 num2,將 num1 * num2 的結果傳送到輸出參數 result


步驟 2. 建立三個 Sequences,try-catch, try 與 catch,此三個 sequence 的 Exit on 參數分別為
* ‘Success’ for the ‘try-catch’ sequence.
* ’Failure’ for the ‘try’ sequence.
* ‘Done’ for the catch sequence.


步驟 3. 在 try-sequence 中加入 multiplyInts 進行運算


步驟 4. 在 catch-sequence 中加入 getLastError 來取得例外錯誤訊息,並加入 debugLog 將錯誤訊息印到 server log


步驟 5. 執行並驗證結果

2017/05/06

[webMethods] 在 Flow Service 中使用 Loop

步驟 1. 分別建立 OrderRequest 與 OrderResponse Document ,Request 與 Response 的資料結構相仿,唯一差異的地方是 Response 的 Subtotal = Request 的 Quantity * Price

步驟2. 建立 LoopFlow,並將 input 與 output 分別設定為 OrderRequest 與 OrderResponse

步驟 3. 在 LoopFlow 中,分別加入 MAP、LOOP、MAP 與 MAP,並在 LOOP Step 中設定 Input array 與 Output array


步驟 4. 在 LOOP 中進行 MAP Request 與 Response data,並加入 multiplyInts transformer 來運算 Quantity * Price = Subtotal

步驟 5. 執行 LoopFlow 並查看結果










2017/05/05

[webMethods] 在 Flow Service 中使用 Branch

步驟 1. 建立一個 Math Flow,用來展示加減乘除的數學運算


步驟 2. 建立 input / output parameters,num1 與 num2 是供輸入的兩個整數參數,operator 是輸入加減乘除用的參數,result 是運算結果


步驟 3. 在 MathFlow 中,建立一個 branch step,依照 operator 參數所輸入的值來做不同的處理


步驟 4. 依據不同的 operator 使用不同的套件,即 pub.math:addInts, pub.math:subtractInts, pub.math:multiplyInts, pub.math:divideInts,Label 的值代表是 operator 所輸入的值


步驟 5. 在 pipeline tab 拉 pub.math:addIntspub.math:subtractIntspub.math:multiplyIntspub.math:divideInts 對應的值








步驟 6. 若 operator 輸入非預期的字元,則要做額外的處理,label 設定為 $default,並設定印出 The operator is invalid 此警告訊息




步驟 7. 若 operator 沒有輸入值,,則要做額外的處理,label 設定為 $null,並設定印出 The operator is null 此警告訊息





執行結果




2017/05/04

[webMethods] 刪除 Flow Service 中不需要的參數 - Drop the Selected Variable

假設以下是一個已經完成的 Flow Service,Pipeline Out 那個 column 代表著執行此 Flow Service 會產生的三個 output parameters:



Run Flow Service 的結果如下:



若我們希望 Pipeline Output 只要有 document 物件就好,其餘兩個 parameters 不要顯示,可以在 Pipeline tab 選定 parameter(s),再點選 Drop the Selected Variable 並儲存即可



若是要還原的話,操作如下: