Get underlying soap message of wsimport generated ws client - java

I'm in the following situation:
I use a wsdl file to generate a webservice client with wsimport.
The generated (central) class looks like this:
#WebServiceClient(...)
public class FooService extends javax.xml.ws.Service
Then I use this class to get a "port"...
Foo port = (new FooService()).getHTTPSPort();
and then I invoke the webservice...
... result = port.foo(...);
where result then will be the server's response as a java bean (with corresponding getters).
I want to obtain the underlying soap message of that result.
So far, I managed to obtain a soap message with the following approach:
I attach a handler to the port binding handler chain...
List<Handler> handlerChainCopy = ((BindingProvider) port).getBinding().getHandlerChain();
handlerChainCopy.add(...);
((BindingProvider) port).getBinding().setHandlerChain(handlerChainCopy);
where my handler looks like this
class MyHandler implements SOAPHandler<SOAPMessageContext> {
private final ByteArrayOutputStream myStream = new ByteArrayOutputStream();
public String getLastMessage(Charset charset){
return new String(this.myStream.toByteArray(), charset);
}
#Override
public boolean handleMessage(SOAPMessageContext context){
this.myStream.reset();
try {
context.getMessage().writeTo(this.myStream);
} catch (Exception ignored) { }
return true /*(don't) block processing*/;
}
...
(I guess, alternatively I could use setHandlerResolver on my fooService object - but that doesn't change my problem, see below.)
And this all works, kind of.
I am not convinced at all that proceeding like this is correct, and I haven't found any documentation that would guarantee correctness.
My main concern is synchronization between result = port.foo(...) and myHandler.getLastMessage(...).
(Of course, I have "control" over new FooService(), but the
Foo port = (new FooService()).getHTTPSPort()
object is dynamically constructed (or obtained!) from the depth of the j2ee server and I have no control whether it is shared between different FooService instances.
Is there any way to guarantee correctness?
Or maybe there is a completly different approach? (Of course, I very much would like to use what wsimport / jax-ws is providing, I don't want to manually implement the complete soap message processing and parsing chain. And I don't want to manually adjust the Result class so that it can store the message, either.)
Thanks
Thomas

Related

Java generics for setting up the default AWS clients

I would like to be able to enforce different httpClient setups and credentialsProvider for all service clients created in our AWS backend. To do this I wanted to use Java Generics.
Whenever somone creates a new service client I would like to use it like this:
S3Client s3client = setupAwsClient(S3Client.builder())
.region(Region.EU_WEST_1)
.build();
My NOT compiling impl of setupAwsClient looks like this:
public <T extends AwsSyncClientBuilder<SdkSyncClientBuilder<...>, SdkClient> & BaseClientBuilder<S3ClientBuilder, SdkClient> T setupAwsClient(T client) {
return client
.credentialsProvider(credentialsProvider)
.httpClient(awsBaseClient);
}
The problem is that there are so many interfaces I have to specify that the functions looks like a mess.
My question is: What would be the clean way to enforce some setup among all service clients in the AWS SDK? Is generics a good solution or are there better ways?
UPDATE:
public <T extends AwsSyncClientBuilder<?,?> & AwsClientBuilder<?, ?>> T setup(T clientBuilder) {
}
Trying this is not working either. Even that AwsClientBuilder provides credentialsProvider and AwsSyncClientBuilder provides httpClient.
Is this kind of what you're looking for?
public <T extends AwsSyncClientBuilder<?, ?>> T setup(T clientBuilder) {
/* Do stuff to client */
return clientBuilder;
}
Or if you want the setup method to call build:
public <C, T extends AwsSyncClientBuilder<?, C>> C setup(T clientBuilder) {
/* Do stuff to client */
return clientBuilder.build();
}
AwsSyncClientBuilder take it self or any of it's subtypes as a type params, but SdkSyncClientBuilder is not a subtype of AwsSyncClientBuilder
I think you're over-thinking this, and letting the complexity of the AWS SDK filter into your application code.
First up, do you really need the async clients? What benefit would they provide you versus combining a synchronous client and a threadpool?
Second, what are you really trying to configure? It looks like you want to let the calling code configure the region but not the credentials provider? Is there anything else that you want to allow or control?
The solution that I'd use would be a simple factory method that takes a configuration object that you define:
public static <T> T createClient(Class<T> clientKlass, MyConfigObject config)
So, based on your example you might call like this:
MyConfigObject config = new MyConfigObject().withRegion(Region.EU_WEST_1)
S3Client s3Client = createClient(S3Client.class, config)
Inside the createClient() method I would probably use a simple if-else chain to pick the appropriate builder:
if (clientKlass == S3Client.class) {
S3ClientBuilder builder = S3Client.builder();
applyConfig(builder, config);
return builder.build();
}
If you don't like if-else chains, you could use reflection to invoke the builder() method on the passed client class (and the build() method on the result).
The applyConfig() method relies on all clients deriving from AwsClientBuilder, which provides methods for common configuration:
private static void applyConfig(AwsClientBuilder builder, MyConfiguration config) {
if (config.getRegion() != null) {
builder.region(config.getRegion());
}
builder.credentialsProvider(standardCredentials);
}

Synchronizing rest service using JAVA Spring

I have a POST request that I would like to synchronize based on the incoming request body POJO. The request body has a variable by which I can identify if the incoming request is a duplicate or not.
My problem is that each incoming request body has a different reference.
I am generating some sort of confirmation number with the sample request body. I am getting multiple confirmation numbers for the same identifier(property inside SampleRequestBody class) which I don't want.
#PostMapping(value = "testingSync", headers = {"Content-type=application/json"})
public void testingSync(#RequestBody SampleRequestBody sampleRequestBody) {
synchronized(sampleRequestBody) {
//Do some process with the sample request body
}
}
The sample request body looks something like this
public class SampleRequestBody {
private String identifier;
public String getIdentifier(){
return this.identifier;
}
public void setIdentifier(String identifier){
this.identifier = identifier;
}
}
The synchronized block synchronizes calls that are using the same instance. As each call to your service will create a new instance of SampleRequestBody there is practically no synchronization.
You could synchronize on the identifier property of you request object by storing the strings in some kind of local cache in order to get the same string instance for the same identifier again:
// you should not actually use String.intern() here but some local cache
synchronized(sampleRequestBody.getIdentifier().intern()) {
//Do some process with the sample request body
}
The above example uses String.intern() just for the sake of simplicity. In a real live application using String.intern() should be avoided as it will create objects in memory that are not covered by the Java GC. That is: use a local cache instead.
You should additionally keep in mind that this synchronization will only work on a per JVM basis. That is, if you got two servers in a load balanced setup, this will not work as desired.
And one last thought: You should really rethink the need of synchronization here. Use it only if there is no other possibility to solve your requirements.
If you need a tool to synchronization by the value of the object which you can use in Spring Framework then I can suggest you XSync library.
All that you need is to add the XSync bean in your configuration:
#Configuration
public class Config{
#Bean
public XSync<String> xSync(){
return new XSync<>();
}
}
and now you can use it in your controller:
#Autowired
private XSync<String> xSync;
#PostMapping(value = "testingSync", headers = {"Content-type=application/json"})
public void testingSync(#RequestBody SampleRequestBody sampleRequestBody) {
xSync.execute(sampleRequestBody.getIdentifier(), () -> {
//Do some process with the sample request
});
}
Implementation of this library based on the WeakReference instead of String.intern.
Using String.intern here is a bad idea, you can get a deadlock and memory leaks.

Intercept SOAP RPC method response without EJB

I'm working on a project revamp for a company, where they want to split their system between front-end/client and back-end/server (more like a middleman between the front-end and the database server), and I'm supposed to use JAX-WS RPC and maintain the current functionality.
By maintaining functionality they mean that some methods are supposed to return null, which is forbidden by WS-I.
Searching for possible solutions, I stumbled upon this article: http://victor-ichim.blogspot.com.br/2011/03/rpcliteral-and-null-object-pattern.html which basically solves a similar problem by using EJB Interceptors to intercept and replace null results with empty objects.
Working around the concept, I thought of intercepting the results just like so, replacing null with something like a string template, intercepting it again on the client and replacing that template back with null.
My questions are:They don't use EJB by default, so no Interceptors per se. Is there some implementation that could work for both Tomcat and JBoss?
Even if I'm able to intercept the return server-side, how could I do it client-side?
If I can use SOAPHandlers, how can I avoid raising the SOAP Fault for trying to return null?
Since I also had problems with JAXB not handling interfaces, what I ended up doing was using the #XmlJavaTypeAdapter annotation to enable (selectively, since every return and parameter that could practically be null needs to be annotated) converting values from and back to null, in sort of a hackjob manner. I created a generic-ish adapter for Serializable objects, and followed the same sort of approach for other kinds of Objects:
public class SerializableAdapter extends XmlAdapter<String, Serializable>>{
private static final String NULL = "'NULL'"; // Will hopefully never collide
#Override
public Serializable unmarshal(String e) throws Exception {
if (e == NULL) {
return null;
}
byte [] eB = e.getBytes("ISO-8859-1");
InputStream iS = new ByteArrayInputStream(Base64.getDecoder().decode(eB));
ObjectInputStream oIS = new ObjectInputStream(iS);
return (Serializable) oIS.readObject();
}
#Override
public String marshal(Serializable o) throws Exception {
if (o == null) {
return NULL;
}
ByteArrayOutputStream bAOS = new ByteArrayOutputStream();
ObjectOutputStream oOS = new ObjectOutputStream(bAOS);
oOS.writeObject(o);
return Base64.getEncoder().encodeToString(bAOS.toByteArray());
}
}
And then annotated every Serializable instance with #XmlJavaTypeAdapter(SerializableAdapter.class) since using package-level #XmlJavaTypeAdaptersdidn't work for some reason, and so forth for other cases. JAXB seems to eagerly cast the types encoded to and from when calling the adapters, so it will compile just fine even if the object to be marshalled isn't an instance of the expected class/interface, and throw exceptions only at runtime.
I don't recommend doing it this way, since it will require annotating every single method/parameter or package, and will break at the first one that didn't get annotated and yet received null. This very adapter still serves a purpose for cases where I need to work with interfaces, and the implementing classes also implement Serializable, although there are cases that still need specific adapters, but that's usually badly thought-out code.
Partially because of the hackness of this and the hassle of annotating everything, I managed to convince the company to move away from SOAP RPC bindings, so I was able to have null parameters and returns without this.

Camel Rest DSL response encoding

I am currently working on a REST based java application using the new Camel REST DSL as the foundation.
It mostly works except that I noticed when calling the URLs through a REST client (instead of say a browser) the JSON response is "garbled" and comes through with what I assume is the wrong encoding
MyRouteBuilder.java
#Component
public class MyRouteBuilder extends RouteBuilder{
#Autowired
LocalEnvironmentBean environmentBean;
#Override
public void configure() throws Exception {
restConfiguration().component("jetty").host("0.0.0.0").port(80)
.bindingMode(RestBindingMode.auto);
rest("/testApp")
.get("/data").route()
.to("bean:daoService?method=getData")
.setProperty("viewClass", constant(CustomeJsonViews.class))
.marshal("customDataFormat").endRest()
.get("/allData").route()
.to("bean:daoService?method=getDatas")
.setProperty("viewClass", constant(CustomeJsonViews.class))
.marshal("customDataFormat").endRest();
}
}
CustomeDataFormat.java
public class CustomDataFormat implements DataFormat{
private ObjectMapper jacksonMapper;
public CustomDataFormat(){
jacksonMapper = new ObjectMapper();
}
#Override
public void marshal(Exchange exchange, Object obj, OutputStream stream) throws Exception {
Class view = (Class) exchange.getProperty("viewClass");
if (view != null)
{
ObjectWriter w = jacksonMapper.writerWithView(view);
w.writeValue(stream, obj);
}
else
stream.write(jacksonMapper.writeValueAsBytes(obj));
}
#Override
public Object unmarshal(Exchange exchange, InputStream stream) throws Exception {
return null;
}
}
A full working version can be found here:
https://github.com/zwhitten/camel-rest-test
When going to the URL, {host}/testApp/data, in Chrome for example the response comes through as:
{
data: "Sherlock",
value: "Holmes",
count: 10
}
However using the Postman browser plugin as the client returns:
"W3siZGF0YSI6ImRhdGE6OjAiLCJ2YWx1ZSI6InZhbHVlOjowIiwiY291bnQiOjB9LHsiZGF0YSI6ImRhdGE6OjEiLCJ2YWx1ZSI6InZhbHVlOjoxIiwiY291bnQiOjF9LHsiZGF0YSI6ImRhdGE6OjIiLCJ2YWx1ZSI6InZhbHVlOjoyIiwiY291bnQiOjJ9LHsiZGF0YSI6ImRhdGE6OjMiLCJ2YWx1ZSI6InZhbHVlOjozIiwiY291bnQiOjN9LHsiZGF0YSI6ImRhdGE6OjQiLCJ2YWx1ZSI6InZhbHVlOjo0IiwiY291bnQiOjR9LHsiZGF0YSI6ImRhdGE6OjUiLCJ2YWx1ZSI6InZhbHVlOjo1IiwiY291bnQiOjV9LHsiZGF0YSI6ImRhdGE6OjYiLCJ2YWx1ZSI6InZhbHVlOjo2IiwiY291bnQiOjZ9LHsiZGF0YSI6ImRhdGE6OjciLCJ2YWx1ZSI6InZhbHVlOjo3IiwiY291bnQiOjd9LHsiZGF0YSI6ImRhdGE6OjgiLCJ2YWx1ZSI6InZhbHVlOjo4IiwiY291bnQiOjh9LHsiZGF0YSI6ImRhdGE6OjkiLCJ2YWx1ZSI6InZhbHVlOjo5IiwiY291bnQiOjl9XQ=="
The problem seems to be with the REST bind mode being "auto" and using a custom marshaller.
If I set the binding mode to "json" then both the browser and client responses get garbled.
If I set the binding mode to "json" and bypass the custom marshallers everything works correctly.
Is there a way to configure the route to use a custom marshaller and encode the responses correctly regardless of the client?
I think the solution is to use the default binding option(off) since you are using custom marshallers.
You have two ways to achieve it:
Turn off the RestBindingMode, because otherwise the RestBindingMarshalOnCompletion in RestBindingProcessor will be registered and manually (un)marshal.
Register your own DataFormat and use it within the RestBinding automatically. You configure the REST configuration via jsonDataFormat to set the custom data format.
Map<String, DataFormatDefinition> dataFormats = getContext().getDataFormats();
if (dataFormats == null) {
dataFormats = new HashMap<>();
}
dataFormats.put("yourFormat", new DataFormatDefinition(new CustomDataFormat()));
restConfiguration()....jsonDataFormat("yourFormat")
You can also create your own dataformat like so:
in your restconfiguration it will look sthg like this (see json-custom)
builder.restConfiguration().component("jetty")
.host(host(propertiesResolver))
.port(port(propertiesResolver))
.bindingMode(RestBindingMode.json)
.jsonDataFormat("json-custom")
;
You must create a file "json-custom"
that's the name of the file and that file should contain the class name that implements your own way to marshal and unmarshal...
it must be located in your jar : META-INF\services\org\apache\camel\dataformat
so the content of the file should be:
class=packageofmyclass.MyOwnDataformatter
The response you were receiving is JSON, but it had been encoded to base64. Taking the String from your post, I was able to decode it as:
[{"data":"data::0","value":"value::0","count":0},{"data":"data::1","value":"value::1","count":1},{"data":"data::2","value":"value::2","count":2},{"data":"data::3","value":"value::3","count":3},{"data":"data::4","value":"value::4","count":4},{"data":"data::5","value":"value::5","count":5},{"data":"data::6","value":"value::6","count":6},{"data":"data::7","value":"value::7","count":7},{"data":"data::8","value":"value::8","count":8},{"data":"data::9","value":"value::9","count":9}]
The answers above stop the response body being encoded to base64. The documentation from Apache Camel on bindingMode is illusive as to why it behaves that way when combined with explicit marshalling. Removing the explicit marshalling will return a JSON body, but you may also notice that it contains the any class names in the body. The documentation suggests that bindingMode is more for the transportation of classes and that you specifiy a type(Pojo.class) and optionally outType(Pojo.class) of your requests/responses. See http://camel.apache.org/rest-dsl.html (section Binding to POJOs Using) for more details.
Base64 is the safest way of transferring JSON across networks to ensure it is received exactly as the server sent it, according to some posts I've read. It is then the responsibility of the client to then decode the response.
The answers above do solve the problem. However, I'm not entirely convinced that mixing the data format in the service routes is such as good thing and should ideally be at a higher level of abstraction. This would then allow the data format to be changed in one place, rather than having to change it on every route that produces JSON. Though, I must admit, I've never seen a service that has change data format in its lifetime, so this really is a mute point.
We were also facing the same issue.
Our DataFormat was Json .Once we implented our own custom marshaller. Camel was encoding the data to base64.I tried the approach provided by Cshculz but our CustomDataFormatter was not getting called for some reason which i couldn't figure out.
So We added .marshal(YourDataFormatter) after every Bean call.This provided us with the formatted json but in the encoded form so in the end of the route we added .unmarshal().json(JsonLibrary.Jackson) to return a raw json to the client.
sample snippet :-
.to("xxxxxxx").marshal(YourDataFormatterBeanRef)
.to("xxxxxxx").marshal(YourDataFormatterBeanRef)
.to("xxxxxxx").marshal(YourDataFormatterBeanRef)
.to("xxxxxxx").marshal(YourDataFormatterBeanRef)
.end().unmarshal().json(JsonLibrary.Jackson)

Does GWT RequestFactory support implementation of optimistic concurrency control?

In a GWT app I present items that can be edited by users. Loading and saving the items is perfomed by using the GWT request factory. What I now want to achive is if two users concurrently edit an item that the user that saves first wins in the fashion of optimistic concurrency control. Meaning that when the second user saves his changes the request factory backend recognizes that the version or presence of the item stored in the backend has changed since it has been transfered to the client and the request factory/backend then somehow prevents the items from being updated/saved.
I tried to implement this in the service method that is used to save the items but this will not work because request factory hands in the items just retrieved from the backend with applied user's changes meaning the versions of these items are the current versions from the backend and a comparison pointless.
Are there any hooks in the request factory processing I coud leverage to achieve the requested behaviour? Any other ideas? Or do I have to use GWT-RPC instead...
No: http://code.google.com/p/google-web-toolkit/issues/detail?id=6046
Until the proposed API is implemented (EntityLocator, in comment #1, but it's not clear to me how the version info could be reconstructed from its serialized form), you'll have to somehow send the version back to the server.
As I said in the issue, this cannot be done by simply making the version property available in the proxy and setting it; but you could add another property: getting it would always return null (or similar nonexistent value), so that setting it on the client-side to the value of the "true" version property would always produce a change, which guaranties the value will be sent to the server as part of the "property diff"; and on the server-side, you could handle things either in the setter (when RequestFactory applies the "property diff" and calls the setter, if the value is different from the "true" version, then throw an exception) or in the service methods (compare the version sent from the client –which you'd get from a different getter than the one mapped on the client, as that one must always return null– to the "true" version of the object, and raise an error if they don't match).
Something like:
#ProxyFor(MyEntity.class)
interface MyEntityProxy extends EntityProxy {
String getServerVersion();
String getClientVersion();
void setClientVersion(String clientVersion);
…
}
#Entity
class MyEntity {
private String clientVersion;
#Version private String serverVersion;
public String getServerVersion() { return serverVersion; }
public String getClientVersion() { return null; }
public void setClientVersion(String clientVersion) {
this.clientVersion = clientVersion;
}
public void checkVersion() {
if (Objects.equal(serverVersion, clientVersion)) {
throw new OptimisticConcurrencyException();
}
}
}
Note that I haven't tested this, this is pure theory.
We came up with another workaround for optimistic locking in our app. Since the version can't be passed with the proxy itself (as Thomas explained) we are passing it via HTTP GET parameter to the request factory.
On the client:
MyRequestFactory factory = GWT.create( MyRequestFactory.class );
RequestTransport transport = new DefaultRequestTransport() {
#Override
public String getRequestUrl() {
return super.getRequestUrl() + "?version=" + getMyVersion();
}
};
factory.initialize(new SimpleEventBus(), transport);
On the server we create a ServiceLayerDecorator and read version from the RequestFactoryServlet.getThreadLocalRequest():
public static class MyServiceLayerDecorator extends ServiceLayerDecorator {
#Override
public final <T> T loadDomainObject(final Class<T> clazz, final Object domainId) {
HttpServletRequest threadLocalRequest = RequestFactoryServlet.getThreadLocalRequest();
String clientVersion = threadLocalRequest.getParameter("version") );
T domainObject = super.loadDomainObject(clazz, domainId);
String serverVersion = ((HasVersion)domainObject).getVersion();
if ( versionMismatch(serverVersion, clientVersion) )
report("Version error!");
return domainObject;
}
}
The advantage is that loadDomainObject() is called before any changes are applied to the domain object by RF.
In our case we're just tracking one entity so we're using one version but approach can be extended to multiple entities.

Categories