code: ///////////////////////////////////////////////////////////////////////////////////////////////
  // checkstyle: Checks Java source code and other text files for adherence to a set of rules.
  // Copyright (C) 2001-2023 the original author or authors.
  //
  // This library is free software; you can redistribute it and/or
  // modify it under the terms of the GNU Lesser General Public
  // License as published by the Free Software Foundation; either
  // version 2.1 of the License, or (at your option) any later version.
  //
  // This library 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
  // Lesser General Public License for more details.
  //
  // You should have received a copy of the GNU Lesser General Public
  // License along with this library; if not, write to the Free Software
  // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  ///////////////////////////////////////////////////////////////////////////////////////////////
  
  package com.puppycrawl.tools.checkstyle.checks.indentation;
  
  import com.puppycrawl.tools.checkstyle.api.DetailAST;
  import com.puppycrawl.tools.checkstyle.api.TokenTypes;
  
  /**
   * Handler for try blocks.
   *
   */
  public class TryHandler extends BlockParentHandler {
  
      /**
       * Construct an instance of this handler with the given indentation check,
       * abstract syntax tree, and parent handler.
       *
       * @param indentCheck   the indentation check
       * @param ast           the abstract syntax tree
       * @param parent        the parent handler
       */
      public TryHandler(IndentationCheck indentCheck,
          DetailAST ast, AbstractExpressionHandler parent) {
          super(indentCheck, "try", ast, parent);
      }
  
      /**
       * Method to find left parenthesis of try with resources.
       *
       * @return DetailAst    left parenthesis of try with resources
       */
      private DetailAST getTryResLparen() {
          return getMainAst().getFirstChild().getFirstChild();
      }
  
      /**
       * Method to find right parenthesis of try with resources.
       *
       * @return DetailAst    right parenthesis of try with resources
       */
      private DetailAST getTryResRparen() {
          return getMainAst().getFirstChild().getLastChild();
      }
  
      @Override
      public IndentLevel getSuggestedChildIndent(AbstractExpressionHandler child) {
          final IndentLevel result;
          if (child instanceof CatchHandler
              || child instanceof FinallyHandler
              || child instanceof NewHandler
                  && isTryBlocksResourceSpecification(child)) {
              result = getIndent();
          }
          else {
              result = super.getSuggestedChildIndent(child);
          }
          return result;
      }
  
      @Override
      public void checkIndentation() {
          super.checkIndentation();
          if (getMainAst().getFirstChild().getType() == TokenTypes.RESOURCE_SPECIFICATION) {
              checkTryResParen(getTryResLparen(), "lparen");
              checkTryResParen(getTryResRparen(), "rparen");
              checkTryResources(getMainAst().getFirstChild());
          }
      }
  
      /**
       * Method to check the indentation of left paren or right paren.
       * This method itself checks whether either of these are on start of line. This method
       * takes care of line wrapping strict condition as well.
       *
       * @param parenAst      lparen or rparen ast to check
       * @param subType       name to be used in log message
       */
      private void checkTryResParen(final DetailAST parenAst,
                                      final String subType) {
          if (isOnStartOfLine(parenAst)) {
              final IndentLevel expectedIdent = new IndentLevel(getIndent(), 0,
                  getIndentCheck().getLineWrappingIndentation());
  
              checkChildIndentation(parenAst, subType, expectedIdent);
          }
      }
  
      /**
       * Method to check indentation of try resources children.
       * It takes into account forceStrictCondition value when logging violations.
       * Example of usage would include checking for try parenthesis and try resources.
       *
       * @param ast           AST to check.
       * @param subType       String representing child type.
       * @param expectedIdent Expected indent level.
       */
      private void checkChildIndentation(DetailAST ast, String subType, IndentLevel expectedIdent) {
          if (getIndentCheck().isForceStrictCondition()) {
              if (!expectedIdent.isAcceptable(expandedTabsColumnNo(ast))) {
                  logError(ast, subType, expandedTabsColumnNo(ast), expectedIdent);
              }
          }
          else {
              if (expandedTabsColumnNo(ast) < expectedIdent.getFirstIndentLevel()) {
                  logError(ast, subType, expandedTabsColumnNo(ast), expectedIdent);
              }
          }
      }
  
      /**
       * Checks indentation of resources parameters in try resources.
       *
       * @param resourcesSpecAst   Resource specification ast
       */
      private void checkTryResources(final DetailAST resourcesSpecAst) {
          final DetailAST resourcesAst = resourcesSpecAst.findFirstToken(TokenTypes.RESOURCES);
          final int indentation = getIndent().getFirstIndentLevel()
              + getIndentCheck().getLineWrappingIndentation();
          final IndentLevel expectedResourceIndent = new IndentLevel(indentation);
  
          final String subType = "resource";
  
          DetailAST resourceAst = resourcesAst.getFirstChild();
          while (resourceAst != null) {
              if (resourceAst.getType() == TokenTypes.RESOURCE) {
                  final DetailAST nextSibling;
                  if (resourceAst.getNextSibling() == null) {
                      nextSibling = getTryResRparen();
                  }
                  else {
                      nextSibling = resourceAst.getNextSibling();
                  }
                  if (isOnStartOfLine(resourceAst)) {
                      checkChildIndentation(resourceAst, subType, expectedResourceIndent);
                      checkWrappingIndentation(
                          resourceAst,
                          nextSibling,
                          getIndentCheck().getLineWrappingIndentation(),
                          expectedResourceIndent.getFirstIndentLevel(),
                          true);
                  }
                  else {
                      checkWrappingIndentation(resourceAst, nextSibling);
                  }
              }
              resourceAst = resourceAst.getNextSibling();
          }
      }
  
      /**
       * Check if the expression is resource of
       * <a href="https://docs.oracle.com/javase/specs/jls/se8/html/jls-14.html#jls-14.20.3">
       * try block</a>.
       *
       * @param expression The expression to check
       * @return if the expression provided is try block's resource specification.
       */
      private static boolean isTryBlocksResourceSpecification(AbstractExpressionHandler expression) {
          boolean isResourceSpecificationExpression = false;
  
          DetailAST ast = expression.getMainAst();
  
          while (ast.getType() != TokenTypes.LITERAL_TRY) {
              if (ast.getType() == TokenTypes.RESOURCE_SPECIFICATION) {
                  isResourceSpecificationExpression = true;
                  break;
              }
  
              ast = ast.getParent();
          }
  
          return isResourceSpecificationExpression;
      }
  
  }
  