이번에 프로젝트로 Monitoring System을 개발해 볼까 해서 Eclipse에서는 어찌 DEBUGGING이 되는 건가 했더니.. JVM Level에서 지원되는 거였다는... -.-

몇 년 동안을 자바 개발자라고... DEBUGGING TOOL을 매번 써 왔으면서 왜 이런거에 대한 생각을 해보지 않고 살았을까..

이게 단순 개발자와 Technical Leader의 차이일까..

http://stackoverflow.com/questions/138511/what-are-java-command-line-options-to-set-to-allow-jvm-to-be-remotely-debugged

http://www.eclipsezone.com/eclipse/forums/t53459.html

http://docs.oracle.com/javase/6/docs/technotes/guides/jpda/conninv.html



Posted by headiron
,

이번에 Project를 진행하면서.
Framework에 기본 Property를 넣고..
Project 단위로 Overwrite를 할 수 있는 방법을 찾다 보니 몇 가지 방법이 나왔다.

http://stackoverflow.com/questions/9470551/spring-property-substitution-for-test-and-production

그중에도 context:property-placeholder 에 order 속성을 주어서... property를 읽어 들이는 우선 순위를 정하면 되는데.
order 순서로 파일을 읽어서... 나중에 define 되면 overwrite되는 것을 기대했는데..
overwrite가 되질 않고 처음 읽었던 property가 등록이 된다.

이렇게도 하고 저렇게도 해보고 하다가 하루를 보내고 나니..
Project쪽 order를 낳게 설정하고... Framework에 order를 높게 설정해서..
Project쪽 property를 먼저 읽어 버리게 하면... Project에서 overwrite가 되는 거랑 다를 것이 없지 않은가...

흐.... 아직도 생각이 너무 갇혀 있어서...
쓸데 없는 이슈로 시간을 버린걸 생각하니 너무 어이가 없다.

어쨋든.. 인터넷을 뒤지고 조금 생각을 하게 되면..
해결되지 않는 이슈는 거의 없는듯..

특히나 StackOverflow는 왠만한 질문의 답이 있는 보고이다... :-)


아.. 그리고 overwrite 관련해서 자료를 찾다 보니 context:property-override 도 있는데..
이것은 bean에 설정된 property를 override 하는 기능을 제공한다.
따라서 해당 context에 설정된 bean 이름에 맞추어 property를 설정해 줘야 하지만..
어쨋든 이것도 쓸 수 있는 일이 종종 있을 듯 싶다.




Posted by headiron
,

API 관련 테스팅 프레임워크를 만들면서 json을 출력하게 하는데..
그냥 출력하려니.. 양심에 찔려서 인터넷을 뒤져 봤더니 gson을 이용하면 깔끔하게 출력해 주는 Tip이 있다.

http://stackoverflow.com/questions/8596161/json-string-tidy-formatter-for-java

JsonParser parser = new JsonParser();
Gson gson = new GsonBuilder().setPrettyPrinting().create();

JsonElement el = parser.parse(jsonString);
jsonString = gson.toJson(el);
위와 같이 간단히 해결하고 한동한 있고 있었는데.
오늘 독일팀이 잘 쓰고 있는데 좀 문제가 있네 하면서 보내준 내용을 보니
json 리턴 값에 HTML 태그랑, JavaScript가 있어서 출력값이 깨져서 나오게 된다.

흐미... 내가 왜 HTML이 포함될 수 있다는 걸 까먹고 있었는감...-.-
어쨋든 뭐...JSON 결과를 HTML escaping하면 간단히 해결되지 않을까 싶었는데..
테스트 해보니. JSON 내의 " 까지도 escaping이 되버리는 바람에 formatting 한게 물거품이 되어 버리고 만다.-.-
( formattting 한후 <pre></pre> 태그를 앞 뒤로 붙여 formatting한 결과를 보여 주어서...)

이런 저런 생각을 계속 하다 보니 결국 방법은 JSON 데이터를 Parsing 한 후 Field 를 Traversing 하며 출력해 주면서 Field 값이 문자열일 경우에 HTML escaping을 하면 될 것 같다.

마침 다른 이슈로 recursive 하게 json traversing하는 로직을 만들어 놓은 게 있어서 사용을 했더니 결국 HTML escaping이 깔끔하게 해결되었다.

public String getPrettyHtmlJson(String content){
try {
Object jsonContent = JSONParser.parseJSON(content);
return "<pre>"+getPrettyHtmlJsonElement(jsonContent, 0,false)+"</pre>";

} catch (JSONException e) {
e.printStackTrace();
return content;
}
}

