2013-02-18 15 views
18
import java.util.concurrent.CountDownLatch; 

    import quickfix.Initiator; 


    public class UserSession { 
    private final CountDownLatch latch = new CountDownLatch(1); 

public String await() { 
     try { 
      System.out.println("waiting..."); 
      if (latch.await(5, TimeUnit.SECONDS)) 
       System.out.println("released!"); 
      else 
       System.out.println("timed out"); 
      return secret; 
     } catch (InterruptedException e) { 
      // TODO Auto-generated catch block 
      System.out.println(e.getMessage()); 
      e.printStackTrace(); 
     } 
     return null; 
    } 

    public void countdown(String s) { 
     System.out.println("In countdown: "+s+ ". Latch count: "+latch.getCount()); 
     secret = s; 
     latch.countDown(); 
     System.out.println("Latch count: "+latch.getCount()); 
    } 
    } 


    public class LogonHandler extends AbstractHandler { 

    public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) 
     throws IOException, ServletException 
     { 
      Map<String,String[]> query = request.getParameterMap(); 

      if (query.containsKey("method")) { 
       if (query.get("method")[0].compareTo(method) == 0) { 
        baseRequest.setHandled(true); 
        response.getWriter().println(logon(query)); 
       } 
      } 
      else 
       baseRequest.setHandled(false); 
     } 

    private String logon(Map<String,String[]> query) { 
     if (query.containsKey("username") && query.containsKey("password") &&   query.containsKey("sendercompid")) { 

      app.mapUser(query.get("sendercompid")[0], new UserSession(query.get("username")[0], query.get("password")[0])); 

      SessionID session = new SessionID(new BeginString("FIX.4.4"), new SenderCompID(query.get("sendercompid")[0]), new TargetCompID("PARFX")); 

      try { 
       ThreadedSocketInitiator tsi = new ThreadedSocketInitiator(app, app.getFileStoreFactory(), settings, app.getLogFactory(), app.getMessageFactory()); 
       UserSession userSession = new UserSession(query.get("username")[0], query.get("password")[0]); 
       userSession.setInitiator(tsi); 

       tsi.start(); 
       return userSession.await(); 
      } catch (ConfigError e) { 
       // TODO Auto-generated catch block 
       e.printStackTrace(); 
       return e.toString(); 
      } 
     } 
     return "fail"; 
    } 
    } 


public class QuickfixjApplication implements Application { 
    private Map<String,UserSession> users = new HashMap<String,UserSession>(); 

    public void mapUser(String s, UserSession u) { 
     users.put(s, u); 
    } 

    public void toAdmin(Message message, SessionID sessionId) { 

     try { 
      if (message.getHeader().getField(new StringField(MsgType.FIELD)).valueEquals(Logon.MSGTYPE)) { 
       UserSession user = users.get(sessionId.getSenderCompID()); 
       message.setField(new Username(user.getUsername())); 
       message.setField(new Password(user.getPassword())); 
      } 
     } catch (FieldNotFound e) { 
      e.printStackTrace(); 
     } 
    } 

    public void fromAdmin(Message message, SessionID sessionId) 
     throws FieldNotFound, IncorrectDataFormat, IncorrectTagValue, RejectLogon { 

     if (message.getHeader().getField(new StringField(MsgType.FIELD)).valueEquals(Logon.MSGTYPE)) { 
      System.out.println(message.toString()); 
      UserSession user = users.get(sessionId.getSenderCompID()); 
      user.countdown(message.toString()); 
     } 
    } 
} 

Ok, starałem się tylko zawierać minimalną ilość kodu tutaj. Istnieją trzy interesujące klasy, UserSession jest wewnętrznym klejem pomiędzy obsługą Jetty i aplikacją QuickFix/j.trzeba czekać na asynchronicznym api zwrotnego zanim wrócę z metody w Javie

LogonHandler odbiera żądanie logowania HTTP i próbuje zalogować użytkownika do sesji aplikacji QuickFix/j.

QuickFix/j wysyła komunikat logowania na serwer FIX, to żądanie/odpowiedź logowania jest asynchroniczne. Żądanie logowania HTTP jest oczywiście synchroniczne. Musimy więc poczekać na odpowiedź z serwera FIX, zanim powrócimy z żądania HTTP. Robię to za pomocą CountDownLatch i tego obiektu UserSession.

Po utworzeniu obiektu sesji QuickFix/j utworzę również obiekt UserSession i dodaję go do mapy (dzieje się to w metodzie logowania LogonHandler).

Istnieją dwa wywołania zwrotne w obiekcie aplikacji QuickFix/j, toAdmin() i odAdmin(). W funkcji fromAdmin() sprawdzam, czy komunikat jest odpowiedzią logowania, a jeśli tak, to nazywam metodę UserSession, aby odliczać zatrzask. Podczas debugowania kodu widzę, że została wywołana metoda fromAdmin(), obiekt UserSession znajduje się na mapie i wywoływana jest metoda odliczania(), a funkcja latch.getCount() przechodzi od 1 do 0, ale funkcja latch.await () metoda w UserSession czeka() nigdy nie wraca. Zawsze przekracza limit czasu.

Odpowiedz

36

Można użyć CountDownLatch takiego:

public class LogonHandler implements Handler { 
    private final CountDownLatch loginLatch = new CountDownLatch (1); 

    private boolean callbackResults; 

    public void serverResponseCallback(boolean result) { 
     callbackResults = result; 
     loginLatch.countDown(); 
    } 

    public boolean tryLogon(Credentials creds) throws InterruptedException { 
     SomeServer server = new SomeServer(address); 
     server.tryLogon (creds.getName(), creds.getPass()); 
     loginLatch.await(); 
     return callbackResults; 
    } 
} 

Jeśli chcesz ograniczyć czas oczekiwania, na przykład, 5 sekund, a następnie zamiast loginLatch.await() użyć następujących:

if (loginLatch.await (5L, TimeUnit.SECONDS)) 
    return callbackResults; 
else 
    return false; // Timeout exceeded 
+0

Thanks Michaił właśnie tego próbowałem. LoginLatch.count() przechodzi do 0, ale funkcja wait() nigdy się nie zwalnia. – shaz

+0

@shaz 'CountDownLatch' powinien działać. Prawdopodobnie błąd znajduje się w innym miejscu kodu. Czy mógłbyś opublikować swój kod z 'CountDownLatch' tutaj? –

+0

Kod opublikowany powyżej. Dzięki. – shaz

Powiązane problemy