text:
package com.facebook.buck.cli;

import static java.lang.Integer.parseInt;

import com.facebook.buck.config.Config;
import com.facebook.buck.config.ConfigView;
import com.facebook.buck.config.ConfigViewCache;
import com.facebook.buck.io.MorePaths;
import com.facebook.buck.io.ProjectFilesystem;
import com.facebook.buck.model.BuildTarget;
import com.facebook.buck.parser.BuildTargetParseException;
import com.facebook.buck.parser.BuildTargetParser;
import com.facebook.buck.parser.BuildTargetPatternParser;
import com.facebook.buck.rules.BinaryBuildRuleToolProvider;
import com.facebook.buck.rules.BuildRuleResolver;
import com.facebook.buck.rules.CellPathResolver;
import com.facebook.buck.rules.ConstantToolProvider;
import com.facebook.buck.rules.DefaultBuildTargetSourcePath;
import com.facebook.buck.rules.HashedFileTool;
import com.facebook.buck.rules.PathSourcePath;
import com.facebook.buck.rules.RuleKeyDiagnosticsMode;
import com.facebook.buck.rules.SourcePath;
import com.facebook.buck.rules.Tool;
import com.facebook.buck.rules.ToolProvider;
import com.facebook.buck.util.Ansi;
import com.facebook.buck.util.AnsiEnvironmentChecking;
import com.facebook.buck.util.HumanReadableException;
import com.facebook.buck.util.MoreCollectors;
import com.facebook.buck.util.PatternAndMessage;
import com.facebook.buck.util.cache.FileHashCacheMode;
import com.facebook.buck.util.concurrent.ResourceAllocationFairness;
import com.facebook.buck.util.concurrent.ResourceAmounts;
import com.facebook.buck.util.concurrent.ResourceAmountsEstimator;
import com.facebook.buck.util.environment.Architecture;
import com.facebook.buck.util.environment.Platform;
import com.facebook.buck.util.network.hostname.HostnameFetching;
import com.facebook.infer.annotation.PropagatesNullable;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Objects;
import com.google.common.base.Preconditions;
import com.google.common.base.Predicates;
import com.google.common.base.Splitter;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableMultimap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSetMultimap;
import com.google.common.collect.LinkedHashMultimap;
import com.google.common.collect.Maps;
import com.google.common.collect.SetMultimap;
import com.google.common.collect.Sets;
import java.io.IOException;
import java.net.URI;
import java.nio.file.Path;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.regex.Pattern;

/** Structured representation of data read from a {@code .buckconfig} file. */
public class BuckConfig implements ConfigPathGetter {

  public static final String BUCK_CONFIG_OVERRIDE_FILE_NAME = ".buckconfig.local";

  private static final String ALIAS_SECTION_HEADER = "alias";
  public static final String RESOURCES_SECTION_HEADER = "resources";
  public static final String RESOURCES_PER_RULE_SECTION_HEADER = "resources_per_rule";

  private static final Float DEFAULT_THREAD_CORE_RATIO = Float.valueOf(1.0F);

  /**
   * This pattern is designed so that a fully-qualified build target cannot be a valid alias name
   * and vice-versa.
   */
  private static final Pattern ALIAS_PATTERN = Pattern.compile("[a-zA-Z_-][a-zA-Z0-9_-]*");

  private static final ImmutableMap<String, ImmutableSet<String>> IGNORE_FIELDS_FOR_DAEMON_RESTART;

  private final CellPathResolver cellPathResolver;

  private final Architecture architecture;

  private final Config config;

  private final ImmutableSetMultimap<String, BuildTarget> aliasToBuildTargetMap;

  private final ProjectFilesystem projectFilesystem;

  private final Platform platform;

  private final ImmutableMap<String, String> environment;

  private final ConfigViewCache<BuckConfig> viewCache = new ConfigViewCache<>(this);

  static {
    ImmutableMap.Builder<String, ImmutableSet<String>> ignoreFieldsForDaemonRestartBuilder =
        ImmutableMap.builder();
    ignoreFieldsForDaemonRestartBuilder.put(
        "apple", ImmutableSet.of("generate_header_symlink_tree_only"));
    ignoreFieldsForDaemonRestartBuilder.put("build", ImmutableSet.of("threads"));
    ignoreFieldsForDaemonRestartBuilder.put(
        "cache",
        ImmutableSet.of("dir", "dir_mode", "http_mode", "http_url", "mode", "slb_server_pool"));
    ignoreFieldsForDaemonRestartBuilder.put(
        "client", ImmutableSet.of("id", "skip-action-graph-cache"));
    ignoreFieldsForDaemonRestartBuilder.put(
        "log",
        ImmutableSet.of(
            "chrome_trace_generation",
            "compress_traces",
            "max_traces",
            "public_announcements"));
    ignoreFieldsForDaemonRestartBuilder.put("project", ImmutableSet.of("ide_prompt"));
    IGNORE_FIELDS_FOR_DAEMON_RESTART = ignoreFieldsForDaemonRestartBuilder.build();
  }

  public BuckConfig(
      Config config,
      ProjectFilesystem projectFilesystem,
      Architecture architecture,
      Platform platform,
      ImmutableMap<String, String> environment,
      CellPathResolver cellPathResolver) {
    this.cellPathResolver = cellPathResolver;
    this.config = config;
    this.projectFilesystem = projectFilesystem;
    this.architecture = architecture;

    // We could create this Map on demand; however, in practice, it is almost always needed when
    // BuckConfig is needed because CommandLineBuildTargetNormalizer needs it.
    this.aliasToBuildTargetMap =
        createAliasToBuildTargetMap(this.getEntriesForSection(ALIAS_SECTION_HEADER));

    this.platform = platform;
    this.environment = environment;
  }

  /**
   * Get a {@link ConfigView} of this config.
   *
   * @param cls Class of the config view.
   * @param <T> Type of the config view.
   */
  public <T extends ConfigView<BuckConfig>> T getView(final Class<T> cls) {
    return viewCache.getView(cls);
  }

  /**
   * @return whether {@code aliasName} conforms to the pattern for a valid alias name. This does not
   *     indicate whether it is an alias that maps to a build target in a BuckConfig.
   */
  private static boolean isValidAliasName(String aliasName) {
    return ALIAS_PATTERN.matcher(aliasName).matches();
  }

  public static void validateAliasName(String aliasName) throws HumanReadableException {
    validateAgainstAlias(aliasName, "Alias");
  }

  public static void validateLabelName(String aliasName) throws HumanReadableException {
    validateAgainstAlias(aliasName, "Label");
  }

  private static void validateAgainstAlias(String aliasName, String fieldName) {
    if (isValidAliasName(aliasName)) {
      return;
    }

    if (aliasName.isEmpty()) {
      throw new HumanReadableException("%s cannot be the empty string.", fieldName);
    }

    throw new HumanReadableException("Not a valid %s: %s.", fieldName.toLowerCase(), aliasName);
  }

  public Architecture getArchitecture() {
    return architecture;
  }

  public ImmutableMap<String, String> getEntriesForSection(String section) {
    ImmutableMap<String, String> entries = config.get(section);
    if (entries != null) {
      return entries;
    } else {
      return ImmutableMap.of();
    }
  }

  public ImmutableList<String> getMessageOfTheDay() {
    return getListWithoutComments("project", "motd");
  }

  public ImmutableList<String> getListWithoutComments(String section, String field) {
    return config.getListWithoutComments(section, field);
  }

  public ImmutableList<String> getListWithoutComments(
      String section, String field, char splitChar) {
    return config.getListWithoutComments(section, field, splitChar);
  }

  public CellPathResolver getCellPathResolver() {
    return cellPathResolver;
  }

  public Optional<ImmutableList<String>> getOptionalListWithoutComments(
      String section, String field) {
    return config.getOptionalListWithoutComments(section, field);
  }

  public Optional<ImmutableList<String>> getOptionalListWithoutComments(
      String section, String field, char splitChar) {
    return config.getOptionalListWithoutComments(section, field, splitChar);
  }

  public Optional<ImmutableList<Path>> getOptionalPathList(
      String section, String field, boolean resolve) {
    Optional<ImmutableList<String>> rawPaths =
        config.getOptionalListWithoutComments(section, field);

    if (rawPaths.isPresent()) {
      ImmutableList<Path> paths =
          rawPaths
              .get()
              .stream()
              .map(
                  input ->
                      convertPath(
                          input,
                          resolve,
                          String.format(
                              "Error in %s.%s: Cell-relative path not found: ", section, field)))
              .collect(MoreCollectors.toImmutableList());
      return Optional.of(paths);
    }

    return Optional.empty();
  }

  public ImmutableSet<String> getBuildTargetForAliasAsString(String possiblyFlavoredAlias) {
    String[] parts = possiblyFlavoredAlias.split("#", 2);
    String unflavoredAlias = parts[0];
    ImmutableSet<BuildTarget> buildTargets = getBuildTargetsForAlias(unflavoredAlias);
    if (buildTargets.isEmpty()) {
      return ImmutableSet.of();
    }
    String suffix = parts.length == 2 ? "#" + parts[1] : "";
    return buildTargets
        .stream()
        .map(buildTarget -> buildTarget.getFullyQualifiedName() + suffix)
        .collect(MoreCollectors.toImmutableSet());
  }

  public ImmutableSet<BuildTarget> getBuildTargetsForAlias(String unflavoredAlias) {
    return aliasToBuildTargetMap.get(unflavoredAlias);
  }

  public BuildTarget getBuildTargetForFullyQualifiedTarget(String target) {
    return BuildTargetParser.INSTANCE.parse(
        target, BuildTargetPatternParser.fullyQualified(), getCellPathResolver());
  }

  public ImmutableList<BuildTarget> getBuildTargetList(String section, String key) {
    ImmutableList<String> targetsToForce = getListWithoutComments(section, key);
    if (targetsToForce.size() == 0) {
      return ImmutableList.of();
    }
    ImmutableList.Builder<BuildTarget> targets = new ImmutableList.Builder<>();
    for (String targetOrAlias : targetsToForce) {
      Set<String> expandedAlias = getBuildTargetForAliasAsString(targetOrAlias);
      if (expandedAlias.isEmpty()) {
        targets.add(getBuildTargetForFullyQualifiedTarget(targetOrAlias));
      } else {
        for (String target : expandedAlias) {
          targets.add(getBuildTargetForFullyQualifiedTarget(target));
        }
      }
    }
    return targets.build();
  }

  /** @return the parsed BuildTarget in the given section and field, if set. */
  public Optional<BuildTarget> getBuildTarget(String section, String field) {
    Optional<String> target = getValue(section, field);
    return target.isPresent()
        ? Optional.of(getBuildTargetForFullyQualifiedTarget(target.get()))
        : Optional.empty();
  }

  /**
   * @return the parsed BuildTarget in the given section and field, if set and a valid build target.
   *     <p>This is useful if you use getTool to get the target, if any, but allow filesystem
   *     references.
   */
  public Optional<BuildTarget> getMaybeBuildTarget(String section, String field) {
    Optional<String> value = getValue(section, field);
    if (!value.isPresent()) {
      return Optional.empty();
    }
    try {
      return Optional.of(getBuildTargetForFullyQualifiedTarget(value.get()));
    } catch (BuildTargetParseException e) {
      return Optional.empty();
    }
  }

  /** @return the parsed BuildTarget in the given section and field. */
  public BuildTarget getRequiredBuildTarget(String section, String field) {
    Optional<BuildTarget> target = getBuildTarget(section, field);
    return required(section, field, target);
  }

  public <T extends Enum<T>> Optional<T> getEnum(String section, String field, Class<T> clazz) {
    return config.getEnum(section, field, clazz);
  }

  /**
   * @return a {@link SourcePath} identified by a @{link BuildTarget} or {@link Path} reference by
   *     the given section:field, if set.
   */
  public Optional<SourcePath> getSourcePath(String section, String field) {
    Optional<String> value = getValue(section, field);
    if (!value.isPresent()) {
      return Optional.empty();
    }
    try {
      BuildTarget target = getBuildTargetForFullyQualifiedTarget(value.get());
      return Optional.of(new DefaultBuildTargetSourcePath(target));
    } catch (BuildTargetParseException e) {
      return Optional.of(
          new PathSourcePath(
              projectFilesystem,
              checkPathExists(
                  value.get(),
                  String.format("Overridden %s:%s path not found: ", section, field))));
    }
  }

  /** @return a {@link SourcePath} identified by a {@link Path}. */
  public SourcePath getSourcePath(Path path) {
    if (path == null) {
      return null;
    }
    return new PathSourcePath(
        projectFilesystem,
        checkPathExists(
            path.toString(),
            String.format(
                "Failed to transform Path %s to Source Path because path was not found.", path)));
  }

