Total Pageviews

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

2016/06/02

[閱讀筆記] 圖解國富論 Part 3



  1. 進口限制可以幫助一國在短時間內建立起特定製造業,然而這種政策卻會扭曲資本和勞動的自然配置,反而對一國經濟產生不利影響
  2. 關稅可以用來調節一國的進出口貿易。但他像一把雙面刃,既能給一國居民帶來極大的收入,也能嚴重傷害一個國家居民的利益
  3. 開放自由貿易會在短期內對一國產業發展和工人就業產生不利影響,但這種損害從長期來看卻不是必然的
  4. 開放自由貿易後,可以用低價進口國外貨物,經加工後再出口獲得利潤
  5. 任何一個國家,如果其生產長期不能滿足消費,才是真正的一國衰亡之源
  6. 匯率問題是當今世界在從事對外貿易時必須關心的議題,因為匯率的變動和結匯幣種的選擇,對進出口雙方的利益有很大的影響。匯率會影響貿易雙方的收入
  7. 生產獎金能提高生產的積極性、激發人們創造財富的熱情,儘管其也可能會帶來詐欺行為和資本自然流向的扭曲,但仍不失為可行的政策
  8. 國家財政要解決的問題不僅包括為軍隊和公共服務機構提供經費來源,其政策措施還會影響社會財富的再分配以及國民經濟的運行
  9. 公債的表現的是國家的信用,公債的出現與商業社會中君主和國家時常面臨入不敷出的狀況有關。富裕的商人及製造業者願意借錢給國家,代表是人民對個人財產安全的信心,以及對國家信用的認可
  10. 四項徵稅的原則:公平原則 (所有公民都要繳稅)、確定原則 (繳稅規定清楚明瞭)、便利原則 (繳稅方式便利省時)、經濟原則 (徵收適當的稅金,過高的稅收會成為逃稅的誘因)
  11. 司法機構的出現,在於保護社會所有成員不受其他成員的欺辱與壓迫有關,,獨立的司法機構為了維持其獨立性,應該自行解決司法開銷
  12. 透過對私人收入徵收賦稅是一國取得財政收入的主要來源,而徵收賦稅必須遵循公平、確定、方便徵收和高效的原則
  13. 所謂公債,就是一國之中央或地方政府,基於政府信用而舉借的各項債務。國家發行公債的原因,通常是因為某些緊急狀況造成的入不敷出
  14. 每個國家應該生產自己生產力最高的產品。李嘉圖提出比較優勢的論點來描述兩個生產者的機會成本(可以理解為把一定資源投入某一用途後,所放棄在其他用途中所能獲得的利益),生產某一物品機會成本較少的生產者,在生產這種物品中有比較優勢。如一國生產奢侈品或農作物都很強的話,生產奢侈品會比較好
  15. 亞當史密斯於《道德感情論》中有提到,人確實是自私的,但是人類隨時隨地都需要他人的協助,但是僅靠他人的恩惠是行不通的,他只能利用他人的利己心。因此,我們每日所需的食物和飲料,不是出自屠宰業者、酒家或麵包業者的恩惠,而是出自於他們自利的打算
  16. 自由競爭的市場經濟模式,才能提高經濟效益和增進社會福利
  17. 如果自由競爭受到阻礙,那麼那隻「看不見的手」就不會把工作做得恰到好處。故亞當史密斯堅決反對政府對市場無理的干預,他主張政府的職責應盡可能地減少到只提供必要的「公共產品」和扮演「守夜者」的角色,也就是小政府大社會
  18. 自私並不可怕,作為一個自動自發的合作體系,市場這隻「看不見的手」會引導自私的個體在不知不覺中服務於整體社會利益
  19. 一種事業若對社會有益,就應當任其自由,任其競爭。競爭越自由、越普遍,這個事業就越有利於社會
  20. 人們所追求的僅僅是一己的安全和私立。但是,當人們這樣做的時候,有一隻看不見的手會引導他,幫助他實現另外一種目標,儘管該目標不是他的本意。追逐個人利益的結果,會不自覺地增進社會利益,其效果比他真的要去增加社會利益時更好
  21. 市場不是不要政府,而是要一個知道自己界限的政府。亞當史密斯認為,政府只具備三種功能:保護社會不受其他獨立社會侵犯;嚴正的司法機關保護公民合法權利;建設並維持公共事業和某些公共設施
  22. 政府有義務合理利用貨幣政策和財政政策,對金融體系嚴加管理,平息經濟的週期變動,盡可能抑制通膨和大規模失業,使經濟能長期平穩的發展
  23. 政府在國際貿易中要做到,減少關稅壁壘,提高國際分工和生產專業化的水準;對窮國進行援助、救濟與技術支援;與其他國家政府協調宏觀經濟政策;保護全球環境

