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

com.unboundid.ldap.sdk.ToCodeArgHelper Maven / Gradle / Ivy

Go to download

The UnboundID LDAP SDK for Java is a fast, comprehensive, and easy-to-use Java API for communicating with LDAP directory servers and performing related tasks like reading and writing LDIF, encoding and decoding data using base64 and ASN.1 BER, and performing secure communication. This package contains the Standard Edition of the LDAP SDK, which is a complete, general-purpose library for communicating with LDAPv3 directory servers.

There is a newer version: 7.0.1
Show newest version
/*
 * Copyright 2015-2022 Ping Identity Corporation
 * All Rights Reserved.
 */
/*
 * Copyright 2015-2022 Ping Identity Corporation
 *
 * 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 (C) 2015-2022 Ping Identity Corporation
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License (GPLv2 only)
 * or the terms of the GNU Lesser General Public License (LGPLv2.1 only)
 * as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, see .
 */
package com.unboundid.ldap.sdk;


import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;

import com.unboundid.asn1.ASN1Constants;
import com.unboundid.asn1.ASN1OctetString;
import com.unboundid.util.InternalUseOnly;
import com.unboundid.util.NotNull;
import com.unboundid.util.Nullable;
import com.unboundid.util.StaticUtils;
import com.unboundid.util.ThreadSafety;
import com.unboundid.util.ThreadSafetyLevel;



/**
 * This class provides a data structure that can be used to represent an
 * argument provided to a method or constructor.  It may also be used to
 * represent an element in an array.
 */
@InternalUseOnly()
@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE)
public final class ToCodeArgHelper
{
  // The lines that comprise the string representations to use for the
  // argument, with all appropriate formatting applied.  The first line will
  // not be indented.  If there are multiple lines, then subsequent lines may be
  // indented relative to the first line.
  @NotNull private final List argStrings;

  // An optional comment that may help clarify the argument.
  @Nullable private final String comment;



  /**
   * Creates a new argument with the provided information.
   *
   * @param  argString  The string representation to use for the argument, with
   *                    all appropriate formatting applied.  It must not be
   *                    {@code null}.
   * @param  comment    A comment that may help clarify the argument.  It may
   *                    be {@code null} if there should be no comment.
   */
  private ToCodeArgHelper(@NotNull final String argString,
                          @Nullable final String comment)
  {
    argStrings = Collections.singletonList(argString);
    this.comment = comment;
  }



  /**
   * Creates a new argument with the provided information.
   *
   * @param  argStrings  The list of strings to use for the argument, with
   *                     all appropriate formatting applied.  It must not be
   *                     {@code null} or empty.
   * @param  comment     A comment that may help clarify the argument.  It may
   *                     be {@code null} if there should be no comment.
   */
  private ToCodeArgHelper(@NotNull final List argStrings,
                          @Nullable final String comment)
  {
    this.argStrings = argStrings;
    this.comment = comment;
  }



  /**
   * Creates an argument for a byte literal value.  It will be represented as
   * a hexadecimal literal (starting with "0x"), and will be prefixed by
   * "(byte)" if necessary.
   *
   * @param  b               The byte value for the argument.
   * @param  includeComment  Indicates whether to attempt to generate a comment
   *                         for the byte.  If this is {@code true} and the byte
   *                         represents a printable ASCII character, then the
   *                         generated comment will consist of that character
   *                         enclosed in quotation marks.
   *
   * @return  The argument that was created.
   */
  @NotNull()
  public static ToCodeArgHelper createByte(final byte b,
                                           final boolean includeComment)
  {
    String s = "0x" + StaticUtils.toHex(b);
    if ((b & 0x80) != 0x00)
    {
      s = "(byte) " + s;
    }

    final String comment;
    if (includeComment && StaticUtils.isPrintableString(new byte[] { b }))
    {
      comment = "\"" + ((char) b) + '"';
    }
    else
    {
      comment = null;
    }

    return new ToCodeArgHelper(s, comment);
  }



