DateTimeFormatter 사용할 때 파싱하려는 문자열의 Locale 정보도 꼭 주는게 좋다.

다음과 같이 DateTimeFormatter를 사용해서 “6:55 AM”이라는 문자열을 LocalTime으로 파싱하려고 한다.

@Test
public void testParsingTime() {
    String time = "6:55 AM";
    LocalTime localTime = LocalTime.parse(time, DateTimeFormatter.ofPattern("h:mm a"));
    assertThat(localTime.getHour(), is(6));
    assertThat(localTime.getMinute(), is(55));
}

코드에는 별로 크게 이상한 점이 보이지 않는다. 파싱하는 패턴이 올바른지 궁금하다면 샘플 데이터를 몇가지 더 살펴볼 수 있는데, 지금 내가 파싱하려는 데이터는 이런식이다.

7:15 AM, 8:00 AM, 11:05 AM, 1:00 PM, 1:35 PM

시간은 두자리를 꼭 채우지는 않기 때문에 h 하나만 사용하면 되고 시간과 분은 콜론(:)으로 구분하고 다음에 분은 두자리를 꼭 지키고 있기 때문에 mm을 사용했다.
마지막에 스페이스를 하나 띄고나서 a로 AM, PM을 파싱하고자 한다. 딱히 틀린건 없다고 생각했는데 막상 실행하면 에러가 난다.

java.time.format.DateTimeParseException: Text '6:55 AM' could not be parsed at index 5
    at java.time.format.DateTimeFormatter.parseResolved0(DateTimeFormatter.java:1947)
    at java.time.format.DateTimeFormatter.parse(DateTimeFormatter.java:1849)
    at java.time.LocalTime.parse(LocalTime.java:441)
    at me.whiteship.domain.ShuttleTest.testParsingTime(ShuttleTest.java:20)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
    at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
    at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:78)
    at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:212)
    at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:68)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:140)

이 에러를 해결하려면 Locale 정보를 추가해야 한다.

@Test
public void testParsingTime() {
    String time = "6:55 AM";
    LocalTime localTime = LocalTime.parse(time, DateTimeFormatter.ofPattern("h:mm a")
            .withLocale(Locale.ENGLISH)); // without Locale an exception may occur.
    assertThat(localTime.getHour(), is(6));
    assertThat(localTime.getMinute(), is(55));
}

현재 내가 작업중인 개발 환경의 JVM 환결 설정에 Locale 정보다 아마도 KOREA로 되어있는것 같다. 그래서 그 기본값에 따라 AM, PM 정보를 파싱하려는데, 한국어로는 그게 “오전”, “오후”로 표기하니까 AM, PM 정보를 파싱할 수 없어서 에러가 발생한 것이고, 데이터가 영어니까 영문 Locale로 파싱하도록 수정한 코드는 잘 실행된다.

자바스크립트 match 함수를 자바로?

자바스크립트 match 함수는 String에 있는데 정규식에 대응하는 문자열 배열을 리턴해 주는 함수입니다. 매우 편하죠.

http://www.w3schools.com/jsref/jsref_match.asp

그런데 자바에는 그런게 없어요. String 클래스에 비슷해 보이는 메서드가 split이랑 match가 있는데 다 원하던게 아니에요. 자바스크립트 match랑 비슷한걸 만들려면 Patttern이랑 Matcher를 써야하는데… 그 둘을 써도 코드가 간단하질 않아요. 그래서 유틸을 만들었는데.. 자바 String이나 Matcher에 기본으로 들어갔으면 좋겠습니다.

아 귀찮게 이게 뭔짓인지… 제 모든 감정은 gist 제목에 써놨습니다.

테스트도 했어요.

[자바 퍼포먼스] 2장 운영체제 퍼포먼스 모니터링, 용어 정의

퍼포먼스 모니터링

Performance monitoring is an act of nonintrusively collecting or observing per- formance data from an operating or running application.

퍼포먼스 프로파일링

Performance profiling in contrast to performance monitoring is an act of col- lecting performance data from an operating or running application that may be intrusive on application responsiveness or throughput.

퍼포먼스 튜닝

Performance tuning, in contrast to performance monitoring and perfor- mance profiling, is an act of changing tune-ables, source code, or configura- tion attribute(s) for the purposes of improving application responsiveness or throughput.

