이전에 "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 에서는 전달할 파일에 대해서 객체화 시켜서 생성하며,
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 를 이용해야할까요? 아 귀찮아.

Hessian 의 최신 릴리즈를 사용하면 InputStream 을 받아올때는

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:116)
  at sun.net.www.protocol.http.HttpURLConnection$HttpInputStream.read(HttpURLConnection.java:2446)
  at com.caucho.hessian.io.Hessian2Input.readBuffer(Hessian2Input.java:2689)
  at com.caucho.hessian.io.Hessian2Input.read(Hessian2Input.java:2635)
  at com.caucho.hessian.io.Hessian2Input$ReadInputStream.read(Hessian2Input.java:2785)
...

"stream is closed" 오류가 나타납니다. 
3.1.6 으로 사용하면 잘 되는군요. (4.0.7, 3.2.1 안됨)


언제쯤 이문제가 깔끔하게 해결이 될가요?


참조 : http://bugs.caucho.com/view.php?id=4015

WSDL 로부터 C++ 용 스텁 클래스를 만들어 보겠습니다.
다양한(?) 방법이 있겠지만 가장 쉬운 방법. 사실은 제가 시도했던 방법중의 최후이며 성공한 유일한 방법일뿐이죠.. (* - -)

만드는 방법은 iona 사의 Artix ESB 제품을 이용하는 것입니다. 현재는 5.5가 나와있습니다.
다음은 Artix ESB 5.5 가 지원하는 플랫폼입니다.



cpp 만들어내는거랑 설치 환경이 각각 다른데 저는 xp 환경에서 vc6 용 cpp 를 만들겠습니다.
사실 전 윈도우7에서 만들어 낸다고 이틀 뻘짓 했는데. xp 에서 하니깐 에러 한줄 없이 한번에 완벽히 성공이군요ㅡㅡ

이제 만들어봅시다.

1. cpp 컴파일러 설치
우선 cpp 컴파일러를 설치합니다. 전 Visual Studio 6 & 서비스팩3 를 설치했습니다.

2. Artix ESB 설치
Artix ESB 를 다운 받습니다. Artix ESB 는 상용제품이며 http://web.progress.com/en/sonic/artix-index.html  여기에서 30일간 사용가능한 트라이얼을 구할 수 있습니다.
Artix ESB 설치시에 JDK 를 같이 설치할 수도 있고, 아니면 기존에 있는 것을 사용할 수 있습니다.
저는 그냥 편한게 같이 설치했습니다. 그렇다고 윈도우 프로그램에 등록되진 않습니다.

3. 기본 설정
이게 중요한 부분입니다. 우선 JAVA_HOME 환경변수가 설정되어있어야합니다.
그리고 JAVA_HOME 경로는 Version 8.3 방식. 즉 축약된 디렉토리경로명을 사용해야합니다. 커맨드 프롬프트에서 dir/x 를 이용해서 경로를 알 수 있습니다.
e.g) C:\PROGRA~2\Java\JDK15~1.0_2

그 후는 설정을 적용시켜주어야합니다.
다음의 파일을 실행합니다.
  1. %ARTIS_HOME%/java/bin/artix_java_env.bat
  2. %ARTIS_HOME%/cxx_java/bin/artix_env.bat
4. wsdl2cpp
wsdl2cpp 는 artix tool 을 이용합니다.
%ARTIS_HOME%/tools/bin/artix.bat 파일을 이용하여 각종 기능을 이용합니다.

다음을 실행합니다.
artix wsdl2cpp [WSDL_URL]


e.g) D:\app\artix\tools\bin>artix wsdl2cpp http://localhost:8088/ws/ws/CmWebService?wsdl


그 외 artix 툴이 제공하는 기능은 다음과 같습니다.

  • dbconfig2wsdl
  • idl2wsdl
  • java2js
  • java2ws
  • sql2dbconfig
  • validator
  • wsdl2acl
  • wsdl2cpp
  • wsdl2dbservice
  • wsdl2idl
  • wsdl2java
  • wsdl2js
  • wsdl2service
  • wsdl2soap
  • wsdl2xml
  • wsdlgen
  • xsd2wsdl
보는 바와 같이 다양한 것들을 할 수 있습니다. wsdl2java 와 같은 것은 익숙하죠? artix 제품은 이러한 것들을 아파치 CXF 를 이용해서 만들어내고 있습니다. cxf 가 사랑받으니 좋군요 ㅎㅎ

4. 결과 확인
쨘!


※ 참조

+ Recent posts