22
33import com .google .gson .JsonObject ;
44
5+ import net .servicestack .client .IReceiver ;
6+ import net .servicestack .client .IResolver ;
57import net .servicestack .client .JsonServiceClient ;
68import net .servicestack .client .JsonUtils ;
79import net .servicestack .client .Log ;
1113import java .io .FileNotFoundException ;
1214import java .io .IOException ;
1315import java .io .InputStream ;
16+ import java .lang .reflect .Method ;
17+ import java .lang .reflect .Modifier ;
18+ import java .lang .reflect .Parameter ;
1419import java .net .HttpURLConnection ;
1520import java .net .URL ;
1621import java .text .SimpleDateFormat ;
@@ -34,6 +39,7 @@ public class ServerEventsClient implements AutoCloseable {
3439 private String eventStreamPath ;
3540 private String eventStreamUri ;
3641 private JsonServiceClient serviceClient ;
42+ private IResolver resolver ;
3743
3844 private Map <String ,ServerEventCallback > handlers ;
3945 private Map <String ,ServerEventCallback > namedReceivers ;
@@ -60,6 +66,7 @@ public ServerEventsClient(String baseUri, String[] channels) {
6066 setBaseUri (baseUri );
6167 setChannels (channels );
6268 this .serviceClient = new JsonServiceClient (baseUri );
69+ this .resolver = new NewInstanceResolver ();
6370
6471 this .handlers = new HashMap <>();
6572 this .namedReceivers = new HashMap <>();
@@ -110,6 +117,14 @@ public JsonServiceClient getServiceClient() {
110117 return this .serviceClient ;
111118 }
112119
120+ public IResolver getResolver () {
121+ return resolver ;
122+ }
123+
124+ public void setResolver (IResolver resolver ) {
125+ this .resolver = resolver ;
126+ }
127+
113128 public ServerEventsClient setOnConnect (ServerEventConnectCallback onConnect ) {
114129 this .onConnect = onConnect ;
115130 return this ;
@@ -148,12 +163,75 @@ public void setHandlers(Map<String, ServerEventCallback> handlers) {
148163 this .handlers = handlers ;
149164 }
150165
166+ public ServerEventsClient registerHandler (String name , ServerEventCallback handler ){
167+ this .handlers .put (name , handler );
168+ return this ;
169+ }
170+
151171 public Map <String , ServerEventCallback > getNamedReceivers () {
152172 return namedReceivers ;
153173 }
154174
155- public ServerEventsClient setNamedReceivers (Map <String , ServerEventCallback > namedReceivers ) {
156- this .namedReceivers = namedReceivers ;
175+ public ServerEventsClient registerNamedReceiver (String name , Class <?> namedReceiverClass ) {
176+
177+ if (!IReceiver .class .isAssignableFrom (namedReceiverClass ))
178+ throw new IllegalArgumentException (namedReceiverClass .getSimpleName () + " must implement IReceiver" );
179+
180+ namedReceivers .put (name , new ServerEventCallback () {
181+ @ Override
182+ public void execute (ServerEventsClient client , ServerEventMessage msg ) {
183+ try {
184+ IReceiver receiver = (IReceiver )resolver .TryResolve (namedReceiverClass );
185+
186+ if (receiver instanceof ServerEventReceiver ){
187+ ServerEventReceiver injectReceiver = (ServerEventReceiver )receiver ;
188+ injectReceiver .setClient (client );
189+ injectReceiver .setRequest (msg );
190+ }
191+
192+ String target = msg .getTarget ().replace ("-" ,"" ); //css bg-image
193+
194+ for (Method mi : namedReceiverClass .getDeclaredMethods ()){
195+ if (!Modifier .isPublic (mi .getModifiers ()) || Modifier .isStatic (mi .getModifiers ()))
196+ continue ;
197+ if (mi .getParameterCount () != 1 )
198+ continue ;
199+ if ("equals" .equals (mi .getName ()))
200+ continue ;
201+
202+ Parameter [] args = mi .getParameters ();
203+
204+ Class requestType = args [0 ].getType ();
205+
206+ if (target .equals (requestType .getSimpleName ())) {
207+ Object request = msg .getJson () != null
208+ ? JsonUtils .fromJson (msg .getJson (), requestType )
209+ : requestType .newInstance ();
210+ mi .invoke (receiver , request );
211+ return ;
212+ }
213+
214+ String actionName = mi .getName ();
215+ if (!target .equalsIgnoreCase (actionName ) && actionName .startsWith ("set" ))
216+ actionName = actionName .substring (3 ); //= "set".length()
217+
218+ if (target .equalsIgnoreCase (actionName )) {
219+ Object request = msg .getJson () != null
220+ ? JsonUtils .fromJson (msg .getJson (), requestType )
221+ : requestType .newInstance ();
222+ mi .invoke (receiver , request );
223+ return ;
224+ }
225+ }
226+
227+ receiver .noSuchMethod (msg .getTarget (), msg );
228+
229+ } catch (Exception e ) {
230+ throw new RuntimeException (e );
231+ }
232+ }
233+ });
234+
157235 return this ;
158236 }
159237
@@ -233,6 +311,21 @@ public synchronized void stop(){
233311 internalStop ();
234312 }
235313
314+ public ServerEventsClient waitTillConnected () throws Exception {
315+ return waitTillConnected (Integer .MAX_VALUE );
316+ }
317+
318+ public ServerEventsClient waitTillConnected (int timeoutMs ) throws Exception {
319+ Date startedAt = new Date ();
320+ while (connectionInfo == null ) {
321+ Thread .sleep (50 );
322+
323+ if ((new Date ().getTime () - startedAt .getTime ()) > timeoutMs )
324+ throw new TimeoutException ("Not connected after " + timeoutMs + "ms" );
325+ }
326+ return this ;
327+ }
328+
236329 private synchronized void internalStop () {
237330 if (Log .isDebugEnabled ())
238331 Log .d ("Stop() " + getConnectionDisplayName ());
0 commit comments