Total Pageviews

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 並儲存即可



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

2017/05/03

[webMethods] 如何將 JSON String 轉換成 ESB 中的 Document 物件

我有一個 Service Class,可以透過 buildTestJson() 取得測試用的 JSON String,或者是呼叫 buildHeartbeatMsgJson() 並傳入一個 HBMessage 物件取得 JSON String
import java.io.Serializable;

import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class OpcHeartbeatService {
    
    private final static Logger logger = LoggerFactory.getLogger(OpcHeartbeatService.class);
    
    public static void main(String[] args) {
        OpcHeartbeatService test = new OpcHeartbeatService();
        logger.info("buildTestJson = " + test.buildTestJson());
    }
    
    public String buildTestJson() {
        HBMessage hb_msg = new HBMessage("test", "123445", "HBT_MSG");
        return buildHeartbeatMsgJson(hb_msg);
    }
    
    public String buildHeartbeatMsgJson(HBMessage hb_msg) {
        JSONObject dataset = new JSONObject();
        
        JSONObject hbObject = new JSONObject();
        hbObject.put("serviceId", hb_msg.getServiceId());
        hbObject.put("token", hb_msg.getToken());
        hbObject.put("type", hb_msg.getType());
        
        dataset.accumulate("heartbeatMsg", hbObject);
        
        return dataset.toString();
    }

    public static class HBMessage implements Serializable{
        private static final long serialVersionUID = 1L;
        
        private String serviceId;
        private String token;
        private String type;
        
        public HBMessage() {
            super();
        }

        public HBMessage(String serviceId, String token, String type) {
            super();
            this.serviceId = serviceId;
            this.token = token;
            this.type = type;
        }

        public String getServiceId() {
            return serviceId;
        }
        
        public void setServiceId(String serviceId) {
            this.serviceId = serviceId;
        }
        
        public String getToken() {
            return token;
        }
        
        public void setToken(String token) {
            this.token = token;
        }
        
        public String getType() {
            return type;
        }
        
        public void setType(String type) {
            this.type = type;
        }
        
        @Override
        public String toString() {
            return "HBMessage [serviceId=" + serviceId + ", token=" + token + ", type=" + type
                    + "]";
        }
    }
}



在 Design 中建立一個 Java Service,名為 OPC_Heartbeat




在 OPC_Heartbeat 中定義一個 output 參數 (i.e. heartbeatJson),用來接收 buildTestJson() 所得到的 JSON String




在 OPC_Heartbeat 中,呼叫 OpcHeartbeatService 的 buildTestJson() method,取得測試的 JSON String ,並將 JSON String 傳給 output parameter
public final class OPC_Heartbeat_SVC

{

    /** 
     * The primary method for the Java service
     *
     * @param pipeline
     *            The IData pipeline
     * @throws ServiceException
     */
    public static final void OPC_Heartbeat(IData pipeline) throws ServiceException {
        OpcHeartbeatService hbService = new OpcHeartbeatService();
        String hbJson = hbService.buildTestJson();
        
        IDataCursor pipelineCursor = pipeline.getCursor();
        IDataUtil.put(pipelineCursor, "heartbeatJson", hbJson);
        pipelineCursor.destroy();
    }
    
    // ignore......
}    



OPC_Heartbeat 執行結果




將 OPC_Heartbeat 拉近 Flow Service,並利用 pub.json:jsonStringToDocument 此現成套件協助我們將 JSON String 轉成 ESB 中的 Document 物件




