Total Pageviews

2016/06/09

[WAS] WSVR0605W - "Thread may be hung"

Problem
I'm running my web application on IBM WebSphere.
There is a warning message in System.out.log :
 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
[4/25/16 17:16:03:756 CST] 00000068 SystemOut     O [2016-04-25 17:16:03][WARN][Deferrable Alarm : 1][Line:1709][com.ibm.ws.runtime.component.ThreadMonitorImpl.logToJSR47Logger]WSVR0605W: Thread "WebContainer : 6" (000000d3) has been active for 667,910 milliseconds and may be hung.  There is/are 1 thread(s) in total in the server that may be hung.
    at java.io.RandomAccessFile.readBytes(Native Method)
    at java.io.RandomAccessFile.read(RandomAccessFile.java:368)
    at org.apache.fontbox.ttf.BufferedRandomAccessFile.fillBuffer(BufferedRandomAccessFile.java:122)
    at org.apache.fontbox.ttf.BufferedRandomAccessFile.read(BufferedRandomAccessFile.java:160)
    at org.apache.fontbox.ttf.RAFDataStream.read(RAFDataStream.java:162)
    at org.apache.fontbox.ttf.TTFDataStream.read(TTFDataStream.java:263)
    at org.apache.fontbox.ttf.TTFDataStream.readString(TTFDataStream.java:91)
    at org.apache.fontbox.ttf.TTFDataStream.readString(TTFDataStream.java:64)
    at org.apache.fontbox.ttf.TTFParser.readTableDirectory(TTFParser.java:232)
    at org.apache.fontbox.ttf.TTFParser.parse(TTFParser.java:139)
    at org.apache.fontbox.ttf.TTFParser.parse(TTFParser.java:87)
    at org.apache.pdfbox.pdmodel.font.FileSystemFontProvider.addTrueTypeFont(FileSystemFontProvider.java:502)
    at org.apache.pdfbox.pdmodel.font.FileSystemFontProvider.scanFonts(FileSystemFontProvider.java:246)
    at org.apache.pdfbox.pdmodel.font.FileSystemFontProvider.<init>(FileSystemFontProvider.java:225)
    at org.apache.pdfbox.pdmodel.font.FontMapperImpl$DefaultFontProvider.<clinit>(FontMapperImpl.java:132)
    at java.lang.J9VMInternals.initializeImpl(Native Method)
    at java.lang.J9VMInternals.initialize(J9VMInternals.java:236)
    at org.apache.pdfbox.pdmodel.font.FontMapperImpl.getProvider(FontMapperImpl.java:151)
    at org.apache.pdfbox.pdmodel.font.FontMapperImpl.findFont(FontMapperImpl.java:415)
    at org.apache.pdfbox.pdmodel.font.FontMapperImpl.getTrueTypeFont(FontMapperImpl.java:323)
    at org.apache.pdfbox.pdmodel.font.PDTrueTypeFont.<init>(PDTrueTypeFont.java:198)
    at org.apache.pdfbox.pdmodel.font.PDFontFactory.createFont(PDFontFactory.java:75)
    at org.apache.pdfbox.pdmodel.PDResources.getFont(PDResources.java:123)
    at org.apache.pdfbox.contentstream.operator.text.SetFontAndSize.process(SetFontAndSize.java:60)
    at org.apache.pdfbox.contentstream.PDFStreamEngine.processOperator(PDFStreamEngine.java:815)
    at org.apache.pdfbox.contentstream.PDFStreamEngine.processStreamOperators(PDFStreamEngine.java:472)
    at org.apache.pdfbox.contentstream.PDFStreamEngine.processStream(PDFStreamEngine.java:446)
    at org.apache.pdfbox.contentstream.PDFStreamEngine.processPage(PDFStreamEngine.java:149)
    at org.apache.pdfbox.rendering.PageDrawer.drawPage(PageDrawer.java:189)
    at org.apache.pdfbox.rendering.PDFRenderer.renderPage(PDFRenderer.java:208)
    at org.apache.pdfbox.rendering.PDFRenderer.renderImage(PDFRenderer.java:139)
    at org.apache.pdfbox.rendering.PDFRenderer.renderImageWithDPI(PDFRenderer.java:94)

And my function is hung after I click execute button.


