Total Pageviews

2019/02/28

2019/02/27

2019/02/26

2019/02/15

[Java] How to convert seconds to minutes?

Problem
How to convert seconds to minutes in Java ?
For example, 230 seconds should convert to 3 minutes 50 seconds.

How-To
Here has sample code:
package albert.test;

import java.util.concurrent.TimeUnit;

public class TimeUtils {

    public static void main(String[] args) {
        System.out.println(TimeUtils.toMinutes(230));
    }

    public static String toMinutes(long second) {
        long mm = TimeUnit.SECONDS.toMinutes(second);
        long ss = TimeUnit.SECONDS.toSeconds(second) - (mm * 60);

        String str = "%d 分 %d 秒";
        return String.format(str, mm, ss);
    }

}

2019/02/14

[Sybase] How to get the difference between two days

Problem
I have a datetime column in Sybase table, if I would like to calculate the number of second between this column and current datetime. How to do it?


How-To
Using datediff to calculate the number of seconds between two date.
The syntax and parameters are:


The SQL statement is as bellows:
SELECT DATA_TIME, datediff(ss, DATA_TIME, getdate()) as DIFF
FROM TEST;


Reference
http://infocenter.sybase.com/help/index.jsp?topic=/com.sybase.infocenter.dc36271.1570/html/blocks/X47295.htm

2019/02/13

[Java] How to compress TIF file with multiple pages?

Problem
How to compress TIF file with multiple pages in Java?

How-To
Add dependency in your pom.xml
    <dependency>
     <groupId>com.github.jai-imageio</groupId>
     <artifactId>jai-imageio-core</artifactId>
     <version>1.3.1</version>
    </dependency>

Here has sample code:
package demo.util;

import java.awt.image.BufferedImage;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;

import javax.imageio.IIOImage;
import javax.imageio.ImageIO;
import javax.imageio.ImageReader;
import javax.imageio.ImageWriteParam;
import javax.imageio.ImageWriter;
import javax.imageio.stream.ImageInputStream;
import javax.imageio.stream.ImageOutputStream;

import com.github.jaiimageio.impl.plugins.tiff.TIFFImageReaderSpi;
import com.github.jaiimageio.impl.plugins.tiff.TIFFImageWriterSpi;

import lombok.extern.slf4j.Slf4j;

/*
 *  tif 壓縮程式
 */
@Slf4j
public class TiffCompression {

    /**
     * 用 Deflate 進行 TIF 壓縮.
     * 
     * @param source
     *            來源 TIF 檔
     * @param target
     *            壓縮後的 TIF 檔
     * @throws IOException
     */
    public static void compress(File source, File target) throws IOException {
        ImageIO.scanForPlugins();
        ImageWriter writer = null;

        try (InputStream fis = new BufferedInputStream(new FileInputStream(source));
                ImageInputStream iis = ImageIO.createImageInputStream(fis);
                ImageOutputStream targetTif = ImageIO.createImageOutputStream(target);) {
            // tif 來源檔
            TIFFImageReaderSpi readSpi = new TIFFImageReaderSpi();
            ImageReader reader = readSpi.createReaderInstance();
            reader.setInput(iis);

            // tif 目的檔
            TIFFImageWriterSpi tiffspi = new TIFFImageWriterSpi();
            writer = tiffspi.createWriterInstance();
            writer.setOutput(targetTif);

            // 取得 tif 分頁
            Integer pageSize = reader.getNumImages(true);
            BufferedImage image[] = new BufferedImage[pageSize];

            // 設定壓縮參數
            ImageWriteParam param = writer.getDefaultWriteParam();
            param.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
            // 有試過 CCITT T.4, CCITT T.6, PackBits, Deflate 與 LZW,Deflate 壓縮比最佳
            param.setCompressionType("Deflate");

            // 逐頁讀出檔案,並寫入目的地
            for (int i = 0; i < pageSize; i++) {
                image[i] = reader.read(i);
                IIOImage iioImage = new IIOImage(image[i], null, null);
                if (i == 0) {
                    writer.write(null, iioImage, param);
                } else {
                    writer.writeInsert(-1, iioImage, param);
                }
            }
        } catch (IOException e) {
            throw new IOException("TIF 壓縮失敗", e);
        } finally {
            if (writer != null) {
                writer.dispose();
            }
        }
    }
}




