61.6. 엔터티 리더 인터셉터

61.6.1. 개요

이 섹션에서는 클라이언트 측 또는 서버 측에서 메시지 본문을 읽을 때 입력 스트림을 가로채는 데 사용할 수 있는 엔터티 리더 인터셉터 를 구현하고 등록하는 방법을 설명합니다. 이는 일반적으로 암호화 및 암호 해독 또는 압축 해제와 같은 요청 본문의 일반적인 변환에 유용합니다.

61.6.2. ReaderInterceptor 인터페이스

javax.ws.rs.ext.ReaderInterceptor 인터페이스는 다음과 같이 정의됩니다.

// Java
...
package javax.ws.rs.ext;

public interface ReaderInterceptor {
    public Object aroundReadFrom(ReaderInterceptorContext context)
            throws java.io.IOException, javax.ws.rs.WebApplicationException;
}

reader Interceptor 인터페이스를 구현하면 서버 측 또는 클라이언트 측에서 읽는 중에 메시지 본문(Entity object)을 가로챌 수 있습니다. 다음 컨텍스트 중 하나에서 엔터티 리더 인터셉터를 사용할 수 있습니다.

  • 서버 측인터셉터로 바인딩된 경우 엔터티 판독기 인터셉터는 애플리케이션 코드(일치된 리소스의)에서 액세스될 때 요청 메시지 본문을 인터셉트합니다. REST 요청의 의미 체계에 따라 일치된 리소스에서 메시지 본문에 액세스하지 못할 수 있습니다. 이 경우 reader 인터셉터는 호출되지 않습니다.
  • 클라이언트 쪽인터셉터로 바인딩된 경우 엔터티 판독기 인터셉터는 클라이언트 코드에서 액세스될 때 응답 메시지 본문을 인터셉트합니다. 클라이언트 코드가 응답 메시지에 명시적으로 액세스하지 않는 경우(예: Response.getEntity 메서드를 호출하여) reader 인터셉터가 호출되지 않습니다.

61.6.3. ReaderInterceptorContext 인터페이스

readerInterceptor의 aroundReadFrom 방법은 메시지 본문(Entity object) 및 메시지 메타데이터 모두에 액세스하는 데 사용할 수 있는 javax.ws.rs.ext. ReaderInterceptor Context 유형의 하나의 인수를 수신합니다.

reader InterceptorContext 인터페이스는 다음과 같이 정의됩니다.

// Java
...
package javax.ws.rs.ext;

import java.io.IOException;
import java.io.InputStream;

import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.MultivaluedMap;

public interface ReaderInterceptorContext extends InterceptorContext {

    public Object proceed() throws IOException, WebApplicationException;

    public InputStream getInputStream();

    public void setInputStream(InputStream is);

    public MultivaluedMap<String, String> getHeaders();
}

61.6.4. InterceptorContext 인터페이스

ReaderInterceptorContext 인터페이스는 기본 InterceptorContext 인터페이스에서 상속된 메서드도 지원합니다.

InterceptorContext 인터페이스는 다음과 같이 정의됩니다.

// Java
...
package javax.ws.rs.ext;

import java.lang.annotation.Annotation;
import java.lang.reflect.Type;
import java.util.Collection;

import javax.ws.rs.core.MediaType;

public interface InterceptorContext {

    public Object getProperty(String name);

    public Collection<String> getPropertyNames();

    public void setProperty(String name, Object object);

    public void removeProperty(String name);

    public Annotation[] getAnnotations();

    public void setAnnotations(Annotation[] annotations);

    Class<?> getType();

    public void setType(Class<?> type);

    Type getGenericType();

    public void setGenericType(Type genericType);

    public MediaType getMediaType();

    public void setMediaType(MediaType mediaType);
}

61.6.5. 클라이언트 측에서의 샘플 구현

클라이언트 측에 대해 엔터티 리더 인터셉터를 구현하려면 ReaderInterceptor 인터페이스를 구현하는 클래스를 정의합니다.

예를 들어 다음 코드는 클라이언트 측의 엔티티 리더 인터셉터의 예를 보여줍니다(우선 10 우선 순위 10임)는 들어오는 응답의 메시지 본문에서 company _NAME 의 모든 인스턴스를 Red Hat 으로 대체합니다.

// Java
package org.jboss.fuse.example;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;

import javax.annotation.Priority;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.ext.ReaderInterceptor;
import javax.ws.rs.ext.ReaderInterceptorContext;

@Priority(value = 10)
public class SampleClientReaderInterceptor implements ReaderInterceptor {

  @Override
  public Object aroundReadFrom(ReaderInterceptorContext interceptorContext)
          throws IOException, WebApplicationException
  {
    InputStream inputStream = interceptorContext.getInputStream();
    byte[] bytes = new byte[inputStream.available()];
    inputStream.read(bytes);
    String responseContent = new String(bytes);
    responseContent = responseContent.replaceAll("COMPANY_NAME", "Red Hat");
    interceptorContext.setInputStream(new ByteArrayInputStream(responseContent.getBytes()));

    return interceptorContext.proceed();
  }
}

