forked from Qortal/qortal
CHANGED: simplified API error annotations in API resources
FIXED: ApiErrorFactory used no context path and wrong translation key CHANGED: renamed parameters in Translator for consistency
This commit is contained in:
parent
d2aab4b446
commit
6590863201
@ -1,19 +1,27 @@
|
|||||||
|
|
||||||
package api;
|
package api;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.databind.node.ArrayNode;
|
||||||
import globalization.ContextPaths;
|
import globalization.ContextPaths;
|
||||||
import globalization.Translator;
|
import globalization.Translator;
|
||||||
|
import io.swagger.v3.core.converter.ModelConverters;
|
||||||
import io.swagger.v3.jaxrs2.Reader;
|
import io.swagger.v3.jaxrs2.Reader;
|
||||||
import io.swagger.v3.jaxrs2.ReaderListener;
|
import io.swagger.v3.jaxrs2.ReaderListener;
|
||||||
|
import io.swagger.v3.oas.models.media.Content;
|
||||||
import io.swagger.v3.oas.models.OpenAPI;
|
import io.swagger.v3.oas.models.OpenAPI;
|
||||||
import io.swagger.v3.oas.models.Operation;
|
import io.swagger.v3.oas.models.Operation;
|
||||||
import io.swagger.v3.oas.models.PathItem;
|
import io.swagger.v3.oas.models.PathItem;
|
||||||
|
import io.swagger.v3.oas.models.examples.Example;
|
||||||
import io.swagger.v3.oas.models.info.Info;
|
import io.swagger.v3.oas.models.info.Info;
|
||||||
|
import io.swagger.v3.oas.models.media.MediaType;
|
||||||
|
import io.swagger.v3.oas.models.media.Schema;
|
||||||
import io.swagger.v3.oas.models.responses.ApiResponse;
|
import io.swagger.v3.oas.models.responses.ApiResponse;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
|
||||||
public class AnnotationPostProcessor implements ReaderListener {
|
public class AnnotationPostProcessor implements ReaderListener {
|
||||||
|
|
||||||
private class ContextInformation {
|
private class ContextInformation {
|
||||||
@ -22,13 +30,15 @@ public class AnnotationPostProcessor implements ReaderListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private final Translator translator;
|
private final Translator translator;
|
||||||
|
private final ApiErrorFactory apiErrorFactory;
|
||||||
|
|
||||||
public AnnotationPostProcessor() {
|
public AnnotationPostProcessor() {
|
||||||
this(Translator.getInstance());
|
this(Translator.getInstance(), ApiErrorFactory.getInstance());
|
||||||
}
|
}
|
||||||
|
|
||||||
public AnnotationPostProcessor(Translator translator) {
|
public AnnotationPostProcessor(Translator translator, ApiErrorFactory apiErrorFactory) {
|
||||||
this.translator = translator;
|
this.translator = translator;
|
||||||
|
this.apiErrorFactory = apiErrorFactory;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -41,31 +51,60 @@ public class AnnotationPostProcessor implements ReaderListener {
|
|||||||
Info resourceInfo = openAPI.getInfo();
|
Info resourceInfo = openAPI.getInfo();
|
||||||
ContextInformation resourceContext = getContextInformation(openAPI.getExtensions());
|
ContextInformation resourceContext = getContextInformation(openAPI.getExtensions());
|
||||||
removeTranslationAnnotations(openAPI.getExtensions());
|
removeTranslationAnnotations(openAPI.getExtensions());
|
||||||
TranslateProperty(Constants.TRANSLATABLE_INFO_PROPERTIES, resourceContext, resourceInfo);
|
TranslateProperties(Constants.TRANSLATABLE_INFO_PROPERTIES, resourceContext, resourceInfo);
|
||||||
|
|
||||||
for (Map.Entry<String, PathItem> pathEntry : openAPI.getPaths().entrySet())
|
for (Map.Entry<String, PathItem> pathEntry : openAPI.getPaths().entrySet())
|
||||||
{
|
{
|
||||||
PathItem pathItem = pathEntry.getValue();
|
PathItem pathItem = pathEntry.getValue();
|
||||||
ContextInformation pathContext = getContextInformation(pathItem.getExtensions(), resourceContext);
|
ContextInformation pathContext = getContextInformation(pathItem.getExtensions(), resourceContext);
|
||||||
removeTranslationAnnotations(pathItem.getExtensions());
|
removeTranslationAnnotations(pathItem.getExtensions());
|
||||||
TranslateProperty(Constants.TRANSLATABLE_PATH_ITEM_PROPERTIES, pathContext, pathItem);
|
TranslateProperties(Constants.TRANSLATABLE_PATH_ITEM_PROPERTIES, pathContext, pathItem);
|
||||||
|
|
||||||
for (Operation operation : pathItem.readOperations()) {
|
for (Operation operation : pathItem.readOperations()) {
|
||||||
ContextInformation operationContext = getContextInformation(operation.getExtensions(), pathContext);
|
ContextInformation operationContext = getContextInformation(operation.getExtensions(), pathContext);
|
||||||
removeTranslationAnnotations(operation.getExtensions());
|
removeTranslationAnnotations(operation.getExtensions());
|
||||||
TranslateProperty(Constants.TRANSLATABLE_OPERATION_PROPERTIES, operationContext, operation);
|
TranslateProperties(Constants.TRANSLATABLE_OPERATION_PROPERTIES, operationContext, operation);
|
||||||
|
|
||||||
|
addApiErrorResponses(operation);
|
||||||
|
removeApiErrorsAnnotations(operation.getExtensions());
|
||||||
|
|
||||||
for (Map.Entry<String, ApiResponse> responseEntry : operation.getResponses().entrySet()) {
|
for (Map.Entry<String, ApiResponse> responseEntry : operation.getResponses().entrySet()) {
|
||||||
ApiResponse response = responseEntry.getValue();
|
ApiResponse response = responseEntry.getValue();
|
||||||
ContextInformation responseContext = getContextInformation(response.getExtensions(), operationContext);
|
ContextInformation responseContext = getContextInformation(response.getExtensions(), operationContext);
|
||||||
removeTranslationAnnotations(response.getExtensions());
|
removeTranslationAnnotations(response.getExtensions());
|
||||||
TranslateProperty(Constants.TRANSLATABLE_API_RESPONSE_PROPERTIES, responseContext, response);
|
TranslateProperties(Constants.TRANSLATABLE_API_RESPONSE_PROPERTIES, responseContext, response);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private <T> void TranslateProperty(List<TranslatableProperty<T>> translatableProperties, ContextInformation context, T item) {
|
private void addApiErrorResponses(Operation operation) {
|
||||||
|
List<ApiError> apiErrors = getApiErrors(operation.getExtensions());
|
||||||
|
if(apiErrors != null) {
|
||||||
|
for(ApiError apiError : apiErrors) {
|
||||||
|
String statusCode = Integer.toString(apiError.getStatus());
|
||||||
|
ApiResponse apiResponse = operation.getResponses().get(statusCode);
|
||||||
|
if(apiResponse == null) {
|
||||||
|
Schema errorMessageSchema = ModelConverters.getInstance().readAllAsResolvedSchema(ApiErrorMessage.class).schema;
|
||||||
|
MediaType mediaType = new MediaType().schema(errorMessageSchema);
|
||||||
|
Content content = new Content().addMediaType(javax.ws.rs.core.MediaType.APPLICATION_JSON, mediaType);
|
||||||
|
apiResponse = new ApiResponse().content(content);
|
||||||
|
operation.getResponses().addApiResponse(statusCode, apiResponse);
|
||||||
|
}
|
||||||
|
|
||||||
|
int apiErrorCode = apiError.getCode();
|
||||||
|
ApiErrorMessage apiErrorMessage = new ApiErrorMessage(apiErrorCode, this.apiErrorFactory.getErrorMessage(apiError));
|
||||||
|
Example example = new Example().value(apiErrorMessage);
|
||||||
|
|
||||||
|
// XXX: addExamples(..) is not working in Swagger 2.0.4. This bug is referenced in https://github.com/swagger-api/swagger-ui/issues/2651
|
||||||
|
// Replace the call to .setExample(..) by .addExamples(..) when the bug is fixed.
|
||||||
|
apiResponse.getContent().get(javax.ws.rs.core.MediaType.APPLICATION_JSON).setExample(example);
|
||||||
|
//apiResponse.getContent().get(javax.ws.rs.core.MediaType.APPLICATION_JSON).addExamples(Integer.toString(apiErrorCode), example);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private <T> void TranslateProperties(List<TranslatableProperty<T>> translatableProperties, ContextInformation context, T item) {
|
||||||
if(context.keys != null) {
|
if(context.keys != null) {
|
||||||
Map<String, String> keys = context.keys;
|
Map<String, String> keys = context.keys;
|
||||||
for(TranslatableProperty<T> prop : translatableProperties) {
|
for(TranslatableProperty<T> prop : translatableProperties) {
|
||||||
@ -80,6 +119,48 @@ public class AnnotationPostProcessor implements ReaderListener {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private List<ApiError> getApiErrors(Map<String, Object> extensions) {
|
||||||
|
if(extensions == null)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
List<String> apiErrorStrings = new ArrayList();
|
||||||
|
try {
|
||||||
|
ArrayNode apiErrorsNode = (ArrayNode)extensions.get("x-" + Constants.API_ERRORS_EXTENSION_NAME);
|
||||||
|
if(apiErrorsNode == null)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
for(int i = 0; i < apiErrorsNode.size(); i++) {
|
||||||
|
String errorString = apiErrorsNode.get(i).asText();
|
||||||
|
apiErrorStrings.add(errorString);
|
||||||
|
}
|
||||||
|
} catch(Exception e) {
|
||||||
|
// TODO: error logging
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<ApiError> result = new ArrayList<>();
|
||||||
|
for(String apiErrorString : apiErrorStrings) {
|
||||||
|
ApiError apiError = null;
|
||||||
|
try {
|
||||||
|
apiError = ApiError.valueOf(apiErrorString);
|
||||||
|
} catch(IllegalArgumentException e) {
|
||||||
|
try {
|
||||||
|
int errorCodeInt = Integer.parseInt(apiErrorString);
|
||||||
|
apiError = ApiError.fromCode(errorCodeInt);
|
||||||
|
} catch (NumberFormatException ex) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(apiError == null)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
result.add(apiError);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
private ContextInformation getContextInformation(Map<String, Object> extensions) {
|
private ContextInformation getContextInformation(Map<String, Object> extensions) {
|
||||||
return getContextInformation(extensions, null);
|
return getContextInformation(extensions, null);
|
||||||
}
|
}
|
||||||
@ -104,11 +185,21 @@ public class AnnotationPostProcessor implements ReaderListener {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void removeApiErrorsAnnotations(Map<String, Object> extensions) {
|
||||||
|
String extensionName = Constants.API_ERRORS_EXTENSION_NAME;
|
||||||
|
removeExtension(extensions, extensionName);
|
||||||
|
}
|
||||||
|
|
||||||
private void removeTranslationAnnotations(Map<String, Object> extensions) {
|
private void removeTranslationAnnotations(Map<String, Object> extensions) {
|
||||||
|
String extensionName = Constants.TRANSLATION_EXTENSION_NAME;
|
||||||
|
removeExtension(extensions, extensionName);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void removeExtension(Map<String, Object> extensions, String extensionName) {
|
||||||
if(extensions == null)
|
if(extensions == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
extensions.remove("x-" + Constants.TRANSLATION_EXTENSION_NAME);
|
extensions.remove("x-" + extensionName);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Map<String, String> getTranslationKeys(Map<String, Object> translationDefinitions) {
|
private Map<String, String> getTranslationKeys(Map<String, Object> translationDefinitions) {
|
||||||
|
@ -110,6 +110,15 @@ public enum ApiError {
|
|||||||
this.status = status;
|
this.status = status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static ApiError fromCode(int code) {
|
||||||
|
for(ApiError apiError : ApiError.values()) {
|
||||||
|
if(apiError.code == code)
|
||||||
|
return apiError;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
int getCode() {
|
int getCode() {
|
||||||
return this.code;
|
return this.code;
|
||||||
}
|
}
|
||||||
|
@ -147,13 +147,17 @@ public class ApiErrorFactory {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private ErrorMessageEntry createErrorMessageEntry(ApiError errorCode, String defaultTemplate, AbstractMap.SimpleEntry<String, Object>... templateValues) {
|
private ErrorMessageEntry createErrorMessageEntry(ApiError errorCode, String defaultTemplate, AbstractMap.SimpleEntry<String, Object>... templateValues) {
|
||||||
String templateKey = String.format("%s: ApiError.%s message", ApiErrorFactory.class.getSimpleName(), errorCode.name());
|
String templateKey = String.format(Constants.APIERROR_KEY, errorCode.name());
|
||||||
return new ErrorMessageEntry(templateKey, defaultTemplate, templateValues);
|
return new ErrorMessageEntry(templateKey, defaultTemplate, templateValues);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getErrorMessage(ApiError error) {
|
||||||
|
return getErrorMessage(null, error);
|
||||||
|
}
|
||||||
|
|
||||||
public String getErrorMessage(Locale locale, ApiError error) {
|
public String getErrorMessage(Locale locale, ApiError error) {
|
||||||
ErrorMessageEntry errorMessage = this.errorMessages.get(error);
|
ErrorMessageEntry errorMessage = this.errorMessages.get(error);
|
||||||
String message = this.translator.translate(locale, errorMessage.templateKey, errorMessage.defaultTemplate, errorMessage.templateValues);
|
String message = this.translator.translate(locale, Constants.APIERROR_CONTEXT_PATH, errorMessage.templateKey, errorMessage.defaultTemplate, errorMessage.templateValues);
|
||||||
return message;
|
return message;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -48,10 +48,15 @@ public class BlocksResource {
|
|||||||
@Path("/{signature}")
|
@Path("/{signature}")
|
||||||
@Operation(
|
@Operation(
|
||||||
description = "returns the block that matches the given signature",
|
description = "returns the block that matches the given signature",
|
||||||
extensions = @Extension(name = "translation", properties = {
|
extensions = {
|
||||||
@ExtensionProperty(name="path", value="GET signature"),
|
@Extension(name = "translation", properties = {
|
||||||
@ExtensionProperty(name="description.key", value="operation:description")
|
@ExtensionProperty(name="path", value="GET signature"),
|
||||||
}),
|
@ExtensionProperty(name="description.key", value="operation:description")
|
||||||
|
}),
|
||||||
|
@Extension(properties = {
|
||||||
|
@ExtensionProperty(name="apiErrors", value="[\"INVALID_SIGNATURE\", \"BLOCK_NO_EXISTS\"]", parseValue = true),
|
||||||
|
})
|
||||||
|
},
|
||||||
responses = {
|
responses = {
|
||||||
@ApiResponse(
|
@ApiResponse(
|
||||||
description = "the block",
|
description = "the block",
|
||||||
@ -61,32 +66,6 @@ public class BlocksResource {
|
|||||||
@ExtensionProperty(name="description.key", value="success_response:description")
|
@ExtensionProperty(name="description.key", value="success_response:description")
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
),
|
|
||||||
@ApiResponse(
|
|
||||||
responseCode = "400",
|
|
||||||
description = "invalid signature",
|
|
||||||
content = @Content(schema = @Schema(implementation = ApiErrorMessage.class)),
|
|
||||||
extensions = {
|
|
||||||
@Extension(properties = {
|
|
||||||
@ExtensionProperty(name="apiErrorCode", value="101")
|
|
||||||
}),
|
|
||||||
@Extension(name = "translation", properties = {
|
|
||||||
@ExtensionProperty(name="description.key", value="ApiError/101")
|
|
||||||
})
|
|
||||||
}
|
|
||||||
),
|
|
||||||
@ApiResponse(
|
|
||||||
responseCode = "422",
|
|
||||||
description = "block does not exist",
|
|
||||||
content = @Content(schema = @Schema(implementation = ApiErrorMessage.class)),
|
|
||||||
extensions = {
|
|
||||||
@Extension(properties = {
|
|
||||||
@ExtensionProperty(name="apiErrorCode", value="301")
|
|
||||||
}),
|
|
||||||
@Extension(name = "translation", properties = {
|
|
||||||
@ExtensionProperty(name="description.key", value="ApiError/301")
|
|
||||||
})
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
@ -196,10 +175,15 @@ public class BlocksResource {
|
|||||||
@Path("/child/{signature}")
|
@Path("/child/{signature}")
|
||||||
@Operation(
|
@Operation(
|
||||||
description = "returns the child block of the block that matches the given signature",
|
description = "returns the child block of the block that matches the given signature",
|
||||||
extensions = @Extension(name = "translation", properties = {
|
extensions = {
|
||||||
@ExtensionProperty(name="path", value="GET child:signature"),
|
@Extension(name = "translation", properties = {
|
||||||
@ExtensionProperty(name="description.key", value="operation:description")
|
@ExtensionProperty(name="path", value="GET child:signature"),
|
||||||
}),
|
@ExtensionProperty(name="description.key", value="operation:description")
|
||||||
|
}),
|
||||||
|
@Extension(properties = {
|
||||||
|
@ExtensionProperty(name="apiErrors", value="[\"INVALID_SIGNATURE\", \"BLOCK_NO_EXISTS\"]", parseValue = true),
|
||||||
|
})
|
||||||
|
},
|
||||||
responses = {
|
responses = {
|
||||||
@ApiResponse(
|
@ApiResponse(
|
||||||
description = "the block",
|
description = "the block",
|
||||||
@ -209,32 +193,6 @@ public class BlocksResource {
|
|||||||
@ExtensionProperty(name="description.key", value="success_response:description")
|
@ExtensionProperty(name="description.key", value="success_response:description")
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
),
|
|
||||||
@ApiResponse(
|
|
||||||
responseCode = "400",
|
|
||||||
description = "invalid signature",
|
|
||||||
content = @Content(schema = @Schema(implementation = ApiErrorMessage.class)),
|
|
||||||
extensions = {
|
|
||||||
@Extension(properties = {
|
|
||||||
@ExtensionProperty(name="apiErrorCode", value="101")
|
|
||||||
}),
|
|
||||||
@Extension(name = "translation", properties = {
|
|
||||||
@ExtensionProperty(name="description.key", value="ApiError/101")
|
|
||||||
})
|
|
||||||
}
|
|
||||||
),
|
|
||||||
@ApiResponse(
|
|
||||||
responseCode = "422",
|
|
||||||
description = "block does not exist",
|
|
||||||
content = @Content(schema = @Schema(implementation = ApiErrorMessage.class)),
|
|
||||||
extensions = {
|
|
||||||
@Extension(properties = {
|
|
||||||
@ExtensionProperty(name="apiErrorCode", value="301")
|
|
||||||
}),
|
|
||||||
@Extension(name = "translation", properties = {
|
|
||||||
@ExtensionProperty(name="description.key", value="ApiError/301")
|
|
||||||
})
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
@ -303,10 +261,15 @@ public class BlocksResource {
|
|||||||
@Path("/generatingbalance/{signature}")
|
@Path("/generatingbalance/{signature}")
|
||||||
@Operation(
|
@Operation(
|
||||||
description = "calculates the generating balance of the block that will follow the block that matches the signature",
|
description = "calculates the generating balance of the block that will follow the block that matches the signature",
|
||||||
extensions = @Extension(name = "translation", properties = {
|
extensions = {
|
||||||
@ExtensionProperty(name="path", value="GET generatingbalance:signature"),
|
@Extension(name = "translation", properties = {
|
||||||
@ExtensionProperty(name="description.key", value="operation:description")
|
@ExtensionProperty(name="path", value="GET generatingbalance:signature"),
|
||||||
}),
|
@ExtensionProperty(name="description.key", value="operation:description")
|
||||||
|
}),
|
||||||
|
@Extension(properties = {
|
||||||
|
@ExtensionProperty(name="apiErrors", value="[\"INVALID_SIGNATURE\", \"BLOCK_NO_EXISTS\"]", parseValue = true),
|
||||||
|
})
|
||||||
|
},
|
||||||
responses = {
|
responses = {
|
||||||
@ApiResponse(
|
@ApiResponse(
|
||||||
description = "the block",
|
description = "the block",
|
||||||
@ -316,32 +279,6 @@ public class BlocksResource {
|
|||||||
@ExtensionProperty(name="description.key", value="success_response:description")
|
@ExtensionProperty(name="description.key", value="success_response:description")
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
),
|
|
||||||
@ApiResponse(
|
|
||||||
responseCode = "400",
|
|
||||||
description = "invalid signature",
|
|
||||||
content = @Content(schema = @Schema(implementation = ApiErrorMessage.class)),
|
|
||||||
extensions = {
|
|
||||||
@Extension(properties = {
|
|
||||||
@ExtensionProperty(name="apiErrorCode", value="101")
|
|
||||||
}),
|
|
||||||
@Extension(name = "translation", properties = {
|
|
||||||
@ExtensionProperty(name="description.key", value="ApiError/101")
|
|
||||||
})
|
|
||||||
}
|
|
||||||
),
|
|
||||||
@ApiResponse(
|
|
||||||
responseCode = "422",
|
|
||||||
description = "block does not exist",
|
|
||||||
content = @Content(schema = @Schema(implementation = ApiErrorMessage.class)),
|
|
||||||
extensions = {
|
|
||||||
@Extension(properties = {
|
|
||||||
@ExtensionProperty(name="apiErrorCode", value="301")
|
|
||||||
}),
|
|
||||||
@Extension(name = "translation", properties = {
|
|
||||||
@ExtensionProperty(name="description.key", value="ApiError/301")
|
|
||||||
})
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
@ -437,10 +374,15 @@ public class BlocksResource {
|
|||||||
@Path("/height/{signature}")
|
@Path("/height/{signature}")
|
||||||
@Operation(
|
@Operation(
|
||||||
description = "returns the block height of the block that matches the given signature",
|
description = "returns the block height of the block that matches the given signature",
|
||||||
extensions = @Extension(name = "translation", properties = {
|
extensions = {
|
||||||
@ExtensionProperty(name="path", value="GET height:signature"),
|
@Extension(name = "translation", properties = {
|
||||||
@ExtensionProperty(name="description.key", value="operation:description")
|
@ExtensionProperty(name="path", value="GET height:signature"),
|
||||||
}),
|
@ExtensionProperty(name="description.key", value="operation:description")
|
||||||
|
}),
|
||||||
|
@Extension(properties = {
|
||||||
|
@ExtensionProperty(name="apiErrors", value="[\"INVALID_SIGNATURE\", \"BLOCK_NO_EXISTS\"]", parseValue = true),
|
||||||
|
})
|
||||||
|
},
|
||||||
responses = {
|
responses = {
|
||||||
@ApiResponse(
|
@ApiResponse(
|
||||||
description = "the height",
|
description = "the height",
|
||||||
@ -450,32 +392,6 @@ public class BlocksResource {
|
|||||||
@ExtensionProperty(name="description.key", value="success_response:description")
|
@ExtensionProperty(name="description.key", value="success_response:description")
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
),
|
|
||||||
@ApiResponse(
|
|
||||||
responseCode = "400",
|
|
||||||
description = "invalid signature",
|
|
||||||
content = @Content(schema = @Schema(implementation = ApiErrorMessage.class)),
|
|
||||||
extensions = {
|
|
||||||
@Extension(properties = {
|
|
||||||
@ExtensionProperty(name="apiErrorCode", value="101")
|
|
||||||
}),
|
|
||||||
@Extension(name = "translation", properties = {
|
|
||||||
@ExtensionProperty(name="description.key", value="ApiError/101")
|
|
||||||
})
|
|
||||||
}
|
|
||||||
),
|
|
||||||
@ApiResponse(
|
|
||||||
responseCode = "422",
|
|
||||||
description = "block does not exist",
|
|
||||||
content = @Content(schema = @Schema(implementation = ApiErrorMessage.class)),
|
|
||||||
extensions = {
|
|
||||||
@Extension(properties = {
|
|
||||||
@ExtensionProperty(name="apiErrorCode", value="301")
|
|
||||||
}),
|
|
||||||
@Extension(name = "translation", properties = {
|
|
||||||
@ExtensionProperty(name="description.key", value="ApiError/301")
|
|
||||||
})
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
@ -511,10 +427,15 @@ public class BlocksResource {
|
|||||||
@Path("/byheight/{height}")
|
@Path("/byheight/{height}")
|
||||||
@Operation(
|
@Operation(
|
||||||
description = "returns the block whith given height",
|
description = "returns the block whith given height",
|
||||||
extensions = @Extension(name = "translation", properties = {
|
extensions = {
|
||||||
@ExtensionProperty(name="path", value="GET byheight:height"),
|
@Extension(name = "translation", properties = {
|
||||||
@ExtensionProperty(name="description.key", value="operation:description")
|
@ExtensionProperty(name="path", value="GET byheight:height"),
|
||||||
}),
|
@ExtensionProperty(name="description.key", value="operation:description")
|
||||||
|
}),
|
||||||
|
@Extension(properties = {
|
||||||
|
@ExtensionProperty(name="apiErrors", value="[\"BLOCK_NO_EXISTS\"]", parseValue = true),
|
||||||
|
})
|
||||||
|
},
|
||||||
responses = {
|
responses = {
|
||||||
@ApiResponse(
|
@ApiResponse(
|
||||||
description = "the block",
|
description = "the block",
|
||||||
@ -524,19 +445,6 @@ public class BlocksResource {
|
|||||||
@ExtensionProperty(name="description.key", value="success_response:description")
|
@ExtensionProperty(name="description.key", value="success_response:description")
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
),
|
|
||||||
@ApiResponse(
|
|
||||||
responseCode = "422",
|
|
||||||
description = "block does not exist",
|
|
||||||
content = @Content(schema = @Schema(implementation = ApiErrorMessage.class)),
|
|
||||||
extensions = {
|
|
||||||
@Extension(properties = {
|
|
||||||
@ExtensionProperty(name="apiErrorCode", value="301")
|
|
||||||
}),
|
|
||||||
@Extension(name = "translation", properties = {
|
|
||||||
@ExtensionProperty(name="description.key", value="ApiError/301")
|
|
||||||
})
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
@ -8,7 +8,9 @@ import static java.util.Arrays.asList;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
class Constants {
|
class Constants {
|
||||||
|
public static final String APIERROR_CONTEXT_PATH = "/Api";
|
||||||
|
public static final String APIERROR_KEY = "ApiError/%s";
|
||||||
|
|
||||||
public static final String TRANSLATION_EXTENSION_NAME = "translation";
|
public static final String TRANSLATION_EXTENSION_NAME = "translation";
|
||||||
public static final String TRANSLATION_PATH_EXTENSION_NAME = "path";
|
public static final String TRANSLATION_PATH_EXTENSION_NAME = "path";
|
||||||
|
|
||||||
@ -17,8 +19,8 @@ class Constants {
|
|||||||
public static final String TRANSLATION_ANNOTATION_TITLE_KEY = "title.key";
|
public static final String TRANSLATION_ANNOTATION_TITLE_KEY = "title.key";
|
||||||
public static final String TRANSLATION_ANNOTATION_TERMS_OF_SERVICE_KEY = "termsOfService.key";
|
public static final String TRANSLATION_ANNOTATION_TERMS_OF_SERVICE_KEY = "termsOfService.key";
|
||||||
|
|
||||||
|
public static final String API_ERRORS_EXTENSION_NAME = "apiErrors";
|
||||||
public static final String API_ERROR_CODE_EXTENSION_NAME = "apiErrorCode";
|
public static final String API_ERROR_CODE_EXTENSION_NAME = "apiErrorCode";
|
||||||
|
|
||||||
|
|
||||||
public static final List<TranslatableProperty<Info>> TRANSLATABLE_INFO_PROPERTIES = asList(
|
public static final List<TranslatableProperty<Info>> TRANSLATABLE_INFO_PROPERTIES = asList(
|
||||||
new TranslatableProperty<Info>() {
|
new TranslatableProperty<Info>() {
|
||||||
|
@ -53,7 +53,7 @@ public class TranslationXmlStreamReader {
|
|||||||
|
|
||||||
State state = new State(Locale.forLanguageTag("default"), "/");
|
State state = new State(Locale.forLanguageTag("default"), "/");
|
||||||
|
|
||||||
List<TranslationEntry> result = new ArrayList<TranslationEntry>();
|
List<TranslationEntry> result = new ArrayList<>();
|
||||||
if (eventReader.hasNext())
|
if (eventReader.hasNext())
|
||||||
{
|
{
|
||||||
XMLEvent event = eventReader.nextTag();
|
XMLEvent event = eventReader.nextTag();
|
||||||
|
@ -89,52 +89,52 @@ public class Translator {
|
|||||||
return map;
|
return map;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String translate(Locale locale, String contextPath, String templateKey, AbstractMap.Entry<String, Object>... templateValues) {
|
public String translate(Locale locale, String contextPath, String keyPath, AbstractMap.Entry<String, Object>... templateValues) {
|
||||||
Map<String, Object> map = createMap(templateValues);
|
Map<String, Object> map = createMap(templateValues);
|
||||||
return translate(locale, contextPath, templateKey, map);
|
return translate(locale, contextPath, keyPath, map);
|
||||||
}
|
}
|
||||||
|
|
||||||
public String translate(String contextPath, String templateKey, AbstractMap.Entry<String, Object>... templateValues) {
|
public String translate(String contextPath, String keyPath, AbstractMap.Entry<String, Object>... templateValues) {
|
||||||
Map<String, Object> map = createMap(templateValues);
|
Map<String, Object> map = createMap(templateValues);
|
||||||
return translate(contextPath, templateKey, map);
|
return translate(contextPath, keyPath, map);
|
||||||
}
|
}
|
||||||
|
|
||||||
public String translate(Locale locale, String contextPath, String templateKey, Map<String, Object> templateValues) {
|
public String translate(Locale locale, String contextPath, String keyPath, Map<String, Object> templateValues) {
|
||||||
return translate(locale, contextPath, templateKey, null, templateValues);
|
return translate(locale, contextPath, keyPath, null, templateValues);
|
||||||
}
|
}
|
||||||
|
|
||||||
public String translate(String contextPath, String templateKey, Map<String, Object> templateValues) {
|
public String translate(String contextPath, String keyPath, Map<String, Object> templateValues) {
|
||||||
return translate(contextPath, templateKey, null, templateValues);
|
return translate(contextPath, keyPath, null, templateValues);
|
||||||
}
|
}
|
||||||
|
|
||||||
public String translate(Locale locale, String contextPath, String templateKey, String defaultTemplate, AbstractMap.Entry<String, Object>... templateValues) {
|
public String translate(Locale locale, String contextPath, String keyPath, String defaultTemplate, AbstractMap.Entry<String, Object>... templateValues) {
|
||||||
Map<String, Object> map = createMap(templateValues);
|
Map<String, Object> map = createMap(templateValues);
|
||||||
return translate(locale, contextPath, templateKey, defaultTemplate, map);
|
return translate(locale, contextPath, keyPath, defaultTemplate, map);
|
||||||
}
|
}
|
||||||
|
|
||||||
public String translate(String contextPath, String templateKey, String defaultTemplate, AbstractMap.Entry<String, Object>... templateValues) {
|
public String translate(String contextPath, String keyPath, String defaultTemplate, AbstractMap.Entry<String, Object>... templateValues) {
|
||||||
Map<String, Object> map = createMap(templateValues);
|
Map<String, Object> map = createMap(templateValues);
|
||||||
return translate(contextPath, templateKey, defaultTemplate, map);
|
return translate(contextPath, keyPath, defaultTemplate, map);
|
||||||
}
|
}
|
||||||
|
|
||||||
public String translate(Locale locale, String contextPath, String templateKey, String defaultTemplate, Map<String, Object> templateValues) {
|
public String translate(Locale locale, String contextPath, String keyPath, String defaultTemplate, Map<String, Object> templateValues) {
|
||||||
// look for requested language
|
// look for requested language
|
||||||
String template = null;
|
String template = null;
|
||||||
if(locale != null)
|
if(locale != null)
|
||||||
template = getTemplateFromNearestPath(locale, contextPath, templateKey);
|
template = getTemplateFromNearestPath(locale, contextPath, keyPath);
|
||||||
|
|
||||||
if(template != null)
|
if(template != null)
|
||||||
return substitute(template, templateValues);
|
return substitute(template, templateValues);
|
||||||
|
|
||||||
return translate(contextPath, templateKey, defaultTemplate, templateValues);
|
return translate(contextPath, keyPath, defaultTemplate, templateValues);
|
||||||
}
|
}
|
||||||
|
|
||||||
public String translate(String contextPath, String templateKey, String defaultTemplate, Map<String, Object> templateValues) {
|
public String translate(String contextPath, String keyPath, String defaultTemplate, Map<String, Object> templateValues) {
|
||||||
// scan default languages
|
// scan default languages
|
||||||
String template = null;
|
String template = null;
|
||||||
for(String language : this.settings().translationsDefaultLocales()) {
|
for(String language : this.settings().translationsDefaultLocales()) {
|
||||||
Locale defaultLocale = Locale.forLanguageTag(language);
|
Locale defaultLocale = Locale.forLanguageTag(language);
|
||||||
template = getTemplateFromNearestPath(defaultLocale, contextPath, templateKey);
|
template = getTemplateFromNearestPath(defaultLocale, contextPath, keyPath);
|
||||||
if(template != null)
|
if(template != null)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -155,14 +155,14 @@ public class Translator {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getTemplateFromNearestPath(Locale locale, String contextPath, String templateKey) {
|
private String getTemplateFromNearestPath(Locale locale, String contextPath, String keyPath) {
|
||||||
Map<String, String> localTranslations = this.translations.get(locale);
|
Map<String, String> localTranslations = this.translations.get(locale);
|
||||||
if(localTranslations == null)
|
if(localTranslations == null)
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
String template = null;
|
String template = null;
|
||||||
while(true) {
|
while(true) {
|
||||||
String path = ContextPaths.combinePaths(contextPath, templateKey);
|
String path = ContextPaths.combinePaths(contextPath, keyPath);
|
||||||
template = localTranslations.get(path);
|
template = localTranslations.get(path);
|
||||||
if(template != null)
|
if(template != null)
|
||||||
break; // found template
|
break; // found template
|
||||||
|
Loading…
x
Reference in New Issue
Block a user