I made a encoder/decoder can be uploaded to web application server by mina 2.0
It is difficult to manipulate byte stream in mina, because I could not estimate how many bytes sent.
So, the encoder just send file bytes stream, and meta-information.
The docoder stack the stream untile output of stream is end, process it.
If you are first in mina, its examples are useful.

Encoder

public class ImageUploadRequestEncoder extends ProtocolEncoderAdapter  {
 private static final Log log = LogFactory.getLog(ImageUploadRequestDecoder.class);
 
 private CharsetEncoder encoder;
 public ImageUploadRequestEncoder() {
  Charset charset = Charset.forName("UTF-8");
     encoder = charset.newEncoder();
 }
 
 @Override
 public void encode(IoSession session, Object obj, ProtocolEncoderOutput out) throws Exception {
  ImageUploadRequestData data = (ImageUploadRequestData) obj;
  
  IoBuffer buffer = IoBuffer.allocate(1, false);
     buffer.setAutoExpand(true);
    
     int StringLength = ImageUploadCodecFactory.DELIMITER.length() * 5 +
  data.getId().length() + data.getCompanyID().length() + data.getFromFileName().length() +
  data.getToDirName().length() + data.getPureFileName().length() + data.getPhase().name().length();
     int totalLength = 4 + data.getByteStreamLength() + 4 + StringLength;
     log.debug("total length : " + totalLength);
     buffer.putInt(totalLength);
     buffer.putInt(data.getByteStreamLength());
    
     buffer.put(data.getByteStream());
     buffer.putInt(StringLength);
     buffer.putString(data.getId(), encoder);
     buffer.putString(ImageUploadCodecFactory.DELIMITER, encoder);
     buffer.putString(data.getCompanyID(), encoder);
     buffer.putString(ImageUploadCodecFactory.DELIMITER, encoder);
     buffer.putString(data.getFromFileName(), encoder);
     buffer.putString(ImageUploadCodecFactory.DELIMITER, encoder);
     buffer.putString(data.getPureFileName(), encoder);
     buffer.putString(ImageUploadCodecFactory.DELIMITER, encoder);
     buffer.putString(data.getToDirName(), encoder);
     buffer.putString(ImageUploadCodecFactory.DELIMITER, encoder);
     buffer.putString(data.getPhase().name(), encoder);
     buffer.flip();
        out.write(buffer);
 }
 
}


Decoder


