Is it possible for a class that is subscribed to a certain event class to fire the same event type without listening to it?
Example:
Class A {
EventBus bus = new EventBus();
public A() {
bus.register(this);
bus.post ( new String("event!"));
}
#Subscribe public void consume(String event) {
System.out.println("Got event: "+event);
}
}
You could have your event class include the source of the event (the object that posted the event) and then just ignore any events where the source is this. I'd recommend trying to make your class handle events consistently regardless of the source, though.
No, there isn't. How could EventBus determine where an event originated in the first place?
If you want to ignore certain events, you must include enough information in the event object itself to determine if the event should be ignored.
Related
I have created an OSGi EventHandler to know about the Sling CD events, here is the sample class.
#Component(immediate = true,
property = {
"event.topics=org/apache/sling/distribution/agent/package/distributed",
"event.filter=(|(distribution.type=ADD)(distribution.type=DELETE))"
})
public class MyEventHandler implements EventHandler {
private static final Logger LOGGER = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
#Override
public void handleEvent(Event event) {
// consume event.
}
}
When a content is distributed from AEM using the Add Tree option, the deepPaths field in org.apache.sling.distribution.SimpleDistributionRequest is initialised but it is not sent to the event handler.
This way we never get to know that it was a tree activation. So, is there a way to know about the deepPaths using this approach?
I found out that if we subscribe to this topic org/apache/sling/event/notification/job/FINISHED and filter on (|(distribution.request.type=ADD)(distribution.request.type=DELETE)) we can get the deepPaths as well as several other event properties but I am not sure if that would be right approach.
Please suggest.
I'm working on a code in a wicket project, where the original devs used the onModelChanged() method quite a lot in Ajax request handling methods. I, for one, however am not a strong believer of this implementation.
In fact, I can't think of any examples, where calling the target.add(...) is inferior to calling the onModelChanged method.
Am I missing some key concepts here?
Example:
public MyComponent extends Panel {
public MyComponent(String id, Component... componentsToRefresh) {
add(new AjaxLink<Void>("someId") {
#Override
public void onClick(AjaxRequestTarget target) {
// some logic with model change
for(Component c: componentsToRefresh) {
c.modelChanged();
}
target.add(componentsToRefresh);
}
};
}
}
Now, there are a couple of things I don't agree with, the very first is the componentsToRefresh parameter, the second is (as the question suggests), the fact that we called c.modelChanged() on all components in that array. My guess would be that it is completely un necessary and instead of a parameter in the constructor, one should just write an empty function in MyComponent and override it, and put the necessary components in there when needed.
I would suggest to use Wicket Event system instead. That is, whenever the AjaxLink is clicked you will broadcast an event:
send(getPage(), Broadcast.BREATH, new MyEventPayload(target));
This will broadcast the event to the current Page and all its components.
Then in any of your components you can listen for events:
#Override
public void onEvent(IEvent event) {
Object payload = event.getPayload();
if (payload instanceof MyEventPayload) {
((MyEventPayload) payload).getTarget().add(this); // or any of my sub-components
event.stop(); // optionally you can stop the broadcasting
}
}
This way you do not couple unrelated components in your application.
See Wicket Guide for more information.
I want to fuse the inputs of several Android sensors and expose the output as an observable (or at least something that can be subscribed to) that supports multiple simultaneous observers. What's the idiomatic way to approach this? Is there a class in the standard library that would make a good starting point?
I was thinking of wrapping a PublishSubject in an object with delegates for one or more subscribe methods that test hasObservers to activate the sensors, and wrap the returned Disposable in a proxy that tests hasObservers to deactivate them. Something like this, although this already has some obvious problems:
public class SensorSubject<T> {
private final PublishSubject<T> mSubject = PublishSubject.create();
public Disposable subscribe(final Consumer<? super T> consumer) {
final Disposable d = mSubject.subscribe(consumer);
if(mSubject.hasObservers()) {
// activate sensors
}
return new Disposable() {
#Override
public void dispose() {
// possible race conditions!
if(!isDisposed()) {
d.dispose();
if(!mSubject.hasObservers()) {
// deactivate sensors
}
}
}
#Override
public boolean isDisposed() {
return d.isDisposed();
}
};
}
}
The idiomatic way to do that in RxJava would be to use hot observable.
Cold observables do some action when someone subscribes to them and emit all items to that subscriber. So it's 1 to 1 relation.
Hot observable do some action and emits items independently on individual subscription. So if you subscribe too late, you might not get some values that were emitted earlier. This is 1 to many relation, aka multicast - which is what you want.
Usual way to do it is Flowable.publish() which makes Flowable multicast, but requires calling connect() method to start emitting values.
In your case you can also call refCount() which adds your desired functionality - it subscribes to source Flowable when there is at least one subscription and unsubscribes when everyone unsubsribed.
Because publish().refCount() is pretty popular combination, there is a shortcut for them - share(). And as far as I understand this is exactly what you want.
Edit by asker: This code incorporates this answer and David Karnok's comment in the form of a Dagger 2 provider method. SimpleMatrix is from EJML. This seems to be doing what I asked for.
#Provides
#Singleton
#Named(MAGNETOMETER)
public Observable<SimpleMatrix> magnetometer(final SensorManager sensorManager) {
final PublishSubject<SimpleMatrix> ps = PublishSubject.create();
final Sensor sensor = sensorManager.getDefaultSensor(TYPE_MAGNETIC_FIELD);
final SensorEventListener listener = new SensorEventAdapter() {
#Override
public void onSensorChanged(final SensorEvent event) {
ps.onNext(new SimpleMatrix(1, 3, true, event.values));
}
};
return ps.doOnSubscribe(s -> {
sensorManager.registerListener(listener, sensor, SENSOR_DELAY_NORMAL);
}).doOnDispose(() -> {
sensorManager.unregisterListener(listener);
}).share();
}
I'm using spring-data to Integrate our application with Mongodb.
In one of the use-cases, I invoke
MongoOperation.updateMulti(query, set.., Lead.class)
method to update a set of documents in our mongo collection.
I also have a Listener bean registered that extends AbstractMongoEventListener to listen to events on this particular Collection(Lead) as follows
public class LeadListener extends AbstractMongoEventListener<Lead> {
#Override
public void onBeforeSave(Lead p, com.mongodb.DBObject dbo) {
//do something
}
#Override
public void onBeforeConvert(Lead p) {
//do something
}
}
I observed that none of these methods get fired when mongoOperation.updateMulti is executed, but they get called when mongoOperation.save(lead) is executed.
What is the equivalent listener method that I can use for this updateMulti/update operation.
https://github.com/spring-projects/spring-data-mongodb/blob/master/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/core/MongoTemplate.java?source=c
If you take a look into the source code, updateMulti calls the doUpdate method, which does not contain any triggers of listeners maybeEmitEvent(...).
Compared to the doRemove-Method, which calls events on remove.
It seems there is a slightly little inconsistency.
I have na event-based API (Geolocator) that I want to convert to Rx.
The problem is that some operations require that all events are unsubscribed and I don't want to pass that burdon to the user of the Rx API.
So, the user will subscribe to a few observables and when the events are subscribed they are published to those observables.
What's the best way to do this?
I thought of creating a subject that the users subscribe to and then have the events published to those through another set of observables.
Is this the best way? If so, how?
The key problem is to find a way to keep an Observer subscribed to a stream whilst tearing down and replacing an underlying source. Let's just focus on a single event source - you should be able to extrapolate from that.
First of all, here is an example class we can use that has a single event SomeEvent that follows the standard .NET pattern using an EventHandler<StringEventArgs> delegate. We will use this to create sources of events.
Note I have intercepted the event add/remove handlers in order to show you when Rx subscribes and unsubscribes from the events, and given the class a name property to let us track different instances:
public class EventSource
{
private string _sourceName;
public EventSource(string sourceName)
{
_sourceName = sourceName;
}
private event EventHandler<MessageEventArgs> _someEvent;
public event EventHandler<MessageEventArgs> SomeEvent
{
add
{
_someEvent = (EventHandler<MessageEventArgs>)
Delegate.Combine(_someEvent, value);
Console.WriteLine("Subscribed to SomeEvent: " + _sourceName);
}
remove
{
_someEvent = (EventHandler<MessageEventArgs>)
Delegate.Remove(_someEvent, value);
Console.WriteLine("Unsubscribed to SomeEvent: " + _sourceName);
}
}
public void RaiseSomeEvent(string message)
{
var temp = _someEvent;
if(temp != null)
temp(this, new MessageEventArgs(message));
}
}
public class MessageEventArgs : EventArgs
{
public MessageEventArgs(string message)
{
Message = message;
}
public string Message { get; set; }
public override string ToString()
{
return Message;
}
}
Solution Key Idea - StreamSwitcher
Now, here is the heart of the solution. We will use a Subject<IObservable<T>> to create a stream of streams. We can use the Observable.Switch() operator to return only the most recent stream to Observers. Here's the implementation, and an example of usage will follow:
public class StreamSwitcher<T> : IObservable<T>
{
private Subject<IObservable<T>> _publisher;
private IObservable<T> _stream;
public StreamSwitcher()
{
_publisher = new Subject<IObservable<T>>();
_stream = _publisher.Switch();
}
public IDisposable Subscribe(IObserver<T> observer)
{
return _stream.Subscribe(observer);
}
public void Switch(IObservable<T> newStream)
{
_publisher.OnNext(newStream);
}
public void Suspend()
{
_publisher.OnNext(Observable.Never<T>());
}
public void Stop()
{
_publisher.OnNext(Observable.Empty<T>());
_publisher.OnCompleted();
}
}
Usage
With this class you can hook up a new stream on each occasion you want to start events flowing by using the Switch method - which just sends the new event stream to the Subject.
You can unhook events using the Suspend method, which sends an Observable.Never<T>() to the Subject effectively pausing the flow of events.
Finally you can stop altogether by called to Stop to push an Observable.Empty<T>() andOnComplete()` the subject.
The best part is that this technique will cause Rx to do the right thing and properly unsubscribe from the underlying event sources each time you Switch, Suspend or Stop. Note also, that once Stopped no more events will flow, even if you Switch again.
Here's an example program:
static void Main()
{
// create the switch to operate on
// an event type of EventHandler<MessageEventArgs>()
var switcher = new StreamSwitcher<EventPattern<MessageEventArgs>>();
// You can expose switcher using Observable.AsObservable() [see MSDN]
// to hide the implementation but here I just subscribe directly to
// the OnNext and OnCompleted events.
// This is how the end user gets their uninterrupted stream:
switcher.Subscribe(
Console.WriteLine,
() => Console.WriteLine("Done!"));
// Now I'll use the example event source to wire up the underlying
// event for the first time
var source = new EventSource("A");
var sourceObservable = Observable.FromEventPattern<MessageEventArgs>(
h => source.SomeEvent += h,
h => source.SomeEvent -= h);
// And we expose it to our observer with a call to Switch
Console.WriteLine("Subscribing");
switcher.Switch(sourceObservable);
// Raise some events
source.RaiseSomeEvent("1");
source.RaiseSomeEvent("2");
// When we call Suspend, the underlying event is unwired
switcher.Suspend();
Console.WriteLine("Unsubscribed");
// Just to prove it, this is not received by the observer
source.RaiseSomeEvent("3");
// Now pretend we want to start events again
// Just for kicks, we'll use an entirely new source of events
// ... but we don't have to, you could just call Switch(sourceObservable)
// with the previous instance.
source = new EventSource("B");
sourceObservable = Observable.FromEventPattern<MessageEventArgs>(
h => source.SomeEvent += h,
h => source.SomeEvent -= h);
// Switch to the new event stream
Console.WriteLine("Subscribing");
switcher.Switch(sourceObservable);
// Prove it works
source.RaiseSomeEvent("3");
source.RaiseSomeEvent("4");
// Finally unsubscribe
switcher.Stop();
}
This gives output like this:
Subscribing
Subscribed to SomeEvent: A
1
2
Unsubscribed to SomeEvent: A
Unsubscribed
Subscribing
Subscribed to SomeEvent: B
3
4
Unsubscribed to SomeEvent: B
Done!
Note it doesn't matter when the end user subscribes - I did it up front, but they can Subscribe any time and they'll start getting events at that point.
Hope that helps! Of course you'll need to pull together the various event types of the Geolocator API into a single convenient wrapper - but this should enable you to get there.
If you have several events you want to combine into a single stream using this technique, look at operators like Merge, which requires you to project the source streams into a common type, with Select maybe, or something like CombineLatest - this part of the problem shouldn't be too tricky.
This is what I came up with.
I have created two subjects for the clients of my API to subscribe:
private readonly Subject<Geoposition> positionSubject = new Subject<Geoposition>();
private readonly Subject<PositionStatus> statusSubject = new Subject<PositionStatus>();
And observables for the events my API is subscribing to:
private IDisposable positionObservable;
private IDisposable statusObservable;
When I want to subscribe to the events, I just subscribe them into the subjects:
this.positionObservable = Observable
.FromEvent<TypedEventHandler<Geolocator, PositionChangedEventArgs>, PositionChangedEventArgs>(
conversion: handler => (s, e) => handler(e),
addHandler: handler => this.geolocator.PositionChanged += handler,
removeHandler: handler => this.geolocator.PositionChanged -= handler)
.Select(e => e.Position)
.Subscribe(
onNext: this.positionSubject.OnNext,
onError: this.positionSubject.OnError);
this.statusObservable = Observable
.FromEvent<TypedEventHandler<Geolocator, StatusChangedEventArgs>, StatusChangedEventArgs>(
conversion: handler => (s, e) => handler(e),
addHandler: handler => this.geolocator.StatusChanged += handler,
removeHandler: handler => this.geolocator.StatusChanged -= handler)
.Select(e => e.Status)
.Subscribe(
onNext: this.statusSubject.OnNext,
onError: this.statusSubject.OnError);
When I want to cancel the subscription, I just dispose of the subscriptions:
this.positionObservable.Dispose();
this.statusObservable.Dispose();