mirror of https://github.com/apache/jclouds.git
Merge pull request #553 from nacx/eventbus-module
Added EventBus module to configure the sync and async EventBus
This commit is contained in:
commit
9cd9e4feeb
|
@ -45,8 +45,6 @@ import org.jclouds.lifecycle.Closer;
|
||||||
import org.jclouds.logging.Logger;
|
import org.jclouds.logging.Logger;
|
||||||
|
|
||||||
import com.google.common.annotations.VisibleForTesting;
|
import com.google.common.annotations.VisibleForTesting;
|
||||||
import com.google.common.eventbus.AsyncEventBus;
|
|
||||||
import com.google.common.eventbus.EventBus;
|
|
||||||
import com.google.common.util.concurrent.ThreadFactoryBuilder;
|
import com.google.common.util.concurrent.ThreadFactoryBuilder;
|
||||||
import com.google.inject.AbstractModule;
|
import com.google.inject.AbstractModule;
|
||||||
import com.google.inject.Provides;
|
import com.google.inject.Provides;
|
||||||
|
@ -323,12 +321,6 @@ public class ExecutorServiceModule extends AbstractModule {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Provides
|
|
||||||
@Singleton
|
|
||||||
EventBus provideEventBus(@Named(Constants.PROPERTY_USER_THREADS) ExecutorService userThreads){
|
|
||||||
return new AsyncEventBus(userThreads);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
@Singleton
|
@Singleton
|
||||||
@Named(Constants.PROPERTY_USER_THREADS)
|
@Named(Constants.PROPERTY_USER_THREADS)
|
||||||
|
|
|
@ -0,0 +1,38 @@
|
||||||
|
/**
|
||||||
|
* Licensed to jclouds, Inc. (jclouds) under one or more
|
||||||
|
* contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. jclouds licenses this file
|
||||||
|
* to you 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jclouds.events.config;
|
||||||
|
|
||||||
|
import java.lang.annotation.ElementType;
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
import java.lang.annotation.Target;
|
||||||
|
|
||||||
|
import com.google.common.eventbus.EventBus;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Designates the module configures an {@link EventBus}.
|
||||||
|
*
|
||||||
|
* @author Ignasi Barrera
|
||||||
|
*/
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
@Target(ElementType.TYPE)
|
||||||
|
public @interface ConfiguresEventBus {
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,85 @@
|
||||||
|
/**
|
||||||
|
* Licensed to jclouds, Inc. (jclouds) under one or more
|
||||||
|
* contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. jclouds licenses this file
|
||||||
|
* to you 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jclouds.events.config;
|
||||||
|
|
||||||
|
import java.util.concurrent.ExecutorService;
|
||||||
|
|
||||||
|
import javax.inject.Named;
|
||||||
|
import javax.inject.Singleton;
|
||||||
|
|
||||||
|
import org.jclouds.Constants;
|
||||||
|
import org.jclouds.concurrent.config.ExecutorServiceModule;
|
||||||
|
import org.jclouds.events.config.annotations.AsyncBus;
|
||||||
|
import org.jclouds.events.handlers.DeadEventLoggingHandler;
|
||||||
|
|
||||||
|
import com.google.common.eventbus.AsyncEventBus;
|
||||||
|
import com.google.common.eventbus.EventBus;
|
||||||
|
import com.google.inject.AbstractModule;
|
||||||
|
import com.google.inject.Provides;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configures the {@link EventBus} to be used in the platform.
|
||||||
|
* <p>
|
||||||
|
* This class will provide an {@link AsyncEventBus} to be used to provide a basic pub/sub system for
|
||||||
|
* asynchronous operations.
|
||||||
|
*
|
||||||
|
* @author Ignasi Barrera
|
||||||
|
*
|
||||||
|
* @see ExecutorServiceModule
|
||||||
|
* @see AsyncEventBus
|
||||||
|
* @see EventBus
|
||||||
|
* @see AsyncBus
|
||||||
|
*/
|
||||||
|
@ConfiguresEventBus
|
||||||
|
public class EventBusModule extends AbstractModule {
|
||||||
|
/**
|
||||||
|
* Provides an {@link AsyncEventBus} that will use the configured executor service to dispatch
|
||||||
|
* events to subscribers.
|
||||||
|
*/
|
||||||
|
@Provides
|
||||||
|
@Singleton
|
||||||
|
AsyncEventBus provideAsyncEventBus(
|
||||||
|
@Named(Constants.PROPERTY_USER_THREADS) final ExecutorService executor,
|
||||||
|
final DeadEventLoggingHandler deadEventsHandler) {
|
||||||
|
AsyncEventBus asyncBus = new AsyncEventBus("jclouds-async-event-bus", executor);
|
||||||
|
asyncBus.register(deadEventsHandler);
|
||||||
|
return asyncBus;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides asynchronous {@link EventBus}.
|
||||||
|
*/
|
||||||
|
@Provides
|
||||||
|
@Singleton
|
||||||
|
EventBus provideSyncEventBus(final DeadEventLoggingHandler deadEventsHandler) {
|
||||||
|
EventBus syncBus = new EventBus("jclouds-sync-event-bus");
|
||||||
|
syncBus.register(deadEventsHandler);
|
||||||
|
return syncBus;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configures the {@link EventBus} to be singleton and enables the {@link AsyncBus} annotation.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected void configure() {
|
||||||
|
bind(EventBus.class).annotatedWith(AsyncBus.class).to(AsyncEventBus.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,50 @@
|
||||||
|
/**
|
||||||
|
* Licensed to jclouds, Inc. (jclouds) under one or more
|
||||||
|
* contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. jclouds licenses this file
|
||||||
|
* to you 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jclouds.events.config.annotations;
|
||||||
|
|
||||||
|
import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
|
||||||
|
import static java.lang.annotation.ElementType.FIELD;
|
||||||
|
import static java.lang.annotation.ElementType.PARAMETER;
|
||||||
|
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||||
|
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.Target;
|
||||||
|
|
||||||
|
import javax.inject.Qualifier;
|
||||||
|
|
||||||
|
import org.jclouds.events.config.EventBusModule;
|
||||||
|
|
||||||
|
import com.google.common.eventbus.AsyncEventBus;
|
||||||
|
import com.google.common.eventbus.EventBus;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used to configure {@link EventBus} injection, providing a flexible way to inject the
|
||||||
|
* {@link AsyncEventBus}.
|
||||||
|
*
|
||||||
|
* @author Ignasi Barrera
|
||||||
|
*
|
||||||
|
* @see EventBusModule
|
||||||
|
*/
|
||||||
|
@Target({ANNOTATION_TYPE, FIELD, PARAMETER})
|
||||||
|
@Retention(RUNTIME)
|
||||||
|
@Qualifier
|
||||||
|
public @interface AsyncBus {
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,52 @@
|
||||||
|
/**
|
||||||
|
* Licensed to jclouds, Inc. (jclouds) under one or more
|
||||||
|
* contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. jclouds licenses this file
|
||||||
|
* to you 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jclouds.events.handlers;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import javax.inject.Singleton;
|
||||||
|
|
||||||
|
import org.jclouds.logging.Logger;
|
||||||
|
|
||||||
|
import com.google.common.eventbus.DeadEvent;
|
||||||
|
import com.google.common.eventbus.Subscribe;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default handler for dead events.
|
||||||
|
* <p>
|
||||||
|
* It simply logs all dead events to allow debugging and troubleshooting.
|
||||||
|
*
|
||||||
|
* @author Ignasi Barrera
|
||||||
|
*/
|
||||||
|
@Singleton
|
||||||
|
public class DeadEventLoggingHandler
|
||||||
|
{
|
||||||
|
@Resource
|
||||||
|
private Logger logger = Logger.NULL;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Due to <a href="http://code.google.com/p/guava-libraries/issues/detail?id=783">Guava Issue
|
||||||
|
* 786</a> {@link #handleDeadEvent(DeadEvent)} is marked <code>final</code>to avoid having
|
||||||
|
* duplicate events.
|
||||||
|
*/
|
||||||
|
@Subscribe
|
||||||
|
public final void handleDeadEvent(DeadEvent deadEvent) {
|
||||||
|
logger.warn("detected dead event %s", deadEvent.getEvent());
|
||||||
|
}
|
||||||
|
}
|
|
@ -35,6 +35,8 @@ import org.jclouds.concurrent.MoreExecutors;
|
||||||
import org.jclouds.concurrent.SingleThreaded;
|
import org.jclouds.concurrent.SingleThreaded;
|
||||||
import org.jclouds.concurrent.config.ConfiguresExecutorService;
|
import org.jclouds.concurrent.config.ConfiguresExecutorService;
|
||||||
import org.jclouds.concurrent.config.ExecutorServiceModule;
|
import org.jclouds.concurrent.config.ExecutorServiceModule;
|
||||||
|
import org.jclouds.events.config.ConfiguresEventBus;
|
||||||
|
import org.jclouds.events.config.EventBusModule;
|
||||||
import org.jclouds.http.RequiresHttp;
|
import org.jclouds.http.RequiresHttp;
|
||||||
import org.jclouds.http.config.ConfiguresHttpCommandExecutorService;
|
import org.jclouds.http.config.ConfiguresHttpCommandExecutorService;
|
||||||
import org.jclouds.http.config.JavaUrlHttpCommandExecutorServiceModule;
|
import org.jclouds.http.config.JavaUrlHttpCommandExecutorServiceModule;
|
||||||
|
@ -109,6 +111,7 @@ public class RestContextBuilder<S, A> {
|
||||||
addHttpModuleIfNeededAndNotPresent(modules);
|
addHttpModuleIfNeededAndNotPresent(modules);
|
||||||
ifHttpConfigureRestOtherwiseGuiceClientFactory(modules);
|
ifHttpConfigureRestOtherwiseGuiceClientFactory(modules);
|
||||||
addExecutorServiceIfNotPresent(modules);
|
addExecutorServiceIfNotPresent(modules);
|
||||||
|
addEventBusIfNotPresent(modules);
|
||||||
addCredentialStoreIfNotPresent(modules);
|
addCredentialStoreIfNotPresent(modules);
|
||||||
modules.add(new LifeCycleModule());
|
modules.add(new LifeCycleModule());
|
||||||
modules.add(new BindPropertiesToAnnotations());
|
modules.add(new BindPropertiesToAnnotations());
|
||||||
|
@ -212,6 +215,19 @@ public class RestContextBuilder<S, A> {
|
||||||
modules.add(new RestClientModule<S, A>(syncClientType, asyncClientType));
|
modules.add(new RestClientModule<S, A>(syncClientType, asyncClientType));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
protected void addEventBusIfNotPresent(List<Module> modules) {
|
||||||
|
if (!any(modules, new Predicate<Module>() {
|
||||||
|
public boolean apply(Module input) {
|
||||||
|
return input.getClass().isAnnotationPresent(ConfiguresEventBus.class);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
)) {
|
||||||
|
modules.add(new EventBusModule());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
protected void addExecutorServiceIfNotPresent(List<Module> modules) {
|
protected void addExecutorServiceIfNotPresent(List<Module> modules) {
|
||||||
if (!any(modules, new Predicate<Module>() {
|
if (!any(modules, new Predicate<Module>() {
|
||||||
|
|
|
@ -0,0 +1,80 @@
|
||||||
|
/**
|
||||||
|
* Licensed to jclouds, Inc. (jclouds) under one or more
|
||||||
|
* contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. jclouds licenses this file
|
||||||
|
* to you 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jclouds.events.config;
|
||||||
|
|
||||||
|
import static org.testng.Assert.assertNotNull;
|
||||||
|
import static org.testng.Assert.assertTrue;
|
||||||
|
|
||||||
|
import org.jclouds.Constants;
|
||||||
|
import org.jclouds.concurrent.config.ExecutorServiceModule;
|
||||||
|
import org.jclouds.events.config.annotations.AsyncBus;
|
||||||
|
import org.testng.annotations.BeforeMethod;
|
||||||
|
import org.testng.annotations.Test;
|
||||||
|
|
||||||
|
import com.google.common.eventbus.AsyncEventBus;
|
||||||
|
import com.google.common.eventbus.EventBus;
|
||||||
|
import com.google.inject.Guice;
|
||||||
|
import com.google.inject.Injector;
|
||||||
|
import com.google.inject.Key;
|
||||||
|
import com.google.inject.name.Names;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unit tests for the {@link EventBusModule} class.
|
||||||
|
*
|
||||||
|
* @author Ignasi Barrera
|
||||||
|
*/
|
||||||
|
@Test(groups = "unit")
|
||||||
|
public class EventBusModuleTest
|
||||||
|
{
|
||||||
|
private Injector injector;
|
||||||
|
|
||||||
|
@BeforeMethod
|
||||||
|
public void setup() {
|
||||||
|
ExecutorServiceModule executorServiceModule = new ExecutorServiceModule() {
|
||||||
|
@Override
|
||||||
|
protected void configure() {
|
||||||
|
bindConstant().annotatedWith(Names.named(Constants.PROPERTY_IO_WORKER_THREADS)).to(1);
|
||||||
|
bindConstant().annotatedWith(Names.named(Constants.PROPERTY_USER_THREADS)).to(1);
|
||||||
|
super.configure();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
EventBusModule eventBusModule = new EventBusModule();
|
||||||
|
injector = Guice.createInjector(executorServiceModule, eventBusModule);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testAsyncExecutorIsProvided() {
|
||||||
|
assertNotNull(injector.getInstance(AsyncEventBus.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testAsyncAnnotatedEventBusIsBound() {
|
||||||
|
Key<EventBus> eventBusKey = Key.get(EventBus.class, AsyncBus.class);
|
||||||
|
EventBus eventBus = injector.getInstance(eventBusKey);
|
||||||
|
|
||||||
|
assertNotNull(eventBus);
|
||||||
|
assertTrue(eventBus instanceof AsyncEventBus);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testEventBusIsSingleton() {
|
||||||
|
EventBus eventBus1 = injector.getInstance(EventBus.class);
|
||||||
|
EventBus eventBus2 = injector.getInstance(EventBus.class);
|
||||||
|
|
||||||
|
assertTrue(eventBus1 == eventBus2);
|
||||||
|
}
|
||||||
|
}
|
|
@ -26,6 +26,7 @@ import java.util.List;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
|
|
||||||
import org.jclouds.concurrent.config.ExecutorServiceModule;
|
import org.jclouds.concurrent.config.ExecutorServiceModule;
|
||||||
|
import org.jclouds.events.config.EventBusModule;
|
||||||
import org.jclouds.http.RequiresHttp;
|
import org.jclouds.http.RequiresHttp;
|
||||||
import org.jclouds.http.config.ConfiguresHttpCommandExecutorService;
|
import org.jclouds.http.config.ConfiguresHttpCommandExecutorService;
|
||||||
import org.jclouds.http.config.JavaUrlHttpCommandExecutorServiceModule;
|
import org.jclouds.http.config.JavaUrlHttpCommandExecutorServiceModule;
|
||||||
|
@ -78,6 +79,17 @@ public class RestContextBuilderTest {
|
||||||
assertEquals(modules.remove(0), module);
|
assertEquals(modules.remove(0), module);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAddEventBusModuleIfNotPresent() {
|
||||||
|
List<Module> modules = new ArrayList<Module>();
|
||||||
|
EventBusModule module = new EventBusModule();
|
||||||
|
modules.add(module);
|
||||||
|
new RestContextBuilder<String, String>(String.class, String.class, new Properties())
|
||||||
|
.addEventBusIfNotPresent(modules);
|
||||||
|
assertEquals(modules.size(), 1);
|
||||||
|
assertEquals(modules.remove(0), module);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testAddExecutorServiceModuleIfNotPresent() {
|
public void testAddExecutorServiceModuleIfNotPresent() {
|
||||||
List<Module> modules = new ArrayList<Module>();
|
List<Module> modules = new ArrayList<Module>();
|
||||||
|
|
Loading…
Reference in New Issue