Total Pageviews

Showing posts with label Apache Project. Show all posts
Showing posts with label Apache Project. Show all posts

2017/12/10

[DBCP2] [DB2] java.lang.AbstractMethodError: com.ibm.db2.jcc.t4.b.isValid(I)Z

Problem
I am using DBCP2 as my third party library to do connection pool.


But as I try to get connection it throws exception:
java.lang.AbstractMethodError: com.ibm.db2.jcc.t4.b.isValid(I)Z


How-To

Owing to the isValid method was added in JDBC 4.0. I need to change IBM DB2 class from db2jcc.jar (JDBC 3.0) to db2jcc4.jar (JDBC 4.0), then this problem will be solved.


Reference

[1] https://stackoverflow.com/questions/37193965/java-lang-abstractmethoderror-com-ibm-db2-jcc-t4-b-isvalidiz

2017/10/05

How to check file's media type?

Problem
If I have a file upload function in my web application, this function need to check the file which upload by user is image file or not. How to do it?

How-To
You can make good use of Apache Tika to fulfill this requirement.

Add dependency in your pom.xml
        <dependency>
            <groupId>org.apache.tika</groupId>
            <artifactId>tika-core</artifactId>
            <version>1.14</version>
            <scope>compile</scope>
        </dependency>




Sample code is as follow:
package albert.practice.file;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import org.apache.commons.io.FileUtils;
import org.apache.tika.Tika;

import lombok.extern.slf4j.Slf4j;

@Slf4j
public class FileContentTypeUtils {

    private static List<String> imageMediaTypes = new ArrayList<>();

    private static void setImageMediaTypes() {
        // http://www.fileformat.info/info/mimetype/image/index.htm
        imageMediaTypes = Arrays.asList("image/cgm", "image/fits",
                "image/g3fax", "image/gif", "image/ief", "image/jp2",
                "image/jpeg", "image/jpm", "image/jpx", "image/naplps",
                "image/png", "image/prs.btif", "image/prs.pti", "image/t38",
                "image/tiff", "image/tiff-fx", "image/vnd.adobe.photoshop",
                "image/vnd.cns.inf2", "image/vnd.djvu", "image/vnd.dwg",
                "image/vnd.dxf", "image/vnd.fastbidsheet", "image/vnd.fpx",
                "image/vnd.fst", "image/vnd.fujixerox.edmics-mmr",
                "image/vnd.fujixerox.edmics-rlc",
                "image/vnd.globalgraphics.pgb", "image/vnd.microsoft.icon",
                "image/vnd.mix", "image/vnd.ms-modi", "image/vnd.net-fpx",
                "image/vnd.sealed.png", "image/vnd.sealedmedia.softseal.gif",
                "image/vnd.sealedmedia.softseal.jpg", "image/vnd.svf",
                "image/vnd.wap.wbmp", "image/vnd.xiff");
    }

    public static Boolean isImage(String sourceFile) throws IOException {
        setImageMediaTypes();
        Boolean isImage = Boolean.FALSE;
        File file = FileUtils.getFile(sourceFile);
        Tika tika = new Tika();
        try {
            String mediaType = tika.detect(file);
            isImage = imageMediaTypes.contains(mediaType);
        } catch (IOException e) {
            throw e;
        }
        return isImage;
    }

}



Test code is the following:
package albert.practice.file;

import java.io.IOException;

import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;

public class FileContentTypeUtilsTest extends FileContentTypeUtils {

    private String imageFile;
    private String pdfFile;

    @Before
    public void setup() {
        imageFile = "/Users/albert/Dropbox/picture/panda.png";
        pdfFile = "/Users/albert/Dropbox/test_測試.pdf";
    }

    @Test
    public void testImageFile() throws IOException {
        Assert.assertTrue(isImage(imageFile));
    }

    @Test
    public void testPdfFile() throws IOException {
        Assert.assertFalse(isImage(pdfFile));
    }

}



