com.google.devtools.moe.client.project.ProjectConfig.java Source code

Java tutorial

Introduction

Here is the source code for com.google.devtools.moe.client.project.ProjectConfig.java

Source

/*
 * Copyright (c) 2011 Google, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.google.devtools.moe.client.project;

import com.google.auto.value.AutoValue;
import com.google.common.base.Strings;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSortedSet;
import com.google.devtools.moe.client.MoeProblem;
import com.google.devtools.moe.client.gson.GsonModule;
import com.google.devtools.moe.client.gson.JsonStructureChecker;
import com.google.devtools.moe.client.migrations.MigrationConfig;
import com.google.gson.Gson;
import com.google.gson.JsonElement;
import com.google.gson.JsonParseException;
import com.google.gson.JsonParser;
import com.google.gson.TypeAdapter;
import com.google.gson.annotations.SerializedName;
import com.google.gson.stream.JsonReader;
import com.google.json.JsonSanitizer;
import java.io.StringReader;
import java.util.Map;
import javax.annotation.Nullable;

/**
 * Configuration for a MOE Project
 */
@AutoValue
public abstract class ProjectConfig {

    /** The name of this project */
    @Nullable
    public abstract String name();

    /**
     * Location of the database MOE should use for this project.
     *
     * <p>While this should be a URI, implementers may choose to honor "/foo" as "file:///foo" or
     * "foo" as a relative file to support legacy clients.
     *
     * <p>This can be overridden by the {@code --db} command-line flag, and can be null, in which case
     * any code-path that requires a database will require that it be set on the command-line.
     */
    @Nullable
    @SerializedName("database_uri") // TODO(cushon): remove pending rharter/auto-value-gson#18
    public abstract String databaseUri();

    /** The set of configured editors for this project */
    public abstract Map<String, EditorConfig> editors();

    /** The set of migration configurations that have been set for this project. */
    public abstract ImmutableList<MigrationConfig> migrations();

    /** The configured repositories this project is aware of. */
    public abstract Map<String, RepositoryConfig> repositories();

    /** The set of translations that have been configured for this project. */
    public abstract ImmutableList<TranslatorConfig> translators();

    public static Builder builder() {
        Builder builder = new AutoValue_ProjectConfig.Builder();
        builder.editors(ImmutableMap.<String, EditorConfig>of()); // default empty list.
        builder.migrations(ImmutableList.<MigrationConfig>of()); // default empty list.
        builder.repositories(ImmutableMap.<String, RepositoryConfig>of()); // default empty list.
        builder.translators(ImmutableList.<TranslatorConfig>of()); // default empty list.
        return builder;
    }

    /**
     * A standard builder pattern object to create a ProjectConfig.
     */
    @AutoValue.Builder
    public abstract static class Builder {
        public abstract Builder name(String name);

        public abstract Builder databaseUri(String name);

        public abstract Builder editors(Map<String, EditorConfig> editors);

        public abstract Builder migrations(ImmutableList<MigrationConfig> migrations);

        public abstract Builder repositories(Map<String, RepositoryConfig> repositories);

        public abstract Builder translators(ImmutableList<TranslatorConfig> translators);

        public abstract ProjectConfig build();
    }

    /**
     * Returns the {@link RepositoryConfig} in this config with the given name.
     *
     * @throws MoeProblem if no such repository with the given name exists
     */
    public RepositoryConfig getRepositoryConfig(String repositoryName) {
        if (!repositories().containsKey(repositoryName)) {
            throw new MoeProblem("No such repository '%s' in the config. Found: %s", repositoryName,
                    ImmutableSortedSet.copyOf(repositories().keySet()));
        }
        return repositories().get(repositoryName);
    }

    /**
     * Returns a configuration from one repository to another, if any is configured.
     */
    public TranslatorConfig findTranslatorFrom(String fromRepository, String toRepository) {
        String fromProjectSpace = getRepositoryConfig(fromRepository).getProjectSpace();
        String toProjectSpace = getRepositoryConfig(toRepository).getProjectSpace();
        for (TranslatorConfig translator : translators()) {
            if (translator.getFromProjectSpace().equals(fromProjectSpace)
                    && translator.getToProjectSpace().equals(toProjectSpace)) {
                return translator;
            }
        }
        return null;
    }

    public ScrubberConfig findScrubberConfig(String fromRepository, String toRepository) {
        TranslatorConfig translator = findTranslatorFrom(fromRepository, toRepository);
        return (translator == null) ? null : translator.scrubber();
    }

    void validate() throws InvalidProject {
        InvalidProject.assertFalse(Strings.isNullOrEmpty(name()), "Must specify a name");
        InvalidProject.assertFalse(repositories().isEmpty(), "Must specify repositories");

        for (RepositoryConfig r : repositories().values()) {
            r.validate();
        }
        for (EditorConfig e : editors().values()) {
            e.validate();
        }
        for (TranslatorConfig t : translators()) {
            t.validate();
        }
        for (MigrationConfig m : migrations()) {
            m.validate();
        }
    }

    public static ProjectConfig parse(String configText) throws InvalidProject {
        ProjectConfig config = null;
        if (configText != null) {
            try {
                JsonReader configReader = new JsonReader(new StringReader(configText));
                configReader.setLenient(true);
                JsonElement configJsonElement = new JsonParser().parse(configReader);
                if (configJsonElement != null) {
                    // Config files often contain JavaScript idioms like comments, single quoted strings,
                    // and trailing commas in lists.
                    // Check that the JSON parsed from configText is structurally the same as that
                    // produced when it is interpreted by GSON in lax mode.
                    String normalConfigText = JsonSanitizer.sanitize(configText);
                    JsonElement normalConfigJsonElement = new JsonParser().parse(normalConfigText);
                    JsonStructureChecker.requireSimilar(configJsonElement, normalConfigJsonElement);

                    Gson gson = GsonModule.provideGson(); // TODO(user): Remove this static reference.
                    config = gson.fromJson(configText, ProjectConfig.class);
                }
            } catch (JsonParseException e) {
                throw new InvalidProject(e, "Could not parse MOE config: " + e.getMessage());
            }
        }

        if (config == null) {
            throw new InvalidProject("Could not parse MOE config");
        }
        config.validate();
        return config;
    }

    public static TypeAdapter<ProjectConfig> typeAdapter(Gson gson) {
        return new AutoValue_ProjectConfig.GsonTypeAdapter(gson);
    }
}