<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[Stories by Phat Thanh Nguyen on Medium]]></title>
        <description><![CDATA[Stories by Phat Thanh Nguyen on Medium]]></description>
        <link>https://medium.com/@ngthphat?source=rss-a82d6740fe84------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/0*hyEuRTnrPFyLWLxs.</url>
            <title>Stories by Phat Thanh Nguyen on Medium</title>
            <link>https://medium.com/@ngthphat?source=rss-a82d6740fe84------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Sat, 14 Nov 2026 12:30:51 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@ngthphat/feed" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com/" rel="hub"/>
        <item>
            <title><![CDATA[Server Name Indication (SNI) Support]]></title>
            <link>https://medium.com/@ngthphat/server-name-indication-sni-support-ebaa3d1c222e?source=rss-a82d6740fe84------2</link>
            <guid isPermaLink="false">https://medium.com/p/ebaa3d1c222e</guid>
            <category><![CDATA[sni]]></category>
            <category><![CDATA[tls]]></category>
            <category><![CDATA[security]]></category>
            <category><![CDATA[https]]></category>
            <dc:creator><![CDATA[Phat Thanh Nguyen]]></dc:creator>
            <pubDate>Fri, 09 Jun 2017 04:14:53 GMT</pubDate>
            <atom:updated>2018-06-11T04:34:00.325Z</atom:updated>
            <content:encoded><![CDATA[<p>Recently, our team faced an issue relate SNI, which leading to the system cannot complete at handshake step. The integration perfectly worked in the past. The issue happened after partner side they updated their system.</p><p>What is SNI? Wikipedia:</p><p><strong><em>Server Name Indication</em></strong><em> (</em><strong><em>SNI</em></strong><em>) is an extension to the </em><a href="https://en.wikipedia.org/wiki/Transport_layer_security"><em>TLS</em></a><em> computer networking protocol </em><a href="https://en.wikipedia.org/wiki/Server_Name_Indication#cite_note-1"><em>[1]</em></a><em> by which a </em><a href="https://en.wikipedia.org/wiki/Client_(computing)"><em>client</em></a><em> indicates which </em><a href="https://en.wikipedia.org/wiki/Hostname"><em>hostname</em></a><em> it is attempting to connect to at the start of the </em><a href="https://en.wikipedia.org/wiki/Handshaking"><em>handshaking</em></a><em> process. This allows a server to present multiple </em><a href="https://en.wikipedia.org/wiki/Public_key_certificate"><em>certificates</em></a><em> on the same </em><a href="https://en.wikipedia.org/wiki/IP_address"><em>IP address</em></a><em> and </em><a href="https://en.wikipedia.org/wiki/TCP_port"><em>TCP port</em></a><em> number and hence allows multiple secure (</em><a href="https://en.wikipedia.org/wiki/HTTP_Secure"><em>HTTPS</em></a><em>) websites (or any other </em><a href="https://en.wikipedia.org/wiki/Server_(computing)#Types_of_servers"><em>Service</em></a><em> over TLS) to be served by the same IP address without requiring all those sites to use the same certificate</em></p><p>This should handle by JVM, unfortunately, there is a bug in the way JVM handle SNI <a href="http://bugs.java.com/bugdatabase/view_bug.do?bug_id=8144566">http://bugs.java.com/bugdatabase/view_bug.do?bug_id=8144566</a>. Oracle planned to release the fix with JDK 9.</p><p>I found a workaround solution as below:</p><pre>SSLContext sslcontext = SSLContexts.createSystemDefault();<br>SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslcontext) {<br><br>    @Override<br>    public Socket connectSocket(<br>            int connectTimeout,<br>            Socket socket,<br>            HttpHost host,<br>            InetSocketAddress remoteAddress,<br>            InetSocketAddress localAddress,<br>            HttpContext context) throws IOException, ConnectTimeoutException {<br>        if (socket instanceof SSLSocket) {<br>            try {<br>                PropertyUtils.setProperty(socket, &quot;host&quot;, host.getHostName());<br>            } catch (NoSuchMethodException ex) {<br>            } catch (IllegalAccessException ex) {<br>            } catch (InvocationTargetException ex) {<br>            }<br>        }<br>        return super.connectSocket(connectTimeout, socket, host, remoteAddress,<br>                localAddress, context);<br>    }<br><br>};<br>CloseableHttpClient httpclient = HttpClients.custom()<br>        .setSSLSocketFactory(sslsf)<br>        .build();<br>CloseableHttpResponse response = httpclient.execute(new HttpGet(&quot;https://verisign.com/&quot;));<br>try {<br>    System.out.println(response.getStatusLine());<br>    EntityUtils.consume(response.getEntity());<br>} finally {<br>    response.close();<br>}</pre><p>Ref:<br> <a href="https://issues.apache.org/jira/browse/HTTPCLIENT-1119">https://issues.apache.org/jira/browse/HTTPCLIENT-1119</a></p><p><em>Originally published at </em><a href="https://ngthphat.wordpress.com/2017/06/09/httpclient-support-sni/"><em>ngthphat.wordpress.com</em></a><em> on June 9, 2017.</em></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=ebaa3d1c222e" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[How to handle REST request with multipart/form-data in Camel ?]]></title>
            <link>https://medium.com/@ngthphat/how-to-handle-rest-request-with-multipart-form-data-in-camel-a4f3ab7403c7?source=rss-a82d6740fe84------2</link>
            <guid isPermaLink="false">https://medium.com/p/a4f3ab7403c7</guid>
            <category><![CDATA[multipart]]></category>
            <category><![CDATA[camel]]></category>
            <category><![CDATA[netty]]></category>
            <category><![CDATA[java]]></category>
            <category><![CDATA[file-upload]]></category>
            <dc:creator><![CDATA[Phat Thanh Nguyen]]></dc:creator>
            <pubDate>Fri, 31 Mar 2017 03:59:47 GMT</pubDate>
            <atom:updated>2018-06-12T13:30:02.739Z</atom:updated>
            <content:encoded><![CDATA[<p>Apache Camel is one of my favorite open source frameworks in the Java environment. It enables easy integration of different applications which use several protocols and technologies. You can use Java, Spring XML, Scala or Groovy. Almost every technology you can imagine is available, for example, HTTP, FTP, JMS, EJB, JPA, RMI, JMS, JMX, LDAP, Netty, and much more . Besides, own custom components can be created very easily.</p><p>This article shows you how to handle multipart/form-data in camel. Assume that we need to write an application that allows user to upload multiple reports via RESTful Api. To solve this requirement, we need complete steps below:</p><p>1) Tell camel which component we want to handle REST request<br>2) Define REST signature<br>3) Define a processor to extract data<br>4) Write unit test<br>5) Write Main class and test with Postman</p><p>Now, Let’s start with some dependencies as below:</p><pre>&lt;properties&gt;<br>    &lt;java.version&gt;1.8&lt;/java.version&gt;<br>    &lt;camel.version&gt;2.18.1&lt;/camel.version&gt;<br>    &lt;sf4j.version&gt;1.7.21&lt;/sf4j.version&gt;<br>&lt;/properties&gt;</pre><pre>&lt;dependency&gt;<br>    &lt;groupId&gt;org.apache.camel&lt;/groupId&gt;<br>    &lt;artifactId&gt;<strong>camel-core</strong>&lt;/artifactId&gt;<br>    &lt;version&gt;${camel.version}&lt;/version&gt;<br>&lt;/dependency&gt;<br>&lt;dependency&gt;<br>    &lt;groupId&gt;org.apache.camel&lt;/groupId&gt;<br>    &lt;artifactId&gt;<strong>camel-netty</strong>&lt;/artifactId&gt;<br>    &lt;version&gt;${camel.version}&lt;/version&gt;<br>&lt;/dependency&gt;<br>&lt;dependency&gt;<br>    &lt;groupId&gt;org.apache.camel&lt;/groupId&gt;<br>    &lt;artifactId&gt;<strong>camel-netty4-http</strong>&lt;/artifactId&gt;<br>    &lt;version&gt;${camel.version}&lt;/version&gt;<br>&lt;/dependency&gt;<br>&lt;dependency&gt;<br>    &lt;groupId&gt;org.apache.camel&lt;/groupId&gt;<br>    &lt;artifactId&gt;camel-test&lt;/artifactId&gt;<br>    &lt;version&gt;${camel.version}&lt;/version&gt;<br>    &lt;scope&gt;test&lt;/scope&gt;<br>&lt;/dependency&gt;<br>&lt;dependency&gt;<br>    &lt;groupId&gt;org.slf4j&lt;/groupId&gt;<br>    &lt;artifactId&gt;slf4j-api&lt;/artifactId&gt;<br>    &lt;version&gt;${sf4j.version}&lt;/version&gt;<br>    &lt;type&gt;jar&lt;/type&gt;<br>&lt;/dependency&gt;<br>&lt;dependency&gt;<br>    &lt;groupId&gt;org.slf4j&lt;/groupId&gt;<br>    &lt;artifactId&gt;slf4j-simple&lt;/artifactId&gt;<br>    &lt;version&gt;${sf4j.version}&lt;/version&gt;<br>&lt;/dependency&gt;</pre><p>Step 1) We will tell to camel that we will use netty4-http as Restful handler. To simplify, I add some fixed value as below. However in case of production code, you should move them to config file.</p><pre>public class BaseRestRoute extends RouteBuilder {<br>    @Override <br>    public void configure() throws Exception {<br>        restConfiguration().component(&quot;<strong>netty4-http</strong>&quot;)<br>                .host(&quot;localhost&quot;)<br>                .port(&quot;8881&quot;)<br>                .bindingMode(RestBindingMode.auto);<br>    }<br>}</pre><p>Step 2) Define REST signature. One of my favorite point about camel framework its fluent api. How easy it is to define REST signature?</p><pre>public class UploadReportRoute extends BaseRestRoute{<br>    private Processor processor;<br>    public UploadReportRoute(Processor processor){<br>        this.processor = processor;<br>    }<br>    @Override <br>    public void configure() throws Exception {<br>        super.configure();<br>        rest(&quot;/<strong>upload</strong>&quot;)<br>                .description(&quot;Upload Multiple Report via camel and netty&quot;)<br>                .consumes(&quot;<strong>multipart/form-data</strong>&quot;)<br>                .produces(&quot;<strong>application/json</strong>&quot;)<br>                .post(&quot;/report&quot;)<br>                .to(&quot;seda:uploadReportProcessor&quot;);<br>        from(&quot;seda:uploadReportProcessor&quot;)<br>                .routeId(&quot;uploadProcessorRoute&quot;)<br>                .process(processor);<br>    }<br>}</pre><p>We have just defined a REST API (POST — ‘/upload/report’) consume multipart/form-data and produce a result in JSON format.</p><p>Step 3) Define a camel processor to extract data from nettyHttpRequest</p><pre>public class UploadProcessor implements Processor {<br>    private static final Logger LOGGER = LoggerFactory.getLogger(UploadProcessor.class);<br>    @Override <br>    public void process(Exchange exchange) throws Exception {<br>        HttpPostRequestDecoder postRequest = new HttpPostRequestDecoder(exchange.getIn(NettyHttpMessage.class).getHttpRequest());<br>        getHttpDataAttributes(postRequest);<br>        exchange.getIn().setBody(new ResponseWrapper(ResponseStatus.Success));<br>    }<br>    public void getHttpDataAttributes(HttpPostRequestDecoder request) {<br>        ResponseWrapper result = new ResponseWrapper();<br>        try {<br>            for (InterfaceHttpData part : request.getBodyHttpDatas()) {<br>                if (part instanceof MixedAttribute) {<br>                    Attribute attribute = (MixedAttribute) part;<br>                    LOGGER.info(String.format(“Found key: %s and value: %s &quot;, attribute.getName(), attribute.getValue()));<br>                } else if (part instanceof MixedFileUpload) {<br>                    MixedFileUpload attribute = (MixedFileUpload) part;<br>                    LOGGER.info(String.format(&quot;Found key: %s and value: %s &quot;, attribute.getName(), attribute.getFilename()));<br>                }<br>            }<br>        } catch (IOException e) {<br>            String errorMsg = String.format(&quot;Cannot parse request&quot;);<br>            result.setMessage(errorMsg);<br>            LOGGER.error(errorMsg,e);<br>        } finally {<br>            request.destroy();<br>        }<br>    }<br>}</pre><p>Step 4) Write some test</p><p>Let define some mock endpoints as below:</p><pre>@Produce(uri = &quot;direct:mockProducerRoute&quot;)<br>protected ProducerTemplate templateProducerRoute;<br>@EndpointInject(uri = &quot;mock:mockEndRoute&quot;)<br>protected MockEndpoint mockEndRoute;<br>@Before <br>public void mockEndpoints() throws Exception {<br>    AdviceWithRouteBuilder routeMockEndpoint = new AdviceWithRouteBuilder() {<br>        @Override <br>        public void configure() throws Exception {<br>            replaceFromWith(templateProducerRoute.getDefaultEndpoint().getEndpointUri());<br>            interceptSendToEndpoint(&quot;direct:uploadServiceProcessor&quot;)<br>                    .skipSendToOriginalEndpoint()<br>                    .to(mockEndRoute);<br>        }<br>    };<br>    context.getRouteDefinition(&quot;uploadProcessorRoute&quot;).adviceWith(context, routeMockEndpoint);<br>}<br>@Override <br>protected RoutesBuilder[] createRouteBuilders() throws Exception {<br>    return new RoutesBuilder[]{<br>            new UploadReportRoute(new UploadProcessor())};<br>}</pre><p>You can checkout an example of test case in my github repo. Whenever the test case is executed, you able to see some information log as:<br>UploadProcessor — Found part with key: paymentMethod and value: ippOcbc<br>UploadProcessor — Found part with key: file and value: report_file_name.csv</p><p>Step 5) Write App class and test with Postman<br>Let create a new class name “App”, then add UploadReportRoute into CamelContext :</p><pre>public static void main(String[] args) throws Exception {<br>    UploadReportRoute uploadService = new UploadReportRoute(new UploadProcessor());<br>    Main main = new Main();<br>    main.addRouteBuilder(uploadService);<br>    main.run(args);<br>}</pre><p>Let start our application, after the application is started successful , you will able to see some log message as below:<br>[main] INFO org.apache.camel.component.netty4.SingleTCPNettyServerBootstrapFactory — ServerBootstrap binding to localhost:8881<br>[main] INFO org.apache.camel.component.netty4.NettyConsumer — Netty consumer bound to: localhost:8881<br>[main] INFO org.apache.camel.impl.DefaultCamelContext — Route: route1 started and consuming from: <a href="http://localhost:8881/upload/report?httpMethodRestrict=POST">http://localhost:8881/upload/report?httpMethodRestrict=POST</a></p><p>Let do real the test with Postman:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/665/0*WFkwGZ_Dz20qRplu" /></figure><p>It’s worked as expectation.</p><p>By default, netty allows upload maximum 1MB for each part file. You can increase this number by updating the BaseRestRoute:</p><pre>getContext().setUseMDCLogging(true);<br>Long maxSize = 2L * 1024 * 1024;<br>restConfiguration().component(&quot;netty4-http&quot;)<br>        .host(&quot;localhost&quot;)<br>        .port(&quot;8881&quot;)<br>        .endpointProperty(&quot;chunkedMaxContentLength&quot;, maxSize.toString())<br>        .bindingMode(RestBindingMode.auto);</pre><p>You can check out the source code from this <a href="https://github.com/ngthphat/camel-netty-upload-file">link</a>.</p><p><em>Originally published at </em><a href="https://ngthphat.wordpress.com/2017/03/31/how-to-handle-rest-request-with-multipartform-data-in-camel/"><em>ngthphat.wordpress.com</em></a><em> on March 31, 2017.</em></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=a4f3ab7403c7" width="1" height="1" alt="">]]></content:encoded>
        </item>
    </channel>
</rss>