  /**
   * @return a {@link Tool} identified by a @{link BuildTarget} or {@link Path} reference by the
   *     given section:field, if set.
   */
  public Optional<ToolProvider> getToolProvider(String section, String field) {
    Optional<String> value = getValue(section, field);
    if (!value.isPresent()) {
      return Optional.empty();
    }
    Optional<BuildTarget> target = getMaybeBuildTarget(section, field);
    if (target.isPresent()) {
      return Optional.of(
          new BinaryBuildRuleToolProvider(target.get(), String.format("[%s] %s", section, field)));
    } else {
      return Optional.of(
          new ConstantToolProvider(
              new HashedFileTool(
                  () ->
                      checkPathExists(
                          value.get(),
                          String.format("Overridden %s:%s path not found: ", section, field)))));
    }
  }

  public Optional<Tool> getTool(String section, String field, BuildRuleResolver resolver) {
    Optional<ToolProvider> provider = getToolProvider(section, field);
    if (!provider.isPresent()) {
      return Optional.empty();
    }
    return Optional.of(provider.get().resolve(resolver));
  }

  public Tool getRequiredTool(String section, String field, BuildRuleResolver resolver) {
    Optional<Tool> path = getTool(section, field, resolver);
    return required(section, field, path);
  }

  /**
   * In a {@link BuckConfig}, an alias can either refer to a fully-qualified build target, or an
   * alias defined earlier in the {@code alias} section. The mapping produced by this method
   * reflects the result of resolving all aliases as values in the {@code alias} section.
   */
  private ImmutableSetMultimap<String, BuildTarget> createAliasToBuildTargetMap(
      ImmutableMap<String, String> rawAliasMap) {
    // We use a LinkedHashMap rather than an ImmutableMap.Builder because we want both (1) order to
    // be preserved, and (2) the ability to inspect the Map while building it up.
    SetMultimap<String, BuildTarget> aliasToBuildTarget = LinkedHashMultimap.create();
    for (Map.Entry<String, String> aliasEntry : rawAliasMap.entrySet()) {
      String alias = aliasEntry.getKey();
      validateAliasName(alias);

      // Determine whether the mapping is to a build target or to an alias.
      List<String> values = Splitter.on(' ').splitToList(aliasEntry.getValue());
      for (String value : values) {
        Set<BuildTarget> buildTargets;
        if (isValidAliasName(value)) {
          buildTargets = aliasToBuildTarget.get(value);
          if (buildTargets.isEmpty()) {
            throw new HumanReadableException("No alias for: %s.", value);
          }
        } else if (value.isEmpty()) {
          continue;
        } else {
          // Here we parse the alias values with a BuildTargetParser to be strict. We could be
          // looser and just grab everything between "//" and ":" and assume it's a valid base path.
          buildTargets =
              ImmutableSet.of(
                  BuildTargetParser.INSTANCE.parse(
                      value, BuildTargetPatternParser.fullyQualified(), getCellPathResolver()));
        }
        aliasToBuildTarget.putAll(alias, buildTargets);
      }
    }
    return ImmutableSetMultimap.copyOf(aliasToBuildTarget);
  }

  /**
   * Create a map of {@link BuildTarget} base paths to aliases. Note that there may be more than one
   * alias to a base path, so the first one listed in the .buckconfig will be chosen.
   */
  public ImmutableMap<Path, String> getBasePathToAliasMap() {
    ImmutableMap<String, String> aliases = config.get(ALIAS_SECTION_HEADER);
    if (aliases == null) {
      return ImmutableMap.of();
    }

    // Build up the Map with an ordinary HashMap because we need to be able to check whether the Map
    // already contains the key before inserting.
    Map<Path, String> basePathToAlias = new HashMap<>();
    for (Map.Entry<String, BuildTarget> entry : aliasToBuildTargetMap.entries()) {
      String alias = entry.getKey();
      BuildTarget buildTarget = entry.getValue();

      Path basePath = buildTarget.getBasePath();
      if (!basePathToAlias.containsKey(basePath)) {
        basePathToAlias.put(basePath, alias);
      }
    }
    return ImmutableMap.copyOf(basePathToAlias);
  }

  public ImmutableMultimap<String, BuildTarget> getAliases() {
    return this.aliasToBuildTargetMap;
  }

  public long getDefaultTestTimeoutMillis() {
    return Long.parseLong(getValue("test", "timeout").orElse("0"));
  }

  private static final String LOG_SECTION = "log";

  public boolean isPublicAnnouncementsEnabled() {
    return getBooleanValue(LOG_SECTION, "public_announcements", true);
  }

  public boolean isProcessTrackerEnabled() {
    return getBooleanValue(LOG_SECTION, "process_tracker_enabled", true);
  }

  public boolean isProcessTrackerDeepEnabled() {
    return getBooleanValue(LOG_SECTION, "process_tracker_deep_enabled", false);
  }

  public boolean isRuleKeyLoggerEnabled() {
    return getBooleanValue(LOG_SECTION, "rule_key_logger_enabled", false);
  }

  public RuleKeyDiagnosticsMode getRuleKeyDiagnosticsMode() {
    return getEnum(LOG_SECTION, "rule_key_diagnostics_mode", RuleKeyDiagnosticsMode.class)
        .orElse(RuleKeyDiagnosticsMode.NEVER);
  }

  public boolean isMachineReadableLoggerEnabled() {
    return getBooleanValue(LOG_SECTION, "machine_readable_logger_enabled", true);
  }

  public ProjectTestsMode xcodeProjectTestsMode() {
    return getEnum("project", "xcode_project_tests_mode", ProjectTestsMode.class)
        .orElse(ProjectTestsMode.WITH_TESTS);
  }

  public boolean getRestartAdbOnFailure() {
    return Boolean.parseBoolean(getValue("adb", "adb_restart_on_failure").orElse("true"));
  }

  public boolean getMultiInstallMode() {
    return getBooleanValue("adb", "multi_install_mode", false);
  }

  public boolean getFlushEventsBeforeExit() {
    return getBooleanValue("daemon", "flush_events_before_exit", false);
  }

  public ImmutableSet<String> getListenerJars() {
    return ImmutableSet.copyOf(getListWithoutComments("extensions", "listeners"));
  }

  /** Return Strings so as to avoid a dependency on {@link LabelSelector}! */
  public ImmutableList<String> getDefaultRawExcludedLabelSelectors() {
    return getListWithoutComments("test", "excluded_labels");
  }

  /**
   * Create an Ansi object appropriate for the current output. First respect the user's preferences,
   * if set. Next, respect any default provided by the caller. (This is used by buckd to tell the
   * daemon about the client's terminal.) Finally, allow the Ansi class to autodetect whether the
   * current output is a tty.
   *
   * @param defaultColor Default value provided by the caller (e.g. the client of buckd)
   */
  public Ansi createAnsi(Optional<String> defaultColor) {
    String color = getValue("color", "ui").map(Optional::of).orElse(defaultColor).orElse("auto");

    switch (color) {
      case "false":
      case "never":
        return Ansi.withoutTty();
      case "true":
      case "always":
        return Ansi.forceTty();
      case "auto":
      default:
        return new Ansi(
            AnsiEnvironmentChecking.environmentSupportsAnsiEscapes(platform, environment));
    }
  }

  public Path resolvePathThatMayBeOutsideTheProjectFilesystem(@PropagatesNullable Path path) {
    if (path == null) {
      return path;
    }
    return resolveNonNullPathOutsideTheProjectFilesystem(path);
  }

  public Path resolveNonNullPathOutsideTheProjectFilesystem(Path path) {
    if (path.isAbsolute()) {
      return getPathFromVfs(path);
    }

    Path expandedPath = MorePaths.expandHomeDir(path);
    return projectFilesystem.resolve(expandedPath);
  }

  public String getLocalhost() {
    try {
      return HostnameFetching.getHostname();
    } catch (IOException e) {
      return "<unknown>";
    }
  }

  public Platform getPlatform() {
    return platform;
  }

  public boolean isActionGraphCheckingEnabled() {
    return getBooleanValue("cache", "action_graph_cache_check_enabled", false);
  }

  public Optional<String> getRepository() {
    return config.get("cache", "repository");
  }

  public Optional<ImmutableSet<PatternAndMessage>> getUnexpectedFlavorsMessages() {
    ImmutableMap<String, String> entries = config.get("unknown_flavors_messages");
    if (!entries.isEmpty()) {
      Set<PatternAndMessage> patternAndMessages = new HashSet<>();
      for (Map.Entry<String, String> entry : entries.entrySet()) {
        patternAndMessages.add(
            PatternAndMessage.of(Pattern.compile(entry.getKey()), entry.getValue()));
      }
      return Optional.of(ImmutableSet.copyOf(patternAndMessages));
    }

    return Optional.empty();
  }

  public boolean hasUserDefinedValue(String sectionName, String propertyName) {
    return config.get(sectionName).containsKey(propertyName);
  }

  public Optional<ImmutableMap<String, String>> getSection(String sectionName) {
    ImmutableMap<String, String> values = config.get(sectionName);
    return values.isEmpty() ? Optional.empty() : Optional.of(values);
  }

  /**
   * @return the string value for the config settings, where present empty values are {@code
   *     Optional.empty()}.
   */
  public Optional<String> getValue(String sectionName, String propertyName) {
    return config.getValue(sectionName, propertyName);
  }

  /**
   * @return the string value for the config settings, where present empty values are {@code
   *     Optional[]}.
   */
  public Optional<String> getRawValue(String sectionName, String propertyName) {
    return config.get(sectionName, propertyName);
  }

  public Optional<Integer> getInteger(String sectionName, String propertyName) {
    return config.getInteger(sectionName, propertyName);
  }

  public Optional<Long> getLong(String sectionName, String propertyName) {
    return config.getLong(sectionName, propertyName);
  }

  public Optional<Float> getFloat(String sectionName, String propertyName) {
    return config.getFloat(sectionName, propertyName);
  }

  public Optional<Boolean> getBoolean(String sectionName, String propertyName) {
    return config.getBoolean(sectionName, propertyName);
  }

  public boolean getBooleanValue(String sectionName, String propertyName, boolean defaultValue) {
    return config.getBooleanValue(sectionName, propertyName, defaultValue);
  }

  public Optional<URI> getUrl(String section, String field) {
    return config.getUrl(section, field);
  }

  public ImmutableMap<String, String> getMap(String section, String field) {
    return config.getMap(section, field);
  }

  private <T> T required(String section, String field, Optional<T> value) {
    if (!value.isPresent()) {
      throw new HumanReadableException(
          String.format(".buckconfig: %s:%s must be set", section, field));
    }
    return value.get();
  }

  // This is a hack. A cleaner approach would be to expose a narrow view of the config to any code
  // that affects the state cached by the Daemon.
  public boolean equalsForDaemonRestart(BuckConfig other) {
    return this.config.equalsIgnoring(other.config, IGNORE_FIELDS_FOR_DAEMON_RESTART);
  }

  @Override
  public boolean equals(Object obj) {
    if (this == obj) {
      return true;
    } else if (!(obj instanceof BuckConfig)) {
      return false;
    }
    BuckConfig that = (BuckConfig) obj;
    return Objects.equal(this.config, that.config);
  }

  @Override
  public String toString() {
    return String.format("%s (config=%s)", super.toString(), config);
  }

  @Override
  public int hashCode() {
    return Objects.hashCode(config);
  }

  public ImmutableMap<String, String> getEnvironment() {
    return environment;
  }

  public String[] getEnv(String propertyName, String separator) {
    String value = getEnvironment().get(propertyName);
    if (value == null) {
      value = "";
    }
    return value.split(separator);
  }
  /** @return the local cache directory */
  public String getLocalCacheDirectory(String dirCacheName) {
    return getValue(dirCacheName, "dir")
        .orElse(projectFilesystem.getBuckPaths().getCacheDir().toString());
  }

  public int getKeySeed() {
    return parseInt(getValue("cache", "key_seed").orElse("0"));
  }

  /** @return the path for the given section and property. */
  @Override
  public Optional<Path> getPath(String sectionName, String name) {
    return getPath(sectionName, name, true);
  }

  public Path getRequiredPath(String section, String field) {
    Optional<Path> path = getPath(section, field);
    return required(section, field, path);
  }

  public String getClientId() {
    return getValue("client", "id").orElse("buck");
  }

  /**
   * @return whether the current invocation of Buck should skip the Action Graph cache, leaving the
   *     cached Action Graph in memory for the next request and creating a fresh Action Graph for
   *     the current request (which will be garbage-collected when the current request is complete).
   *     Commonly, a one-off request, like from a linter, will specify this option so that it does
   *     not invalidate the primary in-memory Action Graph that the user is likely relying on for
   *     fast iterative builds.
   */
  public boolean isSkipActionGraphCache() {
    return getBooleanValue("client", "skip-action-graph-cache", false);
  }

