* apache httpclient 4.4 이상 버전

import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.client.HttpClients;
import javax.net.ssl.SSLContext;
import org.apache.http.ssl.SSLContexts;
import org.apache.http.ssl.TrustStrategy;
import java.security.cert.X509Certificate;
import java.security.cert.CertificateException;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.impl.client.CloseableHttpClient;

HttpClientBuilder httpClientBuilder = HttpClients.custom();

SSLContext sslcontext = SSLContexts.custom()
    .useProtocol("SSL")
// .loadTrustMaterial(null, new TrustSelfSignedStrategy())
    .loadTrustMaterial(null, new TrustStrategy() {
        @Override
        public boolean isTrusted(X509Certificate[] paramArrayOfX509Certificate, String paramString) throws CertificateException {
            return true;
        }
    }).build();

httpClientBuilder.setSSLHostnameVerifier(new NoopHostnameVerifier()).setSSLContext(sslcontext);

CloseableHttpClient httpClient = httpClientBuilder.build();
httpClient.execute();



* apache httpclient 4.3 이하 버전

import javax.net.ssl.SSLContext;
import org.apache.http.conn.ssl.SSLContexts;
import org.apache.http.conn.ssl.TrustSelfSignedStrategy;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;

SSLContext sslcontext = SSLContexts.custom()
    .useSSL()
    .loadTrustMaterial(null, new TrustSelfSignedStrategy())
/*
    .loadTrustMaterial(null, new TrustStrategy() {
        @Override
        public boolean isTrusted(java.security.cert.X509Certificate[] paramArrayOfX509Certificate, String paramString) throws java.security.cert.CertificateException {
            return true;
        }
    })
*/
    .build();

SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslcontext, SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);

CloseableHttpClient httpClient = HttpClients.custom()
    .setSSLSocketFactory(sslsf)
    .build();

httpClient.execute();




===========================================================================================


출처 : http://comphy.iptime.org/user/wordpress/?p=81


Apache Commons HttpClient는 JDK 1.4부터 등장한 Java Secure Socket Extension (JSSE)를 기반으로 SSL (또는 TLS) 상의 HTTP (HTTP/S) 통신에 대한 지원을 제공한다. Commons HttpClient를 이용한 HTTP/S 통신 방법을 살펴보자.

1. Commons HttpClient 사용하기
일반적으로 Commons HttpClient의 HTTP 통신은 아래와 같다.

import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.httpclient.methods.GetMethod;
// import org.apache.commons.httpclient.methods.PostMethod;

public class HttpClientSample {

    public static void main(String[] args) {

        HttpClient httpclient = new HttpClient();
        GetMethod httpget = new GetMethod("http://www.java2go.net/");
        // PostMethod httppost = new 
        // PostMethod("https://www.java2go.net/nopage.html");

        try {
            int statusCode = httpclient.executeMethod(httpget);

            System.out.println("Response Status Code: " + statusCode);
            System.out.println("Response Status Line: " + httpget.getStatusLine());
            System.out.println("Response Body: \n" 
                    + httpget.getResponseBodyAsString());

            if (statusCode == HttpStatus.SC_OK) {
                // if (statusCode >= 200 && statusCode < 300) {
                System.out.println("Success!");
            } else {
                System.out.println("Fail!");
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            httpget.releaseConnection();
        }
    }
}


정상적인 경우 결과는 아래와 같다.

Response Status Code: 200
Response Status Line: HTTP/1.1 200 OK
Response Body: 
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Java2go.net</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />

... 생략 ...

</body>
</html>
Success!


실패한 경우 결과는 아래와 같다.

Response Status Code: 404
Response Status Line: HTTP/1.1 404 Not Found
Response Body: 
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<HTML><HEAD>
<TITLE>404 Not Found</TITLE>
</HEAD><BODY>
<H1>Not Found</H1>
The requested URL /nopage.html was not found on this server.<P>
<HR>
<ADDRESS>Apache/1.3.37p3 Server at java2go.net Port 80</ADDRESS>
</BODY></HTML>

Fail!


2. SSL 통신과 Trusted CA 인증서 등록하기
JSSE가 올바르게 설치되었다면, 기본적으로 HTTP/S 통신도 일반 HTTP 통신과 같이 위와 같은  코드를 그대로 사용할 수 있다. 단, 이 경우에 서버 싸이트 인증서가 클라이언트쪽에 신뢰하는 인증서로서 인식될 수 있어야 한다. 그렇지 않으면 아래와 같은 SSL handshake 오류가 발생한다.

javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: 
No trusted certificate found
at com.sun.net.ssl.internal.ssl.BaseSSLSocketImpl.a(DashoA12275)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.a(DashoA12275)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.a(DashoA12275)
at com.sun.net.ssl.internal.ssl.SunJSSE_az.a(DashoA12275)
at com.sun.net.ssl.internal.ssl.SunJSSE_az.a(DashoA12275)
at com.sun.net.ssl.internal.ssl.SunJSSE_ax.a(DashoA12275)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.a(DashoA12275)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.j(DashoA12275)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.a(DashoA12275)
at com.sun.net.ssl.internal.ssl.AppOutputStream.write(DashoA12275)
... 생략 ...
Caused by: sun.security.validator.ValidatorException: No trusted certificate found
at sun.security.validator.SimpleValidator.buildTrustedChain(SimpleValidator.java:304)
at sun.security.validator.SimpleValidator.engineValidate(SimpleValidator.java:107)
at sun.security.validator.Validator.validate(Validator.java:202)
at com.sun.net.ssl.internal.ssl.X509TrustManagerImpl.checkServerTrusted(DashoA12275)
at com.sun.net.ssl.internal.ssl.JsseX509TrustManager.checkServerTrusted(DashoA12275)
... 17 more


JDK에 의해 제공되어지는 Java Standard Trust Keystore는 ${JAVA_HOME}/jre/lib/security/cacerts에 위치한다. 이 cacerts 키스토어 파일에 대상 서버의 SSL 싸이트 인증서를 발행한 기관의 CA 인증서가 신뢰하는 인증서로 등록되어 있어야 한다. 다음과 같이 keytool.exe를 사용하여 키스토어에 등록된 신뢰하는 인증서 목록을 조회할 수 있다.

C:\jdk1.4.2\jre\lib\security>keytool -list -v -keystore cacerts
Enter keystore password: changeit

Keystore type: jks
Keystore provider: SUN

Your keystore contains 52 entries

Alias name: verisignclass3g2ca
Creation date: Jun 16, 2004
Entry type: trustedCertEntry

Owner: OU=VeriSign Trust Network, OU="(c) 1998 VeriSign, Inc. - For authorized
use only", OU=Class 3 Public Primary Certification Authority - G2, O="VeriSign,
Inc.", C=US
Issuer: OU=VeriSign Trust Network, OU="(c) 1998 VeriSign, Inc. - For authorized
use only", OU=Class 3 Public Primary Certification Authority - G2, O="VeriSign,
Inc.", C=US
Serial number: 7dd9fe07cfa81eb7107967fba78934c6
Valid from: Mon May 18 09:00:00 KST 1998 until: Wed Aug 02 08:59:59 KST 2028
Certificate fingerprints:
MD5: A2:33:9B:4C:74:78:73:D4:6C:E7:C1:F3:8D:CB:5C:E9
SHA1: 85:37:1C:A6:E5:50:14:3D:CE:28:03:47:1B:DE:3A:09:E8:F8:77:0F


*******************************************
*******************************************


Alias name: entrustclientca
Creation date: Jan 10, 2003
Entry type: trustedCertEntry

Owner: CN=Entrust.net Client Certification Authority, OU=(c) 1999 Entrust.net
Limited, OU=www.entrust.net/Client_CA_Info/CPS incorp. by ref. limits liab.,
O=Entrust.net, C=US
Issuer: CN=Entrust.net Client Certification Authority, OU=(c) 1999 Entrust.net
Limited, OU=www.entrust.net/Client_CA_Info/CPS incorp. by ref. limits liab.,
O=Entrust.net, C=US
Serial number: 380391ee
Valid from: Wed Oct 13 04:24:30 KST 1999 until: Sun Oct 13 04:54:30 KST 2019
Certificate fingerprints:
MD5: 0C:41:2F:13:5B:A0:54:F5:96:66:2D:7E:CD:0E:03:F4
SHA1: DA:79:C1:71:11:50:C2:34:39:AA:2B:0B:0C:62:FD:55:B2:F9:F5:80

... 생략 ...


다음과 같은 방법으로 키스토어 파일에 Trusted CA 인증서를 추가로 등록할 수 있다. CA 인증서는 웹브라우저에서 열쇠모양의 아이콘을 누르면 해당 싸이트 인증서를 볼 수 있고, 거기에서 인증서를 복사할 수 있다. 아래 예시는 Trusted CA 인증서를 ${JAVA_HOME}\jre\lib\secutiry\cacerts에 등록을 하는 방법이다.

C:\j2sdk1.4.2\jre\lib\security>keytool -import -keystore cacerts -file 
c:\certs\TradeSignCA.cer -alias tradesignca
Enter keystore password:  changeit
Owner: CN=TradeSignCA, OU=AccreditedCA, O=TradeSign, C=KR
Issuer: CN=KISA RootCA 1, OU=Korea Certification Authority Central, O=KISA, C=KR
Serial number: 2764
Valid from: Tue Nov 15 11:14:59 KST 2005 until: Sun Nov 15 11:14:59 KST 2015
Certificate fingerprints:
         MD5:  C2:E0:27:3D:36:4B:86:29:74:4D:6B:9F:5A:B5:01:26
         SHA1: A0:CD:6A:6D:A4:7B:73:15:F5:8A:CB:1F:C6:FD:C2:14:C9:3B:5D:BE
Trust this certificate? [no]:  y
Certificate was added to keystore


이렇게 서버 CA 인증서가 신뢰하는 인증서로 등록이 되면, 일반 HTTP 통신과 같이 URL이 https://인 주소로 SSL 통신을 정상적으로 할 수 있다. 키스토어 파일에서 인증서를 제거하는 방법은 아래와 같다.

C:\jdk1.4.2\jre\lib\security>keytool -delete -keystore cacerts -alias tradesignca
Enter keystore password:  changeit


아래처럼 서버 싸이트 인증서를 바로 등록할 수도 있다. 그러나 싸이트 인증서는 보통 Trusted CA 인증서보다 유효기간이 짧아 매번 갱신을 해줘야 할 것이다.

C:\jdk1.4.2\jre\lib\security>keytool -import -keystore cacerts -file
c:\certs\www.java2go.net.cer -alias mykey
Enter keystore password:  changeit
Owner: CN=www.java2go.net, OU=KTNET, OU=AccreditedCA, O=TradeSign, C=KR
Issuer: CN=TradeSignCA, OU=AccreditedCA, O=TradeSign, C=KR
Serial number: 596e9cf0
Valid from: Tue May 12 13:37:20 KST 2009 until: Wed May 12 14:07:20 KST 2010
Certificate fingerprints:
         MD5:  EF:EB:11:66:BD:CC:B1:D4:88:35:AB:25:9F:2F:79:8B
         SHA1: DC:C4:31:20:46:25:72:68:8B:96:AC:92:EE:F3:8D:15:EF:A7:46:2D
Trust this certificate? [no]:  y
Certificate was added to keystore


3. Commons HttpClient의 SSL 커스터마이징
기본적인 사용법 이외에 자기서명(self-signed)되었거나 또는 신뢰되지 않은(untrusted) SSL 인증서를 사용하는 경우처럼 SSL 통신을 커스터마이징할 필요가 있을 수 있다.

기본 커스터마이징 방법은 org.apache.commons.httpclient.protocol.SecureProtocolSocketFactory을 구현해서 org.apache.commons.httpclient.protocol.Protocol를 생성하여 등록해주면 된다. 다음과 같은 코드 한 줄을 추가해 주면 된다. 자세한 내용은 이곳을 참조한다.

Protocol.registerProtocol("https", 
new Protocol("https", new MySSLSocketFactory(), 443));


Commons HttpClient의 contribution 패키지에서 사용할 수 있는 EasySSLProtocolSocketFactory를 사용하면 신뢰되지 않은 자기서명(self-signed)된 인증서를 가진 서버와도 바로 SSL 통신을 할 수 있다. 즉, cacerts 키스토어에 서버 인증서를 별도로 등록할 필요가 없다. 다음과 같이 사용할 수 있다.

import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.httpclient.contrib.ssl.EasySSLProtocolSocketFactory;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.httpclient.protocol.Protocol;

public class HttpClientSample2 {

