ServiceEndpoint Mapping

BXM 3.0에서는 통신프로토콜별로 다르게 적용되는 처리와 ServiceEndpoint로 입력데이터를 전달하기 전에 처리되어야 하는 로직을 ServiceEndpointMapping 클래스에서 처리하고 ServiceEndpoint는 입력/응답전문에 대한 객체 변화 및 서비스호출을 담당한다. 기본버전에서는 DefaultHttpServiceEndpointMapping과 GenericServiceEndpoint가 각각 ServiceEndpointMapping과 ServiceEndpoint역할을 수행한다. ServiceEndpointMapping의 경우 JEUS의 TCPServlet을 사용하게 되는 것과 같이 통신프로토콜이 달라지게 되게 사용자 환경에 맞게 작성되어야 한다.

1. ServiceEndpointMapping 구현

ServiceEndpointMapping 구현체는 통신프로토콜별로 구현클래스가 달라질 수 있다. HTTP인 경우는 HttpServlet, JEUS TCPServlet인 경우는 TCPServlet 및 TCPServlet관련클래스들을 구현한다. default extension에서 제공하는 DefaultHttpServiceEndpointMapping은 HttpServlet으로 구현되었으며 본 문서에서는 HttpServlet을 기준으로 설명한다.

1.1. 초기화

HttpServlet의 init()를 사용한다. ServiceEndpoint가 사용할 환경변수를 초기화 하는 작업을 수행한다.

…
    @SuppressWarnings( "serial")
    @Override
    public void init() throws ServletException
    {
        super.init();
        this.container= (ApplicationContainer)getServletContext().getAttribute( EndpointContextListener.FRAMEWORK_INSTANCE);

        if( this.container== null)
        {
            getServletContext().log( "framework instance preparation is failed.");
            logger.error( "framework instance preparation is failed.");
        }

        String encodingParam= getServletConfig().getInitParameter( "fld-encoding");
        if( StringUtils.hasText( encodingParam))    fldEncoding= encodingParam;

        try
        {
            suffixs= new HashMap<EndpointMessageType, Pattern>(){{
                put( EndpointMessageType.FLD, Pattern.compile( "(.*)(.fld)$"));
                put( EndpointMessageType.BINARY, Pattern.compile( "(.*)(.bin)$"));
                put( EndpointMessageType.JSON, Pattern.compile( "(.*)(.json)$"));
                put( EndpointMessageType.SERIALIZED_OBJ, Pattern.compile( "(.*)(.obj)$"));
                put( EndpointMessageType.XML, Pattern.compile( "(.*)(.xml)$"));
            }};

            serviceEndpoint = new GenericServiceEndpoint(); (1)
            serviceEndpoint.init(container);

            //service executor interceptor 초기화
            serviceExecutorInterceptor = (ServiceExecutorInterceptor) Thread.currentThread().getContextClassLoader().loadClass(container.getServiceExecutorInterceptorClassName()).newInstance();
            DefaultServiceExecutor.setServiceExecutorInterceptor(serviceExecutorInterceptor);   (2)
        }
        catch( Throwable e)
        {
            getServletContext().log( "HttpServiceEndpointMapping preparation is failed.", e);
            logger.error( "HttpServiceEndpointMapping preparation is failed.", e);
        }

    }
1 GenericServiceEndpoint객체를 초기화하고 Framework객체를 넘겨주어 ServiceEndpoint환경변수를 설정한다.
2 서비스연동시 사용될 ServiceExecutor객체를 초기화하여 DefaultServiceExecutor에 설정한다. SeriveExecutorInterceptor에 대한 설명은 다른 장에서 진행한다.

1.2. ServiceEndpoint호출

HttpServlet의 service()메소드를 이용하여 ServiceEndpoint를 호출한다.

아래의 예제는 ServiceEndpoint를 호출하는 기본적인 예제이다.

