/**
*
*/
package com.thinkbiganalytics.metadata.event.reactor;
/*-
* #%L
* thinkbig-metadata-core
* %%
* Copyright (C) 2017 ThinkBig Analytics
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import com.thinkbiganalytics.metadata.api.event.EventMatcher;
import com.thinkbiganalytics.metadata.api.event.MetadataEvent;
import com.thinkbiganalytics.metadata.api.event.MetadataEventListener;
import com.thinkbiganalytics.metadata.api.event.MetadataEventService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.ResolvableType;
import java.io.Serializable;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import javax.inject.Inject;
import javax.inject.Named;
import reactor.bus.Event;
import reactor.bus.EventBus;
import reactor.bus.registry.Registration;
import reactor.bus.selector.HeaderResolver;
import reactor.bus.selector.Selector;
import reactor.fn.Consumer;
/**
*
*/
public class ReactorMetadataEventService implements MetadataEventService {
private static final Logger log = LoggerFactory.getLogger(ReactorMetadataEventService.class);
private final Map<MetadataEventListener<?>, Registration<?, ?>> registrations;
@Inject
@Named("metadataEventBus")
private EventBus eventBus;
/**
*
*/
public ReactorMetadataEventService() {
this.registrations = new ConcurrentHashMap<>();
}
/* (non-Javadoc)
* @see com.thinkbiganalytics.metadata.api.event.MetadataEventService#notify(com.thinkbiganalytics.metadata.api.event.MetadataEvent)
*/
@Override
public <E extends MetadataEvent<? extends Serializable>> void notify(E event) {
log.debug("Notify event: {}", event);
this.eventBus.notify(event, Event.wrap(event));
}
/* (non-Javadoc)
* @see com.thinkbiganalytics.metadata.api.event.MetadataEventService#addListener(com.thinkbiganalytics.metadata.api.event.MetadataEventListener)
*/
@Override
public <E extends MetadataEvent<? extends Serializable>> void addListener(MetadataEventListener<E> listener) {
log.debug("Adding event listener: {}", listener);
Registration<?, ?> reg = this.eventBus.on(asSelector(listener), asConsumer(listener));
this.registrations.put(listener, reg);
}
/* (non-Javadoc)
* @see com.thinkbiganalytics.metadata.api.event.MetadataEventService#addListener(com.thinkbiganalytics.metadata.api.event.MetadataEventListener, com.thinkbiganalytics.metadata.api.event.EventMatcher)
*/
@Override
public <E extends MetadataEvent<? extends Serializable>> void addListener(MetadataEventListener<E> listener, EventMatcher<E> matcher) {
log.debug("Adding event listener: {}", listener);
Registration<?, ?> reg = this.eventBus.on(asSelector(matcher), asConsumer(listener));
this.registrations.put(listener, reg);
}
@Override
public void removeListener(MetadataEventListener<?> listener) {
log.debug("Removing event listener: {}", listener);
Registration<?, ?> reg = this.registrations.remove(listener);
if (reg != null) {
reg.cancel();
}
}
private <E extends MetadataEvent<? extends Serializable>> Selector<E> asSelector(MetadataEventListener<E> listener) {
return new EventTypeMatcher<>(listener);
}
private <E extends MetadataEvent<? extends Serializable>> Selector<E> asSelector(EventMatcher<E> matcher) {
// TODO Auto-generated method stub
return null;
}
private <E extends MetadataEvent<? extends Serializable>> Consumer<Event<E>> asConsumer(MetadataEventListener<E> listener) {
return new ListenerConsumer<>(listener);
}
private static class ListenerConsumer<E extends MetadataEvent<? extends Serializable>> implements Consumer<Event<E>> {
private final MetadataEventListener<E> listener;
public ListenerConsumer(MetadataEventListener<E> listener) {
super();
this.listener = listener;
}
@Override
public void accept(Event<E> event) {
this.listener.notify(event.getData());
}
}
private static class EventTypeMatcher<E extends MetadataEvent<? extends Serializable>> implements EventMatcher<E>, Selector<E> {
private final Class<? extends MetadataEvent<?>> eventClass;
private final Class<? extends Serializable> dataClass;
public EventTypeMatcher(MetadataEventListener<E> listener) {
ResolvableType listenerType = ResolvableType.forClass(MetadataEventListener.class, listener.getClass());
@SuppressWarnings("unchecked")
Class<? extends MetadataEvent<?>> evClass = (Class<? extends MetadataEvent<?>>) listenerType.resolveGeneric(0);
ResolvableType evType = ResolvableType.forClass(MetadataEvent.class, evClass);
@SuppressWarnings("unchecked")
Class<? extends Serializable> serClass = (Class<? extends Serializable>) evType.resolveGeneric(0);
this.eventClass = evClass;
this.dataClass = serClass;
}
@Override
public boolean test(E event) {
if (this.eventClass.isAssignableFrom(event.getClass())) {
return this.dataClass.isAssignableFrom(event.getData().getClass());
} else {
return false;
}
}
@Override
public boolean matches(E event) {
return test(event);
}
@Override
public Object getObject() {
return null;
}
@Override
public HeaderResolver<?> getHeaderResolver() {
return null;
}
}
}