  /** @return the number of threads Buck should use. */
  public int getNumThreads() {
    return getNumThreads(getDefaultMaximumNumberOfThreads());
  }

  /** @return the number of threads to be used for the scheduled executor thread pool. */
  public int getNumThreadsForSchedulerPool() {
    return config.getLong("build", "scheduler_threads").orElse((long) 2).intValue();
  }

  private int getDefaultMaximumNumberOfThreads() {
    return getDefaultMaximumNumberOfThreads(Runtime.getRuntime().availableProcessors());
  }

  @VisibleForTesting
  int getDefaultMaximumNumberOfThreads(int detectedProcessorCount) {
    double ratio = config.getFloat("build", "thread_core_ratio").orElse(DEFAULT_THREAD_CORE_RATIO);
    if (ratio <= 0.0F) {
      throw new HumanReadableException(
          "thread_core_ratio must be greater than zero (was " + ratio + ")");
    }

    int scaledValue = (int) Math.ceil(ratio * detectedProcessorCount);

    int threadLimit = detectedProcessorCount;

    Optional<Long> reservedCores = getNumberOfReservedCores();
    if (reservedCores.isPresent()) {
      threadLimit -= reservedCores.get();
    }

    if (scaledValue > threadLimit) {
      scaledValue = threadLimit;
    }

    Optional<Long> minThreads = getThreadCoreRatioMinThreads();
    if (minThreads.isPresent()) {
      scaledValue = Math.max(scaledValue, minThreads.get().intValue());
    }

    Optional<Long> maxThreads = getThreadCoreRatioMaxThreads();
    if (maxThreads.isPresent()) {
      long maxThreadsValue = maxThreads.get();

      if (minThreads.isPresent() && minThreads.get() > maxThreadsValue) {
        throw new HumanReadableException(
            "thread_core_ratio_max_cores must be larger than thread_core_ratio_min_cores");
      }

      if (maxThreadsValue > threadLimit) {
        throw new HumanReadableException(
            "thread_core_ratio_max_cores is larger than thread_core_ratio_reserved_cores allows");
      }

      scaledValue = Math.min(scaledValue, (int) maxThreadsValue);
    }

    if (scaledValue <= 0) {
      throw new HumanReadableException(
          "Configuration resulted in an invalid number of build threads (" + scaledValue + ").");
    }

    return scaledValue;
  }

  private Optional<Long> getNumberOfReservedCores() {
    Optional<Long> reservedCores = config.getLong("build", "thread_core_ratio_reserved_cores");
    if (reservedCores.isPresent() && reservedCores.get() < 0) {
      throw new HumanReadableException("thread_core_ratio_reserved_cores must be larger than zero");
    }
    return reservedCores;
  }

  private Optional<Long> getThreadCoreRatioMaxThreads() {
    Optional<Long> maxThreads = config.getLong("build", "thread_core_ratio_max_threads");
    if (maxThreads.isPresent() && maxThreads.get() < 0) {
      throw new HumanReadableException("thread_core_ratio_max_threads must be larger than zero");
    }
    return maxThreads;
  }

  private Optional<Long> getThreadCoreRatioMinThreads() {
    Optional<Long> minThreads = config.getLong("build", "thread_core_ratio_min_threads");
    if (minThreads.isPresent() && minThreads.get() <= 0) {
      throw new HumanReadableException("thread_core_ratio_min_threads must be larger than zero");
    }
    return minThreads;
  }

  /**
   * @return the number of threads Buck should use or the specified defaultValue if it is not set.
   */
  public int getNumThreads(int defaultValue) {
    return config.getLong("build", "threads").orElse((long) defaultValue).intValue();
  }

  public Optional<ImmutableList<String>> getAllowedJavaSpecificationVersions() {
    return getOptionalListWithoutComments("project", "allowed_java_specification_versions");
  }

  public long getCountersFirstFlushIntervalMillis() {
    return config.getLong("counters", "first_flush_interval_millis").orElse(5000L);
  }

  public long getCountersFlushIntervalMillis() {
    return config.getLong("counters", "flush_interval_millis").orElse(30000L);
  }

  public Optional<Path> getPath(String sectionName, String name, boolean isCellRootRelative) {
    Optional<String> pathString = getValue(sectionName, name);
    return pathString.isPresent()
        ? Optional.of(
            convertPathWithError(
                pathString.get(),
                isCellRootRelative,
                String.format("Overridden %s:%s path not found: ", sectionName, name)))
        : Optional.empty();
  }

  /**
   * Return a {@link Path} from the underlying {@link java.nio.file.FileSystem} implementation. This
   * allows to safely call {@link Path#resolve(Path)} and similar calls without exceptions caused by
   * mis-matched underlying filesystem implementations causing grief. This is particularly useful
   * for those times where we're using (eg) JimFs for our testing.
   */
  private Path getPathFromVfs(String path) {
    return projectFilesystem.getPath(path);
  }

  private Path getPathFromVfs(Path path) {
    return projectFilesystem.getPath(path.toString());
  }

  private Path convertPathWithError(String pathString, boolean isCellRootRelative, String error) {
    return isCellRootRelative
        ? checkPathExistsAndResolve(pathString, error)
        : getPathFromVfs(pathString);
  }

  private Path convertPath(String pathString, boolean resolve, String error) {
    return resolve
        ? checkPathExistsAndResolve(pathString, error)
        : checkPathExists(pathString, error);
  }

  public Path checkPathExistsAndResolve(String pathString, String errorMsg) {
    return projectFilesystem.getPathForRelativePath(checkPathExists(pathString, errorMsg));
  }

  private Path checkPathExists(String pathString, String errorMsg) {
    Path path = getPathFromVfs(pathString);
    if (projectFilesystem.exists(path)) {
      return path;
    }
    throw new HumanReadableException(errorMsg + path);
  }

  public ImmutableSet<String> getSections() {
    return config.getSectionToEntries().keySet();
  }

  public ImmutableMap<String, ImmutableMap<String, String>> getRawConfigForParser() {
    ImmutableMap<String, ImmutableMap<String, String>> rawSections = config.getSectionToEntries();

    // If the raw config doesn't have sections which have ignored fields, then just return it as-is.
    ImmutableSet<String> sectionsWithIgnoredFields = IGNORE_FIELDS_FOR_DAEMON_RESTART.keySet();
    if (Sets.intersection(rawSections.keySet(), sectionsWithIgnoredFields).isEmpty()) {
      return rawSections;
    }

    // Otherwise, iterate through the config to do finer-grain filtering.
    ImmutableMap.Builder<String, ImmutableMap<String, String>> filtered = ImmutableMap.builder();
    for (Map.Entry<String, ImmutableMap<String, String>> sectionEnt : rawSections.entrySet()) {
      String sectionName = sectionEnt.getKey();

      // If this section doesn't have a corresponding ignored section, then just add it as-is.
      if (!sectionsWithIgnoredFields.contains(sectionName)) {
        filtered.put(sectionEnt);
        continue;
      }

      // If none of this section's entries are ignored, then add it as-is.
      ImmutableMap<String, String> fields = sectionEnt.getValue();
      ImmutableSet<String> ignoredFieldNames =
          IGNORE_FIELDS_FOR_DAEMON_RESTART.getOrDefault(sectionName, ImmutableSet.of());
      if (Sets.intersection(fields.keySet(), ignoredFieldNames).isEmpty()) {
        filtered.put(sectionEnt);
        continue;
      }

      // Otherwise, filter out the ignored fields.
      ImmutableMap<String, String> remainingKeys =
          ImmutableMap.copyOf(Maps.filterKeys(fields, Predicates.not(ignoredFieldNames::contains)));

      if (!remainingKeys.isEmpty()) {
        filtered.put(sectionName, remainingKeys);
      }
    }

    return filtered.build();
  }

  public Optional<ImmutableList<String>> getExternalTestRunner() {
    Optional<String> value = getValue("test", "external_runner");
    if (!value.isPresent()) {
      return Optional.empty();
    }
    return Optional.of(ImmutableList.copyOf(Splitter.on(' ').splitToList(value.get())));
  }

  /**
   * @return whether to symlink the default output location (`buck-out`) to the user-provided
   *     override for compatibility.
   */
  public boolean getBuckOutCompatLink() {
    return getBooleanValue("project", "buck_out_compat_link", false);
  }

  public ResourceAllocationFairness getResourceAllocationFairness() {
    return config
        .getEnum(
            RESOURCES_SECTION_HEADER,
            "resource_allocation_fairness",
            ResourceAllocationFairness.class)
        .orElse(ResourceAllocationFairness.FAIR);
  }

  public boolean isResourceAwareSchedulingEnabled() {
    return config.getBooleanValue(
        RESOURCES_SECTION_HEADER, "resource_aware_scheduling_enabled", false);
  }

  public boolean isGrayscaleImageProcessingEnabled() {
    return config.getBooleanValue(RESOURCES_SECTION_HEADER, "resource_grayscale_enabled", false);
  }

  public ImmutableMap<String, ResourceAmounts> getResourceAmountsPerRuleType() {
    ImmutableMap.Builder<String, ResourceAmounts> result = ImmutableMap.builder();
    ImmutableMap<String, String> entries = getEntriesForSection(RESOURCES_PER_RULE_SECTION_HEADER);
    for (String ruleName : entries.keySet()) {
      ImmutableList<String> configAmounts =
          getListWithoutComments(RESOURCES_PER_RULE_SECTION_HEADER, ruleName);
      Preconditions.checkArgument(
          configAmounts.size() == ResourceAmounts.RESOURCE_TYPE_COUNT,
          "Buck config entry [%s].%s contains %s values, but expected to contain %s values "
              + "in the following order: cpu, memory, disk_io, network_io",
          RESOURCES_PER_RULE_SECTION_HEADER,
          ruleName,
          configAmounts.size(),
          ResourceAmounts.RESOURCE_TYPE_COUNT);
      ResourceAmounts amounts =
          ResourceAmounts.of(
              Integer.valueOf(configAmounts.get(0)),
              Integer.valueOf(configAmounts.get(1)),
              Integer.valueOf(configAmounts.get(2)),
              Integer.valueOf(configAmounts.get(3)));
      result.put(ruleName, amounts);
    }
    return result.build();
  }

  public int getManagedThreadCount() {
    if (!isResourceAwareSchedulingEnabled()) {
      return getNumThreads();
    }
    return config
        .getLong(RESOURCES_SECTION_HEADER, "managed_thread_count")
        .orElse((long) getNumThreads() + getDefaultMaximumNumberOfThreads())
        .intValue();
  }

  public ResourceAmounts getDefaultResourceAmounts() {
    if (!isResourceAwareSchedulingEnabled()) {
      return ResourceAmounts.of(1, 0, 0, 0);
    }
    return ResourceAmounts.of(
        config
            .getInteger(RESOURCES_SECTION_HEADER, "default_cpu_amount")
            .orElse(ResourceAmountsEstimator.DEFAULT_CPU_AMOUNT),
        config
            .getInteger(RESOURCES_SECTION_HEADER, "default_memory_amount")
            .orElse(ResourceAmountsEstimator.DEFAULT_MEMORY_AMOUNT),
        config
            .getInteger(RESOURCES_SECTION_HEADER, "default_disk_io_amount")
            .orElse(ResourceAmountsEstimator.DEFAULT_DISK_IO_AMOUNT),
        config
            .getInteger(RESOURCES_SECTION_HEADER, "default_network_io_amount")
            .orElse(ResourceAmountsEstimator.DEFAULT_NETWORK_IO_AMOUNT));
  }

  public ResourceAmounts getMaximumResourceAmounts() {
    ResourceAmounts estimated = ResourceAmountsEstimator.getEstimatedAmounts();
    return ResourceAmounts.of(
        getNumThreads(estimated.getCpu()),
        getInteger(BuckConfig.RESOURCES_SECTION_HEADER, "max_memory_resource")
            .orElse(estimated.getMemory()),
        getInteger(BuckConfig.RESOURCES_SECTION_HEADER, "max_disk_io_resource")
            .orElse(estimated.getDiskIO()),
        getInteger(BuckConfig.RESOURCES_SECTION_HEADER, "max_network_io_resource")
            .orElse(estimated.getNetworkIO()));
  }

  /** @return whether to enabled versions on build/test command. */
  public boolean getBuildVersions() {
    return getBooleanValue("build", "versions", false);
  }

  /** @return whether to enabled versions on targets command. */
  public boolean getTargetsVersions() {
    return getBooleanValue("targets", "versions", false);
  }

  /** @return whether to enable caching of rule key calculations between builds. */
  public boolean getRuleKeyCaching() {
    return getBooleanValue("build", "rule_key_caching", false);
  }

  public ImmutableList<String> getCleanAdditionalPaths() {
    return getListWithoutComments("clean", "additional_paths");
  }

