/******************************************************************************* * 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.project.server.type; import org.eclipse.che.api.core.model.project.type.Attribute; import org.eclipse.che.api.core.model.project.type.ProjectType; import org.eclipse.che.api.core.model.project.type.Value; import org.eclipse.che.api.project.server.FolderEntry; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import static com.google.common.collect.Maps.newHashMap; import static java.lang.String.format; /** * @author gazarenkov */ public abstract class ProjectTypeDef implements ProjectType { protected final Map<String, Attribute> attributes; protected final List<String> parents; protected final List<String> ancestors; protected final Map<String, ValueProviderFactory> factoriesToOverride; protected final String id; protected final String displayName; protected final boolean primaryable; protected final boolean mixable; protected final boolean persisted; protected ProjectTypeDef(String id, String displayName, boolean primaryable, boolean mixable, boolean persisted) { ancestors = new ArrayList<>(); attributes = new HashMap<>(); parents = new ArrayList<>(); factoriesToOverride = new HashMap<>(); this.id = id; this.displayName = displayName; this.primaryable = primaryable; this.mixable = mixable; this.persisted = persisted; } /** * @param id * @param displayName * @param primaryable * whether the ProjectTypeDef can be used as Primary * @param mixable * whether the projectType can be used as Mixin */ protected ProjectTypeDef(String id, String displayName, boolean primaryable, boolean mixable) { this(id, displayName, primaryable, mixable, true); } @Override public String getId() { return id; } @Override public boolean isPersisted() { return persisted; } @Override public String getDisplayName() { return displayName; } @Override public List<Attribute> getAttributes() { return new ArrayList<>(attributes.values()); } @Override public List<String> getParents() { return parents; } @Override public boolean isMixable() { return mixable; } @Override public boolean isPrimaryable() { return primaryable; } /** * @return ids of ancestors */ public List<String> getAncestors() { return ancestors; } /** * whether this type is subtype of typeId * * @param typeId * @return true if it is a subtype */ public boolean isTypeOf(String typeId) { return this.id.equals(typeId) || ancestors.contains(typeId); } /** * @param name * @return attribute by name */ public Attribute getAttribute(String name) { return attributes.get(name); } protected void addConstantDefinition(String name, String description, AttributeValue value) { attributes.put(name, new Constant(id, name, description, value)); } protected void addConstantDefinition(String name, String description, String value) { attributes.put(name, new Constant(id, name, description, value)); } protected void addVariableDefinition(String name, String description, boolean required) { attributes.put(name, new Variable(id, name, description, required)); } protected void addVariableDefinition(String name, String description, boolean required, AttributeValue value) { attributes.put(name, new Variable(id, name, description, required, value)); } protected void addVariableDefinition(String name, String description, boolean required, ValueProviderFactory factory) { attributes.put(name, new Variable(id, name, description, required, factory)); } /** * Sets new value for ValueProviderFactory * Useful if child project type needs to redefine ValueProviderFactory of parent PT attribute * todo check if attribute is provided * @param name attribute name * @param factory to set * @return true if attribute found and factory set */ protected void setValueProviderFactory(String name, ValueProviderFactory factory) { this.factoriesToOverride.put(name, factory); } protected void addAttributeDefinition(Attribute attr) { attributes.put(attr.getName(), attr); } protected void addParent(String parentId) { for (String pid : parents) { if (pid.equals(parentId)) return; } parents.add(parentId); } void addAncestor(String ancestor) { this.ancestors.add(ancestor); } public ProjectTypeResolution resolveSources(FolderEntry projectFolder) { Map<String, Value> matchAttrs = new HashMap<>(); for (Map.Entry<String, Attribute> entry : attributes.entrySet()) { Attribute attr = entry.getValue(); String name = entry.getKey(); if (attr.isVariable()) { Variable var = (Variable)attr; ValueProviderFactory factory = var.getValueProviderFactory(); if (factory != null) { Value value; String errorMessage = ""; try { value = new AttributeValue(factory.newInstance(projectFolder).getValues(name)); } catch (ValueStorageException e) { value = null; errorMessage = e.getLocalizedMessage(); } if (value == null || value.isEmpty()) { if (var.isRequired()) { // this PT is not match errorMessage = errorMessage.isEmpty() ? format("Value for required attribute %s is not initialized", name) : errorMessage; return new DefaultResolution(id, errorMessage); } } else { // add one more matched attribute matchAttrs.put(name, value); } } } } return new DefaultResolution(id, matchAttrs, true); } public static class DefaultResolution extends ProjectTypeResolution { private boolean match; public DefaultResolution(String type, Map<String, Value> attributes, boolean match) { super(type, attributes); this.match = match; } /** Use this one when source code not matches project type requirements */ public DefaultResolution(String type, String resolution) { super(type, newHashMap(), resolution); this.match = false; } @Override public boolean matched() { return match; } } }