Microsoft MVP성태의 닷넷 이야기
Java: 8. 닷넷 개발자가 구현해 본 자바 웹 서비스 (2) [링크 복사], [링크+제목 복사],
조회: 29073
글쓴 사람
정성태 (techsharer at outlook.com)
홈페이지
첨부 파일
 
(연관된 글이 1개 있습니다.)

닷넷 개발자가 구현해 본 자바 웹 서비스 (2)


지난번의 경우,

닷넷 개발자가 구현해 본 자바 웹 서비스 (1)
; https://www.sysnet.pe.kr/2/0/1130

개발 환경 구성하고 어떻게든 예제를 돌리느라 바빴는데요. 이제 여유를 가지고 잠시 살펴보면.

우선, 닷넷에 생성된 프록시 코드의 차이점을 파악해 보겠습니다.

(WCF를 제외하고) 닷넷의 웹 서비스인 asmx 서비스에 대해 프록시 코드를 만들면 보통 다음과 같은 식으로 메서드에 SoapDocumentMethod 특성이 부여됩니다.

[System.Web.Services.Protocols.SoapDocumentMethodAttribute("http://tempuri.org/Echo", 
    RequestNamespace="http://tempuri.org/", ResponseNamespace="http://tempuri.org/",
    Use=System.Web.Services.Description.SoapBindingUse.Literal, 
    ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Wrapped)]

public string Echo(string text) {
    object[] results = this.Invoke("Echo", new object[] {text};
    return ((string)(results[0]));
}


반면, 자바 쪽 웹 메서드를 호출하는 프록시 코드에는 SoapRpcMethod 특성이 부여되었습니다.

[System.Web.Services.Protocols.SoapRpcMethodAttribute("", RequestNamespace="http://DefaultNamespace", 
        ResponseNamespace="http://localhost:8080/axis/services/HelloService")]
[return: System.Xml.Serialization.SoapElementAttribute("EchoReturn")]

public string Echo(string text) {
    object[] results = this.Invoke("Echo", new object[] {text});
    return ((string)(results[0]));
}

닷넷의 asmx는 기본적으로 Document 스타일임을 알 수 있는데, 물론 RPC 스타일로 변경하는 것도 가능합니다. 방법도 아주 쉬운데요, 그냥 아래와 같이 asmx 파일 안의 웹 메서드 정의를 포함하고 있는 클래스에 SoapRpcService 특성만 지정해 주면 됩니다. (또는 메서드 단위로 SoapRpcMethod 특성을 지정할 수 있습니다.)

[SoapRpcService()] 
public class WebService1 : System.Web.Services.WebService
{
    [WebMethod]
    public string HelloWorld()
    {
        return "Hello World";
    }
}

참고로, Document/literal, Rpc/literal, Document/literal wrapped 방식이 있는데, 이에 대해서는 다음의 글이 도움이 될 것입니다. (WS-I Basic Profile에서 encoded 사용은 더 이상 허용하지 않기 때문에 그 방식은 잊어버리시는 것도 좋겠습니다.)

Which style of WSDL should I use?
; http://www.ibm.com/developerworks/webservices/library/ws-whichwsdl/

마이크로소프트의 경우, 정확히는 Document/literal wrapped 스타일의 SOAP 구현을 하고 있으며 지난번 구현했던 Axis 예제는 Rpc/Encoded 방식의 웹 서비스를 구현한 예제였던 것임을 알 수 있습니다.




자바 예제를 좀 더 확장해 볼까요? 기본 타입 값이 아닌 Complex 타입을 반환하도록 다음과 같이 수정해 보겠습니다.

===== HelloService.java =====
public class HelloService {

    public String Echo(String text)
    {
        return "Hello " + text;
    } 
    
    public Person EchoPerson(String name)
    {
        Person person = new Person();
        person.name = name;
        person.age = 5;
        
        return person;
    }
}

===== Person.java =====
public class Person {
    public String name;
    public int age;
}

노출되어야 할 메서드가 추가되었으므로 deploy.wsdd 파일 역시 변경 사항을 반영시켜줍니다.

<deployment name="test" xmlns="http://xml.apache.org/axis/wsdd/" 
    xmlns:java="http://xml.apache.org/axis/wsdd/providers/java">

  <service name="HelloService" provider="java:RPC">
    <parameter name="className" value="HelloService"/>
    <parameter name="allowedMethods" value="*"/>
  </service>

</deployment>

Axis에 배포해주고, 프록시를 업데이트 한 후 닷넷 클라이언트 프로그램을 실행하면 이번엔 다음과 같이 오류가 발생합니다.

Unhandled Exception: System.InvalidOperationException: Response is not well-formed XML. ---> System.Xml.XmlException: Root element is missing.
   at System.Xml.XmlTextReaderImpl.Throw(Exception e)
   at System.Xml.XmlTextReaderImpl.ParseDocumentContent()
   at System.Xml.XmlTextReaderImpl.Read()
   at System.Xml.XmlTextReader.Read()
   at System.Xml.XmlReader.MoveToContent()
   at System.Web.Services.Protocols.SoapHttpClientProtocol.ReadResponse(SoapClientMessage message, WebResponse response, Stream responseStream, Boolean asyncCall)
   at System.Web.Services.Protocols.SoapHttpClientProtocol.Invoke(String methodName, Object[] parameters)
   --- End of inner exception stack trace ---
   at System.Web.Services.Protocols.SoapHttpClientProtocol.Invoke(String methodName, Object[] parameters)
   at ConsoleApplication1.localhost.HelloServiceService.EchoPerson(String name) in D:\...[생략]...\ConsoleApplication1\Web References\localhost\Reference.cs:line 114
   at ConsoleApplication1.Program.Main(String[] args) in D:\...[생략]...\ConsoleApplication1\Program.cs:line 14
Press any key to continue . . .

이 순간의 네트워크를 가로채 보면 단서가 있을까요?

======= 요청 =======
POST http://192.168.50.132:8080/axis/services/HelloService HTTP/1.1
User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; MS Web Services Client Protocol 4.0.30319.235)
Content-Type: text/xml; charset=utf-8
SOAPAction: ""
Host: 192.168.0.132:8080
Content-Length: 610
Expect: 100-continue
Connection: Keep-Alive