  /** @return whether to enable new file hash cache engine. */
  public boolean getCompareFileHashCacheEngines() {
    return getBooleanValue("build", "compare_file_hash_cache_engines", false);
  }

  /** @return whether to enable new file hash cache engine. */
  public FileHashCacheMode getFileHashCacheMode() {
    return getEnum("build", "file_hash_cache_mode", FileHashCacheMode.class)
        .orElse(FileHashCacheMode.DEFAULT);
  }

  public Config getConfig() {
    return config;
  }
}


text:
{% extends "layouts/master.html" %}

{% block pageheader %} Creacion de Expediente Permanente a partir de Provisional {% endblock %}
{% block paneltitle %} Ficha de identificación del expediente clínico {% endblock %}

{% block panelcontent %}
{{ form.errors }}
<form id="dpa_pacienteProvisionalEditarForm" action="" method="post">{% csrf_token %}

(*) campos requeridos

A) DEL PACIENTE {{pr}}

	                    {{ form.nombrePrimero.label_tag }}
						 {{ form.nombrePrimero.help_text }}

						<input type="text" class="form-control" name="nombrePrimero" id="id_nombrePrimero" value="{{migrar.nombrePrimero}}" readonly />

	                    {{ form.nombreSegundo.label_tag }}
						 {{ form.nombreSegundo.help_text }}
						{% if migrar.nombreSegundo %}
							<input type="text" class="form-control" name="nombreSegundo" id="id_nombreSegundo" value="{{migrar.nombreSegundo}}" />
						{% else %}
							{{ form.nombreSegundo }}
						{% endif %}

						{{ form.apellidoPrimero.label_tag }}
						 {{ form.apellidoPrimero.help_text }}
						<input type="text" class="form-control" name="apellidoPrimero" id="id_apellidoPrimero" value="{{migrar.apellidoPrimero}}" />

	                    {{ form.apellidoSegundo.label_tag }}
						 {{ form.apellidoSegundo.help_text }}
						{% if migrar.apellidoSegundo %}
							<input type="text" class="form-control" name="apellidoSegundo" id="id_apellidoSegundo" value="{{migrar.apellidoSegundo}}" />
						{% else %}
							{{ form.apellidoSegundo }}
						{% endif %}

						{{ form.sexo.label_tag }}
						 {{ form.sexo.help_text }}
						{{ form.sexo }}

						{{ form.fechaNacimiento.label_tag }}
						 {{ form.fechaNacimiento.help_text }}
						<input type="text" class="form-control" name="fechaNacimiento" id="id_fechaNaciemiento" value="{{migrar.fechaNacimiento|date:'SHORT_DATE_FORMAT'}}" />

						{{ form.estadoCivil.label_tag }}
						 {{ form.estadoCivil.help_text }}
						{{ form.estadoCivil }}

					 (*) Por lo menos un documento de identificación:

						{{ form.nit.label_tag }}
						 {{ form.nit.help_text }}
						<input type="text" class="form-control" name="nit" id="id_nit" value="{{migrar.nit}}" />

						{{ form.dui.label_tag }}
						 {{ form.dui.help_text }}
						{{ form.dui }}

						{{ form.due.label_tag }}
						 {{ form.due.help_text }}
						{{ form.due }}

						{{ form.estadoUes.label_tag }}
						 {{ form.estadoUes.help_text }}
						{{ form.estadoUes }}

						{{ form.facultadE.label_tag }}
						 {{ form.facultadE.help_text }}

						<select name="facultadE" class="form-control" data-fv-field="facultadE" id="id_facultadE" readonly>
							<option value="{{data}}" selected>{{migrar.facultad}}</option>
						</select>

						{{ form.direccion.label_tag }}
						 {{ form.direccion.help_text }}

						{{ form.direccion }}

						{{ form.codDepartamento.label_tag }}
						 {{ form.codDepartamento.help_text }}
						{{ form.codDepartamento }}

						Municipio
						(*) {{ form.codMunicipio.help_text }}
						{{ form.codMunicipio }}

						{{ form.telefono.label_tag }}
						 {{ form.telefono.help_text }}
						{% if migrar.telefono %}

							<input type="text" class="form-control" name="telefono" id="id_telefono" value="{{migrar.telefono}}" />
						{% else %}
							{{ form.telefono }}
						{% endif %}

						{{ form.correo.label_tag }}
						 {{ form.correo.help_text }}
						{% if migrar.correo %}

							<input type="text" class="form-control" name="correo" id="id_correo" value="{{migrar.correo}}" />
						{% else %}
							{{ form.correo }}
						{% endif %}

B) DE LA FAMILIA

					{{ form.nombrePadre.label_tag }}
					 {{ form.nombrePadre.help_text }}

						{{ form.nombrePadre }}

					{{ form.nombreMadre.label_tag }}
					 {{ form.nombreMadre.help_text }}

						{{ form.nombreMadre }}

					{{ form.nombrePareja.label_tag }}
					 {{ form.nombrePareja.help_text }}

						{{ form.nombrePareja }}

						{{ form.emergencia.label_tag }}
						 {{ form.emergencia.help_text }}
						{{ form.emergencia }}

						{{ form.telefonoEmergencia.label_tag }}
						 {{ form.telefonoEmergencia.help_text }}
						{{ form.telefonoEmergencia }}

      <button id="save_personalpaciente" type="submit" class="btn btn-success" style="float: center"> Guardar</button>
       Volver a la lista

</form>
{% endblock %}

redpajama_set_name: RedPajamaGithub


text:
package com.jasonlam604.j2me.ui.components;

import java.util.Enumeration;
import java.util.Vector;

import javax.microedition.lcdui.Canvas;
import javax.microedition.lcdui.Graphics;

public class ComponentContainer extends Canvas {

	private Vector components;

	private boolean isInit = true;
	private int focusIndex = -1;
	private int focusIndexLast = -2;
	private boolean modalComponent = false;

	public ComponentContainer() {
		setFullScreenMode(true);
	}

	private void paintWidget(int index,boolean isFocus) {
		Component c = ((Component)components.elementAt(index));
		c.setFocus(isFocus);
		c.setDirty(true);
		refresh();
	}

	protected void paint(Graphics g) {

		g.setFont(Component.getDefaultFont());

		if(isInit) {
			isInit = false;

			if(leftSoftKey != null) {
				addComponent(leftSoftKey);
			}
			if(rightSoftKey != null) {
				addComponent(rightSoftKey);
			}

			initFocus();
		}

		onPaintBefore(g);

		modalComponent = false;
		if(components != null && components.size() > 0) {
			Enumeration e = components.elements();
			int idx = 0;
			int modalIndex = -1;
			while (e.hasMoreElements()) {
				Component c = (Component) e.nextElement();
				if(!c.isModal()) {
					c.paint(g);
				} else {
					if(c.isVisible())
						modalIndex = idx;
				}
				idx++;
			}

			if(modalIndex != -1) {
				//Paint modal last modal added, ideally you can only have 1 modal at a time
				//((Component)components.elementAt(modalIndex)).paint(g);
				((Component)components.elementAt(modalIndex)).paint(g);
				focusIndex = modalIndex;
				modalComponent = true;
			}
		}

		onPaintAfter(g);
	}

	public void onPaintBefore(Graphics g) {

		if(paintBg) {
			paintBg = false;
			onPaintBackground(g);
		}
	}

	public void onPaintAfter(Graphics g) {

	}

	private boolean paintBg = true;
	public void onPaintBackground(Graphics g) {

	}

	public void addComponent(Component component) {
		if(components == null || components.size() == 0) {
			components = new Vector();
		}
		component.setIndex(components.size() + 1);
		components.addElement(component);

	}

	public void dirtyAll() {
		if(components != null && components.size() > 0) {
			Enumeration e = components.elements();
			paintBg = true;
			while (e.hasMoreElements()) {
				((Component) e.nextElement()).setDirty(true);
			}
		}
	}

	public void refresh() {
		repaint();
	}

	protected void keyPressed(int keyCode) {
		//System.out.println("---" + keyCode);

		if(leftSoftKey != null && leftSoftKey.isVisible() && softKeyListener != null && keyCode == -6) {
			this.softKeyListener.leftSoftKeyPressed();
		} else if(rightSoftKey != null && rightSoftKey.isVisible() && softKeyListener != null && keyCode == -7) {
			this.softKeyListener.rightSoftKeyPressed();
		} else {

			if(modalComponent) {
				((Component)components.elementAt(focusIndex)).keyPressed(keyCode,getGameAction(keyCode));
			} else {

				if(getGameAction(keyCode) == Canvas.UP) {
					moveFocus(false);
				} else if(getGameAction(keyCode) == Canvas.DOWN) {
					moveFocus(true);
				} else {

					if(this.components != null && this.components.size() > 0) {
						//((Component)components.elementAt(focusIndex)).keyPressed(keyCode,getGameAction(keyCode));
						if(focusIndex != -1) {
						Component c = ((Component)components.elementAt(focusIndex));
						if(!c.isDynamic() && getGameAction(keyCode) == Canvas.RIGHT) {
							moveFocus(false);
						} else if(!c.isDynamic() && getGameAction(keyCode) == Canvas.LEFT) {
							moveFocus(true);
						} else {
							c.keyPressed(keyCode,getGameAction(keyCode));
						}
						}
					}
				}
			}
		}

		refresh();
	}

	// Set Focus to the first tabStoppable component
	private void initFocus() {
		if(components != null && components.size() > 0) {
			boolean focusFound = false;
			Enumeration e = components.elements();
			int idx = 0;
			while (e.hasMoreElements()) {
				Component c = (Component) e.nextElement();
				c.setFocus(false);
				if(c.isVisible() && c.isTabStop() && !focusFound) {
					c.setFocus(true);
					focusFound = true;
					focusIndex = idx;
				}
				idx++;
			}
		}
	}

	public void updateFocus() {
		// Need to do this better!!!!!
		// No component has focus when a Modal component closes 'visible = false'
		initFocus();

	}

	private void moveFocus(boolean isDown) {
		if(this.components != null && this.components.size() > 0) {
			int maxLoop = 0;
			focusIndexLast = focusIndex;
			do {
				if(isDown) {
					focusIndex++;
					if(focusIndex >= components.size())
						focusIndex = 0;
				} else {
					focusIndex--;
					if(focusIndex < 0)
						focusIndex = (components.size() - 1);
				}

				// Break Out after cycling through all widgets
				maxLoop++;
				if(maxLoop > components.size())
					break;
			} while (!((Component)components.elementAt(focusIndex)).isTabStop() || !((Component)components.elementAt(focusIndex)).isVisible());

			if(focusIndex != -1) {
			Component c = ((Component)components.elementAt(focusIndexLast));
			c.setFocus(false);
			c.setDirty(true);
			}

			if(focusIndex != -1) {
				Component c = ((Component)components.elementAt(focusIndex));
			c.setFocus(true);
			c.setDirty(true);
			}

			return;
		}
	}

	private Button leftSoftKey = null;
	private Button rightSoftKey = null;
	private SoftKeyListener softKeyListener;
	public void setSoftKeyListener(SoftKeyListener softKeyListener) {
		this.softKeyListener = softKeyListener;
	}
	public void addSoftKeys(String leftLabel,String rightLabel) {

		if(leftLabel != null) {
			leftSoftKey = new Button(leftLabel);
			leftSoftKey.setX(0);
			leftSoftKey.setY(getHeight() - leftSoftKey.getHeight());
		}

		if(rightLabel != null) {
			rightSoftKey = new Button(rightLabel);
			rightSoftKey.setX(getWidth() - rightSoftKey.getWidth());
			rightSoftKey.setY(getHeight() - rightSoftKey.getHeight());
		}

	}

}


text:
<?php

namespace Http\Discovery;

use Http\Discovery\Exception\DiscoveryFailedException;
use Http\Message\UriFactory;

/**
 * Finds a URI Factory.
 *
 * @author David de Boer <david@ddeboer.nl>
 *
 * @deprecated This will be removed in 2.0. Consider using Psr17FactoryDiscovery.
 */
final class UriFactoryDiscovery extends ClassDiscovery
{
    /**
     * Finds a URI Factory.
     *
     * @return UriFactory
     *
     * @throws Exception\NotFoundException
     */
    public static function find()
    {
        try {
            $uriFactory = static::findOneByType(UriFactory::class);
        } catch (DiscoveryFailedException $e) {
            throw new NotFoundException(
                'No uri factories found. To use Guzzle, Diactoros or Slim Framework factories install php-http/message and the chosen message implementation.',
                0,
                $e
            );
        }

        return static::instantiateClass($uriFactory);
    }
}


text:
'use strict';

var path = require('path')
  , copy = require('fs2/copy')

  , resolve = path.resolve

  , programTplPath = resolve(__dirname, 'program.tpl')
  , writeOpts = { intermediate: true }

  , scriptName = 'generate-apps-controllers';

