Using WebServiceGatewaySupport to handle requests to multiple webservices - soap

I'm using spring-ws-core to build a SOAP client. For this I'm extending WebServiceGatewaySupport to make the service calls.
public class WeatherClient extends WebServiceGatewaySupport {
...
public WeatherResponse getCityForecastByZip(String zipCode) {
GetCityForecastByZIP request = new GetCityForecastByZIP();
request.setZIP(zipCode);
GetCityForecastByZIPResponse response = (GetCityForecastByZIPResponse) this.getWebServiceTemplate().marshalSendAndReceive(request,
new SoapActionCallback("http://ws.cdyne.com/WeatherWS/GetCityForecastByZIP"));
return response;
}
...
}
Spring configuration is pretty straightforward
#Configuration
public class WebServicesConfiguration {
private static final String WEATHER_SERVICE_DEFAULT_URI = "...";
#Bean(name = "servicesMarshaller")
public Jaxb2Marshaller servicesMarshaller() {
Jaxb2Marshaller marshaller = new Jaxb2Marshaller();
marshaller.setContextPath("some.package");
return marshaller;
}
#Bean
public WeatherClient weatherService(#Qualifier("servicesMarshaller") Jaxb2Marshaller marshaller) {
WeatherClient client = new WeatherClient(WEATHER_SERVICE_DEFAULT_URI);
client.setMarshaller(marshaller);
client.setUnmarshaller(marshaller);
return client;
}
}
This works just fine for a single web service. Now, suppose that I have many similar web services, but each one has it's own .wsdl specification and URI. I know that I can make a service call through the spring WebServiceTemplate and specify the URI to use. So my idea was to use a single WebServiceGatewaySupport to handle all the calls to the different services. In each call, I would pass the soap action, the corresponding request, if any, and the web service URL. My application is suppose to run in a multi-threaded environment.
Is this a good practice to use a single WebServiceGatewaySupport to handle concurrent calls to different URIs?

Looking to the WebServiceGatewaySupport source code, the short asnwer: yes, it is OK to use it for different URLs, as well as the underlying WebServiceTemplate is thread-safe.
Your implementation will be thread-safe too, if you don't save some state between requests.

Related

Axon Framework - Configuring Multiple EventStores in Axon Configuration

