# PortTypeWrapper.java

    /*
    ** Module   : PortTypeWrapper.java
    ** Abstract : container that implements a port-type procedure.
    **
    ** Copyright (c) 2013-2025, Golden Code Development Corporation.
    **
    ** -#- -I- --Date-- ---------------------------------------Description---------------------------------------
    ** 002 CA  20131220 Created initial version.
    ** 003 VIG 20140116 Changed currentWindow method signature.
    ** 004 SVL 20170126 Added no-op setters for FILE-NAME.
    ** 005 CA  20190628 Added SINGLE-RUN and SINGLETON support.
    ** 006 OM  20201030 Invalid attribute API support for getters/setters.
    **     OM  20201120 Added callback procedure management methods.
    **     CA  20221006 UNIQUE-ID is kept as Java type instead of BDT.  Refs #6827
    **     CA  20230116 Avoid using handle.unwrap, handle.getReference or other BDT usage from within FWD runtime.
    ** 007 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.
    ** 008 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.ui.*;
    import com.goldencode.p2j.util.ProcedureManager.SearchMode;
    import com.goldencode.p2j.util.UniqueIdGenerator.IdKind;

    /**
     * Implements a procedure connected to a WSDL port-type. Compared to the
     * {@link ExternalProgramWrapper} implementation, port-type procedures are limited, most of the
     * APIs being no-op or returning default values. Only the following procedure-specific APIs are
     * implemented by port-types too:
     * <ul>
     *   <li>FILE-NAME</li>
     *   <li>PERSISTENT</li>
     *   <li>SERVER</li>
     *   <li>ASYNC-REQUEST-COUNT</li>
     *   <li>SET-CALLBACK-PROCEDURE</li>
     *   <li>SERVER-HANDLE</li>
     *   <li>CURRENT-WINDOW</li>
     * </ul>
     */
    public class PortTypeWrapper
    extends HandleChain
    implements PersistentProcedure,
               AsyncRequestListener
    {
       /** Constant identifying the <code>REQUEST-HEADER</code> callback. */
       private static final String CALLBACK_REQUEST_HEADER = "REQUEST-HEADER";

       /** Constant identifying the <code>RESPONSE-HEADER</code> callback. */
       private static final String CALLBACK_RESPONSE_HEADER = "RESPONSE-HEADER";

       /** The {@link ServerImpl} instance associated with this port-type procedure. */
       private final ServerImpl server;

       /** The ADM-DATA of this port-type procedure. */
       private String admData = null;

       /** The UNIQUE-ID of this port-type procedure. */
       private Long uniqueId = null;

       /**
        * The name of request-header callback procedure.  Unknown if request-header callback is not
        * used.
        */
       private String requestHeaderProc = null;

       /**
        * The context for the request-header procedure.  Unknown if request-header callback is not
        * used.
        */
       private WrappedResource requestHeaderContext = null;

       /**
        * The name of response-header callback procedure.  Unknown if response-header callback is not
        * used.
        */
       private String responseHeaderProc = null;

       /**
        * The context for the response-header procedure.  Unknown if response-header callback is not
        * used.
        */
       private WrappedResource responseHeaderContext = null;

       /** The number of active asynchronous requests. */
       private long asyncRequestCount = 0;

       /** Flag indicating if this port-type procedure was deleted or not. */
       private boolean deleted = false;

       /**
        * Instantiate a new port-type procedure by specifying the port-type name and the associated
        * {@link ServerImpl} instance.
        *
        * @param    name
        *           The port-type name.  This will be reported by the NAME and FILE-NAME attributes.
        * @param    server
        *           The associated server instance.
        */
       PortTypeWrapper(String name, ServerImpl server)
       {
          // port-type procedures do not collide with external or proxy procedures (thus the first/last
          // resource must not be set).
          super(false, false);

          this.name = name;
          this.server = server;
       }

       /**
        * Reports if this object is valid for use.
        * <p>
        * A port-type is valid only if it was not yet deleted.
        *
        * @return   <code>true</code> if we are valid (can be used).
        */
       @Override
       public boolean valid()
       {
          return !deleted;
       }

       /**
        * Get the <code>file-name</code> attribute of this handle.
        *
        * @return   See above.
        */
       @Override
       public character getFileName()
       {
          return new character(name());
       }

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

       /**
        * Returns the number of asynchronous requests.
        *
        * @return   See above.
        */
       @Override
       public integer getAsyncRequestCount()
       {
          return new integer(asyncRequestCount);
       }

       /**
        * Get the <code>persistent</code> attribute of this port-type procedure.
        *
        * @return   Always <code>true</code>.
        */
       @Override
       public logical isPersistent()
       {
          return new logical(true);
       }

       /**
        * Get the <code>singleton</code> attribute of this port-type procedure.
        *
        * @return   Always <code>false</code>.
        */
       @Override
       public logical isSingleton()
       {
          return new logical(false);
       }

       /**
        * Get the <code>single-run</code> attribute of this port-type procedure.
        *
        * @return   Always <code>false</code>.
        */
       @Override
       public logical isSingleRun()
       {
          return new logical(false);
       }

       /**
        * 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.
        *
        * @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),
                                      ProcedureManager.thisProcedure());
       }

       /**
        * Associate the internal procedure with the given web-services event.
        * <p>
        * This method returns false if the event name is not valid.
        *
        * @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), ProcedureManager.thisProcedure());
       }

       /**
        * Associate the internal procedure with the given web-services event.
        * <p>
        * This method returns false if the event name is not valid.
        *
        * @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, ProcedureManager.thisProcedure());
       }

       /**
        * Associate the internal procedure with the given web-services event.
        * <p>
        * This method returns false if the event name is not valid.
        *
        * @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, ProcedureManager.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.
        *
        * @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.
        *
        * @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.
        *
        * @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.
        *
        * @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)
       {
          String evt = (event.isUnknown() ? "" : event.toStringMessage());

          if (!(evt.equalsIgnoreCase(CALLBACK_REQUEST_HEADER) ||
                evt.equalsIgnoreCase(CALLBACK_RESPONSE_HEADER)))
          {
             final int[] errCodes = { 11576, 4065 };
             final String msg1 = "Invalid callback type passed to SET-CALLBACK-PROCEDURE; %s. " +
                "Valid callback types are: REQUEST-HEADER or RESPONSE-HEADER (11576)";
             final String msg2 = "**The SET-CALLBACK-PROCEDURE attribute on the PROCEDURE widget " +
                "has invalid arguments. (4065)";

             ErrorManager.recordOrShowError(errCodes, new String[] {String.format(msg1, evt), msg2},
                                            false, false, false, true);

             return new logical(false);
          }

          if (!context._isValid() || !(context.getResource() instanceof PersistentProcedure))
          {
             final int[] errCodes = {11982, 4065};
             final String msg1 =
                "Third argument to SET-CALLBACK-PROCEDURE must be a valid procedure handle";
             final String msg2 =
               "**The SET-CALLBACK-PROCEDURE attribute on the PROCEDURE widget has invalid arguments";
             ErrorManager.recordOrShowError(errCodes, new String[] {msg1, msg2},
                                            false, false, false);

             return new logical(false);
          }

          // save the procedure and context
          if (CALLBACK_REQUEST_HEADER.equalsIgnoreCase(evt))
          {
             if (proc.toStringMessage().length() == 0)
             {
                // reset them
                this.requestHeaderContext = null;
                this.requestHeaderProc = null;
             }
             else
             {
                this.requestHeaderContext = context.getResource();
                this.requestHeaderProc = proc.toStringMessage();
             }
          }
          else
          {
             if (proc.toStringMessage().length() == 0)
             {
                // reset them
                this.responseHeaderContext = null;
                this.responseHeaderProc = null;
             }
             else
             {
                this.responseHeaderContext = context.getResource();
                this.responseHeaderProc = proc.toStringMessage();
             }
          }

          // false is always returned
          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();
       }

       /**
        * 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();
       }

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

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

       /**
        * Set the value of the ADM-DATA attribute.
        *
        * @param    value
        *           The new value.
        */
       @Override
       public void setADMData(character value)
       {
          this.admData = 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   See above.
        */
       @Override
       public integer getUniqueID()
       {
          if (uniqueId == null)
          {
             this.uniqueId = UniqueIdGenerator.getUniqueId(IdKind.PROCEDURE);
          }
          return new integer(this.uniqueId);
       }

       /**
        * Implements the <code>PUBLISHED-EVENTS</code> attribute.
        * <p>
        * This is a no-op for port-type procedures.
        *
        * @return   Always the empty string.
        */
       @Override
       public character getPublishedEvents()
       {
          return new character("");
       }

       /**
        * Implements the <code>SUPER-PROCEDURES</code> attribute.
        * <p>
        * This is a no-op for port-type procedures.
        *
        * @return   Always the empty string.
        */
       @Override
       public character superProcedures()
       {
          return new character("");
       }

       /**
        * Implements the <code>ADD-SUPER-PROCEDURE</code> method.
        * <p>
        * This is a no-op for port-type procedures.
        *
        * @return   Always <code>false</code>.
        */
       @Override
       public logical addSuperProcedure(handle h)
       {
          return new logical(false);
       }

       /**
        * Implements the <code>ADD-SUPER-PROCEDURE</code> method.
        * <p>
        * This is a no-op for port-type procedures.
        *
        * @return   Always <code>false</code>.
        */
       @Override
       public logical addSuperProcedure(handle h, SearchMode mode)
       {
          return new logical(false);
       }

       /**
        * Implements the <code>ADD-SUPER-PROCEDURE</code> method.
        * <p>
        * This is a no-op for port-type procedures.
        *
        * @return   Always <code>false</code>.
        */
       @Override
       public logical addSuperProcedure(handle h, int mode)
       {
          return new logical(false);
       }

       /**
        * Implements the <code>ADD-SUPER-PROCEDURE</code> method.
        * <p>
        * This is a no-op for port-type procedures.
        *
        * @return   Always <code>false</code>.
        */
       @Override
       public logical addSuperProcedure(handle h, integer mode)
       {
          return new logical(false);
       }

       /**
        * Implements the <code>REMOVE-SUPER-PROCEDURE</code> method.
        * <p>
        * This is a no-op for port-type procedures.
        *
        * @return   Always <code>false</code>.
        */
       @Override
       public logical removeSuperProcedure(handle h)
       {
          return new logical(false);
       }

       /**
        * Implements the <code>REMOTE</code> attribute.
        *
        * @return   Always <code>false</code>.
        */
       @Override
       public logical isRemote()
       {
          return new logical(false);
       }

       /**
        * Implements the <code>INTERNAL-ENTRIES</code> attribute.
        *
        * @return   Always unknown.
        */
       @Override
       public character internalEntries()
       {
          return new character();
       }

       /**
        * Implements the <code>GET-SIGNATURE</code> method.
        *
        * @return   Always the empty string.
        */
       @Override
       public character getSignature(String internalEntry)
       {
          return new character("");
       }

       /**
        * Implements the <code>GET-SIGNATURE</code> method.
        *
        * @return   Always the empty string.
        */
       @Override
       public character getSignature(character internalEntry)
       {
          return new character("");
       }

       /**
        * Get CURRENT-WINDOW attribute for given procedure handle.
        * <p>
        *
        * @return   Alwasy unknown.
        */
       @Override
       public handle currentWindow()
       {
          // TODO: return unknown
          return null;
       }

       /**
        * Set CURRENT-WINDOW attribute for this procedure handle.
        * <p>
        * This is a no-op, but the handle is validated.
        *
        * @param    h
        *           A handle for the window.
        */
       @Override
       public void setCurrentWindow(handle h)
       {
          // TODO: validate it
       }

       /**
        * Set CURRENT-WINDOW attribute for this procedure handle.
        * <p>
        * This is a no-op, but the window is validated.
        *
        * @param    win
        *           Window reference.
        */
       @Override
       public void setCurrentWindow(WindowWidget win)
       {
          // TODO: validate it
       }

       /**
        * This is a no-op, always return <code>false</code>.
        *
        * @return   Always <code>false</code>.
        */
       @Override
       public logical isProxy()
       {
          return new logical(false);
       }

       /**
        * This is a no-op, always return unknown handle.
        *
        * @return   Always unknown handle.
        */
       @Override
       public handle getTransaction()
       {
          return new handle();
       }

       /**
        * Called when an internal-entry of this proxy procedure is invoked async.
        */
       @Override
       public synchronized void notifyStart()
       {
          asyncRequestCount++;
       }

       /**
        * Called when the async call of an internal-entry for proxy procedure has finished.
        */
       @Override
       public synchronized void notifyFinish()
       {
          asyncRequestCount--;
       }

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

       /**
        * 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));
       }

       /**
        * Check if this port-type procedure can be deleted.
        *
        * @return   <code>true</code> if the port-type procedure can be deleted.
        */
       @Override
       protected boolean resourceDelete()
       {
          if (asyncRequestCount > 0)
          {
             // can't delete if async req count > 0
             final String msg = "Handle value supplied to the DELETE PROCEDURE/OBJECT statement " +
                "has outstanding asynchronous requests. Procedure '%s'";

             ErrorManager.recordOrThrowError(8980, String.format(msg, name == null ? "?" : name));
             return false;
          }

          if (!server.valid())
          {
             final String err =
                "Invalid or inappropriate SERVER handle implied by DELETE PROCEDURE statement";
             ErrorManager.displayError(5455, err, false);
             return false;
          }

          if (!server._connected())
          {
             final String err = "SERVER  is not connected; cannot delete procedure handle or object";
             ErrorManager.displayError(5456, err, false);
             return false;
          }

          deleted = true;
          return true;
       }

       /**
        * Get the {@link ServerImpl} instance associated with this port-type.
        *
        * @return   See above.
        */
       ServerImpl getServer()
       {
          return this.server;
       }

       /**
        * Get the {@link #requestHeaderProc} for this port-type. When <code>null</code>, then no
        * <code>request-header</code> procedure is set.
        *
        * @return   See above.
        */
       String getRequestHeaderProc()
       {
          return requestHeaderProc == null ? null : requestHeaderProc;
       }

       /**
        * Get the {@link #requestHeaderContext} for this port-type.
        *
        * @return   See above.
        *
        * @see   #getRequestHeaderProc()
        */
       handle getRequestHeaderContext()
       {
          return new handle(requestHeaderContext);
       }

       /**
        * Get the {@link #responseHeaderProc} for this port-type. When <code>null</code>, then no
        * <code>response-header</code> procedure is set.
        *
        * @return   See above.
        */
       String getResponseHeaderProc()
       {
          return responseHeaderProc == null ? null : responseHeaderProc;
       }

       /**
        * Get the {@link #responseHeaderContext} for this port-type.
        *
        * @return   See above.
        *
        * @see   #getResponseHeaderProc()
        */
       handle getResponseHeaderContext()
       {
          return new handle(responseHeaderContext);
       }
    }