1 /*
2  * Copyright (C) 2017 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.googlecode.android_scripting.event;
18 
19 import com.googlecode.android_scripting.Log;
20 import com.googlecode.android_scripting.SimpleServer;
21 import com.googlecode.android_scripting.jsonrpc.JsonBuilder;
22 
23 import java.io.BufferedReader;
24 import java.io.IOException;
25 import java.io.PrintWriter;
26 import java.net.InetSocketAddress;
27 import java.net.Socket;
28 import java.util.Vector;
29 import java.util.concurrent.CountDownLatch;
30 
31 import org.json.JSONException;
32 
33 /**
34  * An Event Forwarding server that forwards events from the rpc queue in realtime to listener
35  * clients.
36  *
37  */
38 public class EventServer extends SimpleServer implements EventObserver {
39   private static final Vector<Listener> mListeners = new Vector<Listener>();
40   private InetSocketAddress address = null;
41 
EventServer()42   public EventServer() {
43     this(0);
44   }
45 
EventServer(int port)46   public EventServer(int port) {
47     address = startAllInterfaces(port);
48   }
49 
getAddress()50   public InetSocketAddress getAddress() {
51     return address;
52   }
53 
54   @Override
shutdown()55   public void shutdown() {
56     onEventReceived(new Event("sl4a", "{\"shutdown\": \"event-server\"}"));
57     for (Listener listener : mListeners) {
58       mListeners.remove(listener);
59       listener.lock.countDown();
60     }
61     super.shutdown();
62   }
63 
64   @Override
handleConnection(Socket socket)65   protected void handleConnection(Socket socket) throws IOException {
66     Log.d("handle event connection.");
67     Listener l = new Listener(socket);
68     Log.v("Adding EventServer listener " + socket.getPort());
69     mListeners.add(l);
70     // we are running in the socket accept thread
71     // wait until the event dispatcher gets us the events
72     // or we die, what ever happens first
73     try {
74       l.lock.await();
75     } catch (InterruptedException e) {
76       e.printStackTrace();
77     }
78     try {
79       l.sock.close();
80     } catch (IOException e) {
81       e.printStackTrace();
82     }
83     Log.v("Ending EventServer listener " + socket.getPort());
84   }
85 
86   @Override
onEventReceived(Event event)87   public void onEventReceived(Event event) {
88     Object result = null;
89     try {
90       result = JsonBuilder.build(event);
91     } catch (JSONException e) {
92       return;
93     }
94 
95     Log.v("EventServer dispatching " + result);
96 
97     for (Listener listener : mListeners) {
98       if (!listener.out.checkError()) {
99         listener.out.write(result + "\n");
100         listener.out.flush();
101       } else {
102         // let the socket accept thread we're done
103         mListeners.remove(listener);
104         listener.lock.countDown();
105       }
106     }
107   }
108 
109   private class Listener {
110     private Socket sock;
111     private PrintWriter out;
112     private CountDownLatch lock = new CountDownLatch(1);
113 
Listener(Socket l)114     public Listener(Socket l) throws IOException {
115       sock = l;
116       out = new PrintWriter(l.getOutputStream(), true);
117     }
118   }
119 
120   @Override
handleRPCConnection(Socket sock, Integer UID, BufferedReader reader, PrintWriter writer)121   protected void handleRPCConnection(Socket sock, Integer UID, BufferedReader reader, PrintWriter writer)
122       throws Exception {
123   }
124 }
125