How-to
You need to log into WAS administration console, then go to Servers > Application Servers > server_name. Click Administration > Custom Properties Under Server Infrastructure.

And add four arbitrates

  • com.ibm.websphere.threadmonitor.interval: 180
  • com.ibm.websphere.threadmonitor.threshold: 600
  • com.ibm.websphere.threadmonitor.false.alarm.threshold: 100
  • com.ibm.websphere.threadmonitor.dump.java: false



Remember to save attributes and restart WAS.

But this is just a workaround solution, it may means your programs may consume lots of memory for some reasons. You still need to figure out its root causes and fix them.


Reference
[1] http://websphere-solutions.blogspot.tw/2011/10/hung-threads.html

2016/06/08

[AngularJS] How to add tooltips in ng-grid

Problem
I implemented a data grid by ng-grid as bellows:


The problem is if the length of data is larger than the width of column, it will show ... then ignore the rest of information. Our customer requests to show complete information in tooltips as he/she move cursor on it.

The code snippet of ng-grid looks like:
 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
$scope.gridCols  = [ 
 {
     field : 'sourceName',
     width : '10%',
     displayName : '來源系統',
     cellClass : 'text-left'
 }, {
     field : 'policyNumber',
     width : '10%',
     displayName : '保單號碼',
     cellClass : 'text-left'
 },{
     field : 'exeMsg',
     width : '65%',
     displayName : '執行訊息',
     cellClass : 'text-left'
 },{
     field : 'exeTime',
     width : '15%',
     displayName : '執行時間',
     cellFilter : "date:'yyyy-MM-dd HH:mm:ss'",
     cellClass : 'text-left'
 }];
 
 $scope.dataGrid = {
     multiSelect : false,
     data : 'itemData',
     columnDefs : 'gridCols',
     enableColumnResize: true,
     enableRowSelection: true,
     rowHeight : 40
 };


How-to
There has two steps to fulfill this requirement.
Step 1. add css in HTML page
1
2
3
4
5
6
7
   <style type="text/css">
    .tooltip-inner {
      text-align: left;
      white-space: pre-wrap;
      max-width: none;
    }
    </style>

Step 2. Modify the ng-grid, and add cellTemplate to show complete information
 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
 var exeMsgCellTemplate='<span tooltip="{{row.entity.exeMsg}}" tooltip-append-to-body="true" tooltip-trigger:"focus"><div style="vertical-align : middle;"  class="ngCellText">{{row.entity.exeMsg}}</div></span>';
 var exeTimeCellTemplate='<span tooltip="{{row.entity.exeTime|date:\'yyyy-MM-dd HH:mm:ss\'}}" tooltip-append-to-body="true" tooltip-trigger:"focus"><div style="vertical-align : middle;"  class="ngCellText">{{row.entity.exeTime|date:\'yyyy-MM-dd HH:mm:ss\'}}</div></span>';
               
 $scope.gridCols  = [ 
 {
     field : 'sourceName',
     width : '10%',
     displayName : '來源系統',
     cellClass : 'text-left'
 }, {
     field : 'policyNumber',
     width : '10%',
     displayName : '保單號碼',
     cellClass : 'text-left'
 },{
     field : 'exeMsg',
     width : '65%',
     displayName : '執行訊息',
     cellClass : 'text-left',
     cellTemplate : exeMsgCellTemplate
 },{
     field : 'exeTime',
     width : '15%',
     displayName : '執行時間',
     cellFilter : "date:'yyyy-MM-dd HH:mm:ss'",
     cellClass : 'text-left',
     cellTemplate : exeTimeCellTemplate
 }];
 
 $scope.dataGrid = {
     multiSelect : false,
     data : 'itemData',
     columnDefs : 'gridCols',
     enableColumnResize: true,
     enableRowSelection: true,
     rowHeight : 40
 };



Check the result:





Reference
[1] http://www.w3schools.com/cssref/pr_text_white-space.asp



2016/06/07

[PDFBox] Utilize Apache PDFBox to Convert PDF to TIF

Requirement
We have an requirement to convert a PDF file to TIF file(s). 
If PDF has 3 pages, it should generate 3 TIF files with 300 DPI. 
For instance, a Getting Started.pdf has 4 pages,it should convert to 4 TIF files, including Getting Started.pdf_01.tifGetting Started.pdf_02.tifGetting Started.pdf_03.tif, and Getting Started.pdf_04.tif.