Test results are shown bellow:






2017/09/07

How to call a REST service in webMethods Integration Server from commons-httpclient

Scenario
Assume I had created two REST Resources in webMethods, one is via HTTP Post method, another one is by HTTP Get method.

How do I test them by commons-httpclient?


How-to
Add two dependencies in your pom.xml
    <dependency>
        <groupId>commons-httpclient</groupId>
        <artifactId>commons-httpclient</artifactId>
        <version>3.1</version>
    </dependency>

    <dependency>
        <groupId>commons-io</groupId>
        <artifactId>commons-io</artifactId>
        <version>2.5</version>
    </dependency>


Here has sample code to demonstrate how to send  HTTP Post method and HTTP Get method using commons-httpclient:
package albert.practice.httpClient;

import java.io.IOException;

import org.apache.commons.httpclient.Credentials;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpException;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.httpclient.UsernamePasswordCredentials;
import org.apache.commons.httpclient.auth.AuthScope;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.commons.io.IOUtils;

import com.google.common.base.Charsets;

public class HttpClientExample {

    private String post_uri = "http://10.12.14.28:5555/rest/test.restful.RestTest2";
    private String get_uri = "http://10.12.14.28:5555/rest/test.restful.RestTest3";
    private String inputJson = "{\"ip\":\"10.10.12.66\",\"state\": \"OFFLINE\"}";

    /**
     * Implements the HTTP POST method.
     * 
     * @return response code
     * @throws HttpException
     * @throws IOException
     */
    public int sendPost() throws HttpException, IOException {
        AuthScope authScope = getAuthScope();
        Credentials credentials = getCredentials();

        HttpClient client = new HttpClient();
        client.getState().setCredentials(authScope, credentials);

        PostMethod postMethod = new PostMethod(post_uri);
        postMethod.setDoAuthentication(true);
        postMethod.setParameter("data", inputJson);

        return client.executeMethod(postMethod);
    }

    /**
     * Implements the HTTP GET method.
     * 
     * @return the response string of the HTTP method
     * @throws HttpException
     * @throws IOException
     */
    public String sendGet() throws HttpException, IOException {
        String responseString = "";

        AuthScope authScope = getAuthScope();
        Credentials credentials = getCredentials();

        HttpClient client = new HttpClient();
        client.getState().setCredentials(authScope, credentials);

        GetMethod getMethod = new GetMethod(get_uri + "?input=albert");
        getMethod.setDoAuthentication(true);

        int statusCode = client.executeMethod(getMethod);
        if (HttpStatus.SC_OK == statusCode) {
            responseString = IOUtils.toString(getMethod.getResponseBodyAsStream(), Charsets.UTF_8);
        }
        return responseString;
    }

    /**
     * Set authentication scope.
     * 
     * @return authentication scope
     */
    private AuthScope getAuthScope() {
        String ip = "10.12.14.28";
        int port = 5555;
        String realm = AuthScope.ANY_REALM;

        AuthScope authScope = new AuthScope(ip, port, realm);
        return authScope;
    }

    /**
     * Set the authentication credentials for the given scope.
     * 
     * @return credentials
     */
    private Credentials getCredentials() {
        String username = "cctv";
        String password = "cctv";
        Credentials credentials = new UsernamePasswordCredentials(username, password);
        return credentials;
    }

}


Here has the test code:
package albert.practice.httpClient;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;

import java.io.IOException;

import org.apache.commons.httpclient.HttpException;
import org.apache.commons.httpclient.HttpStatus;
import org.junit.Before;
import org.junit.Test;

public class HttpClientExampleTest {

    private HttpClientExample httpClientExample;

    @Before
    public void setup() {
        httpClientExample = new HttpClientExample();
    }

    @Test
    public void testSendPost() throws HttpException, IOException {
        int statusCode = httpClientExample.sendPost();
        assertEquals(HttpStatus.SC_OK, statusCode);
    }