<?xml version="1.0" encoding="utf-8"?><soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:tns="http://localhost:8080/axis/services/HelloService" xmlns:types="http://localhost:8080/axis/services/HelloService/encodedTypes" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><soap:Body soap:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"><q1:EchoPerson xmlns:q1="http://DefaultNamespace"><name xsi:type="xsd:string">test1</name></q1:EchoPerson></soap:Body></soap:Envelope>

======= 응답 =======
HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
Content-Type: text/xml;charset=utf-8
Date: Thu, 22 Sep 2011 02:07:52 GMT
Content-Length: 0

불친절한 Axis군요. 가타부타 아무런 오류 메시지도 없이 200 OK를 보내주다니. ^^;

원인은 책을 찾아보고 나서야 알았습니다. 자바는 RPC 스타일의 경우 클래스 타입에 대해서 get/set 메서드에 대한 정의를 별도로 추가해야 한다는 것입니다. 따라서, Person 클래스는 다음과 같은 코드들이 부가적으로 작성됩니다.

public class Person {

    public String name;
    public int age;
    
    public String getName()
    {
        return name;
    }
    
    public void setName(String name)
    {
        this.name = name;
    }
    
    public int getAge()
    {
        return age;
    }
    
    public void setAge(int age)
    {
        this.age = age;
    }
}

이뿐만이 아니라, 이에 대한 매핑을 wsdd 파일에도 지정해 주어야 합니다.

