Java generics for setting up the default AWS clients - java

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);
}

Related

Dependency injection of IHttpContextAccessor vs passing parameter up the method chain

Our application calls many external API's which take a session token of the current user as input. So what we currently do is in a controller, get the session token for the user and pass it into a service which in turn might call another service or some API client. To give an idea, we end up with something like this (example is .NET but something similar is I think possible in Java)
public IActionResult DoSomething(string something)
{
this.someService.DoSomethingForUser(this.HttpContext.SessionToken, something);
return View();
}
And then we have
public class SomeService
{
private readonly IApiClient apiClient;
public SomeService(IApiClient apiClient)
{
this.apiClient = apiClient;
}
public void DoSomethingForUser(string sessionToken, something)
{
this.apiClient.DoSomethingForUser(sessionToken, something);
}
}
It can also happen that in SomeService another service is injected which in turn calls the IApiClient instead of SomeService calling IApiClient directly, basically adding another "layer".
We had a discussion with the team if it isn't better to instead of passing the session token, inject it using DI so you get something like this:
public IActionResult DoSomething(string something)
{
this.someService.DoSomethingForUser(something);
return View();
}
And then we have
public class SomeService
{
private readonly IUserService userService;
private readonly IApiClient apiClient;
public SomeService(IUserService userService, IApiClient apiClient)
{
this.userService = userService;
this.apiClient = apiClient;
}
public void DoSomethingForUser(string something)
{
this.apiClient.DoSomethingForUser(userService.SessionToken, something);
}
}
The IUserService would have an IHttpContextAccessor injected:
public class UserService : IUserService
{
private readonly IHttpContextAccessor httpContextAccessor;
public UserService(IHttpContextAccessor httpContextAccessor)
{
this.httpContextAccessor = httpContextAccessor;
}
public string SessionToken => httpContextAccessor.HttpContext.SessionToken;
}
The benefits of this pattern are I think pretty clear. Especially with many services, it keeps the code "cleaner" and you end up with less boilerplate code to pass a token around.
Still, I don't like it. To me the downsides of this pattern are more important than its benefit:
I like that passing the token in the methods is concise. It is clear that the service needs some sort of authentication token for it to function. I'm not sure if you can call it a side effect but the fact that a session token is magically injected three layers deep is impossible to tell just by reading the code
Unit testing is a bit more tedious if you have to Mock the IUserService
You run into problems when calling this in another thread, e.g. calling SomeService from another thread. Although these problems can be mitigated by injecting another concrete type of IUserService which gets the token from some place else, it feels like a chore.
To me it strongly feels like an anti pattern but apart from the arguments above it is mostly a feeling. There was a lot of discussion and not everybody was convinced that it was a bad idea. Therefor, my question is, is it an anti pattern or is it perfectly valid? What are some strong arguments for and against it, hopefully so there can be not much debate that this pattern is indeed, either perfectly valid or something to avoid.
I would say the main point is to enable your desired separation of concerns. I think it is a good question if expressed in those terms. As Kit says, different people may prefer different solutions.
REQUEST SCOPED OBJECTS
These occur quite naturally in APIs. Consider the following example, where a UI calls an Orders API, then the Orders API forwards the JWT to an upstream Billing API. A unique Request ID is also sent, in case the flow experiences a temporary problem. If the flow is retried, the Request ID can be used by APIs to prevent data duplication. Yet business logic should not need to know about either the Request ID or the JWT.
BUSINESS LOGIC CLASS DESIGN
I would start by designing my logic classes with my desired inputs, then work out the DI later. In my example the OrderService class might use claims to get the user identity and also for authorization. But I would not want it to know about HTTP level concerns:
public class OrderService
{
private readonly IBillingApiClient billingClient;
public OrderService(IBillingApiClient billingClient, ClaimsPrincipal user)
{
this.billingClient = billingClient;
}
public async void CreateOrder(OrderInput data)
{
this.Authorize();
var order = this.CreateOrder(data);
await this.billingClient.CreateInvoice(order);
}
}
DI SETUP
To enable my preferred business logic, I would write a little DI plumbing, so that I could inject request scoped dependencies in my preferred way. First, when the app starts, I would create a small middleware class. This will run early in the HTTP request pipeline:
private void ConfigureApiMiddleware(IApplicationBuilder api)
{
api.UseMiddleware<ClientContextMiddleware>();
}
In the middleware class I would then create a ClientContext object from runtime data. The OrderService class will run later, after next() is called:
public class ClientContextMiddleware
{
public async Task Invoke(HttpContext context)
{
var jwt = readJwt(context.Request);
var requestId = readRequestId(context.Request);
var holder = context.RequestServices.GetService<ClientContextHolder>();
holder.ClientContext = new ClientContext(jwt, requestIO);
await this.next(context);
}
}
In my DI composition at application startup I would express that the API client should be created when it is first referenced. In the HTTP request pipeline, the OrderService request scoped object will be constructed after the middleware has run. The below lambda will then be invoked:
private void RegisterDependencies(IServiceCollection services)
{
this.services.AddScoped<IApiClient>(
ctx =>
{
var holder = ctx.GetService<ClientContextHolder>();
return new ApiClient(holder.context);
});
this.services.AddScoped<ClientContextHolder>();
}
The holder object is just due to a technology limitation. The MS stack does not allow you to create new request scoped injectable objects at runtime, so you have to update an existing one. In a previous .NET tech stack, the concept of child container per request was made available to developers, so the holder object was not needed.
ASYNC AWAIT
Request scoped objects are stored against the HTTP request object, which is the correct behaviour when using async await. The current thread ID may switch, eg from 4 to 6 after the call to the Billing API.
If the OrderService class has a transient scope, it could get recreated when the flow resumes on thread 6. If this is the case, then resolution will continue to work.
SUMMARY
Designing inputs first, then writing some support code if needed is a good approach I think, and it is also useful to know the DI techniques. Personally I think natural request scoped objects that need to be created at runtime should be usable in DI. Some people may prefer a different approach though.
See in dotnet the area that I am an expert is not an anti standard on the contrary it is the model that many adopt but it is not a model that I would follow for the following reasons
it is not clear where is the token for those who read and use it being an anti clean code
you load important information in a place that is frequently accessed by the framework in the case of .netCore
your classes will reference a large property carrying a lot of unnecessary information when you could have created a more clean model that costs less memory and allocation time, I'm saying this because the HttpAcessor carries all the information relevant to your request
As I would take care of readability (clean code) and improve my performance
I would make a middleware or filter in my flow mvc where I would do the authentication part and create a class like:
public class TokenAuthenciationValues
{
public string TokenClient { get; set; }
public string TokenValue { get; set; }
}
Of course my method is an example but in my middleware I would implement it by loading its token values ​​after calling the necessary apis (of course this model needs an interface and it needs to be configured as .AddScoped() in the case of .net)
That way I would use it in my methods only instantiating my ITokenAuthenciationValues ​​in the constructor and I would have clear and clean information loaded in memory during the entire request
If it is necessary in the middle of the request to change the token any class can access it and change its value
I would have less memory allocated unused in my classes since the IHttpAcessor contract the ITokenAuthenciationValues ​​only has relevant information
Hope this helps

