diff --git a/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/RetrofitClientCodegen.java b/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/RetrofitClientCodegen.java index 66d3f19f948..54f461fe21c 100644 --- a/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/RetrofitClientCodegen.java +++ b/modules/swagger-codegen/src/main/java/io/swagger/codegen/languages/RetrofitClientCodegen.java @@ -52,6 +52,16 @@ public class RetrofitClientCodegen extends DefaultCodegen implements CodegenConf supportingFiles.add(new SupportingFile("pom.mustache", "", "pom.xml")); supportingFiles.add(new SupportingFile("service.mustache", (sourceFolder + File.separator + invokerPackage).replace(".", java.io.File.separator), "ServiceGenerator.java")); + supportingFiles.add(new SupportingFile("auth/basic.mustache", + (sourceFolder + File.separator + invokerPackage + File.separator + "auth").replace(".", java.io.File.separator), "BasicAuthorization.java")); + supportingFiles.add(new SupportingFile("auth/apikey.mustache", + (sourceFolder + File.separator + invokerPackage + File.separator + "auth").replace(".", java.io.File.separator), "ApiKeyAuthorization.java")); + supportingFiles.add(new SupportingFile("auth/oauth.mustache", + (sourceFolder + File.separator + invokerPackage + File.separator + "auth").replace(".", java.io.File.separator), "OauthAuthorization.java")); + supportingFiles.add(new SupportingFile("auth/oauthflow.mustache", + (sourceFolder + File.separator + invokerPackage + File.separator + "auth").replace(".", java.io.File.separator), "OauthFlow.java")); + supportingFiles.add(new SupportingFile("auth/oauthokclient.mustache", + (sourceFolder + File.separator + invokerPackage + File.separator + "auth").replace(".", java.io.File.separator), "OauthOkHttpClient.java")); languageSpecificPrimitives = new HashSet( Arrays.asList( diff --git a/modules/swagger-codegen/src/main/resources/retrofit/api.mustache b/modules/swagger-codegen/src/main/resources/retrofit/api.mustache index 1f49b4a7cba..9d3094e38bd 100644 --- a/modules/swagger-codegen/src/main/resources/retrofit/api.mustache +++ b/modules/swagger-codegen/src/main/resources/retrofit/api.mustache @@ -2,6 +2,7 @@ package {{package}}; import {{modelPackage}}.*; +import retrofit.Callback; import retrofit.http.*; import retrofit.mime.*; import java.util.*; @@ -14,6 +15,7 @@ public interface {{classname}} { {{#operation}} /** * {{summary}} + * Sync method * {{notes}} {{#allParams}} * @param {{paramName}} {{description}} {{/allParams}} * @return {{#returnType}}{{{returnType}}}{{/returnType}}{{^returnType}}void{{/returnType}} @@ -22,8 +24,22 @@ public interface {{classname}} { {{#isMultipart}}@Multipart{{/isMultipart}}{{^isMultipart}}@FormUrlEncoded{{/isMultipart}}{{/-first}}{{/formParams}} @{{httpMethod}}("{{path}}") {{#returnType}}{{{returnType}}}{{/returnType}}{{^returnType}}Object{{/returnType}} {{nickname}}({{^allParams}});{{/allParams}} - {{#allParams}}{{>queryParams}}{{>pathParams}}{{>headerParams}}{{>bodyParams}}{{>formParams}}{{#hasMore}}, {{/hasMore}}{{^hasMore}} - );{{/hasMore}}{{/allParams}} + {{#allParams}}{{>queryParams}}{{>pathParams}}{{>headerParams}}{{>bodyParams}}{{>formParams}}{{#hasMore}},{{/hasMore}}{{^hasMore}} + );{{/hasMore}}{{/allParams}} + + /** + * {{summary}} + * Async method +{{#allParams}} * @param {{paramName}} {{description}} +{{/allParams}} * @param cb callback method + * @return void + */ + {{#formParams}}{{#-first}} + {{#isMultipart}}@Multipart{{/isMultipart}}{{^isMultipart}}@FormUrlEncoded{{/isMultipart}}{{/-first}}{{/formParams}} + @{{httpMethod}}("{{path}}") + void {{nickname}}( + {{#allParams}}{{>queryParams}}{{>pathParams}}{{>headerParams}}{{>bodyParams}}{{>formParams}},{{/allParams}} Callback<{{#returnType}}{{{returnType}}}{{/returnType}}{{^returnType}}Object{{/returnType}}> cb + ); {{/operation}} } -{{/operations}} +{{/operations}} \ No newline at end of file diff --git a/modules/swagger-codegen/src/main/resources/retrofit/auth/apikey.mustache b/modules/swagger-codegen/src/main/resources/retrofit/auth/apikey.mustache new file mode 100644 index 00000000000..9f5eaef7fdc --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/retrofit/auth/apikey.mustache @@ -0,0 +1,68 @@ +package {{invokerPackage}}.auth; + +import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; + +import com.squareup.okhttp.Interceptor; +import com.squareup.okhttp.Request; +import com.squareup.okhttp.Response; + +public class ApiKeyAuthorization implements Interceptor { + private final String location; + private final String paramName; + + private String apiKey; + + public ApiKeyAuthorization(String location, String paramName) { + this.location = location; + this.paramName = paramName; + } + + public String getLocation() { + return location; + } + + public String getParamName() { + return paramName; + } + + public String getApiKey() { + return apiKey; + } + + public void setApiKey(String apiKey) { + this.apiKey = apiKey; + } + + @Override + public Response intercept(Chain chain) throws IOException { + String paramValue; + Request request = chain.request(); + + if (location == "query") { + String newQuery = request.uri().getQuery(); + paramValue = paramName + "=" + apiKey; + if (newQuery == null) { + newQuery = paramValue; + } else { + newQuery += "&" + paramValue; + } + + URI newUri; + try { + newUri = new URI(request.uri().getScheme(), request.uri().getAuthority(), + request.uri().getPath(), newQuery, request.uri().getFragment()); + } catch (URISyntaxException e) { + throw new IOException(e); + } + + request = request.newBuilder().url(newUri.toURL()).build(); + } else if (location == "header") { + request = request.newBuilder() + .addHeader(paramName, apiKey) + .build(); + } + return chain.proceed(request); + } +} \ No newline at end of file diff --git a/modules/swagger-codegen/src/main/resources/retrofit/auth/basic.mustache b/modules/swagger-codegen/src/main/resources/retrofit/auth/basic.mustache new file mode 100644 index 00000000000..f1c88fe9053 --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/retrofit/auth/basic.mustache @@ -0,0 +1,49 @@ +package {{invokerPackage}}.auth; + +import java.io.IOException; + +import com.squareup.okhttp.Credentials; +import com.squareup.okhttp.Interceptor; +import com.squareup.okhttp.Request; +import com.squareup.okhttp.Response; + +public class BasicAuthorization implements Interceptor { + + private String username; + private String password; + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } + + public void setCredentials(String username, String password) { + this.username = username; + this.password = password; + } + + @Override + public Response intercept(Chain chain) throws IOException { + Request request = chain.request(); + + // If the request already have an authorization (eg. Basic auth), do nothing + if (request.header("Authorization") == null) { + String credentials = Credentials.basic(username, password); + request = request.newBuilder() + .addHeader("Authorization", credentials) + .build(); + } + return chain.proceed(request); + } +} diff --git a/modules/swagger-codegen/src/main/resources/retrofit/auth/oauth.mustache b/modules/swagger-codegen/src/main/resources/retrofit/auth/oauth.mustache new file mode 100644 index 00000000000..a1a2ecabfaa --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/retrofit/auth/oauth.mustache @@ -0,0 +1,148 @@ +package {{invokerPackage}}.auth; + +import static java.net.HttpURLConnection.HTTP_UNAUTHORIZED; + +import java.io.IOException; +import java.util.Map; + +import org.apache.oltu.oauth2.client.OAuthClient; +import org.apache.oltu.oauth2.client.request.OAuthBearerClientRequest; +import org.apache.oltu.oauth2.client.request.OAuthClientRequest; +import org.apache.oltu.oauth2.client.request.OAuthClientRequest.AuthenticationRequestBuilder; +import org.apache.oltu.oauth2.client.request.OAuthClientRequest.TokenRequestBuilder; +import org.apache.oltu.oauth2.client.response.OAuthJSONAccessTokenResponse; +import org.apache.oltu.oauth2.common.exception.OAuthProblemException; +import org.apache.oltu.oauth2.common.exception.OAuthSystemException; +import org.apache.oltu.oauth2.common.message.types.GrantType; + +import com.squareup.okhttp.Interceptor; +import com.squareup.okhttp.OkHttpClient; +import com.squareup.okhttp.Request; +import com.squareup.okhttp.Request.Builder; +import com.squareup.okhttp.Response; + +public class OauthAuthorization implements Interceptor { + + private volatile String accessToken; + private OAuthClient oauthClient; + + private TokenRequestBuilder tokenRequestBuilder; + private AuthenticationRequestBuilder authenticationRequestBuilder; + + public OauthAuthorization( OkHttpClient client, TokenRequestBuilder requestBuilder ) { + this.oauthClient = new OAuthClient(new OauthOkHttpClient(client)); + this.tokenRequestBuilder = requestBuilder; + } + + public OauthAuthorization(TokenRequestBuilder requestBuilder ) { + this(new OkHttpClient(), requestBuilder); + } + + public OauthAuthorization(OauthFlow flow, String authorizationUrl, String tokenUrl, String scopes) { + this(OAuthClientRequest.tokenLocation(tokenUrl).setScope(scopes)); + setFlow(flow); + authenticationRequestBuilder = OAuthClientRequest.authorizationLocation(authorizationUrl); + } + + public void setFlow(OauthFlow flow) { + switch(flow) { + case accessCode: + case implicit: + tokenRequestBuilder.setGrantType(GrantType.AUTHORIZATION_CODE); + break; + case password: + tokenRequestBuilder.setGrantType(GrantType.PASSWORD); + break; + case application: + tokenRequestBuilder.setGrantType(GrantType.CLIENT_CREDENTIALS); + break; + default: + break; + } + } + + @Override + public Response intercept(Chain chain) + throws IOException { + + Request request = chain.request(); + + // If the request already have an authorization (eg. Basic auth), do nothing + if (request.header("Authorization") != null) { + return chain.proceed(request); + } + + // If first time, get the token + OAuthClientRequest oAuthRequest; + if (getAccessToken() == null) { + updateAccessToken(null); + } + + // Build the request + Builder rb = request.newBuilder(); + + String requestAccessToken = new String(getAccessToken()); + try { + oAuthRequest = new OAuthBearerClientRequest(request.urlString()) + .setAccessToken(requestAccessToken) + .buildHeaderMessage(); + } catch (OAuthSystemException e) { + throw new IOException(e); + } + + for ( Map.Entry header : oAuthRequest.getHeaders().entrySet() ) { + rb.addHeader(header.getKey(), header.getValue()); + } + rb.url( oAuthRequest.getLocationUri()); + + //Execute the request + Response response = chain.proceed(rb.build()); + + // 401 most likely indicates that access token has expired. + // Time to refresh and resend the request + if ( response.code() == HTTP_UNAUTHORIZED ) { + updateAccessToken(requestAccessToken); + return intercept( chain ); + } + return response; + } + + public synchronized void updateAccessToken(String requestAccessToken) throws IOException { + if (getAccessToken() == null || getAccessToken().equals(requestAccessToken)) { + try { + OAuthJSONAccessTokenResponse accessTokenResponse; + accessTokenResponse = oauthClient.accessToken(this.tokenRequestBuilder.buildBodyMessage()); + setAccessToken(accessTokenResponse.getAccessToken()); + } catch (OAuthSystemException e) { + throw new IOException(e); + } catch (OAuthProblemException e) { + throw new IOException(e); + } + } + } + + public synchronized String getAccessToken() { + return accessToken; + } + + public synchronized void setAccessToken(String accessToken) { + this.accessToken = accessToken; + } + + public TokenRequestBuilder getTokenRequestBuilder() { + return tokenRequestBuilder; + } + + public void setTokenRequestBuilder(TokenRequestBuilder tokenRequestBuilder) { + this.tokenRequestBuilder = tokenRequestBuilder; + } + + public AuthenticationRequestBuilder getAuthenticationRequestBuilder() { + return authenticationRequestBuilder; + } + + public void setAuthenticationRequestBuilder(AuthenticationRequestBuilder authenticationRequestBuilder) { + this.authenticationRequestBuilder = authenticationRequestBuilder; + } + +} diff --git a/modules/swagger-codegen/src/main/resources/retrofit/auth/oauthflow.mustache b/modules/swagger-codegen/src/main/resources/retrofit/auth/oauthflow.mustache new file mode 100644 index 00000000000..6d18cb3aa84 --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/retrofit/auth/oauthflow.mustache @@ -0,0 +1,5 @@ +package {{invokerPackage}}.auth; + +public enum OauthFlow { + accessCode, implicit, password, application +} \ No newline at end of file diff --git a/modules/swagger-codegen/src/main/resources/retrofit/auth/oauthokclient.mustache b/modules/swagger-codegen/src/main/resources/retrofit/auth/oauthokclient.mustache new file mode 100644 index 00000000000..61f651f7696 --- /dev/null +++ b/modules/swagger-codegen/src/main/resources/retrofit/auth/oauthokclient.mustache @@ -0,0 +1,69 @@ +package {{invokerPackage}}.auth; + +import java.io.IOException; +import java.util.Map; +import java.util.Map.Entry; + +import org.apache.oltu.oauth2.client.HttpClient; +import org.apache.oltu.oauth2.client.request.OAuthClientRequest; +import org.apache.oltu.oauth2.client.response.OAuthClientResponse; +import org.apache.oltu.oauth2.client.response.OAuthClientResponseFactory; +import org.apache.oltu.oauth2.common.exception.OAuthProblemException; +import org.apache.oltu.oauth2.common.exception.OAuthSystemException; + +import com.squareup.okhttp.MediaType; +import com.squareup.okhttp.OkHttpClient; +import com.squareup.okhttp.Request; +import com.squareup.okhttp.RequestBody; +import com.squareup.okhttp.Response; + + +public class OauthOkHttpClient implements HttpClient { + + private OkHttpClient client; + + public OauthOkHttpClient() { + this.client = new OkHttpClient(); + } + + public OauthOkHttpClient(OkHttpClient client) { + this.client = client; + } + + public T execute(OAuthClientRequest request, Map headers, + String requestMethod, Class responseClass) + throws OAuthSystemException, OAuthProblemException { + + MediaType mediaType = MediaType.parse("application/json"); + Request.Builder requestBuilder = new Request.Builder().url(request.getLocationUri()); + + if(headers != null) { + for (Entry entry : headers.entrySet()) { + if (entry.getKey().equalsIgnoreCase("Content-Type")) { + mediaType = MediaType.parse(entry.getValue()); + } else { + requestBuilder.addHeader(entry.getKey(), entry.getValue()); + } + } + } + + RequestBody body = request.getBody() != null ? RequestBody.create(mediaType, request.getBody()) : null; + requestBuilder.method(requestMethod, body); + + try { + Response response = client.newCall(requestBuilder.build()).execute(); + return OAuthClientResponseFactory.createCustomResponse( + response.body().string(), + response.body().contentType().toString(), + response.code(), + responseClass); + } catch (IOException e) { + throw new OAuthSystemException(e); + } + } + + public void shutdown() { + // Nothing to do here + } + +} diff --git a/modules/swagger-codegen/src/main/resources/retrofit/pom.mustache b/modules/swagger-codegen/src/main/resources/retrofit/pom.mustache index 7d999db86ca..8ed9335b4ee 100644 --- a/modules/swagger-codegen/src/main/resources/retrofit/pom.mustache +++ b/modules/swagger-codegen/src/main/resources/retrofit/pom.mustache @@ -112,18 +112,22 @@ swagger-annotations ${swagger-annotations-version} - - com.google.code.gson - gson - ${gson-version} - compile - com.squareup.retrofit retrofit ${retrofit-version} + + + org.apache.oltu.oauth2 + org.apache.oltu.oauth2.client + ${oltu-version} compile + + com.squareup.okhttp + okhttp + ${okhttp-version} + @@ -137,6 +141,8 @@ 1.5.0 2.3.1 1.9.0 + 2.4.0 + 1.0.0 1.0.0 4.12 diff --git a/modules/swagger-codegen/src/main/resources/retrofit/service.mustache b/modules/swagger-codegen/src/main/resources/retrofit/service.mustache index df6d61b7ab8..aa7b73f2147 100644 --- a/modules/swagger-codegen/src/main/resources/retrofit/service.mustache +++ b/modules/swagger-codegen/src/main/resources/retrofit/service.mustache @@ -1,15 +1,17 @@ package {{invokerPackage}}; -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; -import com.google.gson.JsonParseException; - import java.io.ByteArrayOutputStream; -import java.io.InputStream; import java.io.IOException; +import java.io.InputStream; import java.lang.reflect.Type; +import java.util.LinkedHashMap; +import java.util.Map; + +import org.apache.oltu.oauth2.client.request.OAuthClientRequest.AuthenticationRequestBuilder; +import org.apache.oltu.oauth2.client.request.OAuthClientRequest.TokenRequestBuilder; import retrofit.RestAdapter; +import retrofit.client.OkClient; import retrofit.converter.ConversionException; import retrofit.converter.Converter; import retrofit.converter.GsonConverter; @@ -17,21 +19,245 @@ import retrofit.mime.TypedByteArray; import retrofit.mime.TypedInput; import retrofit.mime.TypedOutput; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonParseException; +import com.squareup.okhttp.Interceptor; +import com.squareup.okhttp.OkHttpClient; + +import {{invokerPackage}}.auth.BasicAuthorization; +import {{invokerPackage}}.auth.ApiKeyAuthorization; +import {{invokerPackage}}.auth.OauthAuthorization; +import {{invokerPackage}}.auth.OauthFlow; + + public class ServiceGenerator { - // No need to instantiate this class. - private ServiceGenerator() { } - public static S createService(Class serviceClass) { - Gson gson = new GsonBuilder() - .setDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ") - .create(); - RestAdapter adapter = new RestAdapter.Builder() - .setEndpoint("{{basePath}}") - .setConverter(new GsonConverterWrapper(gson)) - .build(); + private Map apiAuthorizations; + private OkHttpClient okClient; + private RestAdapter.Builder adapterBuilder; - return adapter.create(serviceClass); - } + public ServiceGenerator() { + apiAuthorizations = new LinkedHashMap(); + createDefaultAdapter(); + } + + public ServiceGenerator(String[] authNames) { + this(); + okClient = new OkHttpClient(); + adapterBuilder.setClient(new OkClient(okClient)); + for(String authName : authNames) { + if (apiAuthorizations.containsKey(authName)) { + throw new RuntimeException("auth name \"" + authName + "\" already in api authorizations"); + } + Interceptor auth;{{#authMethods}} + if (authName == "{{name}}") { {{#isBasic}} + auth = new BasicAuthorization();{{/isBasic}}{{#isApiKey}} + auth = new ApiKeyAuthorization({{#isKeyInHeader}}"header"{{/isKeyInHeader}}{{^isKeyInHeader}}"query"{{/isKeyInHeader}}, "{{keyParamName}}");{{/isApiKey}}{{#isOAuth}} + auth = new OauthAuthorization(OauthFlow.{{flow}}, "{{authorizationUrl}}", "{{tokenUrl}}", "{{#scopes}}{{^-first}}, {{/-first}}{{this}}{{/scopes}}");{{/isOAuth}} + } else {{/authMethods}}{ + throw new RuntimeException("auth name \"" + authName + "\" not found in available auth names"); + } + apiAuthorizations.put(authName, auth); + } + addAuthsToOkClient(okClient); + } + + /** + * Basic constructor for single auth name + * @param authName + */ + public ServiceGenerator(String authName) { + this(new String[]{authName}); + } + + /** + * Helper constructor for single api key + * @param authName + * @param apiKey + */ + public ServiceGenerator(String authName, String apiKey) { + this(authName); + this.setApiKey(apiKey); + } + + /** + * Helper constructor for single basic auth or password oauth2 + * @param authName + * @param username + * @param password + */ + public ServiceGenerator(String authName, String username, String password) { + this(authName); + this.setCredentials(username, password); + } + + /** + * Helper constructor for single password oauth2 + * @param authName + * @param clientId + * @param secret + * @param username + * @param password + */ + public ServiceGenerator(String authName, String clientId, String secret, String username, String password) { + this(authName); + this.getTokenEndPoint() + .setClientId(clientId) + .setClientSecret(secret) + .setUsername(username) + .setPassword(password); + } + + public void createDefaultAdapter() { + Gson gson = new GsonBuilder() + .setDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ") + .create(); + + adapterBuilder = new RestAdapter + .Builder() + .setEndpoint("{{basePath}}") + .setConverter(new GsonConverterWrapper(gson)); + } + + public S createService(Class serviceClass) { + return adapterBuilder.build().create(serviceClass); + + } + + /** + * Helper method to configure the first api key found + * @param apiKey + */ + private void setApiKey(String apiKey) { + for(Interceptor apiAuthorization : apiAuthorizations.values()) { + if (apiAuthorization instanceof ApiKeyAuthorization) { + ApiKeyAuthorization keyAuth = (ApiKeyAuthorization) apiAuthorization; + keyAuth.setApiKey(apiKey); + return; + } + } + } + + /** + * Helper method to configure the username/password for basic auth or password oauth + * @param username + * @param password + */ + private void setCredentials(String username, String password) { + for(Interceptor apiAuthorization : apiAuthorizations.values()) { + if (apiAuthorization instanceof BasicAuthorization) { + BasicAuthorization basicAuth = (BasicAuthorization) apiAuthorization; + basicAuth.setCredentials(username, password); + return; + } + if (apiAuthorization instanceof OauthAuthorization) { + OauthAuthorization oauth = (OauthAuthorization) apiAuthorization; + oauth.getTokenRequestBuilder().setUsername(username).setPassword(password); + return; + } + } + } + + /** + * Helper method to configure the token endpoint of the first oauth found in the apiAuthorizations (there should be only one) + * @return + */ + public TokenRequestBuilder getTokenEndPoint() { + for(Interceptor apiAuthorization : apiAuthorizations.values()) { + if (apiAuthorization instanceof OauthAuthorization) { + OauthAuthorization oauth = (OauthAuthorization) apiAuthorization; + return oauth.getTokenRequestBuilder(); + } + } + return null; + } + + /** + * Helper method to configure authorization endpoint of the first oauth found in the apiAuthorizations (there should be only one) + * @return + */ + public AuthenticationRequestBuilder getAuthorizationEndPoint() { + for(Interceptor apiAuthorization : apiAuthorizations.values()) { + if (apiAuthorization instanceof OauthAuthorization) { + OauthAuthorization oauth = (OauthAuthorization) apiAuthorization; + return oauth.getAuthenticationRequestBuilder(); + } + } + return null; + } + + /** + * Helper method to pre-set the oauth access token of the first oauth found in the apiAuthorizations (there should be only one) + * @param accessToken + */ + public void setAccessToken(String accessToken) { + for(Interceptor apiAuthorization : apiAuthorizations.values()) { + if (apiAuthorization instanceof OauthAuthorization) { + OauthAuthorization oauth = (OauthAuthorization) apiAuthorization; + oauth.setAccessToken(accessToken); + return; + } + } + } + + /** + * Helper method to configure the oauth accessCode/implicit flow parameters + * @param clientId + * @param clientSecret + * @param redirectURI + */ + public void configureAuthorizationFlow(String clientId, String clientSecret, String redirectURI) { + for(Interceptor apiAuthorization : apiAuthorizations.values()) { + if (apiAuthorization instanceof OauthAuthorization) { + OauthAuthorization oauth = (OauthAuthorization) apiAuthorization; + oauth.getTokenRequestBuilder() + .setClientId(clientId) + .setClientSecret(clientSecret) + .setRedirectURI(redirectURI); + oauth.getAuthenticationRequestBuilder() + .setClientId(clientId) + .setRedirectURI(redirectURI); + return; + } + } + } + + public Map getApiAuthorizations() { + return apiAuthorizations; + } + + public void setApiAuthorizations(Map apiAuthorizations) { + this.apiAuthorizations = apiAuthorizations; + } + + public RestAdapter.Builder getAdapterBuilder() { + return adapterBuilder; + } + + public void setAdapterBuilder(RestAdapter.Builder adapterBuilder) { + this.adapterBuilder = adapterBuilder; + } + + public OkHttpClient getOkClient() { + return okClient; + } + + public void addAuthsToOkClient(OkHttpClient okClient) { + for(Interceptor apiAuthorization : apiAuthorizations.values()) { + okClient.interceptors().add(apiAuthorization); + } + } + + /** + * Clones the okClient given in parameter, adds the auth interceptors and uses it to configure the RestAdapter + * @param okClient + */ + public void configureFromOkclient(OkHttpClient okClient) { + OkHttpClient clone = okClient.clone(); + addAuthsToOkClient(clone); + adapterBuilder.setClient(new OkClient(clone)); + } } /** diff --git a/samples/client/petstore/retrofit/pom.xml b/samples/client/petstore/retrofit/pom.xml index 45463b449bd..0c090b0b85e 100644 --- a/samples/client/petstore/retrofit/pom.xml +++ b/samples/client/petstore/retrofit/pom.xml @@ -112,18 +112,22 @@ swagger-annotations ${swagger-annotations-version} - - com.google.code.gson - gson - ${gson-version} - compile - com.squareup.retrofit retrofit ${retrofit-version} + + + org.apache.oltu.oauth2 + org.apache.oltu.oauth2.client + ${oltu-version} compile + + com.squareup.okhttp + okhttp + ${okhttp-version} + @@ -137,6 +141,8 @@ 1.5.0 2.3.1 1.9.0 + 2.4.0 + 1.0.0 1.0.0 4.12 diff --git a/samples/client/petstore/retrofit/src/main/java/io/swagger/client/ServiceGenerator.java b/samples/client/petstore/retrofit/src/main/java/io/swagger/client/ServiceGenerator.java index 1ffb0c58b0c..244b9f50f84 100644 --- a/samples/client/petstore/retrofit/src/main/java/io/swagger/client/ServiceGenerator.java +++ b/samples/client/petstore/retrofit/src/main/java/io/swagger/client/ServiceGenerator.java @@ -1,15 +1,17 @@ package io.swagger.client; -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; -import com.google.gson.JsonParseException; - import java.io.ByteArrayOutputStream; -import java.io.InputStream; import java.io.IOException; +import java.io.InputStream; import java.lang.reflect.Type; +import java.util.LinkedHashMap; +import java.util.Map; + +import org.apache.oltu.oauth2.client.request.OAuthClientRequest.AuthenticationRequestBuilder; +import org.apache.oltu.oauth2.client.request.OAuthClientRequest.TokenRequestBuilder; import retrofit.RestAdapter; +import retrofit.client.OkClient; import retrofit.converter.ConversionException; import retrofit.converter.Converter; import retrofit.converter.GsonConverter; @@ -17,21 +19,246 @@ import retrofit.mime.TypedByteArray; import retrofit.mime.TypedInput; import retrofit.mime.TypedOutput; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonParseException; +import com.squareup.okhttp.Interceptor; +import com.squareup.okhttp.OkHttpClient; + +import io.swagger.client.auth.BasicAuthorization; +import io.swagger.client.auth.ApiKeyAuthorization; +import io.swagger.client.auth.OauthAuthorization; +import io.swagger.client.auth.OauthFlow; + + public class ServiceGenerator { - // No need to instantiate this class. - private ServiceGenerator() { } - public static S createService(Class serviceClass) { - Gson gson = new GsonBuilder() - .setDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ") - .create(); - RestAdapter adapter = new RestAdapter.Builder() - .setEndpoint("http://petstore.swagger.io/v2") - .setConverter(new GsonConverterWrapper(gson)) - .build(); + private Map apiAuthorizations; + private OkHttpClient okClient; + private RestAdapter.Builder adapterBuilder; - return adapter.create(serviceClass); - } + public ServiceGenerator() { + apiAuthorizations = new LinkedHashMap(); + createDefaultAdapter(); + } + + public ServiceGenerator(String[] authNames) { + this(); + okClient = new OkHttpClient(); + adapterBuilder.setClient(new OkClient(okClient)); + for(String authName : authNames) { + if (apiAuthorizations.containsKey(authName)) { + throw new RuntimeException("auth name \"" + authName + "\" already in api authorizations"); + } + Interceptor auth; + if (authName == "petstore_auth") { + auth = new OauthAuthorization(OauthFlow.implicit, "http://petstore.swagger.io/api/oauth/dialog", "", "write:pets, read:pets"); + } else + if (authName == "api_key") { + auth = new ApiKeyAuthorization("header", "api_key"); + } else { + throw new RuntimeException("auth name \"" + authName + "\" not found in available auth names"); + } + apiAuthorizations.put(authName, auth); + } + addAuthsToOkClient(okClient); + } + + /** + * Basic constructor for single auth name + * @param authName + */ + public ServiceGenerator(String authName) { + this(new String[]{authName}); + } + + /** + * Helper constructor for single api key + * @param authName + * @param apiKey + */ + public ServiceGenerator(String authName, String apiKey) { + this(authName); + this.setApiKey(apiKey); + } + + /** + * Helper constructor for single basic auth or password oauth2 + * @param authName + * @param username + * @param password + */ + public ServiceGenerator(String authName, String username, String password) { + this(authName); + this.setCredentials(username, password); + } + + /** + * Helper constructor for single password oauth2 + * @param authName + * @param clientId + * @param secret + * @param username + * @param password + */ + public ServiceGenerator(String authName, String clientId, String secret, String username, String password) { + this(authName); + this.getTokenEndPoint() + .setClientId(clientId) + .setClientSecret(secret) + .setUsername(username) + .setPassword(password); + } + + public void createDefaultAdapter() { + Gson gson = new GsonBuilder() + .setDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ") + .create(); + + adapterBuilder = new RestAdapter + .Builder() + .setEndpoint("http://petstore.swagger.io/v2") + .setConverter(new GsonConverterWrapper(gson)); + } + + public S createService(Class serviceClass) { + return adapterBuilder.build().create(serviceClass); + + } + + /** + * Helper method to configure the first api key found + * @param apiKey + */ + private void setApiKey(String apiKey) { + for(Interceptor apiAuthorization : apiAuthorizations.values()) { + if (apiAuthorization instanceof ApiKeyAuthorization) { + ApiKeyAuthorization keyAuth = (ApiKeyAuthorization) apiAuthorization; + keyAuth.setApiKey(apiKey); + return; + } + } + } + + /** + * Helper method to configure the username/password for basic auth or password oauth + * @param username + * @param password + */ + private void setCredentials(String username, String password) { + for(Interceptor apiAuthorization : apiAuthorizations.values()) { + if (apiAuthorization instanceof BasicAuthorization) { + BasicAuthorization basicAuth = (BasicAuthorization) apiAuthorization; + basicAuth.setCredentials(username, password); + return; + } + if (apiAuthorization instanceof OauthAuthorization) { + OauthAuthorization oauth = (OauthAuthorization) apiAuthorization; + oauth.getTokenRequestBuilder().setUsername(username).setPassword(password); + return; + } + } + } + + /** + * Helper method to configure the token endpoint of the first oauth found in the apiAuthorizations (there should be only one) + * @return + */ + public TokenRequestBuilder getTokenEndPoint() { + for(Interceptor apiAuthorization : apiAuthorizations.values()) { + if (apiAuthorization instanceof OauthAuthorization) { + OauthAuthorization oauth = (OauthAuthorization) apiAuthorization; + return oauth.getTokenRequestBuilder(); + } + } + return null; + } + + /** + * Helper method to configure authorization endpoint of the first oauth found in the apiAuthorizations (there should be only one) + * @return + */ + public AuthenticationRequestBuilder getAuthorizationEndPoint() { + for(Interceptor apiAuthorization : apiAuthorizations.values()) { + if (apiAuthorization instanceof OauthAuthorization) { + OauthAuthorization oauth = (OauthAuthorization) apiAuthorization; + return oauth.getAuthenticationRequestBuilder(); + } + } + return null; + } + + /** + * Helper method to pre-set the oauth access token of the first oauth found in the apiAuthorizations (there should be only one) + * @param accessToken + */ + public void setAccessToken(String accessToken) { + for(Interceptor apiAuthorization : apiAuthorizations.values()) { + if (apiAuthorization instanceof OauthAuthorization) { + OauthAuthorization oauth = (OauthAuthorization) apiAuthorization; + oauth.setAccessToken(accessToken); + return; + } + } + } + + /** + * Helper method to configure the oauth accessCode/implicit flow parameters + * @param clientId + * @param clientSecret + * @param redirectURI + */ + public void configureAuthorizationFlow(String clientId, String clientSecret, String redirectURI) { + for(Interceptor apiAuthorization : apiAuthorizations.values()) { + if (apiAuthorization instanceof OauthAuthorization) { + OauthAuthorization oauth = (OauthAuthorization) apiAuthorization; + oauth.getTokenRequestBuilder() + .setClientId(clientId) + .setClientSecret(clientSecret) + .setRedirectURI(redirectURI); + oauth.getAuthenticationRequestBuilder() + .setClientId(clientId) + .setRedirectURI(redirectURI); + return; + } + } + } + + public Map getApiAuthorizations() { + return apiAuthorizations; + } + + public void setApiAuthorizations(Map apiAuthorizations) { + this.apiAuthorizations = apiAuthorizations; + } + + public RestAdapter.Builder getAdapterBuilder() { + return adapterBuilder; + } + + public void setAdapterBuilder(RestAdapter.Builder adapterBuilder) { + this.adapterBuilder = adapterBuilder; + } + + public OkHttpClient getOkClient() { + return okClient; + } + + public void addAuthsToOkClient(OkHttpClient okClient) { + for(Interceptor apiAuthorization : apiAuthorizations.values()) { + okClient.interceptors().add(apiAuthorization); + } + } + + /** + * Clones the okClient given in parameter, adds the auth interceptors and uses it to configure the RestAdapter + * @param okClient + */ + public void configureFromOkclient(OkHttpClient okClient) { + OkHttpClient clone = okClient.clone(); + addAuthsToOkClient(clone); + adapterBuilder.setClient(new OkClient(clone)); + } } /** diff --git a/samples/client/petstore/retrofit/src/main/java/io/swagger/client/api/PetApi.java b/samples/client/petstore/retrofit/src/main/java/io/swagger/client/api/PetApi.java index cca8370a181..dd485d7dcef 100644 --- a/samples/client/petstore/retrofit/src/main/java/io/swagger/client/api/PetApi.java +++ b/samples/client/petstore/retrofit/src/main/java/io/swagger/client/api/PetApi.java @@ -2,116 +2,237 @@ package io.swagger.client.api; import io.swagger.client.model.*; +import retrofit.Callback; import retrofit.http.*; import retrofit.mime.*; import java.util.*; import io.swagger.client.model.Pet; import java.io.File; +import io.swagger.client.model.ApiResponse; public interface PetApi { - + /** * Update an existing pet - * + * Sync method + * * @param body Pet object that needs to be added to the store * @return Void */ - - @PUT("/pet") + + @PUT("/pet") Void updatePet( @Body Pet body ); + /** + * Update an existing pet + * Async method + * @param body Pet object that needs to be added to the store + * @param cb callback method + * @return void + */ + + @PUT("/pet") + void updatePet( + @Body Pet body, Callback cb + ); + /** * Add a new pet to the store - * + * Sync method + * * @param body Pet object that needs to be added to the store * @return Void */ - - @POST("/pet") + + @POST("/pet") Void addPet( @Body Pet body ); + /** + * Add a new pet to the store + * Async method + * @param body Pet object that needs to be added to the store + * @param cb callback method + * @return void + */ + + @POST("/pet") + void addPet( + @Body Pet body, Callback cb + ); + /** * Finds Pets by status + * Sync method * Multiple status values can be provided with comma seperated strings * @param status Status values that need to be considered for filter * @return List */ - - @GET("/pet/findByStatus") + + @GET("/pet/findByStatus") List findPetsByStatus( @Query("status") List status ); + /** + * Finds Pets by status + * Async method + * @param status Status values that need to be considered for filter + * @param cb callback method + * @return void + */ + + @GET("/pet/findByStatus") + void findPetsByStatus( + @Query("status") List status, Callback> cb + ); + /** * Finds Pets by tags + * Sync method * Muliple tags can be provided with comma seperated strings. Use tag1, tag2, tag3 for testing. * @param tags Tags to filter by * @return List */ - - @GET("/pet/findByTags") + + @GET("/pet/findByTags") List findPetsByTags( @Query("tags") List tags ); + /** + * Finds Pets by tags + * Async method + * @param tags Tags to filter by + * @param cb callback method + * @return void + */ + + @GET("/pet/findByTags") + void findPetsByTags( + @Query("tags") List tags, Callback> cb + ); + /** * Find pet by ID - * Returns a pet when ID < 10. ID > 10 or nonintegers will simulate API error conditions - * @param petId ID of pet that needs to be fetched + * Sync method + * Returns a single pet + * @param petId ID of pet to return * @return Pet */ - - @GET("/pet/{petId}") + + @GET("/pet/{petId}") Pet getPetById( @Path("petId") Long petId ); + /** + * Find pet by ID + * Async method + * @param petId ID of pet to return + * @param cb callback method + * @return void + */ + + @GET("/pet/{petId}") + void getPetById( + @Path("petId") Long petId, Callback cb + ); + /** * Updates a pet in the store with form data - * + * Sync method + * * @param petId ID of pet that needs to be updated * @param name Updated name of the pet * @param status Updated status of the pet * @return Void */ - + @FormUrlEncoded - @POST("/pet/{petId}") + @POST("/pet/{petId}") Void updatePetWithForm( - @Path("petId") String petId, @Field("name") String name, @Field("status") String status + @Path("petId") Long petId,@Field("name") String name,@Field("status") String status + ); + + /** + * Updates a pet in the store with form data + * Async method + * @param petId ID of pet that needs to be updated + * @param name Updated name of the pet + * @param status Updated status of the pet + * @param cb callback method + * @return void + */ + + @FormUrlEncoded + @POST("/pet/{petId}") + void updatePetWithForm( + @Path("petId") Long petId,@Field("name") String name,@Field("status") String status, Callback cb + ); + + /** + * Deletes a pet + * Sync method + * + * @param petId Pet id to delete + * @param apiKey + * @return Void + */ + + @DELETE("/pet/{petId}") + Void deletePet( + @Path("petId") Long petId,@Header("api_key") String apiKey ); /** * Deletes a pet - * + * Async method * @param petId Pet id to delete - * @param apiKey - * @return Void + * @param apiKey + * @param cb callback method + * @return void */ - - @DELETE("/pet/{petId}") - Void deletePet( - @Path("petId") Long petId, @Header("api_key") String apiKey + + @DELETE("/pet/{petId}") + void deletePet( + @Path("petId") Long petId,@Header("api_key") String apiKey, Callback cb + ); + + /** + * uploads an image + * Sync method + * + * @param petId ID of pet to update + * @param additionalMetadata Additional data to pass to server + * @param file file to upload + * @return ApiResponse + */ + + @Multipart + @POST("/pet/{petId}/uploadImage") + ApiResponse uploadFile( + @Path("petId") Long petId,@Part("additionalMetadata") String additionalMetadata,@Part("file") TypedFile file ); /** * uploads an image - * + * Async method * @param petId ID of pet to update * @param additionalMetadata Additional data to pass to server * @param file file to upload - * @return Void + * @param cb callback method + * @return void */ - + @Multipart - @POST("/pet/{petId}/uploadImage") - Void uploadFile( - @Path("petId") Long petId, @Part("additionalMetadata") String additionalMetadata, @Part("file") TypedFile file - ); - + @POST("/pet/{petId}/uploadImage") + void uploadFile( + @Path("petId") Long petId,@Part("additionalMetadata") String additionalMetadata,@Part("file") TypedFile file, Callback cb + ); + } diff --git a/samples/client/petstore/retrofit/src/main/java/io/swagger/client/api/StoreApi.java b/samples/client/petstore/retrofit/src/main/java/io/swagger/client/api/StoreApi.java index fcd47b4b735..c9944dfc1ff 100644 --- a/samples/client/petstore/retrofit/src/main/java/io/swagger/client/api/StoreApi.java +++ b/samples/client/petstore/retrofit/src/main/java/io/swagger/client/api/StoreApi.java @@ -2,6 +2,7 @@ package io.swagger.client.api; import io.swagger.client.model.*; +import retrofit.Callback; import retrofit.http.*; import retrofit.mime.*; import java.util.*; @@ -13,16 +14,30 @@ public interface StoreApi { /** * Returns pet inventories by status + * Sync method * Returns a map of status codes to quantities * @return Map */ @GET("/store/inventory") Map getInventory(); - + + + /** + * Returns pet inventories by status + * Async method + * @param cb callback method + * @return void + */ + + @GET("/store/inventory") + void getInventory( + Callback> cb + ); /** * Place an order for a pet + * Sync method * * @param body order placed for purchasing the pet * @return Order @@ -31,10 +46,24 @@ public interface StoreApi { @POST("/store/order") Order placeOrder( @Body Order body - ); + ); + + /** + * Place an order for a pet + * Async method + * @param body order placed for purchasing the pet + * @param cb callback method + * @return void + */ + + @POST("/store/order") + void placeOrder( + @Body Order body, Callback cb + ); /** * Find purchase order by ID + * Sync method * For valid response try integer IDs with value <= 5 or > 10. Other values will generated exceptions * @param orderId ID of pet that needs to be fetched * @return Order @@ -42,11 +71,25 @@ public interface StoreApi { @GET("/store/order/{orderId}") Order getOrderById( - @Path("orderId") String orderId - ); + @Path("orderId") Long orderId + ); + + /** + * Find purchase order by ID + * Async method + * @param orderId ID of pet that needs to be fetched + * @param cb callback method + * @return void + */ + + @GET("/store/order/{orderId}") + void getOrderById( + @Path("orderId") Long orderId, Callback cb + ); /** * Delete purchase order by ID + * Sync method * For valid response try integer IDs with value < 1000. Anything above 1000 or nonintegers will generate API errors * @param orderId ID of the order that needs to be deleted * @return Void @@ -55,6 +98,19 @@ public interface StoreApi { @DELETE("/store/order/{orderId}") Void deleteOrder( @Path("orderId") String orderId - ); + ); + + /** + * Delete purchase order by ID + * Async method + * @param orderId ID of the order that needs to be deleted + * @param cb callback method + * @return void + */ + + @DELETE("/store/order/{orderId}") + void deleteOrder( + @Path("orderId") String orderId, Callback cb + ); } diff --git a/samples/client/petstore/retrofit/src/main/java/io/swagger/client/api/UserApi.java b/samples/client/petstore/retrofit/src/main/java/io/swagger/client/api/UserApi.java index b80f9e5fa20..b17769c54e7 100644 --- a/samples/client/petstore/retrofit/src/main/java/io/swagger/client/api/UserApi.java +++ b/samples/client/petstore/retrofit/src/main/java/io/swagger/client/api/UserApi.java @@ -2,6 +2,7 @@ package io.swagger.client.api; import io.swagger.client.model.*; +import retrofit.Callback; import retrofit.http.*; import retrofit.mime.*; import java.util.*; @@ -13,6 +14,7 @@ public interface UserApi { /** * Create user + * Sync method * This can only be done by the logged in user. * @param body Created user object * @return Void @@ -21,10 +23,24 @@ public interface UserApi { @POST("/user") Void createUser( @Body User body - ); + ); + + /** + * Create user + * Async method + * @param body Created user object + * @param cb callback method + * @return void + */ + + @POST("/user") + void createUser( + @Body User body, Callback cb + ); /** * Creates list of users with given input array + * Sync method * * @param body List of user object * @return Void @@ -33,10 +49,24 @@ public interface UserApi { @POST("/user/createWithArray") Void createUsersWithArrayInput( @Body List body - ); + ); + + /** + * Creates list of users with given input array + * Async method + * @param body List of user object + * @param cb callback method + * @return void + */ + + @POST("/user/createWithArray") + void createUsersWithArrayInput( + @Body List body, Callback cb + ); /** * Creates list of users with given input array + * Sync method * * @param body List of user object * @return Void @@ -45,10 +75,24 @@ public interface UserApi { @POST("/user/createWithList") Void createUsersWithListInput( @Body List body - ); + ); + + /** + * Creates list of users with given input array + * Async method + * @param body List of user object + * @param cb callback method + * @return void + */ + + @POST("/user/createWithList") + void createUsersWithListInput( + @Body List body, Callback cb + ); /** * Logs user into the system + * Sync method * * @param username The user name for login * @param password The password for login in clear text @@ -57,21 +101,49 @@ public interface UserApi { @GET("/user/login") String loginUser( - @Query("username") String username, @Query("password") String password - ); + @Query("username") String username,@Query("password") String password + ); + + /** + * Logs user into the system + * Async method + * @param username The user name for login + * @param password The password for login in clear text + * @param cb callback method + * @return void + */ + + @GET("/user/login") + void loginUser( + @Query("username") String username,@Query("password") String password, Callback cb + ); /** * Logs out current logged in user session + * Sync method * * @return Void */ @GET("/user/logout") Void logoutUser(); - + + + /** + * Logs out current logged in user session + * Async method + * @param cb callback method + * @return void + */ + + @GET("/user/logout") + void logoutUser( + Callback cb + ); /** * Get user by user name + * Sync method * * @param username The name that needs to be fetched. Use user1 for testing. * @return User @@ -80,10 +152,24 @@ public interface UserApi { @GET("/user/{username}") User getUserByName( @Path("username") String username - ); + ); + + /** + * Get user by user name + * Async method + * @param username The name that needs to be fetched. Use user1 for testing. + * @param cb callback method + * @return void + */ + + @GET("/user/{username}") + void getUserByName( + @Path("username") String username, Callback cb + ); /** * Updated user + * Sync method * This can only be done by the logged in user. * @param username name that need to be deleted * @param body Updated user object @@ -92,11 +178,26 @@ public interface UserApi { @PUT("/user/{username}") Void updateUser( - @Path("username") String username, @Body User body - ); + @Path("username") String username,@Body User body + ); + + /** + * Updated user + * Async method + * @param username name that need to be deleted + * @param body Updated user object + * @param cb callback method + * @return void + */ + + @PUT("/user/{username}") + void updateUser( + @Path("username") String username,@Body User body, Callback cb + ); /** * Delete user + * Sync method * This can only be done by the logged in user. * @param username The name that needs to be deleted * @return Void @@ -105,6 +206,19 @@ public interface UserApi { @DELETE("/user/{username}") Void deleteUser( @Path("username") String username - ); + ); + + /** + * Delete user + * Async method + * @param username The name that needs to be deleted + * @param cb callback method + * @return void + */ + + @DELETE("/user/{username}") + void deleteUser( + @Path("username") String username, Callback cb + ); } diff --git a/samples/client/petstore/retrofit/src/main/java/io/swagger/client/auth/ApiKeyAuthorization.java b/samples/client/petstore/retrofit/src/main/java/io/swagger/client/auth/ApiKeyAuthorization.java new file mode 100644 index 00000000000..a1292c1d7f1 --- /dev/null +++ b/samples/client/petstore/retrofit/src/main/java/io/swagger/client/auth/ApiKeyAuthorization.java @@ -0,0 +1,68 @@ +package io.swagger.client.auth; + +import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; + +import com.squareup.okhttp.Interceptor; +import com.squareup.okhttp.Request; +import com.squareup.okhttp.Response; + +public class ApiKeyAuthorization implements Interceptor { + private final String location; + private final String paramName; + + private String apiKey; + + public ApiKeyAuthorization(String location, String paramName) { + this.location = location; + this.paramName = paramName; + } + + public String getLocation() { + return location; + } + + public String getParamName() { + return paramName; + } + + public String getApiKey() { + return apiKey; + } + + public void setApiKey(String apiKey) { + this.apiKey = apiKey; + } + + @Override + public Response intercept(Chain chain) throws IOException { + String paramValue; + Request request = chain.request(); + + if (location == "query") { + String newQuery = request.uri().getQuery(); + paramValue = paramName + "=" + apiKey; + if (newQuery == null) { + newQuery = paramValue; + } else { + newQuery += "&" + paramValue; + } + + URI newUri; + try { + newUri = new URI(request.uri().getScheme(), request.uri().getAuthority(), + request.uri().getPath(), newQuery, request.uri().getFragment()); + } catch (URISyntaxException e) { + throw new IOException(e); + } + + request = request.newBuilder().url(newUri.toURL()).build(); + } else if (location == "header") { + request = request.newBuilder() + .addHeader(paramName, apiKey) + .build(); + } + return chain.proceed(request); + } +} \ No newline at end of file diff --git a/samples/client/petstore/retrofit/src/main/java/io/swagger/client/auth/BasicAuthorization.java b/samples/client/petstore/retrofit/src/main/java/io/swagger/client/auth/BasicAuthorization.java new file mode 100644 index 00000000000..80903d49a34 --- /dev/null +++ b/samples/client/petstore/retrofit/src/main/java/io/swagger/client/auth/BasicAuthorization.java @@ -0,0 +1,49 @@ +package io.swagger.client.auth; + +import java.io.IOException; + +import com.squareup.okhttp.Credentials; +import com.squareup.okhttp.Interceptor; +import com.squareup.okhttp.Request; +import com.squareup.okhttp.Response; + +public class BasicAuthorization implements Interceptor { + + private String username; + private String password; + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } + + public void setCredentials(String username, String password) { + this.username = username; + this.password = password; + } + + @Override + public Response intercept(Chain chain) throws IOException { + Request request = chain.request(); + + // If the request already have an authorization (eg. Basic auth), do nothing + if (request.header("Authorization") == null) { + String credentials = Credentials.basic(username, password); + request = request.newBuilder() + .addHeader("Authorization", credentials) + .build(); + } + return chain.proceed(request); + } +} diff --git a/samples/client/petstore/retrofit/src/main/java/io/swagger/client/auth/OauthAuthorization.java b/samples/client/petstore/retrofit/src/main/java/io/swagger/client/auth/OauthAuthorization.java new file mode 100644 index 00000000000..01c2d3e0916 --- /dev/null +++ b/samples/client/petstore/retrofit/src/main/java/io/swagger/client/auth/OauthAuthorization.java @@ -0,0 +1,148 @@ +package io.swagger.client.auth; + +import static java.net.HttpURLConnection.HTTP_UNAUTHORIZED; + +import java.io.IOException; +import java.util.Map; + +import org.apache.oltu.oauth2.client.OAuthClient; +import org.apache.oltu.oauth2.client.request.OAuthBearerClientRequest; +import org.apache.oltu.oauth2.client.request.OAuthClientRequest; +import org.apache.oltu.oauth2.client.request.OAuthClientRequest.AuthenticationRequestBuilder; +import org.apache.oltu.oauth2.client.request.OAuthClientRequest.TokenRequestBuilder; +import org.apache.oltu.oauth2.client.response.OAuthJSONAccessTokenResponse; +import org.apache.oltu.oauth2.common.exception.OAuthProblemException; +import org.apache.oltu.oauth2.common.exception.OAuthSystemException; +import org.apache.oltu.oauth2.common.message.types.GrantType; + +import com.squareup.okhttp.Interceptor; +import com.squareup.okhttp.OkHttpClient; +import com.squareup.okhttp.Request; +import com.squareup.okhttp.Request.Builder; +import com.squareup.okhttp.Response; + +public class OauthAuthorization implements Interceptor { + + private volatile String accessToken; + private OAuthClient oauthClient; + + private TokenRequestBuilder tokenRequestBuilder; + private AuthenticationRequestBuilder authenticationRequestBuilder; + + public OauthAuthorization( OkHttpClient client, TokenRequestBuilder requestBuilder ) { + this.oauthClient = new OAuthClient(new OauthOkHttpClient(client)); + this.tokenRequestBuilder = requestBuilder; + } + + public OauthAuthorization(TokenRequestBuilder requestBuilder ) { + this(new OkHttpClient(), requestBuilder); + } + + public OauthAuthorization(OauthFlow flow, String authorizationUrl, String tokenUrl, String scopes) { + this(OAuthClientRequest.tokenLocation(tokenUrl).setScope(scopes)); + setFlow(flow); + authenticationRequestBuilder = OAuthClientRequest.authorizationLocation(authorizationUrl); + } + + public void setFlow(OauthFlow flow) { + switch(flow) { + case accessCode: + case implicit: + tokenRequestBuilder.setGrantType(GrantType.AUTHORIZATION_CODE); + break; + case password: + tokenRequestBuilder.setGrantType(GrantType.PASSWORD); + break; + case application: + tokenRequestBuilder.setGrantType(GrantType.CLIENT_CREDENTIALS); + break; + default: + break; + } + } + + @Override + public Response intercept(Chain chain) + throws IOException { + + Request request = chain.request(); + + // If the request already have an authorization (eg. Basic auth), do nothing + if (request.header("Authorization") != null) { + return chain.proceed(request); + } + + // If first time, get the token + OAuthClientRequest oAuthRequest; + if (getAccessToken() == null) { + updateAccessToken(null); + } + + // Build the request + Builder rb = request.newBuilder(); + + String requestAccessToken = new String(getAccessToken()); + try { + oAuthRequest = new OAuthBearerClientRequest(request.urlString()) + .setAccessToken(requestAccessToken) + .buildHeaderMessage(); + } catch (OAuthSystemException e) { + throw new IOException(e); + } + + for ( Map.Entry header : oAuthRequest.getHeaders().entrySet() ) { + rb.addHeader(header.getKey(), header.getValue()); + } + rb.url( oAuthRequest.getLocationUri()); + + //Execute the request + Response response = chain.proceed(rb.build()); + + // 401 most likely indicates that access token has expired. + // Time to refresh and resend the request + if ( response.code() == HTTP_UNAUTHORIZED ) { + updateAccessToken(requestAccessToken); + return intercept( chain ); + } + return response; + } + + public synchronized void updateAccessToken(String requestAccessToken) throws IOException { + if (getAccessToken() == null || getAccessToken().equals(requestAccessToken)) { + try { + OAuthJSONAccessTokenResponse accessTokenResponse; + accessTokenResponse = oauthClient.accessToken(this.tokenRequestBuilder.buildBodyMessage()); + setAccessToken(accessTokenResponse.getAccessToken()); + } catch (OAuthSystemException e) { + throw new IOException(e); + } catch (OAuthProblemException e) { + throw new IOException(e); + } + } + } + + public synchronized String getAccessToken() { + return accessToken; + } + + public synchronized void setAccessToken(String accessToken) { + this.accessToken = accessToken; + } + + public TokenRequestBuilder getTokenRequestBuilder() { + return tokenRequestBuilder; + } + + public void setTokenRequestBuilder(TokenRequestBuilder tokenRequestBuilder) { + this.tokenRequestBuilder = tokenRequestBuilder; + } + + public AuthenticationRequestBuilder getAuthenticationRequestBuilder() { + return authenticationRequestBuilder; + } + + public void setAuthenticationRequestBuilder(AuthenticationRequestBuilder authenticationRequestBuilder) { + this.authenticationRequestBuilder = authenticationRequestBuilder; + } + +} diff --git a/samples/client/petstore/retrofit/src/main/java/io/swagger/client/auth/OauthFlow.java b/samples/client/petstore/retrofit/src/main/java/io/swagger/client/auth/OauthFlow.java new file mode 100644 index 00000000000..ba0a8f39f35 --- /dev/null +++ b/samples/client/petstore/retrofit/src/main/java/io/swagger/client/auth/OauthFlow.java @@ -0,0 +1,5 @@ +package io.swagger.client.auth; + +public enum OauthFlow { + accessCode, implicit, password, application +} \ No newline at end of file diff --git a/samples/client/petstore/retrofit/src/main/java/io/swagger/client/auth/OauthOkHttpClient.java b/samples/client/petstore/retrofit/src/main/java/io/swagger/client/auth/OauthOkHttpClient.java new file mode 100644 index 00000000000..a66bec0b158 --- /dev/null +++ b/samples/client/petstore/retrofit/src/main/java/io/swagger/client/auth/OauthOkHttpClient.java @@ -0,0 +1,69 @@ +package io.swagger.client.auth; + +import java.io.IOException; +import java.util.Map; +import java.util.Map.Entry; + +import org.apache.oltu.oauth2.client.HttpClient; +import org.apache.oltu.oauth2.client.request.OAuthClientRequest; +import org.apache.oltu.oauth2.client.response.OAuthClientResponse; +import org.apache.oltu.oauth2.client.response.OAuthClientResponseFactory; +import org.apache.oltu.oauth2.common.exception.OAuthProblemException; +import org.apache.oltu.oauth2.common.exception.OAuthSystemException; + +import com.squareup.okhttp.MediaType; +import com.squareup.okhttp.OkHttpClient; +import com.squareup.okhttp.Request; +import com.squareup.okhttp.RequestBody; +import com.squareup.okhttp.Response; + + +public class OauthOkHttpClient implements HttpClient { + + private OkHttpClient client; + + public OauthOkHttpClient() { + this.client = new OkHttpClient(); + } + + public OauthOkHttpClient(OkHttpClient client) { + this.client = client; + } + + public T execute(OAuthClientRequest request, Map headers, + String requestMethod, Class responseClass) + throws OAuthSystemException, OAuthProblemException { + + MediaType mediaType = MediaType.parse("application/json"); + Request.Builder requestBuilder = new Request.Builder().url(request.getLocationUri()); + + if(headers != null) { + for (Entry entry : headers.entrySet()) { + if (entry.getKey().equalsIgnoreCase("Content-Type")) { + mediaType = MediaType.parse(entry.getValue()); + } else { + requestBuilder.addHeader(entry.getKey(), entry.getValue()); + } + } + } + + RequestBody body = request.getBody() != null ? RequestBody.create(mediaType, request.getBody()) : null; + requestBuilder.method(requestMethod, body); + + try { + Response response = client.newCall(requestBuilder.build()).execute(); + return OAuthClientResponseFactory.createCustomResponse( + response.body().string(), + response.body().contentType().toString(), + response.code(), + responseClass); + } catch (IOException e) { + throw new OAuthSystemException(e); + } + } + + public void shutdown() { + // Nothing to do here + } + +} diff --git a/samples/client/petstore/retrofit/src/main/java/io/swagger/client/model/ApiResponse.java b/samples/client/petstore/retrofit/src/main/java/io/swagger/client/model/ApiResponse.java new file mode 100644 index 00000000000..a929a54dc81 --- /dev/null +++ b/samples/client/petstore/retrofit/src/main/java/io/swagger/client/model/ApiResponse.java @@ -0,0 +1,63 @@ +package io.swagger.client.model; + + +import io.swagger.annotations.*; +import com.google.gson.annotations.SerializedName; + + +@ApiModel(description = "") +public class ApiResponse { + + + /** + **/ + @ApiModelProperty(value = "") + @SerializedName("code") + private Integer code = null; + + /** + **/ + @ApiModelProperty(value = "") + @SerializedName("type") + private String type = null; + + /** + **/ + @ApiModelProperty(value = "") + @SerializedName("message") + private String message = null; + + + public Integer getCode() { + return code; + } + public void setCode(Integer code) { + this.code = code; + } + + public String getType() { + return type; + } + public void setType(String type) { + this.type = type; + } + + public String getMessage() { + return message; + } + public void setMessage(String message) { + this.message = message; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class ApiResponse {\n"); + + sb.append(" code: ").append(code).append("\n"); + sb.append(" type: ").append(type).append("\n"); + sb.append(" message: ").append(message).append("\n"); + sb.append("}\n"); + return sb.toString(); + } +} diff --git a/samples/client/petstore/retrofit/src/main/java/io/swagger/client/model/Pet.java b/samples/client/petstore/retrofit/src/main/java/io/swagger/client/model/Pet.java index 7d1368a74e0..f74264708e3 100644 --- a/samples/client/petstore/retrofit/src/main/java/io/swagger/client/model/Pet.java +++ b/samples/client/petstore/retrofit/src/main/java/io/swagger/client/model/Pet.java @@ -1,8 +1,8 @@ package io.swagger.client.model; import io.swagger.client.model.Category; -import io.swagger.client.model.Tag; import java.util.*; +import io.swagger.client.model.Tag; import io.swagger.annotations.*; import com.google.gson.annotations.SerializedName; diff --git a/samples/client/petstore/retrofit/src/test/java/io/swagger/petstore/test/PetApiTest.java b/samples/client/petstore/retrofit/src/test/java/io/swagger/petstore/test/PetApiTest.java index e7613f189a3..d015095b5c9 100644 --- a/samples/client/petstore/retrofit/src/test/java/io/swagger/petstore/test/PetApiTest.java +++ b/samples/client/petstore/retrofit/src/test/java/io/swagger/petstore/test/PetApiTest.java @@ -22,7 +22,7 @@ public class PetApiTest { @Before public void setup() { - api = ServiceGenerator.createService(PetApi.class); + api = new ServiceGenerator().createService(PetApi.class); } @Test @@ -108,7 +108,7 @@ public class PetApiTest { Pet fetched = api.getPetById(pet.getId()); - api.updatePetWithForm(String.valueOf(fetched.getId()), "furt", null); + api.updatePetWithForm(fetched.getId(), "furt", null); Pet updated = api.getPetById(fetched.getId()); assertEquals(updated.getName(), "furt"); diff --git a/samples/client/petstore/retrofit/src/test/java/io/swagger/petstore/test/StoreApiTest.java b/samples/client/petstore/retrofit/src/test/java/io/swagger/petstore/test/StoreApiTest.java index 3b406cac0b5..629a24cc775 100644 --- a/samples/client/petstore/retrofit/src/test/java/io/swagger/petstore/test/StoreApiTest.java +++ b/samples/client/petstore/retrofit/src/test/java/io/swagger/petstore/test/StoreApiTest.java @@ -16,7 +16,7 @@ public class StoreApiTest { @Before public void setup() { - api = ServiceGenerator.createService(StoreApi.class); + api = new ServiceGenerator().createService(StoreApi.class); } @Test @@ -30,7 +30,7 @@ public class StoreApiTest { Order order = createOrder(); api.placeOrder(order); - Order fetched = api.getOrderById(String.valueOf(order.getId())); + Order fetched = api.getOrderById(order.getId()); assertEquals(order.getId(), fetched.getId()); assertEquals(order.getPetId(), fetched.getPetId()); assertEquals(order.getQuantity(), fetched.getQuantity()); @@ -41,13 +41,13 @@ public class StoreApiTest { Order order = createOrder(); api.placeOrder(order); - Order fetched = api.getOrderById(String.valueOf(order.getId())); + Order fetched = api.getOrderById(order.getId()); assertEquals(fetched.getId(), order.getId()); api.deleteOrder(String.valueOf(order.getId())); try { - api.getOrderById(String.valueOf(order.getId())); + api.getOrderById(order.getId()); // fail("expected an error"); } catch (RetrofitError e) { // ok diff --git a/samples/client/petstore/retrofit/src/test/java/io/swagger/petstore/test/UserApiTest.java b/samples/client/petstore/retrofit/src/test/java/io/swagger/petstore/test/UserApiTest.java index 6613f0c03ad..45a5f1160e1 100644 --- a/samples/client/petstore/retrofit/src/test/java/io/swagger/petstore/test/UserApiTest.java +++ b/samples/client/petstore/retrofit/src/test/java/io/swagger/petstore/test/UserApiTest.java @@ -15,7 +15,7 @@ public class UserApiTest { @Before public void setup() { - api = ServiceGenerator.createService(UserApi.class); + api = new ServiceGenerator().createService(UserApi.class); } @Test