    public static void main(String[] args) {

        HttpClient httpclient = new HttpClient();
        GetMethod httpget = new GetMethod("https://www.java2go.net/");

        try {
            Protocol.registerProtocol("https", new Protocol("https",
                    new EasySSLProtocolSocketFactory(), 443));

            int statusCode = httpclient.executeMethod(httpget);

            System.out.println("Response Status Code: " + statusCode);
            System.out.println("Response Status Line: " + httpget.getStatusLine());
            System.out.println("Response Body: \n"
                    + httpget.getResponseBodyAsString());

            if (statusCode == HttpStatus.SC_OK) {
                System.out.println("Success!");
            } else {
                System.out.println("Fail!");
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            httpget.releaseConnection();
        }
    }
}


호출 로그

{DEBUG} [2009-06-18 23:29:31,062] <org.apache.commons.httpclient.HttpConnection> ()
 : Open connection to www.java2go.net:443


참조: http://hc.apache.org/httpclient-3.x/sslguide.html


redmine : http://www.redmine.org/
redmine plugin list : http://www.redmine.org/projects/redmine/wiki/Plugin_List

ckeditor 다운로드 : https://github.com/a-ono/redmine_ckeditor

참고 : http://mkyojung.wordpress.com/2012/08/30/bitnami-redmine-%EC%84%A4%EC%B9%98-%EA%B4%80%EB%A0%A8-trouble-shooting/
         http://bitnami.com/


0. Redmine이 실행되고 있다면 중지한다.


1. CKEditor를 다운로드 받는다.
    redmine 버전이 1.xx 인 경우 ${RAILS_HOME}/vendor/plugins 폴더에 2.xx 버전인 경우 ${RAILS_HOME}/plugins 폴더에 압축을 해제하고 폴더명으로 redmine_ckeditor 로 변경한다.

   ${RAILS_HOME}은 Redmine 홈 디렉토리로 Redmine을 bitnami 패키지로 설치를 했다면 C:/BitNami\redmine-2.3.2-0/apps/redmine/htdocs 이다.


2. plugins 설치   

C:\BitNami\redmine-2.3.2-0\apps\redmine\htdocs>bundle install --without development test
또는
C:\BitNami\redmine-2.3.2-0\apps\redmine\htdocs>bundle install --no-deployment

참고로 bitnami 패키지로 설치한 경우 cmd 창을 열 때 시작 > 프로그램 > BitNami Redmine Stack > BitNami Redmine Stack 사용 아이콘을 클릭하여 cmd를 열어야 환경파일이 로딩된다. (또는 C:/BitNami/redmine-2.3.2-0/use_redmine.bat) 파일을 클릭하여 실행한 cmd 에서 해도 된다.


3. Redmine을 시작한다.

4. Redmine 로그인 > 관리 (최상단 메뉴) > 플러그인 화면에서 플러그인 설치 확인을 한다. 플러그인이 있으면 설치가 완료 된 것이고 설정 글자를 클릭하면 ckeditor 설정을 할 수 있다.

5. Redmine 로그인 > 관리 (최상단 메뉴) > 설정 > 일반 탭에서 본문형식의 값을 CKEditor로 변경하고 저장하면 완료된다.


참고 : http://tomcat.apache.org/tomcat-7.0-doc/ssl-howto.html
       https://tomcat.apache.org/tomcat-7.0-doc/config/http.html
       https://access.redhat.com/solutions/1232233
      http://www.sysnet.pe.kr/Default.aspx?mode=2&sub=0&detail=1&pageno=0&wid=1132&rssMode=1&wtype=0
       https://www.comodossl.co.kr/Certificate/InstallGuide/Apache.htm
       http://minix.tistory.com/395
       http://charmpa.egloos.com/1535479
        https://www.comodossl.co.kr/certificate/ssl-installation-guides/Tomcat-csr-crt.aspx



무료 인증기관 : http://t.co/1nFgVLJd


1. keystore 파일 생성

jdk/bin 폴더로 이동
keytool -genkey -alias tomcat -keyalg RSA -keystore tomcat.keystore

키 저장소 비밀번호 입력:
새 비밀번호 다시 입력:
이름과 성을 입력하십시오.
 [Unknown]:  maruara
조직 단위 이름을 입력하십시오.
 [Unknown]:
조직 이름을 입력하십시오.
 [Unknown]:
구/군/시 이름을 입력하십시오?
 [Unknown]:
시/도 이름을 입력하십시오.
 [Unknown]:  seoul
이 조직의 두 자리 국가 코드를 입력하십시오.
 [Unknown]:  KR
N=maruara, OU=Unknown, O=Unknown, L=Unknown, ST=seoul, C=KR이(가) 맞습니까?
 [아니오]:  y

tomcat>에 대한 키 비밀번호를 입력하십시오.
       (키 저장소 비밀번호와 동일한 경우 Enter 키를 누름):


2. tomcat - server.xml 설정 추가

<Connector port="8443" protocol="org.apache.coyote.http11.Http11Protocol" SSLEnabled="true"
               maxThreads="150" scheme="https" secure="true"
               clientAuth="false" sslProtocol="TLS"
               keystorePass="tomcat" keystoreFile="C:/Program Files/Java/jdk1.7.0_25/bin/tomcat.keystore"
                />


참고 : Jboss

<connector name="https" protocol="HTTP/1.1" scheme="https" socket-binding="https" secure="true" enable-lookups="false">
    <ssl name="ombs-ssl" key-alias="Key Alias" password="비밀번호" certificate-key-file="/etc/pki/tls/private/ombs.keystore" protocol="TLSv1" verify-client="false" keystore-type="JKS" />
</connector>
<!-- ALL,SSLv2,SSLv3,TLSv1,TLSv1.1,TLSv1.2 --> 



3. 접속 테스트

https://localhost:8443/ 



===========================================================================================


# Tomcat 버젼 7.X 의 경우..
< -- Define a SSL Coyote HTTP/1.1 Connector on port 8443 -->
<Connector port="8443"
   maxThreads="200"
   scheme="https" secure="true" SSLEnabled="true"
   keystoreFile="키스토어파일경로/hanbiro.key" keystorePass="(hanbiro.key 패스워드)" clientAuth="false" sslProtocol="TLS" sslEnabledProtocols="TLSv1,TLSv1.1,TLSv1.2"

/>

# Tomcat 버젼 6.X 의 경우..
<!--Define a SSL Coyote HTTP/1.1 Connector on port 8443 -->
<Connector port="443"
   maxThreads="150" minSpareThreads="25" maxSpareThreads="75" enableLookups="false" disableUploadTimeout="true"
   acceptCount="100" debug="0" scheme="https" secure="true" SSLEnabled="true"  clientAuth="false" sslProtocol="TLS"
   keystoreFile="키스토어파일경로/hanbiro.key" keystorePass="(hanbiro.key 패스워드)" 
/>

# Tomcat 버젼 5.X 의 경우..
<!--Define a SSL Coyote HTTP/1.1 Connector on port 8443 -->
<Connector port="443"
   maxThreads="150" minSpareThreads="25" maxSpareThreads="75"  enableLookups="false" disableUploadTimeout="true"
   acceptCount="100" debug="0" scheme="https" secure="true"  clientAuth="false" sslProtocol="TLS"
   keystoreFile="키스토어파일경로/hanbiro.key"  keystorePass="(hanbiro.key 패스워드)" 
/>

# Tomcat 버전 4.X 의 경우.
<!-- Define a SSL Coyote HTTP/1.1 Connector on port 8443 -->
<Connector className="org.apache.coyote.tomcat4.CoyoteConnector" port="443" minProcessors="5" maxProcessors="75"
  enableLookups="true"  acceptCount="100" debug="0" scheme="https" secure="true"
  useURIValidationHack="false" disableUploadTimeout="true" />
<Factory className="org.apache.coyote.tomcat4.CoyoteServerSocketFactory"
  clientAuth="false" protocol="TLS"  keystoreFile="키스토어파일경로/hanbiro.key"  keystorePass="(hanbiro.key 패스워드)" 
/>


SSL, TLS 보안 관련 : http://docs.aws.amazon.com/ko_kr/AWSEC2/latest/UserGuide/SSL-on-an-instance.html

SSLProtocol -SSLv2 -SSLv3 +TLSv1 +TLSv1.1 +TLSv1.2



=====================================================================

출처 : http://firstboos.tistory.com/entry/SSL-cipher-suite-order-%EC%A1%B0%EC%A0%95


웹 브라우저로 https:// 주소로 접속할때, 클라이언트와 서버 간에 교환하는 보안 알고리즘 집합인 cipher suite 의 우선 순위를 조정할 필요가 생긴다. 주로 메시지 인증 알고리즘을 sha2 로 바꿔달라는 요구사항이 발생한다. (쇼핑몰, 특히 CC 인증 ㅠㅠ 요구사항인 경우가 많다.)


인증서 생성

- Tomcat : JKS 타입

# keytool -genkey -alias KeystoreAlias -keysize 2048 -keyalg RSA -keystore mykeystore -dname "CN=mycompany.com, OU=webteam, O=MyCompany, L=seoul, ST=seoul, C=kr"

-> 키 교환 알고리즘이 RSA, 키 사이즈는 2048 로 설정

※ keytool 은 keysize 2048 로 설정하면 서명 알고리즘이 sha256 으로 설정된다. 


- Tomcat : PKCS12  타입

1. openssl req -nodes -sha256 -newkey rsa:2048 -keyout server.key -out server.csr -subj "/C=kr/ST=seoul/L=seoul/O=MyCompany/OU=webteam/CN=mycompany.com"

-> 키 교환 알고리즘이 RSA, 키 사이즈는 2048 , 서명 알고리즘은 sha256 으로 설정.

-> server.key : 서버 개인키(private key), server.csr : 서버 인증 요구서.


2. openssl x509 -req -days 3650 -in server.csr -signkey server.key -out server.crt -sha256

-> -sha256 : 서명 알고리즘은 sha256  으로 설정. 만일 이 옵션이 없으면 sha1 으로 설정된다.

-> server.crt : self signed 인증서.


3. openssl pkcs12 -export -in server.crt -inkey server.key -out mykeystore

-> 1,2 번에서 생성한 파일들을 가지고 PKCS12 타입으로 키저장소(mykeystore) 파일 생성.


- Apache HTTPD

1. openssl req -nodes -sha256 -newkey rsa:2048 -keyout server.key -out server.csr -subj "/C=kr/ST=seoul/L=seoul/O=MyCompany/OU=webteam/CN=mycompany.com"

-> 키 교환 알고리즘이 RSA, 키 사이즈는 2048 , 서명 알고리즘은 sha256 으로 설정.

-> server.key : 서버 개인키(private key), server.csr : 서버 인증 요구서.


2. openssl x509 -req -days 3650 -in server.csr -signkey server.key -out server.crt -sha256

-> -sha256 : 서명 알고리즘은 sha256  으로 설정. 만일 이 옵션이 없으면 sha1 으로 설정된다.

-> server.crt : self signed 인증서.


3. openssl x509 -in server.crt -noout -text

-> 인증서 내용 확인

-> -noout : PEM 부분을 출력안하도록 설정.


Tomcat 설정

- server.xml 설정 : GCM 이 선택되도록 하기 위해서는 sslProtocol TLSv1.2 로 선택해야함.

        <Connector port="443" protocol="HTTP/1.1" URIEncoding="UTF-8" useBodyEncodingForURI="true"

                maxThreads="150" scheme="https" secure="true"

                clientAuth="false" SSLEnabled="true" sslProtocol="TLSv1.2" sslEnabledProtocols="TLSv1.2"

