<commit_before>// Licensed to the Software Freedom Conservancy (SFC) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The SFC licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License.  You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied.  See the License for the
// specific language governing permissions and limitations
// under the License.

package org.openqa.selenium.remote;

import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSortedSet;
import com.google.common.collect.Ordering;
import com.google.common.collect.Sets;
import com.google.common.io.CharSource;
import com.google.common.io.CharStreams;
import com.google.common.io.FileBackedOutputStream;
import org.openqa.selenium.Capabilities;
import org.openqa.selenium.ImmutableCapabilities;
import org.openqa.selenium.internal.Require;
import org.openqa.selenium.json.Json;
import org.openqa.selenium.json.JsonInput;
import org.openqa.selenium.json.JsonOutput;

import java.io.Closeable;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.Reader;
import java.io.StringReader;
import java.io.UncheckedIOException;
import java.io.Writer;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.function.Predicate;
import java.util.stream.Stream;

import static java.nio.charset.StandardCharsets.UTF_8;
import static org.openqa.selenium.json.Json.LIST_OF_MAPS_TYPE;
import static org.openqa.selenium.json.Json.MAP_TYPE;

public class NewSessionPayload implements Closeable {

  private static final Dialect DEFAULT_DIALECT = Dialect.OSS;
  private static final Predicate<String> ACCEPTED_W3C_PATTERNS = new AcceptedW3CCapabilityKeys();

  private final Json json = new Json();
  private final FileBackedOutputStream backingStore;
  private final ImmutableSet<Dialect> dialects;

  public static NewSessionPayload create(Capabilities caps) {
    // We need to convert the capabilities into a new session payload. At this point we're dealing
    // with references, so I'm Just Sure This Will Be Fine.
    return create(ImmutableMap.of("desiredCapabilities", caps.asMap()));
  }

  public static NewSessionPayload create(Map<String, ?> source) {
    String json = new Json().toJson(Require.nonNull("Payload", source));
    return new NewSessionPayload(new StringReader(json));
  }

  public static NewSessionPayload create(Reader source) {
    return new NewSessionPayload(source);
  }

  private NewSessionPayload(Reader source) {
    // Dedicate up to 10% of all RAM or 20% of available RAM (whichever is smaller) to storing this
    // payload.
    int threshold = (int) Math.min(
      Integer.MAX_VALUE,
      Math.min(
        Runtime.getRuntime().freeMemory() / 5,
        Runtime.getRuntime().maxMemory() / 10));

    backingStore = new FileBackedOutputStream(threshold);
    try (Writer writer = new OutputStreamWriter(backingStore, UTF_8)) {
      CharStreams.copy(source, writer);
    } catch (IOException e) {
      throw new UncheckedIOException(e);
    }

    ImmutableSet.Builder<Dialect> dialects = ImmutableSet.builder();
    try {
      if (getOss() != null) {
        dialects.add(Dialect.OSS);
      }
      if (getAlwaysMatch() != null || getFirstMatches() != null) {
        dialects.add(Dialect.W3C);
      }

      this.dialects = dialects.build();

      validate();
    } catch (IOException e) {
      throw new UncheckedIOException(e);
    }
  }