2016/06/01

[閱讀筆記] 你還在努力省錢來投資理財嗎? Part 3




  1. 戴頓大學財金教授Carl Chen的分析發現,如果觀眾立即賣空財經節目大喊買進的股票,效果反而更好
  2. 女性大半人生財富少於男性的理由是:女性賺的比較少,卻活比較久
  3. 孩子也是造成兩性薪資差距的因素。在第一個孩子出生後,女性的薪資便開始下降,新手爸爸卻賺更多。至於退休儲蓄,女性為退休提撥帳戶的金額比男性少1/3,除了薪資較低,女性生子後減少從事受薪勞務的時間也是原因
  4. 不要以為女性不懂理財,兩性的財務知識同樣匱乏
  5. 女性導向的理財建議,本質上並不好。應該說,金融服務業所給的任何投資建議,都須要審慎評估
  6. 1981~2011年的30年間,債券的投資績效其實好過股票
  7. 相較於男性,女性比較不會眷戀原本的選擇,會比男性更快拋棄賠錢貨
  8. 男性比女性更容易因可能恐慌而在股市低點賣股,造成無法彌補的損失
  9. 根據兩性投資策略研究發現,女性的績效之所以勝過男性,主因是男性較常買賣股票,頻率高過45%,這會累積稅額和手續費,吃掉不少獲利
  10. 針對金融詐騙受害者所做的研究顯示,最可能受騙的人不是無知女性,而是中年後期、自以為懂很多的男人。女性反而有自知之明,清楚自己不知道什麼,並坦承無知,反而可以阻止犯下昂貴的財務錯誤
  11. 女性投資人在尋求理財協助時最關心的事項,包括低廉、透明的手續費,清楚說明產品和建議,以及沒有硬被推銷的壓力。這些其實極為合理、無關性別皆該堅持的原則
  12. 擁有房屋有其作用的真正理由是,至少就有種財務觀念而言,他是一種自動儲蓄計畫,它不會給你最好的報酬,但把錢存在一個很久碰不到的地方,這行為本身就是一大好處。但是,除非妳打算至少住七年,否則不要買,不到七年必虧無疑
  13. 許多原生家庭留給我們最大的經濟創傷不是與金錢的失能關係,而是與階級的失能關係,特別是在這個以美國夢自豪的國家裡,不再有階級流動。根據Pew Charitable Trusts (皮由慈善基金會)的研究,在所得頂部及底部2/5的家庭出生者,有超過六成在成年後,人在同一個群組。
  14. 是因為財務困段導致壓力,進一步造成財務行為錯亂
  15. 低收入者過重的可能性,比高所得者高很多。然而這不是因為低所得者缺乏自制力或是懶,真正原因是加工包裝食品比新鮮的蔬果便宜,想吃的健康,可是要花錢的。
  16. 就在我們薪水追不上通膨的同時,我們卻被越來越多東西誘惑,因為身邊越來越多人屈服於相對便宜的物品和信貸的誘惑
  17. 多數美國人上破產法庭,不是因為買了太多東西,而是因為面臨重創他們的醫療、失業或婚姻狀況
  18. 理財顧問的賺錢之道不是提供對客戶最好的建議,而是對他自己個人營收最好的建議
  19. 認為房地產、股票或其他投資一定會增值的想法,實在是過度單純,且未提及那些在失意時需要現金的人
  20. 我們並非生活在一個允許全體財務成長的經濟環境,無論那些諮詢或建議的立意有多良善。個人理財大師提供的成功故事,都是個人的勝利,在這個經濟不斷下滑的社會中的個別成就
  21. 我們一直被販售一個儲蓄與投資的夢,一個沒有歷史或事實根據的夢。我們是一個大規模實驗的參與者,希望個人理財和投資能為我們完成一切。現在我們知道,對大多人來說,他們沒有結果
  22. 不管理財大師怎麼說,股市、房市和其他投資市場,都不是保證獲利的投資或儲蓄方案
  23. 個人理財無法完全解決問題,但若當成附加物,他可能創造有價值的貢獻,讓我們得以計畫,得以擺脫或不背負債務
  24. 沒有任何個人財務或投資方案能完全保護我們,避開惡性循環或不幸。我們需要家人、朋友和最重要的政府,政府是一切事物的終極執行者,無論是制定法規或充當最後手段的保證人