2017-09-05 7 views
0

네트워크의 다른 호스트 (ssh-tunnel을 통해 dev-pc, 직접 연결을 통해 jenkins-server)에서 동일한 RMI 서버에 액세스하려고합니다. 문제는 RMI 호스트가 다른 클라이언트 호스트의 다른 이름으로 알려져 있다는 것입니다.RMI 스터브 : 클라이언트 측에서 호스트 값 강제

Registry registry = LocateRegistry.getRegistry("hostname", 10099, new CustomSslRMIClientSocketFactory()); 

그러나 우리는 다음과 같은 원격 객체를 조회 할 때, 그것은 잘못된 호스트 이름을 포함 : 우리가 레지스트리에 연결할 때 우리는이 같은 대상 호스트 이름을 설정할 수 있기 때문에

이것은 문제가되지 않습니다. 스텁에 내가 호스트가 레지스트리 객체에 같은 필요하다는 것을 관찰 할 수 디버거에서

HelloRemote hello = (HelloRemote) registry.lookup(HelloRemote.class.getSimpleName()); 

,하지만 우리는의 메소드를 부르는 debugger view on registry and stub

우리는 즉시 연결 시간 초과를 얻을 수 그루터기. 디버거에서 수동으로 호스트 값을 localhost으로 변경하면 메서드 호출이 성공합니다.

나는 서버 측에 java.rmi.server.hostname을 설정할 수 있지만 젠킨스와의 연결은 더 이상 작동하지 않는다는 것을 알고 있습니다. 가장 간단한 해결책은 RMI가 해당 레지스트리에서 검색 한 모든 스텁에 대해 레지스트리와 동일한 호스트를 사용하도록 강제하는 것입니다. 리플렉션을 통해 스텁의 호스트 값을 바꾸는 것보다 나은 방법이 있습니까?

답변

0

불행히도 RMI는 서버 호스트가 하나의 '가장 공개 된'IP 주소 또는 호스트 이름을 가지고 있음을 기본적으로 전제로합니다. 이는 java.rmi.server.hostname 실패를 설명합니다. 시스템이 준수하지 않으면 운이 없어진 것입니다.

0

EJP가 지적한 바와 같이 세련된 out-of-the-box 솔루션은없는 것처럼 보입니다. 나는 두 unelegant 것을 생각할 수 있습니다 :

  1. 대신 localhost에 비 도달 IP 트래픽을 리디렉션하기 위해 모든 클라이언트 호스트에서 네트워크 구성을 변경.
  2. Reflection을 통해 "hello"개체의 호스트 값을 변경합니다.

테스트 환경에 있고 문제의 코드가 생산적이지 않기 때문에 두 번째 옵션으로갔습니다. 이 코드는 Java의 이후 버전에서 중단 될 수 있으며 보안 관리자가있는 경우에는 작동하지 않으므로 달리 수행하지 않는 것이 좋습니다.

그러나, 여기 내 작업 코드 :

private static void forceRegistryHostNameOnStub(Object registry, Object stub) { 
    try { 
     String regHost = getReferenceToInnerObject(registry, "ref", "ref", "ep", "host").toString(); 

     Object stubEp = getReferenceToInnerObject(stub, "h", "ref", "ref", "ep"); 
     Field fStubHost = getInheritedPrivateField(stubEp, "host"); 
     fStubHost.setAccessible(true); 
     fStubHost.set(stubEp, regHost); 
    } catch (Exception e) { 
     LOG.error("Applying the registry host to the Stub failed.", e); 
    } 
} 

private static Object getReferenceToInnerObject(Object from, String... objectHierarchy) throws NoSuchFieldException, IllegalArgumentException, IllegalAccessException { 
    Object ref = from; 
    for (String fieldname : objectHierarchy) { 
     Field f = getInheritedPrivateField(ref, fieldname); 
     f.setAccessible(true); 
     ref = f.get(ref); 
    } 
    return ref; 
} 

private static Field getInheritedPrivateField(Object from, String fieldname) throws NoSuchFieldException { 
    Class<?> i = from.getClass(); 
    while (i != null && i != Object.class) { 
     try { 
      return i.getDeclaredField(fieldname); 
     } catch (NoSuchFieldException e) { 
      // ignore 
     } 
     i = i.getSuperclass(); 
    } 
    return from.getClass().getDeclaredField(fieldname); 
} 

스텁에 메소드 호출은 지금 성공 :

Registry registry = LocateRegistry.getRegistry("hostname", 10099, new CustomSslRMIClientSocketFactory()); 
HelloRemote hello = (HelloRemote) registry.lookup(HelloRemote.class.getSimpleName()); 
forceRegistryHostNameOnStub(registry, hello); // manipulate the stub 
hello.doSomething(); // succeeds