public class ImageUploadRequestDecoder extends CumulativeProtocolDecoder {
 private static final Log log = LogFactory.getLog(ImageUploadRequestDecoder.class);
 private static final int MIN_READ_LENGTH = 4;
 public static final int MAX_SIZE = 1024 * 1024 * 100;
 private IoBuffer savedBuffer = IoBuffer.allocate(4096, true);
 private int remainLength = 0;
 public ImageUploadRequestDecoder() {
  savedBuffer.setAutoExpand(true);
 }
 private boolean isFirst = false;
 @Override
 protected boolean doDecode(IoSession session, IoBuffer in, ProtocolDecoderOutput out) throws Exception {
  if (isDecodable(session, in) == MessageDecoderResult.NEED_DATA) {
   return false;
  }
  if (isFirst == false) {
   int byteStreamLength = getStreamLength(in);
   log.debug("byteStreamLength : " + byteStreamLength);
   if (byteStreamLength <= 0) {
    throw new IOException("Total length of file is negative : " + byteStreamLength);
   } else if (byteStreamLength >= MAX_SIZE) {
    log.warn("Total length of file is so big to receive : " + byteStreamLength);
   }
   log.debug("in.remaining() : " + in.remaining());
   if (in.remaining() == byteStreamLength) {
    savedBuffer.put(in);
    savedBuffer.flip();
    decodeBody(session, out);
    reset();
   } else { // not yet received
    isFirst = true;
    remainLength = byteStreamLength - in.remaining();
    savedBuffer.put(in);
    log.debug("not yet received");
   }
   return true;
  }
  int readableSize = remainLength - in.remaining();
  if (readableSize == 0) { // all received.
   savedBuffer.put(in);
   savedBuffer.flip();
   decodeBody(session, out);
   reset();
  } else { // more received.W
   isFirst = true;
   remainLength = remainLength - in.remaining();
   savedBuffer.put(in);
  }
  return true;
 }
 private void reset() {
  savedBuffer.clear();
  remainLength = 0;
  isFirst = false;
 }
 private void decodeBody(IoSession session, ProtocolDecoderOutput out) throws IOException {
  PushbackInputStream stream = new PushbackInputStream(savedBuffer.asInputStream(), savedBuffer.remaining());
  byte[] sizeArray = new byte[4];
  if (stream.read(sizeArray, 0, 4) < 0) {
   throw new IOException("wrong bytes transmitted.");
  }
  int size = byteArrayToInt(sizeArray);
  byte[] byteStream = new byte[size];
  int datasize = stream.read(byteStream, 0, size);
  ImageUploadRequestData data = new ImageUploadRequestData();
  data.setByteStream(byteStream);
  data.setByteStreamLength(datasize);
  sizeArray = new byte[4];
  datasize = stream.read(sizeArray, 0, 4);
  int StringLength = byteArrayToInt(sizeArray);
  byte[] strStream = new byte[StringLength];
  datasize = stream.read(strStream, 0, StringLength);
  String s = new String(strStream, "UTF-8");
  StringTokenizer tokenizer = new StringTokenizer(s, ImageUploadCodecFactory.DELIMITER);
  int i = 0;
  while (tokenizer.hasMoreTokens()) {
   // id : 1256117865031||KR12662||d:\a.txt||a.txt||e:\vuscript
   String token = tokenizer.nextToken();
   if (i == 0) {
    data.setId(token);
    ;
   } else if (i == 1) {
    data.setCompanyID(token);
    ;
   } else if (i == 2) {
    data.setFromFileName(token);
   } else if (i == 3) {
    data.setPureFileName(token);
   } else if (i == 4) {
    data.setToDirName(token);
   } else if (i == 5) {
    if (token.equals("alpha")) {
     data.setPhase(DEPLOYPHASE.alpha);
    } else if (token.equals("real")) {
     data.setPhase(DEPLOYPHASE.real);
    } else if (token.equals("cache")) {
     data.setPhase(DEPLOYPHASE.cache);
    }
   }
   i++;
  }
  out.write(data);
  //out.flush();
 }
 private MessageDecoderResult isDecodable(IoSession session, IoBuffer in) {
  if (in.remaining() < MIN_READ_LENGTH) {
   return MessageDecoderResult.NEED_DATA;
  }
  return MessageDecoderResult.OK;
 }
 protected int getStreamLength(IoBuffer iobuffer) throws Exception {
  if (iobuffer.remaining() >= 4) {
   return iobuffer.getInt();
  }
  return Integer.MIN_VALUE;
 }
 class Message {
  long bytesLength = -1;
  byte[] bytes;
 }
 private static int byteArrayToInt(byte[] b) {
  int value = 0;
  for (int i = 0; i < 4; i++) {
   int shift = (4 - 1 - i) * 8;
   value += (b[i] & 0x000000FF) << shift;
  }
  return value;
 }
}


CodecFactory

public class ImageUploadCodecFactory implements ProtocolCodecFactory {
    private ProtocolEncoder encoder;
    private ProtocolDecoder decoder;
    public static String DELIMITER = "||";
   
    public ImageUploadCodecFactory() {
        encoder = new ImageUploadRequestEncoder();
  decoder = new ImageUploadRequestDecoder();
    }
    public ProtocolEncoder getEncoder(IoSession ioSession) throws Exception {
        return encoder;
    }
    public ProtocolDecoder getDecoder(IoSession ioSession) throws Exception {
        return decoder;
    }
}
Posted by '김용환'
,

jar형태로 Spring bean을 사용할 때, namespace를 주는 방법이 2.5에서 제시되었다.
2.0에서는 사용할 수 없고, 2.5부터 가능하다.

자세한 내용은 다음의 내용을 참조할 것.