Get underlying soap message of wsimport generated ws client

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

Subscribe to an Observable without triggering it and then passing it on

This could get a little bit complicated and I'm not that experienced with Observables and the RX pattern so bear with me:
Suppose you've got some arbitrary SDK method which returns an Observable. You consume the method from a class which is - among other things - responsible for retrieving data and, while doing so, does some caching, so let's call it DataProvider. Then you've got another class which wants to access the data provided by DataProvider. Let's call it Consumer for now. So there we've got our setup.
Side note for all the pattern friends out there: I'm aware that this is not MVP, it's just an example for an analogous, but much more complex problem I'm facing in my application.
That being said, in Kotlin-like pseudo code the described situation would look like this:
class Consumer(val provider: DataProvider) {
fun logic() {
provider.getData().subscribe(...)
}
}
class DataProvider(val sdk: SDK) {
fun getData(): Consumer {
val observable = sdk.getData()
observable.subscribe(/*cache data as it passes through*/)
return observable
}
}
class SDK {
fun getData(): Observable {
return fetchDataFromNetwork()
}
}
The problem is, that upon calling sdk.subscribe() in the DataProvider I'm already triggering the Observable's subscribe() method which I don't want. I want the DataProvider to just silently listen - in this example the triggering should be done by the Consumer.
So what's the best RX compatible solution for this problem? The one outlined in the pseudo code above definitely isn't for various reasons one of which is the premature triggering of the network request before the Consumer has subscribed to the Observable. I've experimented with publish().autoComplete(2) before calling subscribe() in the DataProvider, but that doesn't seem to be the canonical way to do this kind of things. It just feels hacky.
Edit: Through SO's excellent "related" feature I've just stumbled across another question pointing in a different direction, but having a solution which could also be applicable here namely flatMap(). I knew that one before, but never actually had to use it. Seems like a viable way to me - what's your opinion regarding that?
If the caching step is not supposed to modify events in the chain, the doOnNext() operator can be used:
class DataProvider(val sdk: SDK) {
fun getData(): Observable<*> = sdk.getData().doOnNext(/*cache data as it passes through*/)
}
Yes, flatMap could be a solution. Moreover you could split your stream into chain of small Observables:
public class DataProvider {
private Api api;
private Parser parser;
private Cache cache;
public Observable<List<User>> getUsers() {
return api.getUsersFromNetwork()
.flatMap(parser::parseUsers)
.map(cache::cacheUsers);
}
}
public class Api {
public Observable<Response> getUsersFromNetwork() {
//makes https request or whatever
}
}
public class Parser {
public Observable<List<User>> parseUsers(Response response) {
//parse users
}
}
public class Cache {
public List<User> cacheUsers(List<User> users) {
//cache users
}
}
It's easy to test, maintain and replace implementations(with usage of interfaces). Also you could easily insert additional step into your stream(for instance log/convert/change data which you receive from server).
The other quite convenient operator is map. Basically instead of Observable<Data> it returns just Data. It could make your code even simpler.

