diff --git a/core/src/main/java/org/jclouds/concurrent/config/ExecutorServiceModule.java b/core/src/main/java/org/jclouds/concurrent/config/ExecutorServiceModule.java index 99d8601a4c..e61c7fc824 100644 --- a/core/src/main/java/org/jclouds/concurrent/config/ExecutorServiceModule.java +++ b/core/src/main/java/org/jclouds/concurrent/config/ExecutorServiceModule.java @@ -45,8 +45,6 @@ import org.jclouds.lifecycle.Closer; import org.jclouds.logging.Logger; 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.inject.AbstractModule; 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 @Singleton @Named(Constants.PROPERTY_USER_THREADS) diff --git a/core/src/main/java/org/jclouds/events/config/ConfiguresEventBus.java b/core/src/main/java/org/jclouds/events/config/ConfiguresEventBus.java new file mode 100644 index 0000000000..13c9cd9481 --- /dev/null +++ b/core/src/main/java/org/jclouds/events/config/ConfiguresEventBus.java @@ -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 { + +} diff --git a/core/src/main/java/org/jclouds/events/config/EventBusModule.java b/core/src/main/java/org/jclouds/events/config/EventBusModule.java new file mode 100644 index 0000000000..d7aa3fd864 --- /dev/null +++ b/core/src/main/java/org/jclouds/events/config/EventBusModule.java @@ -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. + *
+ * 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); + } + +} diff --git a/core/src/main/java/org/jclouds/events/config/annotations/AsyncBus.java b/core/src/main/java/org/jclouds/events/config/annotations/AsyncBus.java new file mode 100644 index 0000000000..d92dc367e3 --- /dev/null +++ b/core/src/main/java/org/jclouds/events/config/annotations/AsyncBus.java @@ -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 { + +} diff --git a/core/src/main/java/org/jclouds/events/handlers/DeadEventLoggingHandler.java b/core/src/main/java/org/jclouds/events/handlers/DeadEventLoggingHandler.java new file mode 100644 index 0000000000..20f709c1c4 --- /dev/null +++ b/core/src/main/java/org/jclouds/events/handlers/DeadEventLoggingHandler.java @@ -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. + *
+ * 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 Guava Issue
+ * 786 {@link #handleDeadEvent(DeadEvent)} is marked final
to avoid having
+ * duplicate events.
+ */
+ @Subscribe
+ public final void handleDeadEvent(DeadEvent deadEvent) {
+ logger.warn("detected dead event %s", deadEvent.getEvent());
+ }
+}
diff --git a/core/src/main/java/org/jclouds/rest/RestContextBuilder.java b/core/src/main/java/org/jclouds/rest/RestContextBuilder.java
index c77a721aa8..86f5c4f763 100644
--- a/core/src/main/java/org/jclouds/rest/RestContextBuilder.java
+++ b/core/src/main/java/org/jclouds/rest/RestContextBuilder.java
@@ -35,6 +35,8 @@ import org.jclouds.concurrent.MoreExecutors;
import org.jclouds.concurrent.SingleThreaded;
import org.jclouds.concurrent.config.ConfiguresExecutorService;
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.config.ConfiguresHttpCommandExecutorService;
import org.jclouds.http.config.JavaUrlHttpCommandExecutorServiceModule;
@@ -109,6 +111,7 @@ public class RestContextBuilder {
addHttpModuleIfNeededAndNotPresent(modules);
ifHttpConfigureRestOtherwiseGuiceClientFactory(modules);
addExecutorServiceIfNotPresent(modules);
+ addEventBusIfNotPresent(modules);
addCredentialStoreIfNotPresent(modules);
modules.add(new LifeCycleModule());
modules.add(new BindPropertiesToAnnotations());
@@ -211,6 +214,19 @@ public class RestContextBuilder {
protected void addClientModule(List(syncClientType, asyncClientType));
}
+
+ @VisibleForTesting
+ protected void addEventBusIfNotPresent(List