private String getPrettyHtmlJsonElement(Object object, int indent, boolean indentNeed) throws JSONException{
String content = "";
if ( object instanceof JSONArray){
JSONArray jsonArray = (JSONArray) object;
if ( indentNeed)
for(int i = 0; i < indent; i++) content+=" ";
content+= "[ \n";
for(int j = 0; j < jsonArray.length(); j++){
if ( j > 0 ) {
content+=", \n";
//for(int i = 0; i < indent; i++) content+=" ";
}
content += getPrettyHtmlJsonElement(jsonArray.get(j), indent+1, true);
}
content += "\n";
for(int i = 0; i < indent; i++) content+=" ";
content+= "]";
return content;
}
else if ( object instanceof JSONObject){
if ( indentNeed)
for(int i = 0; i < indent; i++) content+=" ";
content+= "{\n";
JSONObject jsonObject = (JSONObject) object;
String[] names = JSONObject.getNames(jsonObject);
for(int j =0 ; j < names.length; j++){
String name = names[j];
for(int i = 0; i <= indent; i++) content+=" ";
content+= "\""+name+"\" :";
Object fieldObject = jsonObject.get(name);
if ( fieldObject instanceof JSONArray)
content += getPrettyHtmlJsonElement(fieldObject, indent+1, false);
else if ( fieldObject instanceof JSONObject)
content += getPrettyHtmlJsonElement(fieldObject, indent+1, false);
else if ( fieldObject instanceof String){
content += "\""+StringEscapeUtils.escapeHtml4(fieldObject.toString())+"\"";
}
else
content += "\""+fieldObject.toString()+"\"";
if ( j + 1 < names.length )
content += ",";
content +=" \n";
}
for(int i = 0; i < indent; i++) content+=" ";
content+= "}";
return content;
}
else{
for(int i = 0; i < indent; i++) content+=" ";
content+= "\""+object.toString()+"\"";
return content;
}
}

잘 되었네.. 하고 접을 까 싶었더니...
Field 순서가 뒤죽 박죽이다.
구글링을 해보니.. JSON은 순서를 보장하지 않는 필드 List라는 문구가 나온다.
흐... 그래서 field ignore 시킬 때 JSON Parsing을 하면 순서가 뒤바뀌어서 나왔었구나...

뭐.. 순서가 바뀌어 출력되도 스펙 내용에 따르면 별 문제는 없는데..
그래도 개발의 양심이라는 것이...
결국은 좀더 조사해보니...
JSONObject map을 HashMap에서 LinkedHashMap으로 바꾸면 해결 된다고 한다.

http://stackoverflow.com/questions/4515676/keep-the-order-of-the-json-keys-during-json-conversion-to-csv

마침...
J
son Assert가 org.json.* 구조를 이용하는데.. 이 library는 마침 JSON.org에서 다운 받은 jar를 사용하고 있어서..
source를 받아서 위에 얘기한 대로 LinkedHashMap으로 바꾸고 나니 문제점 깔끔하게 해결...

덕분에 field ignore 할 때도 필드 순서 보장하게 되고...
HTML escapaing 문제도 해결하고 ... formatting때문에 사용한 gson library도 빼고...

골치아픈 HTML escaping 이슈가 오히려 전화위복이 되어 더 깔끔한 프레임웤이 완성되었다.


Posted by headiron
,
WSDL2Java로 나온 Class들 전체를 javac로 실행하다 보니 out of memory가 발생한다.

구글링을 해보니 두가지 방법이 보인다.

1. javac Task에 fork="true" memoryMaximumSize="512M" 을 주는 방법
  ( fork를 기재 하지 않을 경우 memoryMaximumSize Option은 ignore 된다. )

2. javac Task에 compilerarg option을 준다.
    javac -help를 입력할 경우 javac 입력시 사용할 수 있는 Option이 나오게 되며 이 중 적절한 option을 입력하면 된다.
<javac srcdir="gen" destdir="gen-bin" debug="on" fork="true">
   
<compilerarg value="-J-Xmx512M" />
</javac>

   ( command prompt 내에서는 -J-Xmx를 입력할 경우 java stack size를 입력할 수 있는 걸로 나오는데 eclipse 의 ant plugin 에서는 해당 option이 먹지 않는걸로 나온다. )
참고 URL : http://stackoverflow.com/questions/16935/ants-javac-tasks-throws-stackoverflowexception
http://blog.paran.com/rabbitshin/6134979
Posted by headiron
,

여지껏 singleton 이외에 다른 scope의 bean을 사용할 일이 없었는데

B3 Tool을 개발하며 필요하게 되었다.

