@@ -537,11 +537,15 @@ private void stopConnection(String errorMessage) {
537
537
* @param args The arguments to be passed to the method.
538
538
*/
539
539
public void send (String method , Object ... args ) {
540
- if (hubConnectionState != HubConnectionState .CONNECTED ) {
541
- throw new RuntimeException ("The 'send' method cannot be called if the connection is not active." );
540
+ hubConnectionStateLock .lock ();
541
+ try {
542
+ if (hubConnectionState != HubConnectionState .CONNECTED ) {
543
+ throw new RuntimeException ("The 'send' method cannot be called if the connection is not active." );
544
+ }
545
+ sendInvocationMessage (method , args );
546
+ } finally {
547
+ hubConnectionStateLock .unlock ();
542
548
}
543
-
544
- sendInvocationMessage (method , args );
545
549
}
546
550
547
551
private void sendInvocationMessage (String method , Object [] args ) {
@@ -605,26 +609,31 @@ Object[] checkUploadStream(Object[] args, List<String> streamIds) {
605
609
*/
606
610
@ SuppressWarnings ("unchecked" )
607
611
public Completable invoke (String method , Object ... args ) {
608
- if (hubConnectionState != HubConnectionState .CONNECTED ) {
609
- throw new RuntimeException ("The 'invoke' method cannot be called if the connection is not active." );
610
- }
612
+ hubConnectionStateLock .lock ();
613
+ try {
614
+ if (hubConnectionState != HubConnectionState .CONNECTED ) {
615
+ throw new RuntimeException ("The 'invoke' method cannot be called if the connection is not active." );
616
+ }
611
617
612
- String id = connectionState .getNextInvocationId ();
618
+ String id = connectionState .getNextInvocationId ();
613
619
614
- CompletableSubject subject = CompletableSubject .create ();
615
- InvocationRequest irq = new InvocationRequest (null , id );
616
- connectionState .addInvocation (irq );
620
+ CompletableSubject subject = CompletableSubject .create ();
621
+ InvocationRequest irq = new InvocationRequest (null , id );
622
+ connectionState .addInvocation (irq );
617
623
618
- Subject <Object > pendingCall = irq .getPendingCall ();
624
+ Subject <Object > pendingCall = irq .getPendingCall ();
619
625
620
- pendingCall .subscribe (result -> subject .onComplete (),
621
- error -> subject .onError (error ),
622
- () -> subject .onComplete ());
626
+ pendingCall .subscribe (result -> subject .onComplete (),
627
+ error -> subject .onError (error ),
628
+ () -> subject .onComplete ());
623
629
624
- // Make sure the actual send is after setting up the callbacks otherwise there is a race
625
- // where the map doesn't have the callbacks yet when the response is returned
626
- sendInvocationMessage (method , args , id , false );
627
- return subject ;
630
+ // Make sure the actual send is after setting up the callbacks otherwise there is a race
631
+ // where the map doesn't have the callbacks yet when the response is returned
632
+ sendInvocationMessage (method , args , id , false );
633
+ return subject ;
634
+ } finally {
635
+ hubConnectionStateLock .unlock ();
636
+ }
628
637
}
629
638
630
639
/**
@@ -638,32 +647,37 @@ public Completable invoke(String method, Object... args) {
638
647
*/
639
648
@ SuppressWarnings ("unchecked" )
640
649
public <T > Single <T > invoke (Class <T > returnType , String method , Object ... args ) {
641
- if (hubConnectionState != HubConnectionState .CONNECTED ) {
642
- throw new RuntimeException ("The 'invoke' method cannot be called if the connection is not active." );
643
- }
650
+ hubConnectionStateLock .lock ();
651
+ try {
652
+ if (hubConnectionState != HubConnectionState .CONNECTED ) {
653
+ throw new RuntimeException ("The 'invoke' method cannot be called if the connection is not active." );
654
+ }
644
655
645
- String id = connectionState .getNextInvocationId ();
656
+ String id = connectionState .getNextInvocationId ();
657
+ InvocationRequest irq = new InvocationRequest (returnType , id );
658
+ connectionState .addInvocation (irq );
646
659
647
- SingleSubject <T > subject = SingleSubject .create ();
648
- InvocationRequest irq = new InvocationRequest (returnType , id );
649
- connectionState .addInvocation (irq );
660
+ SingleSubject <T > subject = SingleSubject .create ();
650
661
651
- // forward the invocation result or error to the user
652
- // run continuations on a separate thread
653
- Subject <Object > pendingCall = irq .getPendingCall ();
654
- pendingCall .subscribe (result -> {
655
- // Primitive types can't be cast with the Class cast function
656
- if (returnType .isPrimitive ()) {
657
- subject .onSuccess ((T )result );
658
- } else {
659
- subject .onSuccess (returnType .cast (result ));
660
- }
661
- }, error -> subject .onError (error ));
662
+ // forward the invocation result or error to the user
663
+ // run continuations on a separate thread
664
+ Subject <Object > pendingCall = irq .getPendingCall ();
665
+ pendingCall .subscribe (result -> {
666
+ // Primitive types can't be cast with the Class cast function
667
+ if (returnType .isPrimitive ()) {
668
+ subject .onSuccess ((T )result );
669
+ } else {
670
+ subject .onSuccess (returnType .cast (result ));
671
+ }
672
+ }, error -> subject .onError (error ));
662
673
663
- // Make sure the actual send is after setting up the callbacks otherwise there is a race
664
- // where the map doesn't have the callbacks yet when the response is returned
665
- sendInvocationMessage (method , args , id , false );
666
- return subject ;
674
+ // Make sure the actual send is after setting up the callbacks otherwise there is a race
675
+ // where the map doesn't have the callbacks yet when the response is returned
676
+ sendInvocationMessage (method , args , id , false );
677
+ return subject ;
678
+ } finally {
679
+ hubConnectionStateLock .unlock ();
680
+ }
667
681
}
668
682
669
683
/**
@@ -677,33 +691,46 @@ public <T> Single<T> invoke(Class<T> returnType, String method, Object... args)
677
691
*/
678
692
@ SuppressWarnings ("unchecked" )
679
693
public <T > Observable <T > stream (Class <T > returnType , String method , Object ... args ) {
680
- String invocationId = connectionState .getNextInvocationId ();
681
- AtomicInteger subscriptionCount = new AtomicInteger ();
682
- InvocationRequest irq = new InvocationRequest (returnType , invocationId );
683
- connectionState .addInvocation (irq );
684
- ReplaySubject <T > subject = ReplaySubject .create ();
685
-
686
- Subject <Object > pendingCall = irq .getPendingCall ();
687
- pendingCall .subscribe (result -> {
688
- // Primitive types can't be cast with the Class cast function
689
- if (returnType .isPrimitive ()) {
690
- subject .onNext ((T )result );
691
- } else {
692
- subject .onNext (returnType .cast (result ));
693
- }
694
- }, error -> subject .onError (error ),
695
- () -> subject .onComplete ());
696
-
697
- Observable <T > observable = subject .doOnSubscribe ((subscriber ) -> subscriptionCount .incrementAndGet ());
698
- sendInvocationMessage (method , args , invocationId , true );
699
- return observable .doOnDispose (() -> {
700
- if (subscriptionCount .decrementAndGet () == 0 ) {
701
- CancelInvocationMessage cancelInvocationMessage = new CancelInvocationMessage (invocationId );
702
- sendHubMessage (cancelInvocationMessage );
703
- connectionState .tryRemoveInvocation (invocationId );
704
- subject .onComplete ();
694
+ String invocationId ;
695
+ InvocationRequest irq ;
696
+ hubConnectionStateLock .lock ();
697
+ try {
698
+ if (hubConnectionState != HubConnectionState .CONNECTED ) {
699
+ throw new RuntimeException ("The 'stream' method cannot be called if the connection is not active." );
705
700
}
706
- });
701
+
702
+ invocationId = connectionState .getNextInvocationId ();
703
+ irq = new InvocationRequest (returnType , invocationId );
704
+ connectionState .addInvocation (irq );
705
+
706
+ AtomicInteger subscriptionCount = new AtomicInteger ();
707
+ ReplaySubject <T > subject = ReplaySubject .create ();
708
+ Subject <Object > pendingCall = irq .getPendingCall ();
709
+ pendingCall .subscribe (result -> {
710
+ // Primitive types can't be cast with the Class cast function
711
+ if (returnType .isPrimitive ()) {
712
+ subject .onNext ((T )result );
713
+ } else {
714
+ subject .onNext (returnType .cast (result ));
715
+ }
716
+ }, error -> subject .onError (error ),
717
+ () -> subject .onComplete ());
718
+
719
+ Observable <T > observable = subject .doOnSubscribe ((subscriber ) -> subscriptionCount .incrementAndGet ());
720
+ sendInvocationMessage (method , args , invocationId , true );
721
+ return observable .doOnDispose (() -> {
722
+ if (subscriptionCount .decrementAndGet () == 0 ) {
723
+ CancelInvocationMessage cancelInvocationMessage = new CancelInvocationMessage (invocationId );
724
+ sendHubMessage (cancelInvocationMessage );
725
+ if (connectionState != null ) {
726
+ connectionState .tryRemoveInvocation (invocationId );
727
+ }
728
+ subject .onComplete ();
729
+ }
730
+ });
731
+ } finally {
732
+ hubConnectionStateLock .unlock ();
733
+ }
707
734
}
708
735
709
736
private void sendHubMessage (HubMessage message ) {
0 commit comments