2019/02/12

[Spring] java.security.InvalidAlgorithmParameterException: the trustAnchors parameter must be non-empty

Problem
When I try to call web service via WebServiceTemplate, which provided by Spring framework. It throw the following exception:
java.lang.RuntimeException: Unexpected error: java.security.InvalidAlgorithmParameterException: the trustAnchors parameter must be non-empty; nested exception is javax.net.ssl.SSLException: java.lang.RuntimeException: Unexpected error: java.security.InvalidAlgorithmParameterException: the trustAnchors parameter must be non-empty
 at org.springframework.ws.client.core.WebServiceTemplate.sendAndReceive(WebServiceTemplate.java:561)
 at org.springframework.ws.client.core.WebServiceTemplate.marshalSendAndReceive(WebServiceTemplate.java:390)
 at org.springframework.ws.client.core.WebServiceTemplate.marshalSendAndReceive(WebServiceTemplate.java:378)

The code snippet is as following:
package demo.service.client;

import javax.net.ssl.TrustManager;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.ws.client.core.WebServiceTemplate;

import demo.dto.status;
import demo.dto.mapper.StatusMapper;
import demo.ws.bind.status.SendStatusRequest;
import demo.ws.bind.status.SendStatusResponse;
import lombok.extern.slf4j.Slf4j;

@Slf4j
@Component
public class StatusClient {
    
    @Autowired
    private WebServiceTemplate wsTemplate;
    
    @Value("${webservices.host}")
    private String host;
    
    @Value("${webservices.url.status}")
    private String url;
    
    @Autowired
    private StatusMapper mapper;

    public SendStatusResponse sendData(Status entity) {
        SendStatusRequest request = new SendStatusRequest();
        request.setStatusDto(mapper.toDto(entity));
        
        return (SendStatusResponse) wsTemplate.marshalSendAndReceive(host + url, request);
    }
    
}



How-To
Owing to the web service url is https, so you need to disable SSL certificate checking.

You need create an UnTrustworthyTrustManager:
package demo.service.client;

import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;

import javax.net.ssl.X509TrustManager;

public class UnTrustworthyTrustManager implements X509TrustManager {

    @Override
    public void checkClientTrusted(X509Certificate[] chain, String authType)
            throws CertificateException {
        // TODO Auto-generated method stub
        
    }

    @Override
    public void checkServerTrusted(X509Certificate[] chain, String authType)
            throws CertificateException {
        // TODO Auto-generated method stub
        
    }

    @Override
    public X509Certificate[] getAcceptedIssuers() {
        // TODO Auto-generated method stub
        return null;
    }
}


And set UnTrustworthyTrustManager into MessageSender
package demo.service.client;

import javax.net.ssl.TrustManager;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.ws.client.core.WebServiceTemplate;
import org.springframework.ws.transport.http.HttpsUrlConnectionMessageSender;

import demo.dto.status;
import demo.dto.mapper.StatusMapper;
import demo.ws.bind.status.SendStatusRequest;
import demo.ws.bind.status.SendStatusResponse;
import lombok.extern.slf4j.Slf4j;

@Slf4j
@Component
public class StatusClient {
    
    @Autowired
    private WebServiceTemplate wsTemplate;
    
    @Value("${webservices.host}")
    private String host;
    
    @Value("${webservices.url.status}")
    private String url;
    
    @Autowired
    private StatusMapper mapper;

    public SendStatusResponse sendData(Status entity) {
        HttpsUrlConnectionMessageSender sender = new HttpsUrlConnectionMessageSender();
        sender.setTrustManagers(new TrustManager[] { new UnTrustworthyTrustManager() });
        wsTemplate.setMessageSender(sender);
        
        SendStatusRequest request = new SendStatusRequest();
        request.setStatusDto(mapper.toDto(entity));
        
        return (SendStatusResponse) wsTemplate.marshalSendAndReceive(host + url, request);
    }
    
}


2019/02/11

[Java] BEA-380001-Internal Server Error

Scenario



How-To
The root cause is unknown. But comparing with workable client code with non-workable client code, there has one difference in package-info.java.

