# Web Service mit legacy Wrapper



## jan213 (13. Okt 2004)

Hi Leute,

ich moechte eine in C++ erstellte .dll Library als SOAP WebService offen legen. Mein Ansatz:

- Verwendung von JAX-RPC
- wrappen der legacy-Anwendung mit einem JNI-Adapter
- WS laeuft im Tomcat WebContainer
- Verbindung Adapter und WS laeuft ueber RMI (denn direkt im WS native-Methoden aufrufen funktionierte bei mir nicht!)

Hat jemand fuer dieses Probelm eine Loesung, oder vielleicht einen alternativen Ansatz? Ich bin nicht sicher, ob RMI das richtige ist.

Bis jetzt funktioniert es soweit:

- Zugriff auf .dll mit JNI (klar)
- Zugriff des WS auf "rmiregistry", sowie Zugriff auf den Stub und Aufruf der Methode.
- Clientzugriff auf WS sowie Methodenaufrufe

Scheitern tuts an:

- ich vermute, dass ich irgendein Problem habe aus dem WebContainer via RMI rauszukommen. In frueheren Anwendungen habe ich breits mit ueber Servlets auf RMI Anwendungen erfolgreich zugegriffen. Vielleicht ist das Problem AXIS spezifisch. Die Fehlermeldung ist jedenfalls folgende:

---------------- FEHLERMELDUNG ------------------------

```
AxisFault
 faultCode: {http://schemas.xmlsoap.org/soap/envelope/}Server
 faultSubcode: 
 faultString: JAXRPC.TIE.04: Internal Server Error (JAXRPCTIE01: caught exception while handling request: java.lang.NullPointerException)
 faultActor: 
 faultNode: 
 faultDetail: 
	{http://xml.apache.org/axis/}stackTrace: AxisFault
 faultCode: {http://schemas.xmlsoap.org/soap/envelope/}Server
 faultSubcode: 
 faultString: JAXRPC.TIE.04: Internal Server Error (JAXRPCTIE01: caught exception while handling request: java.lang.NullPointerException)
 faultActor: 
 faultNode: 
 faultDetail: 

JAXRPC.TIE.04: Internal Server Error (JAXRPCTIE01: caught exception while handling request: java.lang.NullPointerException)
	at org.apache.axis.message.SOAPFaultBuilder.createFault(SOAPFaultBuilder.java:260)
	at org.apache.axis.message.SOAPFaultBuilder.endElement(SOAPFaultBuilder.java:169)
```
[...]
---------------- ENDE FEHLERMELDUNG ------------------------

Keine Ahnung was das bedeutet. Aber vielleicht gibt es ja prinzipiell andere Ansaetze.

Gruss, JAN


----------



## Bleiglanz (14. Okt 2004)

> - Verbindung Adapter und WS laeuft ueber RMI (denn direkt im WS native-Methoden aufrufen funktionierte bei mir nicht!)


dieser Schritt ist doch strange, warum noch einen Layer dazwischenschalten? Neue Fehlerquellen (wg. nicht laufendem Server) und nochmaliges Marshalling sind doch hier sicher nicht nötig?

=> beim Start des Tomcat java.library.path setzen, damit die nativen Klassen gefunden werden können?


----------



## jan213 (14. Okt 2004)

OK, das habe ich probiert und es lläuft auch erstmal soweit, als dass die .dll's geladen werden können. Nun habe ich ein weiteres Problem:
Beim Ausfuehren des Client, der diesen WS nutzen soll kommt folgende Fehlermessage:

java.rmi.ServerException: JAXRPCSERVLET28: Missing port information
	at com.sun.xml.rpc.client.StreamingSender._raiseFault(StreamingSender.java:497)
	at com.sun.xml.rpc.client.StreamingSender._send(StreamingSender.java:294)
	at com.sun.xml.rpc.client.dii.CallInvokerImpl.doInvoke(CallInvokerImpl.java:80)
	at com.sun.xml.rpc.client.dii.BasicCall.invoke(BasicCall.java:489)
	at com.sun.xml.rpc.client.dii.CallInvocationHandler.doCall(CallInvocationHandler.java:122)
	at com.sun.xml.rpc.client.dii.CallInvocationHandler.invoke(CallInvocationHandler.java:86)
	at $Proxy0.getHello(Unknown Source)
	at com.neuhaus.test.ws.client.NativeInvokeClient.main(NativeInvokeClient.java:44)
Exception in thread "main" 

mein generierter WSDL File sieht so aus:


```
<?xml version="1.0" encoding="UTF-8" ?> 
<definitions xmlns="http://schemas.xmlsoap.org/wsdl/" xmlns:tns="http://localhost:8080/jni-ws/ws/NativeInvoke/wsdl/NativeInvoke" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" name="NativeInvoke" targetNamespace="http://localhost:8080/jni-ws/ws/NativeInvoke/wsdl/NativeInvoke">
  <types /> 
  <message name="NativeInvoke_getHello" /> 
  <message name="NativeInvoke_getHelloResponse">
  <part name="result" type="xsd:string" /> 
  </message>
  <portType name="NativeInvoke">
  <operation name="getHello">
  <input message="tns:NativeInvoke_getHello" /> 
  <output message="tns:NativeInvoke_getHelloResponse" /> 
  </operation>
  </portType>
  <binding name="NativeInvokeBinding" type="tns:NativeInvoke">
  <soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="rpc" /> 
  <operation name="getHello">
  <soap:operation soapAction="" /> 
+ <input>
  <soap:body encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" use="encoded" namespace="http://localhost:8080/jni-ws/ws/NativeInvoke/wsdl/NativeInvoke" /> 
  </input>
+ <output>
  <soap:body encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" use="encoded" namespace="http://localhost:8080/jni-ws/ws/NativeInvoke/wsdl/NativeInvoke" /> 
  </output>
  </operation>
  </binding>
  <service name="NativeInvoke">
  <port name="NativeInvokePort" binding="tns:NativeInvokeBinding">
  <soap:address location="http://localhost:8080/nativeInvoke/ws/NativeInvoke" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" /> 
  </port>
  </service>
  </definitions>
```