    @Test
    public void testSendGet() throws HttpException, IOException {
        String responseString = httpClientExample.sendGet();
        System.out.println("responseString = " + responseString);
        assertNotNull(responseString);
    }

}
    



2017/07/11

Utilize AgeFileFilter to filter either newer files or files equal to or older

Scenario
I have an requirement to read a specific directory (including subdirectories) to find five days before log files and delete them.
How to do it?

How-To
Add commons-io to your maven dependency:
1
2
3
4
5
    <dependency>
     <groupId>commons-io</groupId>
     <artifactId>commons-io</artifactId>
     <version>2.5</version>
    </dependency>


Here has code snippet:

 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
    /**
     * 找出某個日期以前的檔案.
     * 
     * @param directory 找出某個目錄下的檔案
     * @param days 找出數天前 (如 -20)
     * @param includeSubdir 是否包含子目錄 (true / false)
     * @return List of File
     */
    public static List<File> getFilesBeforeXDays(File directory, int days, Boolean includeSubdir) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(new Date());
        cal.add(Calendar.DATE, days);
        cal.set(Calendar.HOUR, 0);
        cal.set(Calendar.MINUTE, 0);
        cal.set(Calendar.SECOND, 0);
        cal.set(Calendar.MILLISECOND, 0);
        cal.set(Calendar.HOUR_OF_DAY, 0);
        Date date = cal.getTime();

        IOFileFilter ageFileFilter = FileFilterUtils.ageFileFilter(date);
        IOFileFilter subDirFilter = includeSubdir ? FileFilterUtils.trueFileFilter()
                : FileFilterUtils.falseFileFilter();

        Collection<File> fileCollection = org.apache.commons.io.FileUtils.listFiles(directory, ageFileFilter, subDirFilter);
        if(CollectionUtils.isEmpty(fileCollection)){
            log.info("Cannot find any log files before " + new SimpleDateFormat("yyyy/MM/dd HH:mm:ss.SSS").format(date));
        } else{
            log.info("Find " + fileCollection.size() + " log file(s).");
        }
        
        return new ArrayList<File>(fileCollection);
    }




Reference
[1] https://commons.apache.org/proper/commons-io/javadocs/api-2.4/org/apache/commons/io/filefilter/AgeFileFilter.html    

2017/07/09

[HttpClient] Fail to Get Response from a Valid URL

Problem
I am using HttpClient Get method to retrieve the response body of the HTTP method, if any.
During the execution, I fail to get response from a valid URL. 

The code snippet is as follows:
 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
package albert.practice.http;

import java.io.IOException;

import org.apache.commons.httpclient.DefaultHttpMethodRetryHandler;
import org.apache.commons.httpclient.HostConfiguration;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.httpclient.params.HttpMethodParams;
import org.apache.commons.io.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.common.base.Charsets;
import com.google.common.base.Strings;

public class HttpSmsClient {

    private final static Logger logger = LoggerFactory.getLogger(HttpSmsClient.class);

    public static String getResponse(String url) throws IOException {
        String responseString = "";
        HttpClient client = new HttpClient();
        
        GetMethod method = new GetMethod(url);
        method.getParams().setParameter(HttpMethodParams.RETRY_HANDLER,
                new DefaultHttpMethodRetryHandler(3, false));

        int statusCode;
        try {
            statusCode = client.executeMethod(method);            
            if (HttpStatus.SC_OK == statusCode) {
                responseString = IOUtils.toString(method.getResponseBodyAsStream(), Charsets.UTF_8);
            }
        } catch (IOException e) {
            throw e;
        } finally {
            method.releaseConnection();
        }
        logger.info("responseString = " + responseString);
        return responseString;
    }

}



How-To
In my office, I need to specify proxy server before I connect to various services.
Therefore, the source code will be modified as follows:
 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
package albert.practice.http;

import java.io.IOException;