ApiAdaptor의 생성 overhead를 줄이기 위해 spring에 singleton 으로 생성을 했는데

서로 다른 account에 대해 동시에 ApiAdaptor bean을 사용하게 될 경우에 문제가 생길 가능성이 있었다.

방법은 bean에 config 객체를 set 하는 순간 부터 해당 bean을 synchronize 시키는 방법이 있을 수 있었다.

하지만 언제나 synchonize를 시키는 방법은 여러 문제를 발생 시킬 수 있다.

다른 방법을 생각해 보았는데

민차장님이 회의 들어갔다 나온 사이에 session bean을 사용하는 방법을 찾아 주셨다.


spring 2.0 이상 부터 제공되는 session bean 객체를 이용하는데 

config 를 session scope로 선언하고 aop:proxy를 선언한 후 이를 adaptor의 property로 injection을 하게 되면 config 객체가 사용될 때 마다 proxy 기능에 의해 session scope의 객체가 사용되게 된다.

이를 위해서는


<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:p="http://www.springframework.org/schema/p"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns:aop="http://www.springframework.org/schema/aop"  
  xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/aop
       http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">

 <!-- API Adaptor Object -->
 <bean id="loginConfig"
  class="com.tfsm.apis.oas.config.OasApiConfig" scope="session" >
  <aop:scoped-proxy/>
 </bean>
 <bean id="campaignProxy"
  class="com.tfsm.apis.oas.proxy.implementation.CampaignProxyBean" >
  <property name="oasConfig" ref="loginConfig"/>
 </bean>
</beans>

이를 위해서는 cglib library가 추가로 필요하며
loginConfig가 interface 기반으로 개발되었을 경우 
 <bean id="loginConfig"
  class="interface명" scope="session" >
  <aop:scoped-proxy proxy-target-class="false"/>
 </bean>
로 선언하게 되면 cglib를 사용하지 않게 된다.

이때 web.xml에는 

<listener>
                <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

이외에
<listener>
       <listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
</listener>      
도 추가 되어야 한다.

http://static.springframework.org/spring/docs/2.5.x/reference/beans.html#beans-factory-scopes

추가로 spring만 사용했을 경우에는 session scope를 사용하는데 큰 문제가 생기지 않으나
zk framework에서 session  scope bean을 사용하게 될 경우

zk.xml 파일에

    <listener>
            <description>ThreadLocal Synchronization Listener</description>
            <listener-class>org.zkoss.zkplus.util.ThreadLocalListener</listener-class>
    </listener>

 <preference>
  <name>ThreadLocal</name>
  <value>
   org.springframework.web.context.request.RequestContextHolder=requestAttributesHolder,inheritableRequestAttributesHolder;
  </value>
 </preference>
를 추가 하여야 한다.

http://forum.springsource.org/archive/index.php/t-50631.html
http://www.zkoss.org/javadoc/3.0.3/zkplus/org/zkoss/zkplus/util/ThreadLocalListener.html

Posted by headiron
,

ZUL 파일의 시작 부분에 아래의 문구를 일단 추가...

<?xml version="1.0" encoding="UTF-8"?>
<?init class="org.zkoss.zkplus.databind.AnnotateDataBinderInit" ?>


아래와 같이 input component의 value에 연동할 객체 Handler를 기입
<textbox id="flightName" maxlength="10" value="@{win.flight.flightName}"/>

이렇게 하면 input component에서 작성하는 데이터 ( 지금의 경우 flightName )  의 수정 사항이 객체에 ( 이 경우 win.getFlight().getFlightName()) 자동으로 적용된다.

ZK Design한 사람들이 이 부분은 상당히 잘 생각한 듯 하다.
Posted by headiron
,
B3 Tool POC 하며 ZK SpreadSheet을 사용하게 되었다.

Web화면에 Excel U.I를 띄워 주니 입력 항목이 많은 경우에는 큰 도움이 될 듯 하다.

다만 U.I가 좀 느려서 빠른 화면 전환할 경우에 문제가 생길 수는 있을 것 같다.

ComboBox를 사용할 필요가 있어 ComboBox U.I를 체크해 보았는데

POI나 jExcel 내부에는 constraint를 이용하여 처리해 주고 있는데

SpreadSheet에서는 이 부분을 지원해 주지 않아 조금 아쉽다.


ZK의 다른 Component처럼 Cell에 객체를 mapping하여 Editing 결과를 자동으로 객체에 적용하려고 했는데 ,

객체 Mapping 정보를 Excel의 수식으로 적용하기 때문에 Editing시 해당 Mapping 정보가 날라 가는 현상이 있어 이 부분은 적용하기 어려웠다.

