# LegacyErrorException.java

    /*
    ** Module   : LegacyErrorException.java
    ** Abstract : represents a thrown legacy OO error.
    **
    ** Copyright (c) 2019-2025, Golden Code Development Corporation.
    **
    ** -#- -I- --Date-- ---------------------------------------Description----------------------------------------
    ** 001 CA  20190219 First version.
    ** 002 CA  20190628 Save the legacy error instance, as it may be needed when interpreting this
    **                  error from a different context.
    ** 003 CA  20200324 More fixes related to OO-like error processing via AppError.
    ** 004 CA  20220208 Added support for legacy OO errors thrown from a remote appserver call, via RETURN ERROR.
    **     CA  20220531 Fixed propagation of explicit legacy exceptions - they must propagate if the block has
    **                  ON ERROR UNDO, THROW or if they are explicitly throw by the application.
    ** 005 VVT 20231215 Added a LegacyErrorException constructor, which does not modify call stack in its
    **                  argument. See #8126.
    ** 006 GBB 20240318 "Legacy error"  is not an actual OE error msg, instead pass null and leave it to the
    **                  error handler.
    ** 007 CA  20240708 A block needs to be aware if a RETURN ERROR or UNDO, THROW was used for exit, as this will
    **                  make a FINALLY block to act as if it executes in silent mode.
    ** 008 AP  20250121 populateCallStack() call removed: stack is now populated at the ProError object
    **                  creation time. See discussion around #3827-527. Removed unused constructor.
    */

    /*
    ** This program is free software: you can redistribute it and/or modify
    ** it under the terms of the GNU Affero General Public License as
    ** published by the Free Software Foundation, either version 3 of the
    ** License, or (at your option) any later version.
    **
    ** 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 Affero General Public License for more details.
    **
    ** You may find a copy of the GNU Affero GPL version 3 at the following
    ** location: https://www.gnu.org/licenses/agpl-3.0.en.html
    **
    ** Additional terms under GNU Affero GPL version 3 section 7:
    **
    **   Under Section 7 of the GNU Affero GPL version 3, the following additional
    **   terms apply to the works covered under the License.  These additional terms
    **   are non-permissive additional terms allowed under Section 7 of the GNU
    **   Affero GPL version 3 and may not be removed by you.
    **
    **   0. Attribution Requirement.
    **
    **     You must preserve all legal notices or author attributions in the covered
    **     work or Appropriate Legal Notices displayed by works containing the covered
    **     work.  You may not remove from the covered work any author or developer
    **     credit already included within the covered work.
    **
    **   1. No License To Use Trademarks.
    **
    **     This license does not grant any license or rights to use the trademarks
    **     Golden Code, FWD, any Golden Code or FWD logo, or any other trademarks
    **     of Golden Code Development Corporation. You are not authorized to use the
    **     name Golden Code, FWD, or the names of any author or contributor, for
    **     publicity purposes without written authorization.
    **
    **   2. No Misrepresentation of Affiliation.
    **
    **     You may not represent yourself as Golden Code Development Corporation or FWD.
    **
    **     You may not represent yourself for publicity purposes as associated with
    **     Golden Code Development Corporation, FWD, or any author or contributor to
    **     the covered work, without written authorization.
    **
    **   3. No Misrepresentation of Source or Origin.
    **
    **     You may not represent the covered work as solely your work.  All modified
    **     versions of the covered work must be marked in a reasonable way to make it
    **     clear that the modified work is not originating from Golden Code Development
    **     Corporation or FWD.  All modified versions must contain the notices of
    **     attribution required in this license.
    */

    package com.goldencode.p2j.util;

    import com.goldencode.p2j.oo.lang.*;

    /**
     * An ERROR condition which acts like a throw OO error in 4GL.
     */
    public class LegacyErrorException
    extends ErrorConditionException
    {
       /**
        * The thrown {@link LegacyError}.  Used to hold a reference, so that the object will not be
        * deleted until this exception is caught.
        * <p>
        * Do not serialize this field.
        */
       private transient ObjectVar<? extends LegacyError> error;

       /** The explicit legacy object being thrown.  Will be non-null only for serializable instances. */
       private LegacyError errorRef;

       /** Flag indicating if this was from a RETURN ERROR statement. */
       private boolean fromReturn;

       /** Flag indicating this is an explicit thrown exception, by the application code. */
       private boolean explicit = false;

       /**
        * Create a new instance and populate error stack trace.
        *
        * @param    error
        *           The referenced error.
        */
       public LegacyErrorException(object<? extends LegacyError> error)
       {
          this(error, false);
       }

       /**
        * Create a new instance and populate error stack trace.
        *
        * @param    error
        *           The referenced error.
        * @param    fromReturn
        *           Flag indicating if this was from a RETURN ERROR statement.
        */
       public LegacyErrorException(final object<? extends LegacyError> error, final boolean fromReturn)
       {
          super((String) null);

          this.error = new ObjectVar<>(LegacyError.class);
          this.error.assign(error);

          this.errorRef = (error).ref();
          this.fromReturn = fromReturn;
       }

       /**
        * Duplicate this legacy OO error.  If the {@link #errorRef} is <code>null</code>, a new {@link AppError}
        * instance will be created. Otherwise, the {@link #errorRef} will be re-used and its
        * {@link ProError#getCallStack() callstack} will be assumed as the server's stack trace.
        *
        * @return   See above.
        */
       public LegacyErrorException duplicate()
       {
          ObjectVar<LegacyError> newError = new ObjectVar<>(LegacyError.class);

          if (errorRef == null)
          {
             newError.assign(ObjectOps.newInstance(AppError.class));
          }
          else
          {
             ObjectOps.registerObject(errorRef);
             newError.assign(errorRef); // re-use the instance as it was de-serialized
          }

          LegacyErrorException lex = new LegacyErrorException(newError, fromReturn);
          return lex;
       }

       /**
        * Clear the {@link #errorRef} and {@link #error}, as they can't be serialized to the remote side.
        *
        * @param    clearRef
        *           When <code>true</code>, clear the {@link #errorRef}, too.
        */
       public void clearError(boolean clearRef)
       {
          error = null;
          if (clearRef)
          {
             errorRef = null;
          }
       }

       /**
        * Get the {@link #error}.
        *
        * @return   See above.
        */
       public ObjectVar<? extends LegacyError> getError()
       {
          return error;
       }

       /**
        * Get the {@link #getErrorRef()}.
        *
        * @return   See above.
        */
       public LegacyError getErrorRef()
       {
          return errorRef;
       }

       /**
        * Check the state of the {@link #fromReturn} flag.
        *
        * @return   See above.
        */
       boolean isFromReturn()
       {
          return fromReturn;
       }

       /**
        * Set the {@link #fromReturn} flag state.
        *
        * @param   fromReturn
        *          Flag indicating if this exception is from a RETURN ERROR or UNDO, THROW top-level exit.
        */
       void setFromReturn(boolean fromReturn)
       {
          this.fromReturn = false;
       }

       /**
        * Set the {@link #explicit} flag.
        *
        * @param    explicit
        *           <code>true</code> if this explicitly thrown by the application, and not FWD runtime.
        */
       void setExplicit(boolean explicit)
       {
          this.explicit = explicit;
       }

       /**
        * Check the {@link #explicit} flag.
        *
        * @return    <code>true</code> if this explicitly thrown by the application, and not FWD runtime.
        */
       boolean isExplicit()
       {
          return explicit;
       }
    }