  /**
   * Creates an argument for a byte array.  If the array is non-empty, then it
   * will be represented with multiple lines, with the first line being
   * "new byte[]", the second "{", then the hexadecimal literal representation
   * of each byte on its own line, and then a last line of "}".
   *
   * @param  b                The byte array value for the argument.  It may be
   *                          {@code null}.
   * @param  includeComments  Indicates whether to attempt to generate a comment
   *                          for each byte in the array.  If this is
   *                          {@code true}, then all bytes that represent
   *                          printable characters will have a generated comment
   *                          consisting of that character enclosed in quotation
   *                          marks.
   * @param  comment          A comment to use for the overall array.  It may be
   *                          {@code null} if there should be no comment.
   *
   * @return  The argument that was created.
   */
  @NotNull()
  public static ToCodeArgHelper createByteArray(@Nullable final byte[] b,
                                                final boolean includeComments,
                                                @Nullable final String comment)
  {
    return new ToCodeArgHelper(getByteArrayLines(b, includeComments), comment);
  }



  /**
   * Retrieves the lines that comprise the string representation of the provided
   * byte array.  If the array is non-empty, then it will be represented with
   * multiple lines, with the first line being "new byte[]", the second "{",
   * then the hexadecimal literal representation of each byte on its own line,
   * and then a last line of "}".
   *
   * @param  b                The byte array value for the argument.  It may be
   *                          {@code null}.
   * @param  includeComments  Indicates whether to attempt to generate a comment
   *                          for each byte in the array.  If this is
   *                          {@code true}, then all bytes that represent
   *                          printable characters will have a generated comment
   *                          consisting of that character enclosed in quotation
   *                          marks.
   *
   * @return  The list of lines that comprise the string representation of the
   *          provided byte array.
   */
  @NotNull()
  private static List getByteArrayLines(@Nullable final byte[] b,
                                                final boolean includeComments)
  {
    if (b == null)
    {
      return Collections.singletonList("(byte[]) null");
    }

    if (b.length == 0)
    {
      return Collections.singletonList("new byte[0]");
    }

    final ArrayList lines = new ArrayList<>(3 + b.length);
    lines.add("new byte[]");
    lines.add("{");

    final byte[] oneByteString = new byte[1];
    final StringBuilder buffer = new StringBuilder();
    for (int i=0; i < b.length; i++)
    {
      buffer.setLength(0);
      buffer.append("  ");

      if ((b[i] & 0x80) != 0x00)
      {
        buffer.append("(byte) 0x");
        StaticUtils.toHex(b[i], buffer);
        if (i < (b.length-1))
        {
          buffer.append(',');
        }
      }
      else
      {
        buffer.append("0x");
        StaticUtils.toHex(b[i], buffer);
        if (i < (b.length-1))
        {
          buffer.append(',');
        }

        oneByteString[0] = b[i];
        if (includeComments && StaticUtils.isPrintableString(oneByteString))
        {
          buffer.append(" // \"");
          buffer.append((char) b[i]);
          buffer.append('"');
        }
      }
      lines.add(buffer.toString());
    }

    lines.add("}");
    return lines;
  }



  /**
   * Creates an argument for a boolean literal value.
   *
   * @param  b          The boolean value for the argument.
   * @param  comment    A comment that may help clarify the argument.  It may
   *                    be {@code null} if there should be no comment.
   *
   * @return  The argument that was created.
   */
  @NotNull()
  public static ToCodeArgHelper createBoolean(final boolean b,
                                              @Nullable final String comment)
  {
    return new ToCodeArgHelper((b ? "true" : "false"), comment);
  }



  /**
   * Creates an argument for a literal value of any integer data type.
   *
   * @param  i          The integer value for the argument.
   * @param  comment    A comment that may help clarify the argument.  It may
   *                    be {@code null} if there should be no comment.
   *
   * @return  The argument that was created.
   */
  @NotNull()
  public static ToCodeArgHelper createInteger(final long i,
                                              @Nullable final String comment)
  {
    String valueString = String.valueOf(i);
    if ((i > Integer.MAX_VALUE) || (i < Integer.MIN_VALUE))
    {
      valueString += 'L';
    }

    return new ToCodeArgHelper(valueString, comment);
  }



  /**
   * Creates an argument for a String literal value.  If it is {@code null},
   * then it will be represented as "(String) null" without the quotation marks.
   * If it is non-{@code null}, then it will be surrounded by quotation marks
   * and any embedded quotes will be escaped.
   *
   * @param  s          The string value for the argument.  It may be
   *                    {@code null}.
   * @param  comment    A comment that may help clarify the argument.  It may
   *                    be {@code null} if there should be no comment.
   *
   * @return  The argument that was created.
   */
  @NotNull()
  public static ToCodeArgHelper createString(@Nullable final String s,
                                             @Nullable final String comment)
  {
    if (s == null)
    {
      return new ToCodeArgHelper("(String) null", comment);
    }
    else
    {
      return new ToCodeArgHelper('"' + s.replace("\"", "\\\"") + '"', comment);
    }
  }



