Ich muss auf den asynchronen API-Rückruf warten, bevor ich in Java von der Methode zurückkehre

  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, ich habe versucht, hier nur die minimale Menge an Code einzuschließen. Es gibt drei interessante Klassen: UserSession ist der interne Klebstoff zwischen dem Jetty-Handler und der QuickFix / j-Anwendung.

Der LogonHandler empfängt eine HTTP-Anmeldeanforderung und versucht, einen Benutzer bei einer QuickFix / j-Anwendungssitzung anzumelden.

QuickFix / j sendet eine Anmeldemeldung an einen FIX-Server. Diese Anmeldeanforderung / -antwort ist asynchron. Die HTTP-Anmeldeanforderung ist natürlich synchron. Wir müssen also auf die Antwort vom FIX-Server warten, bevor wir von der HTTP-Anfrage zurückkehren. Ich mache dies mit CountDownLatch und diesem UserSession-Objekt.

Wenn ich das QuickFix / j-Sitzungsobjekt erstelle, erstelle ich auch ein UserSession-Objekt und füge es einer Map hinzu (dies geschieht in der LogonHandler-Anmeldemethode).

Das QuickFix / j-Anwendungsobjekt enthält zwei Rückrufe: toAdmin () und fromAdmin (). In fromAdmin () überprüfe ich, ob es sich bei der Nachricht um eine Anmeldeantwort handelt und ob es sich um eine Methode von UserSession zum Countdown des Latch handelt. Beim Debuggen des Codes sehe ich, dass die fromAdmin () -Methode getroffen wird, das UserSession-Objekt in der Map gefunden wird und die countdown () -Methode aufgerufen wird und die latch.getCount () von 1 auf 0 geht, aber die latch.await ( ) Methode in UserSession wait () gibt nie zurück. Es kommt immer mal raus.

Antworten auf die Frage(1)

Ihre Antwort auf die Frage