2017/05/02

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


  1. 大多避險基金收取一般共同基金十倍的費用,然後交給投資人指數型基金一半的報酬。事實上,避險基金沒什麼特別厲害之處,它們大多帶來令人失望的報酬
  2. 運氣、不確定、意外,是投資的基本外力,而華爾街在在跟外界溝通時,往往否定這些外力的威力
  3. 愈是濃縮、音節愈多的行話術語,愈有可能隱藏不想讓你知道的事。抓住男人的胃或許可以抓住他的心;要撬開投資人的口袋,就得從他的耳朵下手
  4. 金融歷史事件不會完全一模一樣重現,但也相去不遠。不管別人多大聲告訴你這次不一樣,人性是不會改變的。趨勢來來去去,唯一不變的是手續費永遠要繳
  5. 上漲的,遲早會下跌(通常比大家預期的還要早);同樣的,下跌的,也一定會再度上漲(通常是在專家都說不會的時候)
  6. 華爾街賣的是股票和希望,不過真正兜售的是『希望』。投資大眾都希望有奇蹟存在,於是金融業者就不斷宣稱看得到未來、能實現奇蹟。無論如何,千萬別跟著那些人走
  7. 所謂理財成功,並不是在金融遊戲中打敗專業,而是做到自我克制。金融市場每隔幾年就來一次的狂喜或絕望之時,退一步冷靜思考
  8. AAA 等級的債券不能保證你不會賠錢,2008年前三季,有超過 11000 個 AAA 等級房貸有價證券突然遭到大幅修正,其中許多證券的價格跌了七成或更多,導致投資人損失數千億美元
  9. 銀行機構每個月或每一季寄給你的帳戶明細(account statement),會盡量隱藏、偽裝虧損與費用的部份,讓你把注意力放在收入或獲利上
  10. 股市並不是一股一致的力量,不會採取一致的行動;股市是一種機制,看相反的人在其中就彼此的差異取得價格共識
  11. Alpha 係數是指高於市場指數的投資報酬率,通常用來表示投資經理人的選股技巧與能力,但事實上 alpha 幾乎只是隨機偶發的結果
  12. Amortize 有攤提的意思,一即將開支平均分攤一段時間,直到分攤完畢為止。如一支共同基金得先付 5.75% 的手續費,看起來很多。但是如果你 amortize 到未來 25 年,每年才付 0.23% ,就可以得到我未來 25 年的顧問服務,真的很划算喔
  13. 分析師理論上會拆解、分析一家公司的組成,並估算其價值。但實際運作起來,卻變成該公司的推銷員、啦啦隊
  14. 分析師常用的定錨(achor )手法是,為一支股票設定遠高於或遠低於市場價格的目標價,然後這個數值就會深植於投資人的腦中,就像定住的錨一樣,讓他們不去思考目標價合不合理,就能逐漸把該股票的價格拉往目標價
  15. 一年一度的股東大會,公司經營高層常用來粉飾業績,假裝用心傾聽股東的願望和抱怨
  16. Anomaly (異常現象)是一種投資策略或評估技術,可以產生高於大盤的報酬率,而且沒有明顯的高風險。但是不管在哪裡找到的 anomaly,都必然帶有自我衰敗的種子,因為這只是統計上的偶然而已,當大家把資金湧入、如法炮製,潛在的報酬率也隨之降低,最後就會回歸到平均值
  17. 資產配置據說是一門科學,不過很多理財顧問並不是用數學或邏輯來推薦資產配置,而是全憑猜測,或是最近什麼商品熱門就推薦什麼
  18. 若有人向你推薦某個資產配置,務必要問問其中有哪一項曾經報酬率很低。如果都沒有,那對方根本不是在推薦什麼資產配置,而是在邀請你追逐某種熱門投資,而且極可能馬上變得不熱門了
  19. 投資的各種類別各有不同的風險和報酬率,彼此之間的關聯性不高。例如股市表現不佳時,債券往往表現很好,反之亦然;股市或債市的走勢若急轉,期貨行情有可能也會急轉
  20. 如果有某一種「新的」或「另類的」的資產類別(asset class),其持有成本高於股票和債券等傳統資產類別,那麼,其價值大概也不會維持太久
  21. 大部分的理財顧問都盡可能從越多客戶身上搜刮越多的資產,這樣就能以最少的工作量賺到最多的手續費
  22. 股市崩盤很罕見,但是造成的驚人損害會烙印到集體意識中,導致投資人錯失在非崩盤期間(上次崩盤到下次崩盤之間其實非常長)靠股票謀利的機會
  23. 絕大多數的 IPO (Initial Public Offering)都不會比大盤好賺,不過,只要有少數引人注目的 IPO 一飛沖天 (如 Google IPO),就會造成投資 IPO 可以致富的假象
  24. 對股價走勢極有影響力的紅牌分析師(axe),會一直換人,當舊的紅牌不準時,就會出現新的紅牌,這種詭異的狀況一直重複上演,而大多數的投資人卻沒發現。其實 axe 都撐不了太久,不用太認真對待
  25. 理財顧問常從Backtest (歷史回測)得出的大發現,只不過是統計上的僥倖罷了,這只會出現在樣本中,無法代表全體。
  26. 當理財顧問提出一些令人經驗的歷史數據給你,你該問幾個問題
    1. 這些數據是 backtest 嗎?
    2. 這些是多久以前的數據?
    3. 你是什麼時候開始用真正的錢實際操作這個策略?
    4. 你有更改過這項策略嗎?如果有為什麼?
    5. 決定採用這個策略前,你還試過其他多少策略?
  27. 價格走跌階段必然也意味著日後會有上漲階段。一般認為,股市平均下跌至少 20% 就算是 bear market 的開始,不過其實也沒有什麼正式的定義或門檻
  28. 一心想要 beat the market (打敗大盤)的人,通常都會被大盤所打敗
  29. Beta 係數是指某一支股票的報酬率跟大盤指數報酬的連動性。例如如果某一檔股票的 beta 係數是1.0,當大盤指數上漲 10% 時,該股票的報酬率則為 10%;若 beta 係數是 1.5 ,該檔股票在指數下跌 10% 時,會虧損 15%。依此類推, beta 係數越高,風險和報酬也越高。不過這參考看看就好,風險的部分是屢試不爽,報酬的部份則是難得一見
  30. 企業可透過操控可調節的會計項目,提前或過度認列費用和成本,以製造後來營利回彈的假象

2017/05/01

