Total Pageviews

2017/04/30

2017/04 Travel

台北燈會
DSC01401

DSC01409

DSC01405

DSC01460

DSC01445

中山堂光雕秀
DSC01420

DSC01423

DSC01424

2017/04/10

[webMethods] 如何在 Java Service 中,將資料寫入 Integration Server 中的 Cache

Problem
假設我們已經在 Integration Server 中,在 Public Cache Managers 中建立一個名為 Test 的 Cache Manager,並於 Test 中建立一個名為 hello 的 cache



若我們希望在 Java Service 中,用 webMethods 提供的套件來:
1. 新增資料到 cache
2. 從 cache 中取出資料
3. 移除 cache 中的資料  


該如何做?



How-to

以下是 sample code:
// --- <<IS-BEGIN-SHARED-SOURCE-AREA>> ---
    
    private static final String cacheManagerName = "Test";
    private static final String cacheName = "hello";
    
    public static void addValueToCacheByKey(IData pipeline, String key, Object value) throws ServiceException {
        IDataCursor cursor = pipeline.getCursor();
    
        IDataUtil.put(cursor, "cacheManagerName", cacheManagerName);
        IDataUtil.put(cursor, "cacheName", cacheName);
        IDataUtil.put(cursor, "key", key);
        IDataUtil.put(cursor, "value", value);
    
        try {
            Service.doInvoke("pub.cache", "put", pipeline);
        } catch (Exception e) {
            throw new ServiceException(e);
        }
        cursor.destroy();
    }
    
    public static Object getValueFromCacheByKey(IData pipeline, String key) throws ServiceException {
        IDataCursor cursor = pipeline.getCursor();
    
        IDataUtil.put(cursor, "cacheManagerName", cacheManagerName);
        IDataUtil.put(cursor, "cacheName", cacheName);
        IDataUtil.put(cursor, "key", key);
        
        IData data = null;
        try {
            data = Service.doInvoke("pub.cache", "get", pipeline);
        } catch (Exception e) {
            throw new ServiceException(e);
        }
        Object result = IDataUtil.get(data.getCursor(), "value");
        
        cursor.destroy();
        
        return result;
    }
    
    public static void removeCacheByKey(IData pipeline, String key) throws ServiceException {
        IDataCursor cursor = pipeline.getCursor();
        
        IDataUtil.put(cursor, "cacheManagerName", cacheManagerName);
        IDataUtil.put(cursor, "cacheName", cacheName);
        IDataUtil.put(cursor, "key", key);
        
        try {
            Service.doInvoke("pub.cache", "remove", pipeline);
        } catch (Exception e) {
            throw new ServiceException(e);
        }
    }   
    // --- <<IS-END-SHARED-SOURCE-AREA>> ---




2017/04/09

[webMethods] 如何設定在 Integration Server 啟動時,執行 Java Service

Problem
假設我們有一個 OPC Connection 的 Java Service,我們希望這個 Java Service 在啟動 integration server 時,順便啟動此 OPC_Connection Java Service,取得OPC connection,完成初始化的相關動作


How-to
步驟1. 點選要設定的 Java Service 所屬的 package,按下右鍵,並選擇Property



步驟2. 在 dialog 中,點選最後一個選項 (Startup / Shutdown Services),在 Startup Services 處,將 OPC_Connection Service 選取到 Selected services,按下 OK (若要將 flow service 設定為 startup service,其程序相同)


步驟3. 重啟 Integration Server,可以到 administration console 中看到 OPC_Connection 印出的 log



若日後有更動 folder 位置,記得要重做步驟 1 與步驟 2,Designer不會自動更新 service 的位置,會出現以下錯誤
Startup service acme.albert.adapters:OPC_Connection was not found in Acme package


2017/04/08

[webMethods] 如何在Designer 中 create 的 Java Service,使用已經寫好的外部的Java Class

步驟1. 先將所寫好的程式包成一個 jar file


步驟2. 將包好的 jar file 與其相依賴的 jar files 放到 ESB 特定package的目錄中 (即 [integration_server_dir]/packages/[your_pacakge_name]/code/jars ),並重啟 webMethods Integration Server

步驟3. 在出現編譯錯誤的程式碼,按下修正錯誤,點選 Fix project setup...