import org.apache.commons.httpclient.DefaultHttpMethodRetryHandler;
import org.apache.commons.httpclient.HostConfiguration;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.httpclient.params.HttpMethodParams;
import org.apache.commons.io.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.common.base.Charsets;
import com.google.common.base.Strings;

public class HttpSmsClient {

    private final static Logger logger = LoggerFactory.getLogger(HttpSmsClient.class);

    public static String getResponse(String url, String proxy, String port) throws IOException {
        String responseString = "";
        HttpClient client = new HttpClient();

        HostConfiguration hostConfiguration = client.getHostConfiguration();
        hostConfiguration.setProxy(proxy, Integer.valueOf(port));
        client.setHostConfiguration(hostConfiguration);
        
        GetMethod method = new GetMethod(url);
        method.getParams().setParameter(HttpMethodParams.RETRY_HANDLER,
                new DefaultHttpMethodRetryHandler(3, false));

        int statusCode;
        try {
            statusCode = client.executeMethod(method);            
            if (HttpStatus.SC_OK == statusCode) {
                responseString = IOUtils.toString(method.getResponseBodyAsStream(), Charsets.UTF_8);
            }
        } catch (IOException e) {
            throw e;
        } finally {
            method.releaseConnection();
        }
        logger.info("responseString = " + responseString);
        return responseString;
    }

}


Maven dependencies are as follows:
 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
    <dependencies>
        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>1.1.7</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/commons-httpclient/commons-httpclient -->
        <dependency>
            <groupId>commons-httpclient</groupId>
            <artifactId>commons-httpclient</artifactId>
            <version>3.1</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/commons-io/commons-io -->
        <dependency>
            <groupId>commons-io</groupId>
            <artifactId>commons-io</artifactId>
            <version>2.5</version>
        </dependency>

        <dependency>
            <groupId>com.google.guava</groupId>
            <artifactId>guava</artifactId>
            <version>20.0</version>
        </dependency>
    </dependencies>




2017/07/08

[HttpClient] Warning: Going to buffer response body of large or unknown size. Using getResponseBodyAsStream instead is recommended.

Problem
I am using HttpClient Get method to retrieve the response body of the HTTP method, if any.
During the execution, the console print this warning message: 
Going to buffer response body of large or unknown size. Using getResponseBodyAsStream instead is recommended.

The code snippet is as follows:
 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
package albert.practice.http;

import java.io.IOException;

import org.apache.commons.httpclient.DefaultHttpMethodRetryHandler;
import org.apache.commons.httpclient.HostConfiguration;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.httpclient.params.HttpMethodParams;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.common.base.Strings;

public class HttpSmsClient {

    private final static Logger logger = LoggerFactory.getLogger(HttpSmsClient.class);
    
    public static String getResponse(String url, String proxy, String port) throws IOException {
        String responseString = "";
        HttpClient client = new HttpClient();

        if (!Strings.isNullOrEmpty(proxy) && !Strings.isNullOrEmpty(proxy)) {
            HostConfiguration hostConfiguration = client.getHostConfiguration();
            hostConfiguration.setProxy(proxy, Integer.valueOf(port));
            client.setHostConfiguration(hostConfiguration);
        }
        
        GetMethod method = new GetMethod(url);
        method.getParams().setParameter(HttpMethodParams.RETRY_HANDLER,
                new DefaultHttpMethodRetryHandler(3, false));

        int statusCode;
        try {
            statusCode = client.executeMethod(method);
            if (HttpStatus.SC_OK == statusCode) {
                responseString = method.getResponseBodyAsString();
            }
        } catch (IOException e) {
            throw e;
        } finally {
            method.releaseConnection();
        }
        logger.info("responseString = " + responseString);
        return responseString;
    }

}


How-To
This warning message results from Line 38
According to its recommendation, the source code will be modified as bellows:
 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
package albert.practice.http;

import java.io.IOException;