We are having an usecase wherein each aggregate root should have different eventstores. We have used the following configuration where currently , we have only one event-store configured as below
#Configuration
#EnableDiscoveryClient
public class AxonConfig {
private static final String DOMAIN_EVENTS_COLLECTION_NAME = "coll-capture.domainEvents";
//private static final String DOMAIN_EVENTS_COLLECTION_NAME_TEST =
//"coll-capture.domainEvents-test";
#Value("${mongodb.database}")
private String databaseName;
#Value("${spring.application.name}")
private String appName;
#Bean
public RestTemplate restTemplate() {
CloseableHttpClient httpClient = HttpClientBuilder.create().build();
HttpComponentsClientHttpRequestFactory clientHttpRequestFactory = new
HttpComponentsClientHttpRequestFactory(httpClient);
return new RestTemplate(clientHttpRequestFactory);
}
#Bean
#Profile({"uat", "prod"})
public CommandRouter springCloudHttpBackupCommandRouter(DiscoveryClient discoveryClient,
Registration localInstance,
RestTemplate restTemplate,
#Value("${axon.distributed.spring-
cloud.fallback-url}") String messageRoutingInformationEndpoint) {
return new SpringCloudHttpBackupCommandRouter(discoveryClient,
localInstance,
new AnnotationRoutingStrategy(),
serviceInstance -> appName.equalsIgnoreCase(serviceInstance.getServiceId()),
restTemplate,
messageRoutingInformationEndpoint);
}
#Bean
public Repository<TestEnquiry> testEnquiryRepository(EventStore eventStore) {
return new EventSourcingRepository<>(TestEnquiry.class, eventStore);
}
#Bean
public Repository<Test2Enquiry> test2enquiryRepository(EventStore eventStore) {
return new EventSourcingRepository<>(Test2Enquiry.class, eventStore);
}
#Bean
public EventStorageEngine eventStorageEngine(MongoClient client) {
MongoTemplate mongoTemplate = new DefaultMongoTemplate(client, databaseName)
.withDomainEventsCollection(DOMAIN_EVENTS_COLLECTION_NAME);
return new MongoEventStorageEngine(mongoTemplate);
}
}
Now , We want to configure "DOMAIN_EVENTS_COLLECTION_NAME_TEST"(just for example) as well in EventStorageEngine. How we can achieve the same support for multiple event-stores and select the tracking process as which collection they should be part of
If you are going the route of segregating the event streams, then combining them from an event handling perspective could become a necessity indeed. Especially when having several bounded contexts, segregating the event streams into distinct storage solutions is reasonable.
If you want to define which [message source / event store] is used by a TrackingEventProcessor, you will have to deal with the EventProcessingConfigurer. More specifically, you should invoke the EventProcessingConfigurer#registerTrackingEventProcessor(String, Function<Configuration, StreamableMessageSource<TrackedEventMessage<?>>>) method. The first String parameter is the name of the processor you want to configure as being "tracking". The second parameter defines a Function which gives you the message source to be used by this TrackingEventProcessor (TEP). It is here where you should provide the event store you want this TEP to ingest events from.
Pairing them up at a later stage could also occur of course, which is also supported by Axon Framework. This boils down to a specific form of StreamableMessageSource implementation.
More specifically, you can use the MultiStreamableMessageSource, where you can connect any number of StreamableMessageSources together.
Note that Axon's EmbeddedEventStore is in essence an implementation of a StreamableMessageSource. Once the MultiStreamableMessageSource, you will have to specify it as the messageSource for your TrackingEventProcessors of course.
Last note, know that this solution can only be used when you are using TrackingEventProcessors, as those are the only Event Processors provided by Axon ingesting a StreamableMessageSource as the source for it's events.

Dumping bad requests

I have a service implemented with Dropwizard and I need to dump incorrect requests somewhere.
I saw that there is a possibility to customise the error message by registering ExceptionMapper<JerseyViolationException>. But I need to have the complete request (headers, body) and not only ConstraintViolations.
You can inject ContainerRequest into the ExceptionMapper. You need to inject it as a javax.inject.Provider though, so that you can lazily retrieve it. Otherwise you will run into scoping problems.
#Provider
public class Mapper implements ExceptionMapper<ConstraintViolationException> {
#Inject
private javax.inject.Provider<ContainerRequest> requestProvider;
#Override
public Response toResponse(ConstraintViolationException ex) {
ContainerRequest request = requestProvider.get();
}
}
(This also works with constructor argument injection instead of field injection.)
In the ContainerRequest, you can get headers with getHeaderString() or getHeaders(). If you want to get the body, you need to do a little hack because the entity stream is already read by Jersey by the time the mapper is reached. So we need to implement a ContainerRequestFilter to buffer the entity.
public class EntityBufferingFilter implements ContainerRequestFilter {
#Override
public void filter(ContainerRequestContext containerRequestContext) throws IOException {
ContainerRequest request = (ContainerRequest) containerRequestContext;
request.bufferEntity();
}
}
You might not want this filter to be called for all requests (for performance reasons), so you might want to use a DynamicFeature to register the filter just on methods that use bean validation (or use Name Binding).
Once you have this filter registered, you can read the body using ContainerRequest#readEntity(Class). You use this method just like you would on the client side with Response#readEntity(). So for the class, if you want to keep it generic, you can use String.class or InputStream.class and convert the InputStream to a String.
ContainerRequest request = requestProvider.get();
String body = request.readEntity(String.class);

Retrieving additional non DB information using Spring Data Rest

