// Path: src/main/java/io/cdap/plugin/salesforce/authenticator/AuthenticatorCredentials.java
// public class AuthenticatorCredentials implements Serializable {
// 
//   private final OAuthInfo oAuthInfo;
//   private final String username;
//   private final String password;
//   private final String consumerKey;
//   private final String consumerSecret;
//   private final String loginUrl;
// 
//   public AuthenticatorCredentials(OAuthInfo oAuthInfo) {
//     this(Objects.requireNonNull(oAuthInfo), null, null, null, null, null);
//   }
// 
//   public AuthenticatorCredentials(String username, String password,
//                                   String consumerKey, String consumerSecret, String loginUrl) {
//     this(null, Objects.requireNonNull(username), Objects.requireNonNull(password), Objects.requireNonNull(consumerKey),
//          Objects.requireNonNull(consumerSecret), Objects.requireNonNull(loginUrl));
//   }
// 
//   private AuthenticatorCredentials(@Nullable OAuthInfo oAuthInfo,
//                                    @Nullable String username,
//                                    @Nullable String password,
//                                    @Nullable String consumerKey,
//                                    @Nullable String consumerSecret,
//                                    @Nullable String loginUrl) {
//     this.oAuthInfo = oAuthInfo;
//     this.username = username;
//     this.password = password;
//     this.consumerKey = consumerKey;
//     this.consumerSecret = consumerSecret;
//     this.loginUrl = loginUrl;
//   }
// 
//   @Nullable
//   public OAuthInfo getOAuthInfo() {
//     return oAuthInfo;
//   }
// 
//   @Nullable
//   public String getUsername() {
//     return username;
//   }
// 
//   @Nullable
//   public String getPassword() {
//     return password;
//   }
// 
//   @Nullable
//   public String getConsumerKey() {
//     return consumerKey;
//   }
// 
//   @Nullable
//   public String getConsumerSecret() {
//     return consumerSecret;
//   }
// 
//   @Nullable
//   public String getLoginUrl() {
//     return loginUrl;
//   }
// 
//   @Override
//   public boolean equals(Object o) {
//     if (this == o) {
//       return true;
//     }
//     if (o == null || getClass() != o.getClass()) {
//       return false;
//     }
// 
//     AuthenticatorCredentials that = (AuthenticatorCredentials) o;
// 
//     return Objects.equals(username, that.username) &&
//       Objects.equals(password, that.password) &&
//       Objects.equals(consumerKey, that.consumerKey) &&
//       Objects.equals(consumerSecret, that.consumerSecret) &&
//       Objects.equals(loginUrl, that.loginUrl);
//   }
// 
//   @Override
//   public int hashCode() {
//     return Objects.hash(username, password, consumerKey, consumerSecret, loginUrl);
//   }
// }


import java.util.Set;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.sforce.soap.partner.Field;
import com.sforce.soap.partner.FieldType;
import com.sforce.soap.partner.PartnerConnection;
import com.sforce.ws.ConnectionException;
import io.cdap.cdap.api.data.schema.Schema;
import io.cdap.cdap.etl.api.FailureCollector;
import io.cdap.plugin.salesforce.authenticator.AuthenticatorCredentials;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;

  private static final Schema DEFAULT_SCHEMA = Schema.of(Schema.Type.STRING);

  private static final Pattern AVRO_NAME_START_PATTERN = Pattern.compile("^[A-Za-z_]");
  private static final Pattern AVRO_NAME_REPLACE_PATTERN = Pattern.compile("[^A-Za-z0-9_]");

  /**
   * Normalize the given field name to be compatible with
   * <a href="https://avro.apache.org/docs/current/spec.html#names">Avro names</a>
   */
  public static String normalizeAvroName(String name) {
    String finalName = name;
    // Make sure the name starts with allowed character
    if (!AVRO_NAME_START_PATTERN.matcher(name).find()) {
      finalName = "A" + finalName;
    }

    // Replace any not allowed characters with "_".
    return AVRO_NAME_REPLACE_PATTERN.matcher(finalName).replaceAll("_");
  }

  /**
   * Connects to Salesforce and obtains description of sObjects needed to determine schema field types.
   * Based on this information, creates schema for the fields used in sObject descriptor.
   *
   * @param credentials connection credentials
   * @param sObjectDescriptor sObject descriptor
   * @return CDAP schema
   * @throws ConnectionException if unable to connect to Salesforce
   */