그러니깐.. 모니터링으로 성능 문제를 인지하면, 프로파일링을해서 원인을 찾고, 튜닝으로 해결한다. 용어에 대한 정의를 서로 잘 공유하면 대화하기가 편할텐데.. 모니터링/프로파일링은 좀 햇갈렸었는데 이렇게 구분하면 되겠군.

[자바 퍼포먼스] 1장 전략, 접근방법, 방법론

  • “애플리케이션에서 기대하는 throughput은 어느 정도인가?”
  • “기대하는 요청-응답 latency는 어느 정도인가?”
  • “얼마나 많은 동접자 또는 동시 작업을 지원해야하는가?”
  • “최대 동접자 또는 동시 작업 중일 때 수용할 수 있는 throughput과 latency는 어느 정도인가?”
  • “가장 최악의 경우 latency는?”
  • “감당할 수 있는 수준의 latency 내에서 GC 주기는?”

이런 질문으로 지표를 정해야 할텐데… 고객이 이런걸 알 수가 있나? 그냥 측정부터 해보는게 좋겠어.

나머지는 그냥 전통적인 (폭포식) 소프트웨어 개발 프로세스에 성능 테스트랑 프로파일을 추가해서 분석, 설계, 코딩에 그 결과를 반영해서 다시 또 개발 프로세스가 돌고 돌고 돌고 하도록 그림을 그린 Wilson & Kesselman의 성능 프로세스라는 그림을 소개하고 있다.

다음으로는 하향식 방법과 상향식 방법을 설명하고 있다. 하향식은 애플리케이션 모니터링부터 시작한다. OS 시스템 모니터링, JVM 모니터링, JEE 서버 모니터링 등을 수행한 뒤 모니터링 정보를 바탕으로 JVM 커맨드 라인 옵션을 튜닝하거나, OS를 튜닝하거나, 애플리케이션을 프로파일링 한다. 프로파일링을 하면 코드가 더 효율적인 구현방식으로 바뀌거나, 비효율적인 라이브러리를 교체하는 등의 작업을 할 수도 있다.

상향식은 아주 밑바닥인 CPU 아키텍처, CPU 갯수등을 분석하는 것부터 시작한다. 아… 이 부분은 너무 로우 레벨이라.. 아흑.. path length니, CPU cache miss니.. @_@ 패스.

나머지도 패스.

 

[Servlet 3.0 Asynchronous Support] 비동기 서블릿

쉽지 않다. 일단 배경 자체가 매우 긴데…

http://www.javaworld.com/javaworld/jw-02-2009/jw-02-servlet3.html

이 글에서 배경을 잘 설명하고 있다.

HTTP 1.0과 HTTP 1.1의 차이점부터 시작해서, Thread per connection을 설명하고, page-by-page 방식에서 커넥션 쓰레드가 지연상태로 있기 마련인지라, JDK 1.4에 추가된 NIO를 사용해서 놀아도 되는 커넥션 쓰레드를 회수하여 새로운 요청을 처리할 용도로 사용하도록 되었다고 한다. 그러다, Ajax의 등장으로 page 당 요청수가 급증하게되고, 그 중에서도 느리고 제한적인 자원에 접근하는 요청일 경우에는 처리용 쓰레드가 대기하는 상황이 자주 발생하게 됐다. 그래서 등장한 것이 바로 Servlet 3.0의 비동기 기능이다. 대기해야 하는 리소스를 요청한 상태에서 처리용 쓰레드를 계속 대기 상태로 유지(동기)하는게 아니라, 처리용 쓰레드는 대기해야 하는 리소스를 요청하고 회수했다가, 리소스가 다시 가용해졌을 때 처리를 이어가게 해주는 것이다. 이렇게되면, 가만히 기다리느라 멍때리고 있던 리소스를 다른 작업 처리하는데 사용할 수 있으니 훨씬 효율적이라서, 잘하면 처리량이 올라갈 수도 있겠다.

결국 DB로 쏠릴것이다. 지금도 성능의 대부분은 DB에서 먹히는 거라고 하지만, 그걸 뭘 어째겠는가. 그 앞에 캐시를 둬서 잘 운영하거나, DB 자체를 좀 더 효율적으로 활용하는 방법을 찾거나, 그건 또 다른 문제니까 논외로 패스.