                  ciphers="TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384,TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,TLS_RSA_WITH_AES_128_CBC_SHA256,TLS_RSA_WITH_AES_256_CBC_SHA256,TLS_DHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,TLS_ECDHE_RSA_WITH_RC4_128_SHA,TLS_RSA_WITH_AES_128_CBC_SHA,TLS_RSA_WITH_AES_256_CBC_SHA,SSL_RSA_WITH_RC4_128_SHA"

                keystoreFile="${catalina.home}/conf/mykeystore" keyAlias="KeystoreAlias"

                keystoreType="JKS" keystorePass="키스토어패스워드" />


- server.xml 설정 2 : 어떤 환경에서는 sslProtocol 을 TLS 로 설정해야 연결되는 경우도 있다. 

<Connector port="443" protocol="HTTP/1.1" URIEncoding="UTF-8" useBodyEncodingForURI="true"

                maxThreads="150" scheme="https" secure="true"

                clientAuth="false" SSLEnabled="true" sslProtocol="TLS"

          ciphers="TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384,TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,TLS_RSA_WITH_AES_128_CBC_SHA256,TLS_RSA_WITH_AES_256_CBC_SHA256,TLS_DHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,TLS_ECDHE_RSA_WITH_RC4_128_SHA,TLS_RSA_WITH_AES_128_CBC_SHA,TLS_RSA_WITH_AES_256_CBC_SHA,SSL_RSA_WITH_RC4_128_SHA"

                keystoreFile="${catalina.home}/conf/mykeystore"                keyAlias="KeystoreAlias"

                keystoreType="JKS" keystorePass="키스토어패스워드" />


- server.xml 설정 3 : IE11 에서 "TLS_RSA_WITH_AES_256_CBC_SHA256" 먼저 선택되도록 하기 위한 설정.(크롬 브라우저에서는 TLS_RSA_WITH_AES_256_CBC_SHA 가 선택된다.)

<Connector port="443" protocol="HTTP/1.1" URIEncoding="UTF-8" useBodyEncodingForURI="true"

                maxThreads="150" scheme="https" secure="true"

                clientAuth="false" SSLEnabled="true" sslProtocol="TLS"

                ciphers="TLS_ECDH_RSA_WITH_AES_256_CBC_SHA256,TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA256,TLS_RSA_WITH_AES_256_CBC_SHA256,TLS_ECDH_RSA_WITH_AES_256_CBC_SHA,TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,TLS_RSA_WITH_AES_256_CBC_SHA"

                keystoreFile="${catalina.home}/conf/mykeystore" keyAlias="KeystoreAlias"

                keystoreType="JKS" keystorePass="키스토어패스워드" />



※ cipher : 공개키 알고리즘(RSA, Diffie-Hellman, ...) + 대칭키 알고리즘(RC4, DES, AES, ...) + 해쉬 알고리즘(MD5, SHA, ...)의 집합


Apache 설정

# yum install httpd

# yum install mod_ssl


httpd.conf 설정

<VirtualHost *:443>

    SSLEngine on

    SSLCertificateFile /etc/httpd/conf/server.crt

    SSLCertificateKeyFile /etc/httpd/conf/server.key

    SSLCertificateChainFile /etc/httpd/conf/server.csr

    SetEnvIf User-Agent ".*MSIE.*" nokeepalive ssl-unclean-shutdown

    CustomLog logs/ssl_request_log "%t %h %{SSL_PROTOCOL}x %{SSL_CIPHER}x \"%r\" %b"

    DocumentRoot /var/www.html

    SSLProtocol             all

    SSLCipherSuite          ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:ECDHE-RSA-RC4-SHA:ECDHE-ECDSA-RC4-SHA:AES128:AES256:RC4-SHA:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!3DES:!MD5:!PSK

    SSLHonorCipherOrder     on

#    SSLCompression          off

</VirtualHost>


테스트

IE 11 브라우저에서는 https:// 로 접속시,  443 포트 패킷을 캡쳐해보면 SSL handshake 과정에서 "Server Hello" 가 "TLS_DHE_RSA_WITH_AES_128_GCM_SHA256" 로 응답하는 것을 확인했다. 

그런데, 이해가 안되지만 크롬 최신버전(37.0.2062.120 m)에서는 동일한 인증서 파일인데도  "Server Hello" 가 "TLS_DHE_RSA_WITH_AES_128_GCM_SHA1" 으로 응답했다. 


- openssl 으로 접속 테스트

# openssl s_client -connect localhost:443

CONNECTED(00000003)

depth=0 C = kr, ST = seoul, L = seoul, O = MyCompany, OU = webteam, CN = mycompany.com

verify error:num=18:self signed certificate

verify return:1

depth=0 C = kr, ST = seoul, L = seoul, O = MyCompany, OU = webteam, CN = mycompany.com

verify return:1

...

...

...

---

SSL handshake has read 1463 bytes and written 477 bytes

---

New, TLSv1/SSLv3, Cipher is ECDHE-RSA-AES256-SHA384

Server public key is 2048 bit

Secure Renegotiation IS supported

Compression: NONE

Expansion: NONE

SSL-Session:

    Protocol  : TLSv1.2

    Cipher    : ECDHE-RSA-AES256-SHA384

    Session-ID: 541C0297D25D7219750A92F8D17EE82762D7505C79B96F58DECFBF2D420D5FBF

    Session-ID-ctx:

    Master-Key: C50822A4CA025BE58961E3427F8A6F9F04B5F954B9F1D6C1A091D12CF91DE4BF06BDF77F0CEEDB96FB0BC617E60E3EC2

    Key-Arg   : None

    Krb5 Principal: None

    PSK identity: None

    PSK identity hint: None

    Start Time: 1411121874

    Timeout   : 300 (sec)

    Verify return code: 18 (self signed certificate)



openssl version

CentOS 5.X 대는 기본 설치되어 있는 openssl(라이브러리가 아닌 실행 프로그램이다) 의 버전이 0.9.8e 이다. 접속하려고 하면 다음과 같은 오류가 날수 있다. openssl 의 버그일 가능성이 높다.

# openssl s_client -connect localhost:443

CONNECTED(00000003)

31789:error:14077410:SSL routines:SSL23_GET_SERVER_HELLO:sslv3 alert handshake failure:s23_clnt.c:583: 


무시하고 1.X 버전의 openssl 에서 테스트해보자. openssl 을 업데이트한다.(yum update openssl) 

# openssl s_client -connect localhost:443

CONNECTED(00000003)

depth=0 C = kr, ST = seoul, L = seoul, O = MyCompany, OU = webteam, CN = mycompany.com

verify error:num=18:self signed certificate

verify return:1

depth=0 C = kr, ST = seoul, L = seoul, O = MyCompany, OU = webteam, CN = mycompany.com

verify return:1

139902702569288:error:100AE081:elliptic curve routines:EC_GROUP_new_by_curve_name:unknown group:ec_curve.c:316:

139902702569288:error:1408D010:SSL routines:SSL3_GET_KEY_EXCHANGE:EC lib:s3_clnt.c:1641:


openssl 의 버전이 "openssl-1.0.1e-15.el6_5.15.x86_64" (rpm -qa | grep openssl) 이라면  아마 위의 마지막에 나오는 "error: elliptic curve" 이하의 오류를 볼 수 있을 것이다. 관련 내용을 찾아보면 openssl 버그라고 나온다.

이때에는 openssl 을 업데이트(yum update openssl)하면 오류 메시지가 안 나온다. openssl 의 버전도 확인해보면 중간의 15가 16으로 바뀔것이다.(관련 링크1관련 링크2 )


그외

* 인증서에서 pem 정보만 뽑아내는 스크립트

# echo -n | openssl s_client -connect localhost:443 | sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' > ./site.pem



참고한 사이트 :

http://tomcat.apache.org/tomcat-7.0-doc/ssl-howto.html

https://www.ssllabs.com/ssltest/analyze.html?d=github.com&s=192.30.252.131

http://mail-archives.apache.org/mod_mbox/tomcat-users/201405.mbox/%3CCALAJ+5Aa9_yBJbvJxUwpUM4ytDXSQ+7KHd29+fcvpKfYn6Sk1Q@mail.gmail.com%3E

https://wiki.kldp.org/wiki.php/DocbookSgml/SSL-Certificates-HOWTO

http://opentutorials.org/course/228/4894

http://coffeenix.net/board_view.php?bd_code=1661

https://www.openssl.org/docs/apps/ciphers.html#TLS_v1_2_cipher_suites


10진수를 2진수로 변환

방법 1.

 

 

 SELECT REPLACE (MAX (SYS_CONNECT_BY_PATH (SIGN (BITAND (DECI, POWER (2, (TRUNC (LOG (2, DECI) + POWER (10, -20)) + 1 - LEVEL)))), ',')), ',') BIT
      FROM (SELECT 6 DECI FROM DUAL)
CONNECT BY POWER (2, LEVEL - 1) <= DECI


방법 2.

SELECT REPLACE (MAX (SYS_CONNECT_BY_PATH (BIT, ',')), ',') BIN
      FROM (    SELECT COUNT (*) OVER () - LEVEL + 1 LVL
                     , DECODE (TRUNC (DECI / POWER (2, LEVEL)), ROUND (DECI / POWER (2, LEVEL)), 0, 1) BIT
                  FROM (SELECT 7 DECI FROM DUAL)
            CONNECT BY POWER (2, LEVEL - 1) <= DECI)
START WITH LVL = 1
CONNECT BY PRIOR LVL = LVL - 1 




2진수를 10진수로 변환

SELECT SUM (SUBSTR (BIN, LEVEL, 1) * POWER (2, LENGTH (BIN) - LEVEL)) DECI
      FROM (SELECT 11101 BIN FROM DUAL)
CONNECT BY LEVEL <= LENGTH (BIN) 



======================================================================================================
======================================================================================================

10진수로 저장한 컬럼 1개의 값으로 체크박스 checked 설정

붉은색 : 컬럼값
파란색 : 체크박스 개수

첫번째 체크박스만 체크 : 1
두번째 체크박스만 체크 : 2
첫번째/두번째 체크박스만 체크 : 3
세번째 체크박스만 체크 : 4
첫번째/세번째 체크박스만 체크 : 5
두번째/세번째 체크박스만 체크 : 6
모든 체크박스 체크 : 7

SELECT REVERSE(LPAD(REPLACE (MAX (SYS_CONNECT_BY_PATH (SIGN (BITAND (DECI, POWER (2, (TRUNC (LOG (2, DECI) + POWER (10, -20)) + 1 - LEVEL)))), ',')), ','), 3, '0')) BIT
      FROM (SELECT 6 DECI FROM DUAL)
CONNECT BY POWER (2, LEVEL - 1) <= DECI 


======================================================================================================
======================================================================================================

Java에서 진수 변환

10진수를 2진수로 변환
Integer.toBinaryString(7)

10진수를 2진수로 변환시 공백 문자열로 채워서 (붉은색이 채워질 문자, 파란색이 자리수)
String.format("%010d", Integer.parseInt(Integer.toBinaryString(7)))

2진수를 10진수로 변환
Integer.valueOf("100", 2)



출처 : http://pirrip.tistory.com/148

■ 이클립스

1. 메뉴에서 windows > show view > other > Mavn > Maven Repositories 를 선택

2. Maven Repositories 화면의 Global Repositories를 확장해서 보면 central repository가 나오는데 여기서 full index enabled를 체크해주고 rebuild index를 실행시킨다. (한 10~30분 정도 걸리는 듯)

 

3. add dependency 화면에서 원하는 jar를 검색하면 파일이 나오고 선택하면 자동으로 pom.xml에 추가되고 다운로드 된다 ^^

