Tomcat servlet 上的 Firebase admin sdk

Firebase admin sdk on Tomcat servlet

我想做的事情:

我正在为 java 使用 tomcat v8.5.3 和 Firebase Admin SDK v6.8.1。

上图是我想要做的。

但是我在将请求从 servlet 转发到 jsp

时遇到了问题

这是servletA的doPost代码。

protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

    if(FirebaseApp.getApps().isEmpty()) {
        FirebaseOptions options = (FirebaseOptions)getServletContext().getAttribute("options");
        FirebaseApp.initializeApp(options);
    }

    dispatcher = request.getRequestDispatcher("/b.jsp");

    try {
        process(request, response);
    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (ParseException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

    Ref.addListenerForSingleValueEvent(new ValueEventListener() {

        @Override
        public void onDataChange(DataSnapshot snapshot) {
            for(DataSnapshot item: snapshot.getChildren()) {
                couponList.add(item.getValue(CouponItem.class));
            }

            request.setAttribute("bodyObject", requestBody);
            try {
                dispatcher.forward(request, response);
            } catch (ServletException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }

        }

        @Override
        public void onCancelled(DatabaseError error) {
            // TODO Auto-generated method stub

        }});
}


protected void process(HttpServletRequest request, HttpServletResponse response) 
    throws IOException, ParseException{

    initMember();

    //requestBodyString = getBody(request);
    requestBodyString = (String) request.getParameter("body");

    JSONParser parser = new JSONParser();
    JSONObject jobj = (JSONObject) parser.parse(requestBodyString);

    convert(jobj, requestBody);

    Ref = FirebaseDatabase.getInstance().getReference("Coupon").child(requestBody.getRequestId());

}

在ValueEventListener的onDataChange中,dispatcher forward不起作用

我发现当代码从

变为 Ref.addListenerForSingleValueEvent 时守护线程发生了变化
Daemon Thread [http-nio-8080-exec-5] (Suspended (breakpoint at line 67 in ServletA))    
owns: NioEndpoint$NioSocketWrapper  (id=426)    
ServletA.doPost(HttpServletRequest, HttpServletResponse) line: 67   
ServletA(HttpServlet).service(HttpServletRequest, HttpServletResponse) line: 660    
ServletA(HttpServlet).service(ServletRequest, ServletResponse) line: 741    
ApplicationFilterChain.internalDoFilter(ServletRequest, ServletResponse) line: 231  
ApplicationFilterChain.doFilter(ServletRequest, ServletResponse) line: 166  
WsFilter.doFilter(ServletRequest, ServletResponse, FilterChain) line: 52    
ApplicationFilterChain.internalDoFilter(ServletRequest, ServletResponse) line: 193  
ApplicationFilterChain.doFilter(ServletRequest, ServletResponse) line: 166  
StandardWrapperValve.invoke(Request, Response) line: 199    
StandardContextValve.invoke(Request, Response) line: 96 
NonLoginAuthenticator(AuthenticatorBase).invoke(Request, Response) line: 493    
StandardHostValve.invoke(Request, Response) line: 137   
ErrorReportValve.invoke(Request, Response) line: 81 
AccessLogValve(AbstractAccessLogValve).invoke(Request, Response) line: 660  
StandardEngineValve.invoke(Request, Response) line: 87  
CoyoteAdapter.service(Request, Response) line: 343  
Http11Processor.service(SocketWrapperBase<?>) line: 798 
Http11Processor(AbstractProcessorLight).process(SocketWrapperBase<?>, SocketEvent) line: 66 
AbstractProtocol$ConnectionHandler<S>.process(SocketWrapperBase<S>, SocketEvent) line: 808  
NioEndpoint$SocketProcessor.doRun() line: 1498  
NioEndpoint$SocketProcessor(SocketProcessorBase<S>).run() line: 49  
ThreadPoolExecutor(ThreadPoolExecutor).runWorker(ThreadPoolExecutor$Worker) line: 1149  
ThreadPoolExecutor$Worker.run() line: 624   
TaskThread$WrappingRunnable.run() line: 61  
TaskThread(Thread).run() line: 748  

Daemon Thread [firebase-database-event-target] (Suspended (breakpoint at line 87 in ServletA))    
ServletA.onDataChange(DataSnapshot) line: 87  
Query.onDataChange(DataSnapshot) line: 182    
ValueEventRegistration.fireEvent(DataEvent) line: 77    
DataEvent.fire() line: 65   
EventRaiser.run() line: 55    
Executors$RunnableAdapter<T>.call() line: 511   
ScheduledThreadPoolExecutor$ScheduledFutureTask<V>(FutureTask<V>).run() line: 266   
ScheduledThreadPoolExecutor$ScheduledFutureTask<V>.access1(ScheduledThreadPoolExecutor$ScheduledFutureTask) line: 180    
ScheduledThreadPoolExecutor$ScheduledFutureTask<V>.run() line: 293  
FirebaseScheduledExecutor(ThreadPoolExecutor).runWorker(ThreadPoolExecutor$Worker) line: 1149   
ThreadPoolExecutor$Worker.run() line: 624   
Thread.run() line: 748  

我认为我在 Tomcat 和 Java 方面的经验不足以解决这个问题。

数据库事件侦听器在单独的线程上运行。您不能对其执行转发或任何响应操作,因为请求线程在您调用 addListenerForSingleValueEvent() 后立即退出。您需要以某种方式停止请求线程退出,直到您的事件侦听器被执行。 CountDownLatch 可能是最简单的方法。

final CountDownLatch latch = new CountDownLatch(1);
ref.addListenerForSingleValueEvent(new ValueEventListener() {
  @Override
  public void onDataChange(DataSnapshot snapshot) {
    latch.countDown();
  }

  @Override
  public void onCancelled(DatabaseError error) {
    latch.countDown();
  }
});

// Wait for the callbacks to fire
latch.await();

// Send response