The package-info.java in workable client code is:
@javax.xml.bind.annotation.XmlSchema(namespace = "http://test.com", elementFormDefault = javax.xml.bind.annotation.XmlNsForm.QUALIFIED)
package demo.ws.bind.test1;


The package-info.java in non-workable client code is:
package demo.ws.bind.test2;

Therefore, as I add annotation above package, the problem had been resolved.

2019/02/10

[Tool] [SoapUI] How to setup SOAP Web Service HTTP Basic Authentication

Scenario


How-To
Here has two steps to set up HTTP Basic Authentication : 
Step 1. Invoke context menu, and choose "Show Interface Viewer"


Step 2. Fill in user name and password.


2019/02/09

[SoapUI] A class/interface with the same name "xxxx" is already in use. Use a class customization to resolve this conflict.

Problem
When I try to generate SOAP web service client code via SoapUI, I get naming conflict exception:
[ERROR] A class/interface with the same name "xxxx" is already in use. Use a class customization to resolve this conflict. 



How-To
We can add customized argument in SoapUI to automatically resolve naming conflicts without requiring the use of binding customizations.



Reference

[1] http://cxf.apache.org/docs/wsdl-to-java.html

2019/02/08

[Spring] Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException

Problem
I have a  configuration which provide more than one implementations for a bean:
package demo.config;

import org.apache.http.auth.UsernamePasswordCredentials;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.oxm.jaxb.Jaxb2Marshaller;
import org.springframework.ws.client.core.WebServiceTemplate;
import org.springframework.ws.transport.http.HttpComponentsMessageSender;

@Configuration
public class WebServicesClientConfig {

    @Value("${webservice.username}")
    private String userName;

    @Value("${webservice.password}")
    private String password;

    @Bean (name = "webServiceTemplate")
    public Jaxb2Marshaller jaxb2Marshaller() {
        Jaxb2Marshaller jaxb2Marshaller = new Jaxb2Marshaller();
        jaxb2Marshaller.setPackagesToScan("demo.ws.bind");
        return jaxb2Marshaller;
    }

    @Bean
    public WebServiceTemplate webServiceTemplate() {
        WebServiceTemplate webServiceTemplate = new WebServiceTemplate();
        webServiceTemplate.setMarshaller(jaxb2Marshaller());
        webServiceTemplate.setUnmarshaller(jaxb2Marshaller());

        webServiceTemplate.setMessageSender(httpComponentsMessageSender());

        return webServiceTemplate;
    }
    
    @Bean (name = "oq2WebServiceTemplate")
    public Jaxb2Marshaller jaxb2Marshaller2() {
        Jaxb2Marshaller jaxb2Marshaller = new Jaxb2Marshaller();
        jaxb2Marshaller.setPackagesToScan("demo.ws.bind2");
        return jaxb2Marshaller;
    }

    @Bean
    public WebServiceTemplate oq2WebServiceTemplate() {
        WebServiceTemplate oq2WebServiceTemplate = new WebServiceTemplate();
        oq2WebServiceTemplate.setMarshaller(jaxb2Marshaller2());
        oq2WebServiceTemplate.setUnmarshaller(jaxb2Marshaller2());

        oq2WebServiceTemplate.setMessageSender(httpComponentsMessageSender());

        return oq2WebServiceTemplate;
    }

    @Bean
    public HttpComponentsMessageSender httpComponentsMessageSender() {
        HttpComponentsMessageSender httpComponentsMessageSender = new HttpComponentsMessageSender();
        httpComponentsMessageSender.setCredentials(usernamePasswordCredentials());
        return httpComponentsMessageSender;
    }

    @Bean
    public UsernamePasswordCredentials usernamePasswordCredentials() {
        return new UsernamePasswordCredentials(userName, password);
    }

}


The client bean looks like:

package demo.client;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;
import org.springframework.ws.client.core.WebServiceTemplate;

@Component
public class OiClient {

    @Autowired
    @Qualifier("webServiceTemplate")
    private WebServiceTemplate webServiceTemplate;
    
    public Response getInfoByIdno() {
        // ignore details
    }

}