  /**
   * Creates an argument for an ASN.1 octet string value.
   *
   * @param  s          The ASN.1 octet string value for the argument.  It may
   *                    be {@code null}.
   * @param  comment    A comment that may help clarify the argument.  It may
   *                    be {@code null} if there should be no comment.
   *
   * @return  The argument that was created.
   */
  @NotNull()
  public static ToCodeArgHelper createASN1OctetString(
                                     @Nullable final ASN1OctetString s,
                                     @Nullable final String comment)
  {
    if (s == null)
    {
      return new ToCodeArgHelper("(ASN1OctetString) null", comment);
    }
    else
    {
      final ArrayList lines = new ArrayList<>(10);

      final boolean universalType =
           (s.getType() == ASN1Constants.UNIVERSAL_OCTET_STRING_TYPE);

      final byte[] valueBytes = s.getValue();
      if (valueBytes.length == 0)
      {
        if (universalType)
        {
          lines.add("new ASN1OctetString()");
        }
        else
        {
          lines.add("new ASN1OctetString(");
          lines.add("     (byte) 0x" + StaticUtils.toHex(s.getType()) + ')');
        }
      }
      else
      {
        lines.add("new ASN1OctetString(");
        if (! universalType)
        {
          lines.add("     (byte) 0x" + StaticUtils.toHex(s.getType()) + ',');
        }

        final boolean isPrintable = StaticUtils.isPrintableString(valueBytes);
        if (isPrintable)
        {
          lines.add("     \"" + s.stringValue() + "\")");
        }
        else
        {
          final StringBuilder line = new StringBuilder();
          final Iterator iterator =
               getByteArrayLines(valueBytes, true).iterator();
          while (iterator.hasNext())
          {
            line.setLength(0);
            line.append("     ");
            line.append(iterator.next());

            if (! iterator.hasNext())
            {
              line.append(')');
            }

            lines.add(line.toString());
          }
        }
      }

      return new ToCodeArgHelper(lines, comment);
    }
  }



  /**
   * Creates an argument for a modification type value.
   *
   * @param  t          The modification type value for the argument.  It may
   *                    be {@code null}.
   * @param  comment    A comment that may help clarify the argument.  It may
   *                    be {@code null} if there should be no comment.
   *
   * @return  The argument that was created.
   */
  @NotNull()
  public static ToCodeArgHelper createModificationType(
                                     @Nullable final ModificationType t,
                                     @Nullable final String comment)
  {
    if (t == null)
    {
      return new ToCodeArgHelper("(ModificationType) null", comment);
    }

    final ModificationType definedType =
         ModificationType.definedValueOf(t.intValue());
    if (definedType == null)
    {
      return new ToCodeArgHelper(
           "ModificationType.valueOf(" + t.intValue() + ')', comment);
    }
    else
    {
      return new ToCodeArgHelper("ModificationType." + definedType.getName(),
           comment);
    }
  }



  /**
   * Creates an argument for a search scope value.
   *
   * @param  s          The search scope value for the argument.  It may be
   *                    {@code null}.
   * @param  comment    A comment that may help clarify the argument.  It may
   *                    be {@code null} if there should be no comment.
   *
   * @return  The argument that was created.
   */
  @NotNull()
  public static ToCodeArgHelper createScope(@Nullable final SearchScope s,
                                            @Nullable final String comment)
  {
    if (s == null)
    {
      return new ToCodeArgHelper("(SearchScope) null", comment);
    }

    final SearchScope definedScope = SearchScope.definedValueOf(s.intValue());
    if (definedScope == null)
    {
      return new ToCodeArgHelper("SearchScope.valueOf(" + s.intValue() + ')',
           comment);
    }
    else
    {
      return new ToCodeArgHelper("SearchScope." + definedScope.getName(),
           comment);
    }
  }