Can we mock a method in service while testing the service itself?

I am working on a project where I am using MyBatis annotations as persistence framework. Therefore, I have to create an interface for the 'mapper' and compose the mapper in the service like :
class XYZServiceImpl{
public XYZMapper getXYZMapper(){
return SessionUtil.getSqlSession().getMapper(XYZMapper.class)
}
}
Now while unit testing the service with Mockito, I am trying to inject a mock for the mapper. But since I am injecting mock in an instance of XYZService, how can mock a method of the service itself, in this case getXYZMapper() is what I am trying to stub. Although I have got a solution of creating the instance XYZMapper in the service and not call on demand like the above code does something like :
Class XYZServiceImpl{
XYZMapper mapper;
public void useXYZMapper(){
mapper = SessionUtil.getSqlSession().getMapper(XYZMapper.class);
}
}
But that would bring a lot of code changes (ofcourse I can refactor) but is there a way to achieve without having to make code changes?
Also what would be a 'purist' way to have a mapper instance in the class is it the method 1 that is better than method 2 in terms of performance?
EDIT : Here XYZMapper is an interface. Something like :
public interface XYZMapper{
#Select("SELECT * FROM someclass WHERE id = #{id}")
public SomeClass getSomeClass(int id);
}
EDIT : I am facing a similar situation but with a variance that I have a service that I do want to test like XYZServiceImpl. Now it has a method getXYZDetails() which has a lot of business logic handled within the service. Now if getXYZDetails looks like the following :
public XYZDetails getXYZDetails(int id){
XYZDetails details = new XYZDetails();
details.set1Details(fetchSet1Details(id));
//Perform some business logic
details.set2Details(fetchSet2Details(id));
if(details.set2Details() != null){
for(int i = 0; i < details.set2Details().size(); i++){
flushTheseDetails(i);
}
}
.
.
}
Kindly notice that fetchSet1Details(), fetchSet2Details(), flushTheseDetails are public service, public and private service respectively.
I want to know of a method that can mock/stub these methods while testing getXYZDetails() thus enabling me to
There are several options you can use.
Inject dependency
This works only for simple methods like getXYZMapper when method only returns external dependency of you object. This may require to create new XYZServiceImpl instances if for example mapper is bound to connection which is opened per request.
Encapsulate method behavior in object
Another way to achieve similar result is to use a factory or service locator
like this:
public class XYZServiceImpl {
public XYZServiceImpl(XYZMapperFactory mapperFactory) {
this.mapperFactory = mapperFactory;
}
public XYZMapper getXYZMapper() {
return mapperFactory.getMapper();
}
}
This will allow you easily substitute factory in test with implementation which returns mock mapper.
The similar approach can be used for other methods fetchSet1Details, fetchSet2Details, flushTheseDetails that is moving them to other class or classes. If the method contains complex (and may be loosely related) logic it is a good candidate to be moved in separate class. Think about what these methods do. Usually you can move some essential and unrelated part of them to other class or classes and this makes mocking them much easier.
Subclass
This is not recommended but in legacy code sometimes is very helpful as a temporary solution.
In your test subclass you class under test and override methods you need:
#Test
public void someTest() {
XYZServiceImpl sut = new XYZServiceImpl() {
public XYZMapper getXYZMapper() {
return mapperMock;
}
public Whatever fetchSet1Details() {
return whateverYouNeedInTest;
}
}
sut.invokeMethodUnderTest();
}
The only thing you may need to do is to change access modifier of private method to package-private or protected so you can override them.
Spying
This method in also discouraged but you can use mockito spies:
XYZServiceImpl realService = new XYZServiceImpl();
XYZServiceImpl spy = Mockito.spy(realService);
when(spy.fetchSet1Details()).thenReturn(whaeveryouneed);
when(spy.getXYZMapper()).thenReturn(mockMapper);
spy.methodUnderTest();
I would suggest the "purist" way of doing this is to accept an XYZMapper instance in your constructor and store it in a local field.
In production use, you can pass an e.g. SQLXYZMapper, which will interact with your database. In test use, you can pass in a mocked object that you can verify interactions with.

mock https request in java