 - add dependency 화면을 못찾겠다면 열심히 뒤져 보도록 ㅋㅋ

 


JCaptcha

다운로드 : http://sourceforge.net/projects/jcaptcha/

참고 : http://blog.kgom.kr/52
         http://blog.naver.com/tyboss?Redirect=Log&logNo=70021305170&from=postView
         https://jcaptcha.atlassian.net/wiki/display/general/JCaptcha+and+the+SpringFramework


다운로드 한 jcaptcha-1.0-all.jar 를 프로젝트에 포함시킨다.

CaptchaController.java

CaptchaService.java

CaptchaServiceSingleton.java

ImageCaptchaEngine.java

ImageCaptchaServlet.java

index.jsp




1. Servlet 으로 설정


ImageCaptchaEngine.java (커스터마이징 CaptchaEngine)

package com.web.common.captcha;

import java.awt.Font;

import com.octo.captcha.component.image.backgroundgenerator.BackgroundGenerator;
import com.octo.captcha.component.image.backgroundgenerator.FunkyBackgroundGenerator;
import com.octo.captcha.component.image.color.RandomRangeColorGenerator;
import com.octo.captcha.component.image.fontgenerator.FontGenerator;
import com.octo.captcha.component.image.fontgenerator.RandomFontGenerator;
import com.octo.captcha.component.image.textpaster.RandomTextPaster;
import com.octo.captcha.component.image.textpaster.TextPaster;
import com.octo.captcha.component.image.wordtoimage.ComposedWordToImage;
import com.octo.captcha.component.image.wordtoimage.WordToImage;
import com.octo.captcha.component.word.wordgenerator.RandomWordGenerator;
import com.octo.captcha.component.word.wordgenerator.WordGenerator;
import com.octo.captcha.engine.image.ListImageCaptchaEngine;
import com.octo.captcha.image.gimpy.GimpyFactory;

public class ImageCaptchaEngine extends ListImageCaptchaEngine {
    protected void buildInitialFactories() {
        // 랜덤 문자 설정
        WordGenerator wgen = new RandomWordGenerator("ABCDEFGHIJKLMNOPQRSTUVWXYZ123456789");
       
        // Text 색 설정
        RandomRangeColorGenerator cgen = new RandomRangeColorGenerator(
                new int[] { 0, 100 },
                new int[] { 0, 100 },
                new int[] { 0, 100 });
       
        // Text 설정 (랜덤 시작 Text Size, 랜덤 종료 Text Size, 색)
        TextPaster textPaster = new RandomTextPaster(new Integer(4), new Integer(7), cgen, true);
       
        // 백그라운드 색 설정
        RandomRangeColorGenerator bcgen = new RandomRangeColorGenerator(
                new int[] { 150, 255 },
                new int[] { 150, 255 },
                new int[] { 150, 255 });
       
        // 백그라운드 설정 (가로 크기, 세로 크기, 색)
        BackgroundGenerator backgroundGenerator = new FunkyBackgroundGenerator(new Integer(150), new Integer(50), bcgen);
       
        // 백그라운드 기본 설정
        // BackgroundGenerator backgroundGenerator = new FunkyBackgroundGenerator(new Integer(150), new Integer(50));
       
        // 글꼴 설정
        Font[] fontsList = new Font[] {
                new Font("Arial", 0, 10),
                new Font("Tahoma", 0, 10),
                new Font("Verdana", 0, 10)
        };
       
        // 폰트 설정 (랜덤 시작 폰트 Size, 랜덤 종료 폰트 Size)
        FontGenerator fontGenerator = new RandomFontGenerator(new Integer(20), new Integer(35), fontsList);
       
        WordToImage wordToImage = new ComposedWordToImage(fontGenerator, backgroundGenerator, textPaster);
        this.addFactory(new GimpyFactory(wgen, wordToImage));
    }
}



CaptchaServiceSingleton.java

package com.web.common.captcha;

import com.octo.captcha.service.captchastore.FastHashMapCaptchaStore;
import com.octo.captcha.service.image.DefaultManageableImageCaptchaService;
import com.octo.captcha.service.image.ImageCaptchaService;

public class CaptchaServiceSingleton {
    private final static ImageCaptchaService instance;
    static {
        instance = new DefaultManageableImageCaptchaService(new FastHashMapCaptchaStore(), new ImageCaptchaEngine(), 180, 100000, 75000);
    }

    public static ImageCaptchaService getInstance() {
        return instance;
    }
    
    /*
    // 기본 설정 그대로 사용
    private static ImageCaptchaService instance = new DefaultManageableImageCaptchaService();
    public static ImageCaptchaService getInstance(){
        return instance;
    }
    
    // 기본 설정 옵션만 변경하여 사용
    private static ImageCaptchaService instance = initializeService();
    private static ImageCaptchaService initializeService(){
        SimpleListImageCaptchaEngine engine = new SimpleListImageCaptchaEngine();
        return new DefaultManageableImageCaptchaService(new FastHashMapCaptchaStore(), engine, 180, 100000, 75000);
    }
    
    public static ImageCaptchaService getInstance(){
        return instance;
    }
    */
}



ImageCaptchaServlet.java

package com.web.common.captcha;

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

import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.octo.captcha.service.CaptchaServiceException;
import com.sun.image.codec.jpeg.JPEGCodec;
import com.sun.image.codec.jpeg.JPEGImageEncoder;

public class ImageCaptchaServlet extends HttpServlet {

    @Override
    public void init(ServletConfig servletConfig) throws ServletException {
        super.init(servletConfig);
    }
   
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        byte[] captchaChallengeAsJpeg = null;
        ByteArrayOutputStream jpegOutputStream = new ByteArrayOutputStream();
        try {
            String captchaId = request.getSession().getId();
            BufferedImage challenge = CaptchaServiceSingleton.getInstance().getImageChallengeForID(captchaId, request.getLocale());
            JPEGImageEncoder jpegEncoder = JPEGCodec.createJPEGEncoder(jpegOutputStream);
            jpegEncoder.encode(challenge);
        } catch (IllegalArgumentException e) {
            response.sendError(HttpServletResponse.SC_NOT_FOUND);
            return;
        } catch (CaptchaServiceException e) {
            response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
            return;
        }
       
        captchaChallengeAsJpeg = jpegOutputStream.toByteArray();
        response.setHeader("Cache-Control", "no-store");
        response.setHeader("Pragma", "no-cache");
        response.setDateHeader("Expires", 0);
        response.setContentType("image/jpeg");
        ServletOutputStream responseOutputStream = response.getOutputStream();
        responseOutputStream.write(captchaChallengeAsJpeg);
        responseOutputStream.flush();
        responseOutputStream.close();
    }
   



web.xml

<servlet>
        <servlet-name>jcaptcha</servlet-name>
        <servlet-class>com.web.common.captcha.ImageCaptchaServlet</servlet-class>
        <load-on-startup>0</load-on-startup>
 </servlet>
 <servlet-mapping>
        <servlet-name>jcaptcha</servlet-name>
        <url-pattern>/jcaptcha</url-pattern>
 </servlet-mapping>




JSP (HTML)

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="c"  uri="http://java.sun.com/jsp/jstl/core" %>

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>Insert title here</title>

<script type="text/javascript" src="<c:url value="/resources/js/jquery-1.7.1.min.js" />"></script>
<script>
jQuery(function($) {
    $('#j_captcha_response').on('keyup', function() {
        var _self = $(this);
        var val = _self.val();
        if(val) {
            _self.val(val.toUpperCase());
        }
    });
});
</script>

</head>
<body>

<form action="<c:url value="/captcha/insert" />" method="post">
    <div>
        <img src="<c:url value="/jcaptcha" />" style="border:1px solid #999;" />
    </div>
    <div>
        <input type="text" name="j_captcha_response" id="j_captcha_response" style="ime-mode:disabled;" />
    </div>
    <div>
        <input type="submit" value="전송" />    
    </div>
</form>

</body>
</html>



CaptchaController.java (Contoller)

package com.web.captcha.controllers;

import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.support.MessageSourceAccessor;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;

import com.octo.captcha.service.CaptchaServiceException;
import com.web.common.captcha.CaptchaServiceSingleton;


@Controller("captcha.CaptchaController")
@RequestMapping("captcha")
public class CaptchaController {

    public static final Logger log = LoggerFactory.getLogger(CaptchaController.class);
    
    @Autowired
    private MessageSourceAccessor messageSourceAccessor;
    
    
    @RequestMapping(value="index", method=RequestMethod.GET)
    public void index(@RequestParam Map<String, Object> paramMap, ModelMap modelMap) throws Exception {
        log.debug("=========================================================================================");
        log.debug("== paramMap : {}", paramMap);
        log.debug("=========================================================================================");
       
        modelMap.put("paramMap", paramMap);
    }
    
    
    @RequestMapping(value="insert", method=RequestMethod.POST)
    public String insert(@RequestParam Map<String, Object> paramMap, ModelMap modelMap, HttpServletRequest request, HttpSession session) throws Exception {
        log.debug("=========================================================================================");
        log.debug("== paramMap : {}", paramMap);
        log.debug("=========================================================================================");
       
        modelMap.put("paramMap", paramMap);
       
       
        Boolean isResponseCorrect = Boolean.FALSE;
        String captchaId = session.getId();
        String jCaptchaResponse = (String)paramMap.get("j_captcha_response");

        try {
            isResponseCorrect = CaptchaServiceSingleton.getInstance().validateResponseForID(captchaId, jCaptchaResponse);
            log.debug("isResponseCorrect : {}", isResponseCorrect);

           
        } catch (CaptchaServiceException e) {
        }
       
        return "captcha/index";
    }
       
}



=======================================================================================================
=======================================================================================================

2. Spring 으로 설정

1. CaptchaServiceSingleton 를 CaptchaService 로 대체

CaptchaService.java

package com.web.common.captcha;

import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Service;

import com.octo.captcha.service.captchastore.FastHashMapCaptchaStore;
import com.octo.captcha.service.image.DefaultManageableImageCaptchaService;
import com.octo.captcha.service.image.ImageCaptchaService;

@Service
@Scope(value="singleton")
public class CaptchaService {
   
    private final static ImageCaptchaService instance;
   
    static {
        instance = new DefaultManageableImageCaptchaService(new FastHashMapCaptchaStore(), new ImageCaptchaEngine(), 180, 100000, 75000);
    }
   
    public ImageCaptchaService getInstance() {
        return instance;
    }
   
    /*
    @PostConstruct
    public void init() {
    }
   
    @PreDestroy
    public void close() {
    }
    */
   



2. ImageCaptchaServlet 을 Contoller로 대체

CaptchaContoller.java

package com.web.captcha.controllers;

import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.util.Map;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.support.MessageSourceAccessor;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;

import com.octo.captcha.service.CaptchaServiceException;
import com.sun.image.codec.jpeg.JPEGCodec;
import com.sun.image.codec.jpeg.JPEGImageEncoder;
import com.web.common.captcha.CaptchaService;


@Controller("captcha.CaptchaController")
@RequestMapping("captcha")
public class CaptchaController {

    public static final Logger log = LoggerFactory.getLogger(CaptchaController.class);
    
    @Autowired
    private MessageSourceAccessor messageSourceAccessor;
    