  /**
   * Creates an argument for a dereference policy value.
   *
   * @param  p          The dereference policy value for the argument.  It may
   *                    be {@code null}.
   * @param  comment    A comment that may help clarify the argument.  It may
   *                    be {@code null} if there should be no comment.
   *
   * @return  The argument that was created.
   */
  @NotNull()
  public static ToCodeArgHelper createDerefPolicy(
              @Nullable final DereferencePolicy p,
              @Nullable final String comment)
  {
    if (p == null)
    {
      return new ToCodeArgHelper("(DereferencePolicy) null", comment);
    }

    final DereferencePolicy definedPolicy =
         DereferencePolicy.definedValueOf(p.intValue());
    if (definedPolicy == null)
    {
      return new ToCodeArgHelper(
           "DereferencePolicy.valueOf(" + p.intValue() + ')', comment);
    }
    else
    {
      return new ToCodeArgHelper("DereferencePolicy." + definedPolicy.getName(),
           comment);
    }
  }



  /**
   * Creates an argument for an attribute.
   *
   * @param  a          The attribute value for the argument.  It may be
   *                    {@code null}.
   * @param  comment    A comment that may help clarify the argument.  It may
   *                    be {@code null} if there should be no comment.
   *
   * @return  The argument that was created.
   */
  @NotNull()
  public static ToCodeArgHelper createAttribute(@Nullable final Attribute a,
                                                @Nullable final String comment)
  {
    if (a == null)
    {
      return new ToCodeArgHelper("(Attribute) null", comment);
    }

    if (! a.hasValue())
    {
      return new ToCodeArgHelper(
           "new Attribute(\"" + a.getName() + "\")",
           comment);
    }

    final ASN1OctetString[] rawValues = a.getRawValues();
    final ArrayList lines = new ArrayList<>(2 + rawValues.length);
    lines.add("new Attribute(");
    lines.add("     \"" + a.getName() + "\",");

    // FIXME -- Should we make any attempt to use a matching rule here?

    if (StaticUtils.isSensitiveToCodeAttribute(a.getName()))
    {
      if (rawValues.length == 1)
      {
        lines.add("     \"---redacted-value---\")");
      }
      else
      {
        for (int i=1; i <= rawValues.length; i++)
        {
          final String suffix;
          if (i == rawValues.length)
          {
            suffix = ")";
          }
          else
          {
            suffix = ",";
          }

          lines.add("     \"---redacted-value-" + i + "---\"" + suffix);
        }
      }
    }
    else
    {
      if (allPrintable(rawValues))
      {
        for (int i=0; i < rawValues.length; i++)
        {
          final String suffix;
          if (i == (rawValues.length-1))
          {
            suffix = ")";
          }
          else
          {
            suffix = ",";
          }

          lines.add("     \"" +
               rawValues[i].stringValue().replace("\"", "\\\"") + '"' + suffix);
        }
      }
      else
      {
        for (int i=0; i < rawValues.length; i++)
        {
          final String suffix;
          if (i < (rawValues.length-1))
          {
            suffix = ",";
          }
          else
          {
            suffix = ")";
          }

          final Iterator byteArrayLineIterator =
               getByteArrayLines(rawValues[i].getValue(), true).iterator();
          while (byteArrayLineIterator.hasNext())
          {
            final String s = byteArrayLineIterator.next();
            if (byteArrayLineIterator.hasNext())
            {
              lines.add("     " + s);
            }
            else
            {
              lines.add("     " + s + suffix);
            }
          }
        }
      }
    }

    return new ToCodeArgHelper(lines, comment);
  }