결국 POI 처럼 Cell 단위로 입력값 읽어 오도록 일단 처리 하였다.


필요 library를 보면 jExcel을 사용하는것 같은데.. ZK의 ext library에 이미 poi library가 있는데 굳이 jExcel을 사용하나 싶다.

어쩌면 POI 에서 처리못하는 부분을 jExcel에서는 지원하기 때문에 jExcel을 사용하는거 아닐까 하는 생각도 ....


예전에는 OCX로나 구현할 수 있었던 U.I를 library로 비교적 쉽게 구현할 수 있어 좋기는 한데..

우째 또 다른 짐을 지게 되는것 같아 가슴 한편이 좀 무겁기도 하다...-.-

Posted by headiron
,
B3 쪽을 위한 Report Crawler를 만들면서

몇개의 파일 읽어 오는 것을 구현해야 하는데 해당 파일 정보를 properties에 넣을 려고 하니 너무 설정이 많아 지는 듯 하여 ClassPath에 있는 파일을 읽어 오는 방법을 찾다 보니 Solution이 있다.

( Spring이나 Struts 같은 데서 ClassPath에 있는 파일 읽어 오는 것을 보고 어떻게 한건가 했는데 이거 였구나 하는 생각이.^^ )

1.String filePath = Thread.currentThread().getContextClassLoader().getResource("/script/xxx.sh").getFile();
2.String filePath = getClass().getClassLoader().getResource("/script/xxx.sh").getFile();
3.String filePath = getClass().getResource("/script/xxx.sh").getFile();

처음에는 3번으로 개발했는데 Window / linux에서는 잘 되던게 Mac 에 올렸더니 NullPointer Exception이 발생했다.

결국 정팀장님이 1번 형태로 바꾸셨는데 송과장님 Mac에서는 또 1,3번 모두 다 잘 된다...

Internet을 Survey해보니 2,3번 형태를 비교해서 2번은 되는데 3번은 NullPointerException 나오는 경우에 대한 Article도 찾았다.

결국 1 번 혹은 2번 형태로 작성하는 것이 제일 안전한 방법으로 보인다.

'개발자세상 > 자바세상' 카테고리의 다른 글

ZK에서 Input Component와 객체간 Binding  (0) 2009.04.16
ZK에서 Spreadsheet 사용기  (0) 2009.04.16
JavaFX?  (0) 2009.02.03
Process class 사용시 주의점  (0) 2008.11.07
JVMPI, JVMTI  (0) 2008.07.30
Posted by headiron
,
지난번에 신상철 박사의 온라인강의 시도하다 다 실패하고 이번에 JavaFX 신청해서 Lesson 1을 보았다.

다들 JavaFx에 대해서 호의적인 의견이 많은데...

과연 성공할 수 있을지...

1.우선 지금 JavaFx를 실행할려면 Client Site에서 Jdk(혹은 Jre) 1.6 u 10 이상이 깔려 있어야 한다.

일반 유저들이 Flash는 많이 깔려 있어도 Jre 가 깔려 있기는...

물론 자동 다운 로드 기능이 된다면 좋지만..

Flash 처럼 가볍게 깔리지 않는 이상은 일반 사용자들은 다운로드를 닫아 버리기 쉬울 듯하다.

2. 문법이 난해하다.

사실 프로그램 초심자들에게는 쉬울 수 있다.

하지만 Java Programing에 익숙한 개발자들에게는 Script 형식의 언어 스타일이 어려울 수 있을 듯 하다.

( 하기는 요즘 Ruby 등 script 형태의 언어도 Java에서 지원되는데...-.- )

JavaFx가 Flex나 Silverlight 보다 강점을 가진다고 하는 부분중에 하나가 Java Friendly 함인데

이런 식이라면 Flex가 더 좋을 지도 모르겠다.

3. 개발자 중심이다.

개발자들이 함께 Co-work하는 디자이너들이 쉽게 JavaFx에 접근 할 수 있어야 한다.

PPT를 보니 Sun에서도 이를 인지 했는지 디자이너 Tool에 설치하기 위한 PlugIn을 개발해 놓은 듯 하다.

과연 디자이너들에게 어느정도 어필할 지는 두고 봐야 할 일 일듯하다.

4. One-Source , multi platform?

UI AddOn 개발시 ZK Framework을 쓰면서 겪었던 문제점은

Framework 자체적으로 Web , Mobile을 지원하다가 보니 

Dual Client에 공통적인 기능 제공을 위해

JavaScript나 DHTML의 고급 기능 등을 구현해주기 어려운 것을 보았다.