But as I start up spring boot, it throws the following exception:
Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'oiService': Unsatisfied dependency expressed through field 'oiClient'; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'oiClient': Unsatisfied dependency expressed through field 'webServiceTemplate'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'org.springframework.ws.client.core.WebServiceTemplate' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true), @org.springframework.beans.factory.annotation.Qualifier(value=webServiceTemplate)}
 at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:586) ~[spring-beans-5.0.8.RELEASE.jar:5.0.8.RELEASE]
 at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:91) ~[spring-beans-5.0.8.RELEASE.jar:5.0.8.RELEASE]
 at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:372) ~[spring-beans-5.0.8.RELEASE.jar:5.0.8.RELEASE]
 at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1341) ~[spring-beans-5.0.8.RELEASE.jar:5.0.8.RELEASE]
 at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:572) ~[spring-beans-5.0.8.RELEASE.jar:5.0.8.RELEASE]
 at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:495) ~[spring-beans-5.0.8.RELEASE.jar:5.0.8.RELEASE]
 at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:317) ~[spring-beans-5.0.8.RELEASE.jar:5.0.8.RELEASE]
 at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222) ~[spring-beans-5.0.8.RELEASE.jar:5.0.8.RELEASE]
 at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:315) ~[spring-beans-5.0.8.RELEASE.jar:5.0.8.RELEASE]
 at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) ~[spring-beans-5.0.8.RELEASE.jar:5.0.8.RELEASE]
 at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:251) ~[spring-beans-5.0.8.RELEASE.jar:5.0.8.RELEASE]
 at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1135) ~[spring-beans-5.0.8.RELEASE.jar:5.0.8.RELEASE]
 at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1062) ~[spring-beans-5.0.8.RELEASE.jar:5.0.8.RELEASE]


How-To
The configuration class should be fixed as bellows:
package demo.config;

import org.apache.http.auth.UsernamePasswordCredentials;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.oxm.jaxb.Jaxb2Marshaller;
import org.springframework.ws.client.core.WebServiceTemplate;
import org.springframework.ws.transport.http.HttpComponentsMessageSender;

@Configuration
public class WebServicesClientConfig {

    @Value("${webservice.username}")
    private String userName;

    @Value("${webservice.password}")
    private String password;

    @Bean
    @Qualifier("webServiceTemplate")
    public Jaxb2Marshaller jaxb2Marshaller() {
        Jaxb2Marshaller jaxb2Marshaller = new Jaxb2Marshaller();
        jaxb2Marshaller.setPackagesToScan("demo.ws.bind");
        return jaxb2Marshaller;
    }

    @Bean
    public WebServiceTemplate webServiceTemplate() {
        WebServiceTemplate webServiceTemplate = new WebServiceTemplate();
        webServiceTemplate.setMarshaller(jaxb2Marshaller());
        webServiceTemplate.setUnmarshaller(jaxb2Marshaller());

        webServiceTemplate.setMessageSender(httpComponentsMessageSender());

        return webServiceTemplate;
    }
    
    @Bean
    @Qualifier("oq2WebServiceTemplate")
    public Jaxb2Marshaller jaxb2Marshaller2() {
        Jaxb2Marshaller jaxb2Marshaller = new Jaxb2Marshaller();
        jaxb2Marshaller.setPackagesToScan("demo.ws.bind2");
        return jaxb2Marshaller;
    }

    @Bean
    public WebServiceTemplate oq2WebServiceTemplate() {
        WebServiceTemplate oq2WebServiceTemplate = new WebServiceTemplate();
        oq2WebServiceTemplate.setMarshaller(jaxb2Marshaller2());
        oq2WebServiceTemplate.setUnmarshaller(jaxb2Marshaller2());

        oq2WebServiceTemplate.setMessageSender(httpComponentsMessageSender());

        return oq2WebServiceTemplate;
    }

    @Bean
    public HttpComponentsMessageSender httpComponentsMessageSender() {
        HttpComponentsMessageSender httpComponentsMessageSender = new HttpComponentsMessageSender();
        httpComponentsMessageSender.setCredentials(usernamePasswordCredentials());
        return httpComponentsMessageSender;
    }

    @Bean
    public UsernamePasswordCredentials usernamePasswordCredentials() {
        return new UsernamePasswordCredentials(userName, password);
    }

}


Reference
[1] https://www.logicbig.com/tutorials/spring-framework/spring-core/inject-bean-by-name.html