  /**
   * Creates an argument for a modification.
   *
   * @param  m          The modification value for the argument.  It may be
   *                    {@code null}.
   * @param  comment    A comment that may help clarify the argument.  It may
   *                    be {@code null} if there should be no comment.
   *
   * @return  The argument that was created.
   */
  @NotNull()
  public static ToCodeArgHelper createModification(
                                     @Nullable final Modification m,
                                     @Nullable final String comment)
  {
    if (m == null)
    {
      return new ToCodeArgHelper("(Modification) null", comment);
    }

    final ASN1OctetString[] rawValues = m.getRawValues();
    final ArrayList lines = new ArrayList<>(3 + rawValues.length);

    lines.add("new Modification(");
    lines.add("     " +  createModificationType(m.getModificationType(),
         null).getLines().get(0) + ',');

    if (rawValues.length == 0)
    {
      lines.add("     \"" + m.getAttributeName() + "\")");
    }
    else
    {
      lines.add("     \"" + m.getAttributeName() + "\",");

      if (StaticUtils.isSensitiveToCodeAttribute(m.getAttributeName()))
      {
        if (rawValues.length == 1)
        {
          lines.add("     \"---redacted-value---\")");
        }
        else
        {
          for (int i=1; i <= rawValues.length; i++)
          {
            final String suffix;
            if (i == rawValues.length)
            {
              suffix = ")";
            }
            else
            {
              suffix = ",";
            }

            lines.add("     \"---redacted-value-" + i + "---\"" + suffix);
          }
        }
      }
      else if (allPrintable(rawValues))
      {
        for (int i=0; i < rawValues.length; i++)
        {
          final String suffix;
          if (i == (rawValues.length-1))
          {
            suffix = ")";
          }
          else
          {
            suffix = ",";
          }

          lines.add("     \"" +
               rawValues[i].stringValue().replace("\"", "\\\"") + '"' + suffix);
        }
      }
      else
      {
        for (int i=0; i < rawValues.length; i++)
        {
          final String suffix;
          if (i == (rawValues.length-1))
          {
            suffix = ")";
          }
          else
          {
            suffix = ",";
          }

          final Iterator byteArrayLineIterator =
               getByteArrayLines(rawValues[i].getValue(), true).iterator();
          while (byteArrayLineIterator.hasNext())
          {
            final String s = byteArrayLineIterator.next();
            if (byteArrayLineIterator.hasNext())
            {
              lines.add("     " + s);
            }
            else
            {
              lines.add("     " + s + suffix);
            }
          }
        }
      }
    }

    return new ToCodeArgHelper(lines, comment);
  }



  /**
   * Creates an argument for a search filter.
   *
   * @param  f          The filter value for the argument.  It may be
   *                    {@code null}.
   * @param  comment    A comment that may help clarify the argument.  It may
   *                    be {@code null} if there should be no comment.
   *
   * @return  The argument that was created.
   */
  @NotNull()
  public static ToCodeArgHelper createFilter(@Nullable final Filter f,
                                             @Nullable final String comment)
  {
    if (f == null)
    {
      return new ToCodeArgHelper("(Filter) null", comment);
    }

    final ArrayList lines = new ArrayList<>(10);
    addFilterLines(lines, f, "", "");

    return new ToCodeArgHelper(lines, comment);
  }