http://www.javaworld.com/javaworld/jw-02-2008/jw-02-springcomponents.html?page=1


 
  1. Create an XSD file that defines a component.
  2. Write the Java code encapsulating the logic for the component.
  3. Create a namespace handler that maps the schema to the beans.
  4. Create a bean definition parser to handle the parsing of bean configuration data.
  5. Create two deployment-descriptor property files.
  6. Package it all up as a .jar file.

Posted by '김용환'
,


If you do not give the query in validationQuery properties, validation(test) is not applied your application,
because dbcp code check the validationQuery.

Unconditionally TestOnBorrow, TestOnReturn in given properties also false.
package org.apache.commons.dbcp;
public class BasicDataSource implements DataSource {
        // Can't test without a validationQuery
        if (validationQuery == null) {
            setTestOnBorrow(false);
            setTestOnReturn(false);
            setTestWhileIdle(false);
        }

Posted by '김용환'
,
When you use update of SqlClient, you may want to know result value, updated count.
But, contrary to your expectation, the is no return value. Because SqlClient use internally SqlExecutor class(com.ibatis.sqlmap.engine.execution.SqlExecutor), a executeUpdate method of the SqlExecutor return update count of prepareSatement by calling ps.getUpdateCount(), but the that executeUpdate method alway return 0.


To  current(ibatis 2.3.4), if you use the update in ibatis used internally in used merge into statment, there is no measures to confirm the return value.
Posted by '김용환'
,

I have found critical situation about deadlock.
Http thread was full. Most of apache workers  was  in sending reply. 

Busy http thread grew up until suspending its function. When the apache could not respond any request, it removed from L4 (it have L7 function) because of no response.

Every web servers (600 ea) always does not happen, but some web application servers(10ea) fell into the trouble per 2-3 days.

Apache Status : 

Server 
Application Version : 2.0.59,  Mod_jk 1.2.18, Tomcat 5.5.17, JDK 6.0 update 6  Linux Kernel 2.6.9-67.0.22.ELsmp #1 SMP,
OS : CentOS
gcc version
 : gcc version 3.4.6 20060404 (Red Hat 3.4.6-9)
glibc
버전 glibc-2.3.4-2.39


I was wonderying why happened. 

1) I captured apache server status.
Apache Server Status

Server uptime: 4 days 20 hours 41 minutes 2 seconds
Total accesses: 43491259 - Total Traffic: 10.8 GB
CPU Usage: u33.75 s6.42 cu0 cs0 - .00956% CPU load
104 requests/sec - 27.0 kB/second - 266 B/request
109 requests currently being processed, 4 idle workers
WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW_WWW.WWWWWWWWWWWW
CWWWWWWWWWWWWWWWWWWWWW_WWWWCWWWWWWWWWRWWWWWW__CCR.C.............
................................................................
................................................................

Scoreboard Key:
"_" Waiting for Connection, "S" Starting up, "R" Reading Request,
"W" Sending Reply, "K" Keepalive (read), "D" DNS Lookup,
"C" Closing connection, "L" Logging, "G" Gracefully finishing,
"I" Idle cleanup of worker, "." Open slot with no current process


2) lsof
The number of CLOSE_WAIT status tcp sockets was 140. The number was close equal to the number of  apache workers was in sending reply.
java    16907  www   52u  IPv6 1014864218                 TCP localhost.localdomain:8009->localhost.localdomain:35205 (CLOSE_WAIT)
java    16907  www   53u  IPv6 1014869414                 TCP localhost.localdomain:8009->localhost.localdomain:35414 (CLOSE_WAIT)
java    16907  www   54u  IPv6 1014861929                 TCP localhost.localdomain:8009->localhost.localdomain:35171 (CLOSE_WAIT)
java    16907  www   55u  IPv6 1014863474                 TCP localhost.localdomain:8009->localhost.localdomain:35200 (CLOSE_WAIT)
java    16907  www   56u  IPv6 1014781598                 TCP localhost.localdomain:8009->localhost.localdomain:60006 (CLOSE_WAIT)
java    16907  www   57u  IPv6 1014860437                 TCP localhost.localdomain:8009->localhost.localdomain:35091 (CLOSE_WAIT)
java    16907  www   58u  IPv6 1014859292                 TCP localhost.localdomain:8009->localhost.localdomain:35062 (CLOSE_WAIT)
java    16907  www   59u  IPv6 1014853698                 TCP localhost.localdomain:8009->localhost.localdomain:34860 (CLOSE_WAIT)
java    16907  www   60u  IPv6 1014864865                 TCP localhost.localdomain:8009->localhost.localdomain:35353 (CLOSE_WAIT)
java    16907  www   61u  IPv6 1014868132                 TCP localhost.localdomain:8009->localhost.localdomain:35356 (CLOSE_WAIT)
java    16907  www   62u  IPv6 1014864283                 TCP localhost.localdomain:8009->localhost.localdomain:35222 (CLOSE_WAIT)
..