module.exports = function (root) {
	return copy(programTplPath, resolve(root, 'bin', scriptName), writeOpts);
};


text:
////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2021-2022 ArangoDB GmbH, Cologne, Germany
///
/// 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.
///
/// Copyright holder is ArangoDB GmbH, Cologne, Germany
///
/// @author Markus Pfeiffer
////////////////////////////////////////////////////////////////////////////////

#pragma once

#include "Basics/debugging.h"
#include "velocypack/Builder.h"
#include "velocypack/velocypack-common.h"
#include <memory>
#include <utility>

#include <fmt/core.h>
#include <fmt/format.h>
#include <fmt/ostream.h>

#include "Agency/TransactionBuilder.h"
#include "Replication2/ReplicatedLog/AgencyLogSpecification.h"
#include "Replication2/ReplicatedLog/LogCommon.h"
#include "Replication2/Supervision/ModifyContext.h"

using namespace arangodb::replication2::agency;

namespace arangodb::replication2::replicated_log {

using ActionContext =
    ModifyContext<LogPlanSpecification, LogCurrentSupervision>;

/* The empty action signifies that no action has been put
 * into an action context yet; we use a seprarte action
 * instead of a std::optional<Action>, because it is less
 * prone to crashes and undefined behaviour
 */
struct EmptyAction {
  static constexpr std::string_view name = "EmptyAction";

  explicit EmptyAction(){};

  auto execute(ActionContext& ctx) const -> void {}
};
template<typename Inspector>
auto inspect(Inspector& f, EmptyAction& x) {
  auto hack = std::string{x.name};
  return f.object(x).fields(f.field("type", hack));
}

/*
 * This action is placed into the supervision action to prevent
 * any other action from taking place.
 *
 * This is *different* from no action having been put into
 * the context as sometimes we will report a problem through
 * the reporting but do not want to continue;
 *
 * This action does not modify the agency state.
 */
struct NoActionPossibleAction {
  static constexpr std::string_view name = "NoActionPossibleAction";

  explicit NoActionPossibleAction(){};

  auto execute(ActionContext& ctx) const -> void {}
};
template<typename Inspector>
auto inspect(Inspector& f, NoActionPossibleAction& x) {
  auto hack = std::string{x.name};
  return f.object(x).fields(f.field("type", hack));
}

struct AddLogToPlanAction {
  static constexpr std::string_view name = "AddLogToPlanAction";

  AddLogToPlanAction(LogId const id, ParticipantsFlagsMap participants,
                     LogPlanConfig config,
                     std::optional<LogPlanTermSpecification::Leader> leader)
      : _id(id),
        _participants(std::move(participants)),
        _config(std::move(config)),
        _leader(std::move(leader)){};
  LogId _id;
  ParticipantsFlagsMap _participants;
  LogPlanConfig _config;
  std::optional<LogPlanTermSpecification::Leader> _leader;

  auto execute(ActionContext& ctx) const -> void {
    auto newPlan = LogPlanSpecification(
        _id, LogPlanTermSpecification(LogTerm{1}, _leader),
        ParticipantsConfig{
            .generation = 1, .participants = _participants, .config = _config});
    newPlan.owner = "target";
    ctx.setValue<LogPlanSpecification>(std::move(newPlan));

    ctx.modifyOrCreate<LogCurrentSupervision>(
        [&](LogCurrentSupervision& currentSupervision) {
          currentSupervision.assumedWriteConcern =
              _config.effectiveWriteConcern;
          currentSupervision.assumedWaitForSync = _config.waitForSync;
        });
  }
};

template<typename Inspector>
auto inspect(Inspector& f, AddLogToPlanAction& x) {
  auto hack = std::string{x.name};
  return f.object(x).fields(f.field("type", hack), f.field("id", x._id),
                            f.field("participants", x._participants),
                            f.field("leader", x._leader),
                            f.field("config", x._config));
}

struct SwitchLeaderAction {
  static constexpr std::string_view name = "SwitchLeaderAction";

  SwitchLeaderAction(LogPlanTermSpecification::Leader const& leader)
      : _leader{leader} {};

  LogPlanTermSpecification::Leader _leader;

  auto execute(ActionContext& ctx) const -> void {
    ctx.modify<LogPlanSpecification>([&](LogPlanSpecification& plan) {
      plan.currentTerm->term = LogTerm{plan.currentTerm->term.value + 1};
      plan.currentTerm->leader = _leader;
    });
  }
};
template<typename Inspector>
auto inspect(Inspector& f, SwitchLeaderAction& x) {
  auto hack = std::string{x.name};
  return f.object(x).fields(f.field("type", hack),
                            f.field("leader", x._leader));
}

struct WriteEmptyTermAction {
  static constexpr std::string_view name = "WriteEmptyTermAction";
  LogTerm minTerm;

  explicit WriteEmptyTermAction(LogTerm minTerm) : minTerm{minTerm} {};

  auto execute(ActionContext& ctx) const -> void {
    ctx.modify<LogPlanSpecification>([&](LogPlanSpecification& plan) {
      // TODO: what to do if currentTerm does not have a value?
      //       this shouldn't happen, but what if it does?
      plan.currentTerm->term = LogTerm{minTerm.value + 1};
      plan.currentTerm->leader.reset();
    });
  }
};
template<typename Inspector>
auto inspect(Inspector& f, WriteEmptyTermAction& x) {
  auto hack = std::string{x.name};
  return f.object(x).fields(f.field("type", hack),
                            f.field("minTerm", x.minTerm));
}

struct LeaderElectionAction {
  static constexpr std::string_view name = "LeaderElectionAction";

  LeaderElectionAction(LogPlanTermSpecification::Leader electedLeader,
                       size_t effectiveWriteConcern, size_t assumedWriteConcern,
                       LogCurrentSupervisionElection const& electionReport)
      : _electedLeader{electedLeader},
        _effectiveWriteConcern{effectiveWriteConcern},
        _assumedWriteConcern{assumedWriteConcern},
        _electionReport(electionReport){};

  LogPlanTermSpecification::Leader _electedLeader;
  size_t _effectiveWriteConcern;
  size_t _assumedWriteConcern;
  LogCurrentSupervisionElection _electionReport;

  auto execute(ActionContext& ctx) const -> void {
    ctx.modify<LogPlanSpecification>([&](LogPlanSpecification& plan) {
      plan.currentTerm->term = LogTerm{plan.currentTerm->term.value + 1};
      plan.currentTerm->leader = _electedLeader;
      plan.participantsConfig.generation =
          plan.participantsConfig.generation + 1;
      plan.participantsConfig.config.effectiveWriteConcern =
          _effectiveWriteConcern;
    });
    ctx.modify<LogCurrentSupervision>(
        [&](LogCurrentSupervision& currentSupervision) {
          currentSupervision.assumedWriteConcern = _assumedWriteConcern;
        });
  }
};
template<typename Inspector>
auto inspect(Inspector& f, LeaderElectionAction& x) {
  auto hack = std::string{x.name};
  return f.object(x).fields(f.field("type", hack),
                            f.field("election", x._electionReport),
                            f.field("electedLeader", x._electedLeader));
}

struct UpdateParticipantFlagsAction {
  static constexpr std::string_view name = "UpdateParticipantFlagsAction";

  UpdateParticipantFlagsAction(ParticipantId const& participant,
                               ParticipantFlags const& flags)
      : _participant(participant), _flags(flags){};

  ParticipantId _participant;
  ParticipantFlags _flags;

  auto execute(ActionContext& ctx) const -> void {
    ctx.modify<LogPlanSpecification>([&](LogPlanSpecification& plan) {
      TRI_ASSERT(plan.participantsConfig.participants.contains(_participant));
      plan.participantsConfig.participants.at(_participant) = _flags;
      plan.participantsConfig.generation += 1;
    });
  }
};
template<typename Inspector>
auto inspect(Inspector& f, UpdateParticipantFlagsAction& x) {
  auto hack = std::string{x.name};
  return f.object(x).fields(f.field("type", hack),
                            f.field("participant", x._participant),
                            f.field("flags", x._flags));
}

struct AddParticipantToPlanAction {
  static constexpr std::string_view name = "AddParticipantToPlanAction";

  AddParticipantToPlanAction(ParticipantId const& participant,
                             ParticipantFlags const& flags)
      : _participant(participant), _flags(flags) {}

  ParticipantId _participant;
  ParticipantFlags _flags;

  auto execute(ActionContext& ctx) const -> void {
    ctx.modify<LogPlanSpecification>([&](LogPlanSpecification& plan) {
      plan.participantsConfig.generation += 1;
      plan.participantsConfig.participants.emplace(_participant, _flags);
    });
  }
};
template<typename Inspector>
auto inspect(Inspector& f, AddParticipantToPlanAction& x) {
  auto hack = std::string{x.name};
  return f.object(x).fields(f.field("type", hack),
                            f.field("participant", x._participant),
                            f.field("flags", x._flags));
}

struct RemoveParticipantFromPlanAction {
  static constexpr std::string_view name = "RemoveParticipantFromPlanAction";

  RemoveParticipantFromPlanAction(ParticipantId const& participant)
      : _participant(participant){};

  ParticipantId _participant;

  auto execute(ActionContext& ctx) const -> void {
    ctx.modify<LogPlanSpecification>([&](LogPlanSpecification& plan) {
      plan.participantsConfig.participants.erase(_participant);
      plan.participantsConfig.generation += 1;
    });
  }
};
template<typename Inspector>
auto inspect(Inspector& f, RemoveParticipantFromPlanAction& x) {
  auto hack = std::string{x.name};
  return f.object(x).fields(f.field("type", hack),
                            f.field("participant", x._participant));
}

struct UpdateLogConfigAction {
  static constexpr std::string_view name = "UpdateLogConfigAction";

  UpdateLogConfigAction(LogPlanConfig const& config) : _config(config){};

  LogPlanConfig _config;

  auto execute(ActionContext& ctx) const -> void {
    // TODO: updating log config is not implemented yet
  }
};
template<typename Inspector>
auto inspect(Inspector& f, UpdateLogConfigAction& x) {
  auto hack = std::string{x.name};
  return f.object(x).fields(f.field("type", hack));
}

struct UpdateEffectiveAndAssumedWriteConcernAction {
  static constexpr std::string_view name =
      "UpdateEffectiveAndAssumedWriteConcernAction";
  size_t newEffectiveWriteConcern;
  size_t newAssumedWriteConcern;

  auto execute(ActionContext& ctx) const -> void {
    ctx.modify<LogPlanSpecification>([&](LogPlanSpecification& plan) {
      plan.participantsConfig.config.effectiveWriteConcern =
          newEffectiveWriteConcern;
      plan.participantsConfig.generation += 1;
    });
    ctx.modify<LogCurrentSupervision>(
        [&](LogCurrentSupervision& currentSupervision) {
          currentSupervision.assumedWriteConcern = newAssumedWriteConcern;
        });
  }
};
template<typename Inspector>
auto inspect(Inspector& f, UpdateEffectiveAndAssumedWriteConcernAction& x) {
  auto hack = std::string{x.name};
  return f.object(x).fields(
      f.field("type", hack),
      f.field("newEffectiveWriteConcern", x.newEffectiveWriteConcern),
      f.field("newAssumedWriteConcern", x.newAssumedWriteConcern));
}

struct UpdateWaitForSyncAction {
  static constexpr std::string_view name = "UpdateWaitForSyncAction";
  bool newWaitForSync;
  bool newAssumedWaitForSync;

  auto execute(ActionContext& ctx) const -> void {
    ctx.modify<LogPlanSpecification>([&](LogPlanSpecification& plan) {
      plan.participantsConfig.config.waitForSync = newWaitForSync;
      plan.participantsConfig.generation += 1;
    });
    ctx.modify<LogCurrentSupervision>(
        [&](LogCurrentSupervision& currentSupervision) {
          currentSupervision.assumedWaitForSync = newAssumedWaitForSync;
        });
  }
};
template<typename Inspector>
auto inspect(Inspector& f, UpdateWaitForSyncAction& x) {
  auto hack = std::string{x.name};
  return f.object(x).fields(
      f.field("type", hack), f.field("newWaitForSync", x.newWaitForSync),
      f.field("newAssumedWaitForSync", x.newAssumedWaitForSync));
}

struct SetAssumedWriteConcernAction {
  static constexpr std::string_view name = "SetAssumedWriteConcernAction";
  size_t newAssumedWriteConcern;