import org.apache.commons.httpclient.DefaultHttpMethodRetryHandler;
import org.apache.commons.httpclient.HostConfiguration;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.httpclient.params.HttpMethodParams;
import org.apache.commons.io.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.common.base.Charsets;
import com.google.common.base.Strings;

public class HttpSmsClient {

    private final static Logger logger = LoggerFactory.getLogger(HttpSmsClient.class);

    public static String getResponse(String url, String proxy, String port) throws IOException {
        String responseString = "";
        HttpClient client = new HttpClient();

        if (!Strings.isNullOrEmpty(proxy) && !Strings.isNullOrEmpty(proxy)) {
            HostConfiguration hostConfiguration = client.getHostConfiguration();
            hostConfiguration.setProxy(proxy, Integer.valueOf(port));
            client.setHostConfiguration(hostConfiguration);
        }
        logger.info("url = " + url);
        GetMethod method = new GetMethod(url);
        method.getParams().setParameter(HttpMethodParams.RETRY_HANDLER,
                new DefaultHttpMethodRetryHandler(3, false));

        int statusCode;
        try {
            statusCode = client.executeMethod(method);
            logger.info("[getResponse] statusCode = " + statusCode);
            if (HttpStatus.SC_OK == statusCode) {
                responseString = IOUtils.toString(method.getResponseBodyAsStream(), Charsets.UTF_8);
            }
        } catch (IOException e) {
            throw e;
        } finally {
            method.releaseConnection();
        }
        logger.info("responseString = " + responseString);
        return responseString;
    }

}


Maven dependencies are as bellows:
 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
    <dependencies>
        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>1.1.7</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/commons-httpclient/commons-httpclient -->
        <dependency>
            <groupId>commons-httpclient</groupId>
            <artifactId>commons-httpclient</artifactId>
            <version>3.1</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/commons-io/commons-io -->
        <dependency>
            <groupId>commons-io</groupId>
            <artifactId>commons-io</artifactId>
            <version>2.5</version>
        </dependency>

        <dependency>
            <groupId>com.google.guava</groupId>
            <artifactId>guava</artifactId>
            <version>20.0</version>
        </dependency>

    </dependencies>




2017/06/05

How to use Apache Commons CSV to Read/Write CSV file

Step 1. You need to add this dependency to your pom.xml
<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-csv</artifactId>
    <version>1.4</version>
</dependency>


Step 2. Create a POJO class
package albert.practice.csv;

import java.io.Serializable;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;

@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class OpcVo implements Serializable {

    private Integer ns;
    private String identifier;
    
}


Step 3. Here has an example regarding how to read/write CSV file via Apache Commons CSV
package albert.practice.csv;

import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import org.apache.commons.csv.CSVFormat;
import org.apache.commons.csv.CSVParser;
import org.apache.commons.csv.CSVPrinter;
import org.apache.commons.csv.CSVRecord;

import lombok.extern.slf4j.Slf4j;

@Slf4j
public class CSVTest {

    // Delimiter used in CSV file
    private static final String NEW_LINE_SEPARATOR = "\n";

    // CSV file header
    private static final String[] FILE_HEADER = {"ns", "identifier"};

    // OpcVo attributes
    private static final String NS = "ns";
    private static final String ID = "identifier";

    public static void main(String[] args) throws IOException {
        String csvDirectory = "D:/work/AOCS/csv/";
        String csvFileName = "test.csv";

        CSVTest test = new CSVTest();
        // test.writeToCSV(csvFolder.concat(csvFile));
        List<OpcVo> opcs = test.readFromCsv(csvDirectory.concat(csvFileName));
        opcs.forEach(opc -> log.debug(opc.toString()));
    }