[閱讀筆記] Waltzing with Bears (2/2)


  1. 普遍的軟體專案的風險:
    1. 先天的時程規劃錯誤(schedule flaw)
    2. 需求膨脹(requirement inflation)
    3. 人力流失(employee turnover)
    4. 規格崩潰(specification breakdown)
    5. 低生產力(poor productivity)
  2. 常見的五個普遍的軟體專案風險,只有最後一項真正跟員工的工作表現有關,其餘四項都跟做得多辛苦、多精明幹練無關
  3. 預先為無法捉摸的事物進行合理的準備,正式風險管理的核心,預先準備並不能讓妳為失敗開脫,只能在風險造成威脅時保有緩衝的餘地
  4. 時程規劃錯誤是指時間的安排有缺陷,這是時程本身的錯誤,而非專案執行的錯誤。時程錯誤不僅是真正的風險,也是五個核心風險中對專案衝擊最大的。
  5. 七個月的專案最後卻做了十二個月,生氣的高階主管很少會怪時程規劃的人,相反的,他們會怪人員沒有盡力
  6. 從專案的角度來看,刪除某些已經做好的功能,也算是一種需求膨脹,因為這同樣增加了額外的工作負擔
  7. 在規劃時程時,常會忽略需求膨脹的議題。高階主管也不會管,類似的說詞是:客戶要X,預估十個月後交付;若你發現還要X以外的東西,那就是你的問題了
  8. 處理人員流失,你必須知道:
    1. 公司技術人員的每年平均流動率
    2. 接替人員完全進入狀況時間(ramp-up time)的預估值。想辦法做好教育訓練與技術文件,降低進入門檻
  9. 規格崩潰往往溯及專案初期談判過程的失敗,而談判正是需求界定的中心
  10. 界定需求時,為了避免與利害關係人有衝突,常會將一些關鍵的、有爭議的的問題模糊化。被掩飾的問題暫時不見,不代表永遠不見。界定需求也許可以搞得模糊,但是開發階段可模糊不得。最糟糕的是,這些問題都是專案後期才會發生,這個節骨眼幾乎是將預算與時間耗盡的階段,常給專案致命一擊
  11. 閉口不談風險,並不會讓風險消失
  12. 在工作上,我們都被要求保有can do 的態度,問題就在這;討論風險是一種cannot do 的思維,往往風險探索會背離組織的主流意見。組織要有開放的文化,讓負面言論有說出來的可能
  13. 「明確過程」有明確步驟、可預測的程序,相當於white box 。經驗過程則相當於black box,是經由不斷的觀察與驗證後,以經驗來調整輸入,進而產生滿意的輸出
  14. 風險舒緩是預先採取的一套作為,萬一風險成形,便可有效的、快速的處理風險
  15. 有風險認知的管理者,會優先考量含有重大技術風險的部分,這非常合理,不過也有違大部分管理者的本性,因為會太早暴露他們在這場競賽中的弱點。這就是為什麼對如此棘手的問題,他們總是秘而不宣,一拖再拖
  16. 如果系統有哪個部分必須仰賴技術上的突破才能完成,就該把它納入早期版本,到時候就算突破不了,應變選擇也會擁有最大的彈性。假如夠早,也許私下承受一點損失即可;反之,若把相同的挫折放到專案後期,影響層面將會擴大到每一個人
  17. 漸進式交付是降低軟體專案風險的好方法,其是由三種artifacts所構成:
    1. 設計藍圖:顯示要識做的最低階模組或類別,以及彼此之間的關係
    2. WBS(Work Breakdown Structure):顯示要完成的工作,以及彼此之間的相依關係
    3. VAT (Version Acceptance Test):把產品的總驗收測試按照版本細分,顯示哪個測試可用在哪個中間產品上
  18. 冒險的積極程度必須由報酬而決定。你願意冒多少風險,端視你可以得到多少報酬而定
  19. 對複雜、不確定性頗高的問題,建立模型來估算各種變因對結果的敏感性,即為敏感性分析
  20. 軟體專案常會呈現規模不經濟(diseconomieis of scale)的特徵:若系統規模增加為兩倍,則實際系統開發耗費的心力會超過兩倍
  21. 擴大產品規模,成本增加的幅度就會更大;那麼縮小產品規模,便很可能可以大幅節省開支。刪除系統中屬於低價值 / 成本比的部份,也許是紓解時程和預算壓力最簡單且直接的方法
  22. 有些軟體專案,都是以專案的重要性來為死亡行軍的正當性辯護:這次的任務太重要了,請全體專案人員放棄個人生活、超量加班,就算是最後一滴血也要榨乾。但是,既然這個專案有這麼重要,為什麼公司不願意分配合理的時間與金錢來做呢?
  23. 公司很排斥將軟體專案價值量化,隱瞞做這個專案會產生的價值的期望值,如此才有可能在縮減開發成本的情況下完成專案,這是很重要的理由,「我們要把成本壓低,低到不論做出多少價值的東西都划得來」