All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.jangaroo.jooc.mvnplugin.sencha.configbuilder.SenchaConfigBuilder Maven / Gradle / Ivy

The newest version!
package net.jangaroo.jooc.mvnplugin.sencha.configbuilder;

import net.jangaroo.jooc.mvnplugin.sencha.SenchaUtils;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

/**
 * A base class for all builders for Sencha JSON formats.
 */
public class SenchaConfigBuilder {
  protected Map config = new LinkedHashMap<>();
  private File destFile = null;
  private String destFileComment = null;

  @SuppressWarnings("unchecked")
  T nameValue(@Nonnull String name, @Nullable Object value) {
    handleNewValue(config, name, config.get(name), value);
    return (T) this;
  }

  private static void mergeMap(@Nonnull Map baseMap,
                               @Nonnull Map mapWithNewValues) {
    for (Map.Entry entry : mapWithNewValues.entrySet()) {
      String key = entry.getKey();
      handleNewValue(baseMap, key, baseMap.get(key), entry.getValue());
    }
  }

  private static void handleNewValue(@Nonnull Map baseMap,
                                     @Nonnull String key,
                                     @Nullable Object currentValue,
                                     @Nullable Object newValue) {
    boolean isListValue = newValue instanceof List;
    boolean isMapValue = newValue instanceof Map;

    if (currentValue == null || newValue == null || !(isListValue || isMapValue)) {
      baseMap.put(key, newValue);
    } else if (isMapValue) {
      //noinspection unchecked
      addToMapRecursively(baseMap, key, currentValue, (Map) newValue);
    } else {
      addToList(baseMap, key, currentValue, (Collection) newValue);
    }
  }

  private static void addToList(@Nonnull Map baseMap,
                                @Nonnull String key,
                                @Nonnull Object currentValue,
                                @Nonnull Collection additionalValues) {
    if (!(currentValue instanceof List)) {
      String errorMessage = String.format("Expected a list as value for property name %s, but got %s", key, currentValue);
      throw new IllegalArgumentException(errorMessage);
    }
    @SuppressWarnings("unchecked")
    List currentValueAsList = (List) currentValue;
    // we need to add the values to the existing list
    List currentList = new ArrayList<>();
    currentList.addAll(currentValueAsList);
    currentList.addAll(additionalValues);
    baseMap.put(key, currentList);
  }

  private static void addToMapRecursively(@Nonnull Map baseMap,
                                          @Nonnull String key,
                                          @Nonnull Object currentValue,
                                          @Nonnull Map additionalMap) {
    if (!(currentValue instanceof Map)) {
      throw new IllegalArgumentException(String.format("Expected a map as value for property name %s, but got %s", key, currentValue));
    }
    @SuppressWarnings("unchecked")
    Map currentValueAsMap = (Map) currentValue;
    // we need to add the values to the existing map
    Map currentSubMap = new HashMap<>();
    // we need to add values recursively, map can include lists and maps
    currentSubMap.putAll(currentValueAsMap);
    mergeMap(currentSubMap, additionalMap);

    baseMap.put(key, currentSubMap);
  }

  @SuppressWarnings("unchecked")
  public T namesValues(@Nonnull Map properties) {
    for (Map.Entry entry : properties.entrySet()) {
      nameValue(entry.getKey(), entry.getValue());
    }
    return (T) this;
  }

  @SuppressWarnings("unchecked")
  public T destFile(File destFile) {
    this.destFile = destFile;
    return (T) this;
  }

  @SuppressWarnings("unchecked")
  public T destFileComment(String comment) {
    this.destFileComment = comment;
    return (T) this;
  }

  @Nonnull
  public Map build() {
    return Collections.unmodifiableMap(config);
  }

  /**
   * @return the JSON file containing the Sencha configuration
   * @throws IOException if file could not be written
   */
  public File buildFile() throws IOException {
    if (destFile == null) {
      throw new IllegalStateException("Cannot build file without file path being set.");
    }

    try (PrintWriter pw = new PrintWriter(new FileWriter(destFile), false)) {
      if (destFileComment != null) {
        pw.println("/**");
        pw.println(" * " + destFileComment);
        pw.println(" */");
      }
      SenchaUtils.getObjectMapper().writerWithDefaultPrettyPrinter().writeValue(pw, build());
    }
    return destFile;
  }

  @SuppressWarnings("unchecked")
  public T defaults(String jsonFileName) throws IOException {
    return namesValues(readDefaultJson(jsonFileName));
  }

  private Map readDefaultJson(String jsonFileName) throws IOException {
    InputStream inputStream = getClass().getResourceAsStream(jsonFileName);

    //noinspection unchecked
    return (Map) SenchaUtils.getObjectMapper().readValue(inputStream, Map.class);
  }

   T addToList(I item, String ...pathArcs) {
    Map node = config;
    for (int i = 0; i < pathArcs.length - 1; i++) {
      String pathArc = pathArcs[i];
      @SuppressWarnings("unchecked")
      Map nextNode = (Map) node.get(pathArc);
      if (nextNode == null) {
        nextNode = new LinkedHashMap<>();
        node.put(pathArc, nextNode);
      }
      node = nextNode;
    }
    String key = pathArcs[pathArcs.length - 1];
    List newValue = new ArrayList<>();
    @SuppressWarnings("unchecked")
    List value = (List) node.get(key);
    if (value != null && !value.isEmpty()) {
      newValue.addAll(value);
    }
    newValue.add(item);
    node.put(key, Collections.unmodifiableList(newValue));
    //noinspection unchecked
    return (T) this;
  }


}