/******************************************************************************* * Copyright (c) 2012-2017 Codenvy, S.A. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Codenvy, S.A. - initial API and implementation *******************************************************************************/ package org.eclipse.che.api.environment.server; import com.google.common.base.Joiner; import org.eclipse.che.api.core.ServerException; import org.eclipse.che.api.core.model.workspace.Environment; import org.eclipse.che.api.core.model.workspace.EnvironmentRecipe; import org.eclipse.che.api.core.model.workspace.ExtendedMachine; import org.eclipse.che.api.environment.server.model.CheServiceImpl; import org.eclipse.che.api.environment.server.model.CheServicesEnvironmentImpl; import javax.inject.Inject; import java.util.Map; import java.util.Set; import static com.google.common.base.Preconditions.checkArgument; import static java.lang.String.format; import static java.util.stream.Collectors.toList; /** * Parses {@link Environment} into {@link CheServicesEnvironmentImpl}. * * @author Alexander Garagatyi * @author Alexander Andrienko */ public class EnvironmentParser { // TODO move to container related code protected static final String SERVER_CONF_LABEL_PREFIX = "che:server:"; protected static final String SERVER_CONF_LABEL_REF_SUFFIX = ":ref"; protected static final String SERVER_CONF_LABEL_PROTOCOL_SUFFIX = ":protocol"; protected static final String SERVER_CONF_LABEL_PATH_SUFFIX = ":path"; private final Map<String, TypeSpecificEnvironmentParser> environmentParsers; @Inject public EnvironmentParser(Map<String, TypeSpecificEnvironmentParser> environmentParsers) { this.environmentParsers = environmentParsers; } /** * Returns supported types of environments. */ public Set<String> getEnvironmentTypes() { return environmentParsers.keySet(); } /** * Parses {@link Environment} into {@link CheServicesEnvironmentImpl}. * * @param environment * environment to parse * @return environment representation as compose environment * @throws IllegalArgumentException * if provided environment is illegal * @throws ServerException * if fetching of environment recipe content fails */ public CheServicesEnvironmentImpl parse(Environment environment) throws IllegalArgumentException, ServerException { checkNotNull(environment, "Environment should not be null"); EnvironmentRecipe recipe = environment.getRecipe(); checkNotNull(recipe, "Environment recipe should not be null"); checkNotNull(recipe.getType(), "Environment recipe type should not be null"); checkArgument(recipe.getContent() != null || recipe.getLocation() != null, "Recipe of environment must contain location or content"); String envType = recipe.getType(); Set<String> envTypes = getEnvironmentTypes(); if (!envTypes.contains(envType)) { throw new IllegalArgumentException(format("Environment type '%s' is not supported. " + "Supported environment types: %s", envType, Joiner.on(", ").join(envTypes))); } TypeSpecificEnvironmentParser parser = environmentParsers.get(envType); CheServicesEnvironmentImpl cheServicesEnvironment = parser.parse(environment); cheServicesEnvironment.getServices().forEach((name, service) -> { ExtendedMachine extendedMachine = environment.getMachines().get(name); if (extendedMachine != null) { normalizeMachine(name, service, extendedMachine); } }); return cheServicesEnvironment; } private void normalizeMachine(String name, CheServiceImpl service, ExtendedMachine extendedMachine) { if (extendedMachine.getAttributes().containsKey("memoryLimitBytes")) { try { service.setMemLimit(Long.parseLong(extendedMachine.getAttributes().get("memoryLimitBytes"))); } catch (NumberFormatException e) { throw new IllegalArgumentException( format("Value of attribute 'memoryLimitBytes' of machine '%s' is illegal", name)); } } service.setExpose(service.getExpose() .stream() .map(expose -> expose.contains("/") ? expose : expose + "/tcp") .collect(toList())); extendedMachine.getServers().forEach((serverRef, serverConf) -> { String normalizedPort = serverConf.getPort().contains("/") ? serverConf.getPort() : serverConf.getPort() + "/tcp"; service.getExpose().add(normalizedPort); String portLabelPrefix = SERVER_CONF_LABEL_PREFIX + normalizedPort; service.getLabels().put(portLabelPrefix + SERVER_CONF_LABEL_REF_SUFFIX, serverRef); if (serverConf.getProperties() != null && serverConf.getProperties().get("path") != null) { service.getLabels().put(portLabelPrefix + SERVER_CONF_LABEL_PATH_SUFFIX, serverConf.getProperties().get("path")); } if (serverConf.getProtocol() != null) { service.getLabels().put(portLabelPrefix + SERVER_CONF_LABEL_PROTOCOL_SUFFIX, serverConf.getProtocol()); } }); } /** * Checks that object reference is not null, throws {@link IllegalArgumentException} otherwise. * * <p>Exception uses error message built from error message template and error message parameters. */ private static void checkNotNull(Object object, String errorMessageTemplate, Object... errorMessageParams) { if (object == null) { throw new IllegalArgumentException(format(errorMessageTemplate, errorMessageParams)); } } }