  /**
   * Updates the provided list with the appropriate lines for the provided
   * filter.
   *
   * @param  lines   The list to be updated.  It must not be {@code null}.
   * @param  f       The filter whose lines should be added to the list.
   * @param  indent  The indent that should be used at the beginning of each
   *                 line.  It must not be {@code null} but may be empty.
   * @param  suffix  The suffix to append to the last line.  It must not be
   *                 {@code null} but may be empty.
   */
  private static void addFilterLines(@NotNull final List lines,
                                     @NotNull final Filter f,
                                     @NotNull final String indent,
                                     @NotNull final String suffix)
  {
    final String nestedIndent = indent + "     ";

    switch (f.getFilterType())
    {
      case Filter.FILTER_TYPE_AND:
      case Filter.FILTER_TYPE_OR:
        final Filter[] components = f.getComponents();
        if (f.getFilterType() == Filter.FILTER_TYPE_AND)
        {
          if (components.length == 0)
          {
            lines.add(indent + "Filter.createANDFilter()" + suffix);
            return;
          }
          else
          {
            lines.add(indent + "Filter.createANDFilter(");
          }
        }
        else
        {
          if (components.length == 0)
          {
            lines.add(indent + "Filter.createORFilter()" + suffix);
            return;
          }
          else
          {
            lines.add(indent + "Filter.createORFilter(");
          }
        }

        for (int i = 0; i < components.length; i++)
        {
          if (i == (components.length - 1))
          {
            addFilterLines(lines, components[i], nestedIndent, ')' + suffix);
          }
          else
          {
            addFilterLines(lines, components[i], nestedIndent, ",");
          }
        }
        break;


      case Filter.FILTER_TYPE_NOT:
        lines.add(indent + "Filter.createNOTFilter(");
        addFilterLines(lines, f.getNOTComponent(), nestedIndent, ')' + suffix);
        break;


      case Filter.FILTER_TYPE_PRESENCE:
        lines.add(indent + "Filter.createPresenceFilter(");
        lines.add(nestedIndent + '"' + f.getAttributeName() + "\")" + suffix);
        break;


      case Filter.FILTER_TYPE_EQUALITY:
      case Filter.FILTER_TYPE_GREATER_OR_EQUAL:
      case Filter.FILTER_TYPE_LESS_OR_EQUAL:
      case Filter.FILTER_TYPE_APPROXIMATE_MATCH:
        switch (f.getFilterType())
        {
          case Filter.FILTER_TYPE_EQUALITY:
            lines.add(indent + "Filter.createEqualityFilter(");
            break;
          case Filter.FILTER_TYPE_GREATER_OR_EQUAL:
            lines.add(indent + "Filter.createGreaterOrEqualFilter(");
            break;
          case Filter.FILTER_TYPE_LESS_OR_EQUAL:
            lines.add(indent + "Filter.createLessOrEqualFilter(");
            break;
          case Filter.FILTER_TYPE_APPROXIMATE_MATCH:
            lines.add(indent + "Filter.createApproximateMatchFilter(");
            break;
        }

        lines.add(nestedIndent + '"' + f.getAttributeName() + "\",");
        if (StaticUtils.isSensitiveToCodeAttribute(f.getAttributeName()))
        {
          lines.add(nestedIndent + "\"---redacted-value---\")" + suffix);
        }
        else if (StaticUtils.isPrintableString(f.getAssertionValueBytes()))
        {
          lines.add(nestedIndent + '"' + f.getAssertionValue() + "\")" +
               suffix);
        }
        else
        {
          final Iterator iterator =
               getByteArrayLines(f.getAssertionValueBytes(), true).iterator();
          while (iterator.hasNext())
          {
            final String line = iterator.next();
            if (iterator.hasNext())
            {
              lines.add(nestedIndent + line);
            }
            else
            {
              lines.add(nestedIndent + line + ')' + suffix);
            }
          }
        }
        break;


      case Filter.FILTER_TYPE_SUBSTRING:
        lines.add(indent + "Filter.createSubstringFilter(");
        lines.add(nestedIndent + '"' + f.getAttributeName() + "\",");

        if (StaticUtils.isSensitiveToCodeAttribute(f.getAttributeName()))
        {
          if (f.getRawSubInitialValue() == null)
          {
            lines.add(nestedIndent + "null,");
          }
          else
          {
            lines.add(nestedIndent + "\"---redacted-subInitial---\",");
          }

          if (f.getRawSubAnyValues().length == 0)
          {
            lines.add(nestedIndent + "null,");
          }
          else if (f.getRawSubAnyValues().length == 1)
          {
            lines.add(nestedIndent + "new String[]");
            lines.add(nestedIndent + '{');
            lines.add(nestedIndent + "  \"---redacted-subAny---\"");
            lines.add(nestedIndent + "},");
          }
          else
          {
            lines.add(nestedIndent + "new String[]");
            lines.add(nestedIndent + '{');
            for (int i=1; i <= f.getRawSubAnyValues().length; i++)
            {
              final String comma =
                   (i == f.getRawSubAnyValues().length) ? "" : ",";
              lines.add(nestedIndent + "  \"---redacted-subAny-" + i +
                   "---\"" + comma);
            }
            lines.add(nestedIndent + "},");
          }

          if (f.getRawSubFinalValue() == null)
          {
            lines.add(nestedIndent + "null)" + suffix);
          }
          else
          {
            lines.add(nestedIndent + "\"---redacted-subFinal---\")" + suffix);
          }
        }
        else
        {
          boolean allPrintable =
               ((f.getRawSubInitialValue() == null) ||
                StaticUtils.isPrintableString(f.getSubInitialBytes())) &&
               ((f.getRawSubFinalValue() == null) ||
                StaticUtils.isPrintableString(f.getSubFinalBytes()));
          if (allPrintable && (f.getRawSubAnyValues().length > 0))
          {
            for (final byte[] b : f.getSubAnyBytes())
            {
              if (! StaticUtils.isPrintableString(b))
              {
                allPrintable = false;
                break;
              }
            }
          }

          if (f.getRawSubInitialValue() == null)
          {
            lines.add(nestedIndent + "null,");
          }
          else if (allPrintable)
          {
            lines.add(nestedIndent + '"' +
                 f.getSubInitialString().replace("\"", "\\\"") + "\",");
          }
          else
          {
            final Iterator iterator =
                 getByteArrayLines(f.getSubInitialBytes(), true).iterator();
            while (iterator.hasNext())
            {
              final String line = iterator.next();
              if (iterator.hasNext())
              {
                lines.add(nestedIndent + line);
              }
              else
              {
                lines.add(nestedIndent + line + ',');
              }
            }
          }

          if (f.getRawSubAnyValues().length == 0)
          {
            lines.add(nestedIndent + "null,");
          }
          else if (allPrintable)
          {
            lines.add(nestedIndent + "new String[]");
            lines.add(nestedIndent + '{');

            final String[] subAnyStrings = f.getSubAnyStrings();
            for (int i=0; i < subAnyStrings.length; i++)
            {
              final String comma;
              if (i == (subAnyStrings.length-1))
              {
                comma = "";
              }
              else
              {
                comma = ",";
              }
              lines.add(nestedIndent + "  \"" + subAnyStrings[i] + '"' + comma);
            }

            lines.add(nestedIndent + "},");
          }
          else
          {
            lines.add(nestedIndent + "new byte[][]");
            lines.add(nestedIndent + '{');

            final byte[][] subAnyBytes = f.getSubAnyBytes();
            for (int i=0; i < subAnyBytes.length; i++)
            {
              final String comma;
              if (i == (subAnyBytes.length-1))
              {
                comma = "";
              }
              else
              {
                comma = ",";
              }

              final Iterator iterator =
                   getByteArrayLines(subAnyBytes[i], true).iterator();
              while (iterator.hasNext())
              {
                final String line = iterator.next();
                if (iterator.hasNext())
                {
                  lines.add(nestedIndent + "  " + line);
                }
                else
                {
                  lines.add(nestedIndent + "  " + line + comma);
                }
              }
            }

            lines.add(nestedIndent + "},");
          }

          if (f.getRawSubFinalValue() == null)
          {
            lines.add(nestedIndent + "null)" + suffix);
          }
          else if (allPrintable)
          {
            lines.add(nestedIndent + '"' +
                 f.getSubFinalString().replace("\"", "\\\"") + "\")" + suffix);
          }
          else
          {
            final Iterator iterator =
                 getByteArrayLines(f.getSubFinalBytes(), true).iterator();
            while (iterator.hasNext())
            {
              final String line = iterator.next();
              if (iterator.hasNext())
              {
                lines.add(nestedIndent + line);
              }
              else
              {
                lines.add(nestedIndent + line + ')' + suffix);
              }
            }
          }
        }
        break;


      case Filter.FILTER_TYPE_EXTENSIBLE_MATCH:
        lines.add(indent + "Filter.createExtensibleMatchFilter(");

        if (f.getAttributeName() == null)
        {
          lines.add(nestedIndent + "null,");
        }
        else
        {
          lines.add(nestedIndent + '"' + f.getAttributeName() + "\",");
        }

        if (f.getMatchingRuleID() == null)
        {
          lines.add(nestedIndent + "null,");
        }
        else
        {
          lines.add(nestedIndent + '"' + f.getMatchingRuleID() + "\",");
        }

        lines.add(nestedIndent + f.getDNAttributes() + ',');

        if ((f.getAttributeName() != null) &&
            StaticUtils.isSensitiveToCodeAttribute(f.getAttributeName()))
        {
          lines.add(nestedIndent + "\"---redacted-value---\")" + suffix);
        }
        else if (StaticUtils.isPrintableString(f.getAssertionValueBytes()))
        {
          lines.add(nestedIndent + '"' +
               f.getAssertionValue().replace("\"", "\\\"") + "\")" + suffix);
        }
        else
        {
          final Iterator iterator =
               getByteArrayLines(f.getAssertionValueBytes(), true).iterator();
          while (iterator.hasNext())
          {
            final String line = iterator.next();
            if (iterator.hasNext())
            {
              lines.add(nestedIndent + line);
            }
            else
            {
              lines.add(nestedIndent + line + ')' + suffix);
            }
          }
        }
        break;
    }
  }