<deployment name="test" xmlns="http://xml.apache.org/axis/wsdd/" 
    xmlns:java="http://xml.apache.org/axis/wsdd/providers/java">

  <service name="HelloService" provider="java:RPC">
    <parameter name="className" value="HelloService"/>
    <parameter name="allowedMethods" value="*"/>
    <!--parameter name="wsdlServicePort" value="Echo"/-->
  </service>

  <beanMapping qname="ns:Person" xmlns:ns="http://test.com" languageSpecificType="java:Person">  
  </beanMapping>

</deployment>

오호~~~ 이거 불편함이 장난 아닌데요. ^^;

암튼, 이렇게 하고 다시 AdminService로 배포해 준 다음 닷넷 클라이언트 측의 프록시 코드를 업데이트 하고 실행해 주면 정상적으로 메서드 수행 결과값을 반환받을 수 있습니다.

여기까지 해서, 자바 Axis의 Rpc/encoded 방식으로 구현된 웹 서비스를 살펴보는 것이 끝났습니다.




원래는, 한 단계 더 나아가서 Axis로 Document 스타일의 SOAP 서비스를 실습해 보려고 했는데요. 닷넷 개발자로써는 도저히 현실적이지 않은 이유로 인해 포기했습니다.

왜냐하면, Axis의 Document 스타일은 Message라는 것에 너무 충실한 나머지 다음과 같은 식의 signature만 하용이 되기 때문입니다.

Service Styles - RPC, Document, Wrapped, and Message
 - Document / Wrapped services
; http://ws.apache.org/axis/java/user-guide.html#ServiceStylesRPCDocumentWrappedAndMessage

public Element [] method(Element [] bodies); 
public SOAPBodyElement [] method (SOAPBodyElement [] bodies); 
public Document method(Document body); 
public void method(SOAPEnvelope req, SOAPEnvelope resp); 

느낌이 오시죠? 말 그대로 XML 문서를 수작업으로 구성해서 메서드에 전달하고, 다시 반환값을 XML 파서로 select해 가면서 값을 받아와야 하는 구조입니다.

이렇게 구현된 Axis 웹 서비스를 닷넷에서 WSDL 코드 생성기를 거치면 다음과 같은 식으로 나옵니다.

[System.Web.Services.Protocols.SoapDocumentMethodAttribute("", 
    Use=System.Web.Services.Description.SoapBindingUse.Literal, 
    ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Bare)]
[return: System.Xml.Serialization.XmlElementAttribute("getTimeReturn", Namespace="http://localhost:8080/axis/services/TimeService")]

public object portfolio([System.Xml.Serialization.XmlElementAttribute("getTime", Namespace="http://DefaultNamespace")] object getTime1) {
    object[] results = this.Invoke("getTime", new object[] {
                getTime1});
    return ((object)(results[0]));
}

그렇습니다. object 인자에 object 반환값의 메서드로 asmx에서는 SoapParameterStyle.Bare 유형이 바로 Axis의 Document 스타일이었던 것입니다.




위의 실습을 해보고 나니, 개인적으로 설마 자바 개발자들이 Axis를 가지고 웹 서비스를 만들고 있을 거라는 생각은 들지 않더군요. 아마도 좀 더 나은 상용 웹 서비스 기반 도구가 있지 않을까 싶은데... 제가 거기까진 조사를 못했습니다.

어느 정도까지 자바의 상용 웹 서비스 도구들이 편할지는 알 수 없지만, 일단 이 정도만 봐서는 적어도 웹 서비스 환경만큼은 역시 마이크로소프트 제품만한 것이 없는 것 같습니다.




[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]

[연관 글]






[최초 등록일: ]
[최종 수정일: 7/10/2021]

Creative Commons License
이 저작물은 크리에이티브 커먼즈 코리아 저작자표시-비영리-변경금지 2.0 대한민국 라이센스에 따라 이용하실 수 있습니다.
by SeongTae Jeong, mailto:techsharer at outlook.com

비밀번호

댓글 작성자
 