Vorschläge? Änderungen? Ich vermute mal, dass ich irgendwie die Portinformationen meinem Client klar machen muss. Mein derzeitiger (QName)portName, den ich verwende ist:
{http://localhost/jni-ws/ws/NativeInvoke/wsdl/NativeInvoke}NativeInvokePort

Mein (QName)serviceName:
{http://localhost:8080/jni-ws/ws/NativeInvoke/wsdl/NativeInvoke}NativeInvoke

Der Client baut auf jeden Fall eine Verbindung zum Service auf, denn beim WS wird auf jeden Fall die Methode "getHello()" aufgerufen. Sie gibt im log-file von Tomcat auch eine Debug-Ausgabe aus. Diese Methode ruft dann die native Methode auf. Dabei ensteht dann die oben gezeigte Fehlermeldung.

Viele Gruesse, JAN


----------



## Bleiglanz (14. Okt 2004)

kannst du das nochmal machen und einfach ein Servlet schreiben, das den native call absetzt

UND

einen webservice schreiben, der den native call gerade nicht macht, sondern ein dummy resultat liefert

Funktionieren diese beiden Dinge getrennt?

Bau mal einen Haufen log("jetzt bin ich bei") usw. ein, das Einpacken von Exceptions in wirre soap-faults ist bei der fehlersuche ein graus


----------



## jan213 (14. Okt 2004)

Also ich habe das jetzt nochmal auf beide Arten versucht, die Du vorgeschlagen hast. Fazit:

Beim WS mit Dummy-Daten, also ohne Native-Call funktioniert es ohne Probleme.

Die Sache mit dem Servlet bereitet mir ein bissel Kopfschmerzen, denn wenn ich das (HTTP)Servlet aufrufe mit dem Browser (ich gebe alle Anfragen als html aus, somit auch der String, der aus der nativen Methode kommt) bekomme ich den Fehler:


```
java.lang.UnsatisfiedLinkError: Native Library C:\JAVA\Sun\AppServer\jdk\jre\bin\hello.dll already loaded in another classloader
	java.lang.ClassLoader.loadLibrary0(ClassLoader.java:1551)
	java.lang.ClassLoader.loadLibrary(ClassLoader.java:1503)
	java.lang.Runtime.loadLibrary0(Runtime.java:788)
	java.lang.System.loadLibrary(System.java:834)
	com.neuhaus.test.ws.servlet.NativeInvokeServlet.<clinit>(Unknown Source)
	sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
	sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39)
	sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27)
	java.lang.reflect.Constructor.newInstance(Constructor.java:274)
	java.lang.Class.newInstance0(Class.java:308)
	java.lang.Class.newInstance(Class.java:261)
	org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:117)
	org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:535)
	org.apache.coyote.tomcat5.CoyoteAdapter.service(CoyoteAdapter.java:160)
	org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:790)
	org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.processConnection(Http11Protocol.java:709)
	org.apache.tomcat.util.net.TcpWorkerThread.runIt(PoolTcpEndpoint.java:572)
	org.apache.tomcat.util.threads.ThreadPool$ControlRunnable.run(ThreadPool.java:644)
	java.lang.Thread.run(Thread.java:534)
```

Was der zu bedeuten hat ist mir klar, aber was ich dagegen machen soll weiss ich nicht. Ich habe den Pfad der hello.dll in der Windows Umgebungsvariable PATH angegeben. Ausserdem habe ich die Datei einfach mal bei {JAVA_HOME}\jre\bin reingespielt, weil die ja eh' im java.library.path sind.

Vielen Dank schonmal, Gruss JAN


----------



## Bleiglanz (15. Okt 2004)

java.lang.UnsatisfiedLinkError: Native Library C:\JAVA\Sun\AppServer\jdk\jre\bin\hello.dll already loaded in another classloader 

tu sie aus dem jre\bin wieder raus, offenbar wird das Teil zweimal geladen (du musst dich für eine Variante entscheiden)


----------



## jan213 (15. Okt 2004)

Hallo Bleiglanz,

das mit dem ClassLoader habe ich im Griff. (static native Zugriff durch synchronized Singleton gekapselt) aber jetzt kommt der "Missing Port Information" -Error wieder.
Hier die aktuelle ErrorMessage:


```
AxisFault
 faultCode: {http://schemas.xmlsoap.org/soap/envelope/}Server
 faultSubcode: 
 faultString: JAXRPCSERVLET28: Missing port information
 faultActor: 
 faultNode: 
 faultDetail: 
	{http://xml.apache.org/axis/}stackTrace: AxisFault
 faultCode: {http://schemas.xmlsoap.org/soap/envelope/}Server
 faultSubcode: 
 faultString: JAXRPCSERVLET28: Missing port information
 faultActor: 
 faultNode: 
 faultDetail:
JAXRPCSERVLET28: Missing port information
	at org.apache.axis.message.SOAPFaultBuilder.createFault(SOAPFaultBuilder.java:260)
	at org.apache.axis.message.SOAPFaultBuilder.endElement(SOAPFaultBuilder.java:169)
	at org.apache.axis.encoding.DeserializationContextImpl.endElement(DeserializationContextImpl.java:1015)
	at com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.endElement(AbstractSAXParser.java:585)
	at com.sun.org.apache.xerces.internal.impl.XMLNSDocumentScannerImpl.scanEndElement(XMLNSDocumentScannerImpl.java:560)
	at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl$FragmentContentDispatcher.dispatch(XMLDocumentFragmentScannerImpl.java:1555)
	at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanDocument(XMLDocumentFragmentScannerImpl.java:341)
	at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:828)
	at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:758)
	at com.sun.org.apache.xerces.internal.parsers.XMLParser.parse(XMLParser.java:148)
	at com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.parse(AbstractSAXParser.java:1178)
	at javax.xml.parsers.SAXParser.parse(Unknown Source)
	at org.apache.axis.encoding.DeserializationContextImpl.parse(DeserializationContextImpl.java:242)
	at org.apache.axis.SOAPPart.getAsSOAPEnvelope(SOAPPart.java:538)
	at org.apache.axis.Message.getSOAPEnvelope(Message.java:376)
	at org.apache.axis.client.Call.invokeEngine(Call.java:2583)
	at org.apache.axis.client.Call.invoke(Call.java:2553)
	at org.apache.axis.client.Call.invoke(Call.java:2248)
	at org.apache.axis.client.Call.invoke(Call.java:2171)
	at org.apache.axis.client.Call.invoke(Call.java:1691)
	at org.apache.axis.client.AxisClientProxy.invoke(AxisClientProxy.java:186)
	at $Proxy0.getHello(Unknown Source)
	at com.neuhaus.test.client.JNIClient.main(JNIClient.java:46)


JAXRPCSERVLET28: Missing port information
	at org.apache.axis.message.SOAPFaultBuilder.createFault(SOAPFaultBuilder.java:260)
	at org.apache.axis.message.SOAPFaultBuilder.endElement(SOAPFaultBuilder.java:169)
	at org.apache.axis.encoding.DeserializationContextImpl.endElement(DeserializationContextImpl.java:1015)
	at com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.endElement(AbstractSAXParser.java:585)
	at com.sun.org.apache.xerces.internal.impl.XMLNSDocumentScannerImpl.scanEndElement(XMLNSDocumentScannerImpl.java:560)
	at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl$FragmentContentDispatcher.dispatch(XMLDocumentFragmentScannerImpl.java:1555)
	at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanDocument(XMLDocumentFragmentScannerImpl.java:341)
	at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:828)
	at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:758)
	at com.sun.org.apache.xerces.internal.parsers.XMLParser.parse(XMLParser.java:148)
	at com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.parse(AbstractSAXParser.java:1178)
	at javax.xml.parsers.SAXParser.parse(Unknown Source)
	at org.apache.axis.encoding.DeserializationContextImpl.parse(DeserializationContextImpl.java:242)
	at org.apache.axis.SOAPPart.getAsSOAPEnvelope(SOAPPart.java:538)
	at org.apache.axis.Message.getSOAPEnvelope(Message.java:376)
	at org.apache.axis.client.Call.invokeEngine(Call.java:2583)
	at org.apache.axis.client.Call.invoke(Call.java:2553)
	at org.apache.axis.client.Call.invoke(Call.java:2248)
	at org.apache.axis.client.Call.invoke(Call.java:2171)
	at org.apache.axis.client.Call.invoke(Call.java:1691)
	at org.apache.axis.client.AxisClientProxy.invoke(AxisClientProxy.java:186)
	at $Proxy0.getHello(Unknown Source)
	at com.neuhaus.test.client.JNIClient.main(JNIClient.java:46)
Exception in thread "main"
```

Ich komm mir vor wie der Hund, der sich in den Schwanz beisst. Vielleicht ist es auch ein Fehler der WSDL Datei, denn irgendwie scheint ja der Parser zu meckern. Also falls Dir dazu noch was einfaellt, dann lass es mich wissen. Bis hierher hast Du mir aber schon sehr geholfen. Lass es Dir gedankt sein!

Gruss (und schoenes Wochenende) JAN


----------

