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 김용환 '김용환'
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);
In this jira, there are patch on that.
Commons Dbcp
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 김용환 '김용환'
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.
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) connection의 validationQuery를 실행한다. |
|
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) connection의 validationQuery를 실행한다. |
|
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 thread가 Idle connection을 확인하여 connection에 validationQuery를 체크하여 문제가 발생하면 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로 설정하고 있다. |
Posted by 김용환 '김용환'
댓글을 달아 주세요