…
    @Override
    protected void service( HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
    {
        request.getSession( true);

        logger.trace( "using init-param config fld-encoding [{}].", fldEncoding);
        logger.trace( "request content length [{}], requestURI [{}].", request.getContentLength(), request.getRequestURI());

        EndpointMessageType messageType= null;
        for( Map.Entry<EndpointMessageType, Pattern> requestPattern: suffixs.entrySet())
        {
            if( requestPattern.getValue().matcher( request.getRequestURI()).matches())
            {
                messageType= requestPattern.getKey();
                break;
            }
        }

        if( messageType== null)
        {
            throw new InvalidRequestMessageException( "invalid request url");
        }


        if( messageType == EndpointMessageType.FLD && request.getContentLength()> MessageDefinitions.MAX_REQUEST_MESSAGE_LENGTH)
        {
            throw new EndpointLimitExceededException( "endpoint input stream is over the limit",
                    MessageDefinitions.MAX_REQUEST_MESSAGE_LENGTH);
        }

        serviceEndpoint.doService(request.getInputStream(), response.getOutputStream(), messageType,
                fldEncoding, request.getRemoteAddr(), request.getLocale(),
                MessageDefinitions.MAX_REQUEST_MESSAGE_LENGTH);
    }

단, FLD전문을 사용하는 경우 GUID, 거래코드의 위치를 알면 전문 파싱단계부터 특정거래에 대한 GUID를 로그에 출력할 수 있어 디버그작업에 도움을 줄수 있다. 아래의 예제에서는 GUID, 거래코드를 추출하여 log4j의 MDC에 등록하여 로그출력에 활용할 수 있도록 하였다. 보다 자세한 Sample은 bxm.default.extension의 bxm.dft.service.endpoint.http.DefaultHttpServiceEndpointMapping를 참고한다.

…
    @Override
    protected void service( HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
    {
        ...

            // log출력을 위한 MDC정보를 저장한다.
            LogUtils.putPidAtMDC(DefaultSystemUtils.getPid());
            String guid = null;
            String trxCd = null;
            if (EndpointMessageType.FLD == messageType)
            {
                byte [] guidb = new byte[MessageDefinitions.LEN_GUID];
                byte [] trxCdb = new byte[MessageDefinitions.LEN_TRX_CD];
                System.arraycopy(reqDatab,
                                 MessageDefinitions.SYSTEM_HEADER_MSGLEN_LENGTH ,
                                 guidb, 0, MessageDefinitions.LEN_GUID);
                System.arraycopy(reqDatab,
                        MessageDefinitions.SYSTEM_HEADER_MSGLEN_LENGTH + MessageDefinitions.LEN_GUID,
                         trxCdb, 0, MessageDefinitions.LEN_TRX_CD);
                guid = new String(guidb, fldEncoding);
                trxCd = new String(trxCdb, fldEncoding);

                LogUtils.putGuidAtMDC(guid);
                LogUtils.putTrxCdAtMDC(trxCd);
            }

            // ServiceEndpoint를 호출한다.
            if (EndpointMessageType.FLD== messageType)
            {
                int inputMsgSize = reqDatab.length;
                byte[] inputMsgb = new byte[inputMsgSize];
                System.arraycopy(reqDatab, 0, inputMsgb, 0 , reqDatab.length);
                serviceEndpoint.doService(inStream, response.getOutputStream(), messageType,
                        fldEncoding, request.getRemoteAddr(), request.getLocale(),
                        MessageDefinitions.MAX_REQUEST_MESSAGE_LENGTH, inputMsgb);

            }
            else
            {
                serviceEndpoint.doService(inStream, response.getOutputStream(), messageType,
                        fldEncoding, request.getRemoteAddr(), request.getLocale(),
                        MessageDefinitions.MAX_REQUEST_MESSAGE_LENGTH);
            }
        ...
    }

Copyright© Bankwareglobal All Rights Reserved.