  auto execute(ActionContext& ctx) const -> void {
    ctx.modifyOrCreate<LogCurrentSupervision>(
        [&](LogCurrentSupervision& currentSupervision) {
          currentSupervision.assumedWriteConcern = newAssumedWriteConcern;
        });
  }
};
template<typename Inspector>
auto inspect(Inspector& f, SetAssumedWriteConcernAction& x) {
  auto hack = std::string{x.name};
  return f.object(x).fields(
      f.field("type", hack),
      f.field("newAssumedWriteConcern", x.newAssumedWriteConcern));
}

struct SetAssumedWaitForSyncAction {
  static constexpr std::string_view name = "SetAssumedWaitForSyncAction";
  bool newAssumedWaitForSync;

  auto execute(ActionContext& ctx) const -> void {
    ctx.modifyOrCreate<LogCurrentSupervision>(
        [&](LogCurrentSupervision& currentSupervision) {
          currentSupervision.assumedWaitForSync = newAssumedWaitForSync;
        });
  }
};
template<typename Inspector>
auto inspect(Inspector& f, SetAssumedWaitForSyncAction& x) {
  auto hack = std::string{x.name};
  return f.object(x).fields(
      f.field("type", hack),
      f.field("newAssumedWriteConcern", x.newAssumedWaitForSync));
}

struct ConvergedToTargetAction {
  static constexpr std::string_view name = "ConvergedToTargetAction";
  std::optional<std::uint64_t> version{std::nullopt};

  auto execute(ActionContext& ctx) const -> void {
    ctx.modifyOrCreate<LogCurrentSupervision>(
        [&](LogCurrentSupervision& currentSupervision) {
          currentSupervision.targetVersion = version;
        });
  }
};
template<typename Inspector>
auto inspect(Inspector& f, ConvergedToTargetAction& x) {
  auto hack = std::string{x.name};
  return f.object(x).fields(f.field("type", hack),
                            f.field("version", x.version));
}

/* NOTE!
 *
 * EmptyAction *has* *to* *be* first, as the default constructor
 * of a variant constructs the variant with index 0
 *
 */
using Action =
    std::variant<EmptyAction, NoActionPossibleAction, AddLogToPlanAction,
                 SwitchLeaderAction, WriteEmptyTermAction, LeaderElectionAction,
                 UpdateParticipantFlagsAction, AddParticipantToPlanAction,
                 RemoveParticipantFromPlanAction, UpdateLogConfigAction,
                 UpdateEffectiveAndAssumedWriteConcernAction,
                 SetAssumedWriteConcernAction, UpdateWaitForSyncAction,
                 SetAssumedWaitForSyncAction, ConvergedToTargetAction>;

auto executeAction(Log log, Action& action) -> ActionContext;
}  // namespace arangodb::replication2::replicated_log

#include "Inspection/VPack.h"
#include "Replication2/ReplicatedLog/AgencySpecificationInspectors.h"

template<>
struct fmt::formatter<arangodb::replication2::replicated_log::Action>
    : formatter<string_view> {
  // parse is inherited from formatter<string_view>.
  template<typename FormatContext>
  auto format(arangodb::replication2::replicated_log::Action a,
              FormatContext& ctx) const {
    VPackBuilder builder;

    std::visit(
        [&builder](auto&& arg) {
          arangodb::velocypack::serialize(builder, arg);
        },
        a);
    return formatter<string_view>::format(builder.slice().toJson(), ctx);
  }
};


text:
<?xml version="1.0" encoding="utf-8"?>
<!-- $Revision: 321911 $ -->

<refentry xml:id="quickhashintset.loadfromstring" xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink">
 <refnamediv>
  <refname>QuickHashIntSet::loadFromString</refname>
  <refpurpose>This factory method creates a set from a string</refpurpose>
 </refnamediv>

 <refsect1 role="description">
  &reftitle.description;
  <methodsynopsis>
   <modifier>public</modifier> <modifier>static</modifier> <type>QuickHashIntSet</type><methodname>QuickHashIntSet::loadFromString</methodname>
   <methodparam><type>string</type><parameter>contents</parameter></methodparam>
   <methodparam choice="opt"><type>int</type><parameter>size</parameter></methodparam>
   <methodparam choice="opt"><type>int</type><parameter>options</parameter></methodparam>
  </methodsynopsis>
  <para>
   This factory method creates a new set from a definition in a string. The
   file format consists of 32 bit signed integers packed together in the
   Endianness that the system that the code runs on uses.
  </para>
 </refsect1>

 <refsect1 role="parameters">
  &reftitle.parameters;
  <para>
   <variablelist>
    <varlistentry>
     <term><parameter>contents</parameter></term>
     <listitem>
      <para>
       The string containing a serialized format of the set.
      </para>
     </listitem>
    </varlistentry>
    <varlistentry>
     <term><parameter>size</parameter></term>
     <listitem>
      <para>
       The amount of bucket lists to configure. The number you pass in will be
       automatically rounded up to the next power of two. It is also
       automatically limited from 4 to 4194304.
      </para>
     </listitem>
    </varlistentry>
    <varlistentry>
     <term><parameter>options</parameter></term>
     <listitem>
      <para>
       The same options that the class' constructor takes; except that the size
       option is ignored. It is automatically calculated to be the same as the
       number of entries in the set, rounded up to the nearest power of two
       automatically limited from 64 to 4194304.
      </para>
     </listitem>
    </varlistentry>
   </variablelist>
  </para>
 </refsect1>

 <refsect1 role="returnvalues">
  &reftitle.returnvalues;
  <para>
   Returns a new QuickHashIntSet.
  </para>
 </refsect1>

 <refsect1 role="examples">
  &reftitle.examples;
  <para>
   <example>
    <title><function>QuickHashIntSet::loadFromString</function> example</title>
    <programlisting role="php">
<![CDATA[
<?php
$contents = file_get_contents( dirname( __FILE__ ) . "/simple.set" );
$set = QuickHashIntSet::loadFromString(
    $contents,
    QuickHashIntSet::DO_NOT_USE_ZEND_ALLOC
);
foreach( range( 0, 0x0f ) as $key )
{
    printf( "Key %3d (%2x) is %s\n",
        $key, $key,
        $set->exists( $key ) ? 'set' : 'unset'
    );
}
?>
]]>
    </programlisting>
    &example.outputs.similar;
    <screen>
<![CDATA[
Key   0 ( 0) is unset
Key   1 ( 1) is set
Key   2 ( 2) is set
Key   3 ( 3) is set
Key   4 ( 4) is unset
Key   5 ( 5) is set
Key   6 ( 6) is unset
Key   7 ( 7) is set
Key   8 ( 8) is unset
Key   9 ( 9) is unset
Key  10 ( a) is unset
Key  11 ( b) is set
Key  12 ( c) is unset
Key  13 ( d) is set
Key  14 ( e) is unset
Key  15 ( f) is unset
]]>
    </screen>
   </example>
  </para>
 </refsect1>

</refentry>

<!-- Keep this comment at the end of the file
Local variables:
mode: sgml
sgml-omittag:t
sgml-shorttag:t
sgml-minimize-attributes:nil
sgml-always-quote-attributes:t
sgml-indent-step:1
sgml-indent-data:t
indent-tabs-mode:nil
sgml-parent-document:nil
sgml-default-dtd-file:"~/.phpdoc/manual.ced"
sgml-exposed-tags:nil
sgml-local-catalogs:nil
sgml-local-ecat-files:nil
End:
vim600: syn=xml fen fdm=syntax fdl=2 si
vim: et tw=78 syn=sgml
vi: ts=1 sw=1
-->


text:
package com.amazonaws.services.dataexchange.model;

import javax.annotation.Generated;

/**
 *
 */
@Generated("com.amazonaws:aws-java-sdk-code-generator")
public enum JobErrorLimitName {

    AssetsPerRevision("Assets per revision"),
    AssetSizeInGB("Asset size in GB"),
    AmazonRedshiftDatashareAssetsPerRevision("Amazon Redshift datashare assets per revision");

    private String value;

    private JobErrorLimitName(String value) {
        this.value = value;
    }

    @Override
    public String toString() {
        return this.value;
    }

    /**
     * Use this in place of valueOf.
     *
     * @param value
     *        real value
     * @return JobErrorLimitName corresponding to the value
     *
     * @throws IllegalArgumentException
     *         If the specified value does not map to one of the known values in this enum.
     */
    public static JobErrorLimitName fromValue(String value) {
        if (value == null || "".equals(value)) {
            throw new IllegalArgumentException("Value cannot be null or empty!");
        }

        for (JobErrorLimitName enumEntry : JobErrorLimitName.values()) {
            if (enumEntry.toString().equals(value)) {
                return enumEntry;
            }
        }

        throw new IllegalArgumentException("Cannot create enum from " + value + " value!");
    }
}


text:
var Adaptive;
(function (Adaptive) {
    /**
       @enum {Adaptive.ILoggingLogLevel} Adaptive.ILoggingLogLevel
       Enumeration ILoggingLogLevel
    */
    var ILoggingLogLevel = (function () {
        function ILoggingLogLevel(value) {
            this.value = value;
        }
        ILoggingLogLevel.prototype.toString = function () { return this.value; };
        /**
           @method
           @static
           Convert JSON parsed object to enumeration.
           @return {Adaptive.ILoggingLogLevel}
        */
        ILoggingLogLevel.toObject = function (object) {
            var retValue = ILoggingLogLevel.Unknown;
            if (object != null && object.value != null && ILoggingLogLevel.hasOwnProperty(object.value)) {
                retValue = ILoggingLogLevel[object.value];
            }
            return retValue;
        };
        /**
           @property {Adaptive.ILoggingLogLevel} [Debug='Debug']
        */
        ILoggingLogLevel.Debug = new ILoggingLogLevel("Debug");
        /**
           @property {Adaptive.ILoggingLogLevel} [Warn='Warn']
        */
        ILoggingLogLevel.Warn = new ILoggingLogLevel("Warn");
        /**
           @property {Adaptive.ILoggingLogLevel} [Error='Error']
        */
        ILoggingLogLevel.Error = new ILoggingLogLevel("Error");
        /**
           @property {Adaptive.ILoggingLogLevel} [Info='Info']
        */
        ILoggingLogLevel.Info = new ILoggingLogLevel("Info");
        /**
           @property {Adaptive.ILoggingLogLevel} [Unknown='Unknown']
        */
        ILoggingLogLevel.Unknown = new ILoggingLogLevel("Unknown");
        return ILoggingLogLevel;
    })();
    Adaptive.ILoggingLogLevel = ILoggingLogLevel;
})(Adaptive || (Adaptive = {}));
//# sourceMappingURL=ILoggingLogLevel.js.map


text:
ofbiz之entity实体写法与解析

OFBiz之Entity简介:

  一、Entity Engine屏蔽了数据库访问的很多细节,通过XML配置文件定义描述实体,实体引擎自动维护实体至数据库的所有细节

  二、支持主流数据库,包括Oracle、MySql、MS SQL、PostgreSql等

  三、OFBiz实体引擎与其他的ORM框架最大的不同,是OFBiz只有一个GenericValue对象,不像其它ORM框架,要定义各种不同类型的,防止产生过多的实体对象,避免产生类爆炸。

  四、OFBiz的GenericValue对象不同于其它ORM框架定义的实体对象,它没有getter和setter方法,全部通过put(key,value)的形式来设置属性的值,保持最大的灵活性。

 什么是Entities(实体)?

  Entities(实体)是MVC框架中一个模型的组基本单元,简单来说,一个entity是一个单独的数据库表,这个表包含了一个现实世界中的实体信息,例如一个人。一个Person表包含描述一个人的相关字段。

# 实体引擎概念(Entity Engine Concepts)

## 数据源(datasource)

  一个数据源通过作为默认的RDBMS(关系型数据库管理系统),在一个数据库实例中可以有多种数据库模式,每一种数据库模式具有不同的实体

数据源通常被定义和配置在(projectName\framework\config\entityengine.xml),OFBiz默认的数据源为localderby,我们在这里使用PostgreSql数据库来说明,代码如下:

  在<inline-jdbc>元素中,jdbc-uri去创建另一个数据库实例,简单来说,就是在PostgreSql数据库中创建一个名为ofbiz的数据库文件夹

    <datasource name="localpostnew"
            helper-class="org.ofbiz.entity.datasource.GenericHelperDAO"
            schema-name="public"
            field-type-name="postnew"
            check-on-start="true"
            add-missing-on-start="true"
            use-fk-initially-deferred="false"
            alias-view-columns="false"
            join-style="ansi"
            use-binary-type-for-blob="true"
            use-order-by-nulls="true">
        <read-data reader-name="tenant"/>
        <read-data reader-name="seed"/>
        <read-data reader-name="seed-initial"/>
        <read-data reader-name="demo"/>
        <read-data reader-name="ext"/>
        <inline-jdbc
                jdbc-driver="org.postgresql.Driver"
                jdbc-uri="jdbc:postgresql://127.0.0.1:5432/ofbiz"
                jdbc-username="ofbiz"
                jdbc-password="ofbiz"
                isolation-level="ReadCommitted"
                pool-minsize="2"
                pool-maxsize="250"
                time-between-eviction-runs-millis="600000"/>
    </datasource>