How-to
We can utilize Apache PDFBox to fulfill this requirement.

You should add maven dependency in your pom.xml
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
        <dependency>
            <groupId>org.apache.pdfbox</groupId>
            <artifactId>pdfbox-tools</artifactId>
            <version>2.0.0</version>
        </dependency>
        
        <dependency>
            <groupId>com.github.jai-imageio</groupId>
            <artifactId>jai-imageio-core</artifactId>
            <version>1.3.1</version>
        </dependency>


Sample code looks like:

 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
63
64
65
66
67
68
69
70
71
72
package albert.practice.file;

import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;

import lombok.extern.slf4j.Slf4j;

import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.rendering.ImageType;
import org.apache.pdfbox.rendering.PDFRenderer;
import org.apache.pdfbox.tools.imageio.ImageIOUtil;

@Slf4j
public class PdfFileToTif {

    private final float dpi = 300f;

    public static void main(String[] args) {
        File pdfFile = new File("D:\\dropbox\\Getting Started.pdf");
        String destination = "D:\\dropbox\\";

        PdfFileToTif test = new PdfFileToTif();
        test.convertPdfToTif(pdfFile, destination);
    }

    public void convertPdfToTif(File pdfFile, String destination) {
        if (!isFileExisted(pdfFile)) {
            throw new RuntimeException("File not found ! (" + pdfFile.getAbsolutePath() + ")");
        }

        String pdfFileName = pdfFile.getName();

        try {
            // load PDF document
            PDDocument document = PDDocument.load(pdfFile);

            // create PDF renderer
            PDFRenderer renderer = new PDFRenderer(document);

            // go through each page of PDF, and generate TIF for each PDF page.
            for (int i = 0; i < document.getNumberOfPages(); i++) {
                // Returns the given page as an RGB image with 300 DPI.
                BufferedImage image = renderer.renderImageWithDPI(i, dpi, ImageType.BINARY);

                // Assign the file name of TIF
                String fileName = pdfFileName + "_" + String.format("%02d", i + 1);
                log.debug("Generating  " + fileName + ".tif to " + destination);

                // Writes a buffered image to a file using the given image format.
                ImageIOUtil.writeImage(image, destination + fileName + ".tif", Math.round(dpi));
                image.flush();
            }
            log.debug("PDF to TIF conversion well done!");
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 判斷檔案是否存在
     * 
     * @param file
     * @return true - 檔案存在; false - 檔案不存在
     */
    private Boolean isFileExisted(File file) {
        Boolean isExisted = Boolean.FALSE;
        isExisted = (file.exists() && (!file.isDirectory()));
        return isExisted;
    }

}


Reference
[1] https://pdfbox.apache.org/

2016/06/06

[Java] Encryption and Decryption with AES

Problem
If we have to save some configuration-related data into database table, our customer asks us to do encryption before we save into database if it is password-related information.

Some other function will retrieve user name and password to do authentication, we need to do decryption .


Solution
Here has sample code, using AES to do encryption and decryption:
 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
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
package albert.practice.encrypt;

import java.security.GeneralSecurityException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.SecretKeySpec;

import lombok.extern.slf4j.Slf4j;

import org.apache.commons.codec.binary.Base64;

@Slf4j
public class AESUtils {

    private static String secretKey = "your key";

    public static String encryptText(String plainText) {
        byte[] raw;
        String encryptedString = "";
        SecretKeySpec skeySpec;
        byte[] encryptText = plainText.getBytes();
        Cipher cipher;
        raw = Base64.decodeBase64(secretKey);
        skeySpec = new SecretKeySpec(raw, "AES");
        try {
            cipher = Cipher.getInstance("AES");
            cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
            encryptedString = Base64.encodeBase64String(cipher.doFinal(encryptText));
        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException(e);
        } catch (NoSuchPaddingException e) {
            throw new RuntimeException(e);
        } catch (InvalidKeyException e) {
            throw new RuntimeException(e);
        } catch (IllegalBlockSizeException e) {
            throw new RuntimeException(e);
        } catch (BadPaddingException e) {
            throw new RuntimeException(e);
        }

        return encryptedString;

    }

    public static String decryptText(String encryptedText) {
        Cipher cipher;
        String encryptedString;
        byte[] encryptText = null;
        byte[] raw;
        SecretKeySpec skeySpec;
        raw = Base64.decodeBase64(secretKey);
        skeySpec = new SecretKeySpec(raw, "AES");
        encryptText = Base64.decodeBase64(encryptedText);
        try {
            cipher = Cipher.getInstance("AES");
            cipher.init(Cipher.DECRYPT_MODE, skeySpec);
            encryptedString = new String(cipher.doFinal(encryptText));
        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException(e);
        } catch (NoSuchPaddingException e) {
            throw new RuntimeException(e);
        } catch (InvalidKeyException e) {
            throw new RuntimeException(e);
        } catch (IllegalBlockSizeException e) {
            throw new RuntimeException(e);
        } catch (BadPaddingException e) {
            throw new RuntimeException(e);
        }

        return encryptedString;
    }

    public static void main(String[] args) throws NoSuchPaddingException, GeneralSecurityException {
        String plainText = "test123";
        String encryptedText = AESUtils.encryptText(plainText);
        String decryptedText = AESUtils.decryptText(encryptedText);

        log.debug("plainText = " + plainText);
        log.debug("encryptedText = " + encryptedText);
        log.debug("decryptedText = " + decryptedText);
    }
}

Execution result:
1
2
3
2016-04-20 14:06:50.239 [main] DEBUG albert.practice.encrypt.AESUtils - plainText = test123
2016-04-20 14:06:50.255 [main] DEBUG albert.practice.encrypt.AESUtils - encryptedText = P25QKVFoX00OXs5GMOTAhg==
2016-04-20 14:06:50.255 [main] DEBUG albert.practice.encrypt.AESUtils - decryptedText = test123


Reference
[1] http://stackoverflow.com/questions/17567996/illegal-block-size-exception-input-length-must-be-multiple-of-16-when-decrypting

2016/06/05

[Java] error: unmappable character for encoding MS950

Problem
As I try to compile Java class via command line, it throws unmappable character for encoding MS950 error as bellows:


How-to
Assign encoding as you compile:


Reference
[1] http://silverbulletwo.blogspot.tw/2014/11/java-error-unmappable-character-for.html

2016/06/04

[Spring Framework] Caching in Spring (Using GuavaCache)

Problem
I'm using default cache in Spring framework. 
 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
package com.xxx.cache;

import org.springframework.cache.CacheManager;
import org.springframework.cache.concurrent.ConcurrentMapCacheManager;

// http://www.baeldung.com/spring-cache-tutorial
/*
 * To enable caching, Spring makes good use of annotations, much like enabling any other
 * configuration level feature in the framework.
 * 
 * The caching feature can be declaratively enabled by simply adding the @EnableCaching annotation
 * to any of the configuration classes:
 */
@Configuration
@EnableCaching
public class CacheConfig {

    @Bean
    public CacheManager cacheManager() {
        String cacheNames[] = new String[] { "comConfig" };
        // Construct a static ConcurrentMapCacheManager, managing caches for the specified cache
        // names only.
        return new ConcurrentMapCacheManager(cacheNames);
    }

}

If I would like to set the TTL of chache (ex. 1 minute), how to do it?


How-to
Here is 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
package com.xxx.cache;

import java.util.concurrent.TimeUnit;

import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.guava.GuavaCacheManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import com.google.common.cache.CacheBuilder;
import com.google.common.collect.ImmutableList;

@Configuration
@EnableCaching
public class CacheConfig {

    @Bean
    public CacheManager cacheManager() {
        // instantiate GuavaCacheManager
        GuavaCacheManager cacheManager = new GuavaCacheManager();
  
        // set expire time to 1 minute
        cacheManager.setCacheBuilder(CacheBuilder.newBuilder().expireAfterAccess(1,
                TimeUnit.MINUTES));
        
        // set cache name    
        cacheManager.setCacheNames(ImmutableList.of("comConfig"));

        return cacheManager;
    }
}


Reference
[1] https://dzone.com/articles/spring-caching-abstraction-and

2016/06/03

[Spring Framework] Caching in Spring

Problem
If I have a table which is used for the purpose of configuration. For example, if I provide an email service, we must have some information which does not change frequently (ex. smtp, port). 

In this case, we hope email service can retrieve data from cache instead of accessing database, except it had been changed.

How-To
1. create a Cache config class to enable caching.
 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
package com.xxx.ecp.commons.service.cache;

import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.concurrent.ConcurrentMapCacheManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

// http://www.baeldung.com/spring-cache-tutorial
/*
 * To enable caching, Spring makes good use of annotations, much like enabling any other
 * configuration level feature in the framework.
 * 
 * The caching feature can be declaratively enabled by simply adding the @EnableCaching annotation
 * to any of the configuration classes:
 */
@Configuration
@EnableCaching
public class CacheConfig {

    @Bean
    public CacheManager cacheManager() {
        String cacheNames[] = new String[] { "comConfig" };
        // Construct a static ConcurrentMapCacheManager, managing caches for the specified cache
        // names only.
        return new ConcurrentMapCacheManager(cacheNames);
    }

}


2.  Enable caching behavior for a method
 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
package com.xxx.ecp.commons.repository.impl;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Component;

import com.cht.commons.persistence.query.SqlExecutor;
import com.google.common.base.Strings;
import com.yuantalife.ecp.commons.entity.ComConfig;
import com.yuantalife.ecp.commons.repository.custom.ComConfigRepositoryCustom;

/**
 * The Class ComConfigRepositoryImpl.
 */
@Component
public class ComConfigRepositoryImpl implements ComConfigRepositoryCustom {

    @Autowired
    private SqlExecutor sqlExecutor;

    /**
     * {@inheritDoc} <br>
     * The simplest way to enable caching behavior for a method is to demarcate it with @Cacheable
     * and parameterize it with the name of the cache where the results would be stored
     */
    @Override
    @Cacheable("comConfig")
    public List<ComConfig> findByServiceType(String serviceType) {
        String sql = "select * from com_config where service_type = :serviceType";

        Map<String, String> parameter = new HashMap<String, String>();
        parameter.put("serviceType", serviceType);

        return sqlExecutor.queryForList(sql, parameter, ComConfig.class);
    }


}


3. When update com_config table (including create, update, delete), evict cache content so that fresh values can be loaded into the cache again
 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
package com.xxx.ecp.manage.common.service;

import java.sql.Timestamp;
import java.util.Date;
import java.util.List;

import lombok.extern.slf4j.Slf4j;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.stereotype.Service;

import com.cht.commons.security.user.UserHolder;
import com.yuantalife.ecp.commons.entity.ComConfig;
import com.yuantalife.ecp.commons.entity.ComConfigPK;
import com.yuantalife.ecp.commons.exception.EcpException;
import com.yuantalife.ecp.commons.repository.ComConfigRepository;

@Slf4j
@Service
public class Com010wService {

    @Autowired
    ComConfigRepository comConfigRepository;

    @CacheEvict(value = "comConfig", allEntries = true)
    public void create(ComConfig comConfig) {
        ComConfigPK pk = new ComConfigPK();
        pk.setConfigKey(comConfig.getConfigKey());
        pk.setServiceType(comConfig.getServiceType());
        ComConfig existingEntity = comConfigRepository.findOne(pk);

        if (existingEntity == null) {
            comConfig.setUserId(UserHolder.getUser().getId());
            comConfig.setUpdateDate(new Timestamp(new Date().getTime()));
            comConfigRepository.create(comConfig);
        } else {
            throw new EcpException(com.yuantalife.ecp.manage.common.StatusCodes.COM010001W());
        }

    }

    public List<ComConfig> query(String serviceType) {
        return comConfigRepository.findOrderByUpdateDateDesc(serviceType);
    }

    @CacheEvict(value = "comConfig", allEntries = true)
    public void save(ComConfig comConfig) {
        comConfig.setUserId(UserHolder.getUser().getId());
        comConfig.setUpdateDate(new Timestamp(new Date().getTime()));
        comConfigRepository.save(comConfig);
    }

    @CacheEvict(value = "comConfig", allEntries = true)
    public void delete(ComConfig comConfig) {
        ComConfigPK pk = new ComConfigPK();
        pk.setConfigKey(comConfig.getConfigKey());
        pk.setServiceType(comConfig.getServiceType());
        comConfigRepository.delete(pk);
    }
}


Reference
[1] http://www.baeldung.com/spring-cache-tutorial