Let's say I'm writing an application and I need to be able to do something like this:
String url = "https://someurl/";
GetMethod method = new GetMethod(URLEncoder.encode(url));
String content = method.getResponseBodyAsString();
Is there a way to provide a mock server that would let me handle the https request? What I'm looking for is a way to write unit tests, but I need to be able to mock the part that actually goes out to https://someurl so I can get a known response back.
Take a look at jadler (http://jadler.net), an http stubbing/mocking library I've been working on for some time. The 1.0.0 stable version has been just released, it should provide the capabilities you requested:
#Test
public void getAccount() {
onRequest()
.havingMethodEqualTo("GET")
.havingURIEqualTo("/accounts/1")
.havingBody(isEmptyOrNullString())
.havingHeaderEqualTo("Accept", "application/json")
.respond()
.withTimeout(2, SECONDS)
.withStatus(200)
.withBody("{\"account\":{\"id\" : 1}}")
.withEncoding(Charset.forName("UTF-8"))
.withContentType("application/json; charset=UTF-8");
final AccountService service = new AccountServiceRestImpl("http", "localhost", port());
final Account account = service.getAccount(1);
assertThat(account, is(notNullValue()));
assertThat(account.getId(), is(1));
}
#Test
public void deleteAccount() {
onRequest()
.havingMethodEqualTo("DELETE")
.havingPathEqualTo("/accounts/1")
.respond()
.withStatus(204);
final AccountService service = new AccountServiceRestImpl("http", "localhost", port());
service.deleteAccount(1);
verifyThatRequest()
.havingMethodEqualTo("DELETE")
.havingPathEqualTo("/accounts/1")
.receivedOnce();
}
You essentially have two options:
1. Abstract the call to the framework and test this.
E.g. refactor the code to allow you to inject a mock implementation at some point. There are many ways to do this. e.g. create a getUrlAsString() and mock that. (also suggested above). Or create a url getter factory that returns a GetMethod object. The factory then can be mocked.
2. Start up a app server as part of the test and then run your method against it. (This will be more of an integration test)
This can be achieved in an number of ways. This can be external to the test e.g. the maven jetty plugin. or the test can programmatically start up the server. see: http://docs.codehaus.org/display/JETTY/Embedding+Jetty
Running it over https will complicate this but it will still be possible with self signed certs. But I'd ask yourself - what exactly you want to test? I doubt you actually need to test https functionality, its a proven technology.
Personally I'd go for option 1 - you are attempting to test functionality of an external library. That is usually unnecessary. Also it's good practice to abstract out your dependencies to external libraries.
Hope this helps.
If you are writing a unit test, you dont want any external dependencies. from the api,
GetMethod
extends
HttpMethod
so you can easily mock it with your favorite mocking library. Your
method.getResponseBodyAsString()
call can be mocked to return any data you want.
You can wrap that code in some class and have WebClient.getUrl() and then mock (e.g. jmock) that method to return stored files - say
expectation {
oneOf("https://someurl/"), will(returnValue(someHTML));
}
Take a look at JWebUnit http://jwebunit.sourceforge.net/
Here is an example of a test...Its really quite intuitive.
public class ExampleWebTestCase extends WebTestCase {
public void setUp() {
super.setUp();
setBaseUrl("http://localhost:8080/test");
}
public void test1() {
beginAt("/home");
clickLink("login");
assertTitleEquals("Login");
setTextField("username", "test");
setTextField("password", "test123");
submit();
assertTitleEquals("Welcome, test!");
}
}
You could always launch a thttpd server as part of your unit test to serve the requests locally. Though, ideally, you have a well tested GetMethod, and then you can just mock it, and not have to actually have a remote server around for ALL of your tests.
Resources
thttpd: http://www.acme.com/software/thttpd/
To what extend are you interested in mocking this "Get" call, because if you are looking for a general purpose mocking framework for Java which integrates well with JUnit and allows to setup expectations which are automatically asserted when incorporated into a JUnit suite, then you really ought to take a look at jMock.
Now without more code, it's hard to determine whether this is actually what you are looking for, but a (somewhat useless) example, of something similar to the example code you wrote, would go something like this:
class GetMethodTest {
#Rule public JUnitRuleMockery context = new JunitRuleMockery();
#Test
public void testGetMethod() throws Exception {
// Setup mocked object with expectations
final GetMethod method = context.mock(GetMethod.class);
context.checking(new Expectations() {{
oneOf (method).getResponseBodyAsString();
will(returnValue("Response text goes here"));
}});
// Now do the checking against mocked object
String content = method.getResponseBodyAsString();
}
}
Use xml mimic stub server, that can simulate static http response based on request parameters, headers, etc. It is very simple to configure and use it.
http://xmlmimic.sourceforge.net/
http://sourceforge.net/projects/xmlmimic/

Categories