이전에 "Hessian 에서 stream is closed 오류 해결하기" 와 관련된 글을 작성한 적이 있었습니다. 해당 문제는 3.1.6 버젼으로 다운그레이드하여서 해결하였었는데, 그것만으로는 성에 안찹니다.
Hessian 은 XML 웹서비스나, multipart 나 이런 것들을 완전히 대체할 것이라고 판단하였었는데, 그게 안되는 이유는
- InputStream 을 하나밖에 전달하지 못한다.
- InputStream 을 전송(upload) 시에는 마지막 인자로 주어져야한다.
- InputStream 을 수신(download) 할 경우에는 리턴 형으로 InputStream 을 받아와야한다.
이기 때문이었죠. 실컷 Hessian 모듈 만들어놨다만, 이런 제약이 있을 줄이야. 그런데도 더 문제는 이런 조건에 대해서 문서화가 안 되어있다는것입니다.. 도대체 카우초 애들은 뭐하는지;;
자. 아름답지만 안되는 경우를 봅시다. 다음은 Hessian 으로 전송하는 모델 클래스와 서비스 인터페이스입니다.
public interface HessianService {
public HsContentsSurface createContents(String uuid, String name, List<HsFile> attachFiles) throws DuplicateContentsUuidException;
public HsFile createFile2(String name, InputStream data, String fid, String md5, String sha1);
public HsFile getFile2(String fid);
}
public class HsFile implements Serializable {
private String name;
private String fileUuid;
private long size = -1;
private String md5;
private String sha1;
private InputStream data = null;
... get/set methods ...
}
아름답죠?
createContents 에서는 전달할 파일에 대해서 객체화 시켜서 생성하며,
createContents 에서는 전달할 파일에 대해서 객체화 시켜서 생성하며,
getFile2 에서는 받을 때 각종 정보와 함께 받습니다.
createFile2 에서는 InputStream 인자를 가운데에서 넣고 있습니다.
하.지.만.
이 경우 createContnets 나 createFile2 할 경우에는
com.caucho.hessian.io.HessianProtocolException: createFile2: expected string at 0x47
at com.caucho.hessian.io.Hessian2Input.error(Hessian2Input.java:2703)
at com.caucho.hessian.io.Hessian2Input.expect(Hessian2Input.java:2686)
at com.caucho.hessian.io.Hessian2Input.readString(Hessian2Input.java:1403)
at com.caucho.hessian.io.BasicDeserializer.readObject(BasicDeserializer.java:181)
at com.caucho.hessian.io.Hessian2Input.readObject(Hessian2Input.java:1753)
at com.caucho.hessian.server.HessianSkeleton.invoke(HessianSkeleton.java:174)
at com.caucho.hessian.server.HessianSkeleton.invoke(HessianSkeleton.java:109)
at com.caucho.hessian.server.HessianServlet.service(HessianServlet.java:396)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
와 같은 오류가 날 것이고, getFile2() 에서는
java.io.IOException: stream is closed
at sun.net.www.http.ChunkedInputStream.ensureOpen(ChunkedInputStream.java:151)
at sun.net.www.http.ChunkedInputStream.read(ChunkedInputStream.java:646)
at java.io.FilterInputStream.read(FilterInputStream.java:111)
at sun.net.www.protocol.http.HttpURLConnection$HttpInputStream.read(HttpURLConnection.java:2266)
at com.caucho.hessian.io.Hessian2Input.readBuffer(Hessian2Input.java:2644)
at com.caucho.hessian.io.Hessian2Input.read(Hessian2Input.java:2598)
at com.caucho.hessian.io.Hessian2Input$ReadInputStream.read(Hessian2Input.java:2740)
at java.io.BufferedInputStream.fill(BufferedInputStream.java:218)
at java.io.BufferedInputStream.read1(BufferedInputStream.java:256)
at java.io.BufferedInputStream.read(BufferedInputStream.java:313)
와 같은 오류가 발생할겁니다.
처음에 말한대로 Hessian 에서 InputStream 을 사용할 때의 제약점을 적용시키고 다시 인터페이스를 만들어봅시다. 이렇게 적용시키면 인터페이스가 매우 단순해집니다.
public interface HessianService {
public HsFile createFile(String name, String fid, String md5, String sha1, InputStream data);
public InputStream downloadFile(String fid);
}
네. 이렇게 InputStream 을 객체 안에 넣지 않고, 마지막 인자로 주면 업로드 잘 됩니다.
또한 받을 때 리턴형으로 InputStream 을 받으면 또한 잘 받아집니다.
하지만, 이런 제약으로는 저희가 원하는 충분한 인터페이스를 표현하기가 힘들군요. 더구나 파일 여러개와 텍스트 전송이 한 트랜잭션에 이루어져야한다면 좀 깝깝합니다.
결국 XML 웹서비스나 Multipart 를 이용해야할까요? 아 귀찮아.