3) Thread dump
I found dead lock situation in dumped thread in java log.

                         i.         java.lang.Thread.State: BLOCKED (on object monitor)         
at org.apache.commons.pool.impl.GenericObjectPool.borrowObject(GenericObjectPool.java:916)
          - waiting to lock <0x8fedb478> (a org.apache.commons.pool.impl.GenericObjectPool)

1.       "TP-Processor2" daemon prio=10 tid=0x0821f400 nid=0x4286 waiting for monitor entry [0x88ed3000..0x88ed50a0]

2.    "TP-Processor2" daemon prio=10 tid=0x0821f400 nid=0x4286 waiting for monitor entry [0x88ed3000..0x88ed50a0] 



Found one Java-level deadlock:

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

"TP-Processor200":

 waiting to lock monitor 0x080dfd24 (object 0x8fedb478, a org.apache.commons.pool.impl.GenericObjectPool),

 which is held by "Timer-0"

"Timer-0":

waiting to lock monitor 0x080dfcc0 (object 0x8fee6f70, a org.apache.commons.dbcp.PoolableConnection),

which is held by "TP-Processor28"

"TP-Processor28":

waiting to lock monitor 0x080dfd24 (object 0x8fedb478, a org.apache.commons.pool.impl.GenericObjectPool),

which is held by "Timer-0"

 

"TP-Processor200": (Select query) return queryForList("xxx.selectXXXCount",param);

 