61.6.6. 서버 측에서의 샘플 구현

서버 측에 엔터티 리더 인터셉터를 구현하려면 ReaderInterceptor 인터페이스를 구현하고 @Provider 주석으로 주석을 추가하는 클래스를 정의합니다.

예를 들어 다음 코드는 들어오는 요청의 메시지 본문에서 company _NAME 의 모든 인스턴스를 Red Hat 으로 대체하는 서버 측의 엔터티 reader 인터셉터의 예를 보여줍니다.

// Java
package org.jboss.fuse.example;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;

import javax.annotation.Priority;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.ext.Provider;
import javax.ws.rs.ext.ReaderInterceptor;
import javax.ws.rs.ext.ReaderInterceptorContext;

@Priority(value = 10)
@Provider
public class SampleServerReaderInterceptor implements ReaderInterceptor {

  @Override
  public Object aroundReadFrom(ReaderInterceptorContext interceptorContext)
          throws IOException, WebApplicationException {
    InputStream inputStream = interceptorContext.getInputStream();
    byte[] bytes = new byte[inputStream.available()];
    inputStream.read(bytes);
    String requestContent = new String(bytes);
    requestContent = requestContent.replaceAll("COMPANY_NAME", "Red Hat");
    interceptorContext.setInputStream(new ByteArrayInputStream(requestContent.getBytes()));

    return interceptorContext.proceed();
  }
}

61.6.7. 클라이언트 측에서 리더 인터셉터 바인딩

JAX-RS 2.0 클라이언트 API를 사용하여 javax.ws.rs.client.Client 오브젝트 또는 javax.ws.client. WebTarget 오브젝트에 엔터티 리더 인터셉터를 직접 등록할 수 있습니다. 즉, reader 인터셉터를 선택적으로 다른 범위에 적용할 수 있으므로 인터셉터의 특정 URI 경로만 영향을 받습니다.

예를 들어 다음 코드는 client 오브젝트를 사용하여 수행된 모든 호출에 적용되도록 SampleClientReaderInterceptor 인터셉터를 등록하는 방법을 보여줍니다.

// Java
...
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.Invocation;
import javax.ws.rs.client.WebTarget;
import javax.ws.rs.core.Response;
...
Client client = ClientBuilder.newClient();
client.register(SampleClientReaderInterceptor.class);

JAX-RS 2.0 클라이언트를 사용하여 인터셉터를 등록하는 방법에 대한 자세한 내용은 49.5절. “클라이언트 끝점 구성” 을 참조하십시오.

61.6.8. 서버 측에서 리더 인터셉터 바인딩

서버 측의 reader 인터셉터를 바인딩 하려면 (즉, Apache CXF 런타임에 설치) 다음 단계를 수행합니다.

  1. 다음 코드 조각에 표시된 대로 reader 인터셉터 클래스에 @Provider 주석을 추가합니다.

    // Java
    package org.jboss.fuse.example;
    ...
    import javax.annotation.Priority;
    import javax.ws.rs.WebApplicationException;
    import javax.ws.rs.ext.Provider;
    import javax.ws.rs.ext.ReaderInterceptor;
    import javax.ws.rs.ext.ReaderInterceptorContext;
    
    @Priority(value = 10)
    @Provider
    public class SampleServerReaderInterceptor implements ReaderInterceptor {
      ...
    }

    reader 인터셉터 구현이 Apache CXF 런타임에 로드되면 REST 구현에서 로드된 클래스를 자동으로 검사하여 @Provider 주석( 스캔 단계)으로 표시된 클래스를 검색합니다.

  2. XML에서 JAX-RS 서버 엔드포인트를 정의할 때(예: 18.1절. “JAX-RS Server 엔드 포인트 구성”참조), jaxrs:providers 요소의 공급자 목록에 reader 인터셉터를 추가합니다.

    <blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns:jaxrs="http://cxf.apache.org/blueprint/jaxrs"
        xmlns:cxf="http://cxf.apache.org/blueprint/core"
        ...
    >
        ...
        <jaxrs:server id="customerService" address="/customers">
          ...
          <jaxrs:providers>
            <ref bean="interceptorProvider" />
          </jaxrs:providers>
          <bean id="interceptorProvider" class="org.jboss.fuse.example.SampleServerReaderInterceptor"/>
    
        </jaxrs:server>
    
    </blueprint>
    참고

    이 단계는 Apache CXF의 비표준 요구 사항입니다. JAX-RS 표준에 따르면 @Provider 주석은 인터셉터를 바인딩하는 데 필요한 모든 주석이어야 합니다. 그러나 실제로는 표준 접근 방식은 다소 무독하며 많은 라이브러리가 대규모 프로젝트에 포함될 때 번들링 공급자로 이어질 수 있습니다.