    @Autowired
    private CaptchaService captchaService;
    
    
    @RequestMapping(value="index", method=RequestMethod.GET)
    public void index(@RequestParam Map<String, Object> paramMap, ModelMap modelMap) throws Exception {
        log.debug("=========================================================================================");
        log.debug("== paramMap : {}", paramMap);
        log.debug("=========================================================================================");
        
        modelMap.put("paramMap", paramMap);
    }
    
    
    @RequestMapping(value="jcaptcha", method=RequestMethod.GET)
    public void jcaptcha(@RequestParam Map<String, Object> paramMap, ModelMap modelMap, HttpServletRequest request, HttpServletResponse response, HttpSession session) throws Exception {
        byte[] captchaChallengeAsJpeg = null;
        ByteArrayOutputStream jpegOutputStream = new ByteArrayOutputStream();
        try {
            String captchaId = session.getId();
            BufferedImage challenge = captchaService.getInstance().getImageChallengeForID(captchaId, request.getLocale());
            JPEGImageEncoder jpegEncoder = JPEGCodec.createJPEGEncoder(jpegOutputStream);
            jpegEncoder.encode(challenge);
        } catch (IllegalArgumentException e) {
            response.sendError(HttpServletResponse.SC_NOT_FOUND);
            return;
        } catch (CaptchaServiceException e) {
            response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
            return;
        }
        
        captchaChallengeAsJpeg = jpegOutputStream.toByteArray();
        response.setHeader("Cache-Control", "no-store");
        response.setHeader("Pragma", "no-cache");
        response.setDateHeader("Expires", 0);
        response.setContentType("image/jpeg");
        ServletOutputStream responseOutputStream = response.getOutputStream();
        responseOutputStream.write(captchaChallengeAsJpeg);
        responseOutputStream.flush();
        responseOutputStream.close();
    }
    
    
    @RequestMapping(value="insert", method=RequestMethod.POST)
    public String insert(@RequestParam Map<String, Object> paramMap, ModelMap modelMap, HttpServletRequest request, HttpSession session) throws Exception {
        log.debug("=========================================================================================");
        log.debug("== paramMap : {}", paramMap);
        log.debug("=========================================================================================");
        
        modelMap.put("paramMap", paramMap);
        
        Boolean isResponseCorrect = Boolean.FALSE;
        String captchaId = session.getId();
        String jCaptchaResponse = (String)paramMap.get("j_captcha_response");
        try {
            isResponseCorrect = captchaService.getInstance().validateResponseForID(captchaId, jCaptchaResponse);
            log.debug("isResponseCorrect : {}", isResponseCorrect);
            
        } catch (CaptchaServiceException e) {
        }
        
        return "captcha/index";
    }
        
}


3. web.xml 설정 삭제

4. jsp image url 변경

JSP (HTML)

<img src="<c:url value="/captcha/jcaptcha" />" style="border:1px solid #999;" /> 



=======================================================================================================
=======================================================================================================

3. 이미지 새로고침 추가 (Ajax - Base64)


1. CaptchaContoller Ajax (json) 추가

CaptchaController.java

package com.web.captcha.controllers;

import java.awt.image.BufferedImage;
import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.util.Map;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.apache.commons.codec.binary.Base64InputStream;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.support.MessageSourceAccessor;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;

import com.octo.captcha.service.CaptchaServiceException;
import com.sun.image.codec.jpeg.JPEGCodec;
import com.sun.image.codec.jpeg.JPEGImageEncoder;
import com.web.common.captcha.CaptchaService;


@Controller("captcha.CaptchaController")
@RequestMapping("captcha")
public class CaptchaController {

    public static final Logger log = LoggerFactory.getLogger(CaptchaController.class);
   
    @Autowired
    private MessageSourceAccessor messageSourceAccessor;
   
    @Autowired
    private CaptchaService captchaService;
   
   
    @RequestMapping(value="index", method=RequestMethod.GET)
    public void index(@RequestParam Map<String, Object> paramMap, ModelMap modelMap) throws Exception {
        log.debug("=========================================================================================");
        log.debug("== paramMap : {}", paramMap);
        log.debug("=========================================================================================");
       
        modelMap.put("paramMap", paramMap);
    }
   
   
    @RequestMapping(value="jcaptcha", method=RequestMethod.GET)
    public void jcaptcha(@RequestParam Map<String, Object> paramMap, ModelMap modelMap, HttpServletRequest request, HttpServletResponse response, HttpSession session) throws Exception {
        byte[] captchaChallengeAsJpeg = null;
        ByteArrayOutputStream jpegOutputStream = new ByteArrayOutputStream();
        try {
            String captchaId = session.getId();
            BufferedImage challenge = captchaService.getInstance().getImageChallengeForID(captchaId, request.getLocale());
            JPEGImageEncoder jpegEncoder = JPEGCodec.createJPEGEncoder(jpegOutputStream);
            jpegEncoder.encode(challenge);
        } catch (IllegalArgumentException e) {
            response.sendError(HttpServletResponse.SC_NOT_FOUND);
            return;
        } catch (CaptchaServiceException e) {
            response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
            return;
        }
       
        captchaChallengeAsJpeg = jpegOutputStream.toByteArray();
        response.setHeader("Cache-Control", "no-store");
        response.setHeader("Pragma", "no-cache");
        response.setDateHeader("Expires", 0);
        response.setContentType("image/jpeg");
        ServletOutputStream responseOutputStream = response.getOutputStream();
        responseOutputStream.write(captchaChallengeAsJpeg);
        responseOutputStream.flush();
        responseOutputStream.close();
    }
   
   
    @RequestMapping(value="jcaptchaImage.json")
    public String jcaptchaImage(@RequestParam Map<String, Object> paramMap, ModelMap modelMap, HttpServletRequest request, HttpServletResponse response, HttpSession session) throws Exception {
       
        byte[] captchaChallengeAsJpeg = null;
        ByteArrayOutputStream jpegOutputStream = new ByteArrayOutputStream();
        try {
            String captchaId = session.getId();
            BufferedImage challenge = captchaService.getInstance().getImageChallengeForID(captchaId, request.getLocale());
            JPEGImageEncoder jpegEncoder = JPEGCodec.createJPEGEncoder(jpegOutputStream);
            jpegEncoder.encode(challenge);
        } catch (IllegalArgumentException e) {
            response.sendError(HttpServletResponse.SC_NOT_FOUND);
            throw e;
        } catch (CaptchaServiceException e) {
            response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
            throw e;
        }
       
        BufferedInputStream bis = null;
        ByteArrayOutputStream baos = null;
       
        try {
            captchaChallengeAsJpeg = jpegOutputStream.toByteArray();
            BufferedInputStream captchaBis = new BufferedInputStream(new ByteArrayInputStream(captchaChallengeAsJpeg));
            Base64InputStream in = new Base64InputStream(captchaBis, true);
           
            bis = new BufferedInputStream(in);
            baos = new ByteArrayOutputStream();
            byte[] buffer = new byte[4096];
            int read = 0;
            while ((read = bis.read(buffer)) != -1) {
                baos.write(buffer, 0, read);
            }
           
            modelMap.put("captchaCode", baos.toString());
        } finally {
            if(baos != null) {
                baos.close();
            }
            if(bis != null) {
                bis.close();
            }
        }
       
        return "jsonView";
    }

   
   
   
    @RequestMapping(value="insert", method=RequestMethod.POST)
    public String insert(@RequestParam Map<String, Object> paramMap, ModelMap modelMap, HttpServletRequest request, HttpSession session) throws Exception {
        log.debug("=========================================================================================");
        log.debug("== paramMap : {}", paramMap);
        log.debug("=========================================================================================");
       
        modelMap.put("paramMap", paramMap);
       
        Boolean isResponseCorrect = Boolean.FALSE;
        String captchaId = session.getId();
        String jCaptchaResponse = (String)paramMap.get("j_captcha_response");
        try {
            isResponseCorrect = captchaService.getInstance().validateResponseForID(captchaId, jCaptchaResponse);
            log.debug("isResponseCorrect : {}", isResponseCorrect);
           
        } catch (CaptchaServiceException e) {
        }
       
        return "captcha/index";
    }
       
}
 



2. jsp 변경

JSP (HTML)

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="c"  uri="http://java.sun.com/jsp/jstl/core" %>

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>Insert title here</title>

<script type="text/javascript" src="<c:url value="/resources/js/jquery-1.7.1.min.js" />"></script>
<script>
jQuery(function($) {
    $('#j_captcha_response').on('keyup', function() {
        var _self = $(this);
        var val = _self.val();
        if(val) {
            _self.val(val.toUpperCase());
        }
    });


    var _jcaptchaCarousel = $('#jcaptchaCarousel');
    $('#btnCaptchaReload').on('click', function() {
        $.ajax({
            url : '<c:url value="/captcha/jcaptchaImage.json" />',
            dataType : 'json',
            success : function(data, textStatus, jqXHR) {
                if(data.captchaCode) {
                    _jcaptchaCarousel
                        .empty()
                        .append($('<img />', {src:'https://t1.daumcdn.net/cfile/tistory/25572D5056E6794133"<c:url value="/captcha/insert" />" method="post">
    <div id="jcaptchaCarousel"></div>
    <div>
        <input type="button" value="이미지 새로고침" id="btnCaptchaReload" />
    </div>
    <div>
        <input type="text" name="j_captcha_response" id="j_captcha_response" style="ime-mode:disabled;" />
    </div>
    <div>
        <input type="submit" value="전송" />   
    </div>
</form>

</body>
</html> 


=====================================================================

SimpleCaptcha

홈페이지 : http://simplecaptcha.sourceforge.net/index.html

한글음성 custom : http://javaking75.blog.me/220276964082


참고 : http://www.yunsobi.com/blog/406
         http://blog.naver.com/tyboss?Redirect=Log&logNo=70060667814&from=postView

package test;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.nio.channels.FileChannel;

import org.junit.Test;

public class FileTest {

   
    @Test
    public void copyStream() throws Exception {
       
        String sourceFile = "c:/grid.xls";
        String targetFile = "c:/grid_out.xls";
       
        FileInputStream fis = null;
        FileOutputStream fos = null;
       
        try {
           
            fis = new FileInputStream(sourceFile);
            fos = new FileOutputStream(targetFile);
           
            int read = 0;
            byte[] buffer = new byte[4096];
            while((read = fis.read(buffer)) != -1) {
                fos.write(buffer, 0, read);
            }
           
        } finally {
            if(fos != null) {
                fos.close();
            }
            if(fis != null) {
                fis.close();
            }
        }
    }
   
   
    @Test
    public void copyBuffer() throws Exception {
       
        String sourceFile = "c:/grid.xls";
        String targetFile = "c:/grid_out.xls";
       
        FileInputStream fis = null;
        FileOutputStream fos = null;
       
        BufferedInputStream bis = null;
        BufferedOutputStream bos = null;
       
        try {
           
            fis = new FileInputStream(sourceFile);
            fos = new FileOutputStream(targetFile);
           
            bis = new BufferedInputStream(fis);
            bos = new BufferedOutputStream(fos);
           
            int read = 0;
            byte[] buffer = new byte[4096];
            while((read = bis.read(buffer)) != -1) {
                bos.write(buffer, 0, read);
            }
           
        } finally {
            if(bos != null) {
                bos.close();
            }
            if(bis != null) {
                bis.close();
            }
        }
    }
   
   
   
    @SuppressWarnings("resource")
    @Test
    public void copyNIO() throws Exception {
       
        String sourceFile = "c:/grid.xls";
        String targetFile = "c:/grid_out.xls";
       
        FileInputStream fis = null;
        FileOutputStream fos = null;
       
        FileChannel inChannel = null;
        FileChannel outChannel = null;
       
        try {
           
            fis = new FileInputStream(sourceFile);
            fos = new FileOutputStream(targetFile);
           
            inChannel = fis.getChannel();
            outChannel = fos.getChannel();
           
            long size = inChannel.size();
            inChannel.transferTo(0, size, outChannel);
           
        } finally {
            if(outChannel != null) {
                outChannel.close();
            }
            if(inChannel != null) {
                inChannel.close();
            }
        }
       
    }
   
   
}
 


출처 : http://www.javacodegeeks.com/2012/07/anti-cross-site-scripting-xss-filter.html

XSSFilter.java

XSSInterceptor.java

XSSRequestWrapper.java


1. Filter 적용

<filter>
        <filter-name>xss</filter-name>
        <filter-class>com.jejubank.admin.util.xss.XSSFilter</filter-class>
    </filter>
   
    <filter-mapping>
        <filter-name>xss</filter-name>
        <url-pattern>*.do</url-pattern>
    </filter-mapping> 


2. Interceptor 적용

<mvc:interceptors>
        <mvc:interceptor>
            <mvc:mapping path="/**" />
            <bean class="com.jejubank.admin.util.xss.XSSInterceptor" />
        </mvc:interceptor>
    </mvc:interceptors>


=======================================================================================================
=======================================================================================================


첨부파일 있는 경우 XSS Filter
 
참고 : http://www.javapractices.com/topic/TopicAction.do?Id=221

XSSFilter.java 

XSSMultipartRequestWrapper.java 

XSSRequestWrapper.java

 

 

 

 

출처 : http://www.developer.nokia.com/Community/Wiki/Getting_IMEI_and_IMSI_in_Java_ME


Getting IMEI and IMSI in Java ME

Importance of IMEI and IMSI : The IMEI and IMSI can be used to ensure extra security while user make use of your application For e.g if you want manager should access his account from valid phone provided by organization.This two codes can be proven effective.

The code will work in almost all devices.


public String getIMEI() {
String out = "";
try {
out = System.getProperty("com.imei");
if (out == null || out.equals("null") || out.equals("")) {
out = System.getProperty("phone.imei");
}
if (out == null || out.equals("null") || out.equals("")) {
out = System.getProperty("com.nokia.IMEI");
}
if (out == null || out.equals("null") || out.equals("")) {
out = System.getProperty("com.nokia.mid.imei");
}
if (out == null || out.equals("null") || out.equals("")) {
out = System.getProperty("com.sonyericsson.imei");
}
 
if (out == null || out.equals("null") || out.equals("")) {
out = System.getProperty("IMEI");
}
if (out == null || out.equals("null") || out.equals("")) {
out = System.getProperty("com.motorola.IMEI");
}
 
if (out == null || out.equals("null") || out.equals("")) {
out = System.getProperty("com.samsung.imei");
}
if (out == null || out.equals("null") || out.equals("")) {
out = System.getProperty("com.siemens.imei");
}
 
if (out == null || out.equals("null") || out.equals("")) {
out = System.getProperty("imei");
}
 
} catch (Exception e) {
return out == null ? "" : out;
}
return out == null ? "" : out;
}
//code for getting IMSI of the phone
public String getIMSI() {
String out = "";
try {
out = System.getProperty("IMSI");
if (out == null || out.equals("null") || out.equals("")) {
out = System.getProperty("phone.imsi");
}
if (out == null || out.equals("null") || out.equals("")) {
out = System.getProperty("com.nokia.mid.mobinfo.IMSI");
}
if (out == null || out.equals("null") || out.equals("")) {
out = System.getProperty("com.nokia.mid.imsi");
}
if (out == null || out.equals("null") || out.equals("")) {
out = System.getProperty("IMSI");
}
if (out == null || out.equals("null") || out.equals("")) {
out = System.getProperty("imsi");
}
} catch (Exception e) {
return out == null ? "" : out;
}
return out == null ? "" : out;
}

 


출처 : http://nday.tistory.com/entry/MySQL-51-UTF8에서-iOS5-이모티콘emoji-적용하기

참고 : http://stackoverflow.com/questions/13653712/java-sql-sqlexception-incorrect-string-value-xf0-x9f-x91-xbd-xf0-x9f
        http://www.fileformat.info/info/unicode/char/1f47d/index.htm
        http://www.fileformat.info/info/unicode/char/1f494/index.htm
        http://dev.mysql.com/doc/refman/5.6/en/charset-unicode-utf8mb4.html


1. 개요
이번 iOS가 iOS5로 업데이트되면서 이모티콘이 기본으로 추가되어 사용할 수 있게 되었습니다.
이모티콘을 추가하여 글을 작성하면 Incorrect string value (error code [1366]) 에러가 발생하는데요
원인은 현재 아임IN의 DB는 (MySQL 5.1 UTF-8(3Byte))로 되어 있으며, 추가된 이모티콘은 3Byte 영역을 벗어난 4Byte 영역에 포함되어 있기 때문입니다.
이러한 문제를 기존 프로세스 및 데이터에 영향을 주지 않고 빠르게 해결하기 위해 아래 제시한 방법 중 첫번째 방법을 적용하였습니다.
하지만 첫번째 방법은 새로운 이모티콘이 추가되면 소스코드에 추가된 이모티콘 코드를 추가해줘야 하는 이슈가 있습니다.
따라서 추후 MySQL 5.5 UTF8MB4(4Byte)로 변경하는게 맞다고 생각됩니다.

 

2. 해결방법
1) iOS5 에서 추가된 SMP영역의 UNICODE를 BMP 영역의 UNICODE로 변환.
- 장점 : Util 추가로 쉽게 적용할 수 있다.
- 단점 : Util을 추가해야 하며, 새로운 이모티콘이 추가될 경우 Util소스코드에 추가하는 작업이 필요하다.
- 참조
변환코드표(SoftBank 코드 사용) : http://unicode.org/~scherer/emoji4unicode/snapshot/utc.html

 

2) MySQL 5.1 UTF8(3Byte)을 MySQL 5.5 UTF8MB4(4Byte)로 변경.
- 장점 : 5.5로 변경 시 다른 추가 작업이 필요 없다.
- 단점 : 데이터가 많으면 이전 작업 시간이 많이 소요되며, MySQL 5.1과 5.5의 호환성 테스트가 필요하다.
- 참조
MySQL 5.1 UTF8(3Byte) : http://dev.mysql.com/doc/refman/5.1/en/charset-unicode.html
MySQL 5.5 UTF8MB4(4Byte) : http://dev.mysql.com/doc/refman/5.5/en/charset-unicode.html

 

- MySQL 버전에따른 Unicode 지원 범위 표.

Before MySQL 5.5 MySQL 5.5 and up
All Unicode 3.0 characters All Unicode 5.0 characters
No supplementary characters With supplementary characters
ucs2 character set, BMP only No change
utf8 character set for up to three bytes, BMP only No change
  New utf8mb4 character set for up to four bytes, BMP or supplemental
  New utf16 character set, BMP or supplemental
  New utf32 character set, BMP or supplemental

 

3) MySQL 5.1 유지하면서 해당 컬럼을 VARBINARY로 변환하고, SELECT 시 CAST(%컬럼명% AS CHAR(사이즈) CHARSET UTF8) 형태로 조회.
- 장점 : MySQL 버전 변경 없이 적용 가능하며, 새로운 이모티콘이 추가되어도 추가작업이 없다.
- 단점 : 조회 SQL구문에 수정이 필요하며, 기존 데이터를 VARBINARY로 변환 시 데이터가 변경될 수 있어 확인이 필요하다.
- 참조
MySQL 5.1 VARBINARY : http://dev.mysql.com/doc/refman/5.1/en/binary-varbinary.html

 

3. 예제 (iOS5 에서 추가된 SMP영역의 UNICODE를 BMP 영역의 UNICODE로 변환)

package com.paran.test.util;

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

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 * @author 1sec, NDay
 *
 * @see http://unicode.org/~scherer/emoji4unicode/snapshot/utc.html
 * @see http://java.sun.com/developer/technicalArticles/Intl/Supplementary
 * @see MySQL 5.1 UTF8(3Byte):
 *      http://dev.mysql.com/doc/refman/5.1/en/charset-unicode.html
 * @see MySQL 5.5 UTF8MB4(4Byte):
 *      http://dev.mysql.com/doc/refman/5.5/en/charset-unicode.html
 *
 */
public class EmojiUtil {

	private static final Log log = LogFactory.getLog(EmojiUtil.class);

	public static int UNICODE_4_0_EX_START = 0x10000;
	public static int UNICODE_4_0_EX_END = 0x10FFFF;

	/*
	 * NOTE
	 *
	 * BMP (Basic Multilingual Plane)
	 *
	 * SMP (Supplementary Multilingual Plane)
	 */
	private static int EMOJI_TYPE_BMP_2_CHAR = -1;
	private static int EMOJI_TYPE_SMP_2_CHAR = -2;

	private static Map emoji = new HashMap();
	private static Map emoji2 = new HashMap();
	private static Map emojiSMP2 = new HashMap();
	private static Map emojiBMP2 = new HashMap();

	/**
	 * SMP to BMP convert Map
	 * */
	static {
		emoji.put(0x1F300, 0xE443);
		emoji.put(0x1F302, 0xE43C);
		emoji.put(0x1F303, 0xE44B);
		emoji.put(0x1F304, 0xE04D);
		emoji.put(0x1F305, 0xE449);
		emoji.put(0x1F306, 0xE146);
		emoji.put(0x1F307, 0xE44A);
		emoji.put(0x1F308, 0xE44C);
		emoji.put(0x1F309, 0xE44B);
		emoji.put(0x1F30A, 0xE43E);
		emoji.put(0x1F30C, 0xE44B);
		emoji.put(0x1F314, 0xE04C);
		emoji.put(0x1F313, 0xE04C);
		emoji.put(0x1F319, 0xE04C);
		emoji.put(0x1F31B, 0xE04C);
		emoji.put(0x1F31F, 0xE335);
		emoji.put(0x1F550, 0xE024);
		emoji.put(0x1F551, 0xE025);
		emoji.put(0x1F552, 0xE026);
		emoji.put(0x1F553, 0xE027);
		emoji.put(0x1F554, 0xE028);
		emoji.put(0x1F555, 0xE029);
		emoji.put(0x1F556, 0xE02A);
		emoji.put(0x1F557, 0xE02B);
		emoji.put(0x1F558, 0xE02C);
		emoji.put(0x1F559, 0xE02D);
		emoji.put(0x1F55A, 0xE02E);
		emoji.put(0x1F55B, 0xE02F);
		emoji.put(0x1F340, 0xE110);
		emoji.put(0x1F337, 0xE304);
		emoji.put(0x1F331, 0xE110);
		emoji.put(0x1F341, 0xE118);
		emoji.put(0x1F338, 0xE030);
		emoji.put(0x1F339, 0xE032);
		emoji.put(0x1F342, 0xE119);
		emoji.put(0x1F343, 0xE447);
		emoji.put(0x1F33A, 0xE303);
		emoji.put(0x1F33B, 0xE305);
		emoji.put(0x1F334, 0xE307);
		emoji.put(0x1F335, 0xE308);
		emoji.put(0x1F33E, 0xE444);
		emoji.put(0x1F33C, 0xE305);
		emoji.put(0x1F33F, 0xE110);
		emoji.put(0x1F34E, 0xE345);
		emoji.put(0x1F34A, 0xE346);
		emoji.put(0x1F353, 0xE347);
		emoji.put(0x1F349, 0xE348);
		emoji.put(0x1F345, 0xE349);
		emoji.put(0x1F346, 0xE34A);
		emoji.put(0x1F34F, 0xE345);
		emoji.put(0x1F440, 0xE419);
		emoji.put(0x1F442, 0xE41B);
		emoji.put(0x1F443, 0xE41A);
		emoji.put(0x1F444, 0xE41C);
		emoji.put(0x1F445, 0xE409);
		emoji.put(0x1F484, 0xE31C);
		emoji.put(0x1F485, 0xE31D);
		emoji.put(0x1F486, 0xE31E);
		emoji.put(0x1F487, 0xE31F);
		emoji.put(0x1F488, 0xE320);
		emoji.put(0x1F466, 0xE001);
		emoji.put(0x1F467, 0xE002);
		emoji.put(0x1F468, 0xE004);
		emoji.put(0x1F469, 0xE005);
		emoji.put(0x1F46B, 0xE428);
		emoji.put(0x1F46E, 0xE152);
		emoji.put(0x1F46F, 0xE429);
		emoji.put(0x1F471, 0xE515);
		emoji.put(0x1F472, 0xE516);
		emoji.put(0x1F473, 0xE517);
		emoji.put(0x1F474, 0xE518);
		emoji.put(0x1F475, 0xE519);
		emoji.put(0x1F476, 0xE51A);
		emoji.put(0x1F477, 0xE51B);
		emoji.put(0x1F478, 0xE51C);
		emoji.put(0x1F47B, 0xE11B);
		emoji.put(0x1F47C, 0xE04E);
		emoji.put(0x1F47D, 0xE10C);
		emoji.put(0x1F47E, 0xE12B);
		emoji.put(0x1F47F, 0xE11A);
		emoji.put(0x1F480, 0xE11C);
		emoji.put(0x1F481, 0xE253);
		emoji.put(0x1F482, 0xE51E);
		emoji.put(0x1F483, 0xE51F);
		emoji.put(0x1F40D, 0xE52D);
		emoji.put(0x1F40E, 0xE134);
		emoji.put(0x1F414, 0xE52E);
		emoji.put(0x1F417, 0xE52F);
		emoji.put(0x1F42B, 0xE530);
		emoji.put(0x1F418, 0xE526);
		emoji.put(0x1F428, 0xE527);
		emoji.put(0x1F412, 0xE528);
		emoji.put(0x1F411, 0xE529);
		emoji.put(0x1F419, 0xE10A);
		emoji.put(0x1F41A, 0xE441);
		emoji.put(0x1F41B, 0xE525);
		emoji.put(0x1F420, 0xE522);
		emoji.put(0x1F421, 0xE019);
		emoji.put(0x1F424, 0xE523);
		emoji.put(0x1F425, 0xE523);
		emoji.put(0x1F426, 0xE521);
		emoji.put(0x1F423, 0xE523);
		emoji.put(0x1F427, 0xE055);
		emoji.put(0x1F429, 0xE052);
		emoji.put(0x1F41F, 0xE019);
		emoji.put(0x1F42C, 0xE520);
		emoji.put(0x1F42D, 0xE053);
		emoji.put(0x1F42F, 0xE050);
		emoji.put(0x1F431, 0xE04F);
		emoji.put(0x1F433, 0xE054);
		emoji.put(0x1F434, 0xE01A);
		emoji.put(0x1F435, 0xE109);
		emoji.put(0x1F436, 0xE052);
		emoji.put(0x1F437, 0xE10B);
		emoji.put(0x1F43B, 0xE051);
		emoji.put(0x1F439, 0xE524);
		emoji.put(0x1F43A, 0xE52A);
		emoji.put(0x1F42E, 0xE52B);
		emoji.put(0x1F430, 0xE52C);
		emoji.put(0x1F438, 0xE531);
		emoji.put(0x1F43E, 0xE536);
		emoji.put(0x1F43D, 0xE10B);
		emoji.put(0x1F620, 0xE059);
		emoji.put(0x1F629, 0xE403);
		emoji.put(0x1F632, 0xE410);
		emoji.put(0x1F61E, 0xE058);
		emoji.put(0x1F635, 0xE406);
		emoji.put(0x1F630, 0xE40F);
		emoji.put(0x1F612, 0xE40E);
		emoji.put(0x1F60D, 0xE106);
		emoji.put(0x1F624, 0xE404);
		emoji.put(0x1F61C, 0xE105);
		emoji.put(0x1F61D, 0xE409);
		emoji.put(0x1F60B, 0xE056);
		emoji.put(0x1F618, 0xE418);
		emoji.put(0x1F61A, 0xE417);
		emoji.put(0x1F637, 0xE40C);
		emoji.put(0x1F633, 0xE40D);
		emoji.put(0x1F603, 0xE057);
		emoji.put(0x1F606, 0xE40A);
		emoji.put(0x1F601, 0xE404);
		emoji.put(0x1F602, 0xE412);
		emoji.put(0x1F60A, 0xE056);
		emoji.put(0x1F604, 0xE415);
		emoji.put(0x1F622, 0xE413);
		emoji.put(0x1F62D, 0xE411);
		emoji.put(0x1F628, 0xE40B);
		emoji.put(0x1F623, 0xE406);
		emoji.put(0x1F621, 0xE416);
		emoji.put(0x1F60C, 0xE40A);
		emoji.put(0x1F616, 0xE407);
		emoji.put(0x1F614, 0xE403);
		emoji.put(0x1F631, 0xE107);
		emoji.put(0x1F62A, 0xE408);
		emoji.put(0x1F60F, 0xE402);
		emoji.put(0x1F613, 0xE108);
		emoji.put(0x1F625, 0xE401);
		emoji.put(0x1F62B, 0xE406);
		emoji.put(0x1F609, 0xE405);
		emoji.put(0x1F63A, 0xE057);
		emoji.put(0x1F638, 0xE404);
		emoji.put(0x1F639, 0xE412);
		emoji.put(0x1F63D, 0xE418);
		emoji.put(0x1F63B, 0xE106);
		emoji.put(0x1F63F, 0xE413);
		emoji.put(0x1F63E, 0xE416);
		emoji.put(0x1F63C, 0xE404);
		emoji.put(0x1F640, 0xE403);
		emoji.put(0x1F645, 0xE423);
		emoji.put(0x1F646, 0xE424);
		emoji.put(0x1F647, 0xE426);
		emoji.put(0x1F64B, 0xE012);
		emoji.put(0x1F64C, 0xE427);
		emoji.put(0x1F64D, 0xE403);
		emoji.put(0x1F64E, 0xE416);
		emoji.put(0x1F64F, 0xE41D);
		emoji.put(0x1F3E0, 0xE036);
		emoji.put(0x1F3E1, 0xE036);
		emoji.put(0x1F3E2, 0xE038);
		emoji.put(0x1F3E3, 0xE153);
		emoji.put(0x1F3E5, 0xE155);
		emoji.put(0x1F3E6, 0xE14D);
		emoji.put(0x1F3E7, 0xE154);
		emoji.put(0x1F3E8, 0xE158);
		emoji.put(0x1F3E9, 0xE501);
		emoji.put(0x1F3EA, 0xE156);
		emoji.put(0x1F3EB, 0xE157);
		emoji.put(0x1F3EC, 0xE504);
		emoji.put(0x1F3EF, 0xE505);
		emoji.put(0x1F3F0, 0xE506);
		emoji.put(0x1F3ED, 0xE508);
		emoji.put(0x1F3EE, 0xE30B);
		emoji.put(0x1F5FB, 0xE03B);
		emoji.put(0x1F5FC, 0xE509);
		emoji.put(0x1F5FD, 0xE51D);
		emoji.put(0x1F45E, 0xE007);
		emoji.put(0x1F45F, 0xE007);
		emoji.put(0x1F460, 0xE13E);
		emoji.put(0x1F461, 0xE31A);
		emoji.put(0x1F462, 0xE31B);
		emoji.put(0x1F463, 0xE536);
		emoji.put(0x1F455, 0xE006);
		emoji.put(0x1F451, 0xE10E);
		emoji.put(0x1F454, 0xE302);
		emoji.put(0x1F452, 0xE318);
		emoji.put(0x1F457, 0xE319);
		emoji.put(0x1F458, 0xE321);
		emoji.put(0x1F459, 0xE322);
		emoji.put(0x1F45A, 0xE006);
		emoji.put(0x1F45C, 0xE323);
		emoji.put(0x1F4B0, 0xE12F);
		emoji.put(0x1F4B1, 0xE149);
		emoji.put(0x1F4B9, 0xE14A);
		emoji.put(0x1F4B2, 0xE12F);
		emoji.put(0x1F4B5, 0xE12F);
		emoji.put(0x1F525, 0xE11D);
		emoji.put(0x1F528, 0xE116);
		emoji.put(0x1F52B, 0xE113);
		emoji.put(0x1F52E, 0xE23E);
		emoji.put(0x1F52F, 0xE23E);
		emoji.put(0x1F530, 0xE209);
		emoji.put(0x1F531, 0xE031);
		emoji.put(0x1F489, 0xE13B);
		emoji.put(0x1F48A, 0xE30F);
		emoji.put(0x1F170, 0xE532);
		emoji.put(0x1F171, 0xE533);
		emoji.put(0x1F18E, 0xE534);
		emoji.put(0x1F17E, 0xE535);
		emoji.put(0x1F380, 0xE314);
		emoji.put(0x1F381, 0xE112);
		emoji.put(0x1F382, 0xE34B);
		emoji.put(0x1F384, 0xE033);
		emoji.put(0x1F385, 0xE448);
		emoji.put(0x1F38C, 0xE143);
		emoji.put(0x1F386, 0xE117);
		emoji.put(0x1F388, 0xE310);
		emoji.put(0x1F389, 0xE312);
		emoji.put(0x1F38D, 0xE436);
		emoji.put(0x1F38E, 0xE438);
		emoji.put(0x1F393, 0xE439);
		emoji.put(0x1F392, 0xE43A);
		emoji.put(0x1F38F, 0xE43B);
		emoji.put(0x1F387, 0xE440);
		emoji.put(0x1F390, 0xE442);
		emoji.put(0x1F383, 0xE445);
		emoji.put(0x1F391, 0xE446);
		emoji.put(0x1F4DE, 0xE009);
		emoji.put(0x1F4F1, 0xE00A);
		emoji.put(0x1F4F2, 0xE104);
		emoji.put(0x1F4DD, 0xE301);
		emoji.put(0x1F4E0, 0xE00B);
		emoji.put(0x1F4E8, 0xE103);
		emoji.put(0x1F4E9, 0xE103);
		emoji.put(0x1F4EA, 0xE101);
		emoji.put(0x1F4EB, 0xE101);
		emoji.put(0x1F4EE, 0xE102);
		emoji.put(0x1F4E2, 0xE142);
		emoji.put(0x1F4E3, 0xE317);
		emoji.put(0x1F4E1, 0xE14B);
		emoji.put(0x1F4E6, 0xE112);
		emoji.put(0x1F4E7, 0xE103);
		emoji.put(0x1F4BA, 0xE11F);
		emoji.put(0x1F4BB, 0xE00C);
		emoji.put(0x1F4BC, 0xE11E);
		emoji.put(0x1F4BD, 0xE316);
		emoji.put(0x1F4BE, 0xE316);
		emoji.put(0x1F4BF, 0xE126);
		emoji.put(0x1F4C0, 0xE127);
		emoji.put(0x1F4C3, 0xE301);
		emoji.put(0x1F4C4, 0xE301);
		emoji.put(0x1F4D3, 0xE148);
		emoji.put(0x1F4D6, 0xE148);
		emoji.put(0x1F4D4, 0xE148);
		emoji.put(0x1F4D5, 0xE148);
		emoji.put(0x1F4D7, 0xE148);
		emoji.put(0x1F4D8, 0xE148);
		emoji.put(0x1F4D9, 0xE148);
		emoji.put(0x1F4DA, 0xE148);
		emoji.put(0x1F4CB, 0xE301);
		emoji.put(0x1F4CA, 0xE14A);
		emoji.put(0x1F4C8, 0xE14A);
		emoji.put(0x1F4C7, 0xE148);
		emoji.put(0x1F4D2, 0xE148);
		emoji.put(0x1F4D1, 0xE301);
		emoji.put(0x1F3BE, 0xE015);
		emoji.put(0x1F3BF, 0xE013);
		emoji.put(0x1F3C0, 0xE42A);
		emoji.put(0x1F3C1, 0xE132);
		emoji.put(0x1F3C3, 0xE115);
		emoji.put(0x1F3C4, 0xE017);
		emoji.put(0x1F3C6, 0xE131);
		emoji.put(0x1F3C8, 0xE42B);
		emoji.put(0x1F3CA, 0xE42D);
		emoji.put(0x1F683, 0xE01E);
		emoji.put(0x1F687, 0xE434);
		emoji.put(0x1F684, 0xE435);
		emoji.put(0x1F685, 0xE01F);
		emoji.put(0x1F697, 0xE01B);
		emoji.put(0x1F699, 0xE42E);
		emoji.put(0x1F68C, 0xE159);
		emoji.put(0x1F68F, 0xE150);
		emoji.put(0x1F6A2, 0xE202);
		emoji.put(0x1F689, 0xE039);
		emoji.put(0x1F680, 0xE10D);
		emoji.put(0x1F6A4, 0xE135);
		emoji.put(0x1F695, 0xE15A);
		emoji.put(0x1F69A, 0xE42F);
		emoji.put(0x1F692, 0xE430);
		emoji.put(0x1F691, 0xE431);
		emoji.put(0x1F693, 0xE432);
		emoji.put(0x1F17F, 0xE14F);
		emoji.put(0x1F6A5, 0xE14E);
		emoji.put(0x1F6A7, 0xE137);
		emoji.put(0x1F6A8, 0xE432);
		emoji.put(0x1F3A1, 0xE124);
		emoji.put(0x1F3A2, 0xE433);
		emoji.put(0x1F3A3, 0xE019);
		emoji.put(0x1F3A4, 0xE03C);
		emoji.put(0x1F3A5, 0xE03D);
		emoji.put(0x1F3A6, 0xE507);
		emoji.put(0x1F3A7, 0xE30A);
		emoji.put(0x1F3A8, 0xE502);
		emoji.put(0x1F3A9, 0xE503);
		emoji.put(0x1F3AB, 0xE125);
		emoji.put(0x1F3AC, 0xE324);
		emoji.put(0x1F3AD, 0xE503);
		emoji.put(0x1F004, 0xE12D);
		emoji.put(0x1F3AF, 0xE130);
		emoji.put(0x1F3B0, 0xE133);
		emoji.put(0x1F3B1, 0xE42C);
		emoji.put(0x1F3B5, 0xE03E);
		emoji.put(0x1F3B6, 0xE326);
		emoji.put(0x1F3B7, 0xE040);
		emoji.put(0x1F3B8, 0xE041);
		emoji.put(0x1F3BA, 0xE042);
		emoji.put(0x1F3BC, 0xE326);
		emoji.put(0x1F4F7, 0xE008);
		emoji.put(0x1F4F9, 0xE03D);
		emoji.put(0x1F4FA, 0xE12A);
		emoji.put(0x1F4FB, 0xE128);
		emoji.put(0x1F4FC, 0xE129);
		emoji.put(0x1F48B, 0xE003);
		emoji.put(0x1F48D, 0xE034);
		emoji.put(0x1F48E, 0xE035);
		emoji.put(0x1F48F, 0xE111);
		emoji.put(0x1F490, 0xE306);
		emoji.put(0x1F491, 0xE425);
		emoji.put(0x1F492, 0xE43D);
		emoji.put(0x1F51E, 0xE207);
		emoji.put(0x1F4F6, 0xE20B);
		emoji.put(0x1F4F3, 0xE250);
		emoji.put(0x1F4F4, 0xE251);
		emoji.put(0x1F354, 0xE120);
		emoji.put(0x1F359, 0xE342);
		emoji.put(0x1F370, 0xE046);
		emoji.put(0x1F35C, 0xE340);
		emoji.put(0x1F35E, 0xE339);
		emoji.put(0x1F373, 0xE147);
		emoji.put(0x1F366, 0xE33A);
		emoji.put(0x1F35F, 0xE33B);
		emoji.put(0x1F361, 0xE33C);
		emoji.put(0x1F358, 0xE33D);
		emoji.put(0x1F35A, 0xE33E);
		emoji.put(0x1F35D, 0xE33F);
		emoji.put(0x1F35B, 0xE341);
		emoji.put(0x1F362, 0xE343);
		emoji.put(0x1F363, 0xE344);
		emoji.put(0x1F371, 0xE34C);
		emoji.put(0x1F372, 0xE34D);
		emoji.put(0x1F367, 0xE43F);
		emoji.put(0x1F374, 0xE043);
		emoji.put(0x1F378, 0xE044);
		emoji.put(0x1F37A, 0xE047);
		emoji.put(0x1F375, 0xE338);
		emoji.put(0x1F376, 0xE30B);
		emoji.put(0x1F377, 0xE044);
		emoji.put(0x1F37B, 0xE30C);
		emoji.put(0x1F379, 0xE044);
		emoji.put(0x1F493, 0xE327);
		emoji.put(0x1F494, 0xE023);
		emoji.put(0x1F495, 0xE327);
		emoji.put(0x1F496, 0xE327);
		emoji.put(0x1F497, 0xE328);
		emoji.put(0x1F498, 0xE329);
		emoji.put(0x1F499, 0xE32A);
		emoji.put(0x1F49A, 0xE32B);
		emoji.put(0x1F49B, 0xE32C);
		emoji.put(0x1F49C, 0xE32D);
		emoji.put(0x1F49D, 0xE437);
		emoji.put(0x1F49E, 0xE327);
		emoji.put(0x1F49F, 0xE204);
		emoji.put(0x1F6AC, 0xE30E);
		emoji.put(0x1F6AD, 0xE208);
		emoji.put(0x1F6B2, 0xE136);
		emoji.put(0x1F6B6, 0xE201);
		emoji.put(0x1F6B9, 0xE138);
		emoji.put(0x1F6BA, 0xE139);
		emoji.put(0x1F6C0, 0xE13F);
		emoji.put(0x1F6BB, 0xE151);
		emoji.put(0x1F6BD, 0xE140);
		emoji.put(0x1F6BE, 0xE309);
		emoji.put(0x1F6BC, 0xE13A);
		emoji.put(0x1F192, 0xE214);
		emoji.put(0x1F194, 0xE229);
		emoji.put(0x1F195, 0xE212);
		emoji.put(0x1F197, 0xE24D);
		emoji.put(0x1F199, 0xE213);
		emoji.put(0x1F19A, 0xE12E);
		emoji.put(0x1F201, 0xE203);
		emoji.put(0x1F202, 0xE228);
		emoji.put(0x1F233, 0xE22B);
		emoji.put(0x1F235, 0xE22A);
		emoji.put(0x1F236, 0xE215);
		emoji.put(0x1F21A, 0xE216);
		emoji.put(0x1F237, 0xE217);
		emoji.put(0x1F238, 0xE218);
		emoji.put(0x1F239, 0xE227);
		emoji.put(0x1F22F, 0xE22C);
		emoji.put(0x1F23A, 0xE22D);
		emoji.put(0x1F250, 0xE226);
		emoji.put(0x1F4A1, 0xE10F);
		emoji.put(0x1F4A2, 0xE334);
		emoji.put(0x1F4A3, 0xE311);
		emoji.put(0x1F4A4, 0xE13C);
		emoji.put(0x1F4A6, 0xE331);
		emoji.put(0x1F4A7, 0xE331);
		emoji.put(0x1F4A8, 0xE330);
		emoji.put(0x1F4A9, 0xE05A);
		emoji.put(0x1F4AA, 0xE14C);
		emoji.put(0x1F4AB, 0xE407);
		emoji.put(0x1F534, 0xE219);
		emoji.put(0x1F535, 0xE21A);
		emoji.put(0x1F532, 0xE21A);
		emoji.put(0x1F533, 0xE21B);
		emoji.put(0x1F536, 0xE21B);
		emoji.put(0x1F537, 0xE21B);
		emoji.put(0x1F538, 0xE21B);
		emoji.put(0x1F539, 0xE21B);
		emoji.put(0x1F50A, 0xE141);
		emoji.put(0x1F50D, 0xE114);
		emoji.put(0x1F50E, 0xE114);
		emoji.put(0x1F512, 0xE144);
		emoji.put(0x1F513, 0xE145);
		emoji.put(0x1F50F, 0xE144);
		emoji.put(0x1F510, 0xE144);
		emoji.put(0x1F511, 0xE03F);
		emoji.put(0x1F514, 0xE325);
		emoji.put(0x1F519, 0xE235);
		emoji.put(0x1F51D, 0xE24C);
		emoji.put(0x1F44A, 0xE00D);
		emoji.put(0x1F44D, 0xE00E);
		emoji.put(0x1F446, 0xE22E);
		emoji.put(0x1F447, 0xE22F);
		emoji.put(0x1F448, 0xE230);
		emoji.put(0x1F449, 0xE231);
		emoji.put(0x1F44B, 0xE41E);
		emoji.put(0x1F44F, 0xE41F);
		emoji.put(0x1F44C, 0xE420);
		emoji.put(0x1F44E, 0xE421);
		emoji.put(0x1F450, 0xE422);

		// SMILING FACE WITH OPEN MOUTH AND COLD SWEAT
		emoji.put(0x1F605, EMOJI_TYPE_BMP_2_CHAR);
		// LOVE LETTER
		emoji.put(0x1F48C, EMOJI_TYPE_BMP_2_CHAR);

		// NATIONAL FLAG
		emoji.put(0x1F1E8, EMOJI_TYPE_SMP_2_CHAR);
		emoji.put(0x1F1E9, EMOJI_TYPE_SMP_2_CHAR);
		emoji.put(0x1F1EA, EMOJI_TYPE_SMP_2_CHAR);
		emoji.put(0x1F1EB, EMOJI_TYPE_SMP_2_CHAR);
		emoji.put(0x1F1EC, EMOJI_TYPE_SMP_2_CHAR);
		emoji.put(0x1F1EE, EMOJI_TYPE_SMP_2_CHAR);
		emoji.put(0x1F1EF, EMOJI_TYPE_SMP_2_CHAR);
		emoji.put(0x1F1F0, EMOJI_TYPE_SMP_2_CHAR);
		emoji.put(0x1F1F7, EMOJI_TYPE_SMP_2_CHAR);
		emoji.put(0x1F1FA, EMOJI_TYPE_SMP_2_CHAR);

		// NATIONAL FLAG
		emojiSMP2.put(0x1F1E8 + "" + 0x1F1F3, 0xE513);
		emojiSMP2.put(0x1F1E9 + "" + 0x1F1EA, 0xE50E);
		emojiSMP2.put(0x1F1EA + "" + 0x1F1F8, 0xE511);
		emojiSMP2.put(0x1F1EB + "" + 0x1F1F7, 0xE50D);
		emojiSMP2.put(0x1F1EC + "" + 0x1F1E7, 0xE510);
		emojiSMP2.put(0x1F1EE + "" + 0x1F1F9, 0xE50F);
		emojiSMP2.put(0x1F1EF + "" + 0x1F1F5, 0xE50B);
		emojiSMP2.put(0x1F1F0 + "" + 0x1F1F7, 0xE514);
		emojiSMP2.put(0x1F1F7 + "" + 0x1F1FA, 0xE512);
		emojiSMP2.put(0x1F1FA + "" + 0x1F1F8, 0xE50C);

		emojiBMP2.put(0x1F605, new Integer[] { 0xE415, 0xE331 });
		emojiBMP2.put(0x1F48C, new Integer[] { 0xE103, 0xE328 });

		// no use icon key
		// emoji3.put(0x1F1E8, );
		// emoji3.put(0x1F1E9, );
		// emoji3.put(0x1F1EA, );
		// emoji3.put(0x1F1EB, );
		// emoji3.put(0x1F1EC, );
		// emoji3.put(0x1F1EE, );
		// emoji3.put(0x1F1EF, );
		// emoji3.put(0x1F1F0, );
		// emoji3.put(0x1F1F7, );
		// emoji3.put(0x1F1FA, );

		// emoji3.put(0x0023, );
		// emoji3.put(0x0031, );
		// emoji3.put(0x0032, );
		// emoji3.put(0x0033, );
		// emoji3.put(0x0034, );
		// emoji3.put(0x0035, );
		// emoji3.put(0x0036, );
		// emoji3.put(0x0037, );
		// emoji3.put(0x0038, );
		// emoji3.put(0x0039, );
		// emoji3.put(0x0030, );
	}

	public static String toHexString(int org, int padding) {
		StringBuffer buff = new StringBuffer();
		buff.append(Integer.toHexString(org).toUpperCase());
		for (int i = buff.length(); i BMP converted string
	 * */
	public static String convertSMP2BMP(String org) {
		StringBuffer buff = new StringBuffer();

		if (org != null) {
			StringBuffer logData = null;

			if (log.isDebugEnabled()) {
				logData = new StringBuffer();
			}

			int key = 0, val = 0;
			int key2 = 0, val2 = 0;
			Integer val3[] = null;

			for (int i = 0, size = org.length(); i = UNICODE_4_0_EX_START)
						&& (key = UNICODE_4_0_EX_START)
							&& (key2 <= UNICODE_4_0_EX_END)) {
						i++;
					}

					if (log.isDebugEnabled()) {
						logData.append(", key2=").append(toHexString(key2))
								.append(", val=").append(toHexString(val2));
					}

					buff.append((char) val2);
				}
				else if (val == EMOJI_TYPE_BMP_2_CHAR) {
					// BMP 중 예외 이모티콘, 2개의 문자조합.
					if ((val3 = emojiBMP2.get(key)) != null) {
						for (int j = 0, size2 = val3.length; j < size2; j++) {
							if (log.isDebugEnabled()) {
								logData.append(", val").append(j).append("=")
										.append(toHexString(val3[j]));
							}

							buff.append((char) ((int) val3[j]));
						}
					}
				}
				else {
					if (log.isDebugEnabled()) {
						logData.append(", val=").append(toHexString(val));
					}

					buff.append((char) val);
				}

				if (log.isDebugEnabled()) {
					log.debug(logData);
				}
			}
		}

		return buff.toString();
	}

	public static void main(String[] args) throws Exception {
		// test code
		String tmp = "1230\u5b66\ud83d\ude30\ud83d\ude25\ud83d\ude31\ud83d\ude05\ud83c\udde8\ud83c\uddf3";

		System.out.println("TRACE, EmojiUtil.main(), [" + convertSMP2BMP(tmp)
				+ "]");
	}
}



 

+ Recent posts