"TP-Processor28": (Select query

queryForObject("selectmusic",params);



This deadlock reported in "Dead lock using the evictor"(https://issues.apache.org/jira/browse/DBCP-270)
In this jira, there are patch on that.


Commons Dbcp

Dead lock using the evictor

Created: 26/Jun/08 10:18 AM   Updated: 27/Jun/08 03:41 AM
Component/s: None Affects Version/s: 1.2.2 Fix Version/s: 1.3

Patch attached, dead lock reported. the abandonedtrace does synchronized(this) when it really only needs to do synchronized(this.trace)

Dead lock reported when using the evictor

=============================
"Timer-3":
waiting to lock monitor 0x0000000053b40548 (object 0x00002aaabf3210f0, a
org.apache.tomcat.dbcp.dbcp.PoolableConnection),
which is held by "TP-Processor27"
"TP-Processor27":
waiting to lock monitor 0x0000000053b404d0 (object 0x00002aaab9fa8b08, a
org.apache.tomcat.dbcp.pool.impl.GenericObjectPool),
which is held by "Timer-3"

Java stack information for the threads listed above:

patch source

Index: src/java/org/apache/commons/dbcp/AbandonedTrace.java
===================================================================
--- src/java/org/apache/commons/dbcp/AbandonedTrace.java (revision 671937)
+++ src/java/org/apache/commons/dbcp/AbandonedTrace.java (working copy)
@@ -172,7 +172,7 @@
      * @param trace AbandonedTrace object to add
      */
     protected void addTrace(AbandonedTrace trace) {
-        synchronized (this) {
+        synchronized (this.trace) {
             this.trace.add(trace);
         }
         setLastUsed();
@@ -182,8 +182,8 @@
      * Clear the list of objects being traced by this
      * object.
      */
-    protected synchronized void clearTrace() {
-        if (this.trace != null) {
+    protected void clearTrace() {
+        synchronized(this.trace) {
             this.trace.clear();
         }
     }
@@ -194,8 +194,10 @@
      * @return List of objects
      */
     protected List getTrace() {
-        return trace;
+        synchronized (this.trace) {
+            return new ArrayList(trace);
     }
+    }
 
     /**
      * If logAbandoned=true, print a stack trace of the code that
@@ -206,7 +208,7 @@
             System.out.println(format.format(new Date(createdTime)));
             createdBy.printStackTrace(System.out);
         }
-        synchronized(this) {
+        synchronized(this.trace) {
             Iterator it = this.trace.iterator();
             while (it.hasNext()) {
                 AbandonedTrace at = (AbandonedTrace)it.next();
@@ -220,8 +222,8 @@
      *
      * @param trace AbandonedTrace object to remvoe
      */
-    protected synchronized void removeTrace(AbandonedTrace trace) {
-        if (this.trace != null) {
+    protected void removeTrace(AbandonedTrace trace) {
+        synchronized(this.trace) {
             this.trace.remove(trace);
         }
     }


Because Commons-dbcp 1.3 is not year released in formal. (now : 4. 2009) and I do not know what willing happen if the snapshop patch version, I used patched commons-dbcp 1.2.2 library.

After patching that version, there is no trouble or problem like that.


Posted by '김용환'
,
If you meet this log, you shoud take carefully a look at your log4j sqlhandler option, modify it.

log4j:ERROR JDBCAppender::configure(), No SqlHandler or sql, table, procedure option given !
log4j:ERROR JDBCAppender::append(), Not ready to append !


Posted by '김용환'
,
To programe java fx, refer below sites.



http://jfx.wikia.com/wiki/Code_Examples

http://java.sun.com/javafx/1/tutorials/ui/events/index.html

http://java.sun.com/javafx/1/tutorials/core/modifiers/index.html

http://javaora.tistory.com/tag/Learning%20the%20JavaFX%20Script%20Programming%20Language%20-%20Lesson%2011:%20Access%20Modifiers


http://java.sun.com/javafx/script/reference/scenegraph_demo/


http://www.javafx.com/samples/SimpleVideoPlayer/index.html


http://www.vogella.de/articles/JavaFX/article.html

Posted by '김용환'
,
0. Donwload jad
Download and install jad app, and put intalled jad in the path on your computer to execute on any commnad window.

1. Create jad.bat file
Crate jad.bat file and put your jad.bat into path on your computer.
@echo off
jad -o -d. %*
notepad %~n1.jad
del %~n1.jad

2. Link class extension file to jad.bat that you made.

3. Unzip jar
Unzip a certain jar to your computer. and run "cmd" on execute window menu.
And, go to the unzipped jar directory and execute below command to decompile your class files.

4. Click class file
After clicking your class file linked jad.bat, you may see this window.



Strength of this bat file
- You may not decompile every class file.
- You may not know every option of jad.
- Autiomatically remove the jad file when you close the decompiled java source note-pad-window.


'general java' 카테고리의 다른 글

No SqlHandler log4j:ERROR problem  (0) 2009.04.21
JavaFx Programming Reference  (0) 2009.04.17
java sources for ojdbc  (0) 2009.04.17
중요한 DBCP 설정 공부  (0) 2009.04.10
Jad 사용법  (0) 2009.04.10
Posted by '김용환'
,
Those sources are decompiled by jad decompiler. I can't source for ojdbc14.jar anywhere, so that I put sources to my blog.

Prior to see the source, you have to see the readme of ojdbc14.jar in oracle web site to understand jdbc specification and bug fixes.

'general java' 카테고리의 다른 글

JavaFx Programming Reference  (0) 2009.04.17
Notepad with class java file (Jad Usage Tip)  (0) 2009.04.17
중요한 DBCP 설정 공부  (0) 2009.04.10
Jad 사용법  (0) 2009.04.10
JMX 개발중 POJO를 이용하기  (0) 2009.03.31
Posted by '김용환'
,

DBCP(http://commons.apache.org/dbcp/configuration.html) 페이지를 보면 설명이 나오는데. 이거 썩 설명이 많지 않다. 여기다가 사족을 붙이고자 한다. 


 initialSize 0 (디폴트 값)
The initial number of connections that are created when the pool is started.
Since: 1.2
초기화시 싱생되는 connection 수를 의미한다. 

maxActive 8 (디폴트값)
The maximum number of active
 connections that can be allocated from this pool at the same time, or negative for no limit.
동시에 동작 가능한 최대 connection 개수이며, 이 이상의 connection을 요구하면, 반환될때까지 lock이 걸린다. -값은 크기 제한이 없다 

maxIdle 8 (디폴트값)
The maximum number of connections that can remain idle in the pool, without extra ones being released, or negative for no limit.
풀에서 idle를 유지하는 최대 개수를 의미한다.  -값은 크기 제한이 없다 

minIdle 0 (디폴트값)
The minimum number of connections that can remain idle in the pool, without extra ones being created, or zero to create none.
풀에서 idle를 유지할 수 있는 최소의 connection를 의미한다. evictor가 쫓아내더라도 이 숫자는 보장한다.

maxWait (디폴트값)
indefinitely The maximum number of milliseconds that the pool will wait (when there are no available connections) for a connection to be returned before throwing an exception, or -1 to wait indefinitely. 
Exception나기 전까지 풀에서 커넥션을 얻을때까지 얼마나 기다릴지를 지정한다.
보통 3000 이 좋은 값인듯.


파라미터

디폴트값

설명

validationQuery

The SQL query that will be used to validate connections from this pool before returning them to the caller. If specified, this query MUST be an SQL SELECT statement that returns at least one row.

 

물려있는 connection validation 체크를 수행할 sql 문을 지정한다. 오라클의 경우는 select 1 from dual 이며, msql의 경우는 select 1 로 지정하는 경우가 많다.

testOnBorrow

true

The indication of whether objects will be validated before being borrowed from the pool. If the object fails to validate, it will be dropped from the pool, and we will attempt to borrow another.
validationQuery
 connection이 살았나 죽었나 확인해준다.

NOTE - for a
true value to have any effect, the validationQuery parameter must be set to a non-null string.

 

pool에서 connection을 가져와서(borrow) connectionvalidationQuery를 실행한다.

testOnReturn

false

The indication of whether objects will be validated before being returned to the pool.
NOTE - for a
true value to have any effect, the validationQuery parameter must be set to a non-null string.

 

pool에서 connection을 돌려줄 때(return) connectionvalidationQuery를 실행한다.

testWhileIdle

false

The indication of whether objects will be validated by the idle object evictor (if any). If an object fails to validate, it will be dropped from the pool. NOTE - for a true value to have any effect, the validationQuery parameter must be set to a non-null string.
왕 중요하다.

Evitor threadIdle connection을 확인하여 connectionvalidationQuery를 체크하여 문제가 발생하면 connection pool에서 제거한다.

timeBetweenEvictionRunsMillis

-1

The number of milliseconds to sleep between runs of the idle object evictor thread. When non-positive, no idle object evictor thread will be run. 
evictor thread
가 실행되는 주기를 의미한다. 단위는 millisecond이다. 그동안 6000으로 사용해왔다.

numTestsPerEvictionRun

3

The number of objects to examine during each run of the idle object evictor thread (if any).

Evitor thread 동작시 idle connection의 개수만큼 체크한다.

minEvictableIdleTimeMillis

1000 * 60 * 30

The minimum amount of time an object may sit idle in the pool before it is eligable for eviction by the idle object evictor (if any). 
디폴트는 30분이다. evictor요청이 오면 이 시간값을 기준으로 생성된지 오래된 idle connecion을 없앤다
DB
입장에서 보면, 한번 3개가 들어와 session에 대해서 soft parsing하는 쿼리문으로 보인다


if (evictor
요청시간 - idle 객체 생성된 시간
> minEvictableIdleTimeMillis) {
     connection
회수
()
}
Evictor
가 잘 일을 못한다고 해서 -1로 설정하고 있다


 

 

'general java' 카테고리의 다른 글

Notepad with class java file (Jad Usage Tip)  (0) 2009.04.17
java sources for ojdbc  (0) 2009.04.17
Jad 사용법  (0) 2009.04.10
JMX 개발중 POJO를 이용하기  (0) 2009.03.31
jdk 5,6 클래스를 jdk 3,4에서 실행하기  (0) 2009.03.30
Posted by '김용환'
,