Radar: Dechunk mit mod_proxy

fundstücke

Aus aktuellem Anlass beschäftige ich mich gerade mit dem Chunken von HTTP-Requests. Trotz etlicher Jahre auf dem Spezifikationsbuckel ist noch nicht jeder Server-Dienst dazu in der Lage.

Eine sehr einfache Lösung ist das “Dechunken” mit dem Modul mod_proxy von Apache. Wie das Ganze funktioniert, liest Ihr hier:

http://atnan.com/blog/2008/08/08/transfer-encoding-chunked-or-chunky-http

Apache CXF – Falscher Service-Name

java-duke

Problemstellung

Apache CXF ist ein umfangreiches und komfortables Framework zur Erstellung als auch Anbindung von SOAP-Services. Der Entwickler kann grundsätzlich zwischen den Ansätzen Code-First und WSDL-First auswählen.

Beim Code-First-Ansatz erstellt der Entwickler die Service-Klassen direkt und konfiguriert die Schnittstelle mit Hilfe von Annotationen. Dieser Ansatz ermöglicht eine schnelle Entwicklung und ist vorteilhaft, wenn die Implementierung für den Client und Server aus einer Hand erstellt werden.

Beim WSDL-First-Ansatz wird die SOAP-Schnittstelle im Vorfeld mit Hilfe formalen Schnittstellenbeschreibung in Form einer SOAP-WSDL definiert. Diese wird im Idealfall zu Beginn der Implementierung zwischen den Kommunikationspartnern abgestimmt und dient als Basis für den zu erstellenden Webservice. Mit Hilfe dem Maven-Plugin cxf-codegen-plugin von Apache CXF können die nötigen Klassen zur Bereitstellung des Services generiert werden.

Beispiel:

<plugin>
	<groupId>org.apache.cxf</groupId>
	<artifactId>cxf-codegen-plugin</artifactId>
	<version>${cxf.version}</version>
	<executions>
		<execution>
			<id>generate-sources</id>
			<phase>generate-sources</phase>
			<goals>
				<goal>wsdl2java</goal>
			</goals>
		</execution>
	</executions>
	<configuration>
		<defaultOptions>
			<noAddressBinding>true</noAddressBinding>
		</defaultOptions>
		<wsdlOptions>
			<wsdlOption>
				<wsdl>${cxf.wsdl.path}/FoobarService.wsdl</wsdl>
			</wsdlOption>
	</configuration>
</plugin>

Das Plugin erstellt im Ornder ${MODULE_PATH}/target/generated-sources/cxf die Klassen, die für das Mapping der Ein- sowie Ausgabeparameter zuständig sind. Desweiteren erstellt das Plugin die Interfaces für die zu implemtierenden Webservices-Endpoints.

Aus dem Endpoint-Einbtrag in der WSDL

<wsdl:service name="FoobarService">
	<wsdl:port name="FoobarPort" binding="tns:FoobarPortBinding">
		<wsoap12:address location="http://localhost:8080/FoobarServer/Foobar"/>
	</wsdl:port>
</wsdl:service>

erzeugt cxf-codegen-plugin das Endpoint-Interface

@WebService(targetNamespace = "http://webservice.foobar.systemfeld.de/", name = "FoobarService")
@XmlSeeAlso({de.systemfeld.foobar.common.ObjectFactory.class, ObjectFactory.class})
public interface FoobarService{
    // my foobar method declaration
}

Dieses Interface wird im nächsten Schritt in einer eigenen Endpoint-Klasse implementiert. Nennen wir diese Klasse FoobarServiceImpl. Wird die WSDL von außen über den laufenden Service abgefragt (Beispiel: http://localhost:8080/soap?wsdl), generiert Apache CXF die WSDL anhand der Annoationen des zuvor generierten Endpoint-Interfaces Foobar.

Doch anstatt des erwarteten Eintrag für den Service-Namen FoobarService steht in der generierten WSDL:

<wsdl:service name="FoobarServiceImpl">

Wieso generiert Apache CXF auf einmal einen verkehrten Service-Namen? Dies liegt an einer internen fehlerhaften Auswertung der Annotation @WebService. Das Plugin cxf-codegen-plugin schreibt dort den Service-Namen nur in die Property name:

@WebService(targetNamespace = "http://webservice.foobar.systemfeld.de/", name = "FoobarService")

Diese Property wird jedoch von Apache später bei der Initialisierung des Endpoints gar nicht ausgwertet. Apache CXF erwartet den Service-Namen allein in der Annotation @WebService unter der Property serviceName. Da diese nicht gesetzt ist, wird als Default der Klassenname der Endpoint-Implementierung ausgewertet.

Lösung

Als Lösung bietet sich das Ergänzen in dem Hinzufügen einer eigenen @WebService-Annotation in der Implementierungsklasse FoobarServiceImpl an, in die der gewünschte Werte manuel gesetzt wird:

@Service("researchBatch")
@WebService(serviceName="FoobarService", targetNamespace = "http://webservice.foobar.systemfeld.de/")
public class FoobarServiceImpl implements FoobarService{

 // Endpoint implementation here

}

Fertig! Bei einem erneuten Aufruf der WSDL wird jetzt der gewünschte Service-Name angezeigt.

Quellen

Apache CXF: http://cxf.apache.org/

cxf-codegen-plugin: http://cxf.apache.org/docs/maven-cxf-codegen-plugin-wsdl-to-java.html

 

Maven-Settings in IntelliJ Idea setzen

java-duke

Wer mit IntelliJ Idea arbeitet und für Maven-Aufrufe den verfügbaren Speicher hoch setzen muss, kann dies auch direkt in Idea erledigen. Dazu muss der Menupunkt File/Settings geöffnet werden.

In der Settings-Box links Maven>Runner anklicken. In dem rechten Bereich sind die Optionen für die JRE einzustellen, die für die Maven-Aufrufe unter Idea gewünscht sind (hier z.B. die VM-Parameter -Xmx und -XX:MaxPermSize) :

Idea Maven-Settings