  /**
   * Creates an argument for a control.
   *
   * @param  c          The control value for the argument.  It may be
   *                    {@code null}.
   * @param  comment    A comment that may help clarify the argument.  It may
   *                    be {@code null} if there should be no comment.
   *
   * @return  The argument that was created.
   */
  @NotNull()
  public static ToCodeArgHelper createControl(@Nullable final Control c,
                                              @Nullable final String comment)
  {
    if (c == null)
    {
      return new ToCodeArgHelper("(Control) null", comment);
    }

    // NYI -- Figure out what type of control it is and create more specific
    // code for that type of control if possible.  If not, then use the
    // following generic code:

    final ArrayList lines = new ArrayList<>(10);
    lines.add("new Control(");
    lines.add("     \"" + c.getOID() + "\",");

    if (c.hasValue())
    {
      lines.add("     " + c.isCritical() + ',');

      final List valueLines =
           createASN1OctetString(c.getValue(), null).argStrings;
      final Iterator valueLineIterator = valueLines.iterator();
      while (valueLineIterator.hasNext())
      {
        final String s = valueLineIterator.next();
        if (valueLineIterator.hasNext())
        {
          lines.add("     " + s);
        }
        else
        {
          lines.add("     " + s + ')');
        }
      }
    }
    else
    {
      lines.add("     " + c.isCritical() + ')');
    }

    return new ToCodeArgHelper(lines, comment);
  }