// Path: src/main/java/io/cdap/plugin/salesforce/authenticator/AuthenticatorCredentials.java
// public class AuthenticatorCredentials implements Serializable {
// 
//   private final OAuthInfo oAuthInfo;
//   private final String username;
//   private final String password;
//   private final String consumerKey;
//   private final String consumerSecret;
//   private final String loginUrl;
// 
//   public AuthenticatorCredentials(OAuthInfo oAuthInfo) {
//     this(Objects.requireNonNull(oAuthInfo), null, null, null, null, null);
//   }
// 
//   public AuthenticatorCredentials(String username, String password,
//                                   String consumerKey, String consumerSecret, String loginUrl) {
//     this(null, Objects.requireNonNull(username), Objects.requireNonNull(password), Objects.requireNonNull(consumerKey),
//          Objects.requireNonNull(consumerSecret), Objects.requireNonNull(loginUrl));
//   }
// 
//   private AuthenticatorCredentials(@Nullable OAuthInfo oAuthInfo,
//                                    @Nullable String username,
//                                    @Nullable String password,
//                                    @Nullable String consumerKey,
//                                    @Nullable String consumerSecret,
//                                    @Nullable String loginUrl) {
//     this.oAuthInfo = oAuthInfo;
//     this.username = username;
//     this.password = password;
//     this.consumerKey = consumerKey;
//     this.consumerSecret = consumerSecret;
//     this.loginUrl = loginUrl;
//   }
// 
//   @Nullable
//   public OAuthInfo getOAuthInfo() {
//     return oAuthInfo;
//   }
// 
//   @Nullable
//   public String getUsername() {
//     return username;
//   }
// 
//   @Nullable
//   public String getPassword() {
//     return password;
//   }
// 
//   @Nullable
//   public String getConsumerKey() {
//     return consumerKey;
//   }
// 
//   @Nullable
//   public String getConsumerSecret() {
//     return consumerSecret;
//   }
// 
//   @Nullable
//   public String getLoginUrl() {
//     return loginUrl;
//   }
// 
//   @Override
//   public boolean equals(Object o) {
//     if (this == o) {
//       return true;
//     }
//     if (o == null || getClass() != o.getClass()) {
//       return false;
//     }
// 
//     AuthenticatorCredentials that = (AuthenticatorCredentials) o;
// 
//     return Objects.equals(username, that.username) &&
//       Objects.equals(password, that.password) &&
//       Objects.equals(consumerKey, that.consumerKey) &&
//       Objects.equals(consumerSecret, that.consumerSecret) &&
//       Objects.equals(loginUrl, that.loginUrl);
//   }
// 
//   @Override
//   public int hashCode() {
//     return Objects.hash(username, password, consumerKey, consumerSecret, loginUrl);
//   }
// }


// Path: src/main/java/io/cdap/plugin/salesforce/SalesforceSchemaUtil.java
import java.util.Set;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.sforce.soap.partner.Field;
import com.sforce.soap.partner.FieldType;
import com.sforce.soap.partner.PartnerConnection;
import com.sforce.ws.ConnectionException;
import io.cdap.cdap.api.data.schema.Schema;
import io.cdap.cdap.etl.api.FailureCollector;
import io.cdap.plugin.salesforce.authenticator.AuthenticatorCredentials;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;


  private static final Schema DEFAULT_SCHEMA = Schema.of(Schema.Type.STRING);

  private static final Pattern AVRO_NAME_START_PATTERN = Pattern.compile("^[A-Za-z_]");
  private static final Pattern AVRO_NAME_REPLACE_PATTERN = Pattern.compile("[^A-Za-z0-9_]");

  /**
   * Normalize the given field name to be compatible with
   * <a href="https://avro.apache.org/docs/current/spec.html#names">Avro names</a>
   */
  public static String normalizeAvroName(String name) {
    String finalName = name;
    // Make sure the name starts with allowed character
    if (!AVRO_NAME_START_PATTERN.matcher(name).find()) {
      finalName = "A" + finalName;
    }

    // Replace any not allowed characters with "_".
    return AVRO_NAME_REPLACE_PATTERN.matcher(finalName).replaceAll("_");
  }

  /**
   * Connects to Salesforce and obtains description of sObjects needed to determine schema field types.
   * Based on this information, creates schema for the fields used in sObject descriptor.
   *
   * @param credentials connection credentials
   * @param sObjectDescriptor sObject descriptor
   * @return CDAP schema
   * @throws ConnectionException if unable to connect to Salesforce
   */
  public static Schema getSchema(AuthenticatorCredentials credentials, SObjectDescriptor sObjectDescriptor)