步驟4. 點選 here



步驟5. 點選 Add External Jars


步驟6. 選取所需用到的 jar files,按下開啟舊檔



步驟7. 按下 OK



步驟8. 此時即可 import 我所寫好的 Java class




若日後有更動外部的Java code,步驟如下:

步驟1. 先將所寫好的程式包成一個 jar file

步驟2. 將包好的 jar file 放到 ESB 特定 package 的目錄中,並重啟 webMethods Integration Server


步驟3. 將 jar file 更新到你的 Designer 會用到的 library directory

步驟4. 點選目前正在開發的 package,點選右鍵並按下 Reload Package,這樣 Designer 裡就可以用到最新版本的 Java code

2017/04/07

[webMethods] 如何安裝 Designer 工具

Installation Steps
1. 執行 installer,等待出現 installation window 以後,點選 Advanced Options


2. 點選 Images tab、勾選 Use installation image、選取要安裝的 image file,先點選 Validate Image 確定所選取的 image file 是否完整,確認 image file 是正確的才點選 OK



3. 選擇要安裝的 Installation directory,點選 Next



4. 選擇要安裝的 packages,點選 Next



5. 點選 checkbox,按下 Next




6. 選取 trial license file,按下 Next



7. 直接按下 Next



8. 直接按下 Next



9. 直接按下 Next



10. 此步驟需要等待數分鐘



11. 安裝完成畫面,按下 Close 即可完成安裝步驟




Designer Configuration Steps

1. 啟動 Designer 工具


2. Window => Preferences






3. 點選 Integration Servers 的選項



4. 輸入你要連線的 Integration Server 的 IP、Port、User name、Password,點選 Verify Server 可以檢查是否可以正常連上 Integration Server,按下 OK 即可完成設定


5. 完成設定後,若可以正常連上 Integration Server,Status 會顯示 Connected



Reference

[1] http://techcommunity.softwareag.com/pwiki/-/wiki/Main/Guide+to+Downloading+and+installing+the+webMethods+Free+Trial+Version

2017/04/06

[Failsafe] Retry with backoff

Problem
I would like do retry if I fail to connect to database.  
My requirement is 
  • retry 5 times at most and sleep 5 second then retry again
  • Sets the delay between retries (i.e. 5 seconds), exponentially backing off to the maxDelay (i.e. 120 seconds) and multiplying successive delays by the delayFactor (i.e. 2).

How-to
Here has the sample code:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
package albert.practice.retry;

import java.sql.Connection;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.TimeUnit;

import lombok.extern.slf4j.Slf4j;
import net.jodah.failsafe.Failsafe;
import net.jodah.failsafe.RetryPolicy;

@Slf4j
public class RetryTest {

    private int count = 0;

    public static void main(String[] args) throws ConnectionException {
        new RetryTest().connectWithRetry();
    }

    public Connection connectWithRetry() {
        // create a retry policy with 5 max retries and have 2 seconds delay among retries
        RetryPolicy retryPolicy = new RetryPolicy();

        // create a retry policy and sets the delay 5 seconds between retries, exponentially backing off to the maxDelay 120
        // seconds and multiplying successive delays by the delayFactor 2.
        retryPolicy.retryOn(ConnectionException.class).withMaxRetries(5).withBackoff(5, 120,
                TimeUnit.SECONDS, 2);

        // Using Fallbacks allow you to provide an alternative result for a failed execution.
        // In this example, it will retry again after 5 seconds.
        Connection conn = Failsafe.with(retryPolicy).withFallback(() -> retryIfFail())
                .get(() -> connect());

        return conn;
    }

    public void retryIfFail() throws InterruptedException {
        log.debug("GG at " + getCurrentTime());
        Thread.sleep(5000);

        log.debug("retry....." + getCurrentTime());
        connectWithRetry();
    }

    public Connection connect() throws ConnectionException {
        log.debug(" time = " + getCurrentTime());
        Connection conn = null;
        if (count < 9) {
            count++;
            throw new ConnectionException("connection fail!");
        } else {
            log.debug("get connection successfuly...");
        }
        return conn;
    }

    private String getCurrentTime() {
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss.SSS");
        return dateFormat.format(new Date());
    }
}