I am using Spring Data Rest to expose a news feed REST API. I want to add an image (location) to the entity which will be retrieved by a separate web service API call.
What is the best way to do this using Spring Data Rest or would I have to create another separate REST API call/domain object etc.?
Any sample code would be fantastic.
You should use a ResourceProcessor
The Spring Data REST exporter executes any discovered ResourceProcessor's before it creates the output representation
#Bean
public ResourceProcessor<Resource<MyEntity>> myEntityProcessor() {
return new ResourceProcessor<Resource<MyEntity>>() {
#Override
public Resource<MyEntity> process(Resource<MyEntity> resource) {
resource.add(new Link("http://localhost:8080/images/images.jpg", "image"));
return resource;
}
};
}
Another example with access to the repository and EntityLinks object that helps to build links related to the entity..
#Component
class MyEntityResourceProcessor implements ResourceProcessor<Resource<MyEntity>> {
#Autoware
private MyEntityRepo repo;
#Autoware
private EntityLinks entityLinks;
#Override
public Resource<MyEntity> process(Resource<MyEntity> resource) {
MyEntity entity = resource.getContent();
// Some entity processing...
Link link entityLinks.linkForSingleResource(entity).slash("...").withRel("...")
resource.add(link);
return resource;
}
}
More examples of using ResourceProcessor you can find in RESTBucks project

How to call another restapi from rest api in same process using restEasy

I have rest api '/users/{id}/checkin' in which i want to do some processing and call another rest api on different resource but in same service. For example.
ServiceResource.java
#GET
#path(/services/checkin/)
public Response checkinUser(User user)
{
// --- processing.
}
UserResource.Java
#POST
#path(/users/{id}/checkin/)
public Response verifyUser(#PathParam("id) String id)
{
// --- Get the users from the iD.
User user = getUsers(id);
// --- need to call service from the serviceResource.
}
Any idea how to do it? as i want to avoid the HTTPclient call.
Put all method definitions and the resteasy annotations in an interface and use this interface as input to the resteasy proxy framework.
See documentation for details.
ServiceResourceIF.java:
public interface ServiceResourceIF {
#GET
#path(/services/checkin/)
public Response checkinUser(User user);
}
The calling code could look like this (stolen from the original documentation of resteasy, see link above):
User = new User(...);
Client client = ClientBuilder.newClient();
WebTarget target = client.target("http://your.service.url/base/uri");
ResteasyWebTarget rtarget = (ResteasyWebTarget)target;
ServiceClient service = rtarget.proxy(ServiceResourceIF.class);
service.checkinUser(user);
Note: You can use the same interface to configure the client and server.

Unit tests for simple REST client [duplicate]

This question already has answers here:
Need some advice for trying to mock a .NET WebClient or equivalent
(2 answers)
Closed 6 years ago.
Let's assumed that i've got simple method which gets some data from REST service. Method looks like:
public string GetDataFromRest(string uri) {
string result = String.Empty;
using(WebClient web = new WebClient()) {
result = web.DownloadString(uri);
}
return result;
}
So, now i want to create unit test for this method. I don't want to use external REST service but i want fake response from any URI without real conecting to service. Something like every execute of GetDataFromRest(uri) in Unit Test -> always returns some XML.
As the posted answer goes into some detail, part of your problem is you have a dependency on the WebClient class.
A sample wrapper for WebClient could look like:
public interface IWebClient
{
string DownloadString(string address);
}
public class WebClientWrapper : IWebClient
{
public string DownloadString(string address)
{
using(WebClient web = new WebClient()) {
return result = web.DownloadString(uri);
}
}
}
public class MyClass
{
private readonly IWebClient _webClient;
public MyClass(IWebClient webClient)
{
_webClient = webClient;
}
public string GetDataFromRest(string uri)
{
return _webClient.DownloadString(uri);
}
}
Now of course going this route means WebClientWrapper can be unit tested with a "less real" URI or what that you specifically control. I've only implemented one method of the WebClient, but this externalizes the dependency within GetDataFromRest from a real URI, as you can now mock the return data. This also helps in that anything else you need a WebClient for, you can now use the wrapper class, and easily mock the returned data, as you are now programming to an interface, rather than a concretion.