결국은 어떻게든 방법을 찾아서 그 부분을 구현해 주었지만

그 순간 부터 one-source , multi client platform 원칙은 깨지는다는 느낌이었다.

JavaFx에 대해서도 같은 걱정이 든다.

특히 Dynamic 한것을 좋아 하는 사용자들에게 이 부분을 어떻게 설득할 수 있을 지 모르겠다.


물론 너무 부정적인 부분만 있는 것은 아니다.

특히 봄(여름이었나.. ) 에 나온다는 TV client 부분은 기대가 많이 된다.

아마도 요즘 Issue가 되는 IPTV 도 포함시키지 않을 까 기대가 된다.

( 사실 요즘 IPTV가 개인적인 관심분야이기도 하고... 밥 벌어 먹을라면 이 부분도 Study가 필요하다는 생각이 들기도 하고..-.- )


어쨋든 나의 걱정이 기우였으면 한다.

베스킨라빈스 31 에서 큰 컵에 다양한 아이스크림 선택해 놓고선 제일 위에 하나 맛보고
다 맛없다는 우를 범하는 것이기를 바란다.

'개발자세상 > 자바세상' 카테고리의 다른 글

ZK에서 Spreadsheet 사용기  (0) 2009.04.16
ClassPath에 있는 파일 가져오기.  (0) 2009.03.18
Process class 사용시 주의점  (0) 2008.11.07
JVMPI, JVMTI  (0) 2008.07.30
Java One 2008 방문 후기를 보고  (0) 2008.06.26
Posted by headiron
,
이번에 RMF Patch Program 을 작성하면서

Shell의 Output을 Java로 읽어 들이는 Program을 작성하게 되었다.

마침 예전 테라스때 Keytool을 이용한 인증서 저장 프로그램을 짜면서

Java내에 인증서를 핸들링하는 Class가 없어서 Shell command를 이용하도록 하던 Code를 작성한 경험이 있어서 손 쉽게 접근할 수 있었다.

근데 막판에 부하테스트 하면서 예상하지 못했던 Issue가 발생했다.

shell 쪽에서 해야 할 일이

find 로 특정 이름의 파일을 찾아 그 결과를 이용하여 java class가 구동되어야 하는데

처음에 데이터가 작을 때는 잘 작동 되던 것이

데이터가 많아 지니 멈추는 현상이 발생했다.

코드는 아래와 같은 식이 었는데

정확히 어디 쯤에서 멈추는지 까지는 Tracing 하지는 않았지만

아마도 prss.waitFor 구문에서 나오는거 아닐까 하는 생각이 든다.

일단은 sun community에 질문을 올려 놓기는 했는데

어떤 답이 올지 모르겠다.

http://forums.sun.com/thread.jspa?threadID=5345804

아참 글구 이런 문제가 생겼던 근본적인 문제점은...

find . -name XXX -print > b.txt

를 Runtime & Process를 이용해서 구혔했었는데

이때 Redirect 가 처리가 되지 않아서 에러가 발생했었다.

결국 Redirect를 쓰지 않고 하려다 보니 stdout을 받아서 처리 하려 했던 것이다.

( 해결은 find option 중에 -fpint를 쓰게 되면 redirect를 쓰지 않고도 파일로 결과를 저장할 수 있었다. )

Runtime rn = Runtime.getRuntime();
Process prss = rn.exec(command);

InputStream stderr = prss.getErrorStream();
InputStreamReader isr = new InputStreamReader(stderr);
BufferedReader br = new BufferedReader(isr);
String line = null;
StringBuffer errmsg = new StringBuffer();
while ( (line = br.readLine()) != null)
errmsg.append(line);

InputStream stdout = prss.getInputStream();
InputStreamReader isr2 = new InputStreamReader(stdout);
BufferedReader br2 = new BufferedReader(isr2);
List<String> outmsg = new ArrayList<String>();
String line2 = null;
while( ( line2 = br2.readLine() )!= null)
outmsg.add(line2);

int prss_rslt = prss.waitFor();
if ( prss_rslt != 0 ){

throw new Exception(account+ "'s creative file touch is fail. it return "prss_rslt"error code.\n"+errmsg.toString());

}

'개발자세상 > 자바세상' 카테고리의 다른 글

ClassPath에 있는 파일 가져오기.  (0) 2009.03.18
JavaFX?  (0) 2009.02.03
JVMPI, JVMTI  (0) 2008.07.30
Java One 2008 방문 후기를 보고  (0) 2008.06.26
BPM에 빠져 들다.  (0) 2007.07.11
Posted by headiron
,