1  2  3  4  5  6  7  8  9  10  [11]  12  13  14  15  ...
NoWriterDateCnt.TitleFile(s)
13667정성태7/7/20246621닷넷: 2273. C# - 리눅스 환경에서의 Hyper-V Socket 연동 (AF_VSOCK)파일 다운로드1
13666정성태7/7/20247700Linux: 74. C++ - Vsock 예제 (Hyper-V Socket 연동)파일 다운로드1
13665정성태7/6/20247878Linux: 73. Linux 측의 socat을 이용한 Hyper-V 호스트와의 vsock 테스트파일 다운로드1
13663정성태7/5/20247473닷넷: 2272. C# - Hyper-V Socket 통신(AF_HYPERV, AF_VSOCK)의 VMID Wildcards 유형파일 다운로드1
13662정성태7/4/20247491닷넷: 2271. C# - WSL 2 VM의 VM ID를 알아내는 방법 - Host Compute System API파일 다운로드1
13661정성태7/3/20247413Linux: 72. g++ - 다른 버전의 GLIBC로 소스코드 빌드
13660정성태7/3/20247521오류 유형: 912. Visual C++ - Linux 프로젝트 빌드 오류
13659정성태7/1/20247858개발 환경 구성: 715. Windows - WSL 2 환경의 Docker Desktop 네트워크
13658정성태6/28/20248235개발 환경 구성: 714. WSL 2 인스턴스와 호스트 측의 Hyper-V에 운영 중인 VM과 네트워크 연결을 하는 방법 - 두 번째 이야기
13657정성태6/27/20247911닷넷: 2270. C# - Hyper-V Socket 통신(AF_HYPERV, AF_VSOCK)을 위한 EndPoint 사용자 정의
13656정성태6/27/20248076Windows: 264. WSL 2 VM의 swap 파일 위치
13655정성태6/24/20247849닷넷: 2269. C# - Win32 Resource 포맷 해석파일 다운로드1
13654정성태6/24/20247787오류 유형: 911. shutdown - The entered computer name is not valid or remote shutdown is not supported on the target computer.
13653정성태6/22/20247937닷넷: 2268. C# 코드에서 MAKEINTREOURCE 매크로 처리
13652정성태6/21/20249245닷넷: 2267. C# - Linux 환경에서 (Reflection 없이) DLL AssemblyFileVersion 구하는 방법파일 다운로드2
13651정성태6/19/20248487닷넷: 2266. C# - (Reflection 없이) DLL AssemblyFileVersion 구하는 방법파일 다운로드1
13650정성태6/18/20248410개발 환경 구성: 713. "WSL --debug-shell"로 살펴보는 WSL 2 VM의 리눅스 환경
13649정성태6/18/20247957오류 유형: 910. windbg - !py 확장 명령어 실행 시 "failed to find python interpreter" (2)
13648정성태6/17/20248278오류 유형: 909. C# - DynamicMethod 사용 시 System.TypeAccessException
13647정성태6/16/20249344개발 환경 구성: 712. Windows - WSL 2의 네트워크 통신 방법 - 세 번째 이야기 (같은 IP를 공유하는 WSL 2 인스턴스) [1]
13646정성태6/14/20247758오류 유형: 908. Process Explorer - "Error configuring dump resources: The system cannot find the file specified."
13645정성태6/13/20248197개발 환경 구성: 711. Visual Studio로 개발 시 기본 등록하는 dev tag 이미지로 Docker Desktop k8s에서 실행하는 방법
13644정성태6/12/20248868닷넷: 2265. C# - System.Text.Json의 기본적인 (한글 등에서의) escape 처리 [1]
13643정성태6/12/20248306오류 유형: 907. MySqlConnector 사용 시 System.IO.FileLoadException 오류
13642정성태6/11/20248198스크립트: 65. 파이썬 - asgi 버전(2, 3)에 따라 달라지는 uvicorn 호스팅
13641정성태6/11/20248673Linux: 71. Ubuntu 20.04를 22.04로 업데이트
1  2  3  4  5  6  7  8  9  10  [11]  12  13  14  15  ...