# AuthenticatedRequest.java

    /*
    ** Module   : AuthenticatedRequest.java
    ** Abstract : Implementation of the builtin class.
    **
    ** Copyright (c) 2019-2023, Golden Code Development Corporation.
    **
    ** -#- -I- --Date-- ---------------------------------------Description----------------------------------------
    ** 001 IAS 20190923 First version.
    ** 002 MP  20200603 Added stubs taken by converting the skeleton using FWD
    ** 003 ME  20201109 Implemented as per OE12.2 (remove callback not buggy as in 4GL).
    **     ME   20210209 Adapted the mambo jambo 4GL code to pass the tests:
    **                   - remove only set the entry as unknown
    **                   - add does some kind of array resize, all unknowns are moved at the end
    **     CA  20210219 OO input parameter definitions for functions/procedures must not register with  ObjectOps
    **                  - TypeFactory.initInput will take care of this.
    ** 004 CA  20210221 Fixed 'qualified', 'extent' and 'returns' annotations at the legacy signature.
    **     CA  20210609 Updated INPUT/INPUT-OUTPUT parameters to the new approach, where they are explicitly
    **                  initialized at the method's execution, and not at the caller's arguments.
    **     CA  20220120 Do not used TypeFactory.object when the OO reference must not be tracked or registered.
    **                  Do not use TypeFactory.object for internal usages, use ObjectVar if the reference must
    **                  be tracked.
    **                  All TypeFactory.object variable definitions must be done outside of the top-level block.
    ** 005 CA  20230817 Removed ObjectOps.register, as this registration is handled by runtime.
    ** 006 CA  20231113 The 'execute' method must be annotated with LegacySignature Type.Execute, and also can be
    **                  dropped if is a no-op.
    */

    /*
    ** 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.oo.net.http;

    import com.goldencode.p2j.util.*;
    import com.goldencode.p2j.util.BlockManager.Action;
    import com.goldencode.p2j.util.BlockManager.Condition;
    import com.goldencode.p2j.util.InternalEntry.Type;

    import static com.goldencode.p2j.report.ReportConstants.*;
    import static com.goldencode.p2j.util.BlockManager.externalProcedure;
    import static com.goldencode.p2j.util.BlockManager.function;
    import static com.goldencode.p2j.util.BlockManager.internalProcedure;
    import static com.goldencode.p2j.util.BlockManager.onBlockLevel;
    import static com.goldencode.p2j.util.BlockManager.returnNormal;

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

    import com.goldencode.p2j.oo.core.Assert;
    import com.goldencode.p2j.oo.net.http.filter.auth.AuthenticationRequestFilter;
    import com.goldencode.p2j.oo.net.http.filter.auth.IauthFilterEventHandler;
    import com.goldencode.p2j.oo.net.http.filter.writer.AuthenticationRequestWriterBuilder;

    /**
     *
     * Base for authentication requests
     *
     */
    @LegacyResource(resource = "OpenEdge.Net.HTTP.AuthenticatedRequest")
    @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL)
    public class AuthenticatedRequest extends HttpRequestDecorator implements IAuthenticatedRequest
    {
       @LegacySignature(type = Type.PROPERTY, name = "AuthenticationMethod")
       @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL)
       private character authenticationMethod = TypeFactory.character();

       @LegacySignature(type = Type.PROPERTY, name = "Credentials")
       @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL)
       private object<? extends com.goldencode.p2j.oo.net.http.Credentials> credentials = TypeFactory.object(com.goldencode.p2j.oo.net.http.Credentials.class);

       @LegacySignature(type = Type.PROPERTY, name = "AuthenticationChallenge")
       @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL)
       private character authenticationChallenge = TypeFactory.character();

       private List<object<? extends com.goldencode.p2j.oo.net.http.filter.auth.IauthFilterEventHandler>> listeners;

       @LegacySignature(type = Type.EXECUTE)
       public void __net_http_AuthenticatedRequest_execute__()
       {
          onBlockLevel(Condition.ERROR, Action.THROW);
       }

       @LegacySignature(type = Type.CONSTRUCTOR, parameters =
       {
          @LegacyParameter(name = "poHttpRequest", type = "OBJECT", qualified = "openedge.net.http.ihttprequest", mode = "INPUT")
       })
       @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL)
       public void __net_http_AuthenticatedRequest_constructor__(
                final object<? extends com.goldencode.p2j.oo.net.http.IhttpRequest> _poHttpRequest)
       {
          object<? extends com.goldencode.p2j.oo.net.http.IhttpRequest> poHttpRequest = TypeFactory.initInput(_poHttpRequest);

          internalProcedure(AuthenticatedRequest.class, this, "__net_http_AuthenticatedRequest_constructor__", new Block((Body) () ->
          {
             __net_http_HttpRequestDecorator_constructor__(poHttpRequest);
             this.authenticationMethod.assign(AuthenticationMethodEnum.none);
          }));
       }

       @LegacySignature(type = Type.METHOD, name = "AddAuthentication")
       @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL)
       public void addAuthentication()
       {
          internalProcedure(AuthenticatedRequest.class, this, "AddAuthentication", new Block((Body) () ->
          {
             object<? extends IHttpMessageWriter> writer = AuthenticationRequestWriterBuilder.build(new object(this), _getAuthenticationCallbacks());

             if (writer._isValid() && writer.ref() instanceof AuthenticationRequestFilter)
             {
                AuthenticationRequestFilter authWriter = (AuthenticationRequestFilter) writer.ref();

                authWriter.open();
                authWriter.flush();
                authWriter.close();
             }

             writer.setUnknown();
          }));
       }

       @LegacySignature(type = Type.METHOD, name = "SetChallenge", parameters =
       {
          @LegacyParameter(name = "pcAuthMethod", type = "CHARACTER", mode = "INPUT"),
          @LegacyParameter(name = "pcChallenge", type = "CHARACTER", mode = "INPUT")
       })
       @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL)
       public void setChallenge(final character _pcAuthMethod, final character _pcChallenge)
       {
          character pcAuthMethod = TypeFactory.initInput(_pcAuthMethod);
          character pcChallenge = TypeFactory.initInput(_pcChallenge);

          internalProcedure(AuthenticatedRequest.class, this, "SetChallenge", new Block((Body) () ->
          {
             Assert.notNullOrEmpty(pcAuthMethod, new character("Authentication method"));

             this.authenticationMethod.assign(pcAuthMethod);
             this.authenticationChallenge.assign(pcChallenge);
          }));
       }

       @LegacySignature(type = Type.METHOD, name = "AddAuthenticationCallback", parameters =
       {
          @LegacyParameter(name = "poListener", type = "OBJECT",
                   qualified = "openedge.net.http.filter.auth.iauthfiltereventhandler", mode = "INPUT")
       })
       @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL)
       public void addAuthenticationCallback(
                final object<? extends com.goldencode.p2j.oo.net.http.filter.auth.IauthFilterEventHandler> _poListener)
       {
          object<? extends com.goldencode.p2j.oo.net.http.filter.auth.IauthFilterEventHandler> poListener = TypeFactory.initInput(_poListener);

          internalProcedure(AuthenticatedRequest.class, this, "AddAuthenticationCallback", new Block((Body) () ->
          {
             Assert.notNull(poListener, new character("Listener"));

             if (listeners == null)
             {
                listeners = new ArrayList<object<? extends com.goldencode.p2j.oo.net.http.filter.auth.IauthFilterEventHandler>>();
             }

             if (!listeners.stream().filter(l -> poListener.ref().legacyEquals(l).booleanValue()).findFirst().isPresent())
             {
                // 4GL mambo jambo, some sort of array resize
                int prevSize = listeners.size();
                int idx = 0;

                for (int i = 0; i < prevSize; i++)
                {
                   if (!listeners.get(idx)._isValid())
                   {
                      listeners.remove(idx);
                   }
                   else
                   {
                      idx++;
                   }
                }

                ObjectOps.increment(poListener.ref());
                listeners.add(poListener);

                idx = prevSize + 1 - listeners.size();

                for (int i = 0; i < idx; i++)
                {
                   listeners.add(new ObjectVar(IauthFilterEventHandler.class));
                }
             }

          }));
       }

       @LegacySignature(type = Type.METHOD, name = "RemoveAuthenticationCallback", parameters =
       {
          @LegacyParameter(name = "poListener", type = "OBJECT",
                   qualified = "openedge.net.http.filter.auth.iauthfiltereventhandler", mode = "INPUT")
       })
       @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL)
       public void removeAuthenticationCallback(
                final object<? extends com.goldencode.p2j.oo.net.http.filter.auth.IauthFilterEventHandler> _poListener)
       {
          object<? extends com.goldencode.p2j.oo.net.http.filter.auth.IauthFilterEventHandler> poListener =
                   TypeFactory.initInput(_poListener);

          internalProcedure(AuthenticatedRequest.class, this, "RemoveAuthenticationCallback", new Block((Body) () ->
          {
             if (poListener._isValid() && listeners != null) {
                // TODO: 4GL quirk - just leaves the previous entry only set as null
                // listeners.remove(poListener);
                Iterator<object<? extends IauthFilterEventHandler>> it = listeners.iterator();

                while (it.hasNext())
                {
                   object<? extends IauthFilterEventHandler> listener = it.next();

                   if (listener.ref().legacyEquals(poListener).booleanValue())
                   {
                      listener.setUnknown();
                   }
                }
             }
          }));
       }

       @LegacySignature(returns = "INTEGER", type = Type.METHOD, name = "GetAuthenticationCallbacks", parameters = {
                @LegacyParameter(name = "extpoListeners", type = "OBJECT", extent = -1, qualified = "openedge.net.http.filter.auth.iauthfiltereventhandler", mode = "OUTPUT") })
       @LegacyResourceSupport(supportLvl = CVT_LVL_FULL | RT_LVL_FULL)
       public integer getAuthenticationCallbacks(
                final OutputExtentParameter<object<? extends com.goldencode.p2j.oo.net.http.filter.auth.IauthFilterEventHandler>> _extpoListeners)
       {
          int sz = this.listeners == null ? 0 : this.listeners.size();
          object[] extpoListeners = TypeFactory.initOutput(_extpoListeners, sz);

          return function(AuthenticatedRequest.class, this, "GetAuthenticationCallbacks", integer.class, new Block((Body) () ->
          {
             for (int i = 0; i < extpoListeners.length; i++)
             {
                extpoListeners[i] = this.listeners.get(i);
             }

             returnNormal(extpoListeners.length == 0 ? new integer() : new integer(extpoListeners.length));
          }));
       }

       private object<? extends IauthFilterEventHandler>[] _getAuthenticationCallbacks()
       {
          int size = this.listeners == null ? 0 : this.listeners.size();
          object<? extends IauthFilterEventHandler>[] listeners =
             TypeFactory.objectExtent(size, IauthFilterEventHandler.class, false);

          for (int i = 0; i < listeners.length; i++)
          {
             listeners[i].assign(this.listeners.get(i));
          }

          return listeners;
       }

       @LegacySignature(returns = "CHARACTER", type = Type.GETTER, name = "AuthenticationMethod")
       @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL)
       public character getAuthenticationMethod()
       {
          return function(AuthenticatedRequest.class, this, "AuthenticationMethod", character.class, new Block((Body) () ->
          {
             returnNormal(authenticationMethod);
          }));
       }

       @LegacySignature(returns = "OBJECT", qualified = "OpenEdge.Net.HTTP.Credentials", type = Type.GETTER, name = "Credentials")
       @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL)
       public object<? extends com.goldencode.p2j.oo.net.http.Credentials> getCredentials()
       {
          return function(AuthenticatedRequest.class, this, "Credentials", object.class, new Block((Body) () ->
          {
             returnNormal(credentials);
          }));
       }

       @LegacySignature(type = Type.SETTER, name = "Credentials", parameters =
       {
          @LegacyParameter(qualified = "OpenEdge.Net.HTTP.Credentials", name = "var", type = "OBJECT", mode = "INPUT")
       })
       @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL)
       public void setCredentials(final object<? extends com.goldencode.p2j.oo.net.http.Credentials> _var)
       {
          object<? extends com.goldencode.p2j.oo.net.http.Credentials> var = TypeFactory.initInput(_var);

          internalProcedure(AuthenticatedRequest.class, this, "Credentials", new Block((Body) () ->
          {
             credentials.assign(var);
          }));
       }

       @LegacySignature(returns = "CHARACTER", type = Type.GETTER, name = "AuthenticationChallenge")
       @LegacyResourceSupport(supportLvl = CVT_LVL_FULL|RT_LVL_FULL)
       public character getAuthenticationChallenge()
       {
          return function(AuthenticatedRequest.class, this, "AuthenticationChallenge", character.class, new Block((Body) () ->
          {
             returnNormal(authenticationChallenge);
          }));
       }

    }