  private void validate() throws IOException {
    Map<String, Object> alwaysMatch = getAlwaysMatch();
    if (alwaysMatch == null) {
      alwaysMatch = ImmutableMap.of();
    }
    Map<String, Object> always = alwaysMatch;
    Collection<Map<String, Object>> firsts = getFirstMatches();
    if (firsts == null) {
      firsts = ImmutableList.of(ImmutableMap.of());
    }

    if (firsts.isEmpty()) {
      throw new IllegalArgumentException("First match w3c capabilities is zero length");
    }

    firsts.stream()
      .peek(map -> {
        Set<String> overlap = Sets.intersection(always.keySet(), map.keySet());
        if (!overlap.isEmpty()) {
          throw new IllegalArgumentException(
            "Overlapping keys between w3c always and first match capabilities: " + overlap);
        }
      })
      .map(first -> {
        Map<String, Object> toReturn = new HashMap<>();
        toReturn.putAll(always);
        toReturn.putAll(first);
        return toReturn;
      })<commit_msg>Close InputStream after creating the new session payload<commit_after>// Licensed to the Software Freedom Conservancy (SFC) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The SFC licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License.  You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied.  See the License for the
// specific language governing permissions and limitations
// under the License.

package org.openqa.selenium.remote;

import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSortedSet;
import com.google.common.collect.Ordering;
import com.google.common.collect.Sets;
import com.google.common.io.CharSource;
import com.google.common.io.CharStreams;
import com.google.common.io.FileBackedOutputStream;
import org.openqa.selenium.Capabilities;
import org.openqa.selenium.ImmutableCapabilities;
import org.openqa.selenium.internal.Require;
import org.openqa.selenium.json.Json;
import org.openqa.selenium.json.JsonInput;
import org.openqa.selenium.json.JsonOutput;

import java.io.Closeable;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.Reader;
import java.io.StringReader;
import java.io.UncheckedIOException;
import java.io.Writer;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.function.Predicate;
import java.util.stream.Stream;

import static java.nio.charset.StandardCharsets.UTF_8;
import static org.openqa.selenium.json.Json.LIST_OF_MAPS_TYPE;
import static org.openqa.selenium.json.Json.MAP_TYPE;

public class NewSessionPayload implements Closeable {

  private static final Dialect DEFAULT_DIALECT = Dialect.OSS;
  private static final Predicate<String> ACCEPTED_W3C_PATTERNS = new AcceptedW3CCapabilityKeys();

  private final Json json = new Json();
  private final FileBackedOutputStream backingStore;
  private final ImmutableSet<Dialect> dialects;

  public static NewSessionPayload create(Capabilities caps) {
    // We need to convert the capabilities into a new session payload. At this point we're dealing
    // with references, so I'm Just Sure This Will Be Fine.
    return create(ImmutableMap.of("desiredCapabilities", caps.asMap()));
  }

  public static NewSessionPayload create(Map<String, ?> source) {
    String json = new Json().toJson(Require.nonNull("Payload", source));
    return new NewSessionPayload(new StringReader(json));
  }

  public static NewSessionPayload create(Reader source) {
    return new NewSessionPayload(source);
  }

  private NewSessionPayload(Reader source) {
    // Dedicate up to 10% of all RAM or 20% of available RAM (whichever is smaller) to storing this
    // payload.
    int threshold = (int) Math.min(
      Integer.MAX_VALUE,
      Math.min(
        Runtime.getRuntime().freeMemory() / 5,
        Runtime.getRuntime().maxMemory() / 10));

    backingStore = new FileBackedOutputStream(threshold);
    try (Writer writer = new OutputStreamWriter(backingStore, UTF_8)) {
      CharStreams.copy(source, writer);
    } catch (IOException e) {
      throw new UncheckedIOException(e);
    }

    ImmutableSet.Builder<Dialect> dialects = ImmutableSet.builder();
    try {
      if (getOss() != null) {
        dialects.add(Dialect.OSS);
      }
      if (getAlwaysMatch() != null || getFirstMatches() != null) {
        dialects.add(Dialect.W3C);
      }

      this.dialects = dialects.build();

      validate();
    } catch (IOException e) {
      throw new UncheckedIOException(e);
    }

    try {
      source.close();
    } catch (IOException e) {
      // Ignore
    }

  }

  private void validate() throws IOException {
    Map<String, Object> alwaysMatch = getAlwaysMatch();
    if (alwaysMatch == null) {
      alwaysMatch = ImmutableMap.of();
    }
    Map<String, Object> always = alwaysMatch;
    Collection<Map<String, Object>> firsts = getFirstMatches();
    if (firsts == null) {
      firsts = ImmutableList.of(ImmutableMap.of());
    }

    if (firsts.isEmpty()) {
      throw new IllegalArgumentException("First match w3c capabilities is zero length");
    }

    firsts.stream()
      .peek(map -> {
        Set<String> overlap = Sets.intersection(always.keySet(), map.keySet());
        if (!overlap.isEmpty()) {
          throw new IllegalArgumentException(
            "Overlapping keys between w3c always and first match capabilities: " + overlap);
        }
      })
      .map(first -> {
        Map<String, Object> toReturn = new HashMap<>();
        toReturn.putAll(always);
        toReturn.putAll(first);
        return toReturn;
      })
{'fraction_non_alphanumeric': 0.10368776288760638, 'fraction_numerical': 0.0035214711924092734, 'mean_word_length': 3.672760511882998, 'pattern_counts': {'":': 0, '<': 25, '<?xml version=': 0, '>': 29, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1218340', 'n_tokens_mistral': 2970, 'n_tokens_neox': 2891, 'n_words': 835}