## 实体代理(Entity Delegators)

  OFBiz通过实体代理来连接资料库,一个实体代理主要目的是提供CRUD方法去操作资料库。实体代理不能执行这些CRUD任务,因此实体代理指定哪一个数据源(datasource)去访问实体组的哪一个实体,然后执行任务。实体代理被定义在(projectName\framework\config\entityengine.xml)文件中,一个代理定义在<delegator>元素中,OFBiz默认localderby。

## 定义一个实体Entity

  实体定义在(projectName\applications\%module%\entitydef\entitymodel.xml)中,例如:

    <?xml version="1.0" encoding="UTF-8"?>
      <entitymodel xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:noNamespaceSchemaLocation="http://ofbiz.apache.org/dtds/entitymodel.xsd">
    <title>Entity of an Open For Business Project Component</title>
    <description>None</description>
    <version>1.0</version>

    <entity entity-name="Budget"
            package-name="org.ofbiz.accounting.budget"
            title="Budget Entity">
      <field name="budgetId" type="id-ne"></field>
      <field name="budgetTypeId" type="id"></field>
      <field name="customTimePeriodId" type="id"></field>
      <field name="comments" type="comment"></field>
      <prim-key field="budgetId"/>
      <relation type="one" fk-name="BUDGET_BGTTYP" rel-entity-name="BudgetType">
        <key-map field-name="budgetTypeId"/>
      </relation>
      <relation type="one" fk-name="BUDGET_CTP" rel-entity-name="CustomTimePeriod">
        <key-map field-name="customTimePeriodId"/>
      </relation>
      <relation type="many" rel-entity-name="BudgetTypeAttr">
        <key-map field-name="budgetTypeId"/>
      </relation>
    </entity>
    </entitymodel>

  <entity>元素中的属性名entity-name必须是唯一的,因为实体引擎通过entity元素的属性名来鉴别entity;package-name属性充当分类工具,允许OFBiz在不同的包中处理相应的实体。

  一个<entity>元素可以包含<field>、<prim-key>、<relation>、<index>等4个元素,一个实体至少包含一个<field>元素,一个<field>元素必须有 name和type属性,通过<prim-key>来引用实体,一个实体可以有多个<prim-key>,当有多个主键时,要引用实体,就需要更详细的信息,如果不定义主键的话,数据库不会创建表。

  <relation>元素,定义当前实体与其他实体之间的关系,一般用做创建外键和根据关系查询使用

     rel-entity-name:被关联实体名称

     fk-name:如果创建外键,那么定义外键的名称

     title:给当前关系起个别名

     field-name:当前实体的字段,指明当前实体的哪个字段与被关系实体有关系

     rel-field-name:被关系的实体的字段名称,指明field-name和被关系实体的哪个字段有关系,如果rel-field-name与field-name相同,那么rel-field-name可以不定义。

     type="one-nofk":关联类型,主要有三类"one"、"one-nofk"、"many",one、one-nofk的使用条件是倍关系实体的rel-field-name为主键,而many的使用条件是被关系实体的rel-field-name为非主键,one与one-nofk的区别在于one会在数据库表结构中创建外键约束,而one-nofk不会Relation除了用来创建外键约束之外还被用来做关系查询,当访问关系的时候可以用.getRelated("")和.getRelatedOne(""),用title+entityName作为参数,当实体一个"many"关系的时候使用getRelated返回一个列表,当实体一个"one"关系的时候使用getRelatedOne返回一个实体对象

  <index>元素,除了作为提升数据检索速度的性能工具,indexes也允许我们执行特定的约束,indexes可以被定义在一个entity中的任意字段

## 实体组

  实体组是一组实体被组织在一个组名下,组名作为一个把手为实体代理决定指定数据源查询指定的实体。实体组定义在(projectName\applications\%module%\entitydef\entitygroup.xml)

# 实体定义文件

  实体定义文件一般存放在对应模块entitydef文件夹下面,以party为例,路径(%ofbiz-home%\applications\party\entitydef\entitymodel.xml),通过对应模块的ofbiz-component.xml进行加载.

     <entity-resource type="model" reader-name="main" loader="main" location="entitydef/entitymodel.xml"/>
     <entity-resource type="model" reader-name="main" loader="main" location="entitydef/entitymodel_old.xml"/>
# 实体类型

  普通实体(Entity):实体引擎中的模型基本单元,一个实体唯一对应数据库中的一张表

  视图实体(View-Entity):简单的说就是由不同普通实体通过关联得到虚拟的实体。和数据库视图概念类似

  拓展实体(Extend-Entity):可以继承和拓展已存在的普通实体

  动态实体(DynamicViewEntity):在程序中手动创建一个实体,一般用于查询

## 普通实体

    <entity entity-name="TenantDataSource" package-name="org.ofbiz.entity.tenant">
        <description>
            There should be one record for each tenant and each group-map for the active delegator.
            The jdbc fields will override the datasource -> inline-jdbc values for the per-tenant delegator.
        </description>
        <field name="tenantId" type="id-ne"/>
        <field name="entityGroupName" type="name"/>
        <field name="jdbcUri" type="long-varchar"/>
        <field name="jdbcUsername" type="long-varchar"/>
        <field name="jdbcPassword" type="long-varchar"></field>
        <prim-key field="tenantId"/>
        <prim-key field="entityGroupName"/>
        <relation type="one" fk-name="TNTDTSRC_TNT" rel-entity-name="Tenant">
        <key-map field-name="tenantId"/>
        </relation>
      </entity>

普通实体和数据库中的表是一一对应,程序会根据实体定义的数据库中创建表、索引,外键约束等。

## 视图实体

  一个视图实体由四部分组成:成员实体、字段、视图衔接(将成员实体连接在一起的关系)、关系(实体与实体之间的关系);

视图实体一般用于多表连接复杂查询,视图实体不会在数据库中反应出来。

    <view-entity entity-name="WorkEffortAssocView"
            package-name="org.ofbiz.workeffort.workeffort"
            title="Work Effort Association Entity with Name">
      <member-entity entity-alias="WA" entity-name="WorkEffortAssoc"/>
      <member-entity entity-alias="WETO" entity-name="WorkEffort"/>
      <alias-all entity-alias="WA"/>
      <alias entity-alias="WETO" name="workEffortToName" field="workEffortName"/>
      <alias entity-alias="WETO" name="workEffortToSetup" field="estimatedSetupMillis"/>
      <alias entity-alias="WETO" name="workEffortToRun" field="estimatedMilliSeconds"/>
      <alias entity-alias="WETO" name="workEffortToParentId" field="workEffortParentId"/>
      <alias entity-alias="WETO" name="workEffortToCurrentStatusId" field="currentStatusId"/>
      <alias entity-alias="WETO" name="workEffortToWorkEffortPurposeTypeId" field="workEffortPurposeTypeId"/>
      <alias entity-alias="WETO" name="workEffortToEstimatedStartDate" field="estimatedStartDate"/>
      <alias entity-alias="WETO" name="workEffortToEstimatedCompletionDate" field="estimatedCompletionDate"/>
      <alias entity-alias="WETO" name="workEffortToActualStartDate" field="actualStartDate"/>
      <alias entity-alias="WETO" name="workEffortToActualCompletionDate" field="actualCompletionDate"/>
      <view-link entity-alias="WA" rel-entity-alias="WETO">
        <key-map field-name="workEffortIdTo" rel-field-name="workEffortId"/>
      </view-link>
      <relation type="one-nofk" fk-name="WK_EFFRTASSV_FWE" title="From" rel-entity-name="WorkEffort">
        <key-map field-name="workEffortIdFrom" rel-field-name="workEffortId"/>
      </relation>
    </view-entity>

  <member-entity>元素,通常一个视图实体有两个以上成员实体成员,每一个实体在视图实体被定义在<member-entity>元素中,如

    <member-entity entity-alias="HotelGuest" entity-name="PersonL"/>
  每一个实体成员可以被视图实体多次引入,每次引入通过entity-alias属性鉴别,如

    <member-entity entity-alias="HotelGuest" entity-name="PersonL"/>
    <member-entity entity-alias="HotelOwner" entity-name="PersonL"/>
  视图是描述实体成员的层级,例如,一位客人住在一个宾馆,这个宾馆拥有者掌管,如下

    <member-entity entity-alias="HotelGuest" entity-name="PersonL"/>
    <member-entity entity-alias="Hotel" entity-name="HotelL"/>
    <member-entity entity-alias="HotelOwner" entity-name="PersonL"/>
  定义一个视图的关键字用<alias>元素,通过entity-alias属性处理实体别名,在entitydef文件夹下,编辑entitymodel.xml,添加PersonL实体和Hotel实体:

    <entity entity-name="PersonL" package-name="org.ofbiz.learning">
    <field name="personId" type="id-ne"></field>
    <field name="firstName" type="name"></field>
    <field name="lastName" type="name"></field>
    <field name="housedAt" type="id"></field>
    <field name="someExtraDetails" type="description"></field>
    <prim-key field="personId"/>
    <relation type="one-nofk" fk-name="PERSON_HOTEL"
    rel-entity-name="HotelL">
    <key-map field-name="housedAt" rel-field-name="hotelId"/>
    </relation>
    </entity>
    <entity entity-name="HotelL" package-name="org.ofbiz.learning">
    <field name="hotelId" type="id-ne"></field>
    <field name="hotelName" type="name"></field>
    <field name="ownedBy" type="id"></field>
    <field name="postalAddressId" type="id"></field>
    <prim-key field="hotelId"/>
    <relation type="one-nofk" fk-name="HOTEL_OWNER"
    rel-entity-name="PersonL">
    <key-map field-name="ownedBy" rel-field-name="personId"/>
    </relation>
    </entity>

  假如我们想要用一个视图实体包关键字:guest name,hotel name,hotel owner,在entitymodel.xml中添加一个视图实体GuestHotelOwnerViewL:

    <view-entity entity-name="GuestHotelOwnerViewL"
    package-name="org.ofbiz.learning">
    <member-entity entity-alias="HotelGuest" entity-name="PersonL"/>
    <member-entity entity-alias="Hotel" entity-name="HotelL"/>
    <member-entity entity-alias="HotelOwner" entity-name="PersonL"/>
    <alias entity-alias="HotelGuest" name="guestFirstName"  field="firstName"/>
    <alias entity-alias="HotelGuest" name="guestLastName" field="lastName"/>
    <alias entity-alias="Hotel" name="hotelName" field="hotelName"/>
    <alias entity-alias="HotelOwner" name="ownerFirstName"
    field="firstName"/>
    <alias entity-alias="HotelOwner" name="ownerLastName"
    field="lastName"/>
    <view-link entity-alias="HotelGuest" rel-entity-alias="Hotel">
        <key-map field-name="housedAt" rel-field-name="hotelId"/>
    </view-link>
    <view-link entity-alias="Hotel" rel-entity-alias="HotelOwner">
        <key-map field-name="ownedBy" rel-field-name="personId"/>
    </view-link>
    </view-entity>

<alias-all>元素包括所有自定实体成员中的元素,它可以剔除一些元素,也可以给字段名增添前缀,生成有意义的alias别名,我们用<alias-all>元素构建上面例子的视图实体。

      <view-entity entity-name="GuestHotelOwnerViewAllL" package-name="org.ofbiz.learning">
      <member-entity entity-alias="HotelGuest" entity-name="PersonL"/>
      <member-entity entity-alias="Hotel" entity-name="HotelL"/>
      <member-entity entity-alias="HotelOwner" entity-name="PersonL"/>
     <alias-all entity-alias="HotelGuest" prefix="guest">
      <exclude field="id"/>
      <exclude field="housedAt"/>
      <exclude field="someExtraDetails"/>
      </alias-all>
      <alias-all entity-alias="Hotel" prefix="hotel">
      <exclude field="hotelId"/>
      <exclude field="ownedBy"/>
      </alias-all>
      <alias-all entity-alias="HotelOwner" prefix="owner">
      <exclude field="personId"/>
      <exclude field="housedAt"/>
      <exclude field="someExtraDetails"/>
      </alias-all>
      <view-link entity-alias="HotelGuest" rel-entity-alias="Hotel">
      <key-map field-name="housedAt" rel-field-name="hotelId"/>
      </view-link>
      <view-link entity-alias="Hotel" rel-entity-alias="HotelOwner">
      <key-map field-name="ownedBy" rel-field-name="personId"/>
      </view-link>
    </view-entity>

