blob: 3f4444fb4c74d2bc1b86776db85c954babcb6ca6 [file] [log] [blame]
/********************************************************************************
* Copyright (c) 2015-2021 Contributors to the Eclipse Foundation
*
* See the NOTICE file(s) distributed with this work for additional
* information regarding copyright ownership.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* SPDX-License-Identifier: EPL-2.0
*
********************************************************************************/
package org.eclipse.mdm.businessobjects.boundary;
import static org.eclipse.mdm.businessobjects.boundary.ResourceConstants.REQUESTPARAM_SOURCENAME;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Stack;
import javax.ejb.EJB;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import org.eclipse.mdm.api.base.model.MDMLocalization;
import org.eclipse.mdm.businessobjects.entity.MDMEntityResponse;
import org.eclipse.mdm.businessobjects.utils.ServiceUtils;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.tags.Tag;
/**
*
* @author jst
*
*/
@Tag(name = "Localization")
@Path("/environments/{" + REQUESTPARAM_SOURCENAME + "}/mdmlocalizations")
public class LocalizationResource {
private static final String LOCALIZATION_PREFIX = "mdm://i18n/";
@EJB
private LocalizationService localizationService;
@GET
@Operation(summary = "Get all localizations", description = "Returns all localizations as hierarchical map", responses = {
@ApiResponse(description = "All localizations as map", content = @Content(schema = @Schema(implementation = Map.class))),
@ApiResponse(responseCode = "400", description = "Error") })
@Produces(MediaType.APPLICATION_JSON + "+packed")
public Response read(
@Parameter(description = "Name of the MDM datasource", required = true) @PathParam(REQUESTPARAM_SOURCENAME) String sourceName) {
return ServiceUtils.toResponse(groupByKey(localizationService.localize(sourceName)));
}
@GET
@Operation(summary = "Get all localizations as entities", description = "Returns all localizations as list of MDMLocalization entities.", responses = {
@ApiResponse(description = "All localizations", content = @Content(schema = @Schema(implementation = MDMEntityResponse.class))),
@ApiResponse(responseCode = "400", description = "Error") })
@Produces(MediaType.APPLICATION_JSON)
public Response readEntities(
@Parameter(description = "Name of the MDM datasource", required = true) @PathParam(REQUESTPARAM_SOURCENAME) String sourceName) {
return ServiceUtils
.toResponse(new MDMEntityResponse(MDMLocalization.class, localizationService.localize(sourceName)));
}
@GET
@Operation(summary = "Get default mimetypes", description = "Returns all default mimetypes.", responses = {
@ApiResponse(description = "All default mimetypes", content = @Content(schema = @Schema(implementation = Map.class))),
@ApiResponse(responseCode = "400", description = "Error") })
@Produces(MediaType.APPLICATION_JSON)
@Path("mimetypes")
public Response getDefaultMimeTypes(
@Parameter(description = "Name of the MDM datasource", required = true) @PathParam(REQUESTPARAM_SOURCENAME) String sourceName) {
return ServiceUtils.toResponse(localizationService.getDefaultMimeTypes(sourceName));
}
/**
* Pack localization information, by organizing translations in a hierarchical
* map.
*
* Names of {@link MDMLocalization} are used as keys. The keys are split on
* slashes (not the escaped ones) and the prefix is omitted. The actual
* translation values are held as array of the AliasNames.
*
* @param localizations the flat list of {@link MDMLocalization} entities.
* @return hierarchical translation map
*/
private Map<String, Object> groupByKey(List<MDMLocalization> localizations) {
Map<String, Object> result = new HashMap<>();
for (MDMLocalization localization : localizations) {
// remove prefix since it contains no information
String key = localization.getName();
if (key.contains(LOCALIZATION_PREFIX)) {
key = key.substring(LOCALIZATION_PREFIX.length());
}
// create stack with key fragments in backward order
String[] keyFragments = key.split("/");
Stack<String> stack = new Stack<>();
for (int i = keyFragments.length - 1; i >= 0; --i) {
stack.push(keyFragments[i]);
}
// add to result map
addToMap(result, stack, localization.getTranslations());
}
return result;
}
/**
* Adds translations recursively to a hierarchical map.
*
* @param current current submap
* @param keyStack remaining key fragements
* @param translations array with translations
* @return
*/
@SuppressWarnings("unchecked")
private void addToMap(Map<String, Object> current, Stack<String> keyStack, List<String> translations) {
String key = keyStack.pop().replace("%2F", "/");
// key chain contains more fragments
if (!keyStack.isEmpty()) {
// find existing sub-map or create and add new
Map<String, Object> next;
if (current.containsKey(key)) {
next = (Map<String, Object>) current.get(key);
} else {
next = new HashMap<String, Object>();
current.put(key, next);
}
// process next fragment in sub-map
addToMap(next, keyStack, translations);
// last key fragment reached, thus translations are inserted now.
} else {
// last wins
current.put(key, translations);
}
}
}