달력

4

« 2024/4 »

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
2020. 12. 4. 15:35

Raspberry Pi에 대하여.. Linux/Rasberry Pi2020. 12. 4. 15:35

  Raspberry Pi(라즈베리 파이)는 영국에서 개발된 원래는 학생들 교육용으로 만들었다고 하나 개발보드로 더욱더 많이 쓰이게 된 작은 컴퓨터입니다.

Arduino(아두이노)에 비해 (물론 가능합니다만)제어 보다는 Linux Machine 으로 많이들 쓰는 편이며 3 이상 비교적 최신 버전들에는 안드로이드나 무려 윈도우(물론 Arm용)까지 설치해서 사용할 수도 있습니다.


  저는 초창기부터 B형 기본 모델(1/2/3/3+/4)을 모두 써 봤고 현재 1을 제외한 모델은 실제 계속 사용중입니다.
(1은 아무래도 메모리가 512MB 밖에 안되고 CPU도 Single Core라 성능차이가 꽤나 큽니다.)

주로 Linux 위주로 사용 가능한 편이고 성능도 PC 쓰던 사람의 기준으로 보면 너무 느려서 이걸 왜 쓰냐 싶은 사람들도 있을지 모르겠으나 Console 위주로 쓰면 그래도 크게 답답하지 않고 비교적 캐주얼한 개발/운영환경을 세팅해서 돌리는 데는 큰 부담이 없습니다.


특히 USB를 통해 5V 전압을 공급해 주면 되기 때문에 전원 공급도 편하고 무엇보다 전력소모가 적어서 하루종일 켜놔도 전기요금 걱정이 없다는게 가장 큽니다.

(가장 최신 버전인 Pi4 버전으로 외부 USB 안 꽂은 상태에서 풀 코어 컴파일시 1A가 채 안 들어가니 max 5W 정도죠)


이를 이용해서 공유기 설정으로 외부 포트를 열어두면 어디서든 접근 가능한 가벼운 Linux 장비가 하나 생기는 셈이죠.

최근에는 Cloud가 많이 사용되면서 효용성이 좀 줄었으나 그래도 비용 면에 있어서는 괜찮다고 봅니다.

여기에 가벼운 웹서버 등을 올려서 사용하거나 주기적인 crawling 작업들을 걸어놓기는 충분합니다.


  다만 저도 Linux에 그리 익숙한 편이 아니라 사용에 여러가지 제약이 있었고 특히나 비교적 Community가 큰 Raspberry Pi 이지만 아무래도 x86에 비해 여러가지 부족한 부분이 많아서 삽질이 많았고 개인적으로도 정리할 겸, 그리고 같은 내용으로 고민하고 있는 사람들에게도 도움을 줄 겸 정리하고자 하는 페이지입니다.

다만 제 개인적인 해결내용을 적다 보니 모든 사람의 환경에 맞지는 않을 수 있다는 점은 참고 바랍니다.

:
Posted by hanavy

..  이번에는 Constructor Chaining(또는 Cascading)이라는 개념입니다.

대단한건 아니고 생성자를 하나가 아니라 여러 파라미터들을 옵션으로 선택할 경우 코드를 줄이기 위한 방법 중 하나입니다. 


물론 C# 뿐만이 아니라 Java에서도 가능하지만 Java에서는 딱히 이런 명칭을 들어본 적은 없는것 같네요..  C#은 약간 별도의 문법이 있어서 이런 명칭이 붙은 것 같습니다.  당연히 될 거라 생각하고 Java의 문법을 적용했는데 자꾸 Syntax Error가 발생하여 찾아보다가 발견한 내용입니다.



  예를 하나 들겠습니다.

UserException 이라는 사용자 정의 Exception을 하나 생성하려고 하는데 생성자에 파라미터로 에러메시지(message), 에러코드(code)라는 두 개의 파라미터를 받으려고 합니다.

그런데 항상 두 개의 파라미터를 꼭 받아야 하는 건 아니고 디폴트 코드가 있으면 메시지만, 거꾸로 디폴트 메시지가 있다면 코드만 받아서 나머지 하나는 디폴트 값을 넣으려고 합니다.  물론 둘 다 받을 경우도 있으니 총 3개의 경우의 수가 생기겠네요.


단순하게 생각해서 생성자 3개 만들면 끝납니다.  그런데 만일 단순히 이 값을 받아 저장하는 것이 아니라 값들에 따른 로직이 좀 더 있다라면 해당 로직은 세 개의 생성자에 동일하게 복사해서 넣어야 합니다.  코딩에서 주의해야 할 코드 중복이 발생하겠죠..

그렇다면 어떻게 하는 것이 좋을까요?  가장 다양한 케이스인 두 개의 파라미터를 모두 받는 경우에만 해당 로직을 구현해 놓고 나머지 두 개의 생성자에는 디폴트 값과 입력받은 값을 가지고 두 개의 파라미터를 가지는 생성자를 호출하면 깔끔하게 끝납니다.

백문이 불여일타라, Java의 경우는 대략 다음과 같은 코드로 만들 수 있습니다.


	public UserException (int code) {
        this(code, "Default Message");
    }

    public UserException (String message) {
        this(0, message);
    }

    public UserException (int code, String message) {
        // 값을 할당하고 처리하는 로직.....
    }



this() 를 이용하여 생성자 내부에서 생성자를 호출할 수 있죠.

물론 this()  호출은 해당 생성자의 첫번째에 위치해야 합니다.



  그런데 문제는 C#에서 동일한 코드를 사용했더니 자꾸 오류가 발생하는 겁니다.

검색을 해 보니 C#에서는 이런걸 Constructor Chaining(Cascading)이라 부르고(Java에서도 이 기법 자체를 그렇게 부르는지는 모르겠습니다.  지금까지는 들어본 적이 없어서..) 약간 문법이 다릅니다.  해당 내용을 C# 버전으로 구현하면 다음과 같습니다.


    public UserException (int code) : this(code, "Default Message")
    {

    }

    public UserException (String message) : this(0, message) {

    }

    public UserException (int code, String message) {
        // 값을 할당하고 처리하는 로직.....
    }


위 코드와 같이 함수명 뒤에 : this() 형태로 추가를 해야 하지 Java 처럼 내부에서 this를 호출하면 Syntax Error가 발생합니다.

물론 생성자 호출 후 자체적인 초기화 코드가 있으면 Java에서는 this 밑에, C#에서는 코드 본문 영역에 넣으면 됩니다.


이렇게 별 것도 아닌데 사소한 문법의 차이로 시간 낭비할 때가 해결된 후에 제일 허탈하더군요..

그게 어찌 보면 제가 이 꼭지를 만든 이유이기도 합니다.


다른 분들은 삽질을 덜 하길 바라면서...

'C# > Java 개발자를 위한 C#' 카테고리의 다른 글

C# 에서의 문자열 비교, == or Equals?  (3) 2017.02.28
이곳의 용도는...  (0) 2017.02.27
:
Posted by hanavy

  첫번째 주제는 문자열 비교에 대한 부분입니다.

Java 프로그래머라면 초급때부터 주구장창 들어온 격언(?)이 하나 있을겁니다.

유명한 Josuha Bloch 의 Effective Java 책에서도 하나의 아이템으로 나오는 부분으로서, 문자열 비교시에 == 를 쓰면 안되고 .equals()를 써야 한다는 것이죠.

원체 많이 알려진 내용이라 간단하게만 언급하자면 == 연산자는 객체 자체의 동일성을 비교하는 것으로서 쉽게 말하면 메모리상에서 주어진 문자열이 위치하는 영역이 동일한지를 보는 것이고 equals()는 위치는 상관없고 실제 문자열의 각 문자 하나하나가 모두 동일한지를 보는 것이기 때문에 equals() 로는 동일하다고 나오더라도 == 로는 다르다고 판정되는 경우가 있다는 것이죠.


  먼저 Java의 예를 봅시다.

아래와 같은 코드를 실행했을 때 결과가 어떻게 될까요?


	public void static main(String[] args) {
		String a = "11";
		String b = "11";
		String c = "1111".substring(0, 2);

		System.out.println(a.equals(b) + "\t" + a.equals(c));
		System.out.println((a == b) + "\t" + (a == c));
	}


일단, PC 별로 결과가 다를 가능성이 없다고는 못하겠는데 아마도 대부분의 경우 다음과 같이 나올 겁니다.


true    true
true    false


위에 적은 대로 equals는 값을 비교하기 때문에 실제 값이 모두 "11" 이므로 당연히 모두 true가 나오지만 ==의 비교의 경우는 a 와 b는 같다고 나오지만 a와 c는 다르다고 나온다는게 문제인거죠.


== 연산의 경우 a와 b는 왜 같다고 나오느냐, 다른거 아니냐고 혹시 생각하신다면 Java의 경우 스트링 연산으로 인한 메모리의 낭비를 줄이기 위해 내부적으로 String 이 사용하는 메모리 공간을 나름 효율적으로 관리하여 중복되는 문자열은 되도록이면 재 할당하지 않도록 작동하기 때문에 위와 같은 단순한 코드에서는 당연히 a와 b가 값이 같을 수 밖에 없기 때문에 한 번만 할당한 뒤 공유하는 방식을 선택합니다.  그래서 a와 b가 같다는 결과가 나온거구요.


설마 그럴까 싶긴 하지만 혹시 JVM이 둘을 다르게 판단했다면 false false가 나올 수도 있습니다.

위와 같은 간단한 코드에서는 그럴 일이 별로 없지만 복잡하게 돌아가는 실무 코드에서는 충분히 발생할 수 있고 그렇기 때문에 문자열 비교의 경우는 == 이 아니라 equals() 를 써야 한다고 강조하는 거구요.




  이번에는 본론입니다.  C# 의 경우에는 어떨까요?


  최초 다른 사람이 먼저 작성한 C# 코드를 봤는데 대부분 ==으로 비교를 했더군요..

상당히 혼동이 왔습니다.

Java의 경우는 저렇게 하지 말라고 항상 가이드가 되어있고 상식인데 C#은 안그러니 이걸 짠 사람이 잘 못 짠건지, C#은 상관 없는 건지를 판단하기가 좀 애매했습니다.


  결론적으로는 C#에서의 문자열 비교는 == 로도 Equals() (C#은 Pascal Case를 쓰죠..) 와 동일하게 사용 가능합니다.  즉, String class 의 값 비교는 ==로 해도 Equals() 와 동일합니다.



  그 원리는 무엇일까요?


  Java를 만들 때 James Gosling의 철학에 의해 불필요하다고 판단되어 누락되었던 C 계열의 기능 중 하나인 연산자 overloading 에 의한 기능입니다.

원칙적으로는(Object class) == 연산은 Java와 동일한 객체 동일성 비교이지만(System.Object.ReferenceEquals) string class에서는 연산자 overrloading의 기능을 이용하여 == 연산을 Equals() 연산을 수행하게 만들었고 즉, 이는 string class의 경우는 == 를 쓰나, Equals() 를 쓰나 모두 Equals()가 실행되도록 한 것입니다.



  그러면 이제 모두 끝났나, C#은 그냥 문자열 비교시에 ==만 쓰면 끝인가?

그런데 그게 그렇게 간단하지만은 않았습니다.

위의 사실을 알고 나서는 마음 편하게 C#에서는 == 를 쓰다가 한 번 버그로 엄청 고생을 한 적이 있습니다.

LinQ를 이용한 데이터 처리중에 분명히 값이 같은데 ==를 사용시 다르다고 나온 적이 있었죠.

물론 Equals()는 되구요..  아래와 같은 경우입니다.



        static void CompareString()
        {
            string a = "11";
            string b = "1111".Substring(0, 2);
            object c = b;
            Console.WriteLine(a.Equals(b) + "\t" + a.Equals(c));
            Console.WriteLine((a == b) + "\t" + (a == c));
        }


결과가 어떻게 될까요?


True    True
True    False


위와 같은 결과가 나옵니다.

마침, Visual Studio 2013에서는 마지막에 값이 다른 (a == c)의 경우에는 "의도하지 않은 참조 비교가 있을 수 있으니 값 비교를 하려면 오른쪽을 "string" 형식으로 캐스팅하라" 라는 경고를 보여주긴 하네요..

차이는 c의 경우는 실제로는 string 값이 들어가지만 객체가 object이기 때문에 == 비교시 string의 Equals() 비교가 아닌 System.Object.ReferenceEquals() 이 이루어지게 됩니다.  따라서 다르다고 판단이 되죠..

  위의 코드는 일부러 오류 케이스를 보이기 위해 명확하게 적어서 눈에 띄지만 Generics를 쓰지 않은 리스트나 dictionary 등에 넣거나 DataTable 에서 들어간 데이터를 접근시 indexer로 값을 가져올 때 등은 실제로는 string 값이지만 객체 형식이 string이 아닌 경우가 있기 때문에 조심해야 합니다.



  결론은 다음과 같습니다.

string class간 값 비교시에는 C#은 == 를 써도 됩니다.  다만 object 등의 다른 클래스로 형식이 지정되었을 경우는 string class의 Equals() 가 overriding이 되지 않으므로 주의해야 합니다.

'C# > Java 개발자를 위한 C#' 카테고리의 다른 글

생성자(Constructior) Chaining(Cascading)  (0) 2017.03.09
이곳의 용도는...  (0) 2017.02.27
:
Posted by hanavy
2017. 2. 27. 18:15

이곳의 용도는... C#/Java 개발자를 위한 C#2017. 2. 27. 18:15

  업무에서는 2002년부터, 학교에서 공부했던 기간까지 치면 1997년부터 Java를 사용해 왔으니 벌써 20년이나 되었습니다.

물론 자바만 사용한 것은 아니지만 그래도 가장 메인 언어였기 때문에 Java에 대해서는 어느 정도 잘 알고 있다고 생각했고 사용하기도 편했는데 2015년에 회사 내부 사정으로 팀이 이동되면서 갑자기 MS Solution 기반, 특히나 C#을 주로 사용하는 쪽으로 가게 되었습니다.


  다들 자바나 C#이나 그게 그거니까 금방 하겠네, 그러는데 솔직히 전 그 말이 상당히 싫었습니다.

문법이 많이 비슷하긴 하지만 그것이 처음에 익숙해지는데는 도움이 될 망정 초보 단계를 넘어가면 오히려 Java에서의 익숙함 때문에 C처럼 Java를 짜거나(물론 둘다 OOP Language로서 그정도 까지는 안되겠지만) 비슷하지만 다른 점 때문에 오히려 고생할 수도 있을거라는 생각이 들었기 때문입니다.


  이제 벌써 C#을 써온지 1년 반 정도 되어가는 시점에 보니 역시나 예상대로 처음 접근은 익숙했지만 여러가지 비슷하면서도 다른 문법과 구조들 때문에 여러 삽질들이 있어왔습니다.

이 Section은 제목 그대로, 저처럼 Java 는 최소한 초중급 이상 할 줄 알지만 C#을 처음 하시는 분들을 대상으로 비슷하지만 다른 점들을 정리해서 저같은 분들이 헤매지 않았으면 하는 생각에서 정리하려고 합니다.


개구리 올챙이적 생각 못 한다고 벌써 많이들 까먹었지만 생각나는 대로 업데이트를 할 예정이며 아직 Java에 비해 C# 사용능력이 일천한지라 잘 못 적거나 불필요하게 돌아가는 방식으로 풀었을 수도 있으니 그런 부분들은 고수님들께서 지적해 주시면 고쳐놓도록 하겠습니다.

:
Posted by hanavy
2015. 4. 29. 23:03

Java에서 SHA 기반 해시암호화 Java2015. 4. 29. 23:03

  원래부터 중요하긴 하지만 요 몇 년새에 각종 보안사고(포털/금융기관 등에서의 개인정보 유출 등)가 많이 발생하면서 보안에 대해서 많이 깐깐해지고 있습니다.
그래도 외부에 공개되는 사이트의 경우는 좀 신경쓰고 있지만 내부 시스템의 경우는 비교적 최근까지 BASE64 기반 "인코딩"을 하고 나서 암호화라고 하는 곳도 봤고 심하면 아예 패스워드를 눈에 보이게 그대로 저장하는 케이스까지 있었습니다.


  그런데 이제는 구체적으로 암호화의 방법에 대해서 최소 256bit 이상으로 해야 하네, 패스워드는 복호화가 불가능하게 해시 암호화를 해야 하네 등등 가이드가 나오고 있습니다.  좋은 방향이죠...


  원래 암호화라는게 수학, 특히 정수론 등의 상당히 복잡한 이론에 기반한 내용이라 아무나 쉽게 접근할 수 없는 내용이지만 그래도 요즘에는 효율적인 암호화 알고리즘들이 라이브러리화되어 쉽게 사용할 수 있도록 제공되고 있어 내부적인 알고리즘까지는 알지 못하더라도 사용하기는 쉽게 제공되고 있습니다.


  이번에는 그 중에서 먼저 복호화가 불가능한 방식인 해시암호화, 그 중 대표적인 SHA 기반 암호화에 대해서 적어보려고 하는데 구체적인 내용까지는 모르더라도 해시암호화가 뭔지, 복호화가 가능한 암호화와 무엇이 다른지 등등 기본적인 내용은 알아야 상황에 따라서 잘 사용할 수 있겠죠..
암호화 알고리즘을 검토할 때 상당히 도움이 되었던 사이트가 있어서 소개드리니 기본적인 내용은 아시는 분들이라도 먼저 간단하게 내용을 한 번 보고 오기 바랍니다.  해시 암호화 위주의 설명이긴 하지만


안전한 패스워드 저장


  위 사이트에서 나온 부분 중 대표적인 해시 암호화 함수인 SHA- 계열을 Java에서 구현하는 방법을 기술한다.  Oracle(구 Sun)의 1.6 이상 JVM이면 다 지원됩니다(IBM의 JVM에서도 확인).



  SHA(위키피디아)는 Secure Hash Algorithm의 약자로 기존에 많이 사용되던 MD5(Message-Digest algorithm 5, 위키피디아)가 암호화로 쓰이기는 부적합하여 해시 암호화를 위해 개발되었고 Java의 암호화 알고리즘에서는 SHA-1, SHA-256, SHA-384, SHA-512 를 지원합니다.


서론이 길었으니 일단 그 중 SHA-512 방식의 암호화 함수 예제를 한 번 보겠습니다.

 private static String getSha512(String plainText) {
		try {
			MessageDigest md = MessageDigest.getInstance("SHA-512");
			byte[] bytes = plainText.getBytes(Charset.forName("UTF-8"));
			md.update(bytes);
			return Base64.encode(md.digest());
		} catch (Exception e) {
			System.out.println("Sha512 error.");
			e.printStackTrace();
			return null;
		}
	}



  의외로 위와 같이 간단합니다.  SHA-1, SHA-256, SHA-384 등은 3번째 라인의 "SHA-512" 부분만 해당 값으로 변경하면 됩니다.  물론 간단한 코드라 Base64 인코딩이나 NullPointerException 방지를 위한 체크 등은 더 필요하구요.  


  다만 많은 구현에서 String <=> byte[] 간의 변환시에 별도의 인코딩을 지정을 안하는 경우가 많던데 그럴 경우 환경이 달라지면(예를들어 MS949 기반의 윈도우에서 구동하는 프로그램과 UTF-8 기반의 Unix에서 구동하는 프로그램이 동시에 서로 암복호화를 할 경우) 한글 등을 처리할 때 문제가 발생할 수 있으니 인코딩은 꼭 지정하시길 바랍니다.


  담번에는 대표적인 복호화 가능한 대칭키 암호화 알고리즘인 AES와 참고 사이트에서 나왔던 bCrypt에 대해서 간단히 포스팅할 예정입니다.
(일단 테스트는 다 된 상황이라.. 정리만 하면...)

'Java' 카테고리의 다른 글

"\ub4f1" 와 같은 unicode 문자열 읽어오기  (0) 2014.01.28
JDK 1.7.21에서 Runtime.exec의 변경사항  (0) 2013.04.26
:
Posted by hanavy
2014. 1. 28. 12:56

"\ub4f1" 와 같은 unicode 문자열 읽어오기 Java2014. 1. 28. 12:56

컴퓨터가 7bit면 자신들의 모든 문자를 표현 가능한 문화권에서 개발되다 보니 아무래도 우리나라처럼 2-byte 문자열을 쓰는 나라들에서는 아직까지도 문제가 생기는 경우가 많습니다.  우리나라 같은 경우는 한글문제라고 흔히들 통칭하는데..


그나마 현대의 언어들은 상당수 다국어 지원(유니코드를 비롯)을 기본적으로 가져가기 때문에 일반적인 환경에서는 문제가 잘 생기지 않는 경우들이 많지만 그렇기 때문에 가끔 문제가 생기면 더더욱 힘든 케이스들도 많이 보입니다.
자바의 경우는 처음부터 내부적으로 유니코드만을 사용하는 등 언어 자체적으로 국제화를 고려해서 만들었지만 초기 API 설계의 miss로 지금은 deprecated된 함수들도 많이 있죠...(국제화쪽 관련해서는 주로 I/O쪽.. LineNumberInputStream 등등..)


여튼 서론은 이정도고..
이번에 하는 프로젝트에서 property 파일(key=value 형태로 텍스트로 저장하는)에서 값을 읽어와야 할 일이 있는데 Eclipse 기반의 개발환경에서 property 파일 편집을 위해 일본에서 만든 플러그인인 PropertiesEditor라는걸 사용하더군요..
그런데 문제(?)는 이 플러그인이 파일을 저장하면 한글이 다음과 같이 저장됩니다.


# \uc2dc\uc2a4\ud15c \uacf5\ud1b5


저 문자열은 원래 다음과 같은 글자입니다.


# 시스템 공통


유니코드를 저장할 때 ASCII 영역 외의 2-byte 문자열의 경우 \uXXXX 형태로 저장하는 걸로 보입니다.
그런데 문제는 저 내용을 다음과 같이 소스코드상에 넣으면 잘 나오는데

public static void main(String[] args) {
    System.out.println("# \uc2dc\uc2a4\ud15c \uacf5\ud1b5");
}

저걸 파일에서 읽어오면 저 문자열 그대로 읽어오더군요..
처음에는 다음과 같은 방법을 사용해 봤습니다.

public static void main(String[] args) throws IOException {
    LineNumberReader in = new LineNumberReader(new InputStreamReader(new FileInputStream("c:\\a.properties"), "UTF-8"));
    System.out.println(in.readLine());
    in.close();

음.. UTF-8이긴 하지만 헥사값의 내용이 아닌 헥사값의 표현인 영문값이 저장된 형태이기 때문에 효용이 없었습니다.
그래서 이런때를 위한 구글신에게 검색이 들어갔습니다.


찾아보다 보니 다음과 같은 내용이 보이더군요..
Unicode Escape Formats 라는 내용인데 유니코드를 Escape Sequence를 이용해서 표기하는 여러가지 방법을 나열했는데 그 중에 위의 내용이 보입니다.
Java나 Ruby에서 쓰이는 포맷이라고 합니다.  언어별로 표기하는 법들이 다들 천차만별이라..


여튼 검색하다 보니 반대의 경우, 즉 한글을 넣으면 저렇게 unicode sequence를 기반으로 만들어 주는 프로그램은 JDK에 기본적으로 같이 제공이 되고 있습니다.
native2ascii 라는 프로그램인데 실행 후 console에서 입력하면 다음과 같이 만들어 줍니다.


실행하면 그냥 커서만 깜빡이는데 여기에 문자열을 아무거나 입력하면 "\u" 를 이용한 Escape Sequence 문자열로 만들어줍니다.(종료시에는 그냥 Ctrl-C 사용)
그런데 일단 다른 별도의 프로그램을 쓰는 방식은 프로그래머들에게는 별 도움 안되고 일단 지금 필요한 건 반대의 케이스라..
무언가가 있을거 같긴 한데 결국 찾지는 못했고 그냥 만들었습니다.(몇 개 찾는 솔루션들도 다들 직접 구현했더군요..)


원리는 간단합니다.\uXXXXX 형태로 저장된 문자열을 찾으면 \u를 제거하고 XXXX 로 표현된 32bit 문자열을 읽어서 해당 char 형태로 바꿔주면 됩니다.(자바는 내부적으로 유니코드를 사용하므로 char는 2 byte 입니다.)
일단 최적화는 크게 고민은 안했고 기능상으로 다음과 같이 만들었습니다.

	private String unicodeConvert(String str) {
		StringBuilder sb = new StringBuilder();
		char ch;
		int len = str.length();
		for (int i = 0; i < len; i++) {
			ch = str.charAt(i);
			if (ch == '\\' && str.charAt(i+1) == 'u') {
				sb.append((char) Integer.parseInt(str.substring(i+2, i+6), 16));
				i+=5;
				continue;
			}
			sb.append(ch);
		}
		return sb.toString();
	}

일단 개념 정도고 제대로 사용하려면 예외상황(\u 뒤에 4byte의 16진수 데이터가 올바로 나오지 않을때는? 등등)에 대한 처리가 좀 더 필요합니다.

'Java' 카테고리의 다른 글

Java에서 SHA 기반 해시암호화  (1) 2015.04.29
JDK 1.7.21에서 Runtime.exec의 변경사항  (0) 2013.04.26
:
Posted by hanavy
2013. 4. 26. 00:38

JDK 1.7.21에서 Runtime.exec의 변경사항 Java2013. 4. 26. 00:38

정말.. 오랜만에 포스팅이네요.. 1년 하고도 몇 달만에...
일상 포스팅이야 몰라도 개발쪽 포스팅은 아무래도 준비해야 할 것도 많고 해서 좀 부담스러워 자주 못 하게 됩니다.


여튼.. 이번 건은 최근에 자주 버전업이 되고 있는 자바와 관련한 건인데요..


최근 오라클로 넘어간 다음에 자바에 대해서 이러쿵 저러쿵 말이 많은데...
많이들 사용하다 보니 해커도 꼬이고 보안 구멍은 자꾸 늘어나는데다가 오라클이 하는 짓꺼리 때문에 별로 호응도 못 받고...
(James Gosling 아저씨도 떠났더랬죠..)


그때문이기도 하겠지만 예전처럼 버전이(물론 소숫점 아래 둘째 자리 혹은 _ 아래의 fix 버전 얘기지만) 하나씩 올라가는게 아니라 한번에 몇 개씩 올라가기도 합니다.(정확히 올라가는 기준은 잘 모르겠습니다만)
그러다가 이번에는 최신버전인 1.7.x 버전이 1.7.0_17에서 1.7.0_21로 네 단계올라갔는데요..
지금까지는 그냥 그러려니 했는데 이번 버전업을 한 뒤에 기존 프로그램에 오류가 발생한 사건이 생겨서 혹시나 저처럼 삽질하실 분들이 생길까봐 정리합니다.


기본적으로 업데이트 상세내역은 Update Release Notes 페이지에 잘 나와있습니다.
버전의 특성상 대부분 버그 또는 보안 패치인데요..


그 중에서 이번에 저한테 영향을 줬던 부분은 다음 부분입니다.
Changes to Runtime.exec


링크 가보셔도 됩니다만 아래와 같은 내용이 적혀있습니다.


On Windows platform, the decoding of command strings specified to Runtime.exec(String),Runtime.exec(String,String[]) and Runtime.exec(String,String[],File) methods, has been improved to follow the specification more closely. This may cause problems for applications that are using one or more of these methods with commands that contain spaces in the program name, or are invoking these methods with commands that are not quoted correctly.

For example, Runtime.getRuntime().exec("C:\\My Programs\\foo.exe bar") is an attempt to launch the program "C:\\My" with the arguments "Programs\\foo.exe" and "bar". This command is likely to fail with an exception to indicate "C:\My" cannot be found.

The example Runtime.getRuntime().exec("\"C:\\My Programs\\foo.exe\" bar") is an attempt to launch the program "\"C:\\My". This command will fail with an exception to indicate the program has an embedded quote.

Applications that need to launch programs with spaces in the program name should consider using the variants of Runtime.exec that allow the command and arguments to be specified in an array.

Alternatively, the preferred way to create operating systems processes since JDK 5.0 is usingjava.lang.ProcessBuilder. The ProcessBuilder class has a much more complete API for setting the environment, working directory and redirecting streams for the process.


울렁증 있으신 분들을 위해 간략하게 적어보면 Windows 플랫폼의 경우 자바의 Runtime.exec를 통해 다른 프로세스를 호출하여 실행할 경우 규격에 맞게 좀 더 까탈스러워졌다는 말입니다.
주로 경로(또는 파일명)에 공백이 있을 경우(대표적으로 Program Files와 같은 곳이 되겠죠) 발생할 수 있는 보안 이슈를 대비해 바꿨다고 합니다.


예를 들어 Runtime.getRuntime().exec("C:\\My Programs\\foo.exe bar") 라는 문장이 있었다고 보면
예전같으면 C:\My Programs\foo.exe를 bar라는 인자를 주고 실행하는 정상적인 코드였지만
이제는 C:\My 라는 프로그램에 Programs\foo.exe와 bar라는 두 개의 인자를 주고 실행하는 명령으로 인식을 한다고 합니다.
(즉, 무조건 첫번째 공백 다음에는 인자라는 얘기겠죠..)


앞으로는 Runtime.exec 의 다른 계열 중 실행파일명과 인자를 별도로 입력받는 함수들을 사용하라고 합니다.
아니면 JDK 1.5 버전 이상이면 더욱 더 많은 기능을 제공하는 ProcessBuilder 클래스를 사용하라고 하네요.


스펙에 맞도록 바꿨다는 말인걸 보니 스펙문서를 좀 더 자세히 봐야 하겠습니다만 여튼 위와 같은 방식으로 호출하는 경우가 있으면 이번 업그레이드 후 오류납니다..


저같은 경우는 아래와 같이 사용을 했었습니다.
Process proc = Runtime.getRuntime().exec("C:/Program Files/My/SysinternalsSuite/pslist.exe")


저는 일단 두 번째 방법을 이용해서 ProcessBuilder로 실행방식만 아래와 같이 바꾸니 실행이 가능했습니다.
Process proc = new ProcessBuilder("C:/Program Files/My/SysinternalsSuite/pslist.exe").start()

참고하시기 바랍니다.

'Java' 카테고리의 다른 글

Java에서 SHA 기반 해시암호화  (1) 2015.04.29
"\ub4f1" 와 같은 unicode 문자열 읽어오기  (0) 2014.01.28
:
Posted by hanavy
2012. 1. 3. 00:08

Redmine 설치와 Eclipse 연동 개발툴2012. 1. 3. 00:08

예전 블로그TOW(Trac On Windows)의 설치 관련 포스팅을 한 적이 있습니다.
Trac은 개발 프로젝트를 관리하는데 상당히 쓸만한 툴이긴 합니다.
그런데 가장 큰 문제점이 설치가 무척 힘들다는 것과.. 그래서 어느 한국분이 위의 TOW를 만드셔서 Windows 환경에서는 그래도 좀 쉽게 설치가 되게 했습니다만.. 그래도 만만찮죠..

그러던 중 알게 된 툴이 Redmine입니다.
개발자가 개발에 필요한 항목 위주로 설정된 Trac에 비해서 Redmine 은 일단 UI도 좀 더 깔끔하고 한글도 원활히 지원될 뿐 아니라 Gantt Chart 등을 통한 일정관리 등 관리자들과 같이 쓰기에도 더 나은 것 같습니다.

한 가지 단점이 Eclipse의 Mylyn에서 바로 지원이 되던 Trac에 비해서 Redmine은 Eclipse와의 연동이 쉽지 않다는 것이었는데 아직은 Trac에 비해 좀 부족하지만 Eclipse 기반 Plugin도 찾게 되어서 내용을 정리해보고자 합니다.

오픈소스의 특성상 이 내용들은 아마도 수시로 바뀔겁니다.
일단 저는 2011년 12월 10일날 공개된 Redmine 1.3.0 Stable  버전을 기반으로 설치하겠습니다.

Python을 기반으로 하여 구성된 Trac과 달리 Redmine은 Ruby(ruby on rails) 기반으로 작성되어 있습니다.
확실히 요즘은 스크립트 기반의 Framework이 대세인거 같군요..
어느쪽이던 쓸 줄을 모르는 스크립트 언어라..  한번 배워놔야 할 듯..

설치는 다음과 같은 순서로 진행됩니다.
(영문 공식 설치가이드 페이지는 여기입니다.)
  1. Ruby(1.8.7) 설치
  2. Rails(2.3.14), Rack(1.1.1), Rake(0.8.7), iI18n(0.4.2) 설치
  3. Redmine(1.3.0) 설치 => 중간확인
  4. Eclipse Plugin 설치



1. Ruby 설치


현 시점(2012년 1월 2일) 기준으로 최신 버전은 1.9.3이지만 Redmine과의 호환성 때문에 1.8.7 버전을 선택하기로 했습니다.
Ruby 다운로드는 RubyForge 사이트에서 받으시면 되는데 저는 취향대로 installer 를 싫어하는 편이라 7z으로 압축된 압축 해제본을 받았습니다.
일단 경로가 너무 길어서 좀 줄이고 저는 E:\Program\Ruby-1.8.7 에 압축을 풀었습니다.

압축푸는 방식으로 설치했으면 환경설정이 일부 필요합니다.
RUBY_HOME을 추가하고 PATH에 추가하죠...

set RUBY_HOME=E:\Program\Ruby-1.8.7
set PATH=%RUBY_HOME%\bin;%PATH%

물론 Windows는 아래와 같이 시스템 속성->고급->환경 변수에서 세팅해야 합니다.




2. Rails(2.3.14), Rack(1.1.1), Rake(0.8.7), i18n(0.4.2) 설치
Rails는 Ruby에서 웹 개발을 위한 Framework이고(Ruby on Rails) 나머지는 제가 Ruby를 잘 몰라 정확히는 모르지만 여튼 Ruby의 관련 라이브러리입니다(i18n은 internationalization일 듯.. 국제화).
이 파일들은 직접 다운로드 받거나 할 필요는 없고 gem 이라는 일종의 패키지 매니저를 사용해서 받습니다.

그런데 예전 버전에서는 없었던 문제인 듯 싶은데 gem이 업데이트 되면서 호환성 문제가 생깁니다.
당장은 괜찮은데 아래 작업을 하지 않으면 나중에 session store secret 생성시 오류가 발생하므로 gem을 아래와 같이 다운그레이드 시켜줍니다.
 E:\Program\Ruby-1.8.7\bin>gem update --system 1.6.2
확인해 보니 공식 페이지에도 이런 글이 있네요..
 RubyGems 1.3.7 or higher is required with following limitations :

    Rails 2.3.5 will fail with RubyGems 1.5.0 or later, stick to previous versions of RubyGems !
    Rails 2.3.11 will fail with RubyGems 1.7.0 or later, stick to previous versions of RubyGems !



그럼 아래 명령을 실행해서 현재 설치된 현황을 알아봅니다.
E:\Program\Ruby-1.8.7\bin>gem list -- local
*** LOCAL GEMS ***

rubygems-update (1.6.2)

E:\Program\Ruby-1.8.7\bin>

만일 7z으로 압축받아서 설치했으면 위에서 설치한 rubygems-update 하나밖에 없을 것이고 인스톨 버전으로 설치했으면 설치된 내역이 나올겁니다.
버전이 안맞거나 설치된 내역이 없으면 제목의 저 프로그램들을 아래와 같이 각각 인스톨 합니다.

>gem install rails -v=2.3.14
>gem install rack -v=1.1.1
>gem install rake -v=0.8.7
>gem install i18n -v=0.4.2

네트웍을 접속해서 설치가 진행되므로 온라인 상태여야 하며 다운로드 시간을 감안해서 좀 기다려야 합니다.

설치 후 다시 설치내역을 확인하면 다음과 같습니다.
 e:\Program\Ruby-1.8.7\bin>gem list --local

*** LOCAL GEMS ***

actionmailer (2.3.14)
actionpack (2.3.14)
activerecord (2.3.14)
activeresource (2.3.14)
activesupport (2.3.14)
i18n (0.4.2)
rack (1.1.3, 1.1.1)
rails (2.3.14)
rake (0.9.2.2, 0.8.7)
rubygems-update (1.6.2)

e:\Program\Ruby-1.8.7\bin>

rack과 rake는 rails 의 depencency 때문에 2개의 버전이 인스톨 된 상황입니다.
필요하시면 다음의 명령을 실행 후 상위버전을 삭제하면 됩니다.
 >gem uninstall rack
 >gem uninstall rake
입력창에서 삭제하시려는 버전을 선택하면 됩니다.
(그런데 그냥 놔둬도 별 상관 없더군요)

3. Redmine(1.3.0) 설치
드디어 오늘의 주인공 Redmine을 설치할 시간입니다.
이부분은 좀 기니.. 세부 목록으로 좀 나누겠습니다.

3-1. Redmine 설치(압축해제)
다운로드 메인 페이지는 여기이며 역시나 이곳도 결국 RubyForge의 다운로드 페이지로 연결됩니다.
zip으로 압축된 파일을 받으시면 되고 적당한 위치에 압축을 풉니다.
저는 E:\Program\Redmine-1.3.0 에다 설치했습니다.

3-2. DB 선정(mysql) 및 계정생성
그리고 자료를 저장할 Database 를 선정&설치합니다.
Redmine 은 MySQL과 PostgreSQL을 지원하는데 mysql로 설치를 진행하겠습니다.

일단 mysql 설치 및 환경설정은 너무 범위를 벗어나는 거 같아서 다른 블로그 등을 참조하시고..
설치가 되면 redmine 유저를 우선 생성합니다.
mysql에 접속하셔서 다음과 같이 실행합니다.

create database redmine character set utf8;
create user 'redmine'@'localhost' identified by 'my_password';
grant all privileges on redmine.* to 'redmine'@'localhost';

물론 my_password에는 저장하고자 하는 암호를 넣어주시구요.
mysql 버전 5.0.2 이전의 경우에는 아래 두 줄을 다음과 같이 한 번에 실행이 가능합니다.

 grant all privileges on redmine.* to 'redmine'@'localhost' identified by 'my_password';

3-3. database.yml 편집
이제 사용자와 DB 구성이 완료되었으니 redmine용 schema를 생성할 차례입니다.
Redmine 설치위치의 config 에 가보면 database.yml.example 이라는 텍스트 파일이 있는데 이 파일을 database.yml로 이름을 변경하고 다음과 같이 편집합니다.
(production 항목 변경)

 production:
  adapter: mysql
  database: redmine
  host: localhost
  username: redmine
  password: my_password
  encoding: utf8

빨간색 암호 부분은 위의 설정한 암호로 변경하시구요.
만일 port 번호를 기본인 3306 이외의 포트로 쓰신다면 port: 해서 추가해 주시면 됩니다.

3-4. redmine용 mysql 라이브러리 설치
그리고 mysql로 실행할 것이므로 mysql용 접속 라이브러리를 다음과 같이 설치합니다.
 >gem install mysql

No definition for ~~~ 라는 메시지가 여럿 뜨는데 이 부분에 대해서는 아직 정확히 모르겠습니다.
그리고 Windows의 경우 관련 dll이 설치되지 않아서 오류가 발생하므로 여기서 dll 파일을 받아서 %RUBY_HOME%\bin 에 넣어줍니다.



3-5. session store secret 생성
다음은 session store secret이라는 것을 만들 차례인데 redmine 설치위치로 이동해서 다음과 같이 수행합니다.
 rake generate_session_store

3-6. Schema 생성
이제 mysql에 schema를 생성합니다.
우리가 production 항목에 변경했으므로 production으로 설정하고 실행합니다.
 >set RAILS_ENV=production
 >rake db:migrate

그러면 뭔가 한참 돈 다음에 종료됩니다.
툴로 들어가보면 redmine에 관련된 테이블이 수십개 생성되어 있습니다.

3-7. 초기 데이터 입력
초기 설정자료를 아래와 같이 입력하여 생성합니다.
 >set RAILS_ENV=production
 >rake redmine:load_default_data

이 작업은 필수는 아니지만 모든 자료를 처음부터 만들기 어렵기 때문에 되도록이면 실행해 주시는 게 좋습니다.
실행 시 선택한 언어에 따라 다음과 같이 입력창이 뜹니다.
 Select language: bg, bs, ca, cs, da, de, el, en, en-GB, es, eu, fa, fi, fr, gl,
he, hr, hu, id, it, ja, ko, lt, lv, mk, mn, nl, no, pl, pt, pt-BR, ro, ru, sk, sl,
sr, sr-YU, sv, th, tr, uk, vi, zh, zh-TW [en]

엔터를 바로 입력하면 영어(en)이 설정되고 한글을 선택하려면 ko를 입력하면 됩니다.
참고로 이 언어 설정은 redmine의 웹 페이지 언어 설정과는 상관없습니다.
그 부분은 나중에 계정 만들 때 language 설정에서 바꿔주시면 됩니다.

3-8. 실행 및 확인
*nix 계열 OS는 권한 설정 절차가 일부 있지만 Windows는 이제 다 끝났으니 다음과 같이 실행해서 잘 되는지 확인해 보면 됩니다.
 ruby script/server webrick -e production

기본으로 3000번 포트를 사용하므로 처음 실행할 때 ruby 프로그램에 대한 포트 사용 경고가 뜰 수 있으니 허용해 주시고 다음과 같은 메시지가 보이면 완료된 것이므로 웹 브라우저로 확인해 봅니다.
 e:\Program\Redmine-1.3.0>ruby script/server webrick -e production
=> Booting WEBrick
=> Rails 2.3.14 application starting on http://0.0.0.0:3000
=> Call with -d to detach
=> Ctrl-C to shutdown server
[2012-01-02 17:18:29] INFO  WEBrick 1.3.1
[2012-01-02 17:18:29] INFO  ruby 1.8.7 (2011-12-28) [i386-mingw32]
[2012-01-02 17:18:29] INFO  WEBrick::HTTPServer#start: pid=1792 port=3000


http://localhost:3000으로 접근하면 위와 같이 좀 썰렁한 화면이 나타납니다.
기본 관리자 계정인 admin/admin으로 들어가서 개인설정 및 프로젝트 설정 등 필요한 내용을 설정합니다.

이 포스팅의 목적은 우선 설치이므로 프로젝트 등록이나 svn 연결등은 다른 사이트를 참고하시거나 어렵지 않으니 직접 이거저거 만져보면 엔간하면 아실겁니다.
프로젝트 등록되었다고 가정하고 Eclipse와의 연동으로 들어갑니다.

4. Eclipse plugin 설치
Eclipse에서는 이러한 툴들과의 연동을 위해 mylyn이라는 plugin이 이미 존재합니다.
그런데 Eclipse에서 공식적으로 배포하는 mylyn에서는 상용인 jira, 오픈소스인 bugilla와 trac 만 지원이 됩니다.
Connector 추가를 눌러봐도 redmine은 나오지 않는데 아직 개발 초기라 개발 사이트에서만 다운로드 가능한 듯 합니다.
초기단계라 아직 좀 불안전한 부분도 있는데 앞으로 더 나아지길 바랍니다.
여기서는 Eclipse/mylyn까지는 설치된 후부터 진행하겠습니다.

여기를 보면 redmine에서 제공하는 기본적인 mylyn과의 연동에 대한 설명입니다.
generic web repository manager는 거의 대부분의 작업을 eclipse내에 웹브라우저를 띄워서 적용하기 때문에 한계가 좀 있으므로 Eclipse-mylyn connector의 설치에 대해 진행하겠습니다.

4-1. git 설치
git은 svn과 같은 또 하나의 버전관리 시스템인데 좀 다른 점은 분산버전관리 툴이라는 점입니다.
즉, 중앙서버에 접속이 불가능하더라도 작업이 가능한 형태인데 Linux를 만든 것으로 유명한 리누스 토발즈가 원래 Linux Kernel을 개발하기 위해 만든 것인데 현재는 오픈소스 프로젝트들을 중심으로 해서 많이 퍼지고 있는 상황입니다.
최근 몇 년 사이에 오픈소스 버전관리 툴이 CVS->SVN->GIT로 옮겨오는 것 같은 분위기네요..
물론 SVN과 GIT는 분산버전관리라는 점에서 좀 다르긴 합니다만..

여튼 자세한 내용은 아직 저도 잘 모르기 때문에 좀 더 공부하고 따로 포스팅하기로 하고..
(참고로 여기에 보시면 Subversion 사용자를 위한 git 가이드가 있습니다.  영어주의..)
일단 이 프로그램을 받아야 합니다.
여기에 가 보시면 다운로드를 받을 수 있는데 역시 제 취향에 따라 비인스톨 버전인 포터블 버전을 다운로드 받았습니다.
적당한 위치에 풀고 bin 폴더를 경로에 추가해 줍니다.

4-2. Redmine 측 설치
이 플러그인은 통신을 위해 redmine 서버에 설치하는 모듈과 eclipse client에 설치하는 모듈이 나뉘어 있습니다.
git은 redmine 서버모듈 설치를 위한 부분이었으므로 서버쪽 설치를 진행합니다.
redmine이 설치된 위치에서 다음과 같이 실행합니다.
 ruby script/plugin install git://redmin-mylyncon.git.sourceforge.net/gitroot/redmin-mylyncon/redmine-mylyn-connector

만일 재설치를 하려면 install 뒤에 --force를 추가하시면 됩니다.

4-3. Eclipse 측 설치
Eclipse에서는 Help->Install New Software 메뉴를 이용해서 설치합니다.
아래 그림과 같이 http://redmin-mylyncon.sourceforge.net/update-site/N/를 추가하여 인스톨을 진행합니다.

중간에 unsigned conent라면서 경고가 뜹니다만 OK 해서 설치하시기 바랍니다.
(나중에 signing을 해줬으면 하는군요..)


다운로드 및 설치가 끝난 뒤 재시작을 한 다음 Mylyn에서 repository 추가(Add Task Repository)를 해 보면 다음과 같이 redmine이 추가되어 있습니다.

다음 페이지에서 필요한 정보를 입력하고 Validate Settings를 클릭하면 정상적으로 입력했을 경우 Finish가 활성화됩니다.

그런데.. 한 가지 문제가 있습니다.
최신버전을 따라갈 때의 문제인데.. SourceForge의 redmine-mylyn connector 프로젝트의 bugs에 올라온 내용입니다.
원래 해당 plugin은 redmine 1.2.0을 지원하는 버전이어서 1.3.0에서는 undefined method visible_by라는 오류가 발생합니다.
여기에 해당 오류에 대한 설명과 패치를 위한 패치파일이 올라와 있습니다.
controller의 세 파일을 약간씩 수정하면 되는데 patch 파일은 diff 형식으로 되어 있어서 이런 작업을 해 보신 적이 없으신 분들은 부담갈 수가 있을 듯 하여 수정된 파일을 여기에 첨부하니 redmine 홈 위치에서 압축을 바로 풀고 엎어치신 뒤 redmine을 재시작하면 해결이 됩니다.


오픈소스의 고질적인 문제점입니다.
그래서 오픈소스가 상당히 많이 쓰이는 java 쪽에서는 maven 이라는 해결책(?)이 나오기도 했습니다만..
현재 connector 2.7.5 버전에서 발생하는 문제이므로 만일 나중 버전을 쓰신다면 아마 적용되어서 나올 겁니다.



직접 테스트 해 보면서 만드느라 하루종일 걸렸군요..
일단 직접 해 보면서 한 거라 잘 될거라 생각됩니다.
Trac 보다는 그래도 좀 쉽긴 하지만 TOW 같이 ROW 같은거라도 하나 만들어아 할 것 같네요..
:
Posted by hanavy