  /**
   * Creates an argument for an array of controls.
   *
   * @param  c          The control value for the argument.  It may be
   *                    {@code null}.
   * @param  comment    A comment that may help clarify the argument.  It may
   *                    be {@code null} if there should be no comment.
   *
   * @return  The argument that was created.
   */
  @NotNull()
  public static ToCodeArgHelper createControlArray(@Nullable final Control[] c,
                                     @Nullable final String comment)
  {
    if (c == null)
    {
      return new ToCodeArgHelper("(Control[]) null", comment);
    }

    if (c.length == 0)
    {
      return new ToCodeArgHelper("new Control[0]", comment);
    }

    final ArrayList lines = new ArrayList<>(10);
    lines.add("new Control[]");
    lines.add("{");

    for (int i=0; i < c.length; i++)
    {
      final ToCodeArgHelper h = createControl(c[i], null);
      final List hLines = h.argStrings;

      final Iterator iterator = hLines.iterator();
      while (iterator.hasNext())
      {
        final String line = iterator.next();
        if ((! iterator.hasNext()) && (i < (c.length-1)))
        {

          lines.add("  " + line + ',');
        }
        else
        {
          lines.add("  " + line);
        }
      }
    }

    lines.add("}");

    return new ToCodeArgHelper(lines, comment);
  }



  /**
   * Creates an argument that will use exactly the provided representation.
   *
   * @param  s          The raw string representation for the argument.
   * @param  comment    A comment that may help clarify the argument.  It may
   *                    be {@code null} if there should be no comment.
   *
   * @return  The argument that was created.
   */
  @NotNull()
  public static ToCodeArgHelper createRaw(@NotNull final String s,
                                          @Nullable final String comment)
  {
    return new ToCodeArgHelper(s, comment);
  }



  /**
   * Creates an argument that will use exactly the provided representation.
   *
   * @param  s          The list of lines comprising the raw string
   *                    representation for the argument.  If any indent is
   *                    needed for subsequent lines, it should be included in
   *                    the raw values.
   * @param  comment    A comment that may help clarify the argument.  It may
   *                    be {@code null} if there should be no comment.
   *
   * @return  The argument that was created.
   */
  @NotNull()
  public static ToCodeArgHelper createRaw(@NotNull final List s,
                                          @Nullable final String comment)
  {
    return new ToCodeArgHelper(s, comment);
  }



  /**
   * Indicates whether all of the provided values represent printable strings.
   *
   * @param  values  The values for which to make the determination.
   *
   * @return  {@code true} if all of the values represent printable strings, or
   *          {@code false} if not.
   */
  private static boolean allPrintable(@NotNull final ASN1OctetString... values)
  {
    for (final ASN1OctetString s : values)
    {
      if (! StaticUtils.isPrintableString(s.getValue()))
      {
        return false;
      }
    }

    return true;
  }



  /**
   * Retrieves the list of lines comprising the string representation for this
   * argument.  All appropriate formatting will be applied.  There will not be
   * any indent used for the first line.  If there are multiple lines, then
   * subsequent lines may be indented relative to the first line, and any
   * necessary separator will be used at the end of all lines except the last.
   *
   * @return  The list of lines comprising the string representation for this
   *          argument.  At least one line will be included.
   */
  @NotNull()
  public List getLines()
  {
    return argStrings;
  }



  /**
   * Retrieves the comment for this argument, if any.
   *
   * @return  The comment for this argument, or {@code null} if there is none.
   */
  @Nullable()
  public String getComment()
  {
    return comment;
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy