/** * Copyright (c) 2013-2016 Angelo ZERR. * 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: * Angelo Zerr <angelo.zerr@gmail.com> - initial API and implementation */ package tern.metadata; import java.io.File; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import tern.server.ITernModule; import tern.server.TernModuleInfo; import tern.server.protocol.JsonHelper; import tern.utils.StringUtils; import com.eclipsesource.json.JsonArray; import com.eclipsesource.json.JsonObject; import com.eclipsesource.json.JsonValue; /** * Tern module metadata loded from *.metadata.json file. * */ public class TernModuleMetadata { public static String ANY_VERSION = "?"; private static final String NAME_FIELD = "name"; private static final String LABEL_FIELD = "label"; private static final String ORIGIN_FIELD = "origin"; private static final String DESCRIPTION_FIELD = "description"; private static final String HOMEPAGE_FIELD = "homepage"; private static final String AUTHOR_FIELD = "author"; private static final String REPOSITORY_FIELD = "repository"; private static final String BUGS_FIELD = "bugs"; private static final String HELP_FIELD = "help"; private static final String LINTER_FIELD = "linter"; private static final String DEF_FIELD = "def"; private static final String URL_FIELD = "url"; private static final String DEPENDENCIES_FIELD = "dependencies"; private static final String OPTIONS_FIELD = "options"; private static final String ICON_FIELD = "icon"; private final String name; private final String origin; private final String label; private final String description; private final String homepage; private final String author; private final String repositoryURL; private final String bugsURL; private final String helpURL; private final boolean linter; private final boolean def; private final Map<String, Collection<String>> dependencies; private final Map<String, Collection<String>> requiredDependencies; private final Collection<TernModuleMetadataOption> options; private File fileIcon; /** * Create module metadata from JSON object. * * @param json * @param file */ public TernModuleMetadata(JsonObject json, File file) { this.name = JsonHelper.getString(json, NAME_FIELD); this.label = JsonHelper.getString(json, LABEL_FIELD); this.origin = !StringUtils.isEmpty(JsonHelper.getString(json, ORIGIN_FIELD)) ? JsonHelper.getString(json, ORIGIN_FIELD) : null; this.description = JsonHelper.getString(json, DESCRIPTION_FIELD); this.homepage = JsonHelper.getString(json, HOMEPAGE_FIELD); this.author = JsonHelper.getString(json, AUTHOR_FIELD); this.repositoryURL = getURL(json, REPOSITORY_FIELD); this.bugsURL = getURL(json, BUGS_FIELD); this.helpURL = getURL(json, HELP_FIELD); this.linter = json.getBoolean(LINTER_FIELD, false); this.def = json.getBoolean(DEF_FIELD, false); // dependencies JsonValue dependencies = json.get(DEPENDENCIES_FIELD); if (dependencies != null) { this.dependencies = parseDependencies((JsonValue) dependencies); } else { this.dependencies = Collections.emptyMap(); } // required dependencies requiredDependencies = getRequiredDependencies(); // options JsonValue options = json.get(OPTIONS_FIELD); if (options != null && options instanceof JsonArray) { this.options = parseOptions((JsonArray) options); } else { this.options = null; } // icon this.fileIcon = getFileIcon(json, file); } private File getFileIcon(JsonObject json, File file) { if (file == null) { return null; } String icon = JsonHelper.getString(json, ICON_FIELD); if (StringUtils.isEmpty(icon)) { return null; } File fileIcon = new File(file.getParentFile(), icon); return fileIcon.exists() ? fileIcon : null; } private Map<String, Collection<String>> getRequiredDependencies() { Map<String, Collection<String>> requiredDependenciesMap = new HashMap<String, Collection<String>>(); Collection<String> requiredDependencies = null; String version = null; Collection<String> dependencies = null; TernModuleInfo info = null; for (Map.Entry<String, Collection<String>> entry : this.dependencies.entrySet()) { version = entry.getKey(); dependencies = entry.getValue(); for (String dependency : dependencies) { info = new TernModuleInfo(dependency); if (info.getType().equals(getName())) { // same type, add it requiredDependencies = requiredDependenciesMap.get(version); if (requiredDependencies == null) { requiredDependencies = new ArrayList<String>(); requiredDependenciesMap.put(version, requiredDependencies); } requiredDependencies.add(dependency); } } } return requiredDependenciesMap; } public String getURL(JsonObject json, String name) { JsonValue value = json.get(name); if (value != null) { return JsonHelper.getString((JsonObject) value, URL_FIELD); } return null; } private Map<String, Collection<String>> parseDependencies(JsonValue jsonDependencies) { if (jsonDependencies instanceof JsonArray) { return parseDependencies((JsonArray) jsonDependencies); } else if (jsonDependencies instanceof JsonObject) { return parseDependencies((JsonObject) jsonDependencies); } return Collections.emptyMap(); } private Map<String, Collection<String>> parseDependencies(JsonArray jsonDependencies) { List<String> dependencies = new ArrayList<String>(); for (JsonValue jsonDependency : jsonDependencies) { dependencies.add(JsonHelper.getString(jsonDependency)); } Map<String, Collection<String>> dependenciesMap = new HashMap<String, Collection<String>>(); parseDependencies(jsonDependencies, ANY_VERSION, dependenciesMap); return dependenciesMap; } private void parseDependencies(JsonArray jsonDependencies, String version, Map<String, Collection<String>> dependenciesMap) { List<String> dependencies = new ArrayList<String>(); for (JsonValue jsonDependency : jsonDependencies) { dependencies.add(JsonHelper.getString(jsonDependency)); } dependenciesMap.put(version, dependencies); } private Map<String, Collection<String>> parseDependencies(JsonObject jsonDependencies) { Map<String, Collection<String>> dependenciesMap = new HashMap<String, Collection<String>>(); Iterator<com.eclipsesource.json.JsonObject.Member> a = jsonDependencies.iterator(); while (a.hasNext()) { JsonObject.Member member = (JsonObject.Member) a.next(); String version = member.getName(); if (member.getValue() instanceof JsonArray) { parseDependencies((JsonArray) member.getValue(), version, dependenciesMap); } if (!StringUtils.isEmpty(version) && !ANY_VERSION.equals(version)) { Collection<String> commons = dependenciesMap.get(ANY_VERSION); if (commons != null) { dependenciesMap.get(version).addAll(commons); } } } return dependenciesMap; } private Collection<TernModuleMetadataOption> parseOptions(JsonArray jsonOptions) { List<TernModuleMetadataOption> options = new ArrayList<TernModuleMetadataOption>(); for (JsonValue jsonOption : jsonOptions) { options.add(new TernModuleMetadataOption((JsonObject) jsonOption)); } return options; } /** * Returns the label of the module. * * @return the label of the module. */ public String getLabel() { return label; } /** * Returns the name of the module. * * @return the name of the module. */ public String getName() { return name; } /** * Returns the origin of the module. * * @return the origin of the module. */ public String getOrigin() { return origin; } /** * Returns the description of the module. * * @return the description of the module. */ public String getDescription() { return description; } /** * Returns the home page of the module. * * @return the home page of the module. */ public String getHomePage() { return homepage; } /** * Returns the author of the module. * * @return the author of the module. */ public String getAuthor() { return author; } /** * Returns the repository URL of the module. * * @return the repository URL of the module. */ public String getRepositoryURL() { return repositoryURL; } /** * Returns the bugs URL of the module. * * @return the bugs URL of the module. */ public String getBugsURL() { return bugsURL; } /** * Returns the help URL of the module. * * @return the help URL of the module. */ public String getHelpURL() { return helpURL; } /** * Returns list of options. * * @return list of options. */ public Collection<TernModuleMetadataOption> getOptions() { return options; } /** * Returns list of {@link ITernModule} name dependencies. * * @return list of {@link ITernModule} name dependencies. */ @SuppressWarnings("unchecked") public Collection<String> getDependencies(String version) { Collection<String> deps = dependencies.get(StringUtils.isEmpty(version) ? ANY_VERSION : version); if (deps == null) { deps = dependencies.get(ANY_VERSION); } return (Collection<String>) (deps != null ? deps : Collections.emptyList()); } /** * Returns list of required {@link ITernModule} name dependencies. * * @return list of required {@link ITernModule} name dependencies. */ @SuppressWarnings("unchecked") public Collection<String> getRequiredDependencies(String version) { Collection<String> deps = requiredDependencies.get(StringUtils.isEmpty(version) ? ANY_VERSION : version); if (deps == null) { deps = requiredDependencies.get(ANY_VERSION); } return (Collection<String>) (deps != null ? deps : Collections.emptyList()); } /** * Returns true if the plugin is a linter and false otherwise. * * @return true if the plugin is a linter and false otherwise. */ public boolean isLinter() { return linter; } /** * Returns true if the the module is a JSON Type Definition and false * otherwise( it is a plugin) * * @return true if the the module is a JSON Type Definition and false * otherwise( it is a plugin) */ public boolean isDef() { return def; } /** * Returns true if the module has options and false otherwise. * * @return true if the module has options and false otherwise. */ public boolean hasOptions() { return options != null && options.size() > 0; } /** * Returns the file icon and null otherwise. * * @return the file icon and null otherwise. */ public File getFileIcon() { return fileIcon; } }