    public void writeToCSV(String fileName) throws IOException {
        List<OpcVo> opcs = getDummyData();

        // Create the CSVFormat object with "\n" as a record delimiter
        CSVFormat csvFileFormat = CSVFormat.DEFAULT.withRecordSeparator(NEW_LINE_SEPARATOR);

        try (FileWriter fileWriter = new FileWriter(fileName);
                CSVPrinter csvFilePrinter = new CSVPrinter(fileWriter, csvFileFormat);) {
            // Create CSV file header
            csvFilePrinter.printRecord(FILE_HEADER);

            // Write a new OpcVo object list to the CSV file
            for (OpcVo opc : opcs) {
                List dataRecord = new ArrayList<>();
                dataRecord.add(String.valueOf(opc.getNs()));
                dataRecord.add(opc.getIdentifier());
                csvFilePrinter.printRecord(dataRecord);
            }
        } catch (IOException e) {
            throw e;
        }
    }

    public List<OpcVo> readFromCsv(String fileName) throws IOException {
        // Create a new list of OpcVo to be filled by CSV file data
        List<OpcVo> result = new ArrayList<>();

        // Create the CSVFormat object with the header mapping
        CSVFormat csvFileFormat = CSVFormat.DEFAULT.withHeader(FILE_HEADER);

        try (FileReader fileReader = new FileReader(fileName);
                CSVParser csvFileParser = new CSVParser(fileReader, csvFileFormat);) {
            List dataRecord = new ArrayList<>();
            // Get a list of CSV file records
            List<CSVRecord> csvRecords = csvFileParser.getRecords();
            
            for (int i = 1; i < csvRecords.size(); i++) {
              //Create a new OpcVo object and fill this data
                CSVRecord record = csvRecords.get(i);
                String ns = record.get(NS);
                String identifier = record.get(ID);
                result.add(new OpcVo(Integer.valueOf(ns), identifier));
            }
        } catch (IOException e) {
            throw e;
        }

        return result;
    }

    private List<OpcVo> getDummyData() {
        OpcVo opc1 = new OpcVo(2, "Channel1.Device1.FireZone_01");
        OpcVo opc2 = new OpcVo(2, "Channel1.Device1.EmergencyPushButton_01");
        OpcVo opc3 = new OpcVo(2, "Channel1.Device1.EmergencyExitWindow_01");
        OpcVo opc4 = new OpcVo(2, "Channel1.Device1.EmergencyExit_01");

        return Arrays.asList(opc1, opc2, opc3, opc4);
    }
}




2016/10/07

[PDFBox] Generate TIF with 0-kb

Problem
I am using Apache PDFBox to convert PDF to TIF file.

The scenario is to generate TIF file to a specific path, then another application will read this TIF file and move to another directory.



But it will generate TIF file with 0-kb at times and fail to open this TIF file, and does not have any abnormal message in application log.


How-To

Here is the code snippet:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
    private List<String> writeImage(PDDocument document, String outputPrefix, ImageType imageType,
            float dpi, String fileName) throws IOException {
        ImageIO.scanForPlugins();

        List<String> tifNames = new ArrayList<String>();

        PDFRenderer renderer = new PDFRenderer(document);

        for (int i = 0; i < document.getNumberOfPages(); i++) {

            BufferedImage image = renderer.renderImageWithDPI(i, dpi, imageType);

            String outputPostfix = "_" + String.format("%02d", i + 1); // 01開始
            String outputFileName = outputPrefix + outputPostfix;// 檔名: 保單號碼_0X

            tifNames.add(fileName + outputPostfix); // 回傳產了那些檔名

            ImageIOUtil.writeImage(image, outputFileName + "." + "tif", Math.round(dpi));
            image.flush();
        }
        return tifNames;
    }



We can see implementation details in ImageIOUtil.writeImage
https://github.com/apache/pdfbox/blob/04292e421e9531616aa2856b908fbdb05b381af7/tools/src/main/java/org/apache/pdfbox/tools/imageio/ImageIOUtil.java#L65-L79

We can see it will create a File instance at first, then write image to TIF file.


As it create a File instance, this file will be created. It another application had read this file, then this file may be locked and failed to write.

Therefore, we should create TIF file to a temporary directory first, then move the finished TIF file to the destination.