内部链接和外部链接,<view-link>有rel-optional属性去指定被加入这些实体之间的关系是否可选择,如果是可选的(内连接),那么entity-alias指定的成员实体的所有记录将被查询返回到视图实体,如果不是可选的(外连接),将返回被rel-entity-alias指定的成员实体的相关记录。

  视图实体中relation只能用来做关系查询

  而view-link用来做join关联查询。在entityengine.xml中<datasource..>元素当中的join-style属性当中设置你的数据库join方法

###  在字段上应用函数

     视图实体字段可以包含函数结果,不仅仅是成员实体字段值,函数:count、count-distinct、min、max、sum、avg、upper、lower

  计算记录的数量:

    <alias entity-alias="PA" name="contactMechId" function="count"/>
  计算不同记录的数量:

    <alias entity-alias="PA" name="city" function="count-distinct"/>
  大写和小写的功能:

    <alias entity-alias="PA" name="upperToName" field="toName" function="upper"/>
    <alias entity-alias="PA" name="lowerAddress1" field="address1" function="lower"/>
###  Grouping for Summary Views

当我们想通过一个关键字把一组数据分组的时候,我们在一个视图实体alias字段上添加group-by属性,我们通过city数量来计算postal address的数量:

    <view-entity entity-name="TestGrouping" package-name="org.ofbiz.learning">
      <member-entity entity-alias="PA" entity-name="PostalAddress"/>
      <alias entity-alias="PA" name="count" field="contactMechId" function="count"/>
      <alias entity-alias="PA" name="city" group-by="true"/>
    </view-entity>

嵌入<complex-alias>元素,一个<complex-alias>元素可以包含另一个<complex-alias>元素

    <member-entity entity-alias="EA" entity-name="SomeEntityAlias"/>
    <alias name="complexComputedField">
    <complex-alias operator="*">
      <complex-alias operator="+">
         <complex-alias-field entity-alias="EA" field="a"/>
         <complex-alias-field entity-alias="EA" field="b"/>
      </complex-alias>
      <complex-alias operator="/">
         <complex-alias operator="-">
            <complex-alias-field entity-alias="EA" field="c"/>
            <complex-alias-field entity-alias="EA" field="d"/>
         </complex-alias>
         <complex-alias-field entity-alias="EA" field="e"/>
      </complex-alias>
    </complex-alias>
    </alias>

## 扩展实体

  集成已存在的实体并对其进行扩展

    <extend-entity entity-name="UserLogin">
            <field name="partyId" type="id"></field>
            <relation type="one" fk-name="USER_PARTY" rel-entity-name="Party">
                <key-map field-name="partyId"/>
            </relation>
            <relation type="one-nofk" rel-entity-name="Person">
                <key-map field-name="partyId"/>
            </relation>
            <relation type="one-nofk" rel-entity-name="PartyGroup">
                <key-map field-name="partyId"/>
            </relation>
    </extend-entity>

## 动态实体

在程序中手动创建实体,对其进行查询

    DynamicViewEntity salesUsageViewEntity = new DynamicViewEntity();
        salesUsageViewEntity.addMemberEntity("OI", "OrderItem");
        salesUsageViewEntity.addMemberEntity("OH", "OrderHeader");
        salesUsageViewEntity.addMemberEntity("ItIss", "ItemIssuance");
        salesUsageViewEntity.addMemberEntity("InvIt", "InventoryItem");
        salesUsageViewEntity.addViewLink("OI", "OH", Boolean.valueOf(false), ModelKeyMap.makeKeyMapList("orderId"));
        salesUsageViewEntity.addViewLink("OI", "ItIss", Boolean.valueOf(false), ModelKeyMap.makeKeyMapList("orderId", "orderId", "orderItemSeqId", "orderItemSeqId"));
       salesUsageViewEntity.addViewLink("ItIss", "InvIt", Boolean.valueOf(false), ModelKeyMap.makeKeyMapList("inventoryItemId"));
        salesUsageViewEntity.addAlias("OI", "productId");
        salesUsageViewEntity.addAlias("OH", "statusId");
        salesUsageViewEntity.addAlias("OH", "orderTypeId");
        salesUsageViewEntity.addAlias("OH", "orderDate");
        salesUsageViewEntity.addAlias("ItIss", "inventoryItemId");
        salesUsageViewEntity.addAlias("ItIss", "quantity");
      salesUsageViewEntity.addAlias("InvIt", "facilityId");
    EntityListIterator salesUsageIt = delegator.findListIteratorByCondition(salesUsageViewEntity,
    EntityCondition.makeCondition(
    UtilMisc.toList(
             EntityCondition.makeCondition("facilityId", EntityOperator.EQUALS, facilityId),
              EntityCondition.makeCondition("productId", EntityOperator.EQUALS, productId),
                EntityCondition.makeCondition("statusId",
    EntityOperator.IN,
    UtilMisc.toList("ORDER_COMPLETED", "ORDER_APPROVED", "ORDER_HELD")),
            EntityCondition.makeCondition("orderTypeId", EntityOperator.EQUALS, "SALES_ORDER"),
               EntityCondition.makeCondition("orderDate", EntityOperator.GREATER_THAN_EQUAL_TO, checkTime)
    ),
    EntityOperator.AND),null, null, null, null
    );

# 实体定义

## 命名规则

  实体名称(entity-name)首字母大写,如果实体名称由多个关键字组成,那么关键字首字母大写,如entity-name="TenanDataSource",ofbiz会在创建数据库表的时候根据entity-name实体名称首字母之外的大写字母前面加"_",所以entity-name="TenanDataSource"生成的数据库表名为"Tenant_Data_source",要控制entity-name实体名称不要超过25个字母。

Field表字段,命名规则与实体名称一样,唯一不同的是首字母小写

## 实体与数据库的关联

    <entity-group group="org.ofbiz.olap" entity="SalesInvoiceItemFact"/>
    <entity-group group="org.ofbiz.olap" entity="SalesInvoiceItemStarSchema"/>
Entity-group一般被定义在模块\entitydef\entitygroupXXX.xml中,对实体进行分组,使不同的实体分属不同的entity-group。不是所有的entity都进行了entity-group分组,如果没有被分组,系统启动的时候会将实体默认归类到"org.ofbiz"中。

查看数据库定义文件%ofbiz_home%/framework/entity/config/entityengine.xml

    <delegator name="default" entity-model-reader="main" entity-group-reader="main" entity-eca-reader="main" distributed-cache-clear-enabled="false">
            <group-map group-name="org.ofbiz" datasource-name="localpostnew"/>
            <group-map group-name="org.ofbiz.olap" datasource-name="localpostolap"/>
            <group-map group-name="org.ofbiz.tenant" datasource-name="localposttenant"/>
    </delegator>
可以发现delegator将多个group-name组织到一起并将group-name与datasource对应起来,datasource-name是什么?

    <datasource name="localdernew"
        helper-class="org.ofbiz.entity.datasource.GenericHelperDAO"
        schema-name="OFBIZ"
        field-type-name="postgres"
        check-on-start="true"
        add-missing-on-start="true"
        use-pk-constraint-names="false"
        use-indices-unique="false"
        alias-view-columns="false"
        use-order-by-nulls="true">
    <read-data reader-name="seed"/>
    <read-data reader-name="seed-initial"/>
    <read-data reader-name="demo"/>
    <read-data reader-name="ext"/>
    <inline-jdbc
            jdbc-driver="org.apache.derby.jdbc.EmbeddedDriver"
            jdbc-uri="jdbc:derby:ofbiz;create=true"
            jdbc-username="ofbiz"
            jdbc-password="ofbiz"
            isolation-level="ReadCommitted"
            pool-minsize="2"
            pool-maxsize="250"
            time-between-eviction-runs-millis="600000"/>
    </datasource>

Datasource定义了数据库驱动,数据库用户名、密码等,所以datasource就是我们说的数据库。

PS:我们通过entity-group将各个实体和数据库之间关联起来,然后将一个或多个数据库归属到一个delegator中,我们又是怎么使用数据库进行数据库操作的呢?我们可以发现

    <context-param>
            <param-name>entityDelegatorName</param-name>
            <param-value>default</param-value>
            <description>The Name of the Entity Delegator to use, defined in entityengine.xml</description>
    </context-param>
# 常用实体引擎API:GenericPK、GenericValue、GenericDelegator、EntityCondition

## GenericPK

 GenericPK一般用于生产实体的主键

## GenericValue

 GenericValue通用实体值对象,处理任何被定义实体的持久化

## GenericDelegator

 GeneticDelegator通用的数据库访问代理类,对数据库CRUD的实现都通过该类实现。

###  创建实体 以非持久化的GenericValue值对象的形式创建Entity

        GenericValue party = delegator.makeValue("party");

        //创建非主键

        party.setNonPKFields(UtilMisc.toMap("partyTypeId","PERSON","description","测试Party","statusId","PARTY_ENABLED"));

        //创建主键

        String partyId = delegator.getNextSeqId("party");

        party.setPKFields(UtilMisc.toMap("partyId",partyId)); //getNextSeqId("String entityName")生成主键序列号

        //以GenericValue值对象的形式创建Entity实体,并持久化至数据库

        GenericValue createParty = delegetor.create(party);

        Assert.assertEquals(partyId,createParty.getPkShortValueString());

  然后再启动测试用例

  更简便的方式:

         Map<String, String> partyMap = UtilMisc.toMap("partyTypeId","PERSON","description","测试Party","statusId","PARTY_ENABLED");

         //makeValidValue(entityName, Map<String, ?extends Object>fields);验证每个字段的有效性,无效不设置

         delegator.makeValidValue("Party", partyMap);

### 更新实体

    createParty.put("partyId", "123");

    int updated = delegator.store(createParty);//int updated 为更新的字段数量,store()方法只更新数据库已有的字段,storeAll是一个更新字段集合,如果数据库中没有更新的字段,会添加进去。

    Assert.assertEquals(1,updated);

### 删除实体

  int deleted = delegator.removeByAnd("Party", UtilMisc.toMap("partyId",partyId));

  Assert.assertEquals(1,deleted);

## EntityCondition

    EntityCondition封装查询实体的条件,makeCondition()方法设置查询约束

## 实体缓存(cache)

  实体缓存设置,在entity配置文件中添加属性never-cache="false/true"来设置是否添加实体缓存,ofbiz为了性能优化,系统默认开启实体缓存,never-cahce="true"我们才可能调用实体缓存相关API,相关API:

  findByPrimaryKeyCache,

  findByAndCache,

  findByConditonCache,

  findByAllCache,

  OFBiz会自动检测缓存实体是否有更新,如果有更新会自己更新。在OFBiz的开发中,我们优先使用带有cache缓存的API

  UtilCache API下是相关的缓存API,UtilCache.clearCache("")清理缓存,同样我们也在WEBTOOLS→>缓存维护中清理缓存


text:
<?php

namespace Cerad\Bundle\Api01Bundle\Action\ProjectGame;

use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;

use Symfony\Component\HttpFoundation\Response;

class FindOneControllerTest extends WebTestCase
{
    protected $project = '/0.1/project/AYSONationalGames2014/';

    public function testRequestNotFound()
    {
        $client = static::createClient();

        $client->request('GET', '/project/natgames/games/11001');  // games instead of game

        $response = $client->getResponse();

        $statusCode = $response->getStatusCode();
        $statusText = Response::$statusTexts[$statusCode];

        $this->assertEquals('Symfony\Component\HttpFoundation\Response',get_class($response));
        $this->assertEquals(Response::HTTP_NOT_FOUND,$response->getStatusCode());
        $this->assertEquals('Not Found',$statusText);
        $this->assertEquals('text/html; charset=UTF-8',$response->headers->get('Content-Type'));
    }
    //  curl local.api.zayso.org/0.1/project/AYSONationalGames2014/game/11001
    public function testFindProjectGame()
    {
        $client = static::createClient();

        $client->request('GET', $this->project . 'game/11001');

        $response = $client->getResponse();

        $this->assertEquals(Response::HTTP_OK,$response->getStatusCode());
        $this->assertEquals('application/json',$response->headers->get('Content-Type'));

        $content = $response->getContent();

        $game = json_decode($content,true);

        $this->assertEquals(11001,$game['num']);

        $this->assertEquals('Toyota Sports Complex',$game['venueName']);
        $this->assertEquals('MA1',$game['fieldName']);
        $this->assertEquals('2014-07-03 10:30:00',$game['dtBeg']);

        $teams = $game['teams'];
        $this->assertEquals(2,count($teams));

        $awayTeam = $teams[1];
        $this->assertEquals('Away',$awayTeam['role']);

    }
    public function testFindProjectGameWithBadNumber()
    {
        $client = static::createClient();

        $client->request('GET', $this->project . 'game/91001');

        $response = $client->getResponse();

        $this->assertEquals(Response::HTTP_NOT_FOUND,$response->getStatusCode());
        $this->assertEquals('No Project Game For AYSONationalGames2014 91001',$response->getContent());

    }
}