Execution log:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
[main] DEBUG albert.practice.retry.RetryTest -  time = 2016/11/23 17:31:51.495
[main] DEBUG albert.practice.retry.RetryTest -  time = 2016/11/23 17:32:01.509
[main] DEBUG albert.practice.retry.RetryTest -  time = 2016/11/23 17:32:21.515
[main] DEBUG albert.practice.retry.RetryTest -  time = 2016/11/23 17:33:01.498
[main] DEBUG albert.practice.retry.RetryTest -  time = 2016/11/23 17:34:21.499
[main] DEBUG albert.practice.retry.RetryTest -  time = 2016/11/23 17:36:21.539
[main] DEBUG albert.practice.retry.RetryTest - GG at 2016/11/23 17:36:21.539
[main] DEBUG albert.practice.retry.RetryTest - retry.....2016/11/23 17:36:26.545
[main] DEBUG albert.practice.retry.RetryTest -  time = 2016/11/23 17:36:26.545
[main] DEBUG albert.practice.retry.RetryTest -  time = 2016/11/23 17:36:36.554
[main] DEBUG albert.practice.retry.RetryTest -  time = 2016/11/23 17:36:56.564
[main] DEBUG albert.practice.retry.RetryTest -  time = 2016/11/23 17:37:36.571
[main] DEBUG albert.practice.retry.RetryTest - get connection successfuly...

2017/04/05

[Failsafe] Retry with Fallback

Scenario
If we cannot get connection, then we will retry 5 times with 2 seconds delay.
If we fail to retry with 5 times, then we will pause X minutes then retry again.
How to implement it?


How-to
You can make good use of failsafe to fulfill this implement.
In this exampe, it will demonstrate:
1. create a retry policy with 5 max retries and have 2 seconds delay among retries
2. If you got failed execution, it will retry again after 5 seconds.
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
package albert.practice.retry;

import java.sql.Connection;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.TimeUnit;

import lombok.extern.slf4j.Slf4j;
import net.jodah.failsafe.Failsafe;
import net.jodah.failsafe.RetryPolicy;

@Slf4j
public class RetryTest {

    private int count = 0;

    public static void main(String[] args) throws ConnectionException {
        new RetryTest().connectWithRetry();
    }

    public Connection connectWithRetry() {
        // create a retry policy with 5 max retries and have 2 seconds delay among retries 
        RetryPolicy retryPolicy = new RetryPolicy();
        retryPolicy.retryOn(ConnectionException.class).withDelay(2, TimeUnit.SECONDS)
                .withMaxRetries(5);

        // Using Fallbacks allow you to provide an alternative result for a failed execution. 
        // In this example, it will retry again after 5 seconds.
        Connection conn = Failsafe.with(retryPolicy).withFallback(() -> retryIfFail())
                .get(() -> connect());

        return conn;
    }

    public void retryIfFail() throws InterruptedException {
        log.debug("GG at " + getCurrentTime());
        Thread.sleep(5000);

        log.debug("retry....." + getCurrentTime());
        connectWithRetry();
    }

    public Connection connect() throws ConnectionException {
        log.debug(" time = " + getCurrentTime());
        Connection conn = null;
        if (count < 9) {
            count++;
            throw new ConnectionException("connection fail!");
        } else {
            log.debug("get connection successfuly...");
        }
        return conn;
    }

    private String getCurrentTime() {
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss.SSS");
        return dateFormat.format(new Date());
    }
}


Console log:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
DEBUG albert.practice.retry.RetryTest -  time = 2016/11/05 11:42:13.832
DEBUG albert.practice.retry.RetryTest -  time = 2016/11/05 11:42:15.837
DEBUG albert.practice.retry.RetryTest -  time = 2016/11/05 11:42:17.837
DEBUG albert.practice.retry.RetryTest -  time = 2016/11/05 11:42:19.837
DEBUG albert.practice.retry.RetryTest -  time = 2016/11/05 11:42:21.838
DEBUG albert.practice.retry.RetryTest -  time = 2016/11/05 11:42:23.839
DEBUG albert.practice.retry.RetryTest - GG at 2016/11/05 11:42:23.839
DEBUG albert.practice.retry.RetryTest - retry.....2016/11/05 11:42:28.839
DEBUG albert.practice.retry.RetryTest -  time = 2016/11/05 11:42:28.839
DEBUG albert.practice.retry.RetryTest -  time = 2016/11/05 11:42:30.839
DEBUG albert.practice.retry.RetryTest -  time = 2016/11/05 11:42:32.839
DEBUG albert.practice.retry.RetryTest -  time = 2016/11/05 11:42:34.840
DEBUG albert.practice.retry.RetryTest - get connection successfuly...

Reference
[1] https://github.com/jhalterman/failsafe#fallbacks

2017/04/04

[Angular2] fail to load data items in ng2-select component

Problem
I am using ng2-select to implement a dropdown list function.
But my dropdown list cannot be showed just like the example:


Here is my code snippet:
   <div class="row">
    <div class="col-sm-12">
        <div class="form-group">
           <label> 負責人員 </label>
           <div style="width: 300px; margin-bottom: 20px;">
              <ng-select [allowClear]="true" 
                         [items]="items" 
                         [data]="selectedItem"
                         (data)="refreshValue($event)" 
                         (selected)="selected($event)"
                         (removed)="removed($event)" 
                         placeholder="請選擇負責人員">
              </ng-select>
           </div>
        </div>
    </div>
   </div>


How-to
Owning to the data items in ng2-select example is static:

The data items in my function which will retrieve them from 
database, so we need to wait until data items had been finished then create the DOM element.

Owing to I do not know how long I need to wait, so I add *ngIf in the first div tag.
   <div class="row" *ngIf="items && items.length > 0">
    <div class="col-sm-12">
        <div class="form-group">
           <label> 負責人員 </label>
           <div style="width: 300px; margin-bottom: 20px;">
              <ng-select [allowClear]="true" 
                         [items]="items" 
                         [data]="selectedItem"
                         (data)="refreshValue($event)" 
                         (selected)="selected($event)"
                         (removed)="removed($event)" 
                         placeholder="請選擇負責人員">
              </ng-select>
           </div>
        </div>
    </div>
   </div>


Reference
[1] https://valor-software.com/ng2-select/


2017/04/03

[UML] How to Draw a Scheduler Service in Sequence Diagram

Problem
Assume I have a HeartBeatService and HeartbeatProducerService.
HeartBeatService will call HeartbeatProducerService every 5 seconds to check system is alive or not. 

How to show this kind of scheduler job in sequence diagram.


How-to
You can add a loop combined fragment in sequence diagram, it looks like:



2017/04/02

[Failsafe] Simple, sophisticated failure handling

Scenario
We have a Java application to connect to OPC server, if it fail to connect to OPC server it will retry 5 times.


How-to
You can make good use of Failsafe to fulfill this requirement. 
Failsafe is a lightweight, zero-dependency library for handling failures. It was designed to be as easy to use as possible, with a concise API for handling everyday use cases and the flexibility to handle everything else.

Maven dependency:
1
2
3
4
5
6
7
<dependencies>
   <dependency>
      <groupId>net.jodah</groupId>
      <artifactId>failsafe</artifactId>
      <version>0.9.5</version>
   </dependency>
</dependencies>


If I catch ConnectionException, it will do retry, the retry policy is as bellows:

  • it will delay 2 seconds between retries
  • it will retry 5 times at most


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
package albert.practice.retry;

import java.util.Calendar;
import java.util.Date;
import java.util.concurrent.TimeUnit;

import lombok.extern.slf4j.Slf4j;
import net.jodah.failsafe.Failsafe;
import net.jodah.failsafe.RetryPolicy;

@Slf4j
public class RetryTest {

    public static void main(String[] args) throws ConnectionException {
        @SuppressWarnings("unchecked")
        RetryPolicy retryPolicy = new RetryPolicy().retryOn(ConnectionException.class)
                .withDelay(2, TimeUnit.SECONDS).withMaxRetries(5);
        Failsafe.with(retryPolicy).run(() -> new RetryTest().connect());
    }

    public void connect() throws ConnectionException {
        log.debug("time=" + new Date(Calendar.getInstance().getTimeInMillis()));
        if (true) {
             throw new ConnectionException("connection fail!");
        }
    }
}



Reference
[1] https://github.com/jhalterman/failsafe