# ExternalProgramWrapper.java

    /*
    ** Module   : ExternalProgramWrapper.java
    ** Abstract : container that implements persistent-procedure related APIs.
    **
    ** Copyright (c) 2012-2025, Golden Code Development Corporation.
    **
    ** -#- -I- --Date-- ---------------------------------------Description---------------------------------------
    ** 002 CA  20121220 Created initial version.
    ** 003 CS  20130211 Added conversion support for app server.
    ** 004 CA  20130221 getType getter for TYPE attribute was renamed to getResourceType.
    **                  Added ADM-DATA and UNIQUE-ID support.
    ** 005 CS  20130221 Added conversion support for CURRENT-WINDOW attribute.
    ** 006 CA  20130223 Added stubs for SET-CALLBACK-PROCEDURE method.
    ** 007 OM  20130304 Refactored isValid and isUnknown of WrappedResource to valid and unknown.
    ** 008 CA  20130529 Added implementation for REMOTE, SERVER-HANDLE and PROXY attributes.
    **                  Implemented the resource delete here.
    ** 009 CA  20130813 Added support for the ASYNC-REQUEST-COUNT attribute.
    ** 010 CA  20130919 Resource cleanup must be done after it was deleted.
    ** 011 CA  20130925 Added support for PUBLISHED-EVENTS attribute.
    ** 012 CA  20130927 Resource type is determined from LegacyResource constant; the annotation is
    **                  ignored, as it doesn't extend HandleResource.
    ** 013 EVL 20131014 Adding annotation for legacy attributes to be ignored for the class.
    ** 014 SVL 20131203 Changes caused by renaming of Nameable.get/setName to Nameable.name.
    ** 015 CA  20131013 Added support for INSTANTIATING-PROCEDURE attribute.
    ** 016 CA  20131208 Emit SEARCH-TARGET and SEARCH-SELF literals as integer.  Do note delete the
    **                  procedure if is active on the call stack.
    ** 017 HC  20131222 Implemented ADM-DATA and UNIQUE-ID attribute.
    **                  INSTANTIATING-PROCEDURE is now managed by ProcedureManager.
    ** 018 CA  20140107 Implemented setCallbackProcedure for procedures associated with an external
    **                  program.
    ** 019 VIG 20140108 Implemented CURRENT-WINDOW attribute.
    ** 020 CA  20140218 NAME and FILE-NAME return the program name as used at the RUN call (the
    **                  "relative name"). Internally, the absolute program name must be used.
    ** 021 SVL 20170126 Added no-op setters for FILE-NAME.
    ** 022 CA  20181112 Implemented the PROCEDURE:TRANSACTION attribute.
    ** 023 CA  20190628 Added SINGLE-RUN and SINGLETON support.
    ** 024 VVT 20200131 Missing @Override annotations added. Code cleanup.
    ** 025 AIL 20200518 Added support for MultiDeletable.
    **     AIL 20200622 Made use of the new procedure delete signature. Fixed the multidelete.
    **                  Use the StaleProcedureHelper instead of a singleton.
    **     OM  20201120 Added missing CALLBACK management methods.
    **     OM  20201203 Fixed handling of READ/ONLY attributes.
    **     CA  20211214 For State-free appservers, the agents can be bound to remote persistent procedures; this
    **                  binding must be made using the agent's ID, as a client can invoke multiple remote
    **                  persistent procedures, and using the procedure's ID for this binding can lead to
    **                  collisions, as the pair (connection ID, procedure ID) is not guaranteed to be unique for
    **                  a connection.
    **     VVT 20221003 CommonHandle.getResourceType() method renamed to resourceType() to prevent conflicts
    **                  with namesakes in DMO. See #6694.
    **     CA  20230110 Cache the helper for ProcedureManager, ObjectOps and others (as needed), to reduce
    **                  context-local lookup.
    ** 026 CA  20230712 For cases when this is instantiated from deserialization over the network, do not resolve
    **                  the ProcedureHelper if there is no security context.
    ** 027 GBB 20230825 SecurityManager context methods calls updated.
    ** 028 CA  20240918 Removed default methods from interfaces and moved them as concrete implementations, as
    **                  default methods cause the Java metaspace to spike one order of magnitude.
    ** 029 CA  20250321 Added 'setCallback' overloads.
    */

    /*
    ** 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.security.SecurityManager;
    import com.goldencode.p2j.ui.*;
    import com.goldencode.p2j.util.ProcedureManager.SearchMode;

    /**
     * This container adds support for all persistent-procedure related attributes
     * and methods, such as:
     * <ul>
     *   <li>INTERNAL-ENTRIES</li>
     *   <li>NAME</li>
     *   <li>FILE-NAME</li>
     *   <li>PERSISTENT</li>
     *   <li>TYPE</li>
     *   <li>NEXT-SIBLING</li>
     *   <li>PREV-SIBLING</li>
     *   <li>PRIVATE-DATA</li>
     *   <li>GET-SIGNATURE</li>
     *   <li>ADD-SUPER-PROCEDURE</li>
     *   <li>REMOVE-SUPER-PROCEDURE</li>
     *   <li>SUPER-PROCEDURES</li>
     *   <li>SERVER</li>
     *   <li>SINGLE-RUN</li>
     *   <li>SINGLETON</li>
     *   <li>ASYNC-REQUEST-COUNT</li>
     *   <li>INSTANTIATING-PROCEDURE</li>
     *   <li>CURRENT-WINDOW</li>
     * </ul>
     */
    public class ExternalProgramWrapper
    extends TransparentWrapper
    implements PersistentProcedure,
               MultiDeletable,
               DeferredDeletable
    {
       /** Helper to use the ProcedureManager without any context local lookups. */
       protected final ProcedureManager.ProcedureHelper pm;

       /**
        * Constructs a new wrapper for the given external procedure instance.
        *
        * @param    referent
        *           The external procedure instance.
        */
       public ExternalProgramWrapper(Object referent)
       {
          super(referent);

          pm = SecurityManager.getInstance().contextSm.hasContext() ?
             ProcedureManager.getProcedureHelper() :
             null;
       }

       /**
        * Constructs a new wrapper for the given external procedure instance.
        *
        * @param    referent
        *           The external procedure instance.
        */
       public ExternalProgramWrapper(ProcedureManager.ProcedureHelper pm, Object referent)
       {
          super(referent);

          this.pm = pm;
       }

       /**
        * Determine if this instance is valid. This means that its
        * {@link TransparentWrapper#referent} field must be set and valid. More,
        * this must be a known procedure instance, registered with
        * {@link ProcedureManager}.
        *
        * @return   <code>true</code> if this instance is valid,
        *           <code>false</code> otherways.
        */
       @Override
       public boolean valid()
       {
          if (!super.valid())
          {
             return false;
          }

          return pm.hasReferent(referent);
       }

       /**
        * API needed to implement read-only attribute assignment (a 4GL "feature").
        *
        * @param    attribute
        *           The attribute's name.
        */
       @Override
       @Deprecated
       public void readOnlyError(String attribute)
       {
          handle.readOnlyError(new handle(this), attribute, handle.UNKNOWN_ARGUMENT);
       }

       /**
        * Shows a specific error, as this read-only {@code attribute} was used on the right-side of an assignment.
        * If the {@code expr} is evaluated to {@code ?} (unknown value) and this attribute does not support it,
        * a specific error is raised.
        *
        * @param    attribute
        *           The read-only attribute.
        * @param    expr
        *           The expression whose value was attempted to be assigned to READ-ONLY attribute.
        */
       public void readOnlyError(String attribute, Object expr)
       {
          handle.readOnlyError(new handle(this), attribute, expr);
       }

       /**
        * Get the <code>INTERNAL-ENTRIES</code> attribute of this
        * {@link TransparentWrapper#referent external procedure instance.}
        *
        * @return   See above.
        */
       @Override
       public character internalEntries()
       {
          String pname = ProcedureManager.getAbsoluteName(referent);
          boolean prv = this.referent == pm.thisProcedure().get();

          return new character(SourceNameMapper.getInternalEntries(pname, prv));
       }

       /**
        * Get the <code>NAME</code> attribute of this
        * {@link TransparentWrapper#referent external procedure instance.}
        *
        * @return   See above.
        */
       @Override
       public character name()
       {
          return getFileName();
       }

       /**
        * Calls {@link handle#readOnlyError}, as this attribute is read-only for procedure handles.
        *
        * @param    name
        *           Not used.
        */
       @Override
       @LegacyAttribute(name = "NAME", setter = true, ignore = true)
       public void name(String name)
       {
          handle.readOnlyError(new handle(this), "name");
       }

       /**
        * Calls {@link handle#readOnlyError}, as this attribute is read-only for procedure handles.
        *
        * @param    name
        *           Not used.
        */
       @Override
       @LegacyAttribute(name = "NAME", setter = true, ignore = true)
       public void name(character name)
       {
          name((String) null);
       }

       /**
        * Get the <code>FILE-NAME</code> attribute of this
        * {@link TransparentWrapper#referent external procedure instance.}
        *
        * @return   See above.
        */
       @Override
       public character getFileName()
       {
          return new character(pm.getRelativeName(referent));
       }

       /**
        * Get the <code>persistent</code> attribute of this
        * {@link TransparentWrapper#referent external procedure instance.}
        *
        * @return   See above.
        */
       @Override
       public logical isPersistent()
       {
          return pm.isPersistent(referent);
       }

       /**
        * Get the <code>single-run</code> attribute of this
        * {@link TransparentWrapper#referent external procedure instance.}
        *
        * @return   See above.
        */
       @Override
       public logical isSingleRun()
       {
          return new logical(pm.isSingleRun(referent));
       }

       /**
        * Get the <code>single-run</code> attribute of this
        * {@link TransparentWrapper#referent external procedure instance.}
        *
        * @return   See above.
        */
       @Override
       public logical isSingleton()
       {
          return new logical(pm.isSingleton(referent));
       }

       /**
        * Get the <code>TYPE</code> attribute of this
        * {@link TransparentWrapper#referent external procedure instance.}
        *
        * @return   Always returns <code>"PROCEDURE"</code>.
        */
       @Override
       public character resourceType()
       {
          return new character(LegacyResource.PROCEDURE);
       }

       /**
        * Get the <code>NEXT-SIBLING</code> attribute of this
        * {@link TransparentWrapper#referent external procedure instance.}
        *
        * @return   See above.
        */
       @Override
       public handle getNextSibling()
       {
          return pm.getNextSibling(referent);
       }

       /**
        * Get the <code>PREV-SIBLING</code> attribute of this
        * {@link TransparentWrapper#referent external procedure instance.}
        *
        * @return   See above.
        */
       @Override
       public handle getPrevSibling()
       {
          return pm.getPrevSibling(referent);
       }

       /**
        * Get the <code>PRIVATE-DATA</code> attribute of this
        * {@link TransparentWrapper#referent external procedure instance.}
        *
        * @return   See above.
        */
       @Override
       public character getPrivateData()
       {
          return pm.getPrivateData(referent);
       }

       /**
        * Set the <code>PRIVATE-DATA</code> attribute of this
        * {@link TransparentWrapper#referent external procedure instance.}
        *
        * @param    data
        *           The new private-data value.
        */
       @Override
       public void setPrivateData(character data)
       {
          pm.setPrivateData(referent, data);
       }

       /**
        * Set the <code>PRIVATE-DATA</code> attribute of this
        * {@link TransparentWrapper#referent external procedure instance.}
        *
        * @param    data
        *           The new private-data value.
        */
       @Override
       public void setPrivateData(String data)
       {
          setPrivateData(new character(data));
       }

       /**
        * Execute the <code>GET-SIGNATURE</code> method of this
        * {@link TransparentWrapper#referent external procedure instance.}
        *
        * @param    internalEntry
        *           The legacy name of the internal-entry for which the signature
        *           is needed.
        *
        * @return  The internal entry's signature.
        */
       @Override
       public character getSignature(String internalEntry)
       {
          return getSignature(new character(internalEntry));
       }

       /**
        * Execute the <code>GET-SIGNATURE</code> method of this
        * {@link TransparentWrapper#referent external procedure instance.}
        *
        * @param    internalEntry
        *           The legacy name of the internal-entry for which the signature
        *           is needed.
        *
        * @return  The internal entry's signature.
        */
       @Override
       public character getSignature(character internalEntry)
       {
          String ieName = internalEntry.toStringMessage();
          String pname = ProcedureManager.getAbsoluteName(referent);

          if ("".equals(ieName))
          {
             return new character(SourceNameMapper.getSignature(pname, ""));
          }

          // is safe to call both, because: if there are both func and proc with
          // the same name, then the signature is for the func, not the proc
          // (thus if the func is private, then is not seen).
          // else, if no func with this name, proc is cheched
          if (SourceNameMapper.isPrivate(pname, ieName, true) ||
              SourceNameMapper.isPrivate(pname, ieName, false))
          {
             // am I calling this from THIS-PROCEDURE? if yes, then I have access
             handle thisp = pm.thisProcedure();
             String thisName = ProcedureManager.getAbsoluteName(thisp.get());
             if (!CompareOps.equals(new character(pname), new character(thisName)))
             {
                // return blank
                return new character("");
             }
          }

          return new character(SourceNameMapper.getSignature(pname, ieName));
       }

       /**
        * Get the <code>SUPER-PROCEDURES</code> attribute of this
        * {@link TransparentWrapper#referent external procedure instance.}
        *
        * @return   See above.
        */
       @Override
       public character superProcedures()
       {
          return pm.superProcedures(referent);
       }

       /**
        * Add the given handle as a super-procedure for the current handle.
        *
        * @param    h
        *           The handle to be added as a super-procedure.
        *
        * @return   <code>true</code> if <code>h</code> is a valid procedure
        *           handle.
        */
       @Override
       public logical addSuperProcedure(handle h)
       {
          return pm.addSuperProcedure(referent, h);
       }

       /**
        * Add the given handle as a super-procedure for the current handle, using
        * the explicit {@link SearchMode mode}.
        *
        * @param    h
        *           The handle to be added as a super-procedure.
        * @param    mode
        *           The {@link SearchMode} to be set for the <code>h</code>
        *           handle.
        *
        * @return   <code>true</code> if <code>h</code> is a valid procedure
        *           handle.
        */
       @Override
       public logical addSuperProcedure(handle h, SearchMode mode)
       {
          return pm.addSuperProcedure(referent, h, mode);
       }

       /**
        * Add the given handle as a super-procedure for the current handle, using
        * the search-mode set as a string (one of the <code>SEARCH-TARGET</code>
        * or <code>SEARCH-SELF</code> string literals).
        *
        * @param    h
        *           The handle to be added as a super-procedure.
        * @param    mode
        *           The search-mode to be set for the <code>h</code> handle.
        *
        * @return   <code>true</code> if <code>h</code> is a valid procedure
        *           handle.
        */
       @Override
       public logical addSuperProcedure(handle h, int mode)
       {
          return pm.addSuperProcedure(referent, h, mode);
       }

       /**
        * Add the given handle as a super-procedure for the current handle, using
        * the search-mode set as a string (one of the <code>SEARCH-TARGET</code>
        * or <code>SEARCH-SELF</code> string literals).
        *
        * @param    h
        *           The handle to be added as a super-procedure.
        * @param    mode
        *           The search-mode to be set for the <code>h</code> handle.
        *
        * @return   <code>true</code> if <code>h</code> is a valid procedure
        *           handle.
        */
       @Override
       public logical addSuperProcedure(handle h, integer mode)
       {
          if (mode.isUnknown())
          {
             return pm.addSuperProcedure(referent, h, (SearchMode) null);
          }
          return pm.addSuperProcedure(referent, h, mode.intValue());
       }

       /**
        * Remove the given handle from this handle's list of super-procedures.
        *
        * @param    h
        *           The procedure handle to be removed.
        *
        * @return   <code>true</code> if <code>h</code> is a valid procedure
        *           handle.
        */
       @Override
       public logical removeSuperProcedure(handle h)
       {
          return pm.removeSuperProcedure(referent, h);
       }

       /**
        * Get CURRENT-WINDOW attribute for given procedure handle.
        *
        * @return  Reference to current window widget.
        */
       @Override
       public handle currentWindow()
       {
          handle phandle = new handle(this);
          // TODO: handle validation
          return LogicalTerminal.currentWindow(phandle);
       }

       /**
        * Set CURRENT-WINDOW attribute for this procedure handle.
        *
        * @param    h
        *           A handle for the window.
        */
       @Override
       public void setCurrentWindow(handle h)
       {
          handle phandle = new handle(this);
          LogicalTerminal.setProcCurrentWindow(phandle, h);
       }

       /**
        * Set CURRENT-WINDOW attribute for this procedure handle.
        *
        * @param    win
        *           Window reference.
        */
       @Override
       public void setCurrentWindow(WindowWidget win)
       {
          setCurrentWindow(win.asWidgetHandle());
       }

       /**
        * Indicates if the procedure is ran as the remote top-level AppServer.
        *
        * @return   <code>true</code> if the procedure is ran remote , <code>false</code> otherwise.
        */
       @Override
       public  logical isRemote()
       {
          return new logical(SessionUtils._isRemote() &&
                             (pm.isTopLevel(get()) ||
                              AppServerManager.hasProcedure(get())));
       }

       /**
        * Returns a handle to the app server in which the procedure is ran.
        *
        * @return   Always unknown.
        */
       @Override
       public handle getServerHandle()
       {
          return new handle();
       }

       /**
        * Indicates if the procedure is a proxy procedure.
        *
        * @return   always <code>false</code>
        */
       @Override
       public logical isProxy()
       {
          return new logical(false);
       }

       /**
        * Returns a handle to the current opened transaction.
        *
        * @return   See above
        */
       @Override
       public handle getTransaction()
       {
          return new handle(TransactionImpl.get());
       }

       /**
        * Get the value of the ADM-DATA attribute.
        *
        * @return   See above.
        */
       @Override
       public character getADMData()
       {
          return pm.getADMData(referent);
       }

       /**
        * Set the value of the ADM-DATA attribute.
        *
        * @param    value
        *           The new value.
        */
       @Override
       public void setADMData(String value)
       {
          pm.setADMData(referent, value);
       }

       /**
        * Set the value of the ADM-DATA attribute.
        *
        * @param    value
        *           The new value.
        */
       @Override
       public void setADMData(character value)
       {
          pm.setADMData(referent, value.getValue());
       }

       /**
        * Gets the the unique ID number associated to this object by the underlying system. Not the
        * same as the handle value itself.
        *
        * @return   The integer number of the children.
        */
       @Override
       public integer getUniqueID()
       {
          return pm.getUniqueID(referent);
       }

       /**
        * Applies a callback procedure, which allows execution of a defined event without duplicating
        * the event procedure definition.
        *
        * @param   eventName
        *          The event whose callback will be called.
        *
        * @return  {@code true} if operation is successful.
        */
       @Override
       public logical applyCallback(Text eventName)
       {
          return applyCallback(eventName.toJavaType());
       }

       /**
        * Retrieves the name of the internal procedure associated with the ABL callback for the
        * specified event.
        *
        * @param   eventName
        *          The name of the event.
        *
        * @return  the name of the internal procedure associated with specified event.
        */
       @Override
       public character getCallbackProcName(Text eventName)
       {
          return getCallbackProcName(eventName.toJavaType());
       }

       /**
        * Retrieves the handle of the procedure that contains the internal procedure associated
        * with the ABL callback for the specified event
        *
        * @param   eventName
        *          The name of the event.
        *
        * @return  a handle to the procedure that contains the callback procedure.
        */
       @Override
       public handle getCallbackProcContext(Text eventName)
       {
          return getCallbackProcContext(eventName.toJavaType());
       }

       /**
        * Configures a callback. Creates an association between a method within a class instance or
        * an internal procedure within a persistent procedure, with an ABL callback event.
        *
        * @param   callbackName
        *          The name of a callback.
        * @param   routineName
        *          The name of a method or an internal procedure to be associated.
        * @param   context
        *          The context in which the callback will be executed.
        *
        * @return  {@code true} if operation is successful and {@code false} if the parameters are
        *          invalid.
        */
       @Override
       public logical setCallback(Text callbackName, Text routineName, object<?> context)
       {
          return setCallback(callbackName.toJavaType(), routineName.toJavaType(), context);
       }

       /**
        * Configures a callback. Creates an association between a method within a class instance or
        * an internal procedure within a persistent procedure, with an ABL callback event.
        *
        * @param   callbackName
        *          The name of a callback.
        * @param   routineName
        *          The name of a method or an internal procedure to be associated.
        * @param   context
        *          The context in which the callback will be executed.
        *
        * @return  {@code true} if operation is successful and {@code false} if the parameters are
        *          invalid.
        */
       @Override
       public logical setCallback(String callbackName, String routineName, handle context)
       {
          return setCallbackProcedure(callbackName, routineName, context);
       }

       /**
        * Configures a callback. Creates an association between a method within a class instance or
        * an internal procedure within a persistent procedure, with an ABL callback event.
        *
        * @param   callbackName
        *          The name of a callback.
        * @param   routineName
        *          The name of a method or an internal procedure to be associated.
        * @param   context
        *          The context in which the callback will be executed.
        *
        * @return  {@code true} if operation is successful and {@code false} if the parameters are
        *          invalid.
        */
       @Override
       public logical setCallback(Text callbackName, Text routineName, handle context)
       {
          return setCallbackProcedure(callbackName.toJavaType(), routineName.toJavaType(), context);
       }

       /**
        * Configures a callback. Creates an association between a method within a class instance or
        * an internal procedure within a persistent procedure, with an ABL callback event.
        *
        * @param   callbackName
        *          The name of a callback.
        * @param   routineName
        *          The name of a method or an internal procedure to be associated.
        * @param   context
        *          The context in which the callback will be executed.
        *
        * @return  {@code true} if operation is successful and {@code false} if the parameters are
        *          invalid.
        */
       @Override
       public logical setCallback(String callbackName, Text routineName, handle context)
       {
          return setCallbackProcedure(callbackName, routineName.toJavaType(), context);
       }

       /**
        * Configures a callback. Creates an association between a method within a class instance or
        * an internal procedure within a persistent procedure, with an ABL callback event.
        *
        * @param   callbackName
        *          The name of a callback.
        * @param   routineName
        *          The name of a method or an internal procedure to be associated.
        *
        * @return  {@code true} if operation is successful and {@code false} if the parameters are
        *          invalid.
        */
       @Override
       public logical setCallback(String callbackName, String routineName)
       {
          return setCallback(callbackName, routineName, (object<?>) null);
       }

       /**
        * Configures a callback. Creates an association between a method within a class instance or
        * an internal procedure within a persistent procedure, with an ABL callback event.
        *
        * @param   callbackName
        *          The name of a callback.
        * @param   routineName
        *          The name of a method or an internal procedure to be associated.
        *
        * @return  {@code true} if operation is successful and {@code false} if the parameters are
        *          invalid.
        */
       @Override
       public logical setCallback(Text callbackName, Text routineName)
       {
          return setCallback(callbackName.toJavaType(), routineName.toJavaType(), (object<?>) null);
       }

       /**
        * Configures a callback. Creates an association between a method within a class instance or
        * an internal procedure within a persistent procedure, with an ABL callback event.
        *
        * @param   callbackName
        *          The name of a callback.
        * @param   routineName
        *          The name of a method or an internal procedure to be associated.
        *
        * @return  {@code true} if operation is successful and {@code false} if the parameters are
        *          invalid.
        */
       @Override
       public logical setCallback(Text callbackName, String routineName)
       {
          return setCallback(callbackName.toJavaType(), routineName);
       }

       /**
        * Configures a callback. Creates an association between a method within a class instance or
        * an internal procedure within a persistent procedure, with an ABL callback event.
        *
        * @param   callbackName
        *          The name of a callback.
        * @param   routineName
        *          The name of a method or an internal procedure to be associated.
        *
        * @return  {@code true} if operation is successful and {@code false} if the parameters are
        *          invalid.
        */
       @Override
       public logical setCallback(String callbackName, Text routineName)
       {
          return setCallback(callbackName, routineName.toJavaType());
       }

       /**
        * Configures a callback. Creates an association between a method within a class instance or
        * an internal procedure within a persistent procedure, with an ABL callback event.
        *
        * @param   callbackName
        *          The name of a callback.
        * @param   routineName
        *          The name of a method or an internal procedure to be associated.
        * @param   context
        *          The context in which the callback will be executed.
        *
        * @return  {@code true} if operation is successful and {@code false} if the parameters are
        *          invalid.
        */
       @Override
       public logical setCallback(String callbackName, Text routineName, object<?> context)
       {
          return setCallback(callbackName, routineName.toJavaType(), context);
       }

       /**
        * Configures a callback. Creates an association between a method within a class instance or
        * an internal procedure within a persistent procedure, with an ABL callback event.
        *
        * @param   callbackName
        *          The name of a callback.
        * @param   routineName
        *          The name of a method or an internal procedure to be associated.
        * @param   context
        *          The context in which the callback will be executed.
        *
        * @return  {@code true} if operation is successful and {@code false} if the parameters are
        *          invalid.
        */
       @Override
       public logical setCallback(Text callbackName, String routineName, object<?> context)
       {
          return setCallback(callbackName.toJavaType(), routineName, context);
       }

       /**
        * Configures a callback. Creates an association between a method within a class instance or
        * an internal procedure within a persistent procedure, with an ABL callback event.
        *
        * @param   callbackName
        *          The name of a callback.
        * @param   routineName
        *          The name of a method or an internal procedure to be associated.
        * @param   context
        *          The context in which the callback will be executed.
        *
        * @return  {@code true} if operation is successful and {@code false} if the parameters are
        *          invalid.
        */
       @Override
       public logical setCallback(Text callbackName, String routineName, handle context)
       {
          return setCallback(callbackName.toJavaType(), routineName, context);
       }

       /**
        * Associate the internal procedure with the given web-services event.
        * <p>
        * This method returns false if the event name is not valid.
        * <p>
        * For external procedures, this always shows an error.
        *
        * @param   event
        *          The event name, must evaluate to one of the "REQUEST-HEADER" or the "RESPONSE-HEADER" strings.
        * @param   proc
        *          The internal procedure to be executed for this event, which will be executed using the current
        *          THIS-PROCEDURE reference. To remove a callback mapping, set the this parameter to the empty
        *          string.
        * @param   context
        *          The context in which the callback will be executed.
        *
        * @return   <code>true</code> if the event was registered.
        */
       @Override
       public logical setCallback(String event, String proc, object<?> context)
       {
          UnimplementedFeature.missing("SET-CALLBACK-PROCEDURE(String event, String proc, object<?> context)");
          return new logical();
       }

       /**
        * Associate the internal procedure with the given web-services event.
        * <p>
        * This method returns false if the event name is not valid.
        * <p>
        * For external procedures, this always shows an error.
        *
        * @param    event
        *           The event name, must evaluate to one of the "REQUEST-HEADER" or the
        *           "RESPONSE-HEADER" strings.
        * @param    proc
        *           The internal procedure to be executed for this event, which will be executed using
        *           the current THIS-PROCEDURE reference. To remove a callback mapping, set the this
        *           parameter to the empty string.
        *
        * @return   <code>true</code> if the event was registered.
        */
       @Override
       public logical setCallbackProcedure(String event, String proc)
       {
          return setCallbackProcedure(new character(event), new character(proc),
                                      pm.thisProcedure());
       }

       /**
        * Associate the internal procedure with the given web-services event.
        * <p>
        * This method returns false if the event name is not valid.
        * <p>
        * For external procedures, this always shows an error.
        *
        * @param    event
        *           The event name, must evaluate to one of the "REQUEST-HEADER" or the
        *           "RESPONSE-HEADER" strings.
        * @param    proc
        *           The internal procedure to be executed for this event, which will be executed using
        *           the current THIS-PROCEDURE reference. To remove a callback mapping, set the this
        *           parameter to the empty string.
        *
        * @return   <code>true</code> if the event was registered.
        */
       @Override
       public logical setCallbackProcedure(character event, String proc)
       {
          return setCallbackProcedure(event, new character(proc), pm.thisProcedure());
       }

       /**
        * Associate the internal procedure with the given web-services event.
        * <p>
        * This method returns false if the event name is not valid.
        * <p>
        * For external procedures, this always shows an error.
        *
        * @param    event
        *           The event name, must evaluate to one of the "REQUEST-HEADER" or the
        *           "RESPONSE-HEADER" strings.
        * @param    proc
        *           The internal procedure to be executed for this event, which will be executed using
        *           the current THIS-PROCEDURE reference. To remove a callback mapping, set the this
        *           parameter to the empty string.
        *
        * @return   <code>true</code> if the event was registered.
        */
       @Override
       public logical setCallbackProcedure(String event, character proc)
       {
          return setCallbackProcedure(new character(event), proc, pm.thisProcedure());
       }

       /**
        * Associate the internal procedure with the given web-services event.
        * <p>
        * This method returns false if the event name is not valid.
        * <p>
        * For external procedures, this always shows an error.
        *
        * @param    event
        *           The event name, must evaluate to one of the "REQUEST-HEADER" or the
        *           "RESPONSE-HEADER" strings.
        * @param    proc
        *           The internal procedure to be executed for this event, which will be executed using
        *           the current THIS-PROCEDURE reference. To remove a callback mapping, set the this
        *           parameter to the empty string.
        *
        * @return   <code>true</code> if the event was registered.
        */
       @Override
       public logical setCallbackProcedure(character event, character proc)
       {
          return setCallbackProcedure(event, proc, pm.thisProcedure());
       }

       /**
        * Associate the internal procedure with the given web-services event.
        * <p>
        * This method returns false if the event name is not valid or if the procedure's context is
        * not a valid handle.
        * <p>
        * For external procedures, this always shows an error.
        *
        * @param    event
        *           The event name, must evaluate to one of the "REQUEST-HEADER" or the
        *           "RESPONSE-HEADER" strings.
        * @param    proc
        *           The internal procedure to be executed for this event. To remove a callback
        *           mapping, set the this parameter to the empty string.
        * @param    context
        *           The procedure handle where the internal procedure will be searched and executed.
        *
        * @return   <code>true</code> if the event was registered.
        */
       @Override
       public logical setCallbackProcedure(String event, String proc, handle context)
       {
          return setCallbackProcedure(new character(event), new character(proc), context);
       }

       /**
        * Associate the internal procedure with the given web-services event.
        * <p>
        * This method returns false if the event name is not valid or if the procedure's context is
        * not a valid handle.
        * <p>
        * For external procedures, this always shows an error.
        *
        * @param    event
        *           The event name, must evaluate to one of the "REQUEST-HEADER" or the
        *           "RESPONSE-HEADER" strings.
        * @param    proc
        *           The internal procedure to be executed for this event. To remove a callback
        *           mapping, set the this parameter to the empty string.
        * @param    context
        *           The procedure handle where the internal procedure will be searched and executed.
        *
        * @return   <code>true</code> if the event was registered.
        */
       @Override
       public logical setCallbackProcedure(character event, String proc, handle context)
       {
          return setCallbackProcedure(event, new character(proc), context);
       }

       /**
        * Associate the internal procedure with the given web-services event.
        * <p>
        * This method returns false if the event name is not valid or if the procedure's context is
        * not a valid handle.
        * <p>
        * For external procedures, this always shows an error.
        *
        * @param    event
        *           The event name, must evaluate to one of the "REQUEST-HEADER" or the
        *           "RESPONSE-HEADER" strings.
        * @param    proc
        *           The internal procedure to be executed for this event. To remove a callback
        *           mapping, set the this parameter to the empty string.
        * @param    context
        *           The procedure handle where the internal procedure will be searched and executed.
        *
        * @return   <code>true</code> if the event was registered.
        */
       @Override
       public logical setCallbackProcedure(String event, character proc, handle context)
       {
          return setCallbackProcedure(new character(event), proc, context);
       }

       /**
        * Associate the internal procedure with the given web-services event.
        * <p>
        * This method returns false if the event name is not valid or if the procedure's context is
        * not a valid handle.
        * <p>
        * For external procedures, this always shows an error.
        *
        * @param    event
        *           The event name, must evaluate to one of the "REQUEST-HEADER" or the
        *           "RESPONSE-HEADER" strings.
        * @param    proc
        *           The internal procedure to be executed for this event. To remove a callback
        *           mapping, set the this parameter to the empty string.
        * @param    context
        *           The procedure handle where the internal procedure will be searched and executed.
        *
        * @return   <code>true</code> if the event was registered.
        */
       @Override
       public logical setCallbackProcedure(character event, character proc, handle context)
       {
          final String msg =
             "**The SET-CALLBACK-PROCEDURE attribute on the PROCEDURE widget has invalid arguments";
          ErrorManager.recordOrShowError(4065, msg, false, false, false);
          return new logical(false);
       }

       /**
        * Retrieves the handle of the procedure that contains the internal procedure associated
        * with the ABL callback for the specified event
        *
        * @param   eventName
        *          The name of the event.
        *
        * @return  a handle to the procedure that contains the callback procedure.
        */
       @Override
       public handle getCallbackProcContext(String eventName)
       {
          UnimplementedFeature.missing("GET-CALLBACK-PROC-CONTEXT(String event)");
          return new handle();
       }

       /**
        * Retrieves the name of the internal procedure associated with the ABL callback for the
        * specified event.
        *
        * @param   eventName
        *          The name of the event.
        *
        * @return  the name of the internal procedure associated with specified event.
        */
       @Override
       public character getCallbackProcName(String eventName)
       {
          UnimplementedFeature.missing("GET-CALLBACK-PROC-NAME(String event)");
          return new character();
       }

       /**
        * Applies a callback procedure, which allows execution of a defined event without duplicating
        * the event procedure definition.
        *
        * @param   eventName
        *          The event whose callback will be called.
        *
        * @return  {@code true} if operation is successful.
        */
       @Override
       public logical applyCallback(String eventName)
       {
          UnimplementedFeature.missing("APPLY-CALLBACK(String event)");
          return new logical();
       }

       /**
        * Check if the resource can veto the delete or not, before attempting the {@link #delete()} call.
        *
        * @param    ref
        *           The exact handle holding the reference, on which the delete is attempted.
        * @param    explicit
        *           Flag indicating this is called via <code>DELETE OBJECT</code> from the application.
        *
        * @return   <code>false</code> if the delete is vetoed.
        */
       @Override
       public boolean allowDelete(handle ref, boolean explicit)
       {
          return true;
       }

       /**
        * Perform actual delete of this procedure, by calling {@link ProcedureManager#delete(Object, boolean)}.
        * This will trigger a referent clear which won't happen necessarily now - it can be deferred
        * to a specific block, moment at which the deferredDelete method will be fired.
        */
       @Override
       public void delete()
       {
          if (pm.delete(this.get(), true))
          {
             // cleanup after it
             handle.removeResource(this);
          }

          // if this is an appserver REMOTE procedure handle, then the requester side is not informed
          // about the handle deletion; only when deleting it from the requester side, the remote side
          // will be informed
       }

       /**
        * Implement the MuliDeletable interface; this resource is normally cleared at first delete.
        * However, in specific scenario, this can be deleted again even if invalid. Thus postpone
        * the deletion.
        *
        * @return   <code>false</code> if this can't handle an invalid delete or <code>true</code> otherwise.
        */
       @Override
       public boolean handleMultipleDeletes()
       {
          return StaleProcedureManager.invalidateResource(referent);
       }

       /**
        * Implements the DeferredDeletable interface. This will be called when this resource should be deleted
        * for real - meaning that the referent should be removed. A simple delete will only cause an invalidation
        * and a defer, while this will remove the referent.
        */
       @Override
       public void deferredDelete()
       {
          StaleProcedureManager.notifyResourceDelete(referent);
       }

       /**
        * Returns the number of asynchronous requests.
        *
        * @return   For non-proxy procedures, always 0.
        */
       @Override
       public integer getAsyncRequestCount()
       {
          return new integer(0);
       }

       /**
        * Get the named events published by this procedure.  This is a comma separated list of
        * named events collected from the PUBLISH statements, where the named event is a hard-coded
        * string, not a variable.
        *
        * @return    The named events published by this procedure, or the empty string if none found.
        */
       @Override
       public character getPublishedEvents()
       {
          String pname = ProcedureManager.getAbsoluteName(referent);
          return new character(SourceNameMapper.getPublishedEvents(pname));
       }

       /**
        * Getter for the INSTANTIATING-PROCEDURE attribute.
        * <p>
        * The returned handle will refer a valid external procedure (persistent or not) or will be
        * unknown, when this is a entry point procedure or in case its instantiating procedure was
        * persistent and has been deleted.
        *
        * @return   See above.
        */
       @Override
       public handle instantiatingProcedure()
       {
          return pm.resolveInstantiatingProcedure(pm.getInstantiatingProcedure(referent));
       }

       /**
        * Displays "FILE-INFO is not a setable attribute for PROCEDURE widget" error message.
        *
        * @param    name
        *           Not used.
        */
       @Override
       public void initFileInfo(character name)
       {
          ErrorManager.recordOrShowError(4052,
                "FILE-NAME is not a setable attribute for PROCEDURE widget",
                false);
       }

       /**
        * Displays "FILE-INFO is not a setable attribute for PROCEDURE widget" error message.
        *
        * @param    name
        *           Not used.
        */
       @Override
       public void initFileInfo(String name)
       {
          initFileInfo(new character(name));
       }
    }