어쨌거나, 지금까지 배경을 살펴보면 대충 이런것 같다.

  • 일단 두 종류의 자원이 있다. 하나는 커넥션용. 하나는 처리용.
  • 커넥션용 자원은 이미 여러 서블릿 컨테이너가 NIO를 사용해서 효율적으로 작업해 뒀기 때문에 개발자가 신경쓰지 않아도 됨. – “Today, popular Web servers — including Tomcat, Jetty, GlassFish (Grizzly), WebLogic, and WebSphere — all use thread per request through Java NIO.”
  • 처리용 쓰레드는 DB 요청이나, 웹 서비스 요청을 했을 때 대기하게 되는데, 이건 서블릿 3.0의 비동기 기능을 활용해서 절약할 방법이 생김. (어느정도 효과가 있을지는 모르겠음.)

하지만, 이 글에서 보여주는 예제는 ServletContextListener와 조합하고 있는데, 그리 깔끔해 보이는 예제는 아니었다.

http://blogs.oracle.com/enterprisetechtips/entry/asynchronous_support_in_servlet_3

다음으로 읽은 글인데, 비교적 깔끔한 예제와 설명을 제공한다. 그런데 저기 있는 예제 코드처럼 요청이 올때마다 new ThreadPoolExecutor(10)를 생성하는 건 매우 위험해보이고, 쓰레드 풀을 스프링에 빈으로 등록해두고 쓰는게 좋겠다. 스프링 @Async 기능 관련해서 무슨 클래스 이름이 있었는데 잊어버렸다. @_@; 머더라.. 뭔 Factory였는데.. 또 패스.

그치만 저 글로는 AsyncContext, AsyncListener의 주요 기능을 파악하기는 어려웠다. API를 읽어본다고 크게 도움이 되지도 않고, 언제 이 메서드를 사용해야 하는 것인지 알아야 할텐데..

http://jcp.org/en/jsr/detail?id=315

그래서 스펙을 열어봤다. 스펙 문서는 서블릿의 모든것이 설명되어 있는 필독 문서인데, 난 아직 전부다 읽어본적은 없다. 이번 기회에 한번 다 읽어볼까 싶기도 하고… 어쨋든 이 문서에서 비동기 관련 내용이 잘 설명되어 있다. 2.3.3.3을 보면 된다. 사실 나도 아직 다 읽은건 아니라서.. @_@ 일단 링크 정리하면서 요약하려고 적기 시작한거라. 나중에 레퍼런스를 요약해서 정리해야겠다. 서블릿 3.0 부셔버리겠어!!

http://weblogs.java.net/blog/mode/servlet3.0/servlet3.0-javaone09.pdf

마지막으로 전체적으로 훑어보기 좋은 PDF 문서가 있다. 여기 그림과 코드가 주옥같다. 발표 영상도 구할 수 있으면 좋겠지만, 귀찮아서 찾아보진 않았다.

예제를 하나 만들어 보고 슬슬 자야겠다. 벌써 12시 30분을 향해가는구나. 간단한 웹 서비스 요청을 한다고 가정해보자. 야후 주식 API를 호출해서 여러 주가 정보를 받아와야 한다고 가정해보자.

여기서 사용한 야후 주시 정보는 스프링 RestTemplate응 이용했다.

이렇게 짜봤는데… 흠.. 뭔가 좀… 응답이 한방에 오는게 어째 좀 찝찝하다. 응답이 조각 조각 와야 하는거 아닌가. 크롬 인스펙터로 보면 응답 Transper-Encoding: chuncked 이긴한데.. 내가 원한건, Start가 먼저 응답으로 오고, 그 다음에 주식 정보가 다시 응답 조각으로 와서 완료되는 것인데.. 흠.. 디스패치를 이용해야되나.. 아. 찝찝한데 시간은 벌써 1시 반이 넘었고… 자야겠다. 젠장.. OTL…

서블릿 레퍼런스랑 자바 컨커런시 프로그래밍 좀 잘 봐야겠다.

출근길에 Dispatch를 사용하도록 코드를 변경해봤다.

이번에도 내가 원하는대로 되진 않았다. 일단 브라우저에는 Start만 보내고, 그 다음 리모트 호출이 완료된 다음 주가 정보를 출력하는 것이 내가 원하는 결과였는데.. 흠.. 화면단에서 자바스크립트로 코딩이 들어가야 하는걸까? 화면단 코딩을 하지 않더라도, 적어도 크롭 인스펙터에 두줄로 나와야 하는거 아닐까나.. 흠;; 모르겠군;