*
- * @param a sub-class of {@link IClient}
+ * @param a sub-class of {@link IMessagingClient}
* @author Vincent Zurczak - Linagora
*/
public abstract class AbstractMessageProcessor extends Thread {
diff --git a/core/roboconf-messaging-api/src/main/java/net/roboconf/messaging/api/MessagingConstants.java b/core/roboconf-messaging-api/src/main/java/net/roboconf/messaging/api/MessagingConstants.java
index 9e3edefd..f7420d15 100644
--- a/core/roboconf-messaging-api/src/main/java/net/roboconf/messaging/api/MessagingConstants.java
+++ b/core/roboconf-messaging-api/src/main/java/net/roboconf/messaging/api/MessagingConstants.java
@@ -49,7 +49,7 @@ public interface MessagingConstants {
*
*
* This property is used in the provider-specific
- * {@linkplain net.roboconf.messaging.api.client.IClient#getConfiguration() messaging configuration} to ensure a
+ * {@linkplain net.roboconf.messaging.api.business.IClient#getConfiguration() messaging configuration} to ensure a
* configuration is applicable to a given messaging client. It is also used by
* {@link net.roboconf.messaging.api.factory.IMessagingClientFactory} services to indicate which type of messaging
* they
@@ -61,11 +61,10 @@ public interface MessagingConstants {
/**
* The factory's name for test clients.
*/
- String TEST_FACTORY_TYPE = "test";
+ String FACTORY_TEST = "test";
/**
- * The "dismissed" message.
+ * The factory's name for in-memory clients.
*/
- String DISMISSED_MESSAGE = "No messaging client is available. Action is dismissed. Review the messaging configuration.";
-
+ String FACTORY_IN_MEMORY = "in-memory";
}
diff --git a/core/roboconf-messaging-api/src/main/java/net/roboconf/messaging/api/client/IAgentClient.java b/core/roboconf-messaging-api/src/main/java/net/roboconf/messaging/api/business/IAgentClient.java
similarity index 99%
rename from core/roboconf-messaging-api/src/main/java/net/roboconf/messaging/api/client/IAgentClient.java
rename to core/roboconf-messaging-api/src/main/java/net/roboconf/messaging/api/business/IAgentClient.java
index 7acf3603..8b94e318 100644
--- a/core/roboconf-messaging-api/src/main/java/net/roboconf/messaging/api/client/IAgentClient.java
+++ b/core/roboconf-messaging-api/src/main/java/net/roboconf/messaging/api/business/IAgentClient.java
@@ -23,7 +23,7 @@
* limitations under the License.
*/
-package net.roboconf.messaging.api.client;
+package net.roboconf.messaging.api.business;
import java.io.IOException;
import java.util.Map;
diff --git a/core/roboconf-messaging-api/src/main/java/net/roboconf/messaging/api/client/IClient.java b/core/roboconf-messaging-api/src/main/java/net/roboconf/messaging/api/business/IClient.java
similarity index 98%
rename from core/roboconf-messaging-api/src/main/java/net/roboconf/messaging/api/client/IClient.java
rename to core/roboconf-messaging-api/src/main/java/net/roboconf/messaging/api/business/IClient.java
index da3749e0..55710d29 100644
--- a/core/roboconf-messaging-api/src/main/java/net/roboconf/messaging/api/client/IClient.java
+++ b/core/roboconf-messaging-api/src/main/java/net/roboconf/messaging/api/business/IClient.java
@@ -23,7 +23,7 @@
* limitations under the License.
*/
-package net.roboconf.messaging.api.client;
+package net.roboconf.messaging.api.business;
import java.io.IOException;
import java.util.Map;
diff --git a/core/roboconf-messaging-api/src/main/java/net/roboconf/messaging/api/client/IDmClient.java b/core/roboconf-messaging-api/src/main/java/net/roboconf/messaging/api/business/IDmClient.java
similarity index 98%
rename from core/roboconf-messaging-api/src/main/java/net/roboconf/messaging/api/client/IDmClient.java
rename to core/roboconf-messaging-api/src/main/java/net/roboconf/messaging/api/business/IDmClient.java
index 7b312366..9855a049 100644
--- a/core/roboconf-messaging-api/src/main/java/net/roboconf/messaging/api/client/IDmClient.java
+++ b/core/roboconf-messaging-api/src/main/java/net/roboconf/messaging/api/business/IDmClient.java
@@ -23,7 +23,7 @@
* limitations under the License.
*/
-package net.roboconf.messaging.api.client;
+package net.roboconf.messaging.api.business;
import java.io.IOException;
@@ -87,7 +87,7 @@ public interface IDmClient extends IClient {
*
*
* @param application the application the agent is associated with
- * @param rootInstance the root instance associated with the agent
+ * @param rootInstance the root instance associated with the agent (not null)
* @throws IOException if something went wrong
*/
void propagateAgentTermination( Application application, Instance rootInstance ) throws IOException;
diff --git a/core/roboconf-messaging-api/src/main/java/net/roboconf/messaging/api/client/ListenerCommand.java b/core/roboconf-messaging-api/src/main/java/net/roboconf/messaging/api/business/ListenerCommand.java
similarity index 96%
rename from core/roboconf-messaging-api/src/main/java/net/roboconf/messaging/api/client/ListenerCommand.java
rename to core/roboconf-messaging-api/src/main/java/net/roboconf/messaging/api/business/ListenerCommand.java
index cf5e6710..15cf8233 100644
--- a/core/roboconf-messaging-api/src/main/java/net/roboconf/messaging/api/client/ListenerCommand.java
+++ b/core/roboconf-messaging-api/src/main/java/net/roboconf/messaging/api/business/ListenerCommand.java
@@ -23,7 +23,7 @@
* limitations under the License.
*/
-package net.roboconf.messaging.api.client;
+package net.roboconf.messaging.api.business;
/**
* Start or stop listening to events.
diff --git a/core/roboconf-messaging-api/src/main/java/net/roboconf/messaging/api/extensions/AbstractRoutingClient.java b/core/roboconf-messaging-api/src/main/java/net/roboconf/messaging/api/extensions/AbstractRoutingClient.java
new file mode 100644
index 00000000..1ae70fe2
--- /dev/null
+++ b/core/roboconf-messaging-api/src/main/java/net/roboconf/messaging/api/extensions/AbstractRoutingClient.java
@@ -0,0 +1,304 @@
+/**
+ * Copyright 2014-2015 Linagora, Université Joseph Fourier, Floralis
+ *
+ * The present code is developed in the scope of the joint LINAGORA -
+ * Université Joseph Fourier - Floralis research program and is designated
+ * as a "Result" pursuant to the terms and conditions of the LINAGORA
+ * - Université Joseph Fourier - Floralis research program. Each copyright
+ * holder of Results enumerated here above fully & independently holds complete
+ * ownership of the complete Intellectual Property rights applicable to the whole
+ * of said Results, and may freely exploit it in any manner which does not infringe
+ * the moral rights of the other copyright holders.
+ *
+ * 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.
+ */
+
+package net.roboconf.messaging.api.extensions;
+
+import java.io.IOException;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.logging.Logger;
+
+import net.roboconf.core.model.beans.Application;
+import net.roboconf.messaging.api.MessagingConstants;
+import net.roboconf.messaging.api.extensions.MessagingContext.RecipientKind;
+import net.roboconf.messaging.api.messages.Message;
+
+/**
+ * A class to dispatch messages directly into message queues.
+ *
+ * This class can be used to replace a messaging server.
+ * It will directly route messages to the right "recipients".
+ *
+ *
+ * @param a handler class where messages will be directed to
+ * @author Vincent Zurczak - Linagora
+ */
+public abstract class AbstractRoutingClient implements IMessagingClient {
+
+ /**
+ * A bean to wrap routing contexts.
+ *
+ * At the beginning, routing contexts were stored as static final maps.
+ * Sub-classes were thus all sharing the same routing information. When used
+ * in stand-alone mode, it was fine. However, Roboconf allows to switch messaging
+ * type and such an organization would have had side effects.
+ *
+ *
+ * So, we replaced the static maps by a class.
+ * Each messaging factory should extend this class and pass it as an
+ * arguments to the agents it creates. This way, messaging clients that
+ * extends this class are isolated from other implementations.
+ *
+ *
+ * @author Vincent Zurczak - Linagora
+ */
+ public static abstract class RoutingContext {
+ public final Map> subscriptions = new ConcurrentHashMap<> ();
+ }
+
+
+ protected final RoutingContext routingContext;
+ protected final AtomicBoolean connected = new AtomicBoolean( false );
+ protected final Logger logger = Logger.getLogger( getClass().getName());
+
+ protected String ownerId, applicationName, scopedInstancePath;
+ protected boolean connectionIsRequired = true;
+
+
+
+ /**
+ * Constructor.
+ * @param routingContext
+ * @param ownerKind
+ */
+ public AbstractRoutingClient( RoutingContext routingContext, RecipientKind ownerKind ) {
+ this.routingContext = routingContext;
+ setOwnerProperties( ownerKind, null, null );
+ }
+
+
+ @Override
+ public void closeConnection() throws IOException {
+ this.logger.fine( getOwnerId() + " is closing its connection." );
+ this.connected.set( false );
+ }
+
+
+ @Override
+ public void openConnection() throws IOException {
+ this.logger.fine( getOwnerId() + " is opening a connection." );
+ this.connected.set( true );
+ }
+
+
+ @Override
+ public Map getConfiguration() {
+ return Collections.singletonMap(MessagingConstants.MESSAGING_TYPE_PROPERTY, getMessagingType());
+ }
+
+
+ @Override
+ public void deleteMessagingServerArtifacts( Application application ) throws IOException {
+
+ this.logger.fine( getOwnerId() + " is deleting server artifacts for " + application );
+ getStaticContextToObject().remove( this.ownerId );
+ this.routingContext.subscriptions.remove( this.ownerId );
+ }
+
+
+ @Override
+ public boolean isConnected() {
+ return this.connected.get();
+ }
+
+
+ @Override
+ public void subscribe( MessagingContext ctx ) throws IOException {
+ this.logger.fine( getOwnerId() + " is subscribing to " + buildOwnerId( ctx ));
+ subscribe( this.ownerId, ctx );
+ }
+
+
+ @Override
+ public void unsubscribe( MessagingContext ctx ) throws IOException {
+ this.logger.fine( getOwnerId() + " is unsubscribing to " + buildOwnerId( ctx ));
+ unsubscribe( this.ownerId, ctx );
+ }
+
+
+ @Override
+ public void publish( MessagingContext ctx, Message msg ) throws IOException {
+
+ this.logger.fine( getOwnerId() + " is publishing message (" + msg + ") to " + buildOwnerId( ctx ));
+ if( ! canProceed()) {
+ this.logger.fine( getOwnerId() + " is dropping message (" + msg + ") for " + buildOwnerId( ctx ));
+ return;
+ }
+
+ for( Map.Entry> entry : this.routingContext.subscriptions.entrySet()) {
+ if( ! entry.getValue().contains( ctx ))
+ continue;
+
+ T obj = getStaticContextToObject().get( entry.getKey());
+ if( obj != null )
+ process( obj, msg );
+ }
+ }
+
+
+ @Override
+ public void setOwnerProperties( RecipientKind ownerKind, String applicationName, String scopedInstancePath ) {
+
+ // Store the fields (the owner kind is not supposed to change)
+ this.applicationName = applicationName;
+ this.scopedInstancePath = scopedInstancePath;
+
+ // Update the client's owner ID
+ String newOwnerId = buildOwnerId( ownerKind, applicationName, scopedInstancePath );
+ this.logger.fine( "New owner ID in " + getMessagingType() + " client: " + newOwnerId );
+ if( this.ownerId == null) {
+ this.ownerId = newOwnerId;
+
+ } else if( ! newOwnerId.equals( this.ownerId )) {
+
+ // Switch the owner ID first.
+ // Other method calls will thus use the new version.
+ String oldOwnerId = this.ownerId;
+ this.ownerId = newOwnerId;
+
+ // Remove old values and associate them with the new key.
+ // FIXME: I am wondering whether we should not have synchronized accesses to the static maps.
+ // This could be a problem with dynamic reconfiguration of agents.
+ T obj = getStaticContextToObject().remove( oldOwnerId );
+ if( obj != null )
+ getStaticContextToObject().put( newOwnerId, obj );
+
+ Set subscriptions = this.routingContext.subscriptions.remove( oldOwnerId );
+ if( subscriptions != null )
+ this.routingContext.subscriptions.put( newOwnerId, subscriptions );
+ }
+ }
+
+
+ /**
+ * @return the routing context
+ */
+ public RoutingContext getRoutingContext() {
+ return this.routingContext;
+ }
+
+
+ /**
+ * @return the owner ID
+ */
+ public String getOwnerId() {
+ return this.ownerId;
+ }
+
+
+ /**
+ * Builds a unique ID.
+ * @param ownerKind the owner kind (not null)
+ * @param applicationName the application name (can be null)
+ * @param scopedInstancePath the scoped instance path (can be null)
+ * @return a non-null string
+ */
+ public static String buildOwnerId( RecipientKind ownerKind, String applicationName, String scopedInstancePath ) {
+
+ StringBuilder sb = new StringBuilder();
+ if( ownerKind == RecipientKind.DM ) {
+ sb.append( "@DM@" );
+
+ } else {
+ if( scopedInstancePath !=null ) {
+ sb.append( scopedInstancePath );
+ sb.append( " " );
+ }
+
+ if( applicationName != null ) {
+ sb.append( "@ " );
+ sb.append( applicationName );
+ }
+ }
+
+ return sb.toString().trim();
+ }
+
+
+ /**
+ * Builds a unique ID.
+ * @param ownerKind the owner kind (not null)
+ * @param applicationName the application name (can be null)
+ * @param scopedInstancePath the scoped instance path (can be null)
+ * @return a non-null string
+ */
+ public static String buildOwnerId( MessagingContext ctx ) {
+ return ctx == null ? null : buildOwnerId( ctx.getKind(), ctx.getApplicationName(), ctx.getComponentOrFacetName());
+ }
+
+
+ /**
+ * Registers a subscription between an ID and a context.
+ * @param id a client ID
+ * @param ctx a messaging context
+ * @throws IOException
+ */
+ protected void subscribe( String id, MessagingContext ctx ) throws IOException {
+
+ if( ! canProceed())
+ return;
+
+ Set sub = this.routingContext.subscriptions.get( id );
+ if( sub == null ) {
+ sub = new HashSet<> ();
+ this.routingContext.subscriptions.put( id, sub );
+ }
+
+ sub.add( ctx );
+ }
+
+
+ /**
+ * Unregisters a subscription between an ID and a context.
+ * @param id a client ID
+ * @param ctx a messaging context
+ * @throws IOException
+ */
+ protected void unsubscribe( String id, MessagingContext ctx ) throws IOException {
+
+ if( ! canProceed())
+ return;
+
+ Set sub = this.routingContext.subscriptions.get( id );
+ if( sub != null ) {
+ sub.remove( ctx );
+ if( sub.isEmpty())
+ this.routingContext.subscriptions.remove( id );
+ }
+ }
+
+
+ protected boolean canProceed() {
+ return ! this.connectionIsRequired || this.connected.get();
+ }
+
+
+ protected abstract Map getStaticContextToObject();
+ protected abstract void process( T obj, Message message ) throws IOException;
+}
diff --git a/core/roboconf-messaging-api/src/main/java/net/roboconf/messaging/api/extensions/IMessagingClient.java b/core/roboconf-messaging-api/src/main/java/net/roboconf/messaging/api/extensions/IMessagingClient.java
new file mode 100644
index 00000000..3bb289d9
--- /dev/null
+++ b/core/roboconf-messaging-api/src/main/java/net/roboconf/messaging/api/extensions/IMessagingClient.java
@@ -0,0 +1,127 @@
+/**
+ * Copyright 2015 Linagora, Université Joseph Fourier, Floralis
+ *
+ * The present code is developed in the scope of the joint LINAGORA -
+ * Université Joseph Fourier - Floralis research program and is designated
+ * as a "Result" pursuant to the terms and conditions of the LINAGORA
+ * - Université Joseph Fourier - Floralis research program. Each copyright
+ * holder of Results enumerated here above fully & independently holds complete
+ * ownership of the complete Intellectual Property rights applicable to the whole
+ * of said Results, and may freely exploit it in any manner which does not infringe
+ * the moral rights of the other copyright holders.
+ *
+ * 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.
+ */
+
+package net.roboconf.messaging.api.extensions;
+
+import java.io.IOException;
+import java.util.Map;
+import java.util.concurrent.LinkedBlockingQueue;
+
+import net.roboconf.core.model.beans.Application;
+import net.roboconf.messaging.api.extensions.MessagingContext.RecipientKind;
+import net.roboconf.messaging.api.messages.Message;
+
+/**
+ * @author Vincent Zurczak - Linagora
+ */
+public interface IMessagingClient {
+
+ /**
+ * Sets the message queue where the client can store the messages to process.
+ * @param messageQueue the message queue
+ */
+ void setMessageQueue( LinkedBlockingQueue messageQueue );
+
+ /**
+ * @return true if the client is connected, false otherwise
+ */
+ boolean isConnected();
+
+ /**
+ * Sets information about the Roboconf part that uses this client.
+ *
+ * This information can be changed dynamically.
+ * Said differently, this information is not final, it can change with time.
+ *
+ *
+ * @param ownerKind {@link RecipientKind#DM} or {@link RecipientKind#AGENTS}
+ * @param applicationName the application name (only makes sense for agents)
+ * @param scopedInstancePath the scoped instance path (only makes sense for agents)
+ */
+ void setOwnerProperties( RecipientKind ownerKind, String applicationName, String scopedInstancePath );
+
+ /**
+ * Opens a connection with the message server.
+ */
+ void openConnection() throws IOException;
+
+ /**
+ * Closes the connection with the message server.
+ *
+ * There is no need to check {@link #isConnected()} before invoking this method.
+ *
+ */
+ void closeConnection() throws IOException;
+
+ /**
+ * @return the type of messaging currently used by this client.
+ */
+ String getMessagingType();
+
+ /**
+ * Gets the provider-specific messaging configuration of this client.
+ *
+ * Messaging configuration is needed in order to configure a Roboconf VM, for instance when it is replicated.
+ *
+ * @return the provider-specific messaging configuration of this client. The returned map is unmodifiable.
+ */
+ // TODO: /!\ they may be differences between DM & agents messaging configurations (i.e HTTP server/client certificate, passwords, ...).
+ // Exposing everything in the same configuration may raise serious security issues.
+ Map getConfiguration();
+
+ /**
+ * Subscribes to a given context.
+ * @param ctx a messaging context (not null)
+ * @throws IOException if something went wrong
+ */
+ void subscribe( MessagingContext ctx ) throws IOException;
+
+ /**
+ * Unsubscribes to a given context.
+ * @param ctx a messaging context (not null)
+ * @throws IOException if something went wrong
+ */
+ void unsubscribe( MessagingContext ctx ) throws IOException;
+
+ /**
+ * Publishes a message.
+ * @param ctx a messaging context (not null)
+ * @param msg the message to publish (not null)
+ * @throws IOException if something went wrong
+ */
+ void publish( MessagingContext ctx, Message msg ) throws IOException;
+
+ /**
+ * Clear artifacts on the messaging server.
+ *
+ * This method is invoked when an application was deleted.
+ * It allows to remove topics or whatever that were related to the deleted application.
+ *
+ *
+ * @param application a non-null application
+ * @throws IOException if something went wrong
+ */
+ void deleteMessagingServerArtifacts( Application application ) throws IOException;
+}
diff --git a/core/roboconf-messaging-api/src/main/java/net/roboconf/messaging/api/extensions/MessagingContext.java b/core/roboconf-messaging-api/src/main/java/net/roboconf/messaging/api/extensions/MessagingContext.java
new file mode 100644
index 00000000..e56b940f
--- /dev/null
+++ b/core/roboconf-messaging-api/src/main/java/net/roboconf/messaging/api/extensions/MessagingContext.java
@@ -0,0 +1,328 @@
+/**
+ * Copyright 2015 Linagora, Université Joseph Fourier, Floralis
+ *
+ * The present code is developed in the scope of the joint LINAGORA -
+ * Université Joseph Fourier - Floralis research program and is designated
+ * as a "Result" pursuant to the terms and conditions of the LINAGORA
+ * - Université Joseph Fourier - Floralis research program. Each copyright
+ * holder of Results enumerated here above fully & independently holds complete
+ * ownership of the complete Intellectual Property rights applicable to the whole
+ * of said Results, and may freely exploit it in any manner which does not infringe
+ * the moral rights of the other copyright holders.
+ *
+ * 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.
+ */
+
+package net.roboconf.messaging.api.extensions;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+
+import net.roboconf.core.model.beans.ImportedVariable;
+import net.roboconf.core.model.beans.Instance;
+import net.roboconf.core.model.helpers.ComponentHelpers;
+import net.roboconf.core.model.helpers.VariableHelpers;
+import net.roboconf.core.utils.Utils;
+
+/**
+ * A context that identifies messages recipients and topic names.
+ *
+ * Three properties are part of this class.
+ * The kind identifies the message recipient. It can either be the DM,
+ * or agents or inter-application exchanges. The application name indicates
+ * an application scope for the listeners. And the topic name indicates more
+ * precise bindings. For agents, the topic name can be defined from a component
+ * or facet name and a "direction".
+ *
+ *
+ * When using the {@link RecipientKind #DM} kind, the topic name is ignored. The application
+ * name is kept to be reused as a topic name. In terms of messaging, there is only one DM.
+ * Even if we had to deploy several DM (for any reason), DM messages should be routed to all of them.
+ *
+ *
+ * Using the {@link RecipientKind #AGENTS} kind means we target a specific topic name
+ * in a given application. Both the topic name and the application name matter. Generally,
+ * we use an indirection to build the topic name. It is based on a component or facet name
+ * and a "direction" (target those that import a variable, or those that export it).
+ *
+ *
+ * Eventually, the {@link RecipientKind #INTER_APP} kind means exchanges between agents
+ * but without application scope (it is ignored). Only the topic name matters. We could have
+ * implemented this kind with the AGENTS one and a null application name. But having a distinct
+ * value for this use case will simplify debug. Besides, inter-application dependencies are
+ * a real Roboconf feature. It is not only a view of the messaging.
+ *
+ *
+ * @author Vincent Zurczak - Linagora
+ */
+public class MessagingContext implements Serializable {
+
+ private static final long serialVersionUID = 5529159467155629784L;
+
+ private final RecipientKind kind;
+ private final String componentOrFacetName, applicationName;
+ private final ThoseThat thoseThat;
+
+
+ /**
+ * Constructor.
+ * @param kind the recipient kind
+ * @param applicationName an application name
+ */
+ public MessagingContext( RecipientKind kind, String applicationName ) {
+ this( kind, null, null, applicationName );
+ }
+
+
+ /**
+ * Constructor.
+ * @param kind the recipient kind
+ * @param topicName a topic name
+ * @param applicationName an application name
+ */
+ public MessagingContext( RecipientKind kind, String topicName, String applicationName ) {
+ this( kind, topicName, null, applicationName );
+ }
+
+
+ /**
+ * Constructor.
+ *
+ * This is a convenience constructor that builds a topic name
+ * from a component or facet name and an agent direction. This constructor
+ * should be used when sending messages to agents.
+ *
+ *
+ * @param kind the recipient kind
+ * @param componentOrFacetName the component or facet name
+ * @param thoseThat do we target "those that export" or "those that import" componentOrFacetName?
+ * @param applicationName an application name
+ */
+ public MessagingContext( RecipientKind kind, String componentOrFacetName, ThoseThat thoseThat, String applicationName ) {
+ this.kind = kind;
+
+ if( kind == RecipientKind.DM ) {
+ // The application name will be used to build a topic name.
+ this.componentOrFacetName = null;
+ this.applicationName = applicationName;
+ this.thoseThat = null;
+
+ } else if( kind == RecipientKind.INTER_APP ) {
+ this.componentOrFacetName = componentOrFacetName;
+ this.thoseThat = thoseThat;
+ this.applicationName = null;
+
+ } else {
+ this.thoseThat = thoseThat;
+ this.componentOrFacetName = componentOrFacetName;
+ this.applicationName = applicationName;
+ }
+ }
+
+
+ public RecipientKind getKind() {
+ return this.kind;
+ }
+
+
+ public String getApplicationName() {
+ return this.applicationName;
+ }
+
+
+ public String getComponentOrFacetName() {
+ return this.componentOrFacetName;
+ }
+
+
+ public ThoseThat getAgentDirection() {
+ return this.thoseThat;
+ }
+
+
+ /**
+ * @return a topic name, or an empty string if none was specified
+ */
+ public String getTopicName() {
+
+ StringBuilder sb = new StringBuilder();
+ if( this.kind == RecipientKind.DM ) {
+ if( this.applicationName != null )
+ sb.append( this.applicationName );
+
+ } else {
+ if( this.thoseThat != null )
+ sb.append( this.thoseThat );
+
+ if( this.componentOrFacetName != null )
+ sb.append( this.componentOrFacetName );
+ }
+
+ return sb.toString();
+ }
+
+
+ @Override
+ public int hashCode() {
+
+ String topicName = getTopicName();
+ int backup = this.kind.hashCode();
+ return Utils.isEmptyOrWhitespaces( topicName ) ? backup : topicName.hashCode();
+ }
+
+
+ @Override
+ public boolean equals( Object obj ) {
+ return obj instanceof MessagingContext
+ && this.kind == ((MessagingContext ) obj).kind
+ && this.thoseThat == ((MessagingContext ) obj).thoseThat
+ && Objects.equals( this.componentOrFacetName, ((MessagingContext ) obj).componentOrFacetName )
+ && Objects.equals( this.applicationName, ((MessagingContext ) obj).applicationName );
+ }
+
+
+ @Override
+ public String toString() {
+
+ StringBuilder sb = new StringBuilder( getTopicName());
+ if( this.applicationName != null
+ && this.kind != RecipientKind.DM ) {
+ sb.append( " @ " );
+ sb.append( this.applicationName );
+ }
+
+ sb.append( " (" );
+ sb.append( this.kind );
+ sb.append( ")" );
+
+ return sb.toString().trim();
+ }
+
+
+ /**
+ * Builds a list of messaging contexts.
+ * @param applicationName the name of the agent's application
+ * @param instance the current instance
+ * @param thoseThat whether we target "those that import" or "those that export"
+ * @return a non-null list
+ */
+ public static Collection forImportedVariables(
+ String applicationName,
+ Instance instance,
+ ThoseThat thoseThat ) {
+
+ Map result = new HashMap<> ();
+ for( ImportedVariable var : ComponentHelpers.findAllImportedVariables( instance.getComponent()).values()) {
+ String componentOrApplicationTemplateName = VariableHelpers.parseVariableName( var.getName()).getKey();
+ if( result.containsKey( componentOrApplicationTemplateName ))
+ continue;
+
+ // When we import a variable, it is either internal or external, but not both!
+ RecipientKind kind = var.isExternal() ? RecipientKind.INTER_APP : RecipientKind.AGENTS;
+ MessagingContext ctx = new MessagingContext( kind, componentOrApplicationTemplateName, thoseThat, applicationName );
+ result.put( componentOrApplicationTemplateName, ctx );
+ }
+
+ return result.values();
+ }
+
+
+ /**
+ * Builds a list of messaging contexts.
+ * @param applicationName the name of the agent's application
+ * @param instance the current instance
+ * @param externalExports a non-null map that associates internal exported variables with global ones
+ * @param thoseThat whether we target "those that import" or "those that export"
+ * @return a non-null list
+ */
+ public static List forExportedVariables(
+ String applicationName,
+ Instance instance,
+ Map externalExports,
+ ThoseThat thoseThat ) {
+
+ List result = new ArrayList<> ();
+
+ // For inter-app messages, the real question is about whether we need
+ // to create a context for the application template.
+ Set externalExportPrefixes = new HashSet<> ();
+ for( String varName : externalExports.keySet()) {
+ String prefix = VariableHelpers.parseVariableName( varName ).getKey();
+ externalExportPrefixes.add( prefix );
+ }
+
+ // Internal variables
+ boolean publishExternal = false;
+ for( String facetOrComponentName : VariableHelpers.findPrefixesForExportedVariables( instance )) {
+ MessagingContext ctx = new MessagingContext( RecipientKind.AGENTS, facetOrComponentName, thoseThat, applicationName );
+ result.add( ctx );
+
+ if( externalExportPrefixes.contains( facetOrComponentName ))
+ publishExternal = true;
+ }
+
+ // External variables - they all have the same prefix, the application template's name
+ if( publishExternal ) {
+ String varName = externalExports.values().iterator().next();
+ String prefix = VariableHelpers.parseVariableName( varName ).getKey();
+
+ // We indicate the application name, but it will most likely not be used
+ // for inter-application messages.
+ MessagingContext ctx = new MessagingContext( RecipientKind.INTER_APP, prefix, thoseThat, applicationName );
+ result.add( ctx );
+ }
+
+ return result;
+ }
+
+
+ /**
+ * @author Vincent Zurczak - Linagora
+ */
+ public static enum RecipientKind {
+ INTER_APP, DM, AGENTS;
+ }
+
+
+ /**
+ * @author Vincent Zurczak - Linagora
+ */
+ public static enum ThoseThat {
+ EXPORT( "those.that.export." ),
+ IMPORT( "those.that.import." );
+
+ private String string;
+
+
+ /**
+ * Constructor.
+ * @param string
+ */
+ private ThoseThat( String string ) {
+ this.string = string;
+ }
+
+
+ @Override
+ public String toString() {
+ return this.string;
+ }
+ }
+}
diff --git a/core/roboconf-messaging-api/src/main/java/net/roboconf/messaging/api/factory/IMessagingClientFactory.java b/core/roboconf-messaging-api/src/main/java/net/roboconf/messaging/api/factory/IMessagingClientFactory.java
index 565f0db0..b9650e20 100644
--- a/core/roboconf-messaging-api/src/main/java/net/roboconf/messaging/api/factory/IMessagingClientFactory.java
+++ b/core/roboconf-messaging-api/src/main/java/net/roboconf/messaging/api/factory/IMessagingClientFactory.java
@@ -27,11 +27,8 @@
import java.util.Map;
-import net.roboconf.messaging.api.MessagingConstants;
-import net.roboconf.messaging.api.client.IAgentClient;
-import net.roboconf.messaging.api.client.IDmClient;
-import net.roboconf.messaging.api.reconfigurables.ReconfigurableClientAgent;
-import net.roboconf.messaging.api.reconfigurables.ReconfigurableClientDm;
+import net.roboconf.messaging.api.extensions.IMessagingClient;
+import net.roboconf.messaging.api.reconfigurables.ReconfigurableClient;
/**
* A service that allows to create Roboconf messaging clients.
@@ -39,37 +36,18 @@
*/
public interface IMessagingClientFactory {
- /**
- * Service property indicating the type of messaging this factory provides.
- *
- * This property is mandatory, its value is immutable and must be an non-null {@code String}.
- *
- * @see #getType()
- * @see MessagingConstants#MESSAGING_TYPE_PROPERTY
- */
- String MESSAGING_TYPE_PROPERTY = MessagingConstants.MESSAGING_TYPE_PROPERTY;
-
/**
* Get the type of messaging this factory supports.
* @return the type of messaging this factory supports.
- * @see #MESSAGING_TYPE_PROPERTY
*/
String getType();
/**
- * Creates a messaging client for the DM.
- * @return the created DM messaging client.
- * @param parent the parent client.
- */
- IDmClient createDmClient( ReconfigurableClientDm parent );
-
-
- /**
- * Creates a messaging client for an agent.
- * @return the created agent messaging client.
- * @param parent the parent client.
+ * Creates a messaging client.
+ * @return the created messaging client
+ * @param parent the parent client
*/
- IAgentClient createAgentClient( ReconfigurableClientAgent parent );
+ IMessagingClient createClient( ReconfigurableClient> parent );
/**
* Attempts to apply the given provider-specific messaging configuration to this factory.
diff --git a/core/roboconf-messaging-api/src/main/java/net/roboconf/messaging/api/factory/MessagingClientFactoryListener.java b/core/roboconf-messaging-api/src/main/java/net/roboconf/messaging/api/factory/MessagingClientFactoryListener.java
index 542edc36..1ab2294b 100644
--- a/core/roboconf-messaging-api/src/main/java/net/roboconf/messaging/api/factory/MessagingClientFactoryListener.java
+++ b/core/roboconf-messaging-api/src/main/java/net/roboconf/messaging/api/factory/MessagingClientFactoryListener.java
@@ -46,5 +46,4 @@ public interface MessagingClientFactoryListener {
* @param factory the disappearing messaging client factory.
*/
void removeMessagingClientFactory(IMessagingClientFactory factory);
-
}
diff --git a/core/roboconf-messaging-api/src/main/java/net/roboconf/messaging/api/factory/MessagingClientFactoryRegistry.java b/core/roboconf-messaging-api/src/main/java/net/roboconf/messaging/api/factory/MessagingClientFactoryRegistry.java
index f8422d45..7719b73d 100644
--- a/core/roboconf-messaging-api/src/main/java/net/roboconf/messaging/api/factory/MessagingClientFactoryRegistry.java
+++ b/core/roboconf-messaging-api/src/main/java/net/roboconf/messaging/api/factory/MessagingClientFactoryRegistry.java
@@ -47,29 +47,30 @@ public class MessagingClientFactoryRegistry {
/**
* The messaging client factories.
*/
- private final ConcurrentHashMap factories = new ConcurrentHashMap<>();
+ private final ConcurrentHashMap factories = new ConcurrentHashMap<> ();
/**
* The messaging client factory listeners.
*/
- private final ConcurrentLinkedQueue listeners = new ConcurrentLinkedQueue<>();
+ private final ConcurrentLinkedQueue listeners = new ConcurrentLinkedQueue<> ();
/**
* The logger.
*/
- private final Logger logger = Logger.getLogger(this.getClass().getName());
+ private final Logger logger = Logger.getLogger( getClass().getName());
+
+
/**
* @return the messaging client factory with the given type, or {@code null} if there is no registered factory
* with the given type.
*/
public IMessagingClientFactory getMessagingClientFactory(String type) {
- final IMessagingClientFactory result;
- if (type != null) {
+
+ IMessagingClientFactory result = null;
+ if (type != null)
result = this.factories.get(type);
- } else {
- result = null;
- }
+
return result;
}
@@ -79,12 +80,13 @@ public IMessagingClientFactory getMessagingClientFactory(String type) {
* @return {@code true} if the factory has been added, {@code false} if a factory with the same type was already registered.
*/
public boolean addMessagingClientFactory(IMessagingClientFactory factory) {
+
final String type = factory.getType();
this.logger.fine("Adding messaging client factory: " + type);
final boolean result = this.factories.putIfAbsent(type, factory) == null;
- if (result) {
+ if (result)
notifyListeners(factory, true);
- }
+
return result;
}
@@ -94,12 +96,13 @@ public boolean addMessagingClientFactory(IMessagingClientFactory factory) {
* @return {@code true} if the factory has been removed, {@code false} if the factory was not registered.
*/
public boolean removeMessagingClientFactory(IMessagingClientFactory factory) {
+
final String type = factory.getType();
this.logger.fine("Removing messaging client factory: " + type);
final boolean result = this.factories.remove(type, factory);
- if (result) {
+ if (result)
notifyListeners(factory, false);
- }
+
return result;
}
@@ -125,19 +128,21 @@ public void removeListener(MessagingClientFactoryListener listener) {
this.listeners.remove(listener);
}
+
/**
* Notifies the messaging client factory listeners that a factory has been added/removed.
* @param factory the incoming/outgoing messaging client factory.
* @param isAdded flag indicating whether the factory has been added or removed.
*/
private void notifyListeners(IMessagingClientFactory factory, boolean isAdded) {
+
for (MessagingClientFactoryListener listener : this.listeners) {
try {
- if (isAdded) {
+ if (isAdded)
listener.addMessagingClientFactory(factory);
- } else {
+ else
listener.removeMessagingClientFactory(factory);
- }
+
} catch (Throwable t) {
// Log the exception, but *do not* interrupt the notification of the other listeners.
this.logger.warning("Messaging client factory listener has thrown an exception: " + listener);
@@ -145,5 +150,4 @@ private void notifyListeners(IMessagingClientFactory factory, boolean isAdded) {
}
}
}
-
}
diff --git a/core/roboconf-messaging-api/src/main/java/net/roboconf/messaging/api/internal/client/dismiss/DismissClientDm.java b/core/roboconf-messaging-api/src/main/java/net/roboconf/messaging/api/internal/client/dismiss/DismissClient.java
similarity index 56%
rename from core/roboconf-messaging-api/src/main/java/net/roboconf/messaging/api/internal/client/dismiss/DismissClientDm.java
rename to core/roboconf-messaging-api/src/main/java/net/roboconf/messaging/api/internal/client/dismiss/DismissClient.java
index 0ec37428..8bab30d4 100644
--- a/core/roboconf-messaging-api/src/main/java/net/roboconf/messaging/api/internal/client/dismiss/DismissClientDm.java
+++ b/core/roboconf-messaging-api/src/main/java/net/roboconf/messaging/api/internal/client/dismiss/DismissClient.java
@@ -1,5 +1,5 @@
/**
- * Copyright 2014-2015 Linagora, Université Joseph Fourier, Floralis
+ * Copyright 2015 Linagora, Université Joseph Fourier, Floralis
*
* The present code is developed in the scope of the joint LINAGORA -
* Université Joseph Fourier - Floralis research program and is designated
@@ -32,91 +32,82 @@
import java.util.logging.Logger;
import net.roboconf.core.model.beans.Application;
-import net.roboconf.core.model.beans.Instance;
-import net.roboconf.messaging.api.MessagingConstants;
-import net.roboconf.messaging.api.client.IDmClient;
-import net.roboconf.messaging.api.client.ListenerCommand;
+import net.roboconf.messaging.api.extensions.IMessagingClient;
+import net.roboconf.messaging.api.extensions.MessagingContext;
+import net.roboconf.messaging.api.extensions.MessagingContext.RecipientKind;
import net.roboconf.messaging.api.messages.Message;
/**
* @author Vincent Zurczak - Linagora
- * @author Pierre Bourret - Université Joseph Fourier
*/
-public class DismissClientDm implements IDmClient {
+public class DismissClient implements IMessagingClient {
+ private static final String DISMISSED_MESSAGE = "No messaging client is available. Action is dismissed. Review the messaging configuration.";
private final Logger logger = Logger.getLogger( getClass().getName());
@Override
public void setMessageQueue( LinkedBlockingQueue messageQueue ) {
- this.logger.warning( MessagingConstants.DISMISSED_MESSAGE );
+ this.logger.warning( DISMISSED_MESSAGE );
}
@Override
public boolean isConnected() {
- this.logger.warning( MessagingConstants.DISMISSED_MESSAGE );
return false;
}
@Override
public void openConnection() throws IOException {
- this.logger.warning( MessagingConstants.DISMISSED_MESSAGE );
+ this.logger.warning( DISMISSED_MESSAGE );
}
@Override
public void closeConnection() throws IOException {
- this.logger.warning( MessagingConstants.DISMISSED_MESSAGE );
+ this.logger.warning( DISMISSED_MESSAGE );
}
@Override
- public void sendMessageToAgent( Application application, Instance instance, Message message )
- throws IOException {
- this.logger.warning( MessagingConstants.DISMISSED_MESSAGE );
+ public String getMessagingType() {
+ return "dismissed";
}
@Override
- public void listenToAgentMessages( Application application, ListenerCommand command )
- throws IOException {
- this.logger.warning( MessagingConstants.DISMISSED_MESSAGE );
- }
-
- @Override
- public void sendMessageToTheDm( Message msg ) throws IOException {
- this.logger.warning( MessagingConstants.DISMISSED_MESSAGE );
+ public Map getConfiguration() {
+ return Collections.emptyMap();
}
@Override
- public void listenToTheDm( ListenerCommand command ) throws IOException {
- this.logger.warning( MessagingConstants.DISMISSED_MESSAGE );
+ public void subscribe( MessagingContext ctx ) throws IOException {
+ this.logger.warning( DISMISSED_MESSAGE );
}
+
@Override
- public String getMessagingType() {
- return null;
+ public void unsubscribe( MessagingContext ctx ) throws IOException {
+ this.logger.warning( DISMISSED_MESSAGE );
}
@Override
- public Map getConfiguration() {
- // Dismiss client has no configuration.
- return Collections.emptyMap();
+ public void publish( MessagingContext ctx, Message msg ) throws IOException {
+ this.logger.warning( DISMISSED_MESSAGE );
}
+
@Override
- public void deleteMessagingServerArtifacts( Application application )
- throws IOException {
- this.logger.warning( MessagingConstants.DISMISSED_MESSAGE );
+ public void deleteMessagingServerArtifacts( Application application ) throws IOException {
+ this.logger.warning( DISMISSED_MESSAGE );
}
@Override
- public void propagateAgentTermination( Application application, Instance rootInstance ) throws IOException {
- this.logger.warning( MessagingConstants.DISMISSED_MESSAGE );
+ public void setOwnerProperties( RecipientKind ownerKind, String applicationName, String scopedInstancePath ) {
+ this.logger.warning( DISMISSED_MESSAGE );
}
}
diff --git a/core/roboconf-messaging-api/src/main/java/net/roboconf/messaging/api/internal/client/dismiss/DismissClientAgent.java b/core/roboconf-messaging-api/src/main/java/net/roboconf/messaging/api/internal/client/dismiss/DismissClientAgent.java
deleted file mode 100644
index e6c6b50b..00000000
--- a/core/roboconf-messaging-api/src/main/java/net/roboconf/messaging/api/internal/client/dismiss/DismissClientAgent.java
+++ /dev/null
@@ -1,151 +0,0 @@
-/**
- * Copyright 2014-2015 Linagora, Université Joseph Fourier, Floralis
- *
- * The present code is developed in the scope of the joint LINAGORA -
- * Université Joseph Fourier - Floralis research program and is designated
- * as a "Result" pursuant to the terms and conditions of the LINAGORA
- * - Université Joseph Fourier - Floralis research program. Each copyright
- * holder of Results enumerated here above fully & independently holds complete
- * ownership of the complete Intellectual Property rights applicable to the whole
- * of said Results, and may freely exploit it in any manner which does not infringe
- * the moral rights of the other copyright holders.
- *
- * 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.
- */
-
-package net.roboconf.messaging.api.internal.client.dismiss;
-
-import java.io.IOException;
-import java.util.Collections;
-import java.util.Map;
-import java.util.concurrent.LinkedBlockingQueue;
-import java.util.logging.Logger;
-
-import net.roboconf.core.model.beans.Instance;
-import net.roboconf.messaging.api.MessagingConstants;
-import net.roboconf.messaging.api.client.IAgentClient;
-import net.roboconf.messaging.api.client.ListenerCommand;
-import net.roboconf.messaging.api.messages.Message;
-
-/**
- * @author Vincent Zurczak - Linagora
- */
-public class DismissClientAgent implements IAgentClient {
-
- private final Logger logger = Logger.getLogger( getClass().getName());
-
-
- @Override
- public void setMessageQueue( LinkedBlockingQueue messageQueue ) {
- this.logger.warning( MessagingConstants.DISMISSED_MESSAGE );
- }
-
-
- @Override
- public boolean isConnected() {
- this.logger.warning( MessagingConstants.DISMISSED_MESSAGE );
- return false;
- }
-
-
- @Override
- public void openConnection() throws IOException {
- this.logger.warning( MessagingConstants.DISMISSED_MESSAGE );
- }
-
-
- @Override
- public void closeConnection() throws IOException {
- this.logger.warning( MessagingConstants.DISMISSED_MESSAGE );
- }
-
-
- @Override
- public void setApplicationName( String applicationName ) {
- this.logger.warning( MessagingConstants.DISMISSED_MESSAGE );
- }
-
-
- @Override
- public void setScopedInstancePath( String scopedInstancePath ) {
- this.logger.warning( MessagingConstants.DISMISSED_MESSAGE );
- }
-
-
- @Override
- public void setExternalMapping( Map externalExports ) {
- this.logger.warning( MessagingConstants.DISMISSED_MESSAGE );
- }
-
-
- @Override
- public void publishExports( Instance instance ) throws IOException {
- this.logger.warning( MessagingConstants.DISMISSED_MESSAGE );
- }
-
-
- @Override
- public void publishExports( Instance instance, String facetOrComponentName ) throws IOException {
- this.logger.warning( MessagingConstants.DISMISSED_MESSAGE );
- }
-
-
- @Override
- public void unpublishExports( Instance instance ) throws IOException {
- this.logger.warning( MessagingConstants.DISMISSED_MESSAGE );
- }
-
-
- @Override
- public void listenToRequestsFromOtherAgents( ListenerCommand command, Instance instance ) throws IOException {
- this.logger.warning( MessagingConstants.DISMISSED_MESSAGE );
- }
-
-
- @Override
- public void requestExportsFromOtherAgents( Instance instance ) throws IOException {
- this.logger.warning( MessagingConstants.DISMISSED_MESSAGE );
- }
-
-
- @Override
- public void listenToExportsFromOtherAgents( ListenerCommand command, Instance instance ) throws IOException {
- this.logger.warning( MessagingConstants.DISMISSED_MESSAGE );
- }
-
-
- @Override
- public void sendMessageToTheDm( Message message ) throws IOException {
- this.logger.warning( MessagingConstants.DISMISSED_MESSAGE );
- }
-
-
- @Override
- public void listenToTheDm( ListenerCommand command ) throws IOException {
- this.logger.warning( MessagingConstants.DISMISSED_MESSAGE );
- }
-
-
- @Override
- public String getMessagingType() {
- // Dismiss client has no type.
- return null;
- }
-
-
- @Override
- public Map getConfiguration() {
- // Dismiss client has no configuration.
- return Collections.emptyMap();
- }
-}
diff --git a/core/roboconf-messaging-api/src/main/java/net/roboconf/messaging/api/internal/client/in_memory/InMemoryClient.java b/core/roboconf-messaging-api/src/main/java/net/roboconf/messaging/api/internal/client/in_memory/InMemoryClient.java
new file mode 100644
index 00000000..d6859fd2
--- /dev/null
+++ b/core/roboconf-messaging-api/src/main/java/net/roboconf/messaging/api/internal/client/in_memory/InMemoryClient.java
@@ -0,0 +1,93 @@
+/**
+ * Copyright 2014-2015 Linagora, Université Joseph Fourier, Floralis
+ *
+ * The present code is developed in the scope of the joint LINAGORA -
+ * Université Joseph Fourier - Floralis research program and is designated
+ * as a "Result" pursuant to the terms and conditions of the LINAGORA
+ * - Université Joseph Fourier - Floralis research program. Each copyright
+ * holder of Results enumerated here above fully & independently holds complete
+ * ownership of the complete Intellectual Property rights applicable to the whole
+ * of said Results, and may freely exploit it in any manner which does not infringe
+ * the moral rights of the other copyright holders.
+ *
+ * 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.
+ */
+
+package net.roboconf.messaging.api.internal.client.in_memory;
+
+import java.io.IOException;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.LinkedBlockingQueue;
+
+import net.roboconf.messaging.api.MessagingConstants;
+import net.roboconf.messaging.api.extensions.AbstractRoutingClient;
+import net.roboconf.messaging.api.extensions.MessagingContext.RecipientKind;
+import net.roboconf.messaging.api.messages.Message;
+
+/**
+ * A class to dispatch messages directly into message queues.
+ *
+ * This solution only works when the DM and ALL the agents run in the same JVM.
+ * So, it should only work with in-memory agents, and maybe with locally "embedded" agents.
+ *
+ *
+ * @author Vincent Zurczak - Linagora
+ */
+public class InMemoryClient extends AbstractRoutingClient> {
+
+ /**
+ * @author Vincent Zurczak - Linagora
+ */
+ public static class InMemoryRoutingContext extends RoutingContext {
+ public final Map> ctxToQueue = new ConcurrentHashMap<> ();
+ }
+
+ // Internal field (for a convenient access).
+ private final Map> ctxToQueue;
+
+
+ /**
+ * Constructor.
+ * @param routingContext
+ * @param ownerKind
+ */
+ public InMemoryClient( InMemoryRoutingContext routingContext, RecipientKind ownerKind ) {
+ super( routingContext, ownerKind );
+ this.ctxToQueue = routingContext.ctxToQueue;
+ }
+
+
+ @Override
+ public void setMessageQueue( LinkedBlockingQueue messageQueue ) {
+ this.ctxToQueue.put( this.ownerId, messageQueue );
+ }
+
+
+ @Override
+ protected Map> getStaticContextToObject() {
+ return this.ctxToQueue;
+ }
+
+
+ @Override
+ public String getMessagingType() {
+ return MessagingConstants.FACTORY_IN_MEMORY;
+ }
+
+
+ @Override
+ protected void process( LinkedBlockingQueue queue, Message message ) throws IOException {
+ queue.add( message );
+ }
+}
diff --git a/core/roboconf-messaging-api/src/main/java/net/roboconf/messaging/api/internal/client/in_memory/InMemoryClientFactory.java b/core/roboconf-messaging-api/src/main/java/net/roboconf/messaging/api/internal/client/in_memory/InMemoryClientFactory.java
new file mode 100644
index 00000000..5cbc2c99
--- /dev/null
+++ b/core/roboconf-messaging-api/src/main/java/net/roboconf/messaging/api/internal/client/in_memory/InMemoryClientFactory.java
@@ -0,0 +1,60 @@
+/**
+ * Copyright 2014-2015 Linagora, Université Joseph Fourier, Floralis
+ *
+ * The present code is developed in the scope of the joint LINAGORA -
+ * Université Joseph Fourier - Floralis research program and is designated
+ * as a "Result" pursuant to the terms and conditions of the LINAGORA
+ * - Université Joseph Fourier - Floralis research program. Each copyright
+ * holder of Results enumerated here above fully & independently holds complete
+ * ownership of the complete Intellectual Property rights applicable to the whole
+ * of said Results, and may freely exploit it in any manner which does not infringe
+ * the moral rights of the other copyright holders.
+ *
+ * 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.
+ */
+
+package net.roboconf.messaging.api.internal.client.in_memory;
+
+import java.util.Map;
+
+import net.roboconf.messaging.api.MessagingConstants;
+import net.roboconf.messaging.api.extensions.IMessagingClient;
+import net.roboconf.messaging.api.factory.IMessagingClientFactory;
+import net.roboconf.messaging.api.internal.client.in_memory.InMemoryClient.InMemoryRoutingContext;
+import net.roboconf.messaging.api.reconfigurables.ReconfigurableClient;
+
+/**
+ * Messaging client factory for tests.
+ * @author Pierre Bourret - Université Joseph Fourier
+ */
+public class InMemoryClientFactory implements IMessagingClientFactory {
+
+ private final InMemoryRoutingContext routingContext = new InMemoryRoutingContext();
+
+
+ @Override
+ public String getType() {
+ return MessagingConstants.FACTORY_IN_MEMORY;
+ }
+
+ @Override
+ public IMessagingClient createClient( final ReconfigurableClient> parent ) {
+ return new InMemoryClient( this.routingContext, parent.getOwnerKind());
+ }
+
+ @Override
+ public boolean setConfiguration( final Map configuration ) {
+ String messagingType = configuration.get( MessagingConstants.MESSAGING_TYPE_PROPERTY );
+ return MessagingConstants.FACTORY_IN_MEMORY.equals( messagingType );
+ }
+}
diff --git a/core/roboconf-messaging-api/src/main/java/net/roboconf/messaging/api/internal/client/test/TestClientDm.java b/core/roboconf-messaging-api/src/main/java/net/roboconf/messaging/api/internal/client/test/TestClient.java
similarity index 59%
rename from core/roboconf-messaging-api/src/main/java/net/roboconf/messaging/api/internal/client/test/TestClientDm.java
rename to core/roboconf-messaging-api/src/main/java/net/roboconf/messaging/api/internal/client/test/TestClient.java
index 22d1176d..c2115a1c 100644
--- a/core/roboconf-messaging-api/src/main/java/net/roboconf/messaging/api/internal/client/test/TestClientDm.java
+++ b/core/roboconf-messaging-api/src/main/java/net/roboconf/messaging/api/internal/client/test/TestClient.java
@@ -28,16 +28,19 @@
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
import java.util.List;
import java.util.Map;
+import java.util.Set;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.atomic.AtomicBoolean;
import net.roboconf.core.model.beans.Application;
-import net.roboconf.core.model.beans.Instance;
import net.roboconf.messaging.api.MessagingConstants;
-import net.roboconf.messaging.api.client.IDmClient;
-import net.roboconf.messaging.api.client.ListenerCommand;
+import net.roboconf.messaging.api.extensions.IMessagingClient;
+import net.roboconf.messaging.api.extensions.MessagingContext;
+import net.roboconf.messaging.api.extensions.MessagingContext.RecipientKind;
import net.roboconf.messaging.api.messages.Message;
/**
@@ -45,14 +48,20 @@
* @author Vincent Zurczak - Linagora
* @author Pierre Bourret - Université Joseph Fourier
*/
-public class TestClientDm implements IDmClient {
+public class TestClient implements IMessagingClient {
- public final List sentMessages = new ArrayList ();
public AtomicBoolean connected = new AtomicBoolean( false );
public AtomicBoolean failClosingConnection = new AtomicBoolean( false );
- public AtomicBoolean failListeningToTheDm = new AtomicBoolean( false );
+ public AtomicBoolean failSubscribing = new AtomicBoolean( false );
public AtomicBoolean failMessageSending = new AtomicBoolean( false );
+ public Map> ctxToMessages = new HashMap<> ();
+ public List messagesForTheDm = new ArrayList<> ();
+ public List messagesForAgents = new ArrayList<> ();
+ public List allSentMessages = new ArrayList<> ();
+ public Set subscriptions = new HashSet<> ();
+
+
@Override
public void closeConnection() throws IOException {
@@ -62,73 +71,96 @@ public void closeConnection() throws IOException {
this.connected.set( false );
}
+
@Override
public void openConnection() throws IOException {
this.connected.set( true );
}
+
@Override
- public void sendMessageToAgent( Application application, Instance instance, Message message )
- throws IOException {
+ public String getMessagingType() {
+ return MessagingConstants.FACTORY_TEST;
+ }
- if( this.failMessageSending.get())
- throw new IOException( "Message sending was configured to fail." );
- this.sentMessages.add( message );
+ @Override
+ public Map getConfiguration() {
+ return Collections.singletonMap(MessagingConstants.MESSAGING_TYPE_PROPERTY, MessagingConstants.FACTORY_TEST);
}
+
@Override
- public void listenToAgentMessages( Application application, ListenerCommand command )
+ public void deleteMessagingServerArtifacts( Application application )
throws IOException {
// nothing, we do not care
}
+
@Override
- public void sendMessageToTheDm( Message msg ) throws IOException {
+ public boolean isConnected() {
+ return this.connected.get();
+ }
- if ( this.failMessageSending.get() )
- throw new IOException( "Message sending was configured to fail." );
- this.sentMessages.add( msg );
+ @Override
+ public void setMessageQueue( LinkedBlockingQueue messageQueue ) {
+ // nothing
}
+
@Override
- public void listenToTheDm( ListenerCommand command ) throws IOException {
+ public void subscribe( MessagingContext ctx ) throws IOException {
- if( this.failListeningToTheDm.get())
- throw new IOException( "Listening to the DM was configured to fail." );
- }
+ if( this.failSubscribing.get())
+ throw new IOException( "Subscribing was configured to fail." );
- @Override
- public String getMessagingType() {
- return MessagingConstants.TEST_FACTORY_TYPE;
+ this.subscriptions.add( ctx );
}
- @Override
- public Map getConfiguration() {
- return Collections.singletonMap(MessagingConstants.MESSAGING_TYPE_PROPERTY, MessagingConstants.TEST_FACTORY_TYPE);
- }
@Override
- public void deleteMessagingServerArtifacts( Application application )
- throws IOException {
- // nothing, we do not care
+ public void unsubscribe( MessagingContext ctx ) throws IOException {
+ this.subscriptions.remove( ctx );
}
- @Override
- public boolean isConnected() {
- return this.connected.get();
- }
@Override
- public void setMessageQueue( LinkedBlockingQueue messageQueue ) {
- // nothing
+ public void publish( MessagingContext ctx, Message msg ) throws IOException {
+
+ if( this.failMessageSending.get())
+ throw new IOException( "Sending a message was configured to fail." );
+
+ List messages = this.ctxToMessages.get( ctx );
+ if( messages == null ) {
+ messages = new ArrayList<> ();
+ this.ctxToMessages.put( ctx, messages );
+ }
+
+ messages.add( msg );
+
+ this.allSentMessages.add( msg );
+ if( ctx.getKind() == RecipientKind.DM )
+ this.messagesForTheDm.add( msg );
+ else
+ this.messagesForAgents.add( msg );
}
+
@Override
- public void propagateAgentTermination( Application application, Instance rootInstance )
- throws IOException {
- // nothing
+ public void setOwnerProperties( RecipientKind ownerKind, String applicationName, String scopedInstancePath ) {
+ // We do not care...
}
+
+ /**
+ * Clears all the stored messages.
+ */
+ public void clearMessages() {
+
+ this.ctxToMessages.clear();
+ this.messagesForAgents.clear();
+ this.messagesForTheDm.clear();
+ this.allSentMessages.clear();
+ }
}
diff --git a/core/roboconf-messaging-api/src/main/java/net/roboconf/messaging/api/internal/client/test/TestClientAgent.java b/core/roboconf-messaging-api/src/main/java/net/roboconf/messaging/api/internal/client/test/TestClientAgent.java
deleted file mode 100644
index dd26fe90..00000000
--- a/core/roboconf-messaging-api/src/main/java/net/roboconf/messaging/api/internal/client/test/TestClientAgent.java
+++ /dev/null
@@ -1,185 +0,0 @@
-/**
- * Copyright 2014-2015 Linagora, Université Joseph Fourier, Floralis
- *
- * The present code is developed in the scope of the joint LINAGORA -
- * Université Joseph Fourier - Floralis research program and is designated
- * as a "Result" pursuant to the terms and conditions of the LINAGORA
- * - Université Joseph Fourier - Floralis research program. Each copyright
- * holder of Results enumerated here above fully & independently holds complete
- * ownership of the complete Intellectual Property rights applicable to the whole
- * of said Results, and may freely exploit it in any manner which does not infringe
- * the moral rights of the other copyright holders.
- *
- * 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.
- */
-
-package net.roboconf.messaging.api.internal.client.test;
-
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.LinkedBlockingQueue;
-import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.concurrent.atomic.AtomicInteger;
-
-import net.roboconf.core.model.beans.Instance;
-import net.roboconf.messaging.api.MessagingConstants;
-import net.roboconf.messaging.api.client.IAgentClient;
-import net.roboconf.messaging.api.client.ListenerCommand;
-import net.roboconf.messaging.api.messages.Message;
-
-/**
- * @author Vincent Zurczak - Linagora
- */
-public class TestClientAgent implements IAgentClient {
-
- public final List messagesForTheDm = new ArrayList<> ();
- public AtomicInteger messagesForAgentsCount = new AtomicInteger();
- public AtomicBoolean connected = new AtomicBoolean( false );
- public AtomicBoolean failMessageSending = new AtomicBoolean( false );
- // TODO(?) : May be a good idea to make the previous parameters configurable via setConfiguration().
-
- private String applicationName, scopedInstancePath;
- private Map externalExports;
-
-
- @Override
- public boolean isConnected() {
- return this.connected.get();
- }
-
- @Override
- public void openConnection() throws IOException {
- this.connected.set( true );
- }
-
- @Override
- public void closeConnection() throws IOException {
- this.connected.set( false );
- }
-
- @Override
- public void setApplicationName( String applicationName ) {
- this.applicationName = applicationName;
- }
-
- @Override
- public void setScopedInstancePath( String scopedInstancePath ) {
- this.scopedInstancePath = scopedInstancePath;
- }
-
- @Override
- public void setExternalMapping( Map externalExports ) {
- this.externalExports = externalExports;
- }
-
- @Override
- public void publishExports( Instance instance ) throws IOException {
-
- if( this.failMessageSending.get())
- throw new IOException( "Message sending was configured to fail." );
-
- this.messagesForAgentsCount.incrementAndGet();
- }
-
- @Override
- public void publishExports( Instance instance, String facetOrComponentName ) throws IOException {
-
- if( this.failMessageSending.get())
- throw new IOException( "Message sending was configured to fail." );
-
- this.messagesForAgentsCount.incrementAndGet();
- }
-
- @Override
- public void unpublishExports( Instance instance ) throws IOException {
-
- if( this.failMessageSending.get())
- throw new IOException( "Message sending was configured to fail." );
-
- this.messagesForAgentsCount.incrementAndGet();
- }
-
- @Override
- public void listenToRequestsFromOtherAgents( ListenerCommand command, Instance instance )
- throws IOException {
- // nothing
- }
-
- @Override
- public void requestExportsFromOtherAgents( Instance instance ) throws IOException {
-
- if( this.failMessageSending.get())
- throw new IOException( "Message sending was configured to fail." );
-
- this.messagesForAgentsCount.incrementAndGet();
- }
-
- @Override
- public void listenToExportsFromOtherAgents( ListenerCommand command, Instance instance )
- throws IOException {
- // nothing
- }
-
- @Override
- public void sendMessageToTheDm( Message message ) throws IOException {
-
- if( this.failMessageSending.get())
- throw new IOException( "Message sending was configured to fail." );
-
- this.messagesForTheDm.add( message );
- }
-
- @Override
- public void listenToTheDm( ListenerCommand command ) throws IOException {
- // nothing
- }
-
- @Override
- public String getMessagingType() {
- return MessagingConstants.TEST_FACTORY_TYPE;
- }
-
- @Override
- public Map getConfiguration() {
- return Collections.singletonMap(MessagingConstants.MESSAGING_TYPE_PROPERTY, MessagingConstants.TEST_FACTORY_TYPE);
- }
-
- @Override
- public void setMessageQueue( LinkedBlockingQueue messageQueue ) {
- // nothing
- }
-
- /**
- * @return the applicationName
- */
- public String getApplicationName() {
- return this.applicationName;
- }
-
- /**
- * @return the scopedInstancePath
- */
- public String getScopedInstancePath() {
- return this.scopedInstancePath;
- }
-
- /**
- * @return the externalExports
- */
- public Map getExternalExports() {
- return this.externalExports;
- }
-}
diff --git a/core/roboconf-messaging-api/src/main/java/net/roboconf/messaging/api/internal/client/test/TestClientFactory.java b/core/roboconf-messaging-api/src/main/java/net/roboconf/messaging/api/internal/client/test/TestClientFactory.java
index bb30bc01..b4104e10 100644
--- a/core/roboconf-messaging-api/src/main/java/net/roboconf/messaging/api/internal/client/test/TestClientFactory.java
+++ b/core/roboconf-messaging-api/src/main/java/net/roboconf/messaging/api/internal/client/test/TestClientFactory.java
@@ -28,11 +28,9 @@
import java.util.Map;
import net.roboconf.messaging.api.MessagingConstants;
-import net.roboconf.messaging.api.client.IAgentClient;
-import net.roboconf.messaging.api.client.IDmClient;
+import net.roboconf.messaging.api.extensions.IMessagingClient;
import net.roboconf.messaging.api.factory.IMessagingClientFactory;
-import net.roboconf.messaging.api.reconfigurables.ReconfigurableClientAgent;
-import net.roboconf.messaging.api.reconfigurables.ReconfigurableClientDm;
+import net.roboconf.messaging.api.reconfigurables.ReconfigurableClient;
/**
* Messaging client factory for tests.
@@ -40,26 +38,19 @@
*/
public class TestClientFactory implements IMessagingClientFactory {
- private final String type = MessagingConstants.TEST_FACTORY_TYPE;
-
@Override
public String getType() {
- return this.type;
- }
-
- @Override
- public IDmClient createDmClient( final ReconfigurableClientDm parent ) {
- return new TestClientDm();
+ return MessagingConstants.FACTORY_TEST;
}
@Override
- public IAgentClient createAgentClient( final ReconfigurableClientAgent parent ) {
- return new TestClientAgent();
+ public IMessagingClient createClient( final ReconfigurableClient> parent ) {
+ return new TestClient();
}
@Override
public boolean setConfiguration( final Map configuration ) {
- // Nothing to reconfigure.
- return MessagingConstants.TEST_FACTORY_TYPE.equals(configuration.get(IMessagingClientFactory.MESSAGING_TYPE_PROPERTY));
+ String messagingType = configuration.get( MessagingConstants.MESSAGING_TYPE_PROPERTY );
+ return MessagingConstants.FACTORY_TEST.equals( messagingType );
}
}
diff --git a/core/roboconf-messaging-api/src/main/java/net/roboconf/messaging/api/messages/Message.java b/core/roboconf-messaging-api/src/main/java/net/roboconf/messaging/api/messages/Message.java
index 37d206f6..eccdbae0 100644
--- a/core/roboconf-messaging-api/src/main/java/net/roboconf/messaging/api/messages/Message.java
+++ b/core/roboconf-messaging-api/src/main/java/net/roboconf/messaging/api/messages/Message.java
@@ -32,4 +32,10 @@
*/
public abstract class Message implements Serializable {
private static final long serialVersionUID = -4397827141046520759L;
+
+
+ @Override
+ public String toString() {
+ return getClass().getSimpleName();
+ }
}
diff --git a/core/roboconf-messaging-api/src/main/java/net/roboconf/messaging/api/reconfigurables/ReconfigurableClient.java b/core/roboconf-messaging-api/src/main/java/net/roboconf/messaging/api/reconfigurables/ReconfigurableClient.java
index 2df02347..7ab2d354 100644
--- a/core/roboconf-messaging-api/src/main/java/net/roboconf/messaging/api/reconfigurables/ReconfigurableClient.java
+++ b/core/roboconf-messaging-api/src/main/java/net/roboconf/messaging/api/reconfigurables/ReconfigurableClient.java
@@ -31,12 +31,15 @@
import java.util.logging.Logger;
import net.roboconf.core.utils.Utils;
+import net.roboconf.messaging.api.AbstractMessageProcessor;
import net.roboconf.messaging.api.MessagingConstants;
-import net.roboconf.messaging.api.client.IClient;
+import net.roboconf.messaging.api.business.IClient;
+import net.roboconf.messaging.api.extensions.IMessagingClient;
+import net.roboconf.messaging.api.extensions.MessagingContext.RecipientKind;
import net.roboconf.messaging.api.factory.IMessagingClientFactory;
import net.roboconf.messaging.api.factory.MessagingClientFactoryListener;
import net.roboconf.messaging.api.factory.MessagingClientFactoryRegistry;
-import net.roboconf.messaging.api.processors.AbstractMessageProcessor;
+import net.roboconf.messaging.api.internal.client.dismiss.DismissClient;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
@@ -45,22 +48,31 @@
/**
* A class that can switch dynamically between messaging types.
- * @param a sub-class of {@link IClient}
+ * @param a sub-class of {@link IMessagingClient}
* @author Vincent Zurczak - Linagora
*/
public abstract class ReconfigurableClient implements IClient, MessagingClientFactoryListener {
- private final Logger logger = Logger.getLogger( getClass().getName());
+ protected final Logger logger = Logger.getLogger( getClass().getName());
+ private final DismissClient dismissClient;
+
private AbstractMessageProcessor messageProcessor;
private String messagingType;
- private T messagingClient;
+ private IMessagingClient messagingClient;
private MessagingClientFactoryRegistry registry;
+
+ /**
+ * Constructor.
+ */
protected ReconfigurableClient() {
+ this.dismissClient = new DismissClient();
+
// Try to find the MessagingClientFactoryRegistry service.
- setRegistry(lookupMessagingClientFactoryRegistryService());
+ setRegistry( lookupMessagingClientFactoryRegistryService());
}
+
/**
* @return the {@code MessagingClientFactoryRegistry} associated to this client.
*/
@@ -68,11 +80,13 @@ public synchronized MessagingClientFactoryRegistry getRegistry() {
return this.registry;
}
+
/**
* Sets the {@code MessagingClientFactoryRegistry} associated for this client.
* @param registry the {@code MessagingClientFactoryRegistry} for this client.
*/
public synchronized void setRegistry(MessagingClientFactoryRegistry registry) {
+
if (this.registry != null)
this.registry.removeListener(this);
@@ -81,6 +95,7 @@ public synchronized void setRegistry(MessagingClientFactoryRegistry registry) {
registry.addListener(this);
}
+
/**
* Try to locate the {@code MessagingClientFactoryRegistry} service in an OSGi execution context.
*
@@ -121,11 +136,13 @@ public static MessagingClientFactoryRegistry lookupMessagingClientFactoryRegistr
return result;
}
+
@Override
public synchronized String getMessagingType() {
return this.messagingType;
}
+
/**
* Changes the internal messaging client.
* @param factoryName the factory name (see {@link MessagingConstants})
@@ -133,9 +150,9 @@ public synchronized String getMessagingType() {
public void switchMessagingType( String factoryName ) {
// Create a new client
- T newMessagingClient = null;
+ IMessagingClient newMessagingClient = null;
try {
- newMessagingClient = createMessagingClient(factoryName);
+ newMessagingClient = createMessagingClient( factoryName );
if( newMessagingClient != null ) {
newMessagingClient.setMessageQueue( this.messageProcessor.getMessageQueue());
openConnection(newMessagingClient);
@@ -148,7 +165,7 @@ public void switchMessagingType( String factoryName ) {
// Replace the current client
// (the new client may be null, it is not a problem - see #getMessagingClient())
- T oldClient;
+ IMessagingClient oldClient;
synchronized( this ) {
oldClient = this.messagingClient;
this.messagingClient = newMessagingClient;
@@ -158,17 +175,20 @@ public void switchMessagingType( String factoryName ) {
closeConnection(oldClient, "The previous client could not be terminated correctly.");
}
+
@Override
public void addMessagingClientFactory( final IMessagingClientFactory factory ) {
+
synchronized( this ) {
- if (this.messagingClient == null && factory.getType().equals(this.messagingType)) {
+ if( this.messagingClient == null
+ && factory.getType().equals(this.messagingType)) {
// This is the messaging factory we were expecting...
// We can try to switch to this incoming factory right now!
// Create a new client
- T newMessagingClient = null;
+ IMessagingClient newMessagingClient = null;
try {
- newMessagingClient = createMessagingClient(factory.getType());
+ newMessagingClient = createMessagingClient( factory.getType());
if( newMessagingClient != null ) {
newMessagingClient.setMessageQueue( this.messageProcessor.getMessageQueue());
openConnection(newMessagingClient);
@@ -186,12 +206,13 @@ public void addMessagingClientFactory( final IMessagingClientFactory factory ) {
}
}
+
@Override
public void removeMessagingClientFactory( final IMessagingClientFactory factory ) {
- T oldClient = null;
+ IMessagingClient oldClient = null;
synchronized( this ) {
- if (this.messagingClient != null
+ if( this.messagingClient != null
&& this.messagingClient.getMessagingType().equals(this.messagingType)) {
// This is the messaging factory we were using...
@@ -204,6 +225,7 @@ public void removeMessagingClientFactory( final IMessagingClientFactory factory
closeConnection(oldClient, "The previous client could not be terminated correctly.");
}
+
@Override
public Map getConfiguration() {
@@ -220,14 +242,24 @@ public Map getConfiguration() {
/**
- * Creates a new messaging client and opens a connection with the messaging server.
+ * Creates a new messaging client.
* @param factoryName the factory name (see {@link MessagingConstants})
* @return a new messaging client, or {@code null} if {@code factoryName} is {@code null} or cannot be found in the
* available messaging factories.
* @throws IOException if something went wrong
*/
- protected abstract T createMessagingClient( String factoryName )
- throws IOException;
+ protected IMessagingClient createMessagingClient( String factoryName ) throws IOException {
+
+ IMessagingClient client = null;
+ MessagingClientFactoryRegistry registry = getRegistry();
+ if( registry != null ) {
+ IMessagingClientFactory factory = registry.getMessagingClientFactory(factoryName);
+ if( factory != null )
+ client = factory.createClient( this );
+ }
+
+ return client;
+ }
/**
@@ -242,20 +274,20 @@ protected abstract T createMessagingClient( String factoryName )
* @param newMessagingClient the messaging client to configure
* @throws IOException if something went wrong
*/
- protected abstract void openConnection( T newMessagingClient ) throws IOException;
+ protected abstract void openConnection( IMessagingClient newMessagingClient ) throws IOException;
/**
- * @return a dismiss client for the case where the internal client is null
+ * Configures the message processor.
+ * @param messageProcessor the message processor
*/
- protected abstract T getDismissedClient();
+ protected abstract void configureMessageProcessor( AbstractMessageProcessor messageProcessor );
/**
- * Configures the message processor.
- * @param messageProcessor the message processor
+ * @return the kind of this client's owner (DM or AGENT).
*/
- protected abstract void configureMessageProcessor( AbstractMessageProcessor messageProcessor );
+ public abstract RecipientKind getOwnerKind();
/**
@@ -291,24 +323,33 @@ public AbstractMessageProcessor getMessageProcessor() {
* @return true if the internal client exists and is connected, false otherwise
*/
public synchronized boolean hasValidClient() {
- return this.messagingClient != null
- && this.messagingClient.isConnected();
+
+ // The dismissed client always return false for this statement.
+ return getMessagingClient().isConnected();
}
/**
* @return a messaging client (never null)
*/
- protected synchronized T getMessagingClient() {
- return this.messagingClient != null ? this.messagingClient : getDismissedClient();
+ protected IMessagingClient getMessagingClient() {
+
+ IMessagingClient result;
+ synchronized( this ) {
+ result = this.messagingClient != null ? this.messagingClient : this.dismissClient;
+ }
+
+ //this.logger.finest( "The messaging client is of type " + result.getClass().getSimpleName());
+ return result;
}
/**
* Resets the internal client (sets it to null).
*/
- protected synchronized T resetInternalClient() {
- T oldClient = this.messagingClient;
+ protected synchronized IMessagingClient resetInternalClient() {
+
+ IMessagingClient oldClient = this.messagingClient;
this.messagingClient = null;
return oldClient;
}
@@ -319,7 +360,7 @@ protected synchronized T resetInternalClient() {
* @param client the client (may be null)
* @param errorMessage the error message to log in case of problem
*/
- static void closeConnection( IClient client, String errorMessage ) {
+ static void closeConnection( IMessagingClient client, String errorMessage ) {
if( client != null ) {
try {
diff --git a/core/roboconf-messaging-api/src/main/java/net/roboconf/messaging/api/reconfigurables/ReconfigurableClientAgent.java b/core/roboconf-messaging-api/src/main/java/net/roboconf/messaging/api/reconfigurables/ReconfigurableClientAgent.java
index 4206008f..63a4bd14 100644
--- a/core/roboconf-messaging-api/src/main/java/net/roboconf/messaging/api/reconfigurables/ReconfigurableClientAgent.java
+++ b/core/roboconf-messaging-api/src/main/java/net/roboconf/messaging/api/reconfigurables/ReconfigurableClientAgent.java
@@ -26,71 +26,67 @@
package net.roboconf.messaging.api.reconfigurables;
import java.io.IOException;
+import java.util.HashMap;
import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.LinkedBlockingQueue;
import net.roboconf.core.model.beans.Instance;
-import net.roboconf.messaging.api.client.IAgentClient;
-import net.roboconf.messaging.api.client.ListenerCommand;
-import net.roboconf.messaging.api.factory.IMessagingClientFactory;
-import net.roboconf.messaging.api.factory.MessagingClientFactoryRegistry;
-import net.roboconf.messaging.api.internal.client.dismiss.DismissClientAgent;
+import net.roboconf.core.model.helpers.InstanceHelpers;
+import net.roboconf.core.model.helpers.VariableHelpers;
+import net.roboconf.core.utils.Utils;
+import net.roboconf.messaging.api.AbstractMessageProcessor;
+import net.roboconf.messaging.api.business.IAgentClient;
+import net.roboconf.messaging.api.business.ListenerCommand;
+import net.roboconf.messaging.api.extensions.IMessagingClient;
+import net.roboconf.messaging.api.extensions.MessagingContext;
+import net.roboconf.messaging.api.extensions.MessagingContext.RecipientKind;
+import net.roboconf.messaging.api.extensions.MessagingContext.ThoseThat;
import net.roboconf.messaging.api.messages.Message;
+import net.roboconf.messaging.api.messages.from_agent_to_agent.MsgCmdAddImport;
+import net.roboconf.messaging.api.messages.from_agent_to_agent.MsgCmdRemoveImport;
+import net.roboconf.messaging.api.messages.from_agent_to_agent.MsgCmdRequestImport;
import net.roboconf.messaging.api.messages.from_agent_to_dm.MsgNotifHeartbeat;
-import net.roboconf.messaging.api.processors.AbstractMessageProcessor;
+import net.roboconf.messaging.api.utils.MessagingUtils;
/**
* @author Vincent Zurczak - Linagora
*/
public class ReconfigurableClientAgent extends ReconfigurableClient implements IAgentClient {
- private Map externalExports;
+ private final ConcurrentHashMap externalExports = new ConcurrentHashMap<> ();
private String applicationName, scopedInstancePath, ipAddress;
private boolean needsModel = false;
// Methods inherited from ReconfigurableClient
- @Override
- protected IAgentClient createMessagingClient( String factoryName )
- throws IOException {
- IAgentClient client = null;
- MessagingClientFactoryRegistry registry = getRegistry();
- if (registry != null) {
- IMessagingClientFactory factory = registry.getMessagingClientFactory(factoryName);
- if (factory != null) {
- client = factory.createAgentClient(this);
- }
- }
- return client;
- }
-
@Override
- protected void openConnection( IAgentClient newMessagingClient ) throws IOException {
+ protected void openConnection( IMessagingClient newMessagingClient ) throws IOException {
- newMessagingClient.setApplicationName( this.applicationName );
- newMessagingClient.setScopedInstancePath( this.scopedInstancePath );
- newMessagingClient.setExternalMapping( this.externalExports );
+ newMessagingClient.setOwnerProperties( getOwnerKind(), this.applicationName, this.scopedInstancePath );
newMessagingClient.openConnection();
-
- newMessagingClient.listenToTheDm( ListenerCommand.START );
+ listenToTheDm( newMessagingClient, ListenerCommand.START );
MsgNotifHeartbeat msg = new MsgNotifHeartbeat( this.applicationName, this.scopedInstancePath, this.ipAddress );
msg.setModelRequired( this.needsModel );
- newMessagingClient.sendMessageToTheDm( msg );
+
+ MessagingContext ctx = new MessagingContext( RecipientKind.DM, this.applicationName );
+ newMessagingClient.publish( ctx, msg );
}
@Override
- protected IAgentClient getDismissedClient() {
- return new DismissClientAgent();
+ protected void configureMessageProcessor( AbstractMessageProcessor messageProcessor ) {
+ messageProcessor.setMessagingClient( this );
}
@Override
- protected void configureMessageProcessor( AbstractMessageProcessor messageProcessor ) {
- messageProcessor.setMessagingClient( this );
+ public RecipientKind getOwnerKind() {
+ return RecipientKind.AGENTS;
}
@@ -111,64 +107,213 @@ public boolean isConnected() {
@Override
public void openConnection() throws IOException {
- getMessagingClient().openConnection();
+ openConnection( getMessagingClient());
}
@Override
public void closeConnection() throws IOException {
- final IAgentClient toClose = resetInternalClient();
- if (toClose != null) {
+
+ final IMessagingClient toClose = resetInternalClient();
+ if (toClose != null)
toClose.closeConnection();
- }
}
@Override
public void publishExports( Instance instance ) throws IOException {
- getMessagingClient().publishExports( instance );
+
+ // For all the exported variables...
+ // ... find the component or facet name...
+ Set names = VariableHelpers.findPrefixesForExportedVariables( instance );
+ if( names.isEmpty())
+ this.logger.fine( "Agent '" + getAgentId() + "' is publishing its exports." );
+
+ else for( String facetOrComponentName : names ) {
+ publishExports( instance, facetOrComponentName );
+ }
}
@Override
public void publishExports( Instance instance, String facetOrComponentName ) throws IOException {
- getMessagingClient().publishExports( instance, facetOrComponentName );
+ this.logger.fine( "Agent '" + getAgentId() + "' is publishing its exports prefixed by " + facetOrComponentName + "." );
+
+ // Find the variables to export.
+ Map toPublishInternally = new HashMap<> ();
+ Map toPublishExternally = new HashMap<> ();
+
+ Map exports = InstanceHelpers.findAllExportedVariables( instance );
+ for( Map.Entry entry : exports.entrySet()) {
+
+ // Publishing an export may be about a facet or component name or about an external prefix.
+ // If an "internal prefix" is required, export both the internal and associated external, if any.
+ String alias = this.externalExports.get( entry.getKey());
+ if( entry.getKey().startsWith( facetOrComponentName + "." )) {
+ toPublishInternally.put( entry.getKey(), entry.getValue());
+ if( alias != null )
+ toPublishExternally.put( alias, entry.getValue());
+ }
+
+ // If an external prefix is required, only export the external variables
+ else if( alias != null && alias.startsWith( facetOrComponentName + "." )) {
+ toPublishExternally.put( alias, entry.getValue());
+ }
+ }
+
+ // Publish the internal exports
+ if( ! toPublishInternally.isEmpty()) {
+ MsgCmdAddImport message = new MsgCmdAddImport(
+ this.applicationName,
+ facetOrComponentName,
+ InstanceHelpers.computeInstancePath( instance ),
+ toPublishInternally );
+
+ MessagingContext ctx = new MessagingContext(
+ RecipientKind.AGENTS,
+ facetOrComponentName,
+ ThoseThat.IMPORT,
+ this.applicationName );
+
+ getMessagingClient().publish( ctx, message );
+ }
+
+ // Publish the external ones, if any
+ if( ! toPublishExternally.isEmpty()) {
+ String varName = toPublishExternally.keySet().iterator().next();
+ String appTplName = VariableHelpers.parseVariableName( varName ).getKey();
+
+ MsgCmdAddImport message = new MsgCmdAddImport(
+ this.applicationName,
+ appTplName,
+ InstanceHelpers.computeInstancePath( instance ),
+ toPublishExternally );
+
+ MessagingContext ctx = new MessagingContext(
+ RecipientKind.INTER_APP,
+ appTplName,
+ ThoseThat.IMPORT,
+ this.applicationName );
+
+ getMessagingClient().publish( ctx, message );
+ }
}
@Override
public void unpublishExports( Instance instance ) throws IOException {
- getMessagingClient().unpublishExports( instance );
+ this.logger.fine( "Agent '" + getAgentId() + "' is un-publishing its exports." );
+
+ // For all the exported variables...
+ // ... find the component or facet name...
+ for( MessagingContext ctx : MessagingContext.forExportedVariables(
+ this.applicationName, instance, this.externalExports, ThoseThat.IMPORT )) {
+
+ // Log here, for debug
+ this.logger.fine( "Agent '" + getAgentId() + "' is un-publishing its exports (" + ctx + ")." );
+
+ // Un-publish them
+ MsgCmdRemoveImport message = new MsgCmdRemoveImport(
+ this.applicationName,
+ ctx.getComponentOrFacetName(),
+ InstanceHelpers.computeInstancePath( instance ));
+
+ getMessagingClient().publish( ctx, message );
+ }
}
@Override
public void listenToRequestsFromOtherAgents( ListenerCommand command, Instance instance ) throws IOException {
- getMessagingClient().listenToRequestsFromOtherAgents( command, instance );
+
+ // Find the right contexts to subscribe.
+ // This depends on the exported variables.
+ for( MessagingContext ctx : MessagingContext.forExportedVariables(
+ this.applicationName, instance, this.externalExports, ThoseThat.EXPORT )) {
+
+ if( command == ListenerCommand.START ) {
+ this.logger.fine( "Agent '" + getAgentId() + "' starts listening requests from other agents (" + ctx + ")." );
+ getMessagingClient().subscribe( ctx );
+
+ } else {
+ this.logger.fine( "Agent '" + getAgentId() + "' stops listening requests from other agents (" + ctx + ")." );
+ getMessagingClient().unsubscribe( ctx );
+ }
+ }
}
@Override
public void requestExportsFromOtherAgents( Instance instance ) throws IOException {
- getMessagingClient().requestExportsFromOtherAgents( instance );
+ this.logger.fine( "Agent '" + getAgentId() + "' is requesting exports from other agents." );
+
+ // For all the imported variables...
+ // ... find the component or facet name...
+ for( MessagingContext ctx : MessagingContext.forImportedVariables(
+ this.applicationName, instance, ThoseThat.EXPORT )) {
+
+ // Log here, for debug
+ this.logger.fine( "Agent '" + getAgentId() + "' is requesting exports from other agents (" + ctx + ")." );
+
+ // ... and ask to publish them.
+ // Grouping variable requests by prefix reduces the number of messages.
+ MsgCmdRequestImport message = new MsgCmdRequestImport( this.applicationName, ctx.getComponentOrFacetName());
+ getMessagingClient().publish( ctx, message );
+ }
}
@Override
public void listenToExportsFromOtherAgents( ListenerCommand command, Instance instance ) throws IOException {
- getMessagingClient().listenToExportsFromOtherAgents( command, instance );
+
+ // With RabbitMQ, and for agents, listening to others means
+ // create a binding between the "agents" exchange and the agent's queue.
+ for( MessagingContext ctx : MessagingContext.forImportedVariables(
+ this.applicationName, instance, ThoseThat.IMPORT )) {
+
+ // On which routing key do export go? Those.that.import...
+ if( command == ListenerCommand.START ) {
+ this.logger.fine( "Agent '" + getAgentId() + "' starts listening exports from other agents (" + ctx + ")." );
+ getMessagingClient().subscribe( ctx );
+
+ } else {
+ this.logger.fine( "Agent '" + getAgentId() + "' stops listening exports from other agents (" + ctx + ")." );
+ getMessagingClient().unsubscribe( ctx );
+ }
+ }
}
@Override
public void sendMessageToTheDm( Message message ) throws IOException {
- getMessagingClient().sendMessageToTheDm( message );
+
+ // The context match the one used by the DM to listen to messages sent by agents.
+ this.logger.fine( "Agent '" + getAgentId() + "' is sending a " + message.getClass().getSimpleName() + " message to the DM." );
+ MessagingContext ctx = new MessagingContext( RecipientKind.DM, this.applicationName );
+ getMessagingClient().publish( ctx, message );
}
@Override
public void listenToTheDm( ListenerCommand command ) throws IOException {
- getMessagingClient().listenToTheDm( command );
+ listenToTheDm( getMessagingClient(), command );
+ }
+
+
+ private void listenToTheDm( IMessagingClient client, ListenerCommand command ) throws IOException {
+
+ // The context match the one used by the DM to send a message to an agent.
+ // The agent client MUST have a scoped instance path!
+ String topicName = MessagingUtils.buildTopicNameForAgent( this.scopedInstancePath );
+ MessagingContext ctx = new MessagingContext( RecipientKind.AGENTS, topicName, this.applicationName );
+ if( command == ListenerCommand.START ) {
+ this.logger.fine( "Agent '" + getAgentId() + "' starts listening to the DM." );
+ client.subscribe( ctx );
+
+ } else {
+ this.logger.fine( "Agent '" + getAgentId() + "' stops listening to the DM." );
+ client.unsubscribe( ctx );
+ }
}
@@ -178,22 +323,27 @@ public void listenToTheDm( ListenerCommand command ) throws IOException {
@Override
public void setApplicationName( String applicationName ) {
this.applicationName = applicationName;
+
+ // Propagate the information to the internal client.
+ getMessagingClient().setOwnerProperties( getOwnerKind(), applicationName, this.scopedInstancePath );
}
@Override
public void setScopedInstancePath( String scopedInstancePath ) {
this.scopedInstancePath = scopedInstancePath;
+
+ // Propagate the information to the internal client.
+ getMessagingClient().setOwnerProperties( getOwnerKind(), this.applicationName, scopedInstancePath );
}
@Override
public void setExternalMapping( Map externalExports ) {
- this.externalExports = externalExports;
- // Unlike other setters, this one is invoked by the agent AFTER
- // the messaging was initialized (and after the first message was received).
- getMessagingClient().setExternalMapping( externalExports );
+ this.externalExports.clear();
+ if( externalExports != null )
+ this.externalExports.putAll( externalExports );
}
@@ -205,4 +355,9 @@ public void setIpAddress( String ipAddress ) {
public void setNeedsModel( boolean needsModel ) {
this.needsModel = needsModel;
}
+
+
+ private String getAgentId() {
+ return Utils.isEmptyOrWhitespaces( this.scopedInstancePath ) ? "?" : this.scopedInstancePath;
+ }
}
diff --git a/core/roboconf-messaging-api/src/main/java/net/roboconf/messaging/api/reconfigurables/ReconfigurableClientDm.java b/core/roboconf-messaging-api/src/main/java/net/roboconf/messaging/api/reconfigurables/ReconfigurableClientDm.java
index 07ffa210..7f892184 100644
--- a/core/roboconf-messaging-api/src/main/java/net/roboconf/messaging/api/reconfigurables/ReconfigurableClientDm.java
+++ b/core/roboconf-messaging-api/src/main/java/net/roboconf/messaging/api/reconfigurables/ReconfigurableClientDm.java
@@ -26,17 +26,23 @@
package net.roboconf.messaging.api.reconfigurables;
import java.io.IOException;
+import java.util.Collections;
+import java.util.List;
import java.util.concurrent.LinkedBlockingQueue;
import net.roboconf.core.model.beans.Application;
import net.roboconf.core.model.beans.Instance;
-import net.roboconf.messaging.api.client.IDmClient;
-import net.roboconf.messaging.api.client.ListenerCommand;
-import net.roboconf.messaging.api.factory.IMessagingClientFactory;
-import net.roboconf.messaging.api.factory.MessagingClientFactoryRegistry;
-import net.roboconf.messaging.api.internal.client.dismiss.DismissClientDm;
+import net.roboconf.core.model.helpers.InstanceHelpers;
+import net.roboconf.messaging.api.AbstractMessageProcessor;
+import net.roboconf.messaging.api.business.IDmClient;
+import net.roboconf.messaging.api.business.ListenerCommand;
+import net.roboconf.messaging.api.extensions.IMessagingClient;
+import net.roboconf.messaging.api.extensions.MessagingContext;
+import net.roboconf.messaging.api.extensions.MessagingContext.RecipientKind;
+import net.roboconf.messaging.api.extensions.MessagingContext.ThoseThat;
import net.roboconf.messaging.api.messages.Message;
-import net.roboconf.messaging.api.processors.AbstractMessageProcessor;
+import net.roboconf.messaging.api.messages.from_agent_to_agent.MsgCmdRemoveImport;
+import net.roboconf.messaging.api.utils.MessagingUtils;
/**
* @author Vincent Zurczak - Linagora
@@ -47,36 +53,20 @@ public class ReconfigurableClientDm extends ReconfigurableClient impl
// Methods inherited from ReconfigurableClient
@Override
- protected IDmClient createMessagingClient( String factoryName )
- throws IOException {
-
- IDmClient client = null;
- MessagingClientFactoryRegistry registry = getRegistry();
- if (registry != null) {
- IMessagingClientFactory factory = registry.getMessagingClientFactory(factoryName);
- if (factory != null) {
- client = factory.createDmClient(this);
- }
- }
- return client;
- }
-
-
- @Override
- protected void openConnection( IDmClient newMessagingClient ) throws IOException {
+ protected void openConnection( IMessagingClient newMessagingClient ) throws IOException {
newMessagingClient.openConnection();
}
@Override
- protected IDmClient getDismissedClient() {
- return new DismissClientDm();
+ protected void configureMessageProcessor( AbstractMessageProcessor messageProcessor ) {
+ messageProcessor.setMessagingClient( this );
}
@Override
- protected void configureMessageProcessor( AbstractMessageProcessor messageProcessor ) {
- messageProcessor.setMessagingClient( this );
+ public RecipientKind getOwnerKind() {
+ return RecipientKind.DM;
}
@@ -101,47 +91,91 @@ public void openConnection() throws IOException {
}
+ @Override
+ public void deleteMessagingServerArtifacts( Application application ) throws IOException {
+ getMessagingClient().deleteMessagingServerArtifacts( application );
+ }
+
+
@Override
public void closeConnection() throws IOException {
- final IDmClient toClose = resetInternalClient();
- if (toClose != null) {
+
+ final IMessagingClient toClose = resetInternalClient();
+ if (toClose != null)
toClose.closeConnection();
- }
}
@Override
public void sendMessageToAgent( Application application, Instance instance, Message message ) throws IOException {
- getMessagingClient().sendMessageToAgent( application, instance, message );
+
+ // The context match the one used by agents to listen to messages sent by the DM.
+ String topicName = MessagingUtils.buildTopicNameForAgent( instance );
+ MessagingContext ctx = new MessagingContext( RecipientKind.AGENTS, topicName, application.getName());
+ getMessagingClient().publish( ctx, message );
}
@Override
public void listenToAgentMessages( Application application, ListenerCommand command ) throws IOException {
- getMessagingClient().listenToAgentMessages( application, command );
+ listenToAgentMessages( getMessagingClient(), application, command );
}
@Override
public void sendMessageToTheDm( Message msg ) throws IOException {
- getMessagingClient().sendMessageToTheDm( msg );
+
+ MessagingContext ctx = new MessagingContext( RecipientKind.DM, null );
+ getMessagingClient().publish( ctx, msg );
}
@Override
public void listenToTheDm( ListenerCommand command ) throws IOException {
- getMessagingClient().listenToTheDm( command );
+
+ MessagingContext ctx = new MessagingContext( RecipientKind.DM, null );
+ if( command == ListenerCommand.STOP )
+ getMessagingClient().unsubscribe( ctx );
+ else
+ getMessagingClient().subscribe( ctx );
}
@Override
- public void deleteMessagingServerArtifacts( Application application ) throws IOException {
- getMessagingClient().deleteMessagingServerArtifacts( application );
+ public void propagateAgentTermination( Application application, Instance rootInstance ) throws IOException {
+
+ // Start with the deepest instances
+ List instances = InstanceHelpers.buildHierarchicalList( rootInstance );
+ Collections.reverse( instances );
+
+ // Roughly, we unpublish all the variables for all the instances that were on the agent's machine.
+ // This code is VERY similar to ...ClientAgent#unpublishExports
+ // The messages will go through JUST like if they were coming from other agents.
+ this.logger.fine( "The DM is un-publishing exports related to agent of " + rootInstance + " (termination propagation)." );
+ for( Instance instance : instances ) {
+ for( MessagingContext ctx : MessagingContext.forExportedVariables(
+ application.getName(), instance, application.getExternalExports(), ThoseThat.IMPORT )) {
+
+ MsgCmdRemoveImport message = new MsgCmdRemoveImport(
+ application.getName(),
+ ctx.getComponentOrFacetName(),
+ InstanceHelpers.computeInstancePath( instance ));
+
+ // FIXME: external exports are not handled here!!!!
+ getMessagingClient().publish( ctx, message );
+ }
+ }
}
- @Override
- public void propagateAgentTermination( Application application, Instance rootInstance ) throws IOException {
- getMessagingClient().propagateAgentTermination( application, rootInstance );
+ protected void listenToAgentMessages( IMessagingClient messagingClient, Application application, ListenerCommand command )
+ throws IOException {
+
+ // The context match the one used by agents to send messages to the DM.
+ MessagingContext ctx = new MessagingContext( RecipientKind.DM, application.getName());
+ if( command == ListenerCommand.STOP )
+ messagingClient.unsubscribe( ctx );
+ else
+ messagingClient.subscribe( ctx );
}
}
diff --git a/core/roboconf-messaging-api/src/main/java/net/roboconf/messaging/api/utils/MessagingUtils.java b/core/roboconf-messaging-api/src/main/java/net/roboconf/messaging/api/utils/MessagingUtils.java
new file mode 100644
index 00000000..6e37c644
--- /dev/null
+++ b/core/roboconf-messaging-api/src/main/java/net/roboconf/messaging/api/utils/MessagingUtils.java
@@ -0,0 +1,81 @@
+/**
+ * Copyright 2015 Linagora, Université Joseph Fourier, Floralis
+ *
+ * The present code is developed in the scope of the joint LINAGORA -
+ * Université Joseph Fourier - Floralis research program and is designated
+ * as a "Result" pursuant to the terms and conditions of the LINAGORA
+ * - Université Joseph Fourier - Floralis research program. Each copyright
+ * holder of Results enumerated here above fully & independently holds complete
+ * ownership of the complete Intellectual Property rights applicable to the whole
+ * of said Results, and may freely exploit it in any manner which does not infringe
+ * the moral rights of the other copyright holders.
+ *
+ * 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.
+ */
+
+package net.roboconf.messaging.api.utils;
+
+import net.roboconf.core.model.beans.Instance;
+import net.roboconf.core.model.helpers.InstanceHelpers;
+import net.roboconf.core.utils.Utils;
+
+/**
+ * @author Vincent Zurczak - Linagora
+ */
+public final class MessagingUtils {
+
+ /**
+ * Constructor.
+ */
+ private MessagingUtils() {
+ // nothing
+ }
+
+
+ /**
+ * Builds the default topic name for an agent.
+ * @param instance an instance managed by the agent
+ * @return a non-null string
+ */
+ public static String buildTopicNameForAgent( Instance instance ) {
+ Instance scopedInstance = InstanceHelpers.findScopedInstance( instance );
+ return buildTopicNameForAgent( InstanceHelpers.computeInstancePath( scopedInstance ));
+ }
+
+
+ /**
+ * Builds the default topic name for an agent.
+ * @param scopedInstancePath the path of the (scoped) instance associated with the agent
+ * @return a non-null string
+ */
+ public static String buildTopicNameForAgent( String scopedInstancePath ) {
+ return "machine." + escapeInstancePath( scopedInstancePath );
+ }
+
+
+ /**
+ * Removes unnecessary slashes and transforms the others into dots.
+ * @param instancePath an instance path
+ * @return a non-null string
+ */
+ public static String escapeInstancePath( String instancePath ) {
+
+ String result;
+ if( Utils.isEmptyOrWhitespaces( instancePath ))
+ result = "";
+ else
+ result = instancePath.replaceFirst( "^/*", "" ).replaceFirst( "/*$", "" ).replaceAll( "/+", "." );
+
+ return result;
+ }
+}
diff --git a/core/roboconf-messaging-api/src/test/java/net/roboconf/messaging/api/extensions/AbstractRoutingClientTest.java b/core/roboconf-messaging-api/src/test/java/net/roboconf/messaging/api/extensions/AbstractRoutingClientTest.java
new file mode 100644
index 00000000..3bb34bbd
--- /dev/null
+++ b/core/roboconf-messaging-api/src/test/java/net/roboconf/messaging/api/extensions/AbstractRoutingClientTest.java
@@ -0,0 +1,98 @@
+/**
+ * Copyright 2015 Linagora, Université Joseph Fourier, Floralis
+ *
+ * The present code is developed in the scope of the joint LINAGORA -
+ * Université Joseph Fourier - Floralis research program and is designated
+ * as a "Result" pursuant to the terms and conditions of the LINAGORA
+ * - Université Joseph Fourier - Floralis research program. Each copyright
+ * holder of Results enumerated here above fully & independently holds complete
+ * ownership of the complete Intellectual Property rights applicable to the whole
+ * of said Results, and may freely exploit it in any manner which does not infringe
+ * the moral rights of the other copyright holders.
+ *
+ * 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.
+ */
+
+package net.roboconf.messaging.api.extensions;
+
+import java.io.IOException;
+import java.util.Map;
+import java.util.concurrent.LinkedBlockingQueue;
+
+import net.roboconf.messaging.api.extensions.MessagingContext.RecipientKind;
+import net.roboconf.messaging.api.messages.Message;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+/**
+ * @author Vincent Zurczak - Linagora
+ */
+public class AbstractRoutingClientTest {
+
+ @Test
+ public void testCanProceed() {
+
+ // A connection is required.
+ CanProceedTest c1 = new CanProceedTest( true );
+ c1.connected.set( true );
+ Assert.assertTrue( c1.canProceed());
+
+ c1.connected.set( false );
+ Assert.assertFalse( c1.canProceed());
+
+ // We do not care about the connection.
+ CanProceedTest c2 = new CanProceedTest( false );
+ c2.connected.set( true );
+ Assert.assertTrue( c2.canProceed());
+
+ c2.connected.set( false );
+ Assert.assertTrue( c2.canProceed());
+ }
+
+
+ /**
+ * @author Vincent Zurczak - Linagora
+ */
+ private static class CanProceedTest extends AbstractRoutingClient {
+
+ /**
+ * Constructor.
+ * @param connectionIsRequired
+ */
+ public CanProceedTest( boolean connectionIsRequired ) {
+ super( null, RecipientKind.DM );
+ this.connectionIsRequired = connectionIsRequired;
+ }
+
+ @Override
+ public void setMessageQueue( LinkedBlockingQueue messageQueue ) {
+ // nothing
+ }
+
+ @Override
+ protected Map getStaticContextToObject() {
+ return null;
+ }
+
+ @Override
+ protected void process( String obj, Message message ) throws IOException {
+ // nothing
+ }
+
+ @Override
+ public String getMessagingType() {
+ return "whatever";
+ }
+ }
+}
diff --git a/core/roboconf-messaging-api/src/test/java/net/roboconf/messaging/api/extensions/MessagingContextTest.java b/core/roboconf-messaging-api/src/test/java/net/roboconf/messaging/api/extensions/MessagingContextTest.java
new file mode 100644
index 00000000..a1136154
--- /dev/null
+++ b/core/roboconf-messaging-api/src/test/java/net/roboconf/messaging/api/extensions/MessagingContextTest.java
@@ -0,0 +1,227 @@
+/**
+ * Copyright 2015 Linagora, Université Joseph Fourier, Floralis
+ *
+ * The present code is developed in the scope of the joint LINAGORA -
+ * Université Joseph Fourier - Floralis research program and is designated
+ * as a "Result" pursuant to the terms and conditions of the LINAGORA
+ * - Université Joseph Fourier - Floralis research program. Each copyright
+ * holder of Results enumerated here above fully & independently holds complete
+ * ownership of the complete Intellectual Property rights applicable to the whole
+ * of said Results, and may freely exploit it in any manner which does not infringe
+ * the moral rights of the other copyright holders.
+ *
+ * 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.
+ */
+
+package net.roboconf.messaging.api.extensions;
+
+import org.junit.Assert;
+import net.roboconf.messaging.api.extensions.MessagingContext.RecipientKind;
+import net.roboconf.messaging.api.extensions.MessagingContext.ThoseThat;
+
+import org.junit.Test;
+
+/**
+ * @author Vincent Zurczak - Linagora
+ */
+public class MessagingContextTest {
+
+ @Test
+ public void testEquals() {
+
+ MessagingContext ctx = new MessagingContext( RecipientKind.DM, "whatever" );
+ Assert.assertEquals( ctx, new MessagingContext( RecipientKind.DM, "whatever", null, "whatever" ));
+ Assert.assertEquals( ctx, ctx );
+
+ Assert.assertFalse( ctx.equals( new MessagingContext( RecipientKind.DM, null )));
+ Assert.assertFalse( ctx.equals( new MessagingContext( RecipientKind.DM, "whatever2" )));
+ Assert.assertFalse( ctx.equals( new MessagingContext( RecipientKind.AGENTS, null )));
+ Assert.assertFalse( ctx.equals( new MessagingContext( RecipientKind.INTER_APP, null )));
+ Assert.assertFalse( ctx.equals( new Object()));
+
+ ctx = new MessagingContext( RecipientKind.INTER_APP, "facet", ThoseThat.EXPORT, "app" );
+ Assert.assertEquals( ctx, new MessagingContext( RecipientKind.INTER_APP, "facet", ThoseThat.EXPORT, "app2" ));
+ Assert.assertEquals( ctx, new MessagingContext( RecipientKind.INTER_APP, "facet", ThoseThat.EXPORT, "app3" ));
+ Assert.assertEquals( ctx, ctx );
+
+ Assert.assertFalse( ctx.equals( new MessagingContext( RecipientKind.INTER_APP, "facet", ThoseThat.IMPORT, "app" )));
+ Assert.assertFalse( ctx.equals( new MessagingContext( RecipientKind.INTER_APP, "facet2", ThoseThat.EXPORT, "app" )));
+ Assert.assertFalse( ctx.equals( new MessagingContext( RecipientKind.AGENTS, "facet", ThoseThat.EXPORT, "app" )));
+ Assert.assertFalse( ctx.equals( new Object()));
+
+ ctx = new MessagingContext( RecipientKind.AGENTS, "facet", ThoseThat.EXPORT, null );
+ Assert.assertFalse( ctx.equals( new MessagingContext( RecipientKind.AGENTS, "facet", ThoseThat.IMPORT, null )));
+ Assert.assertFalse( ctx.equals( new MessagingContext( RecipientKind.INTER_APP, "facet", ThoseThat.EXPORT, null )));
+ Assert.assertFalse( ctx.equals( new MessagingContext( RecipientKind.AGENTS, "facet2", ThoseThat.EXPORT, null )));
+ Assert.assertFalse( ctx.equals( new MessagingContext( RecipientKind.AGENTS, "facet", ThoseThat.EXPORT, "app" )));
+ Assert.assertEquals( ctx, ctx );
+ }
+
+
+ @Test
+ public void testHashCode() {
+
+ MessagingContext ctx1 = new MessagingContext( RecipientKind.DM, null );
+ Assert.assertEquals( ctx1.hashCode(), ctx1.hashCode());
+ Assert.assertNotSame( ctx1.hashCode(), new MessagingContext( RecipientKind.DM, "whatever" ).hashCode());
+
+ MessagingContext ctx2 = new MessagingContext( RecipientKind.INTER_APP, "facet", ThoseThat.EXPORT, "app" );
+ Assert.assertEquals( ctx2.hashCode(), ctx2.hashCode());
+ Assert.assertNotSame( ctx1.hashCode(), ctx2.hashCode());
+ }
+
+
+ @Test
+ public void testConstructors() {
+
+ // DM
+ MessagingContext ctx = new MessagingContext( RecipientKind.DM, null );
+ Assert.assertEquals( RecipientKind.DM, ctx.getKind());
+ Assert.assertNull( ctx.getApplicationName());
+ Assert.assertNull( ctx.getComponentOrFacetName());
+ Assert.assertNull( ctx.getAgentDirection());
+
+ ctx = new MessagingContext( RecipientKind.DM, "whatever" );
+ Assert.assertEquals( RecipientKind.DM, ctx.getKind());
+ Assert.assertEquals( "whatever", ctx.getApplicationName());
+ Assert.assertNull( ctx.getComponentOrFacetName());
+ Assert.assertNull( ctx.getAgentDirection());
+
+ // Inter-application
+ ctx = new MessagingContext( RecipientKind.INTER_APP, "whatever" );
+ Assert.assertEquals( RecipientKind.INTER_APP, ctx.getKind());
+ Assert.assertNull( ctx.getApplicationName());
+ Assert.assertNull( ctx.getComponentOrFacetName());
+ Assert.assertNull( ctx.getAgentDirection());
+
+ ctx = new MessagingContext( RecipientKind.INTER_APP, null );
+ Assert.assertEquals( RecipientKind.INTER_APP, ctx.getKind());
+ Assert.assertNull( ctx.getApplicationName());
+ Assert.assertNull( ctx.getComponentOrFacetName());
+ Assert.assertNull( ctx.getAgentDirection());
+
+ ctx = new MessagingContext( RecipientKind.INTER_APP, "facet", null, "whatever" );
+ Assert.assertEquals( RecipientKind.INTER_APP, ctx.getKind());
+ Assert.assertNull( ctx.getApplicationName());
+ Assert.assertEquals( "facet", ctx.getComponentOrFacetName());
+ Assert.assertNull( ctx.getAgentDirection());
+
+ ctx = new MessagingContext( RecipientKind.INTER_APP, "facet", ThoseThat.EXPORT, "whatever" );
+ Assert.assertEquals( RecipientKind.INTER_APP, ctx.getKind());
+ Assert.assertNull( ctx.getApplicationName());
+ Assert.assertEquals( "facet", ctx.getComponentOrFacetName());
+ Assert.assertEquals( ThoseThat.EXPORT, ctx.getAgentDirection());
+
+ // Agents
+ ctx = new MessagingContext( RecipientKind.AGENTS, "whatever" );
+ Assert.assertEquals( RecipientKind.AGENTS, ctx.getKind());
+ Assert.assertEquals( "whatever", ctx.getApplicationName());
+ Assert.assertNull( ctx.getComponentOrFacetName());
+ Assert.assertNull( ctx.getAgentDirection());
+
+ ctx = new MessagingContext( RecipientKind.AGENTS, null );
+ Assert.assertEquals( RecipientKind.AGENTS, ctx.getKind());
+ Assert.assertNull( ctx.getApplicationName());
+ Assert.assertNull( ctx.getComponentOrFacetName());
+ Assert.assertNull( ctx.getAgentDirection());
+
+ ctx = new MessagingContext( RecipientKind.AGENTS, "facet", null, "whatever" );
+ Assert.assertEquals( RecipientKind.AGENTS, ctx.getKind());
+ Assert.assertEquals( "whatever", ctx.getApplicationName());
+ Assert.assertEquals( "facet", ctx.getComponentOrFacetName());
+ Assert.assertNull( ctx.getAgentDirection());
+
+ ctx = new MessagingContext( RecipientKind.AGENTS, "facet", ThoseThat.IMPORT, "whatever" );
+ Assert.assertEquals( RecipientKind.AGENTS, ctx.getKind());
+ Assert.assertEquals( "whatever", ctx.getApplicationName());
+ Assert.assertEquals( "facet", ctx.getComponentOrFacetName());
+ Assert.assertEquals( ThoseThat.IMPORT, ctx.getAgentDirection());
+ Assert.assertEquals( "those.that.import.facet", ctx.getTopicName());
+ }
+
+
+ @Test
+ public void testGetTopicName() {
+
+ // DM
+ MessagingContext ctx = new MessagingContext( RecipientKind.DM, null );
+ Assert.assertEquals( "", ctx.getTopicName());
+
+ ctx = new MessagingContext( RecipientKind.DM, "whatever" );
+ Assert.assertEquals( "whatever", ctx.getTopicName());
+
+ // Inter-application
+ ctx = new MessagingContext( RecipientKind.INTER_APP, "whatever" );
+ Assert.assertEquals( "", ctx.getTopicName());
+
+ ctx = new MessagingContext( RecipientKind.INTER_APP, null );
+ Assert.assertEquals( "", ctx.getTopicName());
+
+ ctx = new MessagingContext( RecipientKind.INTER_APP, "facet", null, "whatever" );
+ Assert.assertEquals( "facet", ctx.getTopicName());
+
+ ctx = new MessagingContext( RecipientKind.INTER_APP, "facet", ThoseThat.EXPORT, "whatever" );
+ Assert.assertEquals( "those.that.export.facet", ctx.getTopicName());
+
+ // Agents
+ ctx = new MessagingContext( RecipientKind.AGENTS, "whatever" );
+ Assert.assertEquals( "", ctx.getTopicName());
+
+ ctx = new MessagingContext( RecipientKind.AGENTS, null );
+ Assert.assertEquals( "", ctx.getTopicName());
+
+ ctx = new MessagingContext( RecipientKind.AGENTS, "facet", null, "whatever" );
+ Assert.assertEquals( "facet", ctx.getTopicName());
+
+ ctx = new MessagingContext( RecipientKind.AGENTS, "facet", ThoseThat.IMPORT, "whatever" );
+ Assert.assertEquals( "those.that.import.facet", ctx.getTopicName());
+ }
+
+
+ @Test
+ public void testToString() {
+
+ // DM
+ MessagingContext ctx = new MessagingContext( RecipientKind.DM, null );
+ Assert.assertEquals( "(DM)", ctx.toString());
+
+ ctx = new MessagingContext( RecipientKind.DM, "whatever" );
+ Assert.assertEquals( "whatever (DM)", ctx.toString());
+
+ // Inter-application
+ ctx = new MessagingContext( RecipientKind.INTER_APP, "whatever" );
+ Assert.assertEquals( "(INTER_APP)", ctx.toString());
+
+ ctx = new MessagingContext( RecipientKind.INTER_APP, null );
+ Assert.assertEquals( "(INTER_APP)", ctx.toString());
+
+ ctx = new MessagingContext( RecipientKind.INTER_APP, "facet", null, "whatever" );
+ Assert.assertEquals( "facet (INTER_APP)", ctx.toString());
+
+ ctx = new MessagingContext( RecipientKind.INTER_APP, "facet", ThoseThat.EXPORT, "whatever" );
+ Assert.assertEquals( "those.that.export.facet (INTER_APP)", ctx.toString());
+
+ // Agents
+ ctx = new MessagingContext( RecipientKind.AGENTS, "whatever" );
+ Assert.assertEquals( "@ whatever (AGENTS)", ctx.toString());
+
+ ctx = new MessagingContext( RecipientKind.AGENTS, null );
+ Assert.assertEquals( "(AGENTS)", ctx.toString());
+
+ ctx = new MessagingContext( RecipientKind.AGENTS, "facet", null, "whatever" );
+ Assert.assertEquals( "facet @ whatever (AGENTS)", ctx.toString());
+
+ ctx = new MessagingContext( RecipientKind.AGENTS, "facet", ThoseThat.IMPORT, "whatever" );
+ Assert.assertEquals( "those.that.import.facet @ whatever (AGENTS)", ctx.toString());
+ }
+}
diff --git a/core/roboconf-messaging-api/src/test/java/net/roboconf/messaging/api/factory/MessagingClientFactoryRegistryTest.java b/core/roboconf-messaging-api/src/test/java/net/roboconf/messaging/api/factory/MessagingClientFactoryRegistryTest.java
new file mode 100644
index 00000000..f87f7b7b
--- /dev/null
+++ b/core/roboconf-messaging-api/src/test/java/net/roboconf/messaging/api/factory/MessagingClientFactoryRegistryTest.java
@@ -0,0 +1,55 @@
+/**
+ * Copyright 2015 Linagora, Université Joseph Fourier, Floralis
+ *
+ * The present code is developed in the scope of the joint LINAGORA -
+ * Université Joseph Fourier - Floralis research program and is designated
+ * as a "Result" pursuant to the terms and conditions of the LINAGORA
+ * - Université Joseph Fourier - Floralis research program. Each copyright
+ * holder of Results enumerated here above fully & independently holds complete
+ * ownership of the complete Intellectual Property rights applicable to the whole
+ * of said Results, and may freely exploit it in any manner which does not infringe
+ * the moral rights of the other copyright holders.
+ *
+ * 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.
+ */
+
+package net.roboconf.messaging.api.factory;
+
+import org.junit.Assert;
+import net.roboconf.messaging.api.MessagingConstants;
+import net.roboconf.messaging.api.internal.client.test.TestClientFactory;
+
+import org.junit.Test;
+
+/**
+ * @author Vincent Zurczak - Linagora
+ */
+public class MessagingClientFactoryRegistryTest {
+
+ @Test
+ public void testAddGetAndRemove() {
+
+ MessagingClientFactoryRegistry registry = new MessagingClientFactoryRegistry();
+ Assert.assertNull( registry.getMessagingClientFactory( MessagingConstants.FACTORY_TEST ));
+
+ TestClientFactory factory = new TestClientFactory();
+ Assert.assertTrue( registry.addMessagingClientFactory( factory ));
+ Assert.assertNotNull( registry.getMessagingClientFactory( MessagingConstants.FACTORY_TEST ));
+
+ Assert.assertFalse( registry.addMessagingClientFactory( factory ));
+ Assert.assertTrue( registry.removeMessagingClientFactory( factory ));
+ Assert.assertNull( registry.getMessagingClientFactory( MessagingConstants.FACTORY_TEST ));
+
+ Assert.assertFalse( registry.removeMessagingClientFactory( factory ));
+ }
+}
diff --git a/core/roboconf-messaging-api/src/test/java/net/roboconf/messaging/api/internal/client/AbstractMessagingTest.java b/core/roboconf-messaging-api/src/test/java/net/roboconf/messaging/api/internal/client/AbstractMessagingTest.java
index d26f07a3..1c21e059 100644
--- a/core/roboconf-messaging-api/src/test/java/net/roboconf/messaging/api/internal/client/AbstractMessagingTest.java
+++ b/core/roboconf-messaging-api/src/test/java/net/roboconf/messaging/api/internal/client/AbstractMessagingTest.java
@@ -28,7 +28,6 @@
import java.util.ArrayList;
import java.util.List;
-import junit.framework.Assert;
import net.roboconf.core.internal.tests.TestApplication;
import net.roboconf.core.model.beans.Application;
import net.roboconf.core.model.beans.ApplicationTemplate;
@@ -39,9 +38,10 @@
import net.roboconf.core.model.beans.Instance;
import net.roboconf.core.model.beans.Instance.InstanceStatus;
import net.roboconf.core.model.helpers.InstanceHelpers;
-import net.roboconf.messaging.api.client.IAgentClient;
-import net.roboconf.messaging.api.client.IDmClient;
-import net.roboconf.messaging.api.client.ListenerCommand;
+import net.roboconf.messaging.api.AbstractMessageProcessor;
+import net.roboconf.messaging.api.business.IAgentClient;
+import net.roboconf.messaging.api.business.IDmClient;
+import net.roboconf.messaging.api.business.ListenerCommand;
import net.roboconf.messaging.api.factory.MessagingClientFactoryRegistry;
import net.roboconf.messaging.api.messages.Message;
import net.roboconf.messaging.api.messages.from_agent_to_agent.MsgCmdAddImport;
@@ -53,12 +53,12 @@
import net.roboconf.messaging.api.messages.from_dm_to_agent.MsgCmdRemoveInstance;
import net.roboconf.messaging.api.messages.from_dm_to_agent.MsgCmdSetScopedInstance;
import net.roboconf.messaging.api.messages.from_dm_to_dm.MsgEcho;
-import net.roboconf.messaging.api.processors.AbstractMessageProcessor;
import net.roboconf.messaging.api.reconfigurables.ReconfigurableClient;
import net.roboconf.messaging.api.reconfigurables.ReconfigurableClientAgent;
import net.roboconf.messaging.api.reconfigurables.ReconfigurableClientDm;
import org.junit.After;
+import org.junit.Assert;
/**
* This class defines messaging tests, independently of the implementation.
@@ -76,9 +76,9 @@
*/
public abstract class AbstractMessagingTest {
- private static final long DELAY = 700;
+ protected MessagingClientFactoryRegistry registry = new MessagingClientFactoryRegistry();
private final List> clients = new ArrayList<> ();
- protected final MessagingClientFactoryRegistry registry = new MessagingClientFactoryRegistry();
+
@After
public void releaseClients() throws Exception {
@@ -93,6 +93,12 @@ public void releaseClients() throws Exception {
}
+ /**
+ * @return the delay to wait for messages (in ms)
+ */
+ abstract protected long getDelay();
+
+
/**
* Tests synchronous exchanges between the DM and an agent.
* @throws Exception
@@ -107,34 +113,34 @@ public void testExchangesBetweenTheDmAndOneAgent() throws Exception {
List agentMessages = new ArrayList<>();
ReconfigurableClientDm dmClient = new ReconfigurableClientDm();
- dmClient.setRegistry(this.registry);
+ dmClient.setRegistry( this.registry );
dmClient.associateMessageProcessor( createDmProcessor( dmMessages ));
- dmClient.switchMessagingType(getMessagingType());
+ dmClient.switchMessagingType( getMessagingType());
this.clients.add( dmClient );
ReconfigurableClientAgent agentClient = new ReconfigurableClientAgent();
- agentClient.setRegistry(this.registry);
+ agentClient.setRegistry( this.registry );
agentClient.associateMessageProcessor( createAgentProcessor( agentMessages ));
agentClient.setApplicationName( app.getName());
agentClient.setScopedInstancePath( "/" + rootInstance.getName());
agentClient.setExternalMapping( app.getExternalExports());
- agentClient.switchMessagingType(getMessagingType());
+ agentClient.switchMessagingType( getMessagingType());
this.clients.add( agentClient );
// No message yet
- Thread.sleep( DELAY );
+ Thread.sleep( getDelay());
Assert.assertEquals( 0, dmMessages.size());
Assert.assertEquals( 0, agentMessages.size());
// The agent is already listening to the DM.
dmClient.sendMessageToAgent( app, rootInstance, new MsgCmdSetScopedInstance( rootInstance ));
- Thread.sleep( DELAY );
+ Thread.sleep( getDelay());
Assert.assertEquals( 1, agentMessages.size());
Assert.assertEquals( MsgCmdSetScopedInstance.class, agentMessages.get( 0 ).getClass());
agentClient.listenToTheDm( ListenerCommand.START );
dmClient.sendMessageToAgent( app, rootInstance, new MsgCmdRemoveInstance( rootInstance ));
- Thread.sleep( DELAY );
+ Thread.sleep( getDelay());
Assert.assertEquals( 2, agentMessages.size());
Assert.assertEquals( MsgCmdSetScopedInstance.class, agentMessages.get( 0 ).getClass());
Assert.assertEquals( MsgCmdRemoveInstance.class, agentMessages.get( 1 ).getClass());
@@ -142,18 +148,18 @@ public void testExchangesBetweenTheDmAndOneAgent() throws Exception {
// The agent sends a message to the DM
Assert.assertEquals( 0, dmMessages.size());
agentClient.sendMessageToTheDm( new MsgNotifHeartbeat( app.getName(), rootInstance, "192.168.1.45" ));
- Thread.sleep( DELAY );
+ Thread.sleep( getDelay());
Assert.assertEquals( 0, dmMessages.size());
dmClient.listenToAgentMessages( app, ListenerCommand.START );
agentClient.sendMessageToTheDm( new MsgNotifMachineDown( app.getName(), rootInstance ));
- Thread.sleep( DELAY );
+ Thread.sleep( getDelay());
Assert.assertEquals( 1, dmMessages.size());
Assert.assertEquals( MsgNotifMachineDown.class, dmMessages.get( 0 ).getClass());
// The DM sends another message
dmClient.sendMessageToAgent( app, rootInstance, new MsgCmdChangeInstanceState( rootInstance, InstanceStatus.DEPLOYED_STARTED ));
- Thread.sleep( DELAY );
+ Thread.sleep( getDelay());
Assert.assertEquals( 3, agentMessages.size());
Assert.assertEquals( MsgCmdSetScopedInstance.class, agentMessages.get( 0 ).getClass());
Assert.assertEquals( MsgCmdRemoveInstance.class, agentMessages.get( 1 ).getClass());
@@ -161,25 +167,26 @@ public void testExchangesBetweenTheDmAndOneAgent() throws Exception {
// The agent stops listening the DM
agentClient.listenToTheDm( ListenerCommand.STOP );
+ Thread.sleep( getDelay());
// The agent is not listening to the DM anymore.
// With RabbitMQ, the next invocation will result in a NO_ROUTE error in the channel.
dmClient.sendMessageToAgent( app, rootInstance, new MsgCmdChangeInstanceState( rootInstance, InstanceStatus.DEPLOYED_STARTED ));
- Thread.sleep( DELAY );
+ Thread.sleep( getDelay());
Assert.assertEquals( 3, agentMessages.size());
- Thread.sleep( DELAY );
+ Thread.sleep( getDelay());
Assert.assertEquals( 3, agentMessages.size());
- Thread.sleep( DELAY );
+ Thread.sleep( getDelay());
Assert.assertEquals( 3, agentMessages.size());
// The DM stops listening the agent
dmClient.listenToAgentMessages( app, ListenerCommand.STOP );
agentClient.sendMessageToTheDm( new MsgNotifHeartbeat( app.getName(), rootInstance, "192.168.1.47" ));
- Thread.sleep( DELAY );
+ Thread.sleep( getDelay());
Assert.assertEquals( 1, dmMessages.size());
- Thread.sleep( DELAY );
+ Thread.sleep( getDelay());
Assert.assertEquals( 1, dmMessages.size());
- Thread.sleep( DELAY );
+ Thread.sleep( getDelay());
Assert.assertEquals( 1, dmMessages.size());
}
@@ -204,45 +211,46 @@ public void testExchangesBetweenTheDmAndThreeAgents() throws Exception {
List dmMessages = new ArrayList<>();
ReconfigurableClientDm dmClient = new ReconfigurableClientDm();
- dmClient.setRegistry(this.registry);
+ dmClient.setRegistry( this.registry );
dmClient.associateMessageProcessor( createDmProcessor( dmMessages ));
- dmClient.switchMessagingType(getMessagingType());
+ dmClient.switchMessagingType( getMessagingType());
this.clients.add( dmClient );
List agentMessages_11 = new ArrayList<>();
ReconfigurableClientAgent agentClient_11 = new ReconfigurableClientAgent();
- agentClient_11.setRegistry(this.registry);
+ agentClient_11.setRegistry( this.registry );
agentClient_11.associateMessageProcessor( createAgentProcessor( agentMessages_11 ));
agentClient_11.setApplicationName( app1.getName());
agentClient_11.setScopedInstancePath( "/" + app1_root1.getName());
agentClient_11.setExternalMapping( app1.getExternalExports());
- agentClient_11.switchMessagingType(getMessagingType());
+ agentClient_11.switchMessagingType( getMessagingType());
this.clients.add( agentClient_11 );
List agentMessages_12 = new ArrayList<>();
ReconfigurableClientAgent agentClient_12 = new ReconfigurableClientAgent();
- agentClient_12.setRegistry(this.registry);
+ agentClient_12.setRegistry( this.registry );
agentClient_12.associateMessageProcessor( createAgentProcessor( agentMessages_12 ));
agentClient_12.setApplicationName( app1.getName());
agentClient_12.setScopedInstancePath( "/" + app1_root2.getName());
agentClient_12.setExternalMapping( app1.getExternalExports());
- agentClient_12.switchMessagingType(getMessagingType());
+ agentClient_12.switchMessagingType( getMessagingType());
this.clients.add( agentClient_12 );
List agentMessages_2 = new ArrayList<>();
ReconfigurableClientAgent agentClient_2 = new ReconfigurableClientAgent();
- agentClient_2.setRegistry(this.registry);
+ agentClient_2.setRegistry( this.registry );
agentClient_2.associateMessageProcessor( createAgentProcessor( agentMessages_2 ));
agentClient_2.setApplicationName( app2.getName());
agentClient_2.setScopedInstancePath( "/" + app2_root.getName());
agentClient_2.setExternalMapping( app2.getExternalExports());
- agentClient_2.switchMessagingType(getMessagingType());
+ agentClient_2.switchMessagingType( getMessagingType());
this.clients.add( agentClient_2 );
// Everybody starts listening...
agentClient_11.listenToTheDm( ListenerCommand.START );
agentClient_12.listenToTheDm( ListenerCommand.START );
agentClient_2.listenToTheDm( ListenerCommand.START );
+ Thread.sleep( getDelay());
// The DM sends messages
dmClient.sendMessageToAgent( app1, app1_root1, new MsgCmdSetScopedInstance( app1_root1 ));
@@ -257,7 +265,7 @@ public void testExchangesBetweenTheDmAndThreeAgents() throws Exception {
dmClient.sendMessageToAgent( app1, app1_root1, new MsgCmdSetScopedInstance( app1_root1 ));
// Check what was received
- Thread.sleep( DELAY );
+ Thread.sleep( getDelay());
Assert.assertEquals( 3, agentMessages_11.size());
Assert.assertEquals( MsgCmdSetScopedInstance.class, agentMessages_11.get( 0 ).getClass());
@@ -319,48 +327,49 @@ public void testExportsBetweenAgents() throws Exception {
// Initialize the messaging
List tomcatMessages = new ArrayList<>();
ReconfigurableClientAgent tomcatClient = new ReconfigurableClientAgent();
- tomcatClient.setRegistry(this.registry);
+ tomcatClient.setRegistry( this.registry );
tomcatClient.associateMessageProcessor( createAgentProcessor( tomcatMessages ));
tomcatClient.setApplicationName( app1.getName());
tomcatClient.setScopedInstancePath( "/" + tomcat.getName());
tomcatClient.setExternalMapping( app1.getExternalExports());
- tomcatClient.switchMessagingType(getMessagingType());
+ tomcatClient.switchMessagingType( getMessagingType());
this.clients.add( tomcatClient );
List apacheMessages = new ArrayList<>();
ReconfigurableClientAgent apacheClient = new ReconfigurableClientAgent();
- apacheClient.setRegistry(this.registry);
+ apacheClient.setRegistry( this.registry );
apacheClient.associateMessageProcessor( createAgentProcessor( apacheMessages ));
apacheClient.setApplicationName( app1.getName());
apacheClient.setScopedInstancePath( "/" + apache.getName());
apacheClient.setExternalMapping( app1.getExternalExports());
- apacheClient.switchMessagingType(getMessagingType());
+ apacheClient.switchMessagingType( getMessagingType());
this.clients.add( apacheClient );
List mySqlMessages = new ArrayList<>();
ReconfigurableClientAgent mySqlClient = new ReconfigurableClientAgent();
- mySqlClient.setRegistry(this.registry);
+ mySqlClient.setRegistry( this.registry );
mySqlClient.associateMessageProcessor( createAgentProcessor( mySqlMessages ));
mySqlClient.setApplicationName( app1.getName());
mySqlClient.setScopedInstancePath( "/" + mysql.getName());
mySqlClient.setExternalMapping( app1.getExternalExports());
- mySqlClient.switchMessagingType(getMessagingType());
+ mySqlClient.switchMessagingType( getMessagingType());
this.clients.add( mySqlClient );
List otherMessages = new ArrayList<>();
ReconfigurableClientAgent otherClient = new ReconfigurableClientAgent();
- otherClient.setRegistry(this.registry);
+ otherClient.setRegistry( this.registry );
otherClient.associateMessageProcessor( createAgentProcessor( otherMessages ));
otherClient.setApplicationName( app2.getName());
otherClient.setScopedInstancePath( "/" + other.getName());
otherClient.setExternalMapping( app2.getExternalExports());
- otherClient.switchMessagingType(getMessagingType());
+ otherClient.switchMessagingType( getMessagingType());
this.clients.add( otherClient );
// OK, let's start.
// MySQL publishes its exports but nobody is listening.
mySqlClient.publishExports( mysql );
- Thread.sleep( DELAY );
+ Thread.sleep( getDelay());
+
Assert.assertEquals( 0, mySqlMessages.size());
Assert.assertEquals( 0, apacheMessages.size());
Assert.assertEquals( 0, tomcatMessages.size());
@@ -370,8 +379,10 @@ public void testExportsBetweenAgents() throws Exception {
// Let's re-export MySQL.
otherClient.listenToExportsFromOtherAgents( ListenerCommand.START, other );
tomcatClient.listenToExportsFromOtherAgents( ListenerCommand.START, tomcat );
+ Thread.sleep( getDelay());
+
mySqlClient.publishExports( mysql );
- Thread.sleep( DELAY );
+ Thread.sleep( getDelay());
Assert.assertEquals( 0, mySqlMessages.size());
Assert.assertEquals( 0, apacheMessages.size());
@@ -388,6 +399,7 @@ public void testExportsBetweenAgents() throws Exception {
// Let's publish an unknown facet. Nobody should receive it.
mySqlClient.publishExports( mysql, "an-unknown-facet-or-component-name" );
+ Thread.sleep( getDelay());
Assert.assertEquals( 0, mySqlMessages.size());
Assert.assertEquals( 0, apacheMessages.size());
@@ -397,7 +409,7 @@ public void testExportsBetweenAgents() throws Exception {
// Other publishes its exports.
// Tomcat is not supposed to receive it.
otherClient.publishExports( other );
- Thread.sleep( DELAY );
+ Thread.sleep( getDelay());
Assert.assertEquals( 0, mySqlMessages.size());
Assert.assertEquals( 0, apacheMessages.size());
@@ -409,8 +421,10 @@ public void testExportsBetweenAgents() throws Exception {
// Tomcat publishes its exports.
apacheClient.listenToExportsFromOtherAgents( ListenerCommand.START, apache );
mySqlClient.listenToExportsFromOtherAgents( ListenerCommand.START, mysql );
+ Thread.sleep( getDelay());
+
tomcatClient.publishExports( tomcat );
- Thread.sleep( DELAY );
+ Thread.sleep( getDelay());
Assert.assertEquals( 0, mySqlMessages.size());
Assert.assertEquals( 0, otherMessages.size());
@@ -427,7 +441,7 @@ public void testExportsBetweenAgents() throws Exception {
// MySQL publishes (again) its exports
mySqlClient.publishExports( mysql );
- Thread.sleep( DELAY );
+ Thread.sleep( getDelay());
Assert.assertEquals( 0, mySqlMessages.size());
Assert.assertEquals( 0, otherMessages.size());
@@ -445,7 +459,7 @@ public void testExportsBetweenAgents() throws Exception {
// MySQL un-publishes its exports
mySqlClient.unpublishExports( mysql );
- Thread.sleep( DELAY );
+ Thread.sleep( getDelay());
Assert.assertEquals( 0, mySqlMessages.size());
Assert.assertEquals( 0, otherMessages.size());
@@ -462,8 +476,10 @@ public void testExportsBetweenAgents() throws Exception {
// MySQL publishes (again) its exports
// But this time, Tomcat does not listen anymore
tomcatClient.listenToExportsFromOtherAgents( ListenerCommand.STOP, tomcat );
+ Thread.sleep( getDelay());
+
mySqlClient.publishExports( mysql );
- Thread.sleep( DELAY );
+ Thread.sleep( getDelay());
Assert.assertEquals( 0, mySqlMessages.size());
Assert.assertEquals( 0, otherMessages.size());
@@ -514,48 +530,48 @@ public void testExportsRequestsBetweenAgents() throws Exception {
// Initialize the messaging
List tomcatMessages = new ArrayList<>();
ReconfigurableClientAgent tomcatClient = new ReconfigurableClientAgent();
- tomcatClient.setRegistry(this.registry);
+ tomcatClient.setRegistry( this.registry );
tomcatClient.associateMessageProcessor( createAgentProcessor( tomcatMessages ));
tomcatClient.setApplicationName( app1.getName());
tomcatClient.setScopedInstancePath( "/" + tomcat.getName());
tomcatClient.setExternalMapping( app1.getExternalExports());
- tomcatClient.switchMessagingType(getMessagingType());
+ tomcatClient.switchMessagingType( getMessagingType());
this.clients.add( tomcatClient );
List apacheMessages = new ArrayList<>();
ReconfigurableClientAgent apacheClient = new ReconfigurableClientAgent();
- apacheClient.setRegistry(this.registry);
+ apacheClient.setRegistry( this.registry );
apacheClient.associateMessageProcessor( createAgentProcessor( apacheMessages ));
apacheClient.setApplicationName( app1.getName());
apacheClient.setScopedInstancePath( "/" + apache.getName());
apacheClient.setExternalMapping( app1.getExternalExports());
- apacheClient.switchMessagingType(getMessagingType());
+ apacheClient.switchMessagingType( getMessagingType());
this.clients.add( apacheClient );
List mySqlMessages = new ArrayList<>();
ReconfigurableClientAgent mySqlClient = new ReconfigurableClientAgent();
- mySqlClient.setRegistry(this.registry);
+ mySqlClient.setRegistry( this.registry );
mySqlClient.associateMessageProcessor( createAgentProcessor( mySqlMessages ));
mySqlClient.setApplicationName( app1.getName());
mySqlClient.setScopedInstancePath( "/" + mysql.getName());
mySqlClient.setExternalMapping( app1.getExternalExports());
- mySqlClient.switchMessagingType(getMessagingType());
+ mySqlClient.switchMessagingType( getMessagingType());
this.clients.add( mySqlClient );
List otherMessages = new ArrayList<>();
ReconfigurableClientAgent otherClient = new ReconfigurableClientAgent();
- otherClient.setRegistry(this.registry);
+ otherClient.setRegistry( this.registry );
otherClient.associateMessageProcessor( createAgentProcessor( otherMessages ));
otherClient.setApplicationName( app2.getName());
otherClient.setScopedInstancePath( "/" + other.getName());
otherClient.setExternalMapping( app2.getExternalExports());
- otherClient.switchMessagingType(getMessagingType());
+ otherClient.switchMessagingType( getMessagingType());
this.clients.add( otherClient );
// OK, let's start.
// Tomcat requests MySQL exports but MySQL is not listening
tomcatClient.requestExportsFromOtherAgents( tomcat );
- Thread.sleep( DELAY );
+ Thread.sleep( getDelay());
Assert.assertEquals( 0, mySqlMessages.size());
Assert.assertEquals( 0, apacheMessages.size());
Assert.assertEquals( 0, tomcatMessages.size());
@@ -566,7 +582,7 @@ public void testExportsRequestsBetweenAgents() throws Exception {
otherClient.listenToRequestsFromOtherAgents( ListenerCommand.START, other );
mySqlClient.listenToRequestsFromOtherAgents( ListenerCommand.START, mysql );
tomcatClient.requestExportsFromOtherAgents( tomcat );
- Thread.sleep( DELAY );
+ Thread.sleep( getDelay());
Assert.assertEquals( 0, apacheMessages.size());
Assert.assertEquals( 0, tomcatMessages.size());
@@ -580,7 +596,7 @@ public void testExportsRequestsBetweenAgents() throws Exception {
// Now, let's do it again but MySQL stops listening.
mySqlClient.listenToRequestsFromOtherAgents( ListenerCommand.STOP, mysql );
tomcatClient.requestExportsFromOtherAgents( tomcat );
- Thread.sleep( DELAY );
+ Thread.sleep( getDelay());
Assert.assertEquals( 0, apacheMessages.size());
Assert.assertEquals( 0, tomcatMessages.size());
@@ -589,7 +605,7 @@ public void testExportsRequestsBetweenAgents() throws Exception {
// Other requires exports from others.
otherClient.requestExportsFromOtherAgents( other );
- Thread.sleep( DELAY );
+ Thread.sleep( getDelay());
Assert.assertEquals( 0, apacheMessages.size());
Assert.assertEquals( 0, tomcatMessages.size());
@@ -625,35 +641,37 @@ public void testExportsBetweenSiblingAgents() throws Exception {
// Initialize the messaging
List messages1 = new ArrayList<>();
ReconfigurableClientAgent client1 = new ReconfigurableClientAgent();
- client1.setRegistry(this.registry);
+ client1.setRegistry( this.registry );
client1.associateMessageProcessor( createAgentProcessor( messages1 ));
client1.setApplicationName( app.getName());
client1.setScopedInstancePath( "/" + instance1.getName());
client1.setExternalMapping( app.getExternalExports());
- client1.switchMessagingType(getMessagingType());
+ client1.switchMessagingType( getMessagingType());
this.clients.add( client1 );
List messages2 = new ArrayList<>();
ReconfigurableClientAgent client2 = new ReconfigurableClientAgent();
- client2.setRegistry(this.registry);
+ client2.setRegistry( this.registry );
client2.associateMessageProcessor( createAgentProcessor( messages2 ));
client2.setApplicationName( app.getName());
client2.setScopedInstancePath( "/" + instance2.getName());
client2.setExternalMapping( app.getExternalExports());
- client2.switchMessagingType(getMessagingType());
+ client2.switchMessagingType( getMessagingType());
this.clients.add( client2 );
// OK, let's start.
// Instance1 is alone.
client1.requestExportsFromOtherAgents( instance1 );
- Thread.sleep( DELAY );
+ Thread.sleep( getDelay());
Assert.assertEquals( 0, messages1.size());
Assert.assertEquals( 0, messages2.size());
// Now, instance2 is listening.
client2.listenToRequestsFromOtherAgents( ListenerCommand.START, instance2 );
+ Thread.sleep( getDelay());
client1.requestExportsFromOtherAgents( instance1 );
- Thread.sleep( DELAY );
+ Thread.sleep( getDelay());
+
Assert.assertEquals( 0, messages1.size());
Assert.assertEquals( 2, messages2.size());
Assert.assertEquals( MsgCmdRequestImport.class, messages2.get( 0 ).getClass());
@@ -670,8 +688,10 @@ public void testExportsBetweenSiblingAgents() throws Exception {
// instance1 should receive the notification it has sent. It will be up to the agent to ignore it.
client2.listenToRequestsFromOtherAgents( ListenerCommand.STOP, instance2 );
client1.listenToRequestsFromOtherAgents( ListenerCommand.START, instance1 );
+ Thread.sleep( getDelay());
+
client1.requestExportsFromOtherAgents( instance1 );
- Thread.sleep( DELAY );
+ Thread.sleep( getDelay());
Assert.assertEquals( 2, messages2.size());
Assert.assertEquals( 2, messages1.size());
@@ -719,9 +739,9 @@ public void testPropagateAgentTermination() throws Exception {
// Except it is not in the same application.
List dmMessages = new ArrayList<>();
ReconfigurableClientDm dmClient = new ReconfigurableClientDm();
- dmClient.setRegistry(this.registry);
+ dmClient.setRegistry( this.registry );
dmClient.associateMessageProcessor( createDmProcessor( dmMessages ));
- dmClient.switchMessagingType(getMessagingType());
+ dmClient.switchMessagingType( getMessagingType());
this.clients.add( dmClient );
Component otherComponent = new Component( "other" );
@@ -735,48 +755,48 @@ public void testPropagateAgentTermination() throws Exception {
// Initialize the messaging
List tomcatMessages = new ArrayList<>();
ReconfigurableClientAgent tomcatClient = new ReconfigurableClientAgent();
- tomcatClient.setRegistry(this.registry);
+ tomcatClient.setRegistry( this.registry );
tomcatClient.associateMessageProcessor( createAgentProcessor( tomcatMessages ));
tomcatClient.setApplicationName( app1.getName());
tomcatClient.setScopedInstancePath( "/" + tomcat.getName());
tomcatClient.setExternalMapping( app1.getExternalExports());
- tomcatClient.switchMessagingType(getMessagingType());
+ tomcatClient.switchMessagingType( getMessagingType());
tomcatClient.listenToTheDm( ListenerCommand.START );
tomcatClient.listenToExportsFromOtherAgents( ListenerCommand.START, tomcat );
this.clients.add( tomcatClient );
List apacheMessages = new ArrayList<>();
ReconfigurableClientAgent apacheClient = new ReconfigurableClientAgent();
- apacheClient.setRegistry(this.registry);
+ apacheClient.setRegistry( this.registry );
apacheClient.associateMessageProcessor( createAgentProcessor( apacheMessages ));
apacheClient.setApplicationName( app1.getName());
apacheClient.setScopedInstancePath( "/" + apache.getName());
apacheClient.setExternalMapping( app1.getExternalExports());
- apacheClient.switchMessagingType(getMessagingType());
+ apacheClient.switchMessagingType( getMessagingType());
apacheClient.listenToTheDm( ListenerCommand.START );
apacheClient.listenToExportsFromOtherAgents( ListenerCommand.START, apache );
this.clients.add( apacheClient );
List mySqlMessages = new ArrayList<>();
ReconfigurableClientAgent mySqlClient = new ReconfigurableClientAgent();
- mySqlClient.setRegistry(this.registry);
+ mySqlClient.setRegistry( this.registry );
mySqlClient.associateMessageProcessor( createAgentProcessor( mySqlMessages ));
mySqlClient.setApplicationName( app1.getName());
mySqlClient.setScopedInstancePath( "/" + mysql.getName());
mySqlClient.setExternalMapping( app1.getExternalExports());
- mySqlClient.switchMessagingType(getMessagingType());
+ mySqlClient.switchMessagingType( getMessagingType());
mySqlClient.listenToTheDm( ListenerCommand.START );
mySqlClient.listenToExportsFromOtherAgents( ListenerCommand.START, mysql );
this.clients.add( mySqlClient );
List otherMessages = new ArrayList<>();
ReconfigurableClientAgent otherClient = new ReconfigurableClientAgent();
- otherClient.setRegistry(this.registry);
+ otherClient.setRegistry( this.registry );
otherClient.associateMessageProcessor( createAgentProcessor( otherMessages ));
otherClient.setApplicationName( app2.getName());
otherClient.setScopedInstancePath( "/" + other.getName());
otherClient.setExternalMapping( app2.getExternalExports());
- otherClient.switchMessagingType(getMessagingType());
+ otherClient.switchMessagingType( getMessagingType());
otherClient.listenToTheDm( ListenerCommand.START );
otherClient.listenToExportsFromOtherAgents( ListenerCommand.START, other );
this.clients.add( otherClient );
@@ -786,7 +806,7 @@ public void testPropagateAgentTermination() throws Exception {
dmClient.propagateAgentTermination( app1, mysql );
dmClient.propagateAgentTermination( app2, other );
- Thread.sleep( DELAY );
+ Thread.sleep( getDelay());
Assert.assertEquals( 0, apacheMessages.size());
Assert.assertEquals( 0, mySqlMessages.size());
@@ -808,19 +828,19 @@ public void testDmDebug() throws Exception {
List dmMessages = new ArrayList<>();
ReconfigurableClientDm dmClient = new ReconfigurableClientDm();
- dmClient.setRegistry(this.registry);
+ dmClient.setRegistry( this.registry );
dmClient.associateMessageProcessor( createDmProcessor( dmMessages ));
- dmClient.switchMessagingType(getMessagingType());
+ dmClient.switchMessagingType( getMessagingType());
this.clients.add( dmClient );
dmClient.sendMessageToTheDm( new MsgEcho( "hey 1" ));
- Thread.sleep( DELAY );
+ Thread.sleep( getDelay());
Assert.assertEquals( 0, dmMessages.size());
dmClient.listenToTheDm( ListenerCommand.START );
dmClient.sendMessageToTheDm( new MsgEcho( "hey 2" ));
dmClient.sendMessageToTheDm( new MsgEcho( "hey 3" ));
- Thread.sleep( DELAY );
+ Thread.sleep( getDelay());
Assert.assertEquals( 2, dmMessages.size());
Assert.assertEquals( MsgEcho.class, dmMessages.get( 0 ).getClass());
@@ -830,7 +850,7 @@ public void testDmDebug() throws Exception {
dmClient.listenToTheDm( ListenerCommand.STOP );
dmClient.sendMessageToTheDm( new MsgEcho( "hey again" ));
- Thread.sleep( DELAY );
+ Thread.sleep( getDelay());
Assert.assertEquals( 2, dmMessages.size());
}
@@ -860,7 +880,7 @@ public void testExternalExports_withTwoApplications() throws Exception {
// Prepare messaging clients - we only focus on MySQL and Tomcat
List app1_mysqlMessages = new ArrayList<> ();
ReconfigurableClientAgent app1_mysqlClient = new ReconfigurableClientAgent();
- app1_mysqlClient.setRegistry(this.registry);
+ app1_mysqlClient.setRegistry( this.registry );
app1_mysqlClient.associateMessageProcessor( createAgentProcessor( app1_mysqlMessages ));
app1_mysqlClient.setApplicationName( app1.getName());
app1_mysqlClient.setScopedInstancePath( InstanceHelpers.computeInstancePath( app1.getMySqlVm()));
@@ -870,7 +890,7 @@ public void testExternalExports_withTwoApplications() throws Exception {
List app2_mysqlMessages = new ArrayList<> ();
ReconfigurableClientAgent app2_mysqlClient = new ReconfigurableClientAgent();
- app2_mysqlClient.setRegistry(this.registry);
+ app2_mysqlClient.setRegistry( this.registry );
app2_mysqlClient.associateMessageProcessor( createAgentProcessor( app2_mysqlMessages ));
app2_mysqlClient.setApplicationName( app2.getName());
app2_mysqlClient.setScopedInstancePath( InstanceHelpers.computeInstancePath( app2.getMySqlVm()));
@@ -880,7 +900,7 @@ public void testExternalExports_withTwoApplications() throws Exception {
List app1_tomcatMessages = new ArrayList<> ();
ReconfigurableClientAgent app1_tomcatClient = new ReconfigurableClientAgent();
- app1_tomcatClient.setRegistry(this.registry);
+ app1_tomcatClient.setRegistry( this.registry );
app1_tomcatClient.associateMessageProcessor( createAgentProcessor( app1_tomcatMessages ));
app1_tomcatClient.setApplicationName( app1.getName());
app1_tomcatClient.setScopedInstancePath( InstanceHelpers.computeInstancePath( app1.getTomcatVm()));
@@ -890,7 +910,7 @@ public void testExternalExports_withTwoApplications() throws Exception {
List app2_tomcatMessages = new ArrayList<> ();
ReconfigurableClientAgent app2_tomcatClient = new ReconfigurableClientAgent();
- app2_tomcatClient.setRegistry(this.registry);
+ app2_tomcatClient.setRegistry( this.registry );
app2_tomcatClient.associateMessageProcessor( createAgentProcessor( app2_tomcatMessages ));
app2_tomcatClient.setApplicationName( app2.getName());
app2_tomcatClient.setScopedInstancePath( InstanceHelpers.computeInstancePath( app2.getTomcatVm()));
@@ -901,7 +921,7 @@ public void testExternalExports_withTwoApplications() throws Exception {
// OK, let's start.
// Tomcat requests MySQL exports but no MySQL is listening
app1_tomcatClient.requestExportsFromOtherAgents( app1.getTomcat());
- Thread.sleep( DELAY );
+ Thread.sleep( getDelay());
Assert.assertEquals( 0, app1_tomcatMessages.size());
Assert.assertEquals( 0, app2_tomcatMessages.size());
Assert.assertEquals( 0, app1_mysqlMessages.size());
@@ -910,7 +930,7 @@ public void testExternalExports_withTwoApplications() throws Exception {
// Now, start the (external) MySQL, the one in app2.
app2_mysqlClient.listenToRequestsFromOtherAgents( ListenerCommand.START, app2.getMySql());
app1_tomcatClient.requestExportsFromOtherAgents( app1.getTomcat());
- Thread.sleep( DELAY );
+ Thread.sleep( getDelay());
Assert.assertEquals( 0, app1_tomcatMessages.size());
Assert.assertEquals( 0, app2_tomcatMessages.size());
@@ -924,7 +944,7 @@ public void testExternalExports_withTwoApplications() throws Exception {
// Let's check exports.
// Tomcat is not listening...
app2_mysqlClient.publishExports( app2.getMySql());
- Thread.sleep( DELAY );
+ Thread.sleep( getDelay());
Assert.assertEquals( 0, app1_tomcatMessages.size());
Assert.assertEquals( 0, app2_tomcatMessages.size());
@@ -934,7 +954,7 @@ public void testExternalExports_withTwoApplications() throws Exception {
// Let's check exports with Tomcat listening...
app1_tomcatClient.listenToExportsFromOtherAgents( ListenerCommand.START, app1.getTomcat());
app2_mysqlClient.publishExports( app2.getMySql());
- Thread.sleep( DELAY );
+ Thread.sleep( getDelay());
Assert.assertEquals( 0, app2_tomcatMessages.size());
Assert.assertEquals( 0, app1_mysqlMessages.size());
@@ -952,7 +972,7 @@ public void testExternalExports_withTwoApplications() throws Exception {
// What happens if we ask to only publish an external variable?
app2_mysqlClient.publishExports( app2.getMySql(), "tpl2" );
- Thread.sleep( DELAY );
+ Thread.sleep( getDelay());
Assert.assertEquals( 0, app2_tomcatMessages.size());
Assert.assertEquals( 0, app1_mysqlMessages.size());
@@ -972,7 +992,7 @@ public void testExternalExports_withTwoApplications() throws Exception {
// Just to be sure, turn off the listening on the Tomcat side.
app1_tomcatClient.listenToExportsFromOtherAgents( ListenerCommand.STOP, app1.getTomcat());
app2_mysqlClient.unpublishExports( app2.getMySql());
- Thread.sleep( DELAY );
+ Thread.sleep( getDelay());
Assert.assertEquals( 0, app2_tomcatMessages.size());
Assert.assertEquals( 0, app1_mysqlMessages.size());
@@ -982,7 +1002,7 @@ public void testExternalExports_withTwoApplications() throws Exception {
// Good! Now, let's check unpublish events.
app1_tomcatClient.listenToExportsFromOtherAgents( ListenerCommand.START, app1.getTomcat());
app2_mysqlClient.unpublishExports( app2.getMySql());
- Thread.sleep( DELAY );
+ Thread.sleep( getDelay());
Assert.assertEquals( 0, app2_tomcatMessages.size());
Assert.assertEquals( 0, app1_mysqlMessages.size());
@@ -998,7 +1018,7 @@ public void testExternalExports_withTwoApplications() throws Exception {
// app2 >> MySQL does not listen anymore. Requests are not propagated anymore.
app2_mysqlClient.listenToRequestsFromOtherAgents( ListenerCommand.STOP, app2.getMySql());
app1_tomcatClient.requestExportsFromOtherAgents( app1.getTomcat());
- Thread.sleep( DELAY );
+ Thread.sleep( getDelay());
Assert.assertEquals( 0, app2_tomcatMessages.size());
Assert.assertEquals( 0, app1_mysqlMessages.size());
@@ -1007,7 +1027,144 @@ public void testExternalExports_withTwoApplications() throws Exception {
}
- protected abstract AbstractMessageProcessor createDmProcessor( List dmMessages );
- protected abstract AbstractMessageProcessor createAgentProcessor( List agentMessages );
+ /**
+ * Verify agent termination is correctly propagated by the DM.
+ * @throws Exception
+ */
+ public void testExternalExports_twoApplicationsAndTheDm_verifyAgentTerminationPropagation() throws Exception {
+
+ // Create two applications
+ TestApplication app1 = new TestApplication();
+ app1.getTemplate().setName( "tpl1" );
+ app1.setName( "app1" );
+
+ TestApplication app2 = new TestApplication();
+ app2.getTemplate().setName( "tpl2" );
+ app2.setName( "app2" );
+
+ // Add an external dependency between them: app1 depends on app2
+ ImportedVariable var = new ImportedVariable( "tpl2.ext-ip", false, true );
+ app1.getTomcat().getComponent().importedVariables.put( var.getName(), var );
+
+ app2.getTemplate().externalExports.put( "mysql.ip", "tpl2.ext-ip" );
+ app2.getTemplate().externalExports.put( "mysql.port", "tpl2.ext-port" );
+
+ // Prepare messaging clients
+ List dmMessages = new ArrayList<>();
+ ReconfigurableClientDm dmClient = new ReconfigurableClientDm();
+ dmClient.setRegistry( this.registry );
+ dmClient.associateMessageProcessor( createDmProcessor( dmMessages ));
+ dmClient.switchMessagingType( getMessagingType());
+ this.clients.add( dmClient );
+
+ List app2_mysqlMessages = new ArrayList<> ();
+ ReconfigurableClientAgent app2_mysqlClient = new ReconfigurableClientAgent();
+ app2_mysqlClient.setRegistry( this.registry );
+ app2_mysqlClient.associateMessageProcessor( createAgentProcessor( app2_mysqlMessages ));
+ app2_mysqlClient.setApplicationName( app2.getName());
+ app2_mysqlClient.setScopedInstancePath( InstanceHelpers.computeInstancePath( app2.getMySqlVm()));
+ app2_mysqlClient.setExternalMapping( app2.getExternalExports());
+ app2_mysqlClient.switchMessagingType( getMessagingType());
+ this.clients.add( app2_mysqlClient );
+
+ List app1_tomcatMessages = new ArrayList<> ();
+ ReconfigurableClientAgent app1_tomcatClient = new ReconfigurableClientAgent();
+ app1_tomcatClient.setRegistry( this.registry );
+ app1_tomcatClient.associateMessageProcessor( createAgentProcessor( app1_tomcatMessages ));
+ app1_tomcatClient.setApplicationName( app1.getName());
+ app1_tomcatClient.setScopedInstancePath( InstanceHelpers.computeInstancePath( app1.getTomcatVm()));
+ app1_tomcatClient.setExternalMapping( app1.getExternalExports());
+ app1_tomcatClient.switchMessagingType( getMessagingType());
+ this.clients.add( app1_tomcatClient );
+
+ // OK, deploy and start all.
+ // Verify everything works
+ app1_tomcatClient.requestExportsFromOtherAgents( app1.getTomcat());
+ Thread.sleep( getDelay());
+ Assert.assertEquals( 0, app1_tomcatMessages.size());
+ Assert.assertEquals( 0, app2_mysqlMessages.size());
+
+ // Now, start the (external) MySQL, the one in app2.
+ app2_mysqlClient.listenToRequestsFromOtherAgents( ListenerCommand.START, app2.getMySql());
+ app1_tomcatClient.requestExportsFromOtherAgents( app1.getTomcat());
+ Thread.sleep( getDelay());
+
+ Assert.assertEquals( 0, app1_tomcatMessages.size());
+ Assert.assertEquals( 1, app2_mysqlMessages.size());
+
+ Assert.assertEquals( MsgCmdRequestImport.class, app2_mysqlMessages.get( 0 ).getClass());
+ MsgCmdRequestImport msg1 = (MsgCmdRequestImport) app2_mysqlMessages.get( 0 );
+ Assert.assertEquals( "tpl2", msg1.getComponentOrFacetName());
+
+ // Let's check exports with Tomcat listening...
+ app1_tomcatClient.listenToExportsFromOtherAgents( ListenerCommand.START, app1.getTomcat());
+ app2_mysqlClient.publishExports( app2.getMySql());
+ Thread.sleep( getDelay());
+
+ Assert.assertEquals( 1, app2_mysqlMessages.size());
+ Assert.assertEquals( 1, app1_tomcatMessages.size());
+
+ Assert.assertEquals( MsgCmdAddImport.class, app1_tomcatMessages.get( 0 ).getClass());
+ MsgCmdAddImport msg2 = (MsgCmdAddImport) app1_tomcatMessages.get( 0 );
+ Assert.assertEquals( "tpl2", msg2.getComponentOrFacetName());
+ Assert.assertEquals( "app2", msg2.getApplicationOrContextName());
+ Assert.assertEquals( InstanceHelpers.computeInstancePath( app2.getMySql()), msg2.getAddedInstancePath());
+ Assert.assertEquals( 2, msg2.getExportedVariables().size());
+ Assert.assertEquals( "3306", msg2.getExportedVariables().get( "tpl2.ext-port" ));
+ Assert.assertTrue( msg2.getExportedVariables().containsKey( "tpl2.ext-ip" ));
+
+ // What happens if we ask to only publish an external variable?
+ app2_mysqlClient.publishExports( app2.getMySql(), "tpl2" );
+ Thread.sleep( getDelay());
+
+ Assert.assertEquals( 1, app2_mysqlMessages.size());
+ Assert.assertEquals( 2, app1_tomcatMessages.size());
+
+ Assert.assertEquals( MsgCmdAddImport.class, app1_tomcatMessages.get( 1 ).getClass());
+ msg2 = (MsgCmdAddImport) app1_tomcatMessages.get( 1 );
+ Assert.assertEquals( "tpl2", msg2.getComponentOrFacetName());
+ Assert.assertEquals( "app2", msg2.getApplicationOrContextName());
+ Assert.assertEquals( InstanceHelpers.computeInstancePath( app2.getMySql()), msg2.getAddedInstancePath());
+ Assert.assertEquals( 2, msg2.getExportedVariables().size());
+ Assert.assertEquals( "3306", msg2.getExportedVariables().get( "tpl2.ext-port" ));
+ Assert.assertTrue( msg2.getExportedVariables().containsKey( "tpl2.ext-ip" ));
+
+ // Now, let's simulate the MySQL instance being stopped.
+ // We directly invoke the DM client to propagate the information.
+ dmClient.propagateAgentTermination( app2, app2.getMySqlVm());
+ Thread.sleep( getDelay());
+
+ // The Tomcat should have received a notification because one of its dependencies disappeared.
+ Assert.assertEquals( 3, app1_tomcatMessages.size());
+ Assert.assertEquals( MsgCmdRemoveImport.class, app1_tomcatMessages.get( 2 ).getClass());
+ MsgCmdRemoveImport msg3 = (MsgCmdRemoveImport) app1_tomcatMessages.get( 2 );
+ Assert.assertEquals( "tpl2", msg3.getComponentOrFacetName());
+ Assert.assertEquals( "/mysql-vm/mysql-server", msg3.getRemovedInstancePath());
+ Assert.assertEquals( "app2", msg3.getApplicationOrContextName());
+ }
+
+
+ protected AbstractMessageProcessor createDmProcessor( final List dmMessages ) {
+
+ return new AbstractMessageProcessor( "DM Processor - Test" ) {
+ @Override
+ protected void processMessage( Message message ) {
+ dmMessages.add( message );
+ }
+ };
+ }
+
+
+ protected AbstractMessageProcessor createAgentProcessor( final List agentMessages ) {
+
+ return new AbstractMessageProcessor( "Agent Processor - Test" ) {
+ @Override
+ protected void processMessage( Message message ) {
+ agentMessages.add( message );
+ }
+ };
+ }
+
+
protected abstract String getMessagingType();
}
diff --git a/core/roboconf-messaging-api/src/test/java/net/roboconf/messaging/api/internal/client/dismiss/DismissClientsTest.java b/core/roboconf-messaging-api/src/test/java/net/roboconf/messaging/api/internal/client/dismiss/DismissClientsTest.java
index 30d0df0e..a50b89ff 100644
--- a/core/roboconf-messaging-api/src/test/java/net/roboconf/messaging/api/internal/client/dismiss/DismissClientsTest.java
+++ b/core/roboconf-messaging-api/src/test/java/net/roboconf/messaging/api/internal/client/dismiss/DismissClientsTest.java
@@ -25,10 +25,7 @@
package net.roboconf.messaging.api.internal.client.dismiss;
-import java.util.HashMap;
-
-import junit.framework.Assert;
-import net.roboconf.messaging.api.client.ListenerCommand;
+import org.junit.Assert;
import org.junit.Test;
@@ -38,45 +35,19 @@
public class DismissClientsTest {
@Test
- public void testDm() throws Exception {
+ public void testAll() throws Exception {
- DismissClientDm client = new DismissClientDm();
+ DismissClient client = new DismissClient();
client.closeConnection();
client.deleteMessagingServerArtifacts( null );
Assert.assertFalse( client.isConnected());
- client.listenToAgentMessages( null, ListenerCommand.START );;
- client.openConnection();
- client.propagateAgentTermination( null, null );
- client.sendMessageToAgent( null, null, null );
- client.sendMessageToTheDm( null );
- client.listenToTheDm( ListenerCommand.START );
- client.setMessageQueue( null );
- client.getMessagingType();
- client.getConfiguration();
- }
-
-
- @Test
- public void testAgent() throws Exception {
-
- DismissClientAgent client = new DismissClientAgent();
- client.closeConnection();
- Assert.assertFalse( client.isConnected());
+ client.subscribe( null );
client.openConnection();
+ client.unsubscribe( null );
+ client.publish( null, null );
+ client.deleteMessagingServerArtifacts( null );
client.setMessageQueue( null );
- client.listenToExportsFromOtherAgents( ListenerCommand.STOP, null );
- client.listenToRequestsFromOtherAgents( ListenerCommand.STOP, null );
- client.listenToTheDm( ListenerCommand.START );
- client.publishExports( null );
- client.publishExports( null, "" );
- client.requestExportsFromOtherAgents( null );
- client.setScopedInstancePath( "/root" );
- client.setApplicationName( "app" );
- client.sendMessageToTheDm( null );
- client.unpublishExports( null );
client.getMessagingType();
- client.setExternalMapping( null );
client.getConfiguration();
- client.setExternalMapping( new HashMap( 0 ));
}
}
diff --git a/core/roboconf-messaging-api/src/test/java/net/roboconf/messaging/api/internal/client/in_memory/InMemoryClientFactoryTest.java b/core/roboconf-messaging-api/src/test/java/net/roboconf/messaging/api/internal/client/in_memory/InMemoryClientFactoryTest.java
new file mode 100644
index 00000000..59397428
--- /dev/null
+++ b/core/roboconf-messaging-api/src/test/java/net/roboconf/messaging/api/internal/client/in_memory/InMemoryClientFactoryTest.java
@@ -0,0 +1,60 @@
+/**
+ * Copyright 2015 Linagora, Université Joseph Fourier, Floralis
+ *
+ * The present code is developed in the scope of the joint LINAGORA -
+ * Université Joseph Fourier - Floralis research program and is designated
+ * as a "Result" pursuant to the terms and conditions of the LINAGORA
+ * - Université Joseph Fourier - Floralis research program. Each copyright
+ * holder of Results enumerated here above fully & independently holds complete
+ * ownership of the complete Intellectual Property rights applicable to the whole
+ * of said Results, and may freely exploit it in any manner which does not infringe
+ * the moral rights of the other copyright holders.
+ *
+ * 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.
+ */
+
+package net.roboconf.messaging.api.internal.client.in_memory;
+
+import java.util.HashMap;
+
+import net.roboconf.messaging.api.MessagingConstants;
+import net.roboconf.messaging.api.extensions.IMessagingClient;
+import net.roboconf.messaging.api.reconfigurables.ReconfigurableClientAgent;
+import net.roboconf.messaging.api.reconfigurables.ReconfigurableClientDm;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+/**
+ * @author Vincent Zurczak - Linagora
+ */
+public class InMemoryClientFactoryTest {
+
+ @Test
+ public void testBasics() {
+
+ InMemoryClientFactory factory = new InMemoryClientFactory();
+ Assert.assertEquals( MessagingConstants.FACTORY_IN_MEMORY, factory.getType());
+ factory.setConfiguration( new HashMap( 0 ));
+
+ ReconfigurableClientDm parentDm = new ReconfigurableClientDm();
+ IMessagingClient client = factory.createClient( parentDm );
+ Assert.assertEquals( InMemoryClient.class, client.getClass());
+ Assert.assertEquals( "@DM@", ((InMemoryClient) client).getOwnerId());
+
+ ReconfigurableClientAgent parentAgent = new ReconfigurableClientAgent();
+ client = factory.createClient( parentAgent );
+ Assert.assertEquals( InMemoryClient.class, client.getClass());
+ Assert.assertEquals( "", ((InMemoryClient) client).getOwnerId());
+ }
+}
diff --git a/core/roboconf-messaging-api/src/test/java/net/roboconf/messaging/api/internal/client/in_memory/InMemoryClientTest.java b/core/roboconf-messaging-api/src/test/java/net/roboconf/messaging/api/internal/client/in_memory/InMemoryClientTest.java
new file mode 100644
index 00000000..23b2b0ae
--- /dev/null
+++ b/core/roboconf-messaging-api/src/test/java/net/roboconf/messaging/api/internal/client/in_memory/InMemoryClientTest.java
@@ -0,0 +1,204 @@
+/**
+ * Copyright 2015 Linagora, Université Joseph Fourier, Floralis
+ *
+ * The present code is developed in the scope of the joint LINAGORA -
+ * Université Joseph Fourier - Floralis research program and is designated
+ * as a "Result" pursuant to the terms and conditions of the LINAGORA
+ * - Université Joseph Fourier - Floralis research program. Each copyright
+ * holder of Results enumerated here above fully & independently holds complete
+ * ownership of the complete Intellectual Property rights applicable to the whole
+ * of said Results, and may freely exploit it in any manner which does not infringe
+ * the moral rights of the other copyright holders.
+ *
+ * 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.
+ */
+
+package net.roboconf.messaging.api.internal.client.in_memory;
+
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.LinkedBlockingQueue;
+
+import net.roboconf.core.model.beans.Instance;
+import net.roboconf.messaging.api.MessagingConstants;
+import net.roboconf.messaging.api.extensions.MessagingContext;
+import net.roboconf.messaging.api.extensions.MessagingContext.RecipientKind;
+import net.roboconf.messaging.api.internal.client.in_memory.InMemoryClient.InMemoryRoutingContext;
+import net.roboconf.messaging.api.messages.Message;
+import net.roboconf.messaging.api.messages.from_dm_to_agent.MsgCmdAddInstance;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+/**
+ * @author Vincent Zurczak - Linagora
+ */
+public class InMemoryClientTest {
+
+ @Test
+ public void testGetMessagingType() {
+
+ InMemoryClient client = new InMemoryClient( new InMemoryRoutingContext(), RecipientKind.DM );
+ Assert.assertEquals( MessagingConstants.FACTORY_IN_MEMORY, client.getMessagingType());
+ }
+
+
+ @Test
+ public void testGetConfiguration() {
+
+ InMemoryClient client = new InMemoryClient( new InMemoryRoutingContext(), RecipientKind.DM );
+ Map conf = client.getConfiguration();
+
+ Assert.assertEquals( 1, conf.size());
+ Assert.assertEquals( MessagingConstants.FACTORY_IN_MEMORY, conf.get( MessagingConstants.MESSAGING_TYPE_PROPERTY ));
+ }
+
+
+ @Test
+ public void testScenarios_subscriptions() throws Exception {
+
+ InMemoryClient client = new InMemoryClient( new InMemoryRoutingContext(), RecipientKind.DM );
+ MessagingContext ctx = new MessagingContext( RecipientKind.AGENTS, "app" );
+
+ // Not connected, subscriptions cannot work
+ Assert.assertFalse( client.isConnected());
+ Assert.assertNull( getSubscriptions( client ));
+ client.subscribe( ctx );
+ Assert.assertNull( getSubscriptions( client ));
+ client.unsubscribe( ctx );
+ Assert.assertNull( getSubscriptions( client ));
+
+ // Connection
+ client.openConnection();
+ Assert.assertTrue( client.isConnected());
+ client.subscribe( ctx );
+ Assert.assertEquals( 1, getSubscriptions( client ).size());
+ Assert.assertTrue( getSubscriptions( client ).contains( ctx ));
+
+ client.unsubscribe( ctx );
+ Assert.assertNull( getSubscriptions( client ));
+
+ client.unsubscribe( ctx );
+ client.unsubscribe( null );
+ Assert.assertNull( getSubscriptions( client ));
+
+ // Cleaning artifacts
+ client.subscribe( ctx );
+ Assert.assertEquals( 1, getSubscriptions( client ).size());
+
+ client.deleteMessagingServerArtifacts( null );
+ Assert.assertNull( getSubscriptions( client ));
+ }
+
+
+ @Test
+ public void testScenarios_publications() throws Exception {
+
+ InMemoryClient client = new InMemoryClient( new InMemoryRoutingContext(), RecipientKind.DM );
+ LinkedBlockingQueue queue = new LinkedBlockingQueue ();
+ client.setMessageQueue( queue );
+
+ MessagingContext ctx = new MessagingContext( RecipientKind.AGENTS, "app" );
+
+ // Not connected, publications cannot work
+ Message msg = new MsgCmdAddInstance( new Instance( "" ));
+
+ Assert.assertFalse( client.isConnected());
+ Assert.assertEquals( 0, queue.size());
+ client.publish( ctx, msg );
+ Assert.assertEquals( 0, queue.size());
+
+ // Connection
+ client.openConnection();
+ Assert.assertTrue( client.isConnected());
+ client.publish( ctx, msg );
+ Assert.assertEquals( 0, queue.size());
+
+ // We need to subscribe to this context to dispatch the message.
+ // The messaging tests verify routing more precisely.
+ client.subscribe( ctx );
+ client.publish( ctx, msg );
+
+ Assert.assertEquals( 1, queue.size());
+ Assert.assertEquals( msg, queue.element());
+ }
+
+
+ @Test
+ public void testSetOwnerProperties_ownerId() {
+
+ Set ownerIds = new HashSet<> ();
+
+ InMemoryClient client = new InMemoryClient( new InMemoryRoutingContext(), RecipientKind.DM );
+ client.setOwnerProperties( RecipientKind.DM, null, null );
+ ownerIds.add( client.getOwnerId());
+
+ client.setOwnerProperties( RecipientKind.AGENTS, "app1", "root1" );
+ ownerIds.add( client.getOwnerId());
+
+ client.setOwnerProperties( RecipientKind.AGENTS, "app1", "root2" );
+ ownerIds.add( client.getOwnerId());
+
+ client.setOwnerProperties( RecipientKind.AGENTS, "app2", "root2" );
+ ownerIds.add( client.getOwnerId());
+
+ Assert.assertEquals( 4, ownerIds.size());
+ }
+
+
+ @Test
+ public void testSetOwnerProperties_propertiesAreMoved() throws Exception {
+
+ // Init...
+ InMemoryClient client = new InMemoryClient( new InMemoryRoutingContext(), RecipientKind.DM );
+ LinkedBlockingQueue queue = new LinkedBlockingQueue ();
+ client.setMessageQueue( queue );
+ client.openConnection();
+
+ MessagingContext ctx = new MessagingContext( RecipientKind.AGENTS, "app" );
+ client.subscribe( ctx );
+ String ownerId_1 = client.getOwnerId();
+
+ // Verify associations
+ Map> sub = client.getRoutingContext().subscriptions;
+ Map> ctxToQueue = ((InMemoryRoutingContext) client.getRoutingContext()).ctxToQueue;
+ Assert.assertEquals( queue, ctxToQueue.get( ownerId_1 ));
+
+ Set subscribedContexts = sub.get( ownerId_1 );
+ Assert.assertNotNull( subscribedContexts );
+ Assert.assertEquals( 1, subscribedContexts.size());
+ Assert.assertTrue( subscribedContexts.contains( ctx ));
+
+ // Change the owner ID
+ client.setOwnerProperties( RecipientKind.AGENTS, "app1", "root1" );
+
+ // Verify properties were kept
+ String ownerId_2 = client.getOwnerId();
+ Assert.assertFalse( ownerId_2.equals( ownerId_1 ));
+
+ Assert.assertEquals( queue, ctxToQueue.get( ownerId_2 ));
+ Assert.assertNull( ctxToQueue.get( ownerId_1 ));
+ Assert.assertNull( sub.get( ownerId_1 ));
+
+ subscribedContexts = sub.get( ownerId_2 );
+ Assert.assertNotNull( subscribedContexts );
+ Assert.assertEquals( 1, subscribedContexts.size());
+ Assert.assertTrue( subscribedContexts.contains( ctx ));
+ }
+
+
+ private Set getSubscriptions( InMemoryClient client ) {
+ return client.getRoutingContext().subscriptions.get( client.getOwnerId());
+ }
+}
diff --git a/core/roboconf-messaging-api/src/test/java/net/roboconf/messaging/api/internal/client/in_memory/InMemoryMessagingTest.java b/core/roboconf-messaging-api/src/test/java/net/roboconf/messaging/api/internal/client/in_memory/InMemoryMessagingTest.java
new file mode 100644
index 00000000..f959d0be
--- /dev/null
+++ b/core/roboconf-messaging-api/src/test/java/net/roboconf/messaging/api/internal/client/in_memory/InMemoryMessagingTest.java
@@ -0,0 +1,123 @@
+/**
+ * Copyright 2015 Linagora, Université Joseph Fourier, Floralis
+ *
+ * The present code is developed in the scope of the joint LINAGORA -
+ * Université Joseph Fourier - Floralis research program and is designated
+ * as a "Result" pursuant to the terms and conditions of the LINAGORA
+ * - Université Joseph Fourier - Floralis research program. Each copyright
+ * holder of Results enumerated here above fully & independently holds complete
+ * ownership of the complete Intellectual Property rights applicable to the whole
+ * of said Results, and may freely exploit it in any manner which does not infringe
+ * the moral rights of the other copyright holders.
+ *
+ * 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.
+ */
+
+package net.roboconf.messaging.api.internal.client.in_memory;
+
+import net.roboconf.messaging.api.MessagingConstants;
+import net.roboconf.messaging.api.factory.MessagingClientFactoryRegistry;
+import net.roboconf.messaging.api.internal.client.AbstractMessagingTest;
+
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * @author Vincent Zurczak - Linagora
+ */
+public class InMemoryMessagingTest extends AbstractMessagingTest {
+
+
+ @Before
+ public void registerRabbitMqFactory() {
+
+ this.registry = new MessagingClientFactoryRegistry();
+ this.registry.addMessagingClientFactory( new InMemoryClientFactory());
+ }
+
+
+ @Override
+ protected long getDelay() {
+ return 10;
+ }
+
+
+ @Test
+ @Override
+ public void testDmDebug() throws Exception {
+ super.testDmDebug();
+ }
+
+
+ @Test
+ @Override
+ public void testExchangesBetweenTheDmAndOneAgent() throws Exception {
+ super.testExchangesBetweenTheDmAndOneAgent();
+ }
+
+
+ @Test
+ @Override
+ public void testExchangesBetweenTheDmAndThreeAgents() throws Exception {
+ super.testExchangesBetweenTheDmAndThreeAgents();
+ }
+
+
+ @Test
+ @Override
+ public void testExportsBetweenAgents() throws Exception {
+ super.testExportsBetweenAgents();
+ }
+
+
+ @Test
+ @Override
+ public void testExportsBetweenSiblingAgents() throws Exception {
+ super.testExportsBetweenSiblingAgents();
+ }
+
+
+ @Test
+ @Override
+ public void testExportsRequestsBetweenAgents() throws Exception {
+ super.testExportsRequestsBetweenAgents();
+ }
+
+
+ @Test
+ @Override
+ public void testExternalExports_withTwoApplications() throws Exception {
+ super.testExternalExports_withTwoApplications();
+ }
+
+
+ @Test
+ @Override
+ public void testPropagateAgentTermination() throws Exception {
+ super.testPropagateAgentTermination();
+ }
+
+
+ @Test
+ @Override
+ public void testExternalExports_twoApplicationsAndTheDm_verifyAgentTerminationPropagation()
+ throws Exception {
+ super.testExternalExports_twoApplicationsAndTheDm_verifyAgentTerminationPropagation();
+ }
+
+
+ @Override
+ protected String getMessagingType() {
+ return MessagingConstants.FACTORY_IN_MEMORY;
+ }
+}
diff --git a/core/roboconf-messaging-api/src/test/java/net/roboconf/messaging/api/internal/client/test/TestClientAgentTest.java b/core/roboconf-messaging-api/src/test/java/net/roboconf/messaging/api/internal/client/test/TestClientAgentTest.java
deleted file mode 100644
index fb6de11c..00000000
--- a/core/roboconf-messaging-api/src/test/java/net/roboconf/messaging/api/internal/client/test/TestClientAgentTest.java
+++ /dev/null
@@ -1,156 +0,0 @@
-/**
- * Copyright 2014-2015 Linagora, Université Joseph Fourier, Floralis
- *
- * The present code is developed in the scope of the joint LINAGORA -
- * Université Joseph Fourier - Floralis research program and is designated
- * as a "Result" pursuant to the terms and conditions of the LINAGORA
- * - Université Joseph Fourier - Floralis research program. Each copyright
- * holder of Results enumerated here above fully & independently holds complete
- * ownership of the complete Intellectual Property rights applicable to the whole
- * of said Results, and may freely exploit it in any manner which does not infringe
- * the moral rights of the other copyright holders.
- *
- * 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.
- */
-
-package net.roboconf.messaging.api.internal.client.test;
-
-import java.io.IOException;
-import java.util.Map;
-
-import junit.framework.Assert;
-import net.roboconf.core.model.beans.Instance;
-import net.roboconf.messaging.api.MessagingConstants;
-import net.roboconf.messaging.api.client.ListenerCommand;
-import net.roboconf.messaging.api.messages.from_agent_to_dm.MsgNotifMachineDown;
-
-import org.junit.Test;
-
-/**
- * @author Vincent Zurczak - Linagora
- */
-public class TestClientAgentTest {
-
- @Test
- public void testConnectAndDisconnect() throws Exception {
-
- TestClientAgent client = new TestClientAgent();
- Assert.assertFalse( client.isConnected());
-
- client.openConnection();
- Assert.assertTrue( client.isConnected());
-
- client.closeConnection();
- Assert.assertFalse( client.isConnected());
- }
-
-
- @Test
- public void testGetConfiguration() throws Exception {
-
- TestClientDm client = new TestClientDm();
-
- final Map config = client.getConfiguration();
- Assert.assertEquals(1, config.size());
- Assert.assertEquals(MessagingConstants.TEST_FACTORY_TYPE, config.get(MessagingConstants.MESSAGING_TYPE_PROPERTY));
- }
-
-
- @Test
- public void testSend_noException() throws Exception {
-
- TestClientAgent client = new TestClientAgent();
- Assert.assertEquals( 0, client.messagesForAgentsCount.get());
-
- client.publishExports( new Instance( "whatever" ));
- Assert.assertEquals( 1, client.messagesForAgentsCount.get());
-
- client.publishExports( new Instance( "whatever" ), "facet" );
- Assert.assertEquals( 2, client.messagesForAgentsCount.get());
-
- client.unpublishExports( new Instance( "whatever" ));
- Assert.assertEquals( 3, client.messagesForAgentsCount.get());
-
- client.requestExportsFromOtherAgents( new Instance( "something" ));
- Assert.assertEquals( 4, client.messagesForAgentsCount.get());
-
- Assert.assertEquals( 0, client.messagesForTheDm.size());
- client.sendMessageToTheDm( new MsgNotifMachineDown( "app", "root" ));
- Assert.assertEquals( 1, client.messagesForTheDm.size());
- }
-
-
- @Test( expected = IOException.class )
- public void testSendToDm_exception() throws Exception {
-
- TestClientAgent client = new TestClientAgent();
- client.failMessageSending.set( true );
- client.sendMessageToTheDm( new MsgNotifMachineDown( "app", "root" ));
- }
-
-
- @Test( expected = IOException.class )
- public void testSendToAgent_exception_1() throws Exception {
-
- TestClientAgent client = new TestClientAgent();
- client.failMessageSending.set( true );
- client.requestExportsFromOtherAgents( new Instance( "something" ));
- }
-
-
- @Test( expected = IOException.class )
- public void testSendToAgent_exception_2() throws Exception {
-
- TestClientAgent client = new TestClientAgent();
- client.failMessageSending.set( true );
- client.unpublishExports( new Instance( "whatever" ));
- }
-
-
- @Test( expected = IOException.class )
- public void testSendToAgent_exception_3() throws Exception {
-
- TestClientAgent client = new TestClientAgent();
- client.failMessageSending.set( true );
- client.publishExports( new Instance( "whatever" ));
- }
-
-
- @Test( expected = IOException.class )
- public void testSendToAgent_exception_4() throws Exception {
-
- TestClientAgent client = new TestClientAgent();
- client.failMessageSending.set( true );
- client.publishExports( new Instance( "whatever" ), "facet" );
- }
-
-
- @Test
- public void forCodeCoverageOnly() throws Exception {
-
- TestClientAgent client = new TestClientAgent();
- client.listenToExportsFromOtherAgents( ListenerCommand.START, new Instance( "hop" ));
- client.listenToExportsFromOtherAgents( ListenerCommand.STOP, new Instance( "hop" ));
-
- client.listenToRequestsFromOtherAgents( ListenerCommand.START, new Instance( "hop" ));
- client.listenToRequestsFromOtherAgents( ListenerCommand.STOP, new Instance( "hop" ));
-
- client.listenToTheDm( ListenerCommand.START );
- client.listenToTheDm( ListenerCommand.STOP );
-
- Assert.assertEquals( MessagingConstants.TEST_FACTORY_TYPE, client.getMessagingType());
- Map conf = client.getConfiguration();
- Assert.assertEquals( 1, conf.size());
- Assert.assertEquals( MessagingConstants.TEST_FACTORY_TYPE, conf.get( MessagingConstants.MESSAGING_TYPE_PROPERTY ));
- }
-}
diff --git a/core/roboconf-messaging-api/src/test/java/net/roboconf/messaging/api/internal/client/test/TestClientDmTest.java b/core/roboconf-messaging-api/src/test/java/net/roboconf/messaging/api/internal/client/test/TestClientDmTest.java
deleted file mode 100644
index 6e13f1f0..00000000
--- a/core/roboconf-messaging-api/src/test/java/net/roboconf/messaging/api/internal/client/test/TestClientDmTest.java
+++ /dev/null
@@ -1,153 +0,0 @@
-/**
- * Copyright 2014-2015 Linagora, Université Joseph Fourier, Floralis
- *
- * The present code is developed in the scope of the joint LINAGORA -
- * Université Joseph Fourier - Floralis research program and is designated
- * as a "Result" pursuant to the terms and conditions of the LINAGORA
- * - Université Joseph Fourier - Floralis research program. Each copyright
- * holder of Results enumerated here above fully & independently holds complete
- * ownership of the complete Intellectual Property rights applicable to the whole
- * of said Results, and may freely exploit it in any manner which does not infringe
- * the moral rights of the other copyright holders.
- *
- * 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.
- */
-
-package net.roboconf.messaging.api.internal.client.test;
-
-import java.io.IOException;
-import java.util.Map;
-
-import junit.framework.Assert;
-import net.roboconf.core.model.beans.Application;
-import net.roboconf.core.model.beans.Instance;
-import net.roboconf.messaging.api.MessagingConstants;
-import net.roboconf.messaging.api.client.ListenerCommand;
-import net.roboconf.messaging.api.messages.from_dm_to_agent.MsgCmdResynchronize;
-import net.roboconf.messaging.api.messages.from_dm_to_dm.MsgEcho;
-
-import org.junit.Test;
-
-/**
- * @author Vincent Zurczak - Linagora
- */
-public class TestClientDmTest {
-
- @Test
- public void testConnectAndDisconnect() throws Exception {
-
- TestClientDm client = new TestClientDm();
- Assert.assertFalse( client.isConnected());
-
- client.openConnection();
- Assert.assertTrue( client.isConnected());
-
- client.closeConnection();
- Assert.assertFalse( client.isConnected());
- }
-
-
- @Test
- public void testGetConfiguration() throws Exception {
-
- TestClientDm client = new TestClientDm();
-
- final Map config = client.getConfiguration();
- Assert.assertEquals(1, config.size());
- Assert.assertEquals(MessagingConstants.TEST_FACTORY_TYPE, config.get(MessagingConstants.MESSAGING_TYPE_PROPERTY));
- }
-
-
- @Test
- public void testSend_noException() throws Exception {
-
- TestClientDm client = new TestClientDm();
- Assert.assertEquals( 0, client.sentMessages.size());
-
- client.sendMessageToAgent( new Application( "app", null ), new Instance( "whatever" ), new MsgCmdResynchronize());
- Assert.assertEquals( 1, client.sentMessages.size());
-
- client.sendMessageToAgent( new Application( "app-2", null ), new Instance( "whatever" ), new MsgCmdResynchronize());
- Assert.assertEquals( 2, client.sentMessages.size());
- }
-
-
- @Test( expected = IOException.class )
- public void testSend_withException() throws Exception {
-
- TestClientDm client = new TestClientDm();
- client.failMessageSending.set( true );
- client.sendMessageToAgent( new Application( "app", null ), new Instance( "whatever" ), new MsgCmdResynchronize());
- }
-
-
- @Test
- public void testSendToDebug_noException() throws Exception {
-
- TestClientDm client = new TestClientDm();
- Assert.assertEquals( 0, client.sentMessages.size());
-
- client.sendMessageToTheDm( new MsgEcho( "hello" ));
- Assert.assertEquals( 1, client.sentMessages.size());
-
- client.sendMessageToTheDm( new MsgEcho( "hello 2" ));
- Assert.assertEquals( 2, client.sentMessages.size());
- }
-
-
- @Test( expected = IOException.class )
- public void testSendToDebug_withException() throws Exception {
-
- TestClientDm client = new TestClientDm();
- client.failMessageSending.set( true );
- client.sendMessageToTheDm( new MsgEcho( "hello" ));
- }
-
-
- @Test( expected = IOException.class )
- public void testCloseConnection_withException() throws Exception {
-
- TestClientDm client = new TestClientDm();
- client.failClosingConnection.set( true );
- client.closeConnection();
- }
-
-
- @Test( expected = IOException.class )
- public void testListeningToTheDm_withException() throws Exception {
-
- TestClientDm client = new TestClientDm();
- client.failListeningToTheDm.set( true );
- client.listenToTheDm( ListenerCommand.START );
- }
-
-
- @Test
- public void forCodeCoverageOnly() throws Exception {
-
- TestClientDm client = new TestClientDm();
- client.propagateAgentTermination( new Application( null ), new Instance());
- client.deleteMessagingServerArtifacts( new Application( "whatever", null ));
-
- client.listenToAgentMessages( new Application( "app", null ), ListenerCommand.START );
- client.listenToAgentMessages( new Application( "app", null ), ListenerCommand.STOP );
-
- client.listenToTheDm( ListenerCommand.START );
- client.listenToTheDm( ListenerCommand.STOP );
-
- Assert.assertEquals( MessagingConstants.TEST_FACTORY_TYPE, client.getMessagingType());
- Map conf = client.getConfiguration();
- Assert.assertEquals( 1, conf.size());
- Assert.assertEquals( MessagingConstants.TEST_FACTORY_TYPE, conf.get( MessagingConstants.MESSAGING_TYPE_PROPERTY ));
- }
-}
diff --git a/core/roboconf-messaging-api/src/test/java/net/roboconf/messaging/api/internal/client/test/TestClientFactoryTest.java b/core/roboconf-messaging-api/src/test/java/net/roboconf/messaging/api/internal/client/test/TestClientFactoryTest.java
index ac1e6fc8..ba041e7c 100644
--- a/core/roboconf-messaging-api/src/test/java/net/roboconf/messaging/api/internal/client/test/TestClientFactoryTest.java
+++ b/core/roboconf-messaging-api/src/test/java/net/roboconf/messaging/api/internal/client/test/TestClientFactoryTest.java
@@ -27,9 +27,8 @@
import java.util.HashMap;
-import junit.framework.Assert;
+import org.junit.Assert;
import net.roboconf.messaging.api.MessagingConstants;
-import net.roboconf.messaging.api.reconfigurables.ReconfigurableClientAgent;
import net.roboconf.messaging.api.reconfigurables.ReconfigurableClientDm;
import org.junit.Test;
@@ -43,13 +42,10 @@ public class TestClientFactoryTest {
public void testBasics() {
TestClientFactory factory = new TestClientFactory();
- Assert.assertEquals( MessagingConstants.TEST_FACTORY_TYPE, factory.getType());
+ Assert.assertEquals( MessagingConstants.FACTORY_TEST, factory.getType());
factory.setConfiguration( new HashMap( 0 ));
ReconfigurableClientDm parentDm = new ReconfigurableClientDm();
- Assert.assertEquals( TestClientDm.class, factory.createDmClient( parentDm ).getClass());
-
- ReconfigurableClientAgent parentAgent = new ReconfigurableClientAgent();
- Assert.assertEquals( TestClientAgent.class, factory.createAgentClient( parentAgent ).getClass());
+ Assert.assertEquals( TestClient.class, factory.createClient( parentDm ).getClass());
}
}
diff --git a/core/roboconf-messaging-api/src/test/java/net/roboconf/messaging/api/internal/client/test/TestClientTest.java b/core/roboconf-messaging-api/src/test/java/net/roboconf/messaging/api/internal/client/test/TestClientTest.java
new file mode 100644
index 00000000..c9e4c0a8
--- /dev/null
+++ b/core/roboconf-messaging-api/src/test/java/net/roboconf/messaging/api/internal/client/test/TestClientTest.java
@@ -0,0 +1,176 @@
+/**
+ * Copyright 2014-2015 Linagora, Université Joseph Fourier, Floralis
+ *
+ * The present code is developed in the scope of the joint LINAGORA -
+ * Université Joseph Fourier - Floralis research program and is designated
+ * as a "Result" pursuant to the terms and conditions of the LINAGORA
+ * - Université Joseph Fourier - Floralis research program. Each copyright
+ * holder of Results enumerated here above fully & independently holds complete
+ * ownership of the complete Intellectual Property rights applicable to the whole
+ * of said Results, and may freely exploit it in any manner which does not infringe
+ * the moral rights of the other copyright holders.
+ *
+ * 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.
+ */
+
+package net.roboconf.messaging.api.internal.client.test;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import net.roboconf.messaging.api.MessagingConstants;
+import net.roboconf.messaging.api.extensions.MessagingContext;
+import net.roboconf.messaging.api.extensions.MessagingContext.RecipientKind;
+import net.roboconf.messaging.api.messages.Message;
+import net.roboconf.messaging.api.messages.from_dm_to_agent.MsgCmdChangeBinding;
+import net.roboconf.messaging.api.messages.from_dm_to_agent.MsgCmdRemoveInstance;
+import net.roboconf.messaging.api.messages.from_dm_to_agent.MsgCmdResynchronize;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+/**
+ * @author Vincent Zurczak - Linagora
+ */
+public class TestClientTest {
+
+ @Test
+ public void testConnectAndDisconnect() throws Exception {
+
+ TestClient client = new TestClient();
+ Assert.assertFalse( client.isConnected());
+
+ client.openConnection();
+ Assert.assertTrue( client.isConnected());
+
+ client.closeConnection();
+ Assert.assertFalse( client.isConnected());
+
+ client.deleteMessagingServerArtifacts( null );
+ }
+
+
+ @Test( expected = IOException.class )
+ public void testCloseConnection_exception() throws Exception {
+
+ TestClient client = new TestClient();
+ client.failClosingConnection.set( true );
+ client.closeConnection();
+ }
+
+
+ @Test
+ public void testGetMessagingType() {
+
+ TestClient client = new TestClient();
+ Assert.assertEquals( MessagingConstants.FACTORY_TEST, client.getMessagingType());
+ }
+
+
+ @Test
+ public void testGetConfiguration() throws Exception {
+
+ TestClient client = new TestClient();
+
+ final Map config = client.getConfiguration();
+ Assert.assertEquals(1, config.size());
+ Assert.assertEquals(MessagingConstants.FACTORY_TEST, config.get(MessagingConstants.MESSAGING_TYPE_PROPERTY));
+ }
+
+
+ @Test
+ public void testSubscriptions() throws Exception {
+
+ MessagingContext ctx1 = new MessagingContext( RecipientKind.DM, "app1" );
+ MessagingContext ctx2 = new MessagingContext( RecipientKind.AGENTS, "app2" );
+ MessagingContext ctx3 = new MessagingContext( RecipientKind.AGENTS, "app1" );
+
+ TestClient client = new TestClient();
+ client.subscribe( ctx1 );
+ client.subscribe( ctx2 );
+ client.subscribe( ctx3 );
+ client.subscribe( ctx1 );
+ Assert.assertEquals( 3, client.subscriptions.size());
+
+ client.unsubscribe( ctx1 );
+ Assert.assertEquals( 2, client.subscriptions.size());
+ }
+
+
+ @Test( expected = IOException.class )
+ public void testSubscriptions_exception() throws Exception {
+
+ TestClient client = new TestClient();
+ client.failSubscribing.set( true );
+ client.subscribe( new MessagingContext( RecipientKind.DM, "app1" ));
+ }
+
+
+ @Test
+ public void testPublish() throws Exception {
+
+ TestClient client = new TestClient();
+ MessagingContext ctx = new MessagingContext( RecipientKind.DM, "app1" );
+
+ Assert.assertEquals( 0, client.ctxToMessages.size());
+ client.publish( ctx, new MsgCmdChangeBinding( "prefix", "app" ));
+ client.publish( ctx, new MsgCmdChangeBinding( "prefix", "app" ));
+
+ Assert.assertEquals( 1, client.ctxToMessages.size());
+ List messages = client.ctxToMessages.get( ctx );
+
+ Assert.assertEquals( 2, client.messagesForTheDm.size());
+ Assert.assertEquals( 2, messages.size());
+ Assert.assertEquals( MsgCmdChangeBinding.class, messages.get( 0 ).getClass());
+ Assert.assertEquals( MsgCmdChangeBinding.class, messages.get( 1 ).getClass());
+
+ Assert.assertEquals( 0, client.messagesForAgents.size());
+ ctx = new MessagingContext( RecipientKind.AGENTS, "app1" );
+ client.publish( ctx, new MsgCmdResynchronize());
+
+ Assert.assertEquals( 1, client.messagesForAgents.size());
+ Assert.assertEquals( MsgCmdResynchronize.class, client.messagesForAgents.get( 0 ).getClass());
+ }
+
+
+ @Test( expected = IOException.class )
+ public void testPublish_exception() throws Exception {
+
+ TestClient client = new TestClient();
+ client.failMessageSending.set( true );
+ client.publish( null, null );
+ }
+
+
+ @Test
+ public void testClearMessages() {
+
+ TestClient client = new TestClient();
+
+ List messages = new ArrayList ();
+ messages.add( new MsgCmdRemoveInstance( "/root" ));
+ client.ctxToMessages.put( new MessagingContext( RecipientKind.DM, "app" ), messages );
+
+ client.messagesForAgents.add( new MsgCmdRemoveInstance( "/root1" ));
+ client.messagesForTheDm.add( new MsgCmdRemoveInstance( "/root2" ));
+ client.allSentMessages.add( new MsgCmdRemoveInstance( "/root2" ));
+
+ client.clearMessages();
+ Assert.assertEquals( 0, client.messagesForAgents.size());
+ Assert.assertEquals( 0, client.messagesForTheDm.size());
+ Assert.assertEquals( 0, client.ctxToMessages.size());
+ Assert.assertEquals( 0, client.allSentMessages.size());
+ }
+}
diff --git a/core/roboconf-messaging-api/src/test/java/net/roboconf/messaging/api/messages/MessageTest.java b/core/roboconf-messaging-api/src/test/java/net/roboconf/messaging/api/messages/MessageTest.java
new file mode 100644
index 00000000..52c6dd91
--- /dev/null
+++ b/core/roboconf-messaging-api/src/test/java/net/roboconf/messaging/api/messages/MessageTest.java
@@ -0,0 +1,48 @@
+/**
+ * Copyright 2015 Linagora, Université Joseph Fourier, Floralis
+ *
+ * The present code is developed in the scope of the joint LINAGORA -
+ * Université Joseph Fourier - Floralis research program and is designated
+ * as a "Result" pursuant to the terms and conditions of the LINAGORA
+ * - Université Joseph Fourier - Floralis research program. Each copyright
+ * holder of Results enumerated here above fully & independently holds complete
+ * ownership of the complete Intellectual Property rights applicable to the whole
+ * of said Results, and may freely exploit it in any manner which does not infringe
+ * the moral rights of the other copyright holders.
+ *
+ * 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.
+ */
+
+package net.roboconf.messaging.api.messages;
+
+import net.roboconf.messaging.api.messages.from_dm_to_agent.MsgCmdRemoveInstance;
+import net.roboconf.messaging.api.messages.from_dm_to_agent.MsgCmdResynchronize;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+/**
+ * @author Vincent Zurczak - Linagora
+ */
+public class MessageTest {
+
+ @Test
+ public void testToString() {
+
+ MsgCmdRemoveInstance msg1 = new MsgCmdRemoveInstance( "/path" );
+ Assert.assertEquals( "MsgCmdRemoveInstance", msg1.toString());
+
+ MsgCmdResynchronize msg2 = new MsgCmdResynchronize();
+ Assert.assertEquals( "MsgCmdResynchronize", msg2.toString());
+ }
+}
diff --git a/core/roboconf-messaging-api/src/test/java/net/roboconf/messaging/api/processors/AbstractMessageProcessorTest.java b/core/roboconf-messaging-api/src/test/java/net/roboconf/messaging/api/processors/AbstractMessageProcessorTest.java
index 72d55d33..5af3aa16 100644
--- a/core/roboconf-messaging-api/src/test/java/net/roboconf/messaging/api/processors/AbstractMessageProcessorTest.java
+++ b/core/roboconf-messaging-api/src/test/java/net/roboconf/messaging/api/processors/AbstractMessageProcessorTest.java
@@ -25,9 +25,10 @@
package net.roboconf.messaging.api.processors;
-import junit.framework.Assert;
+import org.junit.Assert;
+import net.roboconf.messaging.api.AbstractMessageProcessor;
import net.roboconf.messaging.api.MessagingConstants;
-import net.roboconf.messaging.api.client.IDmClient;
+import net.roboconf.messaging.api.business.IDmClient;
import net.roboconf.messaging.api.messages.Message;
import net.roboconf.messaging.api.messages.from_dm_to_agent.MsgCmdResynchronize;
@@ -108,7 +109,7 @@ public static class EmptyTestDmMessageProcessor extends AbstractMessageProcessor
* Constructor.
*/
public EmptyTestDmMessageProcessor() {
- super( MessagingConstants.TEST_FACTORY_TYPE);
+ super( MessagingConstants.FACTORY_TEST);
}
@Override
diff --git a/core/roboconf-messaging-api/src/test/java/net/roboconf/messaging/api/reconfigurables/ReconfigurableClientTest.java b/core/roboconf-messaging-api/src/test/java/net/roboconf/messaging/api/reconfigurables/ReconfigurableClientTest.java
index aeec3d4e..6c60243f 100644
--- a/core/roboconf-messaging-api/src/test/java/net/roboconf/messaging/api/reconfigurables/ReconfigurableClientTest.java
+++ b/core/roboconf-messaging-api/src/test/java/net/roboconf/messaging/api/reconfigurables/ReconfigurableClientTest.java
@@ -27,22 +27,24 @@
import java.io.IOException;
import java.util.Map;
+import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.LinkedBlockingQueue;
+import net.roboconf.core.internal.tests.TestUtils;
import net.roboconf.core.model.beans.Application;
import net.roboconf.core.model.beans.ApplicationTemplate;
+import net.roboconf.messaging.api.AbstractMessageProcessor;
import net.roboconf.messaging.api.MessagingConstants;
-import net.roboconf.messaging.api.client.IAgentClient;
-import net.roboconf.messaging.api.client.IDmClient;
+import net.roboconf.messaging.api.business.IAgentClient;
+import net.roboconf.messaging.api.business.IDmClient;
+import net.roboconf.messaging.api.extensions.IMessagingClient;
import net.roboconf.messaging.api.factory.IMessagingClientFactory;
import net.roboconf.messaging.api.factory.MessagingClientFactoryRegistry;
-import net.roboconf.messaging.api.internal.client.dismiss.DismissClientAgent;
-import net.roboconf.messaging.api.internal.client.dismiss.DismissClientDm;
-import net.roboconf.messaging.api.internal.client.test.TestClientAgent;
-import net.roboconf.messaging.api.internal.client.test.TestClientDm;
+import net.roboconf.messaging.api.internal.client.dismiss.DismissClient;
+import net.roboconf.messaging.api.internal.client.test.TestClient;
import net.roboconf.messaging.api.messages.Message;
-import net.roboconf.messaging.api.processors.AbstractMessageProcessor;
import net.roboconf.messaging.api.processors.AbstractMessageProcessorTest.EmptyTestDmMessageProcessor;
+
import org.junit.Assert;
import org.junit.Test;
@@ -54,17 +56,17 @@ public class ReconfigurableClientTest {
@Test
public void testCloseConnection() throws Exception {
- IDmClient client = new TestClientDm();
+ IMessagingClient client = new TestClient();
Assert.assertFalse( client.isConnected());
ReconfigurableClient.closeConnection( client, "" );
- client = new TestClientDm();
+ client = new TestClient();
client.openConnection();
Assert.assertTrue( client.isConnected());
ReconfigurableClient.closeConnection( client, "" );
Assert.assertFalse( client.isConnected());
- client = new TestClientDm() {
+ client = new TestClient() {
@Override
public void closeConnection() throws IOException {
throw new IOException( "For test purpose" );
@@ -94,11 +96,21 @@ public void testInvalidFactory_agent() throws Exception {
// The internal client will be null.
// But still, there will be no NPE or other exception.
ReconfigurableClientAgent client = new ReconfigurableClientAgent();
+ client.setApplicationName( "app" );
+ client.setScopedInstancePath( "/root" );
client.switchMessagingType( null );
client.openConnection();
}
+ @Test
+ public void testHasValidClient() {
+
+ ReconfigurableClientAgent client = new ReconfigurableClientAgent();
+ Assert.assertFalse( client.hasValidClient());
+ }
+
+
@Test
public void testDm() throws Exception {
@@ -147,86 +159,165 @@ public void testAssociateMessageProcessor_exception() {
client.associateMessageProcessor( processor );
}
+
+ @Test
+ public void testSetFactory() throws Exception {
+
+ // Set a first factory
+ ReconfigurableClientDm client = new ReconfigurableClientDm();
+ final MessagingClientFactoryRegistry registry1 = new MessagingClientFactoryRegistry();
+
+ ConcurrentLinkedQueue> listeners1 = TestUtils.getInternalField( registry1, "listeners", ConcurrentLinkedQueue.class );
+ Assert.assertEquals( 0, listeners1.size());
+ Assert.assertNull( TestUtils.getInternalField( client, "registry", MessagingClientFactoryRegistry.class ));
+
+ client.setRegistry( registry1 );
+
+ Assert.assertEquals( 1, listeners1.size());
+ Assert.assertEquals( registry1, TestUtils.getInternalField( client, "registry", MessagingClientFactoryRegistry.class ));
+
+ // Change the factory
+ final MessagingClientFactoryRegistry registry2 = new MessagingClientFactoryRegistry();
+
+ ConcurrentLinkedQueue> listeners2 = TestUtils.getInternalField( registry2, "listeners", ConcurrentLinkedQueue.class );
+ Assert.assertEquals( 0, listeners2.size());
+
+ client.setRegistry( registry2 );
+
+ Assert.assertEquals( 0, listeners1.size());
+ Assert.assertEquals( 1, listeners2.size());
+ Assert.assertEquals( registry2, TestUtils.getInternalField( client, "registry", MessagingClientFactoryRegistry.class ));
+ }
+
+
+ @Test
+ public void testRegistryCallbacks() {
+
+ // Instead of creating a messaging client explicitly, we rely
+ // on the registry callbacks. At runtime, this can happen
+ // when we configured the DM or an agent with a messaging type that was not
+ // yet deployed or available in the OSGi registry.
+ ReconfigurableClientDm client = new ReconfigurableClientDm();
+ MessagingClientFactoryRegistry registry = new MessagingClientFactoryRegistry();
+ client.setRegistry( registry );
+
+ client.associateMessageProcessor( new AbstractMessageProcessor("dummy.messageProcessor") {
+ @Override
+ protected void processMessage( final Message message ) {
+ // nothing
+ }
+ });
+
+ client.switchMessagingType("foo");
+ Assert.assertEquals( DismissClient.class, client.getMessagingClient().getClass());
+
+ // Make a new factory appear.
+ DummyMessagingClientFactory factory = new DummyMessagingClientFactory("foo");
+ registry.addMessagingClientFactory( factory );
+
+ // Verify a new client was instantiated, with the right type.
+ Assert.assertEquals( DummyMessagingClient.class, client.getMessagingClient().getClass());
+
+ // Now, remove the factory (e.g. we remove the messaging bundle associated with "foo").
+ registry.removeMessagingClientFactory( factory );
+ Assert.assertEquals( DismissClient.class, client.getMessagingClient().getClass());
+ }
+
+
@Test
public void testFactorySwitchClientDm() {
+
+ // Here, the factories are created BEFORE the registry is
+ // associated with the reconfigurable client. It is a different scenario
+ // than the one covered by #testRegistryCallbacks().
+
// Create the messaging client factory registry, and register the "foo" and "bar" dummy factories.
final MessagingClientFactoryRegistry registry = new MessagingClientFactoryRegistry();
- registry.addMessagingClientFactory(new DummyMessagingClientFactory("foo"));
- registry.addMessagingClientFactory(new DummyMessagingClientFactory("bar"));
+ registry.addMessagingClientFactory( new DummyMessagingClientFactory("foo"));
+ registry.addMessagingClientFactory( new DummyMessagingClientFactory("bar"));
// Create the client DM
final ReconfigurableClientDm client = new ReconfigurableClientDm();
client.associateMessageProcessor(new AbstractMessageProcessor("dummy.messageProcessor") {
@Override
protected void processMessage( final Message message ) {
-
+ // nothing
}
});
+
client.setRegistry(registry);
// Check initial state.
Assert.assertNull(client.getMessagingType());
- Assert.assertTrue(client.getMessagingClient() instanceof DismissClientDm);
+ Assert.assertTrue(client.getMessagingClient() instanceof DismissClient);
Assert.assertSame(registry, client.getRegistry());
// Switch to foo!
client.switchMessagingType("foo");
Assert.assertEquals("foo", client.getMessagingType());
Assert.assertEquals("foo", client.getMessagingClient().getMessagingType());
- Assert.assertTrue(client.getMessagingClient() instanceof DummyMessagingDmClient);
+ Assert.assertTrue(client.getMessagingClient() instanceof DummyMessagingClient);
// Switch to bar!
client.switchMessagingType("bar");
Assert.assertEquals("bar", client.getMessagingType());
Assert.assertEquals("bar", client.getMessagingClient().getMessagingType());
- Assert.assertTrue(client.getMessagingClient() instanceof DummyMessagingDmClient);
+ Assert.assertTrue(client.getMessagingClient() instanceof DummyMessagingClient);
// Switch to null!
client.switchMessagingType(null);
Assert.assertNull(client.getMessagingType());
- Assert.assertTrue(client.getMessagingClient() instanceof DismissClientDm);
+ Assert.assertTrue(client.getMessagingClient() instanceof DismissClient);
}
+
@Test
public void testFactorySwitchClientAgent() {
+
// Create the messaging client factory registry, and register the "foo" and "bar" dummy factories.
final MessagingClientFactoryRegistry registry = new MessagingClientFactoryRegistry();
- registry.addMessagingClientFactory(new DummyMessagingClientFactory("foo"));
- registry.addMessagingClientFactory(new DummyMessagingClientFactory("bar"));
+ registry.addMessagingClientFactory( new DummyMessagingClientFactory("foo"));
+ registry.addMessagingClientFactory( new DummyMessagingClientFactory("bar"));
// Create the client DM
final ReconfigurableClientAgent client = new ReconfigurableClientAgent();
+ client.setApplicationName( "app" );
+ client.setScopedInstancePath( "/root" );
client.associateMessageProcessor(new AbstractMessageProcessor("dummy.messageProcessor") {
@Override
protected void processMessage( final Message message ) {
-
+ // nothing
}
});
+
client.setRegistry(registry);
// Check initial state.
Assert.assertNull(client.getMessagingType());
- Assert.assertTrue(client.getMessagingClient() instanceof DismissClientAgent);
+ Assert.assertTrue(client.getMessagingClient() instanceof DismissClient);
Assert.assertSame(registry, client.getRegistry());
// Switch to foo!
client.switchMessagingType("foo");
Assert.assertEquals("foo", client.getMessagingType());
Assert.assertEquals("foo", client.getMessagingClient().getMessagingType());
- Assert.assertTrue(client.getMessagingClient() instanceof DummyMessagingAgentClient);
+ Assert.assertTrue(client.getMessagingClient() instanceof DummyMessagingClient);
// Switch to bar!
client.switchMessagingType("bar");
Assert.assertEquals("bar", client.getMessagingType());
Assert.assertEquals("bar", client.getMessagingClient().getMessagingType());
- Assert.assertTrue(client.getMessagingClient() instanceof DummyMessagingAgentClient);
+ Assert.assertTrue(client.getMessagingClient() instanceof DummyMessagingClient);
+ Assert.assertEquals( MessagingConstants.FACTORY_TEST, client.getConfiguration().get( MessagingConstants.MESSAGING_TYPE_PROPERTY ));
// Switch to null!
client.switchMessagingType(null);
Assert.assertNull(client.getMessagingType());
- Assert.assertTrue(client.getMessagingClient() instanceof DismissClientAgent);
+ Assert.assertTrue(client.getMessagingClient() instanceof DismissClient);
+ Assert.assertEquals( 0, client.getConfiguration().size());
}
+
/**
* A stupid messaging client.
*/
@@ -239,7 +330,6 @@ private static class DummyMessagingClientFactory implements IMessagingClientFact
/**
* Constructor.
- *
* @param type the type of the messaging factory.
*/
DummyMessagingClientFactory( final String type ) {
@@ -252,13 +342,8 @@ public String getType() {
}
@Override
- public IDmClient createDmClient( final ReconfigurableClientDm parent ) {
- return new DummyMessagingDmClient(this.type);
- }
-
- @Override
- public IAgentClient createAgentClient( final ReconfigurableClientAgent parent ) {
- return new DummyMessagingAgentClient(this.type);
+ public IMessagingClient createClient( ReconfigurableClient> parent ) {
+ return new DummyMessagingClient(this.type);
}
@Override
@@ -267,35 +352,11 @@ public boolean setConfiguration( final Map configuration ) {
}
}
- /**
- * A dummy DM messaging client.
- */
- private static class DummyMessagingDmClient extends TestClientDm {
-
- /**
- * The type of the messaging client.
- */
- final String type;
-
- /**
- * Constructor.
- *
- * @param type the type of the messaging client.
- */
- DummyMessagingDmClient( final String type ) {
- this.type = type;
- }
-
- @Override
- public String getMessagingType() {
- return this.type;
- }
- }
/**
- * A dummy Agent messaging client.
+ * A dummy DM messaging client.
*/
- private static class DummyMessagingAgentClient extends TestClientAgent {
+ private static class DummyMessagingClient extends TestClient {
/**
* The type of the messaging client.
@@ -304,10 +365,9 @@ private static class DummyMessagingAgentClient extends TestClientAgent {
/**
* Constructor.
- *
* @param type the type of the messaging client.
*/
- DummyMessagingAgentClient( final String type ) {
+ DummyMessagingClient( final String type ) {
this.type = type;
}
@@ -316,5 +376,4 @@ public String getMessagingType() {
return this.type;
}
}
-
}
diff --git a/core/roboconf-messaging-api/src/test/java/net/roboconf/messaging/api/utils/MessagingUtilsTest.java b/core/roboconf-messaging-api/src/test/java/net/roboconf/messaging/api/utils/MessagingUtilsTest.java
new file mode 100644
index 00000000..bbc66457
--- /dev/null
+++ b/core/roboconf-messaging-api/src/test/java/net/roboconf/messaging/api/utils/MessagingUtilsTest.java
@@ -0,0 +1,78 @@
+/**
+ * Copyright 2014-2015 Linagora, Université Joseph Fourier, Floralis
+ *
+ * The present code is developed in the scope of the joint LINAGORA -
+ * Université Joseph Fourier - Floralis research program and is designated
+ * as a "Result" pursuant to the terms and conditions of the LINAGORA
+ * - Université Joseph Fourier - Floralis research program. Each copyright
+ * holder of Results enumerated here above fully & independently holds complete
+ * ownership of the complete Intellectual Property rights applicable to the whole
+ * of said Results, and may freely exploit it in any manner which does not infringe
+ * the moral rights of the other copyright holders.
+ *
+ * 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.
+ */
+
+package net.roboconf.messaging.api.utils;
+
+import org.junit.Assert;
+import net.roboconf.core.model.beans.Instance;
+import net.roboconf.core.model.helpers.InstanceHelpers;
+import net.roboconf.messaging.api.utils.MessagingUtils;
+
+import org.junit.Test;
+
+/**
+ * @author Vincent Zurczak - Linagora
+ */
+public class MessagingUtilsTest {
+
+ @Test
+ public void testBuildRoutingKeyForAgent_String() {
+
+ Assert.assertEquals( "machine.root", MessagingUtils.buildTopicNameForAgent( "root" ));
+ Assert.assertEquals( "machine.root", MessagingUtils.buildTopicNameForAgent("/root"));
+ Assert.assertEquals( "machine.root", MessagingUtils.buildTopicNameForAgent( "/root/" ));
+ Assert.assertEquals( "machine.root.docker", MessagingUtils.buildTopicNameForAgent( "/root/docker" ));
+ Assert.assertNotSame(
+ MessagingUtils.buildTopicNameForAgent( "root1" ),
+ MessagingUtils.buildTopicNameForAgent( "root2" ));
+ }
+
+
+ @Test
+ public void testBuildRoutingKeyForAgent_Instance() {
+ Instance inst = new Instance( "my-root" );
+
+ Assert.assertNotNull( MessagingUtils.buildTopicNameForAgent( inst ));
+ Assert.assertEquals(
+ MessagingUtils.buildTopicNameForAgent( inst ),
+ MessagingUtils.buildTopicNameForAgent( inst.getName()));
+
+ Instance childInstance = new Instance( "child" );
+ InstanceHelpers.insertChild( inst, childInstance );
+ Assert.assertEquals(
+ MessagingUtils.buildTopicNameForAgent( childInstance ),
+ MessagingUtils.buildTopicNameForAgent( inst ));
+ }
+
+
+ @Test
+ public void testEscapeInstancePath() {
+
+ Assert.assertEquals( "", MessagingUtils.escapeInstancePath( null ));
+ Assert.assertEquals( "", MessagingUtils.escapeInstancePath( " " ));
+ Assert.assertEquals( "root", MessagingUtils.escapeInstancePath( "/root" ));
+ Assert.assertEquals( "root.server.app", MessagingUtils.escapeInstancePath( "/root/server/app" ));
+ }
+}
diff --git a/core/roboconf-messaging-api/src/test/java/net/roboconf/messaging/api/utils/SerializationUtilsTest.java b/core/roboconf-messaging-api/src/test/java/net/roboconf/messaging/api/utils/SerializationUtilsTest.java
index 25c062ad..a74a59a9 100644
--- a/core/roboconf-messaging-api/src/test/java/net/roboconf/messaging/api/utils/SerializationUtilsTest.java
+++ b/core/roboconf-messaging-api/src/test/java/net/roboconf/messaging/api/utils/SerializationUtilsTest.java
@@ -30,7 +30,7 @@
import java.util.Map;
import java.util.UUID;
-import junit.framework.Assert;
+import org.junit.Assert;
import net.roboconf.core.model.beans.Component;
import net.roboconf.core.model.beans.Instance;
import net.roboconf.core.model.beans.Instance.InstanceStatus;
diff --git a/core/roboconf-messaging-http/.gitignore b/core/roboconf-messaging-http/.gitignore
new file mode 100644
index 00000000..2f4c8833
--- /dev/null
+++ b/core/roboconf-messaging-http/.gitignore
@@ -0,0 +1,19 @@
+*.class
+
+# Package Files #
+*.jar
+*.war
+*.ear
+
+# Maven related elements or those that can be generated from the POM
+.project
+.classpath
+/.externalToolBuilders
+/target
+/bin
+/maven-eclipse.xml
+/.settings
+
+#idea
+*.iml
+.idea/
\ No newline at end of file
diff --git a/core/roboconf-messaging-http/metadata.xml b/core/roboconf-messaging-http/metadata.xml
new file mode 100644
index 00000000..9132b125
--- /dev/null
+++ b/core/roboconf-messaging-http/metadata.xml
@@ -0,0 +1,22 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/core/roboconf-messaging-http/pom.xml b/core/roboconf-messaging-http/pom.xml
new file mode 100644
index 00000000..e025b799
--- /dev/null
+++ b/core/roboconf-messaging-http/pom.xml
@@ -0,0 +1,202 @@
+
+
+
+
+
+
+ 4.0.0
+
+ net.roboconf
+ roboconf-platform-parent
+ 0.6-SNAPSHOT
+ ../../pom.xml
+
+
+ net.roboconf
+ roboconf-messaging-http
+ Roboconf :: Messaging :: HTTP
+ bundle
+
+
+
+ net.roboconf
+ roboconf-core
+ ${project.version}
+ provided
+
+
+
+ net.roboconf
+ roboconf-messaging-api
+ ${project.version}
+ provided
+
+
+
+ org.osgi
+ org.osgi.core
+ 4.3.1
+ provided
+
+
+
+ javax.websocket
+ javax.websocket-api
+ 1.0
+ provided
+
+
+
+
+ org.eclipse.jetty.websocket
+ javax-websocket-server-impl
+ ${websocket.version}
+ test
+
+
+
+
+ org.eclipse.jetty.websocket
+ javax-websocket-client-impl
+ ${websocket.version}
+ provided
+
+
+
+ org.eclipse.jetty.websocket
+ websocket-api
+ ${websocket.version}
+ provided
+
+
+
+ org.eclipse.jetty.websocket
+ websocket-servlet
+ ${websocket.version}
+ provided
+
+
+
+ javax.servlet
+ servlet-api
+ 2.5
+ provided
+
+
+
+ org.apache.felix
+ org.osgi.compendium
+ 1.4.0
+ provided
+
+
+ org.apache.felix
+ javax.servlet
+
+
+ org.apache.felix
+ org.osgi.foundation
+
+
+
+
+
+ junit
+ junit
+ test
+
+
+
+ net.roboconf
+ roboconf-messaging-api
+ ${project.version}
+ test-jar
+ test
+
+
+
+ net.roboconf
+ roboconf-core
+ ${project.version}
+ test-jar
+ test
+
+
+
+ org.apache.felix
+ org.apache.felix.ipojo
+ ${ipojo.version}
+ test
+
+
+
+ org.mockito
+ mockito-core
+ test
+
+
+
+
+
+
+ org.apache.felix
+ maven-bundle-plugin
+
+
+
+
+ net.roboconf.messaging.api.messages.from_agent_to_agent;version="${version.range}",
+ net.roboconf.messaging.api.messages.from_agent_to_dm;version="${version.range}",
+ net.roboconf.messaging.api.messages.from_dm_to_agent;version="${version.range}",
+ net.roboconf.messaging.api.messages.from_dm_to_dm;version="${version.range}",
+
+
+ net.roboconf.*;version="${version.range}",
+ *
+
+
+ !net.roboconf.messaging.http.internal.*,
+ net.roboconf.messaging.http.*
+
+
+
+
+
+
+ org.apache.felix
+ maven-ipojo-plugin
+
+
+
+ ipojo-bundle
+
+
+
+
+
+
+
+
diff --git a/core/roboconf-messaging-http/src/main/java/net/roboconf/messaging/http/HttpConstants.java b/core/roboconf-messaging-http/src/main/java/net/roboconf/messaging/http/HttpConstants.java
new file mode 100644
index 00000000..b4a29cd8
--- /dev/null
+++ b/core/roboconf-messaging-http/src/main/java/net/roboconf/messaging/http/HttpConstants.java
@@ -0,0 +1,71 @@
+/**
+ * Copyright 2014-2015 Linagora, Université Joseph Fourier, Floralis
+ *
+ * The present code is developed in the scope of the joint LINAGORA -
+ * Université Joseph Fourier - Floralis research program and is designated
+ * as a "Result" pursuant to the terms and conditions of the LINAGORA
+ * - Université Joseph Fourier - Floralis research program. Each copyright
+ * holder of Results enumerated here above fully & independently holds complete
+ * ownership of the complete Intellectual Property rights applicable to the whole
+ * of said Results, and may freely exploit it in any manner which does not infringe
+ * the moral rights of the other copyright holders.
+ *
+ * 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.
+ */
+
+package net.roboconf.messaging.http;
+
+import net.roboconf.messaging.api.MessagingConstants;
+
+/**
+ * Constants related to the HTTP messaging client factory.
+ * @author Pierre-Yves Gibello - Linagora
+ */
+public interface HttpConstants {
+
+ /**
+ * The factory type.
+ */
+ String FACTORY_HTTP = "http";
+
+ /**
+ * The prefix for HTTP properties.
+ */
+ String HTTP_PROPERTY_PREFIX = MessagingConstants.MESSAGING_PROPERTY_PREFIX + "." + FACTORY_HTTP;
+
+ /**
+ * The HTTP port (to create a client).
+ */
+ String HTTP_SERVER_PORT = HTTP_PROPERTY_PREFIX + ".server.port";
+
+ /**
+ * The HTTP server IP (to create a client).
+ */
+ String HTTP_SERVER_IP = HTTP_PROPERTY_PREFIX + ".server.ip";
+
+
+ /**
+ * The default IP address.
+ */
+ String DEFAULT_IP = "127.0.0.1";
+
+ /**
+ * The default port (Karaf's one).
+ */
+ int DEFAULT_PORT = 8181;
+
+ /**
+ * The path of the socket registered by the DM.
+ */
+ String DM_SOCKET_PATH = "/roboconf-messaging-http";
+}
diff --git a/core/roboconf-messaging-http/src/main/java/net/roboconf/messaging/http/internal/HttpClientFactory.java b/core/roboconf-messaging-http/src/main/java/net/roboconf/messaging/http/internal/HttpClientFactory.java
new file mode 100644
index 00000000..43610eae
--- /dev/null
+++ b/core/roboconf-messaging-http/src/main/java/net/roboconf/messaging/http/internal/HttpClientFactory.java
@@ -0,0 +1,314 @@
+/**
+ * Copyright 2014-2015 Linagora, Université Joseph Fourier, Floralis
+ *
+ * The present code is developed in the scope of the joint LINAGORA -
+ * Université Joseph Fourier - Floralis research program and is designated
+ * as a "Result" pursuant to the terms and conditions of the LINAGORA
+ * - Université Joseph Fourier - Floralis research program. Each copyright
+ * holder of Results enumerated here above fully & independently holds complete
+ * ownership of the complete Intellectual Property rights applicable to the whole
+ * of said Results, and may freely exploit it in any manner which does not infringe
+ * the moral rights of the other copyright holders.
+ *
+ * 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.
+ */
+
+package net.roboconf.messaging.http.internal;
+
+import static net.roboconf.messaging.http.HttpConstants.DEFAULT_IP;
+import static net.roboconf.messaging.http.HttpConstants.HTTP_SERVER_IP;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Hashtable;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+import java.util.WeakHashMap;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.logging.Logger;
+
+import net.roboconf.core.utils.Utils;
+import net.roboconf.messaging.api.MessagingConstants;
+import net.roboconf.messaging.api.extensions.AbstractRoutingClient.RoutingContext;
+import net.roboconf.messaging.api.extensions.IMessagingClient;
+import net.roboconf.messaging.api.extensions.MessagingContext.RecipientKind;
+import net.roboconf.messaging.api.factory.IMessagingClientFactory;
+import net.roboconf.messaging.api.reconfigurables.ReconfigurableClient;
+import net.roboconf.messaging.http.HttpConstants;
+import net.roboconf.messaging.http.internal.clients.HttpAgentClient;
+import net.roboconf.messaging.http.internal.clients.HttpDmClient;
+import net.roboconf.messaging.http.internal.sockets.DmWebSocketServlet;
+
+import org.eclipse.jetty.websocket.api.Session;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.service.http.HttpService;
+
+/**
+ * Messaging client factory for HTTP.
+ *
+ * In this factory, there is a singleton instance of the client for
+ * the DM. This is because of the web sockets. We do not want to lost
+ * and/or confuse message routing. So, there is no reconfiguration for
+ * this client and we keep a single instance.
+ *
+ *
+ * @author Pierre-Yves Gibello - Linagora
+ * @author Vincent Zurczak - Linagora
+ */
+public class HttpClientFactory implements IMessagingClientFactory {
+
+ /**
+ * @author Vincent Zurczak - Linagora
+ */
+ public static class HttpRoutingContext extends RoutingContext {
+ public final Map ctxToSession = new ConcurrentHashMap<> ();
+ }
+
+ // The created CLIENTS.
+ // References to the CLIENTS are *weak*, so we never prevent their garbage collection.
+ final Set agentClients = Collections.newSetFromMap( new WeakHashMap ());
+
+ private final Logger logger = Logger.getLogger( getClass().getName());
+ private final HttpRoutingContext routingContext = new HttpRoutingContext();
+ private final HttpDmClient dmClient = new HttpDmClient( this.routingContext );
+
+ // Injected by iPojo
+ BundleContext bundleContext;
+ HttpService httpService;
+
+ String httpServerIp;
+ int httpPort;
+
+
+
+ /**
+ * Constructor.
+ */
+ public HttpClientFactory() {
+ // nothing
+ }
+
+
+ /**
+ * Constructor with the bundle context.
+ *
+ * This constructor is automatically invoked by iPojo.
+ *
+ *
+ * @param context
+ */
+ public HttpClientFactory( BundleContext bundleContext ) {
+ this.bundleContext = bundleContext;
+ }
+
+
+ // Getters and Setters
+
+ public synchronized void setHttpServerIp( final String serverIp ) {
+ this.httpServerIp = serverIp;
+ this.dmClient.setHttpServerIp( serverIp );
+ this.logger.finer( "Server IP set to " + this.httpServerIp );
+ }
+
+
+ public synchronized void setHttpPort( final int port ) {
+ this.httpPort = port;
+ this.dmClient.setHttpPort( port );
+ this.logger.finer( "Server port set to " + this.httpPort );
+ }
+
+
+ public HttpDmClient getDmClient() {
+ return this.dmClient;
+ }
+
+
+ // iPojo methods
+
+
+ /**
+ * The method to use when all the dependencies are resolved.
+ *
+ * It means iPojo guarantees that both the manager and the HTTP
+ * service are not null.
+ *
+ *
+ * @throws Exception
+ */
+ public void start() throws Exception {
+
+ // Is the DM part of the distribution?
+ boolean found = false;
+ for( Bundle b : this.bundleContext.getBundles()) {
+ if( "net.roboconf.dm".equals( b.getSymbolicName())) {
+ found = true;
+ break;
+ }
+ }
+
+ // If we are on an agent, we have nothing to do.
+ // Otherwise, we must register a servlet.
+ if( found ) {
+ this.logger.fine( "iPojo registers a servlet for HTTP messaging." );
+
+ Hashtable initParams = new Hashtable ();
+ initParams.put( "servlet-name", "Roboconf DM (HTTP messaging)" );
+
+ DmWebSocketServlet messagingServlet = new DmWebSocketServlet( this );
+ this.httpService.registerServlet( HttpConstants.DM_SOCKET_PATH, messagingServlet, initParams, null );
+
+ } else {
+ this.logger.warning( "Roboconf's DM bundle was not found. No servlet will be registered." );
+ }
+ }
+
+
+ /**
+ * Stops all the agent clients.
+ *
+ * Invoked by iPojo.
+ *
+ */
+ public void stop() {
+ this.logger.fine( "iPojo unregisters a servlet for HTTP messaging." );
+ resetClients( true );
+ }
+
+
+ /**
+ * Stops all the clients (agents and DM).
+ *
+ * Mostly for tests.
+ *
+ */
+ void stopAll() {
+
+ try {
+ this.dmClient.closeConnection();
+ stop();
+
+ } catch( Throwable t ) {
+ this.logger.warning( "An error occurred while closing the connection of the DM client." );
+ Utils.logException( this.logger, new RuntimeException( t ));
+ }
+ }
+
+
+ @Override
+ public IMessagingClient createClient( ReconfigurableClient> parent ) {
+
+ this.logger.fine( "Creating a new HTTP client with owner = " + parent.getOwnerKind());
+ IMessagingClient client;
+ if( parent.getOwnerKind() == RecipientKind.DM ) {
+ client = this.dmClient;
+
+ } else {
+ synchronized( this ) {
+ client = new HttpAgentClient( parent, this.httpServerIp, this.httpPort );
+ }
+
+ this.agentClients.add((HttpAgentClient) client);
+ }
+
+ return client;
+ }
+
+
+ @Override
+ public String getType() {
+ return HttpConstants.FACTORY_HTTP;
+ }
+
+
+ @Override
+ public boolean setConfiguration( final Map configuration ) {
+
+ boolean valid = HttpConstants.FACTORY_HTTP.equals( configuration.get( MessagingConstants.MESSAGING_TYPE_PROPERTY ));
+ if( valid ) {
+ boolean hasChanged = false;
+
+ // Get the new values
+ String ip = Utils.getValue( configuration, HTTP_SERVER_IP, DEFAULT_IP );
+ String portAS = configuration.get( HttpConstants.HTTP_SERVER_PORT );
+ int port = portAS == null ? HttpConstants.DEFAULT_PORT : Integer.parseInt( portAS );
+
+ // Avoid unnecessary (and potentially problematic) reconfiguration if nothing has changed.
+ // First we detect for changes, and set the parameters accordingly.
+ synchronized( this ) {
+
+ if( ! Objects.equals( this.httpServerIp, ip )) {
+ this.httpServerIp = ip;
+ hasChanged = true;
+ }
+
+ if( this.httpPort != port ) {
+ this.httpPort = port;
+ hasChanged = true;
+ }
+ }
+
+ // Then, if changes has occurred, we reconfigure the factory. This will invalidate every created client.
+ // Otherwise, if nothing has changed, we do nothing. Thus we avoid invalidating clients uselessly, and
+ // prevent any message loss.
+ if( hasChanged )
+ reconfigure();
+ }
+
+ return valid;
+ }
+
+
+ public void reconfigure() {
+ this.logger.fine( "HTTP clients are about to be reconfigured." );
+ resetClients( false );
+ }
+
+
+ /**
+ * Closes messaging clients or requests a replacement to the reconfigurable client.
+ * @param shutdown true to close, false to request...
+ */
+ private void resetClients( boolean shutdown ) {
+
+ // Only agent clients need to be reconfigured.
+ // Make fresh snapshots of the CLIENTS, as we don't want to reconfigure them while holding the lock.
+ final List clients;
+ synchronized( this ) {
+
+ // Get the snapshot.
+ clients = new ArrayList<>( this.agentClients );
+
+ // Remove the clients, new ones will be created if necessary.
+ this.agentClients.clear();
+ }
+
+ // Now reconfigure all the CLIENTS.
+ for( HttpAgentClient client : clients ) {
+ try {
+ final ReconfigurableClient> reconfigurable = client.getReconfigurableClient();
+ if (shutdown)
+ reconfigurable.closeConnection();
+ else
+ reconfigurable.switchMessagingType( HttpConstants.FACTORY_HTTP );
+
+ } catch( Throwable t ) {
+ // Warn but continue to reconfigure the next CLIENTS!
+ this.logger.warning( "A client has thrown an exception on reconfiguration: " + client );
+ Utils.logException( this.logger, new RuntimeException( t ));
+ }
+ }
+ }
+}
diff --git a/core/roboconf-messaging-http/src/main/java/net/roboconf/messaging/http/internal/HttpUtils.java b/core/roboconf-messaging-http/src/main/java/net/roboconf/messaging/http/internal/HttpUtils.java
new file mode 100644
index 00000000..d55439a6
--- /dev/null
+++ b/core/roboconf-messaging-http/src/main/java/net/roboconf/messaging/http/internal/HttpUtils.java
@@ -0,0 +1,61 @@
+/**
+ * Copyright 2015 Linagora, Université Joseph Fourier, Floralis
+ *
+ * The present code is developed in the scope of the joint LINAGORA -
+ * Université Joseph Fourier - Floralis research program and is designated
+ * as a "Result" pursuant to the terms and conditions of the LINAGORA
+ * - Université Joseph Fourier - Floralis research program. Each copyright
+ * holder of Results enumerated here above fully & independently holds complete
+ * ownership of the complete Intellectual Property rights applicable to the whole
+ * of said Results, and may freely exploit it in any manner which does not infringe
+ * the moral rights of the other copyright holders.
+ *
+ * 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.
+ */
+
+package net.roboconf.messaging.http.internal;
+
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+import net.roboconf.messaging.api.MessagingConstants;
+import net.roboconf.messaging.http.HttpConstants;
+
+/**
+ * @author Vincent Zurczak - Linagora
+ */
+public final class HttpUtils {
+
+ /**
+ * Private empty constructor.
+ */
+ private HttpUtils() {
+ // nothing
+ }
+
+
+ /**
+ * Return a HTTP messaging configuration for the given parameters.
+ * @param agentPort the HTTP server port of the agent.. May be {@code null}.
+ * @return the messaging configuration for the given parameters.
+ */
+ public static Map httpMessagingConfiguration( String ip, int port ) {
+
+ final Map result = new LinkedHashMap<>();
+ result.put( MessagingConstants.MESSAGING_TYPE_PROPERTY, HttpConstants.FACTORY_HTTP );
+ result.put( HttpConstants.HTTP_SERVER_IP, ip == null ? HttpConstants.DEFAULT_IP : ip );
+ result.put( HttpConstants.HTTP_SERVER_PORT, "" + (port <= 0 ? HttpConstants.DEFAULT_PORT : port));
+
+ return result;
+ }
+}
diff --git a/core/roboconf-messaging-http/src/main/java/net/roboconf/messaging/http/internal/clients/HttpAgentClient.java b/core/roboconf-messaging-http/src/main/java/net/roboconf/messaging/http/internal/clients/HttpAgentClient.java
new file mode 100644
index 00000000..867c1e13
--- /dev/null
+++ b/core/roboconf-messaging-http/src/main/java/net/roboconf/messaging/http/internal/clients/HttpAgentClient.java
@@ -0,0 +1,208 @@
+/**
+ * Copyright 2015 Linagora, Université Joseph Fourier, Floralis
+ *
+ * The present code is developed in the scope of the joint LINAGORA -
+ * Université Joseph Fourier - Floralis research program and is designated
+ * as a "Result" pursuant to the terms and conditions of the LINAGORA
+ * - Université Joseph Fourier - Floralis research program. Each copyright
+ * holder of Results enumerated here above fully & independently holds complete
+ * ownership of the complete Intellectual Property rights applicable to the whole
+ * of said Results, and may freely exploit it in any manner which does not infringe
+ * the moral rights of the other copyright holders.
+ *
+ * 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.
+ */
+
+package net.roboconf.messaging.http.internal.clients;
+
+import java.io.IOException;
+import java.lang.ref.WeakReference;
+import java.net.URI;
+import java.nio.ByteBuffer;
+import java.util.Map;
+import java.util.concurrent.Future;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.logging.Logger;
+
+import net.roboconf.core.model.beans.Application;
+import net.roboconf.messaging.api.extensions.AbstractRoutingClient;
+import net.roboconf.messaging.api.extensions.IMessagingClient;
+import net.roboconf.messaging.api.extensions.MessagingContext;
+import net.roboconf.messaging.api.extensions.MessagingContext.RecipientKind;
+import net.roboconf.messaging.api.messages.Message;
+import net.roboconf.messaging.api.reconfigurables.ReconfigurableClient;
+import net.roboconf.messaging.api.utils.SerializationUtils;
+import net.roboconf.messaging.http.HttpConstants;
+import net.roboconf.messaging.http.internal.HttpUtils;
+import net.roboconf.messaging.http.internal.messages.HttpMessage;
+import net.roboconf.messaging.http.internal.messages.SubscriptionMessage;
+import net.roboconf.messaging.http.internal.sockets.AgentWebSocket;
+
+import org.eclipse.jetty.websocket.api.Session;
+import org.eclipse.jetty.websocket.client.ClientUpgradeRequest;
+import org.eclipse.jetty.websocket.client.WebSocketClient;
+
+/**
+ * @author Vincent Zurczak - Linagora
+ */
+public class HttpAgentClient implements IMessagingClient {
+
+ private final Logger logger = Logger.getLogger( getClass().getName());
+ private final WeakReference> reconfigurable;
+ private final String dmIp;
+ private final int dmPort;
+
+ private LinkedBlockingQueue messageQueue;
+ private String applicationName, scopedInstancePath;
+
+ private AgentWebSocket socket;
+ private Session clientSession;
+ private WebSocketClient client;
+
+
+
+ /**
+ * Constructor.
+ * @param reconfigurable
+ * @param dmIp
+ * @param dmPort
+ */
+ public HttpAgentClient( ReconfigurableClient> reconfigurable, String dmIp, int dmPort ) {
+ this.reconfigurable = new WeakReference>( reconfigurable );
+ this.dmIp = dmIp;
+ this.dmPort = dmPort;
+ }
+
+
+ /**
+ * @return the wrapping reconfigurable client (may be {@code null}).
+ */
+ public final ReconfigurableClient> getReconfigurableClient() {
+ return this.reconfigurable.get();
+ }
+
+
+ @Override
+ public void setMessageQueue( LinkedBlockingQueue messageQueue ) {
+ this.messageQueue = messageQueue;
+ }
+
+
+ @Override
+ public boolean isConnected() {
+ return this.client != null && this.clientSession != null;
+ }
+
+
+ @Override
+ public void setOwnerProperties( RecipientKind ownerKind, String applicationName, String scopedInstancePath ) {
+ this.applicationName = applicationName;
+ this.scopedInstancePath = scopedInstancePath;
+ this.logger.fine( "Owner properties changed to " + getId());
+ }
+
+
+ @Override
+ public void openConnection() throws IOException {
+
+ this.logger.info( getId() + " is opening a connection to the DM." );
+ try {
+ this.client = new WebSocketClient();
+ this.socket = new AgentWebSocket( this.messageQueue );
+ this.client.start();
+
+ URI dmUri = new URI( "ws://" + this.dmIp + ":" + this.dmPort + HttpConstants.DM_SOCKET_PATH );
+ this.logger.fine( "Connecting to " + dmUri );
+ ClientUpgradeRequest request = new ClientUpgradeRequest();
+
+ Future fut = this.client.connect( this.socket, dmUri, request );
+ this.clientSession = fut.get();
+
+ } catch( Exception e ) {
+ throw new IOException( e );
+ }
+ }
+
+
+ @Override
+ public void closeConnection() throws IOException {
+
+ this.logger.info( getId() + " is closing its connection to the DM." );
+ try {
+ if( this.client != null )
+ this.client.stop();
+
+ } catch( Exception e ) {
+ throw new IOException( e );
+ }
+ }
+
+
+ @Override
+ public String getMessagingType() {
+ return HttpConstants.FACTORY_HTTP;
+ }
+
+
+ @Override
+ public Map getConfiguration() {
+ return HttpUtils.httpMessagingConfiguration( this.dmIp, this.dmPort );
+ }
+
+
+ @Override
+ public void subscribe( MessagingContext ctx ) throws IOException {
+
+ String ownerId = AbstractRoutingClient.buildOwnerId( RecipientKind.AGENTS, this.applicationName, this.scopedInstancePath );
+ this.logger.fine( getId() + " is about to subscribe to " + ownerId );
+ sendToTheDm( new SubscriptionMessage( ownerId, ctx, true ));
+ }
+
+
+ @Override
+ public void unsubscribe( MessagingContext ctx ) throws IOException {
+
+ String ownerId = AbstractRoutingClient.buildOwnerId( RecipientKind.AGENTS, this.applicationName, this.scopedInstancePath );
+ this.logger.fine( getId() + " is about to unsubscribe to " + ownerId );
+ sendToTheDm( new SubscriptionMessage( ownerId, ctx, false ));
+ }
+
+
+ @Override
+ public void publish( MessagingContext ctx, Message msg ) throws IOException {
+
+ String ownerId = AbstractRoutingClient.buildOwnerId( RecipientKind.AGENTS, this.applicationName, this.scopedInstancePath );
+ this.logger.fine( getId() + " is about to publish a message (" + msg + ") to " + ownerId );
+ sendToTheDm( new HttpMessage( ownerId, msg, ctx ));
+ }
+
+
+ @Override
+ public void deleteMessagingServerArtifacts( Application application )
+ throws IOException {
+ // nothing
+ }
+
+
+ private void sendToTheDm( Message message ) throws IOException {
+
+ byte[] rawData = SerializationUtils.serializeObject( message );
+ ByteBuffer data = ByteBuffer.wrap( rawData );
+ this.clientSession.getRemote().sendBytes( data );
+ }
+
+
+ String getId() {
+ return this.scopedInstancePath + " @ " + this.applicationName;
+ }
+}
diff --git a/core/roboconf-messaging-http/src/main/java/net/roboconf/messaging/http/internal/clients/HttpDmClient.java b/core/roboconf-messaging-http/src/main/java/net/roboconf/messaging/http/internal/clients/HttpDmClient.java
new file mode 100644
index 00000000..3dd97d3e
--- /dev/null
+++ b/core/roboconf-messaging-http/src/main/java/net/roboconf/messaging/http/internal/clients/HttpDmClient.java
@@ -0,0 +1,209 @@
+/**
+ * Copyright 2015 Linagora, Université Joseph Fourier, Floralis
+ *
+ * The present code is developed in the scope of the joint LINAGORA -
+ * Université Joseph Fourier - Floralis research program and is designated
+ * as a "Result" pursuant to the terms and conditions of the LINAGORA
+ * - Université Joseph Fourier - Floralis research program. Each copyright
+ * holder of Results enumerated here above fully & independently holds complete
+ * ownership of the complete Intellectual Property rights applicable to the whole
+ * of said Results, and may freely exploit it in any manner which does not infringe
+ * the moral rights of the other copyright holders.
+ *
+ * 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.
+ */
+
+package net.roboconf.messaging.http.internal.clients;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import net.roboconf.messaging.api.extensions.AbstractRoutingClient;
+import net.roboconf.messaging.api.extensions.MessagingContext;
+import net.roboconf.messaging.api.extensions.MessagingContext.RecipientKind;
+import net.roboconf.messaging.api.messages.Message;
+import net.roboconf.messaging.api.utils.SerializationUtils;
+import net.roboconf.messaging.http.HttpConstants;
+import net.roboconf.messaging.http.internal.HttpClientFactory.HttpRoutingContext;
+import net.roboconf.messaging.http.internal.HttpUtils;
+import net.roboconf.messaging.http.internal.messages.HttpMessage;
+import net.roboconf.messaging.http.internal.messages.SubscriptionMessage;
+
+import org.eclipse.jetty.websocket.api.Session;
+
+/**
+ * @author Vincent Zurczak - Linagora
+ */
+public class HttpDmClient extends AbstractRoutingClient {
+
+ // Internal field (for a convenient access).
+ private static final String DM_OWNER_ID = AbstractRoutingClient.buildOwnerId( RecipientKind.DM, null, null );
+
+ private final Map ctxToSession;
+ private LinkedBlockingQueue messageQueue;
+ private final AtomicInteger openConnections = new AtomicInteger( 0 );
+
+ private String httpServerIp;
+ private int httpPort;
+
+
+ /**
+ * Constructor.
+ */
+ public HttpDmClient( HttpRoutingContext routingContext ) {
+ super( routingContext, RecipientKind.DM );
+ this.connectionIsRequired = false;
+ this.ctxToSession = routingContext.ctxToSession;
+ }
+
+
+ @Override
+ public void openConnection() throws IOException {
+
+ // There is only one instance per Http Factory.
+ // So, we do not want to close the connection someone is still using it.
+ this.openConnections.incrementAndGet();
+ super.openConnection();
+ }
+
+
+ @Override
+ public void closeConnection() throws IOException {
+
+ // There is only one instance per Http Factory.
+ // So, we do not want to close the connection someone is still using it.
+ if( this.openConnections.decrementAndGet() == 0 )
+ super.closeConnection();
+ }
+
+
+ @Override
+ public void setMessageQueue( LinkedBlockingQueue messageQueue ) {
+ this.messageQueue = messageQueue;
+ }
+
+
+ @Override
+ protected Map getStaticContextToObject() {
+ return this.ctxToSession;
+ }
+
+
+ @Override
+ public String getMessagingType() {
+ return HttpConstants.FACTORY_HTTP;
+ }
+
+
+ @Override
+ public Map getConfiguration() {
+ return HttpUtils.httpMessagingConfiguration( this.httpServerIp, this.httpPort );
+ }
+
+
+ @Override
+ protected void process( Session session, Message message ) throws IOException {
+
+ byte[] rawData = SerializationUtils.serializeObject( message );
+ ByteBuffer data = ByteBuffer.wrap( rawData );
+ session.getRemote().sendBytes( data );
+ }
+
+
+ @Override
+ public void publish( MessagingContext ctx, Message msg ) throws IOException {
+ this.logger.fine( "The DM's HTTP client is about to publish a message (" + msg + ") to" + ctx );
+
+ // The DM has no session.
+ // So, we intercept messages for the DM and determine whether the
+ // message should be enqueued or ignored. This decision is based on subscriptions and the connection.
+ if( ctx.getKind() == RecipientKind.DM
+ && this.connected.get()) {
+
+ Set subs = this.routingContext.subscriptions.get( DM_OWNER_ID );
+ if( subs != null && subs.contains( ctx ))
+ this.messageQueue.add( msg );
+ }
+
+ // Agents => use the standard publish action.
+ else {
+ super.publish( ctx, msg );
+ }
+ }
+
+
+ /**
+ * Processes a message received from a web socket (i.e. sent by agents).
+ * @param message a message
+ * @throws IOException
+ */
+ public void processReceivedMessage( Message message, Session session ) throws IOException {
+ this.logger.fine( "The DM's HTTP client is about to process a message (" + message + ") received through a web socket." );
+
+ // HttpMessage
+ if( message instanceof HttpMessage ) {
+ HttpMessage httpMsg = (HttpMessage) message;
+
+ // Store the session
+ registerSession( httpMsg.getOwnerId(), session );
+
+ // Publish the message
+ publish( httpMsg.getCtx(), httpMsg.getMessage());
+ }
+
+ // Subscription message
+ else if( message instanceof SubscriptionMessage ) {
+ SubscriptionMessage sub = (SubscriptionMessage) message;
+
+ // Store the session
+ registerSession( sub.getOwnerId(), session );
+
+ // Update the subscriptions
+ if( sub.isSubscribe())
+ subscribe( sub.getOwnerId(), sub.getCtx());
+ else
+ unsubscribe( sub.getOwnerId(), sub.getCtx());
+ }
+ }
+
+
+ /**
+ * Sets the DM's IP address (to propagate it through its configuration).
+ * @param httpServerIp the DM's IP address (must be visible/reachable from agents)
+ */
+ public void setHttpServerIp( String httpServerIp ) {
+ this.httpServerIp = httpServerIp;
+ this.logger.info( "The DM's IP address was changed to " + httpServerIp );
+ }
+
+
+ /**
+ * Sets the DM's port (to propagate it through its configuration).
+ * @param httpPort the DM's port
+ */
+ public void setHttpPort( int httpPort ) {
+ this.httpPort = httpPort;
+ this.logger.info( "The DM's port was changed to " + httpPort );
+ }
+
+
+ private void registerSession( String ownerId, Session session ) {
+
+ if( session != null )
+ this.ctxToSession.put( ownerId, session );
+ }
+}
diff --git a/core/roboconf-messaging-http/src/main/java/net/roboconf/messaging/http/internal/messages/HttpMessage.java b/core/roboconf-messaging-http/src/main/java/net/roboconf/messaging/http/internal/messages/HttpMessage.java
new file mode 100644
index 00000000..977aaf17
--- /dev/null
+++ b/core/roboconf-messaging-http/src/main/java/net/roboconf/messaging/http/internal/messages/HttpMessage.java
@@ -0,0 +1,69 @@
+/**
+ * Copyright 2014-2015 Linagora, Université Joseph Fourier, Floralis
+ *
+ * The present code is developed in the scope of the joint LINAGORA -
+ * Université Joseph Fourier - Floralis research program and is designated
+ * as a "Result" pursuant to the terms and conditions of the LINAGORA
+ * - Université Joseph Fourier - Floralis research program. Each copyright
+ * holder of Results enumerated here above fully & independently holds complete
+ * ownership of the complete Intellectual Property rights applicable to the whole
+ * of said Results, and may freely exploit it in any manner which does not infringe
+ * the moral rights of the other copyright holders.
+ *
+ * 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.
+ */
+
+package net.roboconf.messaging.http.internal.messages;
+
+import java.io.Serializable;
+
+import net.roboconf.messaging.api.extensions.MessagingContext;
+import net.roboconf.messaging.api.messages.Message;
+
+/**
+ * A message with additional meta-data useful for HTTP messaging.
+ * @author Pierre-Yves Gibello - Linagora
+ */
+public class HttpMessage extends Message implements Serializable {
+
+ private static final long serialVersionUID = -1012611751797601185L;
+
+ private final String ownerId;
+ private final Message message;
+ private final MessagingContext ctx;
+
+
+ /**
+ * Constructor.
+ * @param ownerId who sent the message
+ * @param message the wrapped message
+ * @param ctx the message recipient(s)
+ */
+ public HttpMessage( String ownerId, Message message, MessagingContext ctx ) {
+ this.ownerId = ownerId;
+ this.message = message;
+ this.ctx = ctx;
+ }
+
+ public String getOwnerId() {
+ return this.ownerId;
+ }
+
+ public Message getMessage() {
+ return this.message;
+ }
+
+ public MessagingContext getCtx() {
+ return this.ctx;
+ }
+}
diff --git a/core/roboconf-messaging-http/src/main/java/net/roboconf/messaging/http/internal/messages/HttpSerializationUtils.java b/core/roboconf-messaging-http/src/main/java/net/roboconf/messaging/http/internal/messages/HttpSerializationUtils.java
new file mode 100644
index 00000000..ab786a13
--- /dev/null
+++ b/core/roboconf-messaging-http/src/main/java/net/roboconf/messaging/http/internal/messages/HttpSerializationUtils.java
@@ -0,0 +1,75 @@
+/**
+ * Copyright 2013-2015 Linagora, Université Joseph Fourier, Floralis
+ *
+ * The present code is developed in the scope of the joint LINAGORA -
+ * Université Joseph Fourier - Floralis research program and is designated
+ * as a "Result" pursuant to the terms and conditions of the LINAGORA
+ * - Université Joseph Fourier - Floralis research program. Each copyright
+ * holder of Results enumerated here above fully & independently holds complete
+ * ownership of the complete Intellectual Property rights applicable to the whole
+ * of said Results, and may freely exploit it in any manner which does not infringe
+ * the moral rights of the other copyright holders.
+ *
+ * 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.
+ */
+
+package net.roboconf.messaging.http.internal.messages;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+
+import net.roboconf.messaging.api.messages.Message;
+
+/**
+ * This class is a partial copy of SerializationUtils.
+ *
+ * This really sucks. We cannot use SerializationUtils with HTTP's custom
+ * message implementation because of class loading issues. When deserializing
+ * a HTTP message roa subscription message, we get a ClassNotFound exception.
+ *
+ *
+ * A workaround was suggested on Stack Overflow:
+ * http://stackoverflow.com/questions/13861342/how-do-you-deserialize-an-object-from-bytes-in-osgi
+ *
+ *
+ * However, it is not more simple. So, this bundle provides its own deserializing method.
+ *
+ *
+ * @author Noël - LIG
+ */
+public final class HttpSerializationUtils {
+
+ /**
+ * Empty private constructor.
+ */
+ private HttpSerializationUtils() {
+ // nothing
+ }
+
+
+ /**
+ * Deserializes a message.
+ * @param bytes a non-null array of bytes
+ * @return the deserialized message, or null if it failed
+ * @throws ClassNotFoundException
+ * @throws IOException
+ */
+ public static Message deserializeObject( byte[] bytes )
+ throws IOException, ClassNotFoundException {
+
+ ByteArrayInputStream is = new ByteArrayInputStream( bytes );
+ ObjectInputStream deserializer = new ObjectInputStream( is );
+ return (Message) deserializer.readObject();
+ }
+}
diff --git a/core/roboconf-messaging-http/src/main/java/net/roboconf/messaging/http/internal/messages/SubscriptionMessage.java b/core/roboconf-messaging-http/src/main/java/net/roboconf/messaging/http/internal/messages/SubscriptionMessage.java
new file mode 100644
index 00000000..4b4d2c9c
--- /dev/null
+++ b/core/roboconf-messaging-http/src/main/java/net/roboconf/messaging/http/internal/messages/SubscriptionMessage.java
@@ -0,0 +1,69 @@
+/**
+ * Copyright 2014-2015 Linagora, Université Joseph Fourier, Floralis
+ *
+ * The present code is developed in the scope of the joint LINAGORA -
+ * Université Joseph Fourier - Floralis research program and is designated
+ * as a "Result" pursuant to the terms and conditions of the LINAGORA
+ * - Université Joseph Fourier - Floralis research program. Each copyright
+ * holder of Results enumerated here above fully & independently holds complete
+ * ownership of the complete Intellectual Property rights applicable to the whole
+ * of said Results, and may freely exploit it in any manner which does not infringe
+ * the moral rights of the other copyright holders.
+ *
+ * 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.
+ */
+
+package net.roboconf.messaging.http.internal.messages;
+
+import java.io.Serializable;
+
+import net.roboconf.messaging.api.extensions.MessagingContext;
+import net.roboconf.messaging.api.messages.Message;
+
+/**
+ * A subscribe/unsubscribe message for HTTP messaging system.
+ * @author Pierre-Yves Gibello - Linagora
+ */
+public class SubscriptionMessage extends Message implements Serializable {
+
+ private static final long serialVersionUID = -857054136326662577L;
+
+ private final String ownerId;
+ private final MessagingContext ctx;
+ private final boolean subscribe;
+
+
+ /**
+ * Constructor.
+ * @param ownerId the subscriber or unsubscriber ID
+ * @param ctx the context to subscribe or unsubscribe
+ * @param subscribe true to subscribe, false to unsubscribe
+ */
+ public SubscriptionMessage( String ownerId, MessagingContext ctx, boolean subscribe ) {
+ this.ownerId = ownerId;
+ this.ctx = ctx;
+ this.subscribe = subscribe;
+ }
+
+ public String getOwnerId() {
+ return this.ownerId;
+ }
+
+ public MessagingContext getCtx() {
+ return this.ctx;
+ }
+
+ public boolean isSubscribe() {
+ return this.subscribe;
+ }
+}
diff --git a/core/roboconf-messaging-http/src/main/java/net/roboconf/messaging/http/internal/sockets/AgentWebSocket.java b/core/roboconf-messaging-http/src/main/java/net/roboconf/messaging/http/internal/sockets/AgentWebSocket.java
new file mode 100644
index 00000000..6d785589
--- /dev/null
+++ b/core/roboconf-messaging-http/src/main/java/net/roboconf/messaging/http/internal/sockets/AgentWebSocket.java
@@ -0,0 +1,107 @@
+/**
+ * Copyright 2015 Linagora, Université Joseph Fourier, Floralis
+ *
+ * The present code is developed in the scope of the joint LINAGORA -
+ * Université Joseph Fourier - Floralis research program and is designated
+ * as a "Result" pursuant to the terms and conditions of the LINAGORA
+ * - Université Joseph Fourier - Floralis research program. Each copyright
+ * holder of Results enumerated here above fully & independently holds complete
+ * ownership of the complete Intellectual Property rights applicable to the whole
+ * of said Results, and may freely exploit it in any manner which does not infringe
+ * the moral rights of the other copyright holders.
+ *
+ * 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.
+ */
+
+package net.roboconf.messaging.http.internal.sockets;
+
+import java.io.IOException;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.logging.Logger;
+
+import net.roboconf.core.utils.Utils;
+import net.roboconf.messaging.api.messages.Message;
+import net.roboconf.messaging.http.internal.messages.HttpSerializationUtils;
+
+import org.eclipse.jetty.websocket.api.Session;
+import org.eclipse.jetty.websocket.api.WebSocketListener;
+
+/**
+ * @author Vincent Zurczak - Linagora
+ */
+public class AgentWebSocket implements WebSocketListener {
+
+ private final Logger logger = Logger.getLogger( getClass().getName());
+ private final LinkedBlockingQueue messageQueue;
+ private Session session;
+
+
+ /**
+ * Constructor.
+ * @param messageQueue
+ */
+ public AgentWebSocket( LinkedBlockingQueue messageQueue ) {
+ this.messageQueue = messageQueue;
+ }
+
+
+ @Override
+ public void onWebSocketBinary( byte[] payload, int offset, int len ) {
+
+ this.logger.finest( "A binary message was received." );
+ try {
+ Message msg = HttpSerializationUtils.deserializeObject( payload );
+ this.logger.finest( "The received message was deserialized as an instance of " + msg.getClass().getSimpleName());
+ this.messageQueue.add( msg );
+
+ } catch( ClassNotFoundException | IOException e ) {
+ this.logger.severe( "A message could not be deserialized. => " + e.getClass().getSimpleName());
+ Utils.logException( this.logger, e );
+ }
+ }
+
+
+ @Override
+ public void onWebSocketClose( int statusCode, String reason ) {
+ this.logger.finest( "Websocket closed: " + reason );
+ this.session = null;
+ }
+
+
+ @Override
+ public void onWebSocketConnect( Session session ) {
+ this.logger.finest( "Socket Connected: " + session );
+ this.session = session;
+ }
+
+
+ @Override
+ public void onWebSocketError( Throwable cause ) {
+ this.logger.finest( "Websocket error: " + cause );
+ this.session = null;
+ }
+
+
+ @Override
+ public void onWebSocketText( String message ) {
+ this.logger.finest( "A text message was received but will be ignored: " + message );
+ }
+
+
+ /**
+ * @return the session (should not be null as long as we are connected)
+ */
+ public Session getSession() {
+ return this.session;
+ }
+}
diff --git a/core/roboconf-messaging-http/src/main/java/net/roboconf/messaging/http/internal/sockets/DmWebSocket.java b/core/roboconf-messaging-http/src/main/java/net/roboconf/messaging/http/internal/sockets/DmWebSocket.java
new file mode 100644
index 00000000..0aaf349f
--- /dev/null
+++ b/core/roboconf-messaging-http/src/main/java/net/roboconf/messaging/http/internal/sockets/DmWebSocket.java
@@ -0,0 +1,100 @@
+/**
+ * Copyright 2015 Linagora, Université Joseph Fourier, Floralis
+ *
+ * The present code is developed in the scope of the joint LINAGORA -
+ * Université Joseph Fourier - Floralis research program and is designated
+ * as a "Result" pursuant to the terms and conditions of the LINAGORA
+ * - Université Joseph Fourier - Floralis research program. Each copyright
+ * holder of Results enumerated here above fully & independently holds complete
+ * ownership of the complete Intellectual Property rights applicable to the whole
+ * of said Results, and may freely exploit it in any manner which does not infringe
+ * the moral rights of the other copyright holders.
+ *
+ * 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.
+ */
+
+package net.roboconf.messaging.http.internal.sockets;
+
+import java.io.IOException;
+import java.util.logging.Logger;
+
+import net.roboconf.core.utils.Utils;
+import net.roboconf.messaging.api.messages.Message;
+import net.roboconf.messaging.http.internal.HttpClientFactory;
+import net.roboconf.messaging.http.internal.messages.HttpSerializationUtils;
+
+import org.eclipse.jetty.websocket.api.Session;
+import org.eclipse.jetty.websocket.api.WebSocketListener;
+
+/**
+ * @author Vincent Zurczak - Linagora
+ */
+public class DmWebSocket implements WebSocketListener {
+
+ private final Logger logger = Logger.getLogger( getClass().getName());
+ private Session session;
+ private final HttpClientFactory httpClientFactory;
+
+
+ /**
+ * Constructor.
+ * @param httpClientFactory
+ */
+ public DmWebSocket( HttpClientFactory httpClientFactory ) {
+ this.httpClientFactory = httpClientFactory;
+ }
+
+
+ @Override
+ public void onWebSocketBinary( byte[] payload, int offset, int len ) {
+
+ this.logger.finest( "A binary message was received." );
+ try {
+ Message msg = HttpSerializationUtils.deserializeObject( payload );
+ this.logger.finest( "The received message was deserialized as an instance of " + msg.getClass().getSimpleName());
+
+ this.httpClientFactory.getDmClient().processReceivedMessage( msg, this.session );
+
+ } catch( ClassNotFoundException | IOException e ) {
+ this.logger.severe( "A message could not be deserialized. => " + e.getClass().getSimpleName());
+ Utils.logException( this.logger, e );
+ }
+ }
+
+
+ @Override
+ public void onWebSocketClose( int statusCode, String reason ) {
+ this.logger.finest( "Websocket closed: " + reason );
+ this.session = null;
+ }
+
+
+ @Override
+ public void onWebSocketConnect( Session session ) {
+ this.logger.finest( "Socket Connected: " + session );
+ this.session = session;
+ }
+
+
+ @Override
+ public void onWebSocketError( Throwable cause ) {
+ this.logger.finest( "Websocket error: " + cause );
+ this.session = null;
+ }
+
+
+ @Override
+ public void onWebSocketText( String message ) {
+ this.logger.finest( "A text message was received but will be ignored: " + message );
+ }
+}
diff --git a/core/roboconf-messaging-http/src/main/java/net/roboconf/messaging/http/internal/sockets/DmWebSocketServlet.java b/core/roboconf-messaging-http/src/main/java/net/roboconf/messaging/http/internal/sockets/DmWebSocketServlet.java
new file mode 100644
index 00000000..08e5fd69
--- /dev/null
+++ b/core/roboconf-messaging-http/src/main/java/net/roboconf/messaging/http/internal/sockets/DmWebSocketServlet.java
@@ -0,0 +1,80 @@
+/**
+ * Copyright 2015 Linagora, Université Joseph Fourier, Floralis
+ *
+ * The present code is developed in the scope of the joint LINAGORA -
+ * Université Joseph Fourier - Floralis research program and is designated
+ * as a "Result" pursuant to the terms and conditions of the LINAGORA
+ * - Université Joseph Fourier - Floralis research program. Each copyright
+ * holder of Results enumerated here above fully & independently holds complete
+ * ownership of the complete Intellectual Property rights applicable to the whole
+ * of said Results, and may freely exploit it in any manner which does not infringe
+ * the moral rights of the other copyright holders.
+ *
+ * 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.
+ */
+
+package net.roboconf.messaging.http.internal.sockets;
+
+import net.roboconf.messaging.http.internal.HttpClientFactory;
+
+import org.eclipse.jetty.websocket.servlet.ServletUpgradeRequest;
+import org.eclipse.jetty.websocket.servlet.ServletUpgradeResponse;
+import org.eclipse.jetty.websocket.servlet.WebSocketCreator;
+import org.eclipse.jetty.websocket.servlet.WebSocketServlet;
+import org.eclipse.jetty.websocket.servlet.WebSocketServletFactory;
+
+/**
+ * @author Pierre-Yves Gibello - Linagora
+ */
+public class DmWebSocketServlet extends WebSocketServlet {
+
+ private static final long serialVersionUID = 1359420439902184795L;
+ private final transient HttpClientFactory httpClientFactory;
+
+
+ /**
+ * Constructor.
+ * @param httpClientFactory
+ */
+ public DmWebSocketServlet( HttpClientFactory httpClientFactory ) {
+ this.httpClientFactory = httpClientFactory;
+ }
+
+
+ @Override
+ public void configure( WebSocketServletFactory factory ) {
+ factory.setCreator( new DmWebSocketCreator( this.httpClientFactory ));
+ }
+
+
+ /**
+ * @author Vincent Zurczak - Linagora
+ */
+ private static class DmWebSocketCreator implements WebSocketCreator {
+ private final HttpClientFactory httpClientFactory;
+
+ /**
+ * Constructor.
+ * @param httpClientFactory
+ */
+ public DmWebSocketCreator( HttpClientFactory httpClientFactory ) {
+ this.httpClientFactory = httpClientFactory;
+ }
+
+
+ @Override
+ public Object createWebSocket( ServletUpgradeRequest req, ServletUpgradeResponse resp ) {
+ return new DmWebSocket( this.httpClientFactory );
+ }
+ }
+}
diff --git a/core/roboconf-messaging-http/src/test/java/net/roboconf/messaging/http/internal/HttpClientFactoryTest.java b/core/roboconf-messaging-http/src/test/java/net/roboconf/messaging/http/internal/HttpClientFactoryTest.java
new file mode 100644
index 00000000..c55f0813
--- /dev/null
+++ b/core/roboconf-messaging-http/src/test/java/net/roboconf/messaging/http/internal/HttpClientFactoryTest.java
@@ -0,0 +1,259 @@
+/**
+ * Copyright 2014-2015 Linagora, Université Joseph Fourier, Floralis
+ *
+ * The present code is developed in the scope of the joint LINAGORA -
+ * Université Joseph Fourier - Floralis research program and is designated
+ * as a "Result" pursuant to the terms and conditions of the LINAGORA
+ * - Université Joseph Fourier - Floralis research program. Each copyright
+ * holder of Results enumerated here above fully & independently holds complete
+ * ownership of the complete Intellectual Property rights applicable to the whole
+ * of said Results, and may freely exploit it in any manner which does not infringe
+ * the moral rights of the other copyright holders.
+ *
+ * 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.
+ */
+
+package net.roboconf.messaging.http.internal;
+
+import java.io.IOException;
+import java.util.Dictionary;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.servlet.Servlet;
+
+import net.roboconf.messaging.api.AbstractMessageProcessor;
+import net.roboconf.messaging.api.MessagingConstants;
+import net.roboconf.messaging.api.business.IAgentClient;
+import net.roboconf.messaging.api.business.IDmClient;
+import net.roboconf.messaging.api.factory.MessagingClientFactoryRegistry;
+import net.roboconf.messaging.api.messages.Message;
+import net.roboconf.messaging.api.reconfigurables.ReconfigurableClient;
+import net.roboconf.messaging.api.reconfigurables.ReconfigurableClientAgent;
+import net.roboconf.messaging.api.reconfigurables.ReconfigurableClientDm;
+import net.roboconf.messaging.http.HttpConstants;
+import net.roboconf.messaging.http.internal.clients.HttpAgentClient;
+import net.roboconf.messaging.http.internal.clients.HttpDmClient;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mockito;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.service.http.HttpContext;
+import org.osgi.service.http.HttpService;
+
+/**
+ * Tests for the HTTP messaging factory.
+ * @author Pierre-Yves Gibello - Linagora
+ */
+public class HttpClientFactoryTest {
+
+ private MessagingClientFactoryRegistry registry;
+ private HttpClientFactory factory;
+
+
+ @Before
+ public void registerHttpFactory() {
+
+ this.registry = new MessagingClientFactoryRegistry();
+ this.factory = new HttpClientFactory();
+ this.factory.setHttpServerIp( HttpConstants.DEFAULT_IP );
+ this.factory.setHttpPort( HttpConstants.DEFAULT_PORT );
+ this.registry.addMessagingClientFactory( this.factory );
+ }
+
+
+ @Test
+ public void testFactoryReconfigurationClientDm() throws IllegalAccessException {
+
+ // Create the client DM
+ final ReconfigurableClientDm client = new ReconfigurableClientDm();
+ client.associateMessageProcessor( new AbstractMessageProcessor("dummy.messageProcessor") {
+ @Override
+ protected void processMessage( final Message message ) {
+ // nothing
+ }
+ });
+
+ client.setRegistry(this.registry);
+ client.switchMessagingType(HttpConstants.FACTORY_HTTP);
+
+ // Check the initial (default) configuration.
+ final HttpDmClient client1 = HttpTestUtils.getMessagingClientDm(client);
+ final Map config1 = client1.getConfiguration();
+ Assert.assertEquals( HttpConstants.FACTORY_HTTP, config1.get( MessagingConstants.MESSAGING_TYPE_PROPERTY ));
+ Assert.assertEquals( HttpConstants.DEFAULT_IP, config1.get( HttpConstants.HTTP_SERVER_IP ));
+ Assert.assertEquals( String.valueOf( HttpConstants.DEFAULT_PORT ), config1.get( HttpConstants.HTTP_SERVER_PORT ));
+ Assert.assertEquals( 3, config1.size());
+
+ // Reconfigure the factory.
+ this.factory.setHttpServerIp( "192.168.1.18" );
+ this.factory.setHttpPort( 10234 );
+ this.factory.reconfigure();
+
+ // Check the client has been automatically changed.
+ final HttpDmClient client2 = HttpTestUtils.getMessagingClientDm(client);
+ Assert.assertSame(client1, client2);
+
+ final Map config2 = client2.getConfiguration();
+ Assert.assertEquals( HttpConstants.FACTORY_HTTP, config2.get( MessagingConstants.MESSAGING_TYPE_PROPERTY ));
+ Assert.assertEquals( "192.168.1.18", config2.get( HttpConstants.HTTP_SERVER_IP ));
+ Assert.assertEquals( "10234", config2.get( HttpConstants.HTTP_SERVER_PORT ));
+ Assert.assertEquals( 3, config2.size());
+ }
+
+
+ @Test
+ public void testFactoryReconfigurationClientAgent() throws IllegalAccessException {
+
+ // Create the client DM
+ final ReconfigurableClientAgent client = new ReconfigurableClientAgent();
+ client.associateMessageProcessor( new AbstractMessageProcessor("dummy.messageProcessor") {
+ @Override
+ protected void processMessage( final Message message ) {
+ // nothing
+ }
+ });
+
+ client.setRegistry(this.registry);
+ client.switchMessagingType(HttpConstants.FACTORY_HTTP);
+
+ // Check the initial (default) configuration.
+ final HttpAgentClient client1 = HttpTestUtils.getMessagingClientAgent(client);
+ final Map config1 = client1.getConfiguration();
+ Assert.assertEquals( HttpConstants.FACTORY_HTTP, config1.get( MessagingConstants.MESSAGING_TYPE_PROPERTY ));
+ Assert.assertEquals( HttpConstants.DEFAULT_IP, config1.get(HttpConstants.HTTP_SERVER_IP ));
+ Assert.assertEquals( String.valueOf( HttpConstants.DEFAULT_PORT ), config1.get(HttpConstants.HTTP_SERVER_PORT ));
+
+ // Reconfigure the factory.
+ this.factory.setHttpServerIp("localhost");
+ this.factory.setHttpPort( 10234 );
+ this.factory.reconfigure();
+
+ // Check the client has been automatically changed.
+ final HttpAgentClient client2 = HttpTestUtils.getMessagingClientAgent(client);
+ Assert.assertNotSame(client1, client2);
+
+ final Map config2 = client2.getConfiguration();
+ Assert.assertEquals( HttpConstants.FACTORY_HTTP, config2.get( MessagingConstants.MESSAGING_TYPE_PROPERTY ));
+ Assert.assertEquals( "localhost", config2.get( HttpConstants.HTTP_SERVER_IP ));
+ Assert.assertEquals( "10234", config2.get( HttpConstants.HTTP_SERVER_PORT ));
+ }
+
+
+ @Test
+ public void testStart_dmFound() throws Exception {
+
+ // Mock
+ Bundle b = Mockito.mock( Bundle.class );
+ Mockito.when( b.getSymbolicName()).thenReturn( "net.roboconf.dm" );
+
+ this.factory.httpService = Mockito.mock( HttpService.class );
+ this.factory.bundleContext = Mockito.mock( BundleContext.class );
+ Mockito.when( this.factory.bundleContext.getBundles()).thenReturn( new Bundle[] { b });
+
+ // Start
+ this.factory.start();
+
+ // Check
+ Mockito.verify( this.factory.httpService, Mockito.times( 1 )).registerServlet(
+ Mockito.eq( HttpConstants.DM_SOCKET_PATH ),
+ Mockito.any( Servlet.class ),
+ Mockito.any( Dictionary.class ),
+ Mockito.isNull( HttpContext.class ));
+ }
+
+
+ @Test
+ public void testStart_dmNotFound() throws Exception {
+
+ // Mock
+ Bundle b = Mockito.mock( Bundle.class );
+ Mockito.when( b.getSymbolicName()).thenReturn( "net.roboconf.NOT.dm" );
+
+ this.factory.httpService = Mockito.mock( HttpService.class );
+ this.factory.bundleContext = Mockito.mock( BundleContext.class );
+ Mockito.when( this.factory.bundleContext.getBundles()).thenReturn( new Bundle[] { b });
+
+ // Start
+ this.factory.start();
+
+ // Check
+ Mockito.verifyZeroInteractions( this.factory.httpService );
+ }
+
+
+ @Test
+ public void testStop() throws Exception {
+
+ // No client, no error.
+ Assert.assertEquals( 0, this.factory.agentClients.size());
+ this.factory.stop();
+
+ // Create a client.
+ testFactoryReconfigurationClientAgent();
+
+ // Verify there is a client.
+ Assert.assertEquals( 1, this.factory.agentClients.size());
+ this.factory.stop();
+ Assert.assertEquals( 0, this.factory.agentClients.size());
+ }
+
+
+ @Test
+ @SuppressWarnings({ "rawtypes" })
+ public void testStop_errorOnClose() throws Exception {
+
+ // Mockito does not like classes with generic... <_<
+ ReconfigurableClient parent = Mockito.mock( ReconfigurableClientDm.class );
+ Mockito.doThrow( new IOException( "For tests..." )).when( parent ).closeConnection();
+
+ HttpAgentClient client = new HttpAgentClient( parent, "localhost", 24587 );
+ this.factory.agentClients.add( client );
+ Assert.assertEquals( 1, this.factory.agentClients.size());
+
+ this.factory.stop();
+ Assert.assertEquals( 0, this.factory.agentClients.size());
+ Mockito.verify( parent, Mockito.times( 1 )).closeConnection();
+ }
+
+
+ @Test
+ public void testSetConfiguration() {
+
+ Map map = new HashMap( 0 );
+ Assert.assertFalse( this.factory.setConfiguration( map ));
+
+ map.put( MessagingConstants.MESSAGING_TYPE_PROPERTY, "whatever" );
+ Assert.assertFalse( this.factory.setConfiguration( map ));
+
+ map.put( MessagingConstants.MESSAGING_TYPE_PROPERTY, HttpConstants.FACTORY_HTTP );
+ Assert.assertTrue( this.factory.setConfiguration( map ));
+
+ synchronized( this.factory ) {
+ Assert.assertEquals( HttpConstants.DEFAULT_IP, this.factory.httpServerIp );
+ Assert.assertEquals( HttpConstants.DEFAULT_PORT, this.factory.httpPort );
+ }
+
+ map.put( HttpConstants.HTTP_SERVER_IP, "127.0.0.4" );
+ map.put( HttpConstants.HTTP_SERVER_PORT, "24658" );
+
+ Assert.assertTrue( this.factory.setConfiguration( map ));
+ synchronized( this.factory ) {
+ Assert.assertEquals( "127.0.0.4", this.factory.httpServerIp );
+ Assert.assertEquals( 24658, this.factory.httpPort );
+ }
+ }
+}
diff --git a/core/roboconf-messaging-http/src/test/java/net/roboconf/messaging/http/internal/HttpMessagingTest.java b/core/roboconf-messaging-http/src/test/java/net/roboconf/messaging/http/internal/HttpMessagingTest.java
new file mode 100644
index 00000000..748c56f7
--- /dev/null
+++ b/core/roboconf-messaging-http/src/test/java/net/roboconf/messaging/http/internal/HttpMessagingTest.java
@@ -0,0 +1,167 @@
+/**
+ * Copyright 2014-2015 Linagora, Université Joseph Fourier, Floralis
+ *
+ * The present code is developed in the scope of the joint LINAGORA -
+ * Université Joseph Fourier - Floralis research program and is designated
+ * as a "Result" pursuant to the terms and conditions of the LINAGORA
+ * - Université Joseph Fourier - Floralis research program. Each copyright
+ * holder of Results enumerated here above fully & independently holds complete
+ * ownership of the complete Intellectual Property rights applicable to the whole
+ * of said Results, and may freely exploit it in any manner which does not infringe
+ * the moral rights of the other copyright holders.
+ *
+ * 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.
+ */
+
+package net.roboconf.messaging.http.internal;
+
+import java.io.IOException;
+
+import net.roboconf.messaging.api.factory.MessagingClientFactoryRegistry;
+import net.roboconf.messaging.api.internal.client.AbstractMessagingTest;
+import net.roboconf.messaging.http.HttpConstants;
+import net.roboconf.messaging.http.internal.HttpTestUtils.WebServer;
+
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Assume;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * @author Pierre-Yves Gibello - Linagora
+ */
+public class HttpMessagingTest extends AbstractMessagingTest {
+
+ private static final int ATTEMPTS = 30;
+ private WebServer webServerRunnable;
+ private HttpClientFactory factory;
+
+
+ @Before
+ public void registerHttpFactory() throws InterruptedException {
+
+ // Register a new factory
+ this.factory = new HttpClientFactory();
+ this.factory.setHttpServerIp( HttpConstants.DEFAULT_IP );
+ this.factory.setHttpPort( HttpTestUtils.TEST_PORT );
+
+ this.registry = new MessagingClientFactoryRegistry();
+ this.registry.addMessagingClientFactory( this.factory );
+
+ // Launch a new web server
+ this.webServerRunnable = new WebServer( this.factory );
+ Thread webServerThread = new Thread( this.webServerRunnable, "Test for Roboconf HTTP Messaging" );
+ webServerThread.start();
+
+ // For diagnostic
+ for( int i=0; i the expected type of the internal messaging client.
+ * @return the internal messaging client, or {@code null} if it is not defined, or has the wrong type.
+ * @throws IllegalAccessException if the internal messaging client could not be read.
+ */
+ public static HttpDmClient getMessagingClientDm( ReconfigurableClientDm reconfigurable )
+ throws IllegalAccessException {
+ return TestUtils.getInternalField(reconfigurable, "messagingClient", HttpDmClient.class);
+ }
+
+
+ /**
+ * Gets the delegate messaging client of a reconfigurable messaging client.
+ *
+ * @param reconfigurable the reconfigurable messaging client.
+ * @param type the expected type of the internal messaging client.
+ * @param the expected type of the internal messaging client.
+ * @return the internal messaging client, or {@code null} if it is not defined, or has the wrong type.
+ * @throws IllegalAccessException if the internal messaging client could not be read.
+ */
+ public static HttpAgentClient getMessagingClientAgent( ReconfigurableClientAgent reconfigurable )
+ throws IllegalAccessException {
+ return TestUtils.getInternalField(reconfigurable, "messagingClient", HttpAgentClient.class);
+ }
+
+
+ /**
+ * @author Pierre-Yves Gibello - Linagora
+ */
+ static class WebServer implements Runnable {
+
+ Server server;
+ boolean running;
+ HttpClientFactory httpClientFactory;
+
+
+ /**
+ * Constructor.
+ */
+ public WebServer( HttpClientFactory httpClientFactory ) {
+ this.httpClientFactory = httpClientFactory;
+ }
+
+
+ @Override
+ public void run() {
+
+ try {
+ this.server = new Server();
+ ServerConnector connector = new ServerConnector( this.server );
+ connector.setPort( TEST_PORT );
+ this.server.addConnector( connector );
+
+ // Setup the basic application "context" for this application at "/"
+ // This is also known as the handler tree (in jetty speak)
+ ServletContextHandler context = new ServletContextHandler( ServletContextHandler.SESSIONS );
+ context.setContextPath( "/" );
+ context.addServlet( new ServletHolder( new DmWebSocketServlet( this.httpClientFactory )), HttpConstants.DM_SOCKET_PATH );
+
+ this.server.setHandler( context );
+ this.server.start();
+ // this.server.dump( System.err );
+
+ this.running = true;
+ this.server.join();
+
+ } catch( Exception e ) {
+ e.printStackTrace( System.err );
+ }
+ }
+
+
+ public void stop() {
+
+ try {
+ this.server.stop();
+ this.server.destroy();
+
+ } catch( Exception e ) {
+ e.printStackTrace( System.err );
+ }
+
+ this.running = false;
+ }
+
+
+ public boolean isServerStarted() {
+ return this.server.isStarted();
+ }
+
+
+ public boolean isServerStopped() {
+ return this.server.isStopped();
+ }
+
+
+ public boolean isRunning() {
+ return this.running;
+ }
+ }
+}
diff --git a/core/roboconf-messaging-http/src/test/java/net/roboconf/messaging/http/internal/clients/HttpAgentClientTest.java b/core/roboconf-messaging-http/src/test/java/net/roboconf/messaging/http/internal/clients/HttpAgentClientTest.java
new file mode 100644
index 00000000..efe1e021
--- /dev/null
+++ b/core/roboconf-messaging-http/src/test/java/net/roboconf/messaging/http/internal/clients/HttpAgentClientTest.java
@@ -0,0 +1,71 @@
+/**
+ * Copyright 2015 Linagora, Université Joseph Fourier, Floralis
+ *
+ * The present code is developed in the scope of the joint LINAGORA -
+ * Université Joseph Fourier - Floralis research program and is designated
+ * as a "Result" pursuant to the terms and conditions of the LINAGORA
+ * - Université Joseph Fourier - Floralis research program. Each copyright
+ * holder of Results enumerated here above fully & independently holds complete
+ * ownership of the complete Intellectual Property rights applicable to the whole
+ * of said Results, and may freely exploit it in any manner which does not infringe
+ * the moral rights of the other copyright holders.
+ *
+ * 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.
+ */
+
+package net.roboconf.messaging.http.internal.clients;
+
+import java.io.IOException;
+import java.util.Map;
+
+import net.roboconf.messaging.api.MessagingConstants;
+import net.roboconf.messaging.http.HttpConstants;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+/**
+ * @author Vincent Zurczak - Linagora
+ */
+public class HttpAgentClientTest {
+
+ @Test
+ public void testBasics() throws Exception {
+
+ // Invalid connection, etc.
+ HttpAgentClient client = new HttpAgentClient( null, "localhost", 9898 );
+ Assert.assertFalse( client.isConnected());
+ client.closeConnection();
+
+ try {
+ client.openConnection();
+ Assert.fail( "An exception was expected." );
+
+ } catch( IOException e ) {
+ // nothing
+ }
+
+ Assert.assertFalse( client.isConnected());
+ client.closeConnection();
+ client.deleteMessagingServerArtifacts( null );
+
+ // Configuration
+ Assert.assertEquals( HttpConstants.FACTORY_HTTP, client.getMessagingType());
+ Map config = client.getConfiguration();
+ Assert.assertEquals( 3, config.size());
+
+ Assert.assertEquals( HttpConstants.FACTORY_HTTP, config.get( MessagingConstants.MESSAGING_TYPE_PROPERTY ));
+ Assert.assertEquals( "localhost", config.get( HttpConstants.HTTP_SERVER_IP ));
+ Assert.assertEquals( "9898", config.get( HttpConstants.HTTP_SERVER_PORT ));
+ }
+}
diff --git a/core/roboconf-messaging-http/src/test/java/net/roboconf/messaging/http/internal/sockets/AgentWebSocketTest.java b/core/roboconf-messaging-http/src/test/java/net/roboconf/messaging/http/internal/sockets/AgentWebSocketTest.java
new file mode 100644
index 00000000..c764a877
--- /dev/null
+++ b/core/roboconf-messaging-http/src/test/java/net/roboconf/messaging/http/internal/sockets/AgentWebSocketTest.java
@@ -0,0 +1,62 @@
+/**
+ * Copyright 2015 Linagora, Université Joseph Fourier, Floralis
+ *
+ * The present code is developed in the scope of the joint LINAGORA -
+ * Université Joseph Fourier - Floralis research program and is designated
+ * as a "Result" pursuant to the terms and conditions of the LINAGORA
+ * - Université Joseph Fourier - Floralis research program. Each copyright
+ * holder of Results enumerated here above fully & independently holds complete
+ * ownership of the complete Intellectual Property rights applicable to the whole
+ * of said Results, and may freely exploit it in any manner which does not infringe
+ * the moral rights of the other copyright holders.
+ *
+ * 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.
+ */
+
+package net.roboconf.messaging.http.internal.sockets;
+
+import java.util.concurrent.LinkedBlockingQueue;
+
+import net.roboconf.messaging.api.messages.Message;
+import net.roboconf.messaging.http.internal.sockets.AgentWebSocket;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+/**
+ * @author Vincent Zurczak - Linagora
+ */
+public class AgentWebSocketTest {
+
+ @Test
+ public void testBasics() {
+
+ LinkedBlockingQueue messageQueue = new LinkedBlockingQueue<> ();
+ AgentWebSocket socket = new AgentWebSocket( messageQueue );
+ socket.onWebSocketError( null );
+ socket.onWebSocketText( "ignored" );
+
+ Assert.assertEquals( 0, messageQueue.size());
+ }
+
+
+ @Test
+ public void testBinaryMessageInError() {
+
+ LinkedBlockingQueue messageQueue = new LinkedBlockingQueue<> ();
+ AgentWebSocket socket = new AgentWebSocket( messageQueue );
+ socket.onWebSocketBinary( new byte[1], 0, 1 );
+
+ Assert.assertEquals( 0, messageQueue.size());
+ }
+}
diff --git a/core/roboconf-messaging-http/src/test/java/net/roboconf/messaging/http/internal/sockets/DmWebSocketTest.java b/core/roboconf-messaging-http/src/test/java/net/roboconf/messaging/http/internal/sockets/DmWebSocketTest.java
new file mode 100644
index 00000000..26934f69
--- /dev/null
+++ b/core/roboconf-messaging-http/src/test/java/net/roboconf/messaging/http/internal/sockets/DmWebSocketTest.java
@@ -0,0 +1,55 @@
+/**
+ * Copyright 2015 Linagora, Université Joseph Fourier, Floralis
+ *
+ * The present code is developed in the scope of the joint LINAGORA -
+ * Université Joseph Fourier - Floralis research program and is designated
+ * as a "Result" pursuant to the terms and conditions of the LINAGORA
+ * - Université Joseph Fourier - Floralis research program. Each copyright
+ * holder of Results enumerated here above fully & independently holds complete
+ * ownership of the complete Intellectual Property rights applicable to the whole
+ * of said Results, and may freely exploit it in any manner which does not infringe
+ * the moral rights of the other copyright holders.
+ *
+ * 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.
+ */
+
+package net.roboconf.messaging.http.internal.sockets;
+
+import net.roboconf.messaging.http.internal.HttpClientFactory;
+
+import org.junit.Test;
+import org.mockito.Mockito;
+
+/**
+ * @author Vincent Zurczak - Linagora
+ */
+public class DmWebSocketTest {
+
+ @Test
+ public void testBasics() {
+
+ HttpClientFactory httpClientFatory = Mockito.mock( HttpClientFactory.class );
+ DmWebSocket socket = new DmWebSocket( httpClientFatory );
+ socket.onWebSocketError( null );
+ socket.onWebSocketText( "ignored" );
+ }
+
+
+ @Test
+ public void testBinaryMessageInError() {
+
+ HttpClientFactory httpClientFatory = Mockito.mock( HttpClientFactory.class );
+ DmWebSocket socket = new DmWebSocket( httpClientFatory );
+ socket.onWebSocketBinary( new byte[1], 0, 1 );
+ }
+}
diff --git a/core/roboconf-messaging-rabbitmq/metadata.xml b/core/roboconf-messaging-rabbitmq/metadata.xml
index abf42c95..8a399fcd 100644
--- a/core/roboconf-messaging-rabbitmq/metadata.xml
+++ b/core/roboconf-messaging-rabbitmq/metadata.xml
@@ -6,10 +6,7 @@
-
-
-
-
+
diff --git a/core/roboconf-messaging-rabbitmq/pom.xml b/core/roboconf-messaging-rabbitmq/pom.xml
index cb2fa42d..67ef0c8d 100644
--- a/core/roboconf-messaging-rabbitmq/pom.xml
+++ b/core/roboconf-messaging-rabbitmq/pom.xml
@@ -97,6 +97,12 @@
${ipojo.version}test
+
+
+ org.mockito
+ mockito-core
+ test
+
diff --git a/core/roboconf-messaging-rabbitmq/src/main/java/net/roboconf/messaging/rabbitmq/RabbitMqConstants.java b/core/roboconf-messaging-rabbitmq/src/main/java/net/roboconf/messaging/rabbitmq/RabbitMqConstants.java
index 38e6819f..adc9b5e7 100644
--- a/core/roboconf-messaging-rabbitmq/src/main/java/net/roboconf/messaging/rabbitmq/RabbitMqConstants.java
+++ b/core/roboconf-messaging-rabbitmq/src/main/java/net/roboconf/messaging/rabbitmq/RabbitMqConstants.java
@@ -31,37 +31,38 @@
* Constants related to the RabbitMQ messaging client factory.
* @author Pierre Bourret - Université Joseph Fourier
*/
-public final class RabbitMqConstants {
-
- /**
- * Constructor.
- */
- private RabbitMqConstants() {
- // nothing
- }
+public interface RabbitMqConstants {
/**
* The factory's name for RabbitMQ clients.
*/
- public static final String RABBITMQ_FACTORY_TYPE = "rabbitmq";
+ String FACTORY_RABBITMQ = "rabbitmq";
/**
* The prefix for all RabbitMQ-related properties.
*/
- private static final String RABBITMQ_PROPERTY_PREFIX = MessagingConstants.MESSAGING_PROPERTY_PREFIX + "." + RABBITMQ_FACTORY_TYPE;
+ String RABBITMQ_PROPERTY_PREFIX = MessagingConstants.MESSAGING_PROPERTY_PREFIX + "." + FACTORY_RABBITMQ;
/**
* Messaging property holding the RabbitMQ server IP (or host). Defaults to {@code "localhost"}.
*/
- public static final String RABBITMQ_SERVER_IP = RABBITMQ_PROPERTY_PREFIX + ".server.ip";
+ String RABBITMQ_SERVER_IP = RABBITMQ_PROPERTY_PREFIX + ".server.ip";
/**
* Messaging property holding the RabbitMQ server username. Defaults to {@code "guest"}.
*/
- public static final String RABBITMQ_SERVER_USERNAME = RABBITMQ_PROPERTY_PREFIX + ".server.username";
+ String RABBITMQ_SERVER_USERNAME = RABBITMQ_PROPERTY_PREFIX + ".server.username";
/**
* Messaging property holding the RabbitMQ server password. Defaults to {@code "guest"}.
*/
- public static final String RABBITMQ_SERVER_PASSWORD = RABBITMQ_PROPERTY_PREFIX + ".server.password";
+ String RABBITMQ_SERVER_PASSWORD = RABBITMQ_PROPERTY_PREFIX + ".server.password";
+
+
+ String EXHANGE_INTER_APP = "roboconf.inter-app";
+ String EXHANGE_DM = "roboconf.dm";
+
+
+ String DEFAULT_IP = "localhost";
+ String GUEST = "guest";
}
diff --git a/core/roboconf-messaging-rabbitmq/src/main/java/net/roboconf/messaging/rabbitmq/internal/RabbitMqClient.java b/core/roboconf-messaging-rabbitmq/src/main/java/net/roboconf/messaging/rabbitmq/internal/RabbitMqClient.java
index 59b4ea31..0cd988b4 100644
--- a/core/roboconf-messaging-rabbitmq/src/main/java/net/roboconf/messaging/rabbitmq/internal/RabbitMqClient.java
+++ b/core/roboconf-messaging-rabbitmq/src/main/java/net/roboconf/messaging/rabbitmq/internal/RabbitMqClient.java
@@ -25,6 +25,7 @@
package net.roboconf.messaging.rabbitmq.internal;
+import java.io.IOException;
import java.lang.ref.WeakReference;
import java.util.Collections;
import java.util.LinkedHashMap;
@@ -32,51 +33,41 @@
import java.util.concurrent.LinkedBlockingQueue;
import java.util.logging.Logger;
+import net.roboconf.core.model.beans.Application;
import net.roboconf.messaging.api.MessagingConstants;
-import net.roboconf.messaging.api.client.IClient;
+import net.roboconf.messaging.api.extensions.IMessagingClient;
+import net.roboconf.messaging.api.extensions.MessagingContext;
+import net.roboconf.messaging.api.extensions.MessagingContext.RecipientKind;
import net.roboconf.messaging.api.messages.Message;
import net.roboconf.messaging.api.reconfigurables.ReconfigurableClient;
+import net.roboconf.messaging.api.utils.MessagingUtils;
+import net.roboconf.messaging.api.utils.SerializationUtils;
import net.roboconf.messaging.rabbitmq.RabbitMqConstants;
+import net.roboconf.messaging.rabbitmq.internal.utils.ListeningThread;
+import net.roboconf.messaging.rabbitmq.internal.utils.RabbitMqUtils;
+import net.roboconf.messaging.rabbitmq.internal.utils.RoboconfReturnListener;
+import com.rabbitmq.client.AMQP.BasicProperties;
import com.rabbitmq.client.Channel;
+import com.rabbitmq.client.ConnectionFactory;
+import com.rabbitmq.client.QueueingConsumer;
/**
* Common RabbitMQ client-related stuffs.
* @author Pierre Bourret - Université Joseph Fourier
+ * @author Vincent Zurczak - Linagora
*/
-public abstract class RabbitMqClient implements IClient {
+public class RabbitMqClient implements IMessagingClient {
- /**
- * The default value of the IP address property.
- *
- * By default, the client assumes the RabbitMQ server is hosted on {@code localhost}, with the default port.
- *
- */
- static final String DEFAULT_IP = "localhost";
-
- /**
- * The default value of the username property.
- *
- * By default, the client connects as {@code guest}, the default account only available locally.
- *
- */
- static final String DEFAULT_USERNAME = "guest";
-
- /**
- * The default value of the password property.
- *
- * By default, the client connects as {@code guest}, the default account only available locally. This property
- * holds
- * the default password for this default account.
- *
- */
- static final String DEFAULT_PASSWORD = "guest";
+ private final Logger logger = Logger.getLogger(this.getClass().getName());
+ private final String messageServerIp, messageServerUsername, messageServerPassword;
+ private final WeakReference> reconfigurable;
+ private LinkedBlockingQueue messageQueue;
+ private RecipientKind ownerKind;
+ private String applicationName, scopedInstancePath;
- protected final Logger logger = Logger.getLogger(this.getClass().getName());
- protected final String messageServerIp, messageServerUsername, messageServerPassword;
- private final WeakReference> reconfigurable;
- protected LinkedBlockingQueue messageQueue;
+ String consumerTag;
Channel channel;
@@ -88,10 +79,24 @@ public abstract class RabbitMqClient implements IClient {
* @param password
*/
protected RabbitMqClient( ReconfigurableClient> reconfigurable, String ip, String username, String password ) {
- this.reconfigurable = new WeakReference>(reconfigurable);
+ this( reconfigurable, ip, username, password, reconfigurable.getOwnerKind());
+ }
+
+
+ /**
+ * Constructor.
+ * @param reconfigurable
+ * @param ip
+ * @param username
+ * @param password
+ * @param ownerKind
+ */
+ protected RabbitMqClient( ReconfigurableClient> reconfigurable, String ip, String username, String password, RecipientKind ownerKind ) {
+ this.reconfigurable = new WeakReference>( reconfigurable );
this.messageServerIp = ip;
this.messageServerUsername = username;
this.messageServerPassword = password;
+ this.ownerKind = ownerKind;
}
@@ -104,7 +109,7 @@ public final ReconfigurableClient> getReconfigurableClient() {
@Override
- public final synchronized void setMessageQueue( LinkedBlockingQueue messageQueue ) {
+ public final void setMessageQueue( LinkedBlockingQueue messageQueue ) {
this.messageQueue = messageQueue;
}
@@ -117,17 +122,183 @@ public final synchronized boolean isConnected() {
@Override
public final String getMessagingType() {
- return RabbitMqConstants.RABBITMQ_FACTORY_TYPE;
+ return RabbitMqConstants.FACTORY_RABBITMQ;
}
@Override
public final Map getConfiguration() {
+
final Map configuration = new LinkedHashMap<>();
- configuration.put(MessagingConstants.MESSAGING_TYPE_PROPERTY, RabbitMqConstants.RABBITMQ_FACTORY_TYPE);
+ configuration.put(MessagingConstants.MESSAGING_TYPE_PROPERTY, RabbitMqConstants.FACTORY_RABBITMQ);
configuration.put(RabbitMqConstants.RABBITMQ_SERVER_IP, this.messageServerIp);
configuration.put(RabbitMqConstants.RABBITMQ_SERVER_USERNAME, this.messageServerUsername);
configuration.put(RabbitMqConstants.RABBITMQ_SERVER_PASSWORD, this.messageServerPassword);
+
return Collections.unmodifiableMap(configuration);
}
+
+
+ @Override
+ public void setOwnerProperties( RecipientKind ownerKind, String applicationName, String scopedInstancePath ) {
+
+ this.ownerKind = ownerKind;
+ this.applicationName = applicationName;
+ this.scopedInstancePath = scopedInstancePath;
+
+ this.logger.fine( "Owner properties changed to " + getId());
+ }
+
+
+ @Override
+ public void openConnection() throws IOException {
+
+ // Already connected? Do nothing
+ this.logger.info( getId() + " is opening a connection to RabbitMQ." );
+ if( isConnected()) {
+ this.logger.info( getId() + " has already a connection to RabbitMQ." );
+ return;
+ }
+
+ // Initialize the connection
+ ConnectionFactory factory = new ConnectionFactory();
+ RabbitMqUtils.configureFactory( factory, this.messageServerIp, this.messageServerUsername, this.messageServerPassword );
+ this.channel = factory.newConnection().createChannel();
+ this.logger.info( getId() + " established a new connection with RabbitMQ. Channel # " + this.channel.getChannelNumber());
+
+ // Be notified when a message does not arrive in a queue (i.e. nobody is listening)
+ this.channel.addReturnListener( new RoboconfReturnListener());
+
+ // Declare the exchanges.
+ RabbitMqUtils.declareGlobalExchanges( this.channel );
+ RabbitMqUtils.declareApplicationExchanges( this.applicationName, this.channel );
+
+ // Declare the dedicated queue.
+ String queueName = getQueueName();
+ this.channel.queueDeclare( queueName, true, false, true, null );
+
+ // Start listening to messages.
+ QueueingConsumer consumer = new QueueingConsumer( this.channel );
+ this.consumerTag = this.channel.basicConsume( queueName, true, consumer );
+
+ String threadName = "Roboconf - Queue listener for " + getId();
+ new ListeningThread( threadName, this.logger, consumer, this.messageQueue, getId()).start();
+ }
+
+
+ @Override
+ public void closeConnection() throws IOException {
+
+ StringBuilder sb = new StringBuilder( getId() + " is closing its connection to RabbitMQ." );
+ if( this.channel != null )
+ sb.append(" Channel # ").append(this.channel.getChannelNumber());
+
+ this.logger.info( sb.toString());
+
+ // Stop listening messages
+ if( this.channel != null
+ && this.channel.isOpen()
+ && this.consumerTag != null )
+ this.channel.basicCancel( this.consumerTag );
+
+ // Close the connection
+ this.consumerTag = null;
+ if( isConnected())
+ RabbitMqUtils.closeConnection( this.channel );
+
+ this.channel = null;
+ }
+
+
+ @Override
+ public void deleteMessagingServerArtifacts( Application application )
+ throws IOException {
+
+ // We delete the application exchanges. There is only one now.
+ this.channel.exchangeDelete( RabbitMqUtils.buildExchangeNameForAgent( application.getName()));
+ this.logger.fine( "Messaging artifacts were deleted for application " + application );
+ // Queues are deleted automatically by RabbitMQ.
+ // Global exchanges do not need to be deleted. There are only 2.
+ }
+
+
+ @Override
+ public void publish( MessagingContext ctx, Message msg ) throws IOException {
+
+ // To which exchange?
+ String exchangeName = RabbitMqUtils.buildExchangeName( ctx );
+
+ // With which routing key?
+ String routingKey = ctx.getTopicName();
+
+ // Log a trace.
+ this.logger.fine( "A message is about to be published to " + exchangeName + " with routing key = " + routingKey );
+
+ // Special case for the DM sending to the DM.
+ // To prevent spamming and residual messages, messages sent by the DM
+ // (to itself or its siblings) have a life span of 500 ms. If there is no
+ // client connected during this period, the message will be dropped.
+ BasicProperties props = null;
+ if( ctx.getKind() == RecipientKind.DM ) {
+ props = new BasicProperties.Builder().expiration( "500" ).build();
+ }
+
+ // Do we want to be notified when a message is not delivered to anyone?
+ // Yes, when the DM sends a message to an agent or when an agent sends a
+ // message to the DM. If the message is not delivered to any queue,
+ // the client will be notified (RoboconfReturnListener).
+ boolean mandatory = false;
+ if( this.ownerKind == RecipientKind.DM && this.ownerKind != ctx.getKind()
+ || this.ownerKind == RecipientKind.AGENTS && ctx.getKind() == RecipientKind.DM )
+ mandatory = true;
+
+ // Send the message.
+ this.channel.basicPublish(
+ exchangeName, // The exchange name
+ routingKey, // The routing key
+ mandatory, // Mandatory => we want it to be delivered
+ false, // Useless, RabbitMQ does not support it for now.
+ props, // The publish properties
+ SerializationUtils.serializeObject( msg ));
+ }
+
+
+ @Override
+ public void subscribe( MessagingContext ctx ) throws IOException {
+
+ // Subscribing means creating a routing key between an exchange and a queue.
+ String exchangeName = RabbitMqUtils.buildExchangeName( ctx );
+ String queueName = getQueueName();
+ this.logger.fine( "Binding queue " + queueName + " and exchange " + exchangeName + " with routing key = " + ctx.getTopicName());
+ this.channel.queueBind( queueName, exchangeName, ctx.getTopicName());
+ }
+
+
+ @Override
+ public void unsubscribe( MessagingContext ctx ) throws IOException {
+
+ // Un-subscribing means deleting a routing key between an exchange and a queue.
+ String exchangeName = RabbitMqUtils.buildExchangeName( ctx );
+ String queueName = getQueueName();
+ this.logger.fine( "Unbinding queue " + queueName + " and exchange " + exchangeName + " with routing key = " + ctx.getTopicName());
+ this.channel.queueUnbind( queueName, exchangeName, ctx.getTopicName());
+
+ }
+
+
+ String getQueueName() {
+
+ String queueName;
+ if( this.ownerKind == RecipientKind.DM )
+ queueName = "roboconf.queue.dm";
+ else
+ queueName = this.applicationName + "." + MessagingUtils.escapeInstancePath( this.scopedInstancePath );
+
+ return queueName;
+ }
+
+
+ String getId() {
+ return this.ownerKind == RecipientKind.DM ? "DM" : this.scopedInstancePath + " @ " + this.applicationName;
+ }
}
diff --git a/core/roboconf-messaging-rabbitmq/src/main/java/net/roboconf/messaging/rabbitmq/internal/RabbitMqClientAgent.java b/core/roboconf-messaging-rabbitmq/src/main/java/net/roboconf/messaging/rabbitmq/internal/RabbitMqClientAgent.java
deleted file mode 100644
index a5a0cd32..00000000
--- a/core/roboconf-messaging-rabbitmq/src/main/java/net/roboconf/messaging/rabbitmq/internal/RabbitMqClientAgent.java
+++ /dev/null
@@ -1,431 +0,0 @@
-/**
- * Copyright 2014-2015 Linagora, Université Joseph Fourier, Floralis
- *
- * The present code is developed in the scope of the joint LINAGORA -
- * Université Joseph Fourier - Floralis research program and is designated
- * as a "Result" pursuant to the terms and conditions of the LINAGORA
- * - Université Joseph Fourier - Floralis research program. Each copyright
- * holder of Results enumerated here above fully & independently holds complete
- * ownership of the complete Intellectual Property rights applicable to the whole
- * of said Results, and may freely exploit it in any manner which does not infringe
- * the moral rights of the other copyright holders.
- *
- * 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.
- */
-
-package net.roboconf.messaging.rabbitmq.internal;
-
-import java.io.IOException;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.ConcurrentHashMap;
-
-import net.roboconf.core.model.beans.Instance;
-import net.roboconf.core.model.helpers.InstanceHelpers;
-import net.roboconf.core.model.helpers.VariableHelpers;
-import net.roboconf.core.utils.Utils;
-import net.roboconf.messaging.api.client.IAgentClient;
-import net.roboconf.messaging.api.client.ListenerCommand;
-import net.roboconf.messaging.api.messages.Message;
-import net.roboconf.messaging.api.messages.from_agent_to_agent.MsgCmdAddImport;
-import net.roboconf.messaging.api.messages.from_agent_to_agent.MsgCmdRemoveImport;
-import net.roboconf.messaging.api.messages.from_agent_to_agent.MsgCmdRequestImport;
-import net.roboconf.messaging.api.reconfigurables.ReconfigurableClientAgent;
-import net.roboconf.messaging.api.utils.SerializationUtils;
-import net.roboconf.messaging.rabbitmq.internal.utils.ListeningThread;
-import net.roboconf.messaging.rabbitmq.internal.utils.MessagingContext;
-import net.roboconf.messaging.rabbitmq.internal.utils.RabbitMqUtils;
-
-import com.rabbitmq.client.ConnectionFactory;
-import com.rabbitmq.client.QueueingConsumer;
-
-/**
- * The RabbitMQ client for an agent.
- * @author Vincent Zurczak - Linagora
- * @author Pierre Bourret - Université Joseph Fourier
- */
-public class RabbitMqClientAgent extends RabbitMqClient implements IAgentClient {
-
- private static final String THOSE_THAT_EXPORT = "those.that.export.";
- public static final String THOSE_THAT_IMPORT = "those.that.import.";
-
- private final ConcurrentHashMap externalExports = new ConcurrentHashMap<> ();
- private String applicationName, scopedInstancePath;
- String consumerTag;
-
-
- /**
- * Constructor.
- * @param reconfigurable
- * @param ip
- * @param username
- * @param password
- */
- public RabbitMqClientAgent( final ReconfigurableClientAgent reconfigurable, String ip, String username, String password ) {
- super(reconfigurable, ip, username, password);
- }
-
-
- /*
- * (non-Javadoc)
- * @see net.roboconf.messaging.api.client.IAgentClient
- * #setScopedInstancePath(java.lang.String)
- */
- @Override
- public void setScopedInstancePath( String scopedInstancePath ) {
- this.scopedInstancePath = scopedInstancePath;
- }
-
-
- /*
- * (non-Javadoc)
- * @see net.roboconf.messaging.api.client.IAgentClient
- * #setExternalMapping(java.util.Map)
- */
- @Override
- public void setExternalMapping( Map externalExports ) {
-
- // Should be invoked only once, so...
- this.externalExports.clear();
- if( externalExports != null )
- this.externalExports.putAll( externalExports );
- }
-
-
- /*
- * (non-Javadoc)
- * @see net.roboconf.messaging.api.client.IClient
- * #openConnection()
- */
- @Override
- public synchronized void openConnection() throws IOException {
-
- // Already connected? Do nothing
- this.logger.info( "Agent '" + getAgentId() + "' is opening a connection to RabbitMQ." );
- if( this.channel != null ) {
- this.logger.info( "Agent '" + getAgentId() + "' has already a connection to RabbitMQ." );
- return;
- }
-
- // Initialize the connection
- ConnectionFactory factory = new ConnectionFactory();
- RabbitMqUtils.configureFactory( factory, this.messageServerIp, this.messageServerUsername, this.messageServerPassword );
- this.channel = factory.newConnection().createChannel();
- this.logger.info( "Agent '" + getAgentId() + "' established a new connection with RabbitMQ. Channel # " + this.channel.getChannelNumber());
-
- // We start listening the queue here
- // We declare both exchanges.
- // This is for cases where the agent would try to contact the DM
- // before the DM was started. In such cases, the RabbitMQ client
- // will get an error. This error will in turn close the channel and it
- // won't be usable anymore.
- RabbitMqUtils.declareApplicationExchanges( this.applicationName, this.channel );
- // This is really important.
-
- // Queue declaration is idem-potent
- String queueName = getQueueName();
- this.channel.queueDeclare( queueName, true, false, true, null );
-
- // Start to listen to the queue
- final QueueingConsumer consumer = new QueueingConsumer( this.channel );
- this.consumerTag = this.channel.basicConsume( queueName, true, consumer );
-
- String threadName = "Roboconf - Queue listener for Agent " + this.scopedInstancePath;
- String id = "Agent '" + getAgentId() + "'";
- new ListeningThread( threadName, this.logger, consumer, this.messageQueue, id ).start();
- }
-
-
- /* (non-Javadoc)
- * @see net.roboconf.messaging.api.client.IClient#closeConnection()
- */
- @Override
- public synchronized void closeConnection() throws IOException {
-
- StringBuilder sb = new StringBuilder( "Agent '" + getAgentId());
- sb.append( "' is closing its connection to RabbitMQ.");
- if( this.channel != null )
- sb.append(" Channel # ").append(this.channel.getChannelNumber());
-
- this.logger.info( sb.toString());
-
- // Stop listening messages
- if( this.channel != null
- && this.channel.isOpen()
- && this.consumerTag != null )
- this.channel.basicCancel( this.consumerTag );
-
- // Close the connection
- this.consumerTag = null;
- if( isConnected())
- RabbitMqUtils.closeConnection( this.channel );
-
- this.channel = null;
- }
-
-
- /* (non-Javadoc)
- * @see net.roboconf.messaging.api.client.IAgentClient#setApplicationName(java.lang.String)
- */
- @Override
- public synchronized void setApplicationName( String applicationName ) {
- this.applicationName = applicationName;
- }
-
-
- /* (non-Javadoc)
- * @see net.roboconf.messaging.api.client.IAgentClient
- * #publishExports(net.roboconf.core.model.beans.Instance)
- */
- @Override
- public void publishExports( Instance instance ) throws IOException {
-
- // For all the exported variables...
- // ... find the component or facet name...
- Set names = VariableHelpers.findPrefixesForExportedVariables( instance );
- if( names.isEmpty())
- this.logger.fine( "Agent '" + getAgentId() + "' is publishing its exports." );
-
- else for( String facetOrComponentName : names ) {
- publishExports( instance, facetOrComponentName );
- }
- }
-
-
- /* (non-Javadoc)
- * @see net.roboconf.messaging.api.client.IAgentClient
- * #publishExports(net.roboconf.core.model.beans.Instance)
- */
- @Override
- public synchronized void publishExports( Instance instance, String facetOrComponentName ) throws IOException {
- this.logger.fine( "Agent '" + getAgentId() + "' is publishing its exports prefixed by " + facetOrComponentName + "." );
-
- // Find the variables to export.
- Map toPublishInternally = new HashMap<> ();
- Map toPublishExternally = new HashMap<> ();
-
- Map exports = InstanceHelpers.findAllExportedVariables( instance );
- for( Map.Entry entry : exports.entrySet()) {
-
- // Publishing an export may be about a facet or component name or about an external prefix.
- // If an "internal prefix" is required, export both the internal and associated external, if any.
- String alias = this.externalExports.get( entry.getKey());
- if( entry.getKey().startsWith( facetOrComponentName + "." )) {
- toPublishInternally.put( entry.getKey(), entry.getValue());
- if( alias != null )
- toPublishExternally.put( alias, entry.getValue());
- }
-
- // If an external prefix is required, only export the external variables
- else if( alias != null && alias.startsWith( facetOrComponentName + "." )) {
- toPublishExternally.put( alias, entry.getValue());
- }
- }
-
- // Publish the internal exports
- if( ! toPublishInternally.isEmpty()) {
- MsgCmdAddImport message = new MsgCmdAddImport(
- this.applicationName,
- facetOrComponentName,
- InstanceHelpers.computeInstancePath( instance ),
- toPublishInternally );
-
- this.channel.basicPublish(
- RabbitMqUtils.buildExchangeName( this.applicationName, false ),
- THOSE_THAT_IMPORT + facetOrComponentName,
- null,
- SerializationUtils.serializeObject( message ));
- }
-
- // Publish the external ones, if any
- if( ! toPublishExternally.isEmpty()) {
- String varName = toPublishExternally.keySet().iterator().next();
- String appTplName = VariableHelpers.parseVariableName( varName ).getKey();
-
- MsgCmdAddImport message = new MsgCmdAddImport(
- this.applicationName,
- appTplName,
- InstanceHelpers.computeInstancePath( instance ),
- toPublishExternally );
-
- this.channel.basicPublish(
- MessagingContext.INTER_APP,
- THOSE_THAT_IMPORT + appTplName,
- null,
- SerializationUtils.serializeObject( message ));
- }
- }
-
-
- /* (non-Javadoc)
- * @see net.roboconf.messaging.api.client.IAgentClient
- * #unpublishExports(net.roboconf.core.model.beans.Instance)
- */
- @Override
- public synchronized void unpublishExports( Instance instance ) throws IOException {
- this.logger.fine( "Agent '" + getAgentId() + "' is un-publishing its exports." );
-
- // For all the exported variables...
- // ... find the component or facet name...
- for( MessagingContext ctx : MessagingContext.forExportedVariables( this.applicationName, instance, this.externalExports )) {
-
- // Log here, for debug
- this.logger.fine( "Agent '" + getAgentId() + "' is un-publishing its exports (" + ctx + ")." );
-
- // Un-publish them
- MsgCmdRemoveImport message = new MsgCmdRemoveImport(
- this.applicationName,
- ctx.getRoutingKeySuffix(),
- InstanceHelpers.computeInstancePath( instance ));
-
- this.channel.basicPublish(
- ctx.getExchangeName(),
- THOSE_THAT_IMPORT + ctx.getRoutingKeySuffix(),
- null,
- SerializationUtils.serializeObject( message ));
- }
- }
-
-
- /* (non-Javadoc)
- * @see net.roboconf.messaging.api.client.IAgentClient
- * #listenToRequestsFromOtherAgents(net.roboconf.messaging.api.client.IClient.ListenerCommand, net.roboconf.core.model.beans.Instance)
- */
- @Override
- public synchronized void listenToRequestsFromOtherAgents( ListenerCommand command, Instance instance )
- throws IOException {
-
- String queueName = getQueueName();
-
- // With RabbitMQ, and for agents, listening to others means
- // create a binding between the "agents" exchange and the agent's queue.
- for( MessagingContext ctx : MessagingContext.forExportedVariables( this.applicationName, instance, this.externalExports )) {
-
- // On which routing key do request go? Those.that.export...
- String routingKey = THOSE_THAT_EXPORT + ctx.getRoutingKeySuffix();
- if( command == ListenerCommand.START ) {
- this.logger.fine( "Agent '" + getAgentId() + "' starts listening requests from other agents (" + ctx + ")." );
- this.channel.queueBind( queueName, ctx.getExchangeName(), routingKey );
-
- } else {
- this.logger.fine( "Agent '" + getAgentId() + "' stops listening requests from other agents (" + ctx + ")." );
- this.channel.queueUnbind( queueName, ctx.getExchangeName(), routingKey );
- }
- }
- }
-
-
- /* (non-Javadoc)
- * @see net.roboconf.messaging.api.client.IAgentClient
- * #requestExportsFromOtherAgents(net.roboconf.core.model.beans.Instance)
- */
- @Override
- public synchronized void requestExportsFromOtherAgents( Instance instance ) throws IOException {
- this.logger.fine( "Agent '" + getAgentId() + "' is requesting exports from other agents." );
-
- // For all the imported variables...
- // ... find the component or facet name...
- for( MessagingContext ctx : MessagingContext.forImportedVariables( this.applicationName, instance )) {
-
- // Log here, for debug
- this.logger.fine( "Agent '" + getAgentId() + "' is requesting exports from other agents (" + ctx + ")." );
-
- // ... and ask to publish them.
- // Grouping variable requests by prefix reduces the number of messages.
- MsgCmdRequestImport message = new MsgCmdRequestImport( this.applicationName, ctx.getRoutingKeySuffix());
- this.channel.basicPublish(
- ctx.getExchangeName(),
- THOSE_THAT_EXPORT + ctx.getRoutingKeySuffix(),
- null,
- SerializationUtils.serializeObject( message ));
- }
- }
-
-
- /* (non-Javadoc)
- * @see net.roboconf.messaging.api.client.IAgentClient
- * #listenToExportsFromOtherAgents(net.roboconf.messaging.api.client.IClient.ListenerCommand, net.roboconf.core.model.beans.Instance)
- */
- @Override
- public synchronized void listenToExportsFromOtherAgents( ListenerCommand command, Instance instance ) throws IOException {
- String queueName = getQueueName();
-
- // With RabbitMQ, and for agents, listening to others means
- // create a binding between the "agents" exchange and the agent's queue.
- for( MessagingContext ctx : MessagingContext.forImportedVariables( this.applicationName, instance )) {
-
- // On which routing key do export go? Those.that.import...
- String routingKey = THOSE_THAT_IMPORT + ctx.getRoutingKeySuffix();
- if( command == ListenerCommand.START ) {
- this.logger.fine( "Agent '" + getAgentId() + "' starts listening exports from other agents (" + ctx + ")." );
- this.channel.queueBind( queueName, ctx.getExchangeName(), routingKey );
-
- } else {
- this.logger.fine( "Agent '" + getAgentId() + "' stops listening exports from other agents (" + ctx + ")." );
- this.channel.queueUnbind( queueName, ctx.getExchangeName(), routingKey );
- }
- }
- }
-
-
- /*
- * (non-Javadoc)
- * @see net.roboconf.messaging.api.client.IClient
- * #sendMessageToTheDm(net.roboconf.messaging.api.messages.Message)
- */
- @Override
- public synchronized void sendMessageToTheDm( Message message ) throws IOException {
-
- this.logger.fine( "Agent '" + getAgentId() + "' is sending a " + message.getClass().getSimpleName() + " message to the DM." );
- this.channel.basicPublish(
- RabbitMqUtils.buildExchangeName( this.applicationName, true ),
- "", null,
- SerializationUtils.serializeObject( message ));
- }
-
-
- /*
- * (non-Javadoc)
- * @see net.roboconf.messaging.api.client.IClient
- * #listenToTheDm(net.roboconf.messaging.api.client.IClient.ListenerCommand)
- */
- @Override
- public synchronized void listenToTheDm( ListenerCommand command ) throws IOException {
-
- // Bind the root instance name with the queue
- String queueName = getQueueName();
- String exchangeName = RabbitMqUtils.buildExchangeName( this.applicationName, false );
- String routingKey = RabbitMqUtils.buildRoutingKeyForAgent( this.scopedInstancePath );
-
- // queueBind is idem-potent
- if( command == ListenerCommand.START ) {
- this.logger.fine( "Agent '" + getAgentId() + "' starts listening to the DM." );
- this.channel.queueBind( queueName, exchangeName, routingKey );
-
- } else {
- this.logger.fine( "Agent '" + getAgentId() + "' stops listening to the DM." );
- this.channel.queueUnbind( queueName, exchangeName, routingKey );
- }
- }
-
-
- private String getQueueName() {
- return this.applicationName + "." + RabbitMqUtils.escapeInstancePath( this.scopedInstancePath );
- }
-
-
- private String getAgentId() {
- return Utils.isEmptyOrWhitespaces( this.scopedInstancePath ) ? "?" : this.scopedInstancePath;
- }
-}
diff --git a/core/roboconf-messaging-rabbitmq/src/main/java/net/roboconf/messaging/rabbitmq/internal/RabbitMqClientDm.java b/core/roboconf-messaging-rabbitmq/src/main/java/net/roboconf/messaging/rabbitmq/internal/RabbitMqClientDm.java
deleted file mode 100644
index f93b01a4..00000000
--- a/core/roboconf-messaging-rabbitmq/src/main/java/net/roboconf/messaging/rabbitmq/internal/RabbitMqClientDm.java
+++ /dev/null
@@ -1,315 +0,0 @@
-/**
- * Copyright 2014-2015 Linagora, Université Joseph Fourier, Floralis
- *
- * The present code is developed in the scope of the joint LINAGORA -
- * Université Joseph Fourier - Floralis research program and is designated
- * as a "Result" pursuant to the terms and conditions of the LINAGORA
- * - Université Joseph Fourier - Floralis research program. Each copyright
- * holder of Results enumerated here above fully & independently holds complete
- * ownership of the complete Intellectual Property rights applicable to the whole
- * of said Results, and may freely exploit it in any manner which does not infringe
- * the moral rights of the other copyright holders.
- *
- * 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.
- */
-
-package net.roboconf.messaging.rabbitmq.internal;
-
-import java.io.IOException;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import net.roboconf.core.model.beans.Application;
-import net.roboconf.core.model.beans.Instance;
-import net.roboconf.core.model.helpers.InstanceHelpers;
-import net.roboconf.messaging.api.client.IDmClient;
-import net.roboconf.messaging.api.client.ListenerCommand;
-import net.roboconf.messaging.api.messages.Message;
-import net.roboconf.messaging.api.messages.from_agent_to_agent.MsgCmdRemoveImport;
-import net.roboconf.messaging.api.reconfigurables.ReconfigurableClientDm;
-import net.roboconf.messaging.api.utils.SerializationUtils;
-import net.roboconf.messaging.rabbitmq.internal.utils.DmReturnListener;
-import net.roboconf.messaging.rabbitmq.internal.utils.ListeningThread;
-import net.roboconf.messaging.rabbitmq.internal.utils.MessagingContext;
-import net.roboconf.messaging.rabbitmq.internal.utils.RabbitMqUtils;
-
-import com.rabbitmq.client.AMQP.BasicProperties;
-import com.rabbitmq.client.ConnectionFactory;
-import com.rabbitmq.client.QueueingConsumer;
-
-/**
- * The RabbitMQ client for the DM.
- * @author Vincent Zurczak - Linagora
- * @author Pierre Bourret - Université Joseph Fourier
- */
-public class RabbitMqClientDm extends RabbitMqClient implements IDmClient {
-
- private static final String DM_NEUTRAL_QUEUE_NAME = "roboconf.dm.neutral";
-
- String neutralConsumerTag;
- final Map applicationNameToConsumerTag = new HashMap<>();
- QueueingConsumer consumer;
-
-
- /**
- * Constructor.
- * @param reconfigurable
- * @param ip
- * @param username
- * @param password
- */
- public RabbitMqClientDm( final ReconfigurableClientDm reconfigurable, String ip, String username, String password ) {
- super(reconfigurable, ip, username, password);
- }
-
-
- /*
- * (non-Javadoc)
- * @see net.roboconf.messaging.api.client.IClient
- * #openConnection()
- */
- @Override
- public synchronized void openConnection() throws IOException {
-
- // Already connected? Do nothing
- this.logger.info( "The DM is opening a connection to RabbitMQ." );
- if( isConnected()) {
- this.logger.info( "The DM has already a connection to RabbitMQ." );
- return;
- }
-
- // Initialize the connection
- ConnectionFactory factory = new ConnectionFactory();
- RabbitMqUtils.configureFactory( factory, this.messageServerIp, this.messageServerUsername, this.messageServerPassword );
- this.channel = factory.newConnection().createChannel();
- this.logger.info( "The DM established a new connection with RabbitMQ. Channel # " + this.channel.getChannelNumber());
-
- // Be notified when a message does not arrive in a queue (i.e. nobody is listening)
- this.channel.addReturnListener( new DmReturnListener());
-
- // Declare the DM debug-dedicated queue.
- this.channel.queueDeclare( DM_NEUTRAL_QUEUE_NAME, true, false, true, null );
-
- // Start listening to messages.
- this.consumer = new QueueingConsumer( this.channel );
- String threadName = "Roboconf - Queue listener for the DM";
- String id = "The DM";
- new ListeningThread( threadName, this.logger, this.consumer, this.messageQueue, id ).start();
- }
-
-
- /* (non-Javadoc)
- * @see net.roboconf.messaging.api.client.IClient
- * #closeConnection()
- */
- @Override
- public synchronized void closeConnection() throws IOException {
-
- StringBuilder sb = new StringBuilder( "The DM is closing its connection to RabbitMQ." );
- if( this.channel != null )
- sb.append(" Channel # ").append(this.channel.getChannelNumber());
-
- this.logger.info( sb.toString());
- if( isConnected())
- RabbitMqUtils.closeConnection( this.channel );
-
- this.channel = null;
- }
-
-
- /*
- * (non-Javadoc)
- * @see net.roboconf.messaging.api.client.IDmClient
- * #publishMessageToAgent(net.roboconf.core.model.beans.Application, net.roboconf.core.model.beans.Instance, net.roboconf.messaging.api.messages.Message)
- */
- @Override
- public synchronized void sendMessageToAgent( Application application, Instance instance, Message message )
- throws IOException {
-
- String exchangeName = RabbitMqUtils.buildExchangeName( application, false );
- String routingKey = RabbitMqUtils.buildRoutingKeyForAgent( instance );
- this.logger.fine( "The DM sends a message to " + routingKey + ". Message type: " + message.getClass().getSimpleName());
-
- // We are requesting mandatory publication.
- // It means we expect this message to reach at least one queue.
- // If not, we want to be notified about it.
- this.channel.basicPublish(
- exchangeName, routingKey,
- true, false, null,
- SerializationUtils.serializeObject( message ));
-
- this.logger.fine( "The DM sent a message to " + routingKey + ". Message type: " + message.getClass().getSimpleName());
- }
-
-
- /* (non-Javadoc)
- * @see net.roboconf.messaging.api.client.IDmClient
- * #listenToAgentMessages(net.roboconf.core.model.beans.Application, net.roboconf.messaging.api.client.IClient.ListenerCommand)
- */
- @Override
- public synchronized void listenToAgentMessages( Application application, ListenerCommand command )
- throws IOException {
-
- if( command == ListenerCommand.STOP ) {
- this.logger.fine( "The DM stops listening agents messages for the '" + application.getName() + "' application." );
- String consumerTag = this.applicationNameToConsumerTag.remove( application.getName());
- if( consumerTag != null
- && this.channel != null
- && this.channel.isOpen())
- this.channel.basicCancel( consumerTag );
-
- } else {
- // Already listening? Ignore...
- if( this.applicationNameToConsumerTag.containsKey( application.getName())) {
- this.logger.finer( "Application " + application + " is already listened to by a messaging client." );
- return;
- }
-
- this.logger.fine( "The DM starts listening agents messages for the '" + application.getName() + "' application." );
-
- // Exchange declaration is idem-potent
- RabbitMqUtils.declareApplicationExchanges( application.getName(), this.channel );
-
- // Queue declaration is idem-potent
- String queueName = application.getName() + ".dm";
- this.channel.queueDeclare( queueName, true, false, true, null );
-
- // queueBind is idem-potent
- // Every message sent to the "DM" exchange will land into the DM's queue.
- String exchangeName = RabbitMqUtils.buildExchangeName( application, true );
- this.channel.queueBind( queueName, exchangeName, "" );
-
- // Start to listen to the queue
- String consumerTag = this.channel.basicConsume( queueName, true, this.consumer );
- this.applicationNameToConsumerTag.put( application.getName(), consumerTag );
- }
- }
-
-
- /*
- * (non-Javadoc)
- * @see net.roboconf.messaging.api.client.IClient
- * #sendMessageToTheDm(net.roboconf.messaging.api.messages.Message)
- */
- @Override
- public synchronized void sendMessageToTheDm( Message msg ) throws IOException {
-
- // The DM can send messages to itself (e.g. for debug).
- // This method could also be used to broadcast information to (potential) other DMs.
- this.logger.fine( "The DM sends a message to the DM's neutral queue." );
- this.channel.queueDeclare( DM_NEUTRAL_QUEUE_NAME, true, false, true, null );
-
- // To prevent spamming and residual messages, messages sent by the DM
- // (to itself or its siblings) have a life span of 500 ms. If there is no
- // client connected during this period, the message will be dropped.
- this.channel.basicPublish(
- "", DM_NEUTRAL_QUEUE_NAME,
- new BasicProperties.Builder().expiration( "500" ).build(),
- SerializationUtils.serializeObject( msg ));
-
- this.logger.fine( "The DM sent a message to the DM's neutral queue." );
- }
-
-
- /*
- * (non-Javadoc)
- * @see net.roboconf.messaging.api.client.IClient
- * #listenToTheDm(net.roboconf.messaging.api.client.IClient.ListenerCommand)
- */
- @Override
- public synchronized void listenToTheDm( ListenerCommand command )
- throws IOException {
-
- if( command == ListenerCommand.START ) {
- if( this.neutralConsumerTag != null ) {
- this.logger.finer( "The DM is already listening to the neutral queue." );
- return;
- }
-
- this.channel.queueDeclare( DM_NEUTRAL_QUEUE_NAME, true, false, true, null );
-
- // Create the debug message consumer and start consuming.
- // No auto-ACK. Messages must be acknowledged manually by the consumer.
- this.neutralConsumerTag = this.channel.basicConsume(
- DM_NEUTRAL_QUEUE_NAME, // queue
- true, // auto ACK
- DM_NEUTRAL_QUEUE_NAME, // consumer tag set to the queue name
- false, // get local messages (ESSENTIAL!)
- false, // consumer is not exclusive
- null, // no parameters
- this.consumer ); // the consumer
-
- } else {
- this.logger.fine( "The DM stops listening to the neutral queue." );
- if ( this.neutralConsumerTag != null
- && this.channel != null
- && this.channel.isOpen())
- this.channel.basicCancel( this.neutralConsumerTag );
-
- this.neutralConsumerTag = null;
- }
- }
-
-
- /* (non-Javadoc)
- * @see net.roboconf.messaging.api.client.IDmClient
- * #deleteMessagingServerArtifacts(net.roboconf.core.model.beans.Application)
- */
- @Override
- public synchronized void deleteMessagingServerArtifacts( Application application )
- throws IOException {
-
- // We delete the exchanges
- this.channel.exchangeDelete( RabbitMqUtils.buildExchangeName( application, true ));
- this.channel.exchangeDelete( RabbitMqUtils.buildExchangeName( application, false ));
- // Queues are deleted automatically by RabbitMQ
- }
-
-
- /*
- * (non-Javadoc)
- * @see net.roboconf.messaging.api.client.IDmClient
- * #propagateAgentTermination(net.roboconf.core.model.beans.Application, net.roboconf.core.model.beans.Instance)
- */
- @Override
- public synchronized void propagateAgentTermination( Application application, Instance rootInstance )
- throws IOException {
-
- this.logger.fine( "The DM is propagating the termination of agent '" + rootInstance + "'." );
-
- // Start with the deepest instances
- List instances = InstanceHelpers.buildHierarchicalList( rootInstance );
- Collections.reverse( instances );
-
- // Roughly, we unpublish all the variables for all the instances that were on the agent's machine.
- // This code is VERY similar to ...ClientAgent#unpublishExports
- // The messages will go through JUST like if they were coming from other agents.
- for( Instance instance : instances ) {
- for( MessagingContext ctx : MessagingContext.forExportedVariables( application.getName(), instance, application.getExternalExports())) {
-
- MsgCmdRemoveImport message = new MsgCmdRemoveImport(
- application.getName(),
- ctx.getRoutingKeySuffix(),
- InstanceHelpers.computeInstancePath( instance ));
-
- this.channel.basicPublish(
- ctx.getExchangeName(),
- RabbitMqClientAgent.THOSE_THAT_IMPORT + ctx.getRoutingKeySuffix(),
- null,
- SerializationUtils.serializeObject( message ));
- }
- }
- }
-}
diff --git a/core/roboconf-messaging-rabbitmq/src/main/java/net/roboconf/messaging/rabbitmq/internal/RabbitMqClientFactory.java b/core/roboconf-messaging-rabbitmq/src/main/java/net/roboconf/messaging/rabbitmq/internal/RabbitMqClientFactory.java
index 89f1bf0e..c64f4ab1 100644
--- a/core/roboconf-messaging-rabbitmq/src/main/java/net/roboconf/messaging/rabbitmq/internal/RabbitMqClientFactory.java
+++ b/core/roboconf-messaging-rabbitmq/src/main/java/net/roboconf/messaging/rabbitmq/internal/RabbitMqClientFactory.java
@@ -25,6 +25,12 @@
package net.roboconf.messaging.rabbitmq.internal;
+import static net.roboconf.messaging.rabbitmq.RabbitMqConstants.DEFAULT_IP;
+import static net.roboconf.messaging.rabbitmq.RabbitMqConstants.GUEST;
+import static net.roboconf.messaging.rabbitmq.RabbitMqConstants.RABBITMQ_SERVER_IP;
+import static net.roboconf.messaging.rabbitmq.RabbitMqConstants.RABBITMQ_SERVER_PASSWORD;
+import static net.roboconf.messaging.rabbitmq.RabbitMqConstants.RABBITMQ_SERVER_USERNAME;
+
import java.util.ArrayList;
import java.util.Collections;
import java.util.Map;
@@ -34,12 +40,10 @@
import java.util.logging.Logger;
import net.roboconf.core.utils.Utils;
-import net.roboconf.messaging.api.client.IAgentClient;
-import net.roboconf.messaging.api.client.IDmClient;
+import net.roboconf.messaging.api.MessagingConstants;
+import net.roboconf.messaging.api.extensions.IMessagingClient;
import net.roboconf.messaging.api.factory.IMessagingClientFactory;
import net.roboconf.messaging.api.reconfigurables.ReconfigurableClient;
-import net.roboconf.messaging.api.reconfigurables.ReconfigurableClientAgent;
-import net.roboconf.messaging.api.reconfigurables.ReconfigurableClientDm;
import net.roboconf.messaging.rabbitmq.RabbitMqConstants;
/**
@@ -49,13 +53,13 @@
public class RabbitMqClientFactory implements IMessagingClientFactory {
// The connection properties.
- private String messageServerIp;
- private String messageServerUsername;
- private String messageServerPassword;
+ String messageServerIp;
+ String messageServerUsername;
+ String messageServerPassword;
// The created clients.
// References to the clients are *weak*, so we never prevent their garbage collection.
- private final Set clients = Collections.newSetFromMap(new WeakHashMap());
+ final Set clients = Collections.newSetFromMap( new WeakHashMap ());
// The logger
private final Logger logger = Logger.getLogger(this.getClass().getName());
@@ -80,33 +84,49 @@ public synchronized void setMessageServerPassword( final String messageServerPas
}
+ /**
+ * Reconfigures the client (invoked by iPojo).
+ */
public void reconfigure() {
+ this.logger.fine( "Rabbit MQ clients are about to be reconfigured." );
+
// Set the properties for all created clients.
- resetClients(false);
+ resetClients( false );
}
+ /**
+ * Stops the client (invoked by iPojo).
+ */
public void stop() {
resetClients(true);
}
- private void resetClients(boolean shutdown) {
+ private void resetClients( boolean shutdown ) {
+
// Make fresh snapshots of the clients, as we don't want to reconfigure them while holding the lock.
final ArrayList clients;
synchronized (this) {
- clients = new ArrayList<>(this.clients);
+
+ // Get the snapshot.
+ clients = new ArrayList<>( this.clients );
+
+ // Remove the clients, new ones will be created if necessary.
+ this.clients.clear();
}
// Now reconfigure all the clients.
- for (RabbitMqClient client : clients) {
+ for( RabbitMqClient client : clients ) {
try {
final ReconfigurableClient> reconfigurable = client.getReconfigurableClient();
- if (reconfigurable != null)
- if (shutdown)
- reconfigurable.closeConnection();
- else
- reconfigurable.switchMessagingType(RabbitMqConstants.RABBITMQ_FACTORY_TYPE);
+
+ // The reconfigurable can never be null.
+ // If it was, a NPE would have been thrown when the Rabbit MQ client was created.
+ if( shutdown )
+ reconfigurable.closeConnection();
+ else
+ reconfigurable.switchMessagingType( RabbitMqConstants.FACTORY_RABBITMQ );
} catch (Throwable t) {
// Warn but continue to reconfigure the next clients!
@@ -119,24 +139,22 @@ private void resetClients(boolean shutdown) {
@Override
public String getType() {
- return RabbitMqConstants.RABBITMQ_FACTORY_TYPE;
+ return RabbitMqConstants.FACTORY_RABBITMQ;
}
@Override
- public synchronized IDmClient createDmClient( final ReconfigurableClientDm parent ) {
- final RabbitMqClientDm client = new RabbitMqClientDm(parent, this.messageServerIp, this.messageServerUsername, this.messageServerPassword);
- this.clients.add(client);
- this.logger.finer("Created a new DM client");
- return client;
- }
-
+ public IMessagingClient createClient( final ReconfigurableClient> parent ) {
+ this.logger.fine( "Creating a new Rabbit MQ client with owner = " + parent.getOwnerKind());
+
+ // The parent cannot be null. A NPE MUST be thrown otherwise.
+ // That's what the RabbitMqClient constructor does. There is unit test for this.
+ final RabbitMqClient client = new RabbitMqClient( parent, this.messageServerIp, this.messageServerUsername, this.messageServerPassword );
+ synchronized( this ) {
+ this.clients.add( client );
+ }
- @Override
- public synchronized IAgentClient createAgentClient( final ReconfigurableClientAgent parent ) {
- final RabbitMqClientAgent client = new RabbitMqClientAgent(parent, this.messageServerIp, this.messageServerUsername, this.messageServerPassword);
- this.clients.add(client);
- this.logger.finer("Created a new Agent client");
+ this.logger.finer( "A new Rabbit MQ client was created." );
return client;
}
@@ -144,33 +162,30 @@ public synchronized IAgentClient createAgentClient( final ReconfigurableClientAg
@Override
public boolean setConfiguration( final Map configuration ) {
- final boolean result;
- final String type = configuration.get(MESSAGING_TYPE_PROPERTY);
- if (RabbitMqConstants.RABBITMQ_FACTORY_TYPE.equals(type)) {
- String ip = configuration.get(RabbitMqConstants.RABBITMQ_SERVER_IP);
- String username = configuration.get(RabbitMqConstants.RABBITMQ_SERVER_USERNAME);
- String password = configuration.get(RabbitMqConstants.RABBITMQ_SERVER_PASSWORD);
-
- // Handles default values.
- if (ip == null)
- ip = RabbitMqClient.DEFAULT_IP;
- if (username == null)
- username = RabbitMqClient.DEFAULT_USERNAME;
- if (password == null)
- password = RabbitMqClient.DEFAULT_PASSWORD;
+ boolean result = false;;
+ final String type = configuration.get( MessagingConstants.MESSAGING_TYPE_PROPERTY ) ;
+ if(( result = RabbitMqConstants.FACTORY_RABBITMQ.equals( type ))) {
+
+ // Get the new values
+ String ip = Utils.getValue( configuration, RABBITMQ_SERVER_IP, DEFAULT_IP );
+ String username = Utils.getValue( configuration, RABBITMQ_SERVER_USERNAME, GUEST );
+ String password = Utils.getValue( configuration, RABBITMQ_SERVER_PASSWORD, GUEST );
// Avoid unnecessary (and potentially problematic) reconfiguration if nothing has changed.
// First we detect for changes, and set the parameters accordingly.
boolean hasChanged = false;
synchronized (this) {
+
if (!Objects.equals(this.messageServerIp, ip)) {
setMessageServerIp(ip);
hasChanged = true;
}
+
if (!Objects.equals(this.messageServerUsername, username)) {
setMessageServerUsername(username);
hasChanged = true;
}
+
if (!Objects.equals(this.messageServerPassword, password)) {
setMessageServerPassword(password);
hasChanged = true;
@@ -182,11 +197,6 @@ public boolean setConfiguration( final Map configuration ) {
// prevent any message loss.
if (hasChanged)
reconfigure();
- result = true;
- } else {
-
- // Not a configuration for this RabbitMQ client factory.
- result = false;
}
return result;
diff --git a/core/roboconf-messaging-rabbitmq/src/main/java/net/roboconf/messaging/rabbitmq/internal/utils/MessagingContext.java b/core/roboconf-messaging-rabbitmq/src/main/java/net/roboconf/messaging/rabbitmq/internal/utils/MessagingContext.java
deleted file mode 100644
index 14cd7404..00000000
--- a/core/roboconf-messaging-rabbitmq/src/main/java/net/roboconf/messaging/rabbitmq/internal/utils/MessagingContext.java
+++ /dev/null
@@ -1,144 +0,0 @@
-/**
- * Copyright 2015 Linagora, Université Joseph Fourier, Floralis
- *
- * The present code is developed in the scope of the joint LINAGORA -
- * Université Joseph Fourier - Floralis research program and is designated
- * as a "Result" pursuant to the terms and conditions of the LINAGORA
- * - Université Joseph Fourier - Floralis research program. Each copyright
- * holder of Results enumerated here above fully & independently holds complete
- * ownership of the complete Intellectual Property rights applicable to the whole
- * of said Results, and may freely exploit it in any manner which does not infringe
- * the moral rights of the other copyright holders.
- *
- * 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.
- */
-
-package net.roboconf.messaging.rabbitmq.internal.utils;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import net.roboconf.core.model.beans.ImportedVariable;
-import net.roboconf.core.model.beans.Instance;
-import net.roboconf.core.model.helpers.ComponentHelpers;
-import net.roboconf.core.model.helpers.VariableHelpers;
-
-/**
- * @author Vincent Zurczak - Linagora
- */
-public final class MessagingContext {
-
- public static final String INTER_APP = "roboconf.inter-app";
- private final String exchangeName, routingKeySuffix;
-
-
- /**
- * Private constructor.
- * @param exchangeName
- * @param routingKeySuffix
- */
- private MessagingContext( String exchangeName, String routingKeySuffix ) {
- this.exchangeName = exchangeName;
- this.routingKeySuffix = routingKeySuffix;
- }
-
- /**
- * @return the exchangeName
- */
- public String getExchangeName() {
- return this.exchangeName == null ? INTER_APP : this.exchangeName;
- }
-
- /**
- * @return the routingKeySuffix
- */
- public String getRoutingKeySuffix() {
- return this.routingKeySuffix;
- }
-
-
- @Override
- public String toString() {
-
- String s = this.routingKeySuffix;
- if( this.exchangeName == null )
- s += " (external)";
-
- return s;
- }
-
-
- /**
- * Builds a list of messaging contexts.
- * @param applicationName the name of the agent's application
- * @param instance the current instance
- * @return a non-null list
- */
- public static Collection forImportedVariables( String applicationName, Instance instance ) {
-
- Map result = new HashMap<> ();
- for( ImportedVariable var : ComponentHelpers.findAllImportedVariables( instance.getComponent()).values()) {
- String componentOrApplicationTemplateName = VariableHelpers.parseVariableName( var.getName()).getKey();
- if( result.containsKey( componentOrApplicationTemplateName ))
- continue;
-
- MessagingContext ctx;
- if( var.isExternal()) {
- String exchangeName = null;
- ctx = new MessagingContext( exchangeName, componentOrApplicationTemplateName );
-
- } else {
- String exchangeName = RabbitMqUtils.buildExchangeName( applicationName, false );
- ctx = new MessagingContext( exchangeName, componentOrApplicationTemplateName );
- }
-
- result.put( componentOrApplicationTemplateName, ctx );
- }
-
- return result.values();
- }
-
-
- /**
- * Builds a list of messaging contexts.
- * @param applicationName the name of the agent's application
- * @param instance the current instance
- * @param externalExports a non-null map that associates internal exported variables with global ones
- * @return a non-null list
- */
- public static List forExportedVariables( String applicationName, Instance instance, Map externalExports ) {
-
- List result = new ArrayList<> ();
-
- // Internal variables
- for( String facetOrComponentName : VariableHelpers.findPrefixesForExportedVariables( instance )) {
- String exchangeName = RabbitMqUtils.buildExchangeName( applicationName, false );
- MessagingContext ctx = new MessagingContext( exchangeName, facetOrComponentName );
- result.add( ctx );
- }
-
- // External variables - they all have the same prefix, the application template's name
- if( ! externalExports.isEmpty()) {
- String varName = externalExports.values().iterator().next();
- String prefix = VariableHelpers.parseVariableName( varName ).getKey();
-
- MessagingContext ctx = new MessagingContext( null, prefix );
- result.add( ctx );
- }
-
- return result;
- }
-}
diff --git a/core/roboconf-messaging-rabbitmq/src/main/java/net/roboconf/messaging/rabbitmq/internal/utils/RabbitMqUtils.java b/core/roboconf-messaging-rabbitmq/src/main/java/net/roboconf/messaging/rabbitmq/internal/utils/RabbitMqUtils.java
index 794e0742..e4bfa7e1 100644
--- a/core/roboconf-messaging-rabbitmq/src/main/java/net/roboconf/messaging/rabbitmq/internal/utils/RabbitMqUtils.java
+++ b/core/roboconf-messaging-rabbitmq/src/main/java/net/roboconf/messaging/rabbitmq/internal/utils/RabbitMqUtils.java
@@ -30,12 +30,12 @@
import java.util.concurrent.LinkedBlockingQueue;
import java.util.logging.Logger;
-import net.roboconf.core.model.beans.Application;
-import net.roboconf.core.model.beans.Instance;
-import net.roboconf.core.model.helpers.InstanceHelpers;
import net.roboconf.core.utils.Utils;
+import net.roboconf.messaging.api.extensions.MessagingContext;
+import net.roboconf.messaging.api.extensions.MessagingContext.RecipientKind;
import net.roboconf.messaging.api.messages.Message;
import net.roboconf.messaging.api.utils.SerializationUtils;
+import net.roboconf.messaging.rabbitmq.RabbitMqConstants;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.ConnectionFactory;
@@ -56,59 +56,6 @@ private RabbitMqUtils() {
}
- /**
- * Builds the exchange name for RabbitMQ.
- * @param applicationName the application name
- * @param dm true if we want the exchange name for the DM, false for the agents
- * @return a non-null string
- */
- public static String buildExchangeName( String applicationName, boolean dm ) {
- return applicationName + (dm ? ".admin" : ".agents" );
- }
-
-
- /**
- * Builds the exchange name for RabbitMQ.
- * @param application an application
- * @param dm true if we want the exchange name for the DM, false for the agents
- * @return a non-null string
- */
- public static String buildExchangeName( Application application, boolean dm ) {
- return buildExchangeName( application.getName(), dm );
- }
-
-
- /**
- * Builds the routing key for an agent.
- * @param instance an instance managed by the agent
- * @return a non-null string
- */
- public static String buildRoutingKeyForAgent( Instance instance ) {
- Instance scopedInstance = InstanceHelpers.findScopedInstance( instance );
- return buildRoutingKeyForAgent( InstanceHelpers.computeInstancePath( scopedInstance ));
- }
-
-
- /**
- * Builds the routing key for an agent.
- * @param scopedInstancePath the path of the (scoped) instance associated with the agent
- * @return a non-null string
- */
- public static String buildRoutingKeyForAgent( String scopedInstancePath ) {
- return "machine." + escapeInstancePath( scopedInstancePath );
- }
-
-
- /**
- * Removes unnecessary slashes and transforms the others into dots.
- * @param instancePath a non-null instance path
- * @return a non-null string
- */
- public static String escapeInstancePath( String instancePath ) {
- return instancePath.replaceFirst( "^/*", "" ).replaceFirst( "/*$", "" ).replaceAll( "/+", "." );
- }
-
-
/**
* Configures the connection factory with the right settings.
* @param factory the connection factory
@@ -150,36 +97,63 @@ public static void closeConnection( Channel channel ) throws IOException {
/**
- * Declares the required exchanges for an application.
- *
- * Every time the DM or an agent must send a message, we must be sure
- * all the exchanges have been declared. Otherwise, it will result in
- * an error in the client. And this error will close the channel.
- *
- *
- * To PREVENT stupid errors, it is really important to declare
- * both exchanges at once!
- *
- *
+ * Declares the required exchanges for an application (only for agents).
* @param applicationName the application name
* @param channel the RabbitMQ channel
* @throws IOException if an error occurs
*/
public static void declareApplicationExchanges( String applicationName, Channel channel ) throws IOException {
- // Exchange declaration is idem-potent
- String dmExchangeName = buildExchangeName( applicationName, true );
- channel.exchangeDeclare( dmExchangeName, "fanout" );
- // "fanout" is a keyword for RabbitMQ.
- // It broadcasts all the messages to all the queues this exchange knows.
-
- String agentExchangeName = buildExchangeName( applicationName, false );
- channel.exchangeDeclare( agentExchangeName, "topic" );
// "topic" is a keyword for RabbitMQ.
+ if( applicationName != null )
+ channel.exchangeDeclare( buildExchangeNameForAgent( applicationName ), "topic" );
+ }
+
+
+ /**
+ * Declares the global exchanges (those that do not depend on an application).
+ *
+ * It includes the DM exchange and the one for inter-application exchanges.
+ *
+ *
+ * @param channel the RabbitMQ channel
+ * @throws IOException if an error occurs
+ */
+ public static void declareGlobalExchanges( Channel channel ) throws IOException {
- // Also create the exchange for inter-application exchanges.
- channel.exchangeDeclare( MessagingContext.INTER_APP, "topic" );
// "topic" is a keyword for RabbitMQ.
+ channel.exchangeDeclare( RabbitMqConstants.EXHANGE_DM, "topic" );
+ channel.exchangeDeclare( RabbitMqConstants.EXHANGE_INTER_APP, "topic" );
+
+ }
+
+
+ /**
+ * Builds the name of an exchange for agents (related to the application name).
+ * @param applicationName the application name
+ * @return a non-null string
+ */
+ public static String buildExchangeNameForAgent( String applicationName ) {
+ return applicationName + ".agents";
+ }
+
+
+ /**
+ * Builds an exchange name from a messaging context.
+ * @param ctx a non-null context
+ * @return a non-null string
+ */
+ public static String buildExchangeName( MessagingContext ctx ) {
+
+ String exchangeName;
+ if( ctx.getKind() == RecipientKind.DM )
+ exchangeName = RabbitMqConstants.EXHANGE_DM;
+ else if( ctx.getKind() == RecipientKind.INTER_APP )
+ exchangeName = RabbitMqConstants.EXHANGE_INTER_APP;
+ else
+ exchangeName = RabbitMqUtils.buildExchangeNameForAgent( ctx.getApplicationName());
+
+ return exchangeName;
}
@@ -222,12 +196,8 @@ public static void listenToRabbitMq( String sourceName, Logger logger, QueueingC
Utils.logException( logger, e );
break;
- } catch( ClassNotFoundException e ) {
- logger.severe( sourceName + ": a message could not be deserialized. Class cast exception." );
- Utils.logException( logger, e );
-
- } catch( IOException e ) {
- logger.severe( sourceName + ": a message could not be deserialized. I/O exception." );
+ } catch( ClassNotFoundException | IOException e ) {
+ logger.severe( sourceName + ": a message could not be deserialized. => " + e.getClass().getSimpleName());
Utils.logException( logger, e );
}
}
diff --git a/core/roboconf-messaging-rabbitmq/src/main/java/net/roboconf/messaging/rabbitmq/internal/utils/DmReturnListener.java b/core/roboconf-messaging-rabbitmq/src/main/java/net/roboconf/messaging/rabbitmq/internal/utils/RoboconfReturnListener.java
similarity index 97%
rename from core/roboconf-messaging-rabbitmq/src/main/java/net/roboconf/messaging/rabbitmq/internal/utils/DmReturnListener.java
rename to core/roboconf-messaging-rabbitmq/src/main/java/net/roboconf/messaging/rabbitmq/internal/utils/RoboconfReturnListener.java
index 9fd9560b..83848101 100644
--- a/core/roboconf-messaging-rabbitmq/src/main/java/net/roboconf/messaging/rabbitmq/internal/utils/DmReturnListener.java
+++ b/core/roboconf-messaging-rabbitmq/src/main/java/net/roboconf/messaging/rabbitmq/internal/utils/RoboconfReturnListener.java
@@ -30,8 +30,8 @@
import java.util.logging.Logger;
import net.roboconf.core.utils.Utils;
-import net.roboconf.messaging.api.utils.SerializationUtils;
import net.roboconf.messaging.api.messages.Message;
+import net.roboconf.messaging.api.utils.SerializationUtils;
import com.rabbitmq.client.AMQP.BasicProperties;
import com.rabbitmq.client.ReturnListener;
@@ -39,7 +39,7 @@
/**
* @author Vincent Zurczak - Linagora
*/
-public class DmReturnListener implements ReturnListener {
+public class RoboconfReturnListener implements ReturnListener {
private final Logger logger = Logger.getLogger( getClass().getName());
diff --git a/core/roboconf-messaging-rabbitmq/src/test/java/net/roboconf/messaging/rabbitmq/internal/DmClientTest.java b/core/roboconf-messaging-rabbitmq/src/test/java/net/roboconf/messaging/rabbitmq/internal/DmClientTest.java
deleted file mode 100644
index 7c531a31..00000000
--- a/core/roboconf-messaging-rabbitmq/src/test/java/net/roboconf/messaging/rabbitmq/internal/DmClientTest.java
+++ /dev/null
@@ -1,118 +0,0 @@
-/**
- * Copyright 2014-2015 Linagora, Université Joseph Fourier, Floralis
- *
- * The present code is developed in the scope of the joint LINAGORA -
- * Université Joseph Fourier - Floralis research program and is designated
- * as a "Result" pursuant to the terms and conditions of the LINAGORA
- * - Université Joseph Fourier - Floralis research program. Each copyright
- * holder of Results enumerated here above fully & independently holds complete
- * ownership of the complete Intellectual Property rights applicable to the whole
- * of said Results, and may freely exploit it in any manner which does not infringe
- * the moral rights of the other copyright holders.
- *
- * 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.
- */
-
-package net.roboconf.messaging.rabbitmq.internal;
-
-import java.util.concurrent.LinkedBlockingQueue;
-
-import junit.framework.Assert;
-import net.roboconf.core.model.beans.Application;
-import net.roboconf.messaging.api.client.ListenerCommand;
-import net.roboconf.messaging.api.messages.Message;
-import net.roboconf.messaging.rabbitmq.RabbitMqConstants;
-import net.roboconf.messaging.rabbitmq.internal.utils.RabbitMqTestUtils;
-
-import org.junit.Assume;
-import org.junit.BeforeClass;
-import org.junit.Test;
-
-import com.rabbitmq.client.Channel;
-
-/**
- * @author Vincent Zurczak - Linagora
- */
-public class DmClientTest {
- private static boolean rabbitMqIsRunning = false;
-
- @BeforeClass
- public static void checkRabbitMqIsRunning() throws Exception {
- rabbitMqIsRunning = RabbitMqTestUtils.checkRabbitMqIsRunning();
- }
-
-
- @Test
- public void testExceptions() throws Exception {
- Assume.assumeTrue( rabbitMqIsRunning );
-
- RabbitMqClientDm dmClient = new RabbitMqClientDm(null, "localhost", "guest", "guest" );
-
- Assert.assertEquals( RabbitMqConstants.RABBITMQ_FACTORY_TYPE, dmClient.getMessagingType());
- Assert.assertFalse( dmClient.isConnected());
- Assert.assertNull( dmClient.channel );
-
- LinkedBlockingQueue messagesQueue = new LinkedBlockingQueue<>();
- dmClient.setMessageQueue( messagesQueue );
- dmClient.openConnection();
- Assert.assertNotNull( dmClient.channel );
-
- // openConnection is idem-potent
- Channel oldChannel = dmClient.channel;
- dmClient.openConnection();
- Assert.assertEquals( oldChannel, dmClient.channel );
-
- Assert.assertEquals( 0, dmClient.applicationNameToConsumerTag.size());
- dmClient.listenToAgentMessages( new Application( "app", null ), ListenerCommand.START );
- Assert.assertEquals( 1, dmClient.applicationNameToConsumerTag.size());
-
- String consumerTag = dmClient.applicationNameToConsumerTag.get( "app" );
- Assert.assertNotNull( consumerTag );
-
- dmClient.listenToAgentMessages( new Application( "app", null ), ListenerCommand.START ); // should be ignored
- Assert.assertEquals( 1, dmClient.applicationNameToConsumerTag.size());
- Assert.assertEquals( consumerTag, dmClient.applicationNameToConsumerTag.get( "app" ));
-
- dmClient.listenToAgentMessages( new Application( "app", null ), ListenerCommand.STOP );
- Assert.assertEquals( 0, dmClient.applicationNameToConsumerTag.size());
-
- // Check the DM's neutral queue
- Assert.assertNull( dmClient.neutralConsumerTag );
- dmClient.listenToTheDm( ListenerCommand.START );
- Assert.assertNotNull( dmClient.neutralConsumerTag );
-
- String oldNeutralConsumer = dmClient.neutralConsumerTag;
- dmClient.listenToTheDm( ListenerCommand.START );
- Assert.assertNotNull( dmClient.neutralConsumerTag );
- Assert.assertEquals( oldNeutralConsumer, dmClient.neutralConsumerTag );
-
- dmClient.listenToTheDm( ListenerCommand.STOP );
- Assert.assertNull( dmClient.neutralConsumerTag );
-
- // Check the idem-potency
- dmClient.listenToTheDm( ListenerCommand.STOP );
- Assert.assertNull( dmClient.neutralConsumerTag );
-
- // Close the connection
- dmClient.deleteMessagingServerArtifacts( new Application( "app", null ));
- dmClient.closeConnection();
- Assert.assertNull( dmClient.channel );
-
- // closeConnection is idem-potent
- dmClient.closeConnection();
- Assert.assertNull( dmClient.channel );
-
- consumerTag = dmClient.applicationNameToConsumerTag.get( "app" );
- Assert.assertNull( consumerTag );
- }
-}
diff --git a/core/roboconf-messaging-rabbitmq/src/test/java/net/roboconf/messaging/rabbitmq/internal/AgentClientTest.java b/core/roboconf-messaging-rabbitmq/src/test/java/net/roboconf/messaging/rabbitmq/internal/RaabitMqClientTest.java
similarity index 68%
rename from core/roboconf-messaging-rabbitmq/src/test/java/net/roboconf/messaging/rabbitmq/internal/AgentClientTest.java
rename to core/roboconf-messaging-rabbitmq/src/test/java/net/roboconf/messaging/rabbitmq/internal/RaabitMqClientTest.java
index 010837f9..5a305811 100644
--- a/core/roboconf-messaging-rabbitmq/src/test/java/net/roboconf/messaging/rabbitmq/internal/AgentClientTest.java
+++ b/core/roboconf-messaging-rabbitmq/src/test/java/net/roboconf/messaging/rabbitmq/internal/RaabitMqClientTest.java
@@ -27,7 +27,8 @@
import java.util.concurrent.LinkedBlockingQueue;
-import junit.framework.Assert;
+import org.junit.Assert;
+import net.roboconf.messaging.api.extensions.MessagingContext.RecipientKind;
import net.roboconf.messaging.api.messages.Message;
import net.roboconf.messaging.rabbitmq.RabbitMqConstants;
import net.roboconf.messaging.rabbitmq.internal.utils.RabbitMqTestUtils;
@@ -41,7 +42,7 @@
/**
* @author Vincent Zurczak - Linagora
*/
-public class AgentClientTest {
+public class RaabitMqClientTest {
private static boolean rabbitMqIsRunning = false;
@@ -55,32 +56,31 @@ public static void checkRabbitMqIsRunning() throws Exception {
public void testConnectAndDisconnect() throws Exception {
Assume.assumeTrue( rabbitMqIsRunning );
- RabbitMqClientAgent agentClient = new RabbitMqClientAgent(null, "localhost", "guest", "guest" );
- agentClient.setApplicationName( "app" );
- agentClient.setScopedInstancePath( "/root" );
+ RabbitMqClient client = new RabbitMqClient( null, "localhost", "guest", "guest", RecipientKind.DM );
+ client.setOwnerProperties( RecipientKind.DM, "app", "/root" );
- Assert.assertEquals( RabbitMqConstants.RABBITMQ_FACTORY_TYPE, agentClient.getMessagingType());
- Assert.assertFalse( agentClient.isConnected());
- Assert.assertNull( agentClient.channel );
+ Assert.assertEquals( RabbitMqConstants.FACTORY_RABBITMQ, client.getMessagingType());
+ Assert.assertFalse( client.isConnected());
+ Assert.assertNull( client.channel );
LinkedBlockingQueue messagesQueue = new LinkedBlockingQueue<>();
- agentClient.setMessageQueue( messagesQueue );
- agentClient.openConnection();
- Assert.assertNotNull( agentClient.channel );
- Assert.assertNotNull( agentClient.consumerTag );
- Assert.assertTrue( agentClient.isConnected());
+ client.setMessageQueue( messagesQueue );
+ client.openConnection();
+ Assert.assertNotNull( client.channel );
+ Assert.assertNotNull( client.consumerTag );
+ Assert.assertTrue( client.isConnected());
// openConnection is idem-potent
- Channel oldChannel = agentClient.channel;
- agentClient.openConnection();
- Assert.assertEquals( oldChannel, agentClient.channel );
+ Channel oldChannel = client.channel;
+ client.openConnection();
+ Assert.assertEquals( oldChannel, client.channel );
- agentClient.closeConnection();
- Assert.assertNull( agentClient.channel );
- Assert.assertNull( agentClient.consumerTag );
+ client.closeConnection();
+ Assert.assertNull( client.channel );
+ Assert.assertNull( client.consumerTag );
// closeConnection is idem-potent
- agentClient.closeConnection();
- Assert.assertNull( agentClient.channel );
+ client.closeConnection();
+ Assert.assertNull( client.channel );
}
}
diff --git a/core/roboconf-messaging-rabbitmq/src/test/java/net/roboconf/messaging/rabbitmq/internal/RabbitMqClientFactoryTest.java b/core/roboconf-messaging-rabbitmq/src/test/java/net/roboconf/messaging/rabbitmq/internal/RabbitMqClientFactoryTest.java
index 37e4791b..2979e1e1 100644
--- a/core/roboconf-messaging-rabbitmq/src/test/java/net/roboconf/messaging/rabbitmq/internal/RabbitMqClientFactoryTest.java
+++ b/core/roboconf-messaging-rabbitmq/src/test/java/net/roboconf/messaging/rabbitmq/internal/RabbitMqClientFactoryTest.java
@@ -25,15 +25,16 @@
package net.roboconf.messaging.rabbitmq.internal;
+import java.io.IOException;
+import java.util.HashMap;
import java.util.Map;
+import net.roboconf.messaging.api.AbstractMessageProcessor;
import net.roboconf.messaging.api.MessagingConstants;
-import net.roboconf.messaging.api.client.IAgentClient;
-import net.roboconf.messaging.api.client.IDmClient;
+import net.roboconf.messaging.api.business.IDmClient;
import net.roboconf.messaging.api.factory.MessagingClientFactoryRegistry;
import net.roboconf.messaging.api.messages.Message;
-import net.roboconf.messaging.api.processors.AbstractMessageProcessor;
-import net.roboconf.messaging.api.reconfigurables.ReconfigurableClientAgent;
+import net.roboconf.messaging.api.reconfigurables.ReconfigurableClient;
import net.roboconf.messaging.api.reconfigurables.ReconfigurableClientDm;
import net.roboconf.messaging.rabbitmq.RabbitMqConstants;
import net.roboconf.messaging.rabbitmq.internal.utils.RabbitMqTestUtils;
@@ -41,106 +42,137 @@
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
+import org.mockito.Mockito;
/**
* Tests for the RabbitMQ {@link net.roboconf.messaging.api.factory.IMessagingClientFactory}.
- *
* @author Pierre Bourret - Université Joseph Fourier
*/
public class RabbitMqClientFactoryTest {
- /**
- * The messaging client factory registry.
- */
- private final MessagingClientFactoryRegistry registry = new MessagingClientFactoryRegistry();
+ private MessagingClientFactoryRegistry registry;
+ private RabbitMqClientFactory factory;
- /**
- * The RabbitMq messaging client factory.
- */
- private final RabbitMqClientFactory factory = new RabbitMqClientFactory();
@Before
public void registerRabbitMqFactory() {
+
+ this.factory = new RabbitMqClientFactory();
this.factory.setMessageServerIp("localhost");
this.factory.setMessageServerUsername("guest");
this.factory.setMessageServerPassword("guest");
+
+ this.registry = new MessagingClientFactoryRegistry();
this.registry.addMessagingClientFactory(this.factory);
}
+
@Test
- public void testFactoryReconfigurationClientDm() throws IllegalAccessException {
+ public void testFactoryReconfiguration() throws IllegalAccessException {
+
// Create the client DM
final ReconfigurableClientDm client = new ReconfigurableClientDm();
client.associateMessageProcessor(new AbstractMessageProcessor("dummy.messageProcessor") {
@Override
protected void processMessage( final Message message ) {
-
+ // nothing
}
});
+
client.setRegistry(this.registry);
- client.switchMessagingType(RabbitMqConstants.RABBITMQ_FACTORY_TYPE);
+ client.switchMessagingType(RabbitMqConstants.FACTORY_RABBITMQ);
// Check the initial (default) configuration.
- final RabbitMqClientDm client1 = RabbitMqTestUtils.getMessagingClientDm(client);
- final Map config1 = client1.getConfiguration();
- Assert.assertEquals(RabbitMqConstants.RABBITMQ_FACTORY_TYPE, config1.get(MessagingConstants.MESSAGING_TYPE_PROPERTY));
+ final RabbitMqClient client1 = RabbitMqTestUtils.getMessagingClient(client);
+ final Map config1 = client1.getConfiguration();
+ Assert.assertEquals(RabbitMqConstants.FACTORY_RABBITMQ, config1.get(MessagingConstants.MESSAGING_TYPE_PROPERTY));
Assert.assertEquals("localhost", config1.get(RabbitMqConstants.RABBITMQ_SERVER_IP));
Assert.assertEquals("guest", config1.get(RabbitMqConstants.RABBITMQ_SERVER_USERNAME));
Assert.assertEquals("guest", config1.get(RabbitMqConstants.RABBITMQ_SERVER_PASSWORD));
+ Assert.assertEquals( 1, this.factory.clients.size());
// Reconfigure the factory.
- factory.setMessageServerIp("127.0.0.1");
- factory.setMessageServerUsername("john.doe");
- factory.setMessageServerPassword("1234");
- factory.reconfigure();
+ this.factory.setMessageServerIp("127.0.0.1");
+ this.factory.setMessageServerUsername("john.doe");
+ this.factory.setMessageServerPassword("1234");
+ this.factory.reconfigure();
// Check the client has been automatically changed.
- final RabbitMqClientDm client2 = RabbitMqTestUtils.getMessagingClientDm(client);
+ final RabbitMqClient client2 = RabbitMqTestUtils.getMessagingClient(client);
Assert.assertNotSame(client1, client2);
- final Map config2 = client2.getConfiguration();
- Assert.assertEquals(RabbitMqConstants.RABBITMQ_FACTORY_TYPE, config2.get(MessagingConstants.MESSAGING_TYPE_PROPERTY));
+ final Map config2 = client2.getConfiguration();
+ Assert.assertEquals(RabbitMqConstants.FACTORY_RABBITMQ, config2.get(MessagingConstants.MESSAGING_TYPE_PROPERTY));
Assert.assertEquals("127.0.0.1", config2.get(RabbitMqConstants.RABBITMQ_SERVER_IP));
Assert.assertEquals("john.doe", config2.get(RabbitMqConstants.RABBITMQ_SERVER_USERNAME));
Assert.assertEquals("1234", config2.get(RabbitMqConstants.RABBITMQ_SERVER_PASSWORD));
+ Assert.assertEquals( 1, this.factory.clients.size());
}
+
@Test
- public void testFactoryReconfigurationClientAgent() throws IllegalAccessException {
- // Create the client agent.
- final ReconfigurableClientAgent client = new ReconfigurableClientAgent();
- client.associateMessageProcessor(new AbstractMessageProcessor("dummy.messageProcessor") {
- @Override
- protected void processMessage( final Message message ) {
+ public void testSetConfiguration() {
- }
- });
- client.setRegistry(this.registry);
- client.setApplicationName("test");
- client.setScopedInstancePath("/test");
- client.switchMessagingType(RabbitMqConstants.RABBITMQ_FACTORY_TYPE);
+ Map map = new HashMap( 0 );
+ Assert.assertFalse( this.factory.setConfiguration( map ));
- // Check the initial (default) configuration.
- final RabbitMqClientAgent client1 = RabbitMqTestUtils.getMessagingClientAgent(client);
- final Map config1 = client1.getConfiguration();
- Assert.assertEquals(RabbitMqConstants.RABBITMQ_FACTORY_TYPE, config1.get(MessagingConstants.MESSAGING_TYPE_PROPERTY));
- Assert.assertEquals("localhost", config1.get(RabbitMqConstants.RABBITMQ_SERVER_IP));
- Assert.assertEquals("guest", config1.get(RabbitMqConstants.RABBITMQ_SERVER_USERNAME));
- Assert.assertEquals("guest", config1.get(RabbitMqConstants.RABBITMQ_SERVER_PASSWORD));
+ map.put( MessagingConstants.MESSAGING_TYPE_PROPERTY, "whatever" );
+ Assert.assertFalse( this.factory.setConfiguration( map ));
- // Reconfigure the factory.
- factory.setMessageServerIp("127.0.0.1");
- factory.setMessageServerUsername("john.doe");
- factory.setMessageServerPassword("1234");
- factory.reconfigure();
+ map.put( MessagingConstants.MESSAGING_TYPE_PROPERTY, RabbitMqConstants.FACTORY_RABBITMQ );
+ Assert.assertTrue( this.factory.setConfiguration( map ));
+ Assert.assertEquals( RabbitMqConstants.DEFAULT_IP, this.factory.messageServerIp );
+ Assert.assertEquals( RabbitMqConstants.GUEST, this.factory.messageServerUsername );
+ Assert.assertEquals( RabbitMqConstants.GUEST, this.factory.messageServerPassword );
- // Check the client has been automatically changed.
- final RabbitMqClientAgent client2 = RabbitMqTestUtils.getMessagingClientAgent(client);
- Assert.assertNotSame(client1, client2);
- final Map config2 = client2.getConfiguration();
- Assert.assertEquals(RabbitMqConstants.RABBITMQ_FACTORY_TYPE, config2.get(MessagingConstants.MESSAGING_TYPE_PROPERTY));
- Assert.assertEquals("127.0.0.1", config2.get(RabbitMqConstants.RABBITMQ_SERVER_IP));
- Assert.assertEquals("john.doe", config2.get(RabbitMqConstants.RABBITMQ_SERVER_USERNAME));
- Assert.assertEquals("1234", config2.get(RabbitMqConstants.RABBITMQ_SERVER_PASSWORD));
+ map.put( RabbitMqConstants.RABBITMQ_SERVER_IP, "127.0.0.1" );
+ map.put( RabbitMqConstants.RABBITMQ_SERVER_USERNAME, "bob" );
+ map.put( RabbitMqConstants.RABBITMQ_SERVER_PASSWORD, "2" );
+
+ Assert.assertTrue( this.factory.setConfiguration( map ));
+ Assert.assertEquals( "127.0.0.1", this.factory.messageServerIp );
+ Assert.assertEquals( "bob", this.factory.messageServerUsername );
+ Assert.assertEquals( "2", this.factory.messageServerPassword );
+ }
+
+
+ @Test
+ public void testStop() throws Exception {
+
+ // No client, no error.
+ Assert.assertEquals( 0, this.factory.clients.size());
+ this.factory.stop();
+
+ // Create a client.
+ testFactoryReconfiguration();
+
+ // Verify there is a client.
+ Assert.assertEquals( 1, this.factory.clients.size());
+ this.factory.stop();
+ Assert.assertEquals( 0, this.factory.clients.size());
}
+
+ @Test( expected = NullPointerException.class )
+ public void testCreateClient_nullParent() {
+
+ this.factory.createClient( null );
+ }
+
+
+ @Test
+ @SuppressWarnings({ "rawtypes" })
+ public void testStop_errorOnClose() throws Exception {
+
+ // Mockito does not like classes with generic... <_<
+ ReconfigurableClient parent = Mockito.mock( ReconfigurableClientDm.class );
+ Mockito.doThrow( new IOException( "For tests..." )).when( parent ).closeConnection();
+
+ RabbitMqClient client = new RabbitMqClient( parent, "", "", "" );
+ this.factory.clients.add( client );
+ Assert.assertEquals( 1, this.factory.clients.size());
+
+ this.factory.stop();
+ Assert.assertEquals( 0, this.factory.clients.size());
+ Mockito.verify( parent, Mockito.times( 1 )).closeConnection();
+ }
}
diff --git a/core/roboconf-messaging-rabbitmq/src/test/java/net/roboconf/messaging/rabbitmq/internal/RabbitMqTest.java b/core/roboconf-messaging-rabbitmq/src/test/java/net/roboconf/messaging/rabbitmq/internal/RabbitMqTest.java
index a72bdf60..930383fb 100644
--- a/core/roboconf-messaging-rabbitmq/src/test/java/net/roboconf/messaging/rabbitmq/internal/RabbitMqTest.java
+++ b/core/roboconf-messaging-rabbitmq/src/test/java/net/roboconf/messaging/rabbitmq/internal/RabbitMqTest.java
@@ -25,14 +25,9 @@
package net.roboconf.messaging.rabbitmq.internal;
-import java.util.List;
-
import net.roboconf.core.model.beans.Application;
-import net.roboconf.messaging.api.client.IAgentClient;
-import net.roboconf.messaging.api.client.IDmClient;
+import net.roboconf.messaging.api.extensions.MessagingContext.RecipientKind;
import net.roboconf.messaging.api.internal.client.AbstractMessagingTest;
-import net.roboconf.messaging.api.messages.Message;
-import net.roboconf.messaging.api.processors.AbstractMessageProcessor;
import net.roboconf.messaging.rabbitmq.RabbitMqConstants;
import net.roboconf.messaging.rabbitmq.internal.utils.RabbitMqTestUtils;
@@ -46,13 +41,22 @@
* @author Vincent Zurczak - Linagora
*/
public class RabbitMqTest extends AbstractMessagingTest {
+
private static boolean rabbitMqIsRunning = false;
+
@BeforeClass
public static void checkRabbitMqIsRunning() throws Exception {
rabbitMqIsRunning = RabbitMqTestUtils.checkRabbitMqIsRunning();
}
+
+ @Override
+ protected long getDelay() {
+ return 700;
+ }
+
+
@Before
public void registerRabbitMqFactory() {
@@ -68,7 +72,13 @@ public void registerRabbitMqFactory() {
public void cleanRabbitMq() throws Exception {
if( rabbitMqIsRunning ) {
- RabbitMqClientDm client = new RabbitMqClientDm(null, getMessagingIp(), getMessagingUsername(), getMessagingPassword());
+ RabbitMqClient client = new RabbitMqClient(
+ null,
+ getMessagingIp(),
+ getMessagingUsername(),
+ getMessagingPassword(),
+ RecipientKind.DM );
+
client.openConnection();
client.deleteMessagingServerArtifacts( new Application( "app", null ));
client.deleteMessagingServerArtifacts( new Application( "app1", null ));
@@ -142,25 +152,12 @@ public void testExternalExports_withTwoApplications() throws Exception {
}
+ @Test
@Override
- protected AbstractMessageProcessor createDmProcessor( final List dmMessages ) {
- return new AbstractMessageProcessor( "DM Processor - Test" ) {
- @Override
- protected void processMessage( Message message ) {
- dmMessages.add( message );
- }
- };
- }
-
-
- @Override
- protected AbstractMessageProcessor createAgentProcessor( final List agentMessages ) {
- return new AbstractMessageProcessor( "Agent Processor - Test" ) {
- @Override
- protected void processMessage( Message message ) {
- agentMessages.add( message );
- }
- };
+ public void testExternalExports_twoApplicationsAndTheDm_verifyAgentTerminationPropagation()
+ throws Exception {
+ Assume.assumeTrue( rabbitMqIsRunning );
+ super.testExternalExports_twoApplicationsAndTheDm_verifyAgentTerminationPropagation();
}
@@ -181,6 +178,6 @@ private String getMessagingPassword() {
@Override
protected String getMessagingType() {
- return RabbitMqConstants.RABBITMQ_FACTORY_TYPE;
+ return RabbitMqConstants.FACTORY_RABBITMQ;
}
}
diff --git a/core/roboconf-messaging-rabbitmq/src/test/java/net/roboconf/messaging/rabbitmq/internal/utils/RabbitMqTestUtils.java b/core/roboconf-messaging-rabbitmq/src/test/java/net/roboconf/messaging/rabbitmq/internal/utils/RabbitMqTestUtils.java
index cd15fc31..0723f2a7 100644
--- a/core/roboconf-messaging-rabbitmq/src/test/java/net/roboconf/messaging/rabbitmq/internal/utils/RabbitMqTestUtils.java
+++ b/core/roboconf-messaging-rabbitmq/src/test/java/net/roboconf/messaging/rabbitmq/internal/utils/RabbitMqTestUtils.java
@@ -33,11 +33,9 @@
import net.roboconf.core.internal.tests.TestUtils;
import net.roboconf.core.utils.Utils;
import net.roboconf.messaging.api.MessagingConstants;
-import net.roboconf.messaging.api.reconfigurables.ReconfigurableClientAgent;
-import net.roboconf.messaging.api.reconfigurables.ReconfigurableClientDm;
+import net.roboconf.messaging.api.reconfigurables.ReconfigurableClient;
import net.roboconf.messaging.rabbitmq.RabbitMqConstants;
-import net.roboconf.messaging.rabbitmq.internal.RabbitMqClientAgent;
-import net.roboconf.messaging.rabbitmq.internal.RabbitMqClientDm;
+import net.roboconf.messaging.rabbitmq.internal.RabbitMqClient;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.ConnectionFactory;
@@ -170,7 +168,7 @@ public static Channel createTestChannel( String messageServerIp, String username
}
/**
- * Get the delegate messaging client of a reconfigurable messaging client.
+ * Gets the delegate messaging client of a reconfigurable messaging client.
*
* @param reconfigurable the reconfigurable messaging client.
* @param type the expected type of the internal messaging client.
@@ -178,23 +176,9 @@ public static Channel createTestChannel( String messageServerIp, String username
* @return the internal messaging client, or {@code null} if it is not defined, or has the wrong type.
* @throws IllegalAccessException if the internal messaging client could not be read.
*/
- public static RabbitMqClientDm getMessagingClientDm( ReconfigurableClientDm reconfigurable )
+ public static RabbitMqClient getMessagingClient( ReconfigurableClient> reconfigurable )
throws IllegalAccessException {
- return TestUtils.getInternalField(reconfigurable, "messagingClient", RabbitMqClientDm.class);
- }
-
- /**
- * Get the delegate messaging client of a reconfigurable messaging client.
- *
- * @param reconfigurable the reconfigurable messaging client.
- * @param type the expected type of the internal messaging client.
- * @param the expected type of the internal messaging client.
- * @return the internal messaging client, or {@code null} if it is not defined, or has the wrong type.
- * @throws IllegalAccessException if the internal messaging client could not be read.
- */
- public static RabbitMqClientAgent getMessagingClientAgent( ReconfigurableClientAgent reconfigurable )
- throws IllegalAccessException {
- return TestUtils.getInternalField(reconfigurable, "messagingClient", RabbitMqClientAgent.class);
+ return TestUtils.getInternalField( reconfigurable, "messagingClient", RabbitMqClient.class );
}
@@ -208,7 +192,7 @@ public static RabbitMqClientAgent getMessagingClientAgent( ReconfigurableClientA
public static Map rabbitMqMessagingConfiguration(String ip, String username, String password) {
final Map result = new LinkedHashMap<> ();
- result.put( MessagingConstants.MESSAGING_TYPE_PROPERTY, RabbitMqConstants.RABBITMQ_FACTORY_TYPE );
+ result.put( MessagingConstants.MESSAGING_TYPE_PROPERTY, RabbitMqConstants.FACTORY_RABBITMQ );
if (ip != null)
result.put( RabbitMqConstants.RABBITMQ_SERVER_IP, ip );
diff --git a/core/roboconf-messaging-rabbitmq/src/test/java/net/roboconf/messaging/rabbitmq/internal/utils/RabbitMqTestUtilsTest.java b/core/roboconf-messaging-rabbitmq/src/test/java/net/roboconf/messaging/rabbitmq/internal/utils/RabbitMqTestUtilsTest.java
index a9524dd3..a253eada 100644
--- a/core/roboconf-messaging-rabbitmq/src/test/java/net/roboconf/messaging/rabbitmq/internal/utils/RabbitMqTestUtilsTest.java
+++ b/core/roboconf-messaging-rabbitmq/src/test/java/net/roboconf/messaging/rabbitmq/internal/utils/RabbitMqTestUtilsTest.java
@@ -25,7 +25,7 @@
package net.roboconf.messaging.rabbitmq.internal.utils;
-import junit.framework.Assert;
+import org.junit.Assert;
import org.junit.Test;
diff --git a/core/roboconf-messaging-rabbitmq/src/test/java/net/roboconf/messaging/rabbitmq/internal/utils/RabbitMqUtilsTest.java b/core/roboconf-messaging-rabbitmq/src/test/java/net/roboconf/messaging/rabbitmq/internal/utils/RabbitMqUtilsTest.java
index 39b5879d..f4808783 100644
--- a/core/roboconf-messaging-rabbitmq/src/test/java/net/roboconf/messaging/rabbitmq/internal/utils/RabbitMqUtilsTest.java
+++ b/core/roboconf-messaging-rabbitmq/src/test/java/net/roboconf/messaging/rabbitmq/internal/utils/RabbitMqUtilsTest.java
@@ -28,16 +28,17 @@
import java.util.concurrent.LinkedBlockingQueue;
import java.util.logging.Logger;
-import junit.framework.Assert;
-import net.roboconf.core.model.beans.Application;
-import net.roboconf.core.model.beans.Instance;
-import net.roboconf.core.model.helpers.InstanceHelpers;
+import org.junit.Assert;
+import net.roboconf.messaging.api.extensions.MessagingContext;
+import net.roboconf.messaging.api.extensions.MessagingContext.RecipientKind;
+import net.roboconf.messaging.api.extensions.MessagingContext.ThoseThat;
import net.roboconf.messaging.api.messages.Message;
-import net.roboconf.messaging.rabbitmq.internal.utils.RabbitMqUtils;
+import net.roboconf.messaging.rabbitmq.RabbitMqConstants;
import org.junit.Assume;
import org.junit.BeforeClass;
import org.junit.Test;
+import org.mockito.Mockito;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.ConnectionFactory;
@@ -49,6 +50,7 @@
* @author Vincent Zurczak - Linagora
*/
public class RabbitMqUtilsTest {
+
private static boolean rabbitMqIsRunning = false;
@BeforeClass
@@ -58,68 +60,57 @@ public static void checkRabbitMqIsRunning() throws Exception {
@Test
- public void testBuildExchangeName_String() {
-
- Assert.assertNotNull( RabbitMqUtils.buildExchangeName( "app", true ));
- Assert.assertNotNull( RabbitMqUtils.buildExchangeName( "app", false ));
- Assert.assertNotSame(
- RabbitMqUtils.buildExchangeName( "app", false ),
- RabbitMqUtils.buildExchangeName( "app", true ));
+ public void testDeclareApplicationExchanges() throws Exception {
- Assert.assertNotSame(
- RabbitMqUtils.buildExchangeName( "app1", false ),
- RabbitMqUtils.buildExchangeName( "app2", false ));
+ Channel channel = Mockito.mock( Channel.class );
+ RabbitMqUtils.declareApplicationExchanges( null, channel );
+ Mockito.verifyZeroInteractions( channel );
- Assert.assertNotSame(
- RabbitMqUtils.buildExchangeName( "app1", true ),
- RabbitMqUtils.buildExchangeName( "app2", true ));
+ RabbitMqUtils.declareApplicationExchanges( "te", channel );
+ String exchangeName = RabbitMqUtils.buildExchangeNameForAgent( "te" );
+ Mockito.verify( channel, Mockito.times( 1 )).exchangeDeclare( exchangeName, "topic" );
}
@Test
- public void testBuildExchangeName_Application() {
- Application app = new Application( "my-app", null );
-
- Assert.assertNotNull( RabbitMqUtils.buildExchangeName( app, true ));
- Assert.assertNotNull( RabbitMqUtils.buildExchangeName( app, false ));
+ public void testDeclareGlobalExchanges() throws Exception {
- Assert.assertEquals(
- RabbitMqUtils.buildExchangeName( app, false ),
- RabbitMqUtils.buildExchangeName( app.getName(), false ));
+ Channel channel = Mockito.mock( Channel.class );
+ RabbitMqUtils.declareGlobalExchanges( channel );
- Assert.assertEquals(
- RabbitMqUtils.buildExchangeName( app, true),
- RabbitMqUtils.buildExchangeName( app.getName(), true ));
+ Mockito.verify( channel, Mockito.times( 1 )).exchangeDeclare( RabbitMqConstants.EXHANGE_DM, "topic" );
+ Mockito.verify( channel, Mockito.times( 1 )).exchangeDeclare( RabbitMqConstants.EXHANGE_INTER_APP, "topic" );
}
@Test
- public void testBuildRoutingKeyForAgent_String() {
-
- Assert.assertEquals( "machine.root", RabbitMqUtils.buildRoutingKeyForAgent( "root" ));
- Assert.assertEquals( "machine.root", RabbitMqUtils.buildRoutingKeyForAgent("/root"));
- Assert.assertEquals( "machine.root", RabbitMqUtils.buildRoutingKeyForAgent( "/root/" ));
- Assert.assertEquals( "machine.root.docker", RabbitMqUtils.buildRoutingKeyForAgent( "/root/docker" ));
- Assert.assertNotSame(
- RabbitMqUtils.buildRoutingKeyForAgent( "root1" ),
- RabbitMqUtils.buildRoutingKeyForAgent( "root2" ));
+ public void testBuildExchangeNameForAgent() {
+
+ Assert.assertEquals( "test.agents", RabbitMqUtils.buildExchangeNameForAgent( "test" ));
+ Assert.assertEquals( "te.agents", RabbitMqUtils.buildExchangeNameForAgent( "te" ));
}
@Test
- public void testBuildRoutingKeyForAgent_Instance() {
- Instance inst = new Instance( "my-root" );
-
- Assert.assertNotNull( RabbitMqUtils.buildRoutingKeyForAgent( inst ));
- Assert.assertEquals(
- RabbitMqUtils.buildRoutingKeyForAgent( inst ),
- RabbitMqUtils.buildRoutingKeyForAgent( inst.getName()));
-
- Instance childInstance = new Instance( "child" );
- InstanceHelpers.insertChild( inst, childInstance );
- Assert.assertEquals(
- RabbitMqUtils.buildRoutingKeyForAgent( childInstance ),
- RabbitMqUtils.buildRoutingKeyForAgent( inst ));
+ public void testBuildExchangeName() {
+
+ MessagingContext ctx = new MessagingContext( RecipientKind.DM, "app1" );
+ Assert.assertEquals( RabbitMqConstants.EXHANGE_DM, RabbitMqUtils.buildExchangeName( ctx ));
+
+ ctx = new MessagingContext( RecipientKind.DM, "app2" );
+ Assert.assertEquals( RabbitMqConstants.EXHANGE_DM, RabbitMqUtils.buildExchangeName( ctx ));
+
+ ctx = new MessagingContext( RecipientKind.INTER_APP, "app1" );
+ Assert.assertEquals( RabbitMqConstants.EXHANGE_INTER_APP, RabbitMqUtils.buildExchangeName( ctx ));
+
+ ctx = new MessagingContext( RecipientKind.INTER_APP, "facet", ThoseThat.IMPORT, "app1" );
+ Assert.assertEquals( RabbitMqConstants.EXHANGE_INTER_APP, RabbitMqUtils.buildExchangeName( ctx ));
+
+ ctx = new MessagingContext( RecipientKind.AGENTS, "facet", ThoseThat.IMPORT, "app1" );
+ Assert.assertEquals( "app1.agents", RabbitMqUtils.buildExchangeName( ctx ));
+
+ ctx = new MessagingContext( RecipientKind.AGENTS, "facet", ThoseThat.EXPORT, "app2" );
+ Assert.assertEquals( "app2.agents", RabbitMqUtils.buildExchangeName( ctx ));
}
diff --git a/core/roboconf-messaging-rabbitmq/src/test/java/net/roboconf/messaging/rabbitmq/internal/utils/DmReturnListenerTest.java b/core/roboconf-messaging-rabbitmq/src/test/java/net/roboconf/messaging/rabbitmq/internal/utils/RoboconfReturnListenerTest.java
similarity index 90%
rename from core/roboconf-messaging-rabbitmq/src/test/java/net/roboconf/messaging/rabbitmq/internal/utils/DmReturnListenerTest.java
rename to core/roboconf-messaging-rabbitmq/src/test/java/net/roboconf/messaging/rabbitmq/internal/utils/RoboconfReturnListenerTest.java
index 1bc606d4..05ec21df 100644
--- a/core/roboconf-messaging-rabbitmq/src/test/java/net/roboconf/messaging/rabbitmq/internal/utils/DmReturnListenerTest.java
+++ b/core/roboconf-messaging-rabbitmq/src/test/java/net/roboconf/messaging/rabbitmq/internal/utils/RoboconfReturnListenerTest.java
@@ -25,19 +25,17 @@
package net.roboconf.messaging.rabbitmq.internal.utils;
-import net.roboconf.messaging.rabbitmq.internal.utils.DmReturnListener;
-
import org.junit.Test;
/**
* @author Vincent Zurczak - Linagora
*/
-public class DmReturnListenerTest {
+public class RoboconfReturnListenerTest {
@Test
public void testDeserializationError() throws Exception {
- DmReturnListener listener = new DmReturnListener();
+ RoboconfReturnListener listener = new RoboconfReturnListener();
listener.handleReturn( 0, "reply", "exchange", "routingKey", null, new byte[ 1 ]);
}
}
diff --git a/core/roboconf-plugin-logger/src/test/java/net/roboconf/plugin/logger/internal/PluginLoggerTest.java b/core/roboconf-plugin-logger/src/test/java/net/roboconf/plugin/logger/internal/PluginLoggerTest.java
index 5172f2ff..1fe39900 100644
--- a/core/roboconf-plugin-logger/src/test/java/net/roboconf/plugin/logger/internal/PluginLoggerTest.java
+++ b/core/roboconf-plugin-logger/src/test/java/net/roboconf/plugin/logger/internal/PluginLoggerTest.java
@@ -25,7 +25,7 @@
package net.roboconf.plugin.logger.internal;
-import junit.framework.Assert;
+import org.junit.Assert;
import net.roboconf.core.model.beans.Instance;
import org.junit.Test;
diff --git a/core/roboconf-plugin-puppet/src/test/java/net/roboconf/plugin/puppet/internal/BasicPluginPuppetTest.java b/core/roboconf-plugin-puppet/src/test/java/net/roboconf/plugin/puppet/internal/BasicPluginPuppetTest.java
index f7324788..6aa4899e 100644
--- a/core/roboconf-plugin-puppet/src/test/java/net/roboconf/plugin/puppet/internal/BasicPluginPuppetTest.java
+++ b/core/roboconf-plugin-puppet/src/test/java/net/roboconf/plugin/puppet/internal/BasicPluginPuppetTest.java
@@ -33,7 +33,7 @@
import java.util.List;
import java.util.Map;
-import junit.framework.Assert;
+import org.junit.Assert;
import net.roboconf.core.model.beans.Component;
import net.roboconf.core.model.beans.Import;
import net.roboconf.core.model.beans.ImportedVariable;
diff --git a/core/roboconf-plugin-puppet/src/test/java/net/roboconf/plugin/puppet/internal/PluginPuppetTest.java b/core/roboconf-plugin-puppet/src/test/java/net/roboconf/plugin/puppet/internal/PluginPuppetTest.java
index b38f3d29..9f25a19e 100644
--- a/core/roboconf-plugin-puppet/src/test/java/net/roboconf/plugin/puppet/internal/PluginPuppetTest.java
+++ b/core/roboconf-plugin-puppet/src/test/java/net/roboconf/plugin/puppet/internal/PluginPuppetTest.java
@@ -32,7 +32,7 @@
import java.util.Map;
import java.util.logging.Logger;
-import junit.framework.Assert;
+import org.junit.Assert;
import net.roboconf.core.internal.tests.TestUtils;
import net.roboconf.core.model.beans.Component;
import net.roboconf.core.model.beans.Import;
diff --git a/core/roboconf-plugin-script/src/test/java/net/roboconf/plugin/script/internal/PluginScriptTest.java b/core/roboconf-plugin-script/src/test/java/net/roboconf/plugin/script/internal/PluginScriptTest.java
index fcb6dddb..c007a189 100644
--- a/core/roboconf-plugin-script/src/test/java/net/roboconf/plugin/script/internal/PluginScriptTest.java
+++ b/core/roboconf-plugin-script/src/test/java/net/roboconf/plugin/script/internal/PluginScriptTest.java
@@ -32,7 +32,7 @@
import java.util.HashMap;
import java.util.Map;
-import junit.framework.Assert;
+import org.junit.Assert;
import net.roboconf.core.internal.tests.TestUtils;
import net.roboconf.core.model.beans.Component;
import net.roboconf.core.model.beans.Import;
diff --git a/core/roboconf-plugin-script/src/test/java/net/roboconf/plugin/script/internal/ScriptUtilsTest.java b/core/roboconf-plugin-script/src/test/java/net/roboconf/plugin/script/internal/ScriptUtilsTest.java
index 16bbb86c..d2ab568f 100644
--- a/core/roboconf-plugin-script/src/test/java/net/roboconf/plugin/script/internal/ScriptUtilsTest.java
+++ b/core/roboconf-plugin-script/src/test/java/net/roboconf/plugin/script/internal/ScriptUtilsTest.java
@@ -27,7 +27,7 @@
import java.io.File;
-import junit.framework.Assert;
+import org.junit.Assert;
import net.roboconf.plugin.script.internal.ScriptUtils.ActionFileFilter;
import org.junit.Rule;
diff --git a/core/roboconf-target-api/src/test/java/net/roboconf/target/api/AbstractThreadedTargetHandlerTest.java b/core/roboconf-target-api/src/test/java/net/roboconf/target/api/AbstractThreadedTargetHandlerTest.java
index 27aa5263..0d309367 100644
--- a/core/roboconf-target-api/src/test/java/net/roboconf/target/api/AbstractThreadedTargetHandlerTest.java
+++ b/core/roboconf-target-api/src/test/java/net/roboconf/target/api/AbstractThreadedTargetHandlerTest.java
@@ -27,7 +27,7 @@
import java.util.Map;
-import junit.framework.Assert;
+import org.junit.Assert;
import net.roboconf.core.internal.tests.TestUtils;
import net.roboconf.core.model.beans.Instance;
import net.roboconf.core.model.beans.Instance.InstanceStatus;
diff --git a/core/roboconf-target-api/src/test/java/net/roboconf/target/api/CancelledMachinesTest.java b/core/roboconf-target-api/src/test/java/net/roboconf/target/api/CancelledMachinesTest.java
index caf02614..b32e0605 100644
--- a/core/roboconf-target-api/src/test/java/net/roboconf/target/api/CancelledMachinesTest.java
+++ b/core/roboconf-target-api/src/test/java/net/roboconf/target/api/CancelledMachinesTest.java
@@ -28,7 +28,7 @@
import java.util.Iterator;
import java.util.Set;
-import junit.framework.Assert;
+import org.junit.Assert;
import net.roboconf.target.api.AbstractThreadedTargetHandler.CancelledMachines;
import org.junit.Test;
diff --git a/core/roboconf-target-docker/src/test/java/net/roboconf/target/docker/internal/DockerHandler_withContainerTest.java b/core/roboconf-target-docker/src/test/java/net/roboconf/target/docker/internal/DockerHandler_withContainerTest.java
index 46a2ab6d..9d17ccc0 100644
--- a/core/roboconf-target-docker/src/test/java/net/roboconf/target/docker/internal/DockerHandler_withContainerTest.java
+++ b/core/roboconf-target-docker/src/test/java/net/roboconf/target/docker/internal/DockerHandler_withContainerTest.java
@@ -38,7 +38,7 @@
import java.util.Properties;
import java.util.logging.Logger;
-import junit.framework.Assert;
+import org.junit.Assert;
import net.roboconf.core.model.beans.Instance;
import net.roboconf.core.model.helpers.InstanceHelpers;
import net.roboconf.core.utils.Utils;
diff --git a/core/roboconf-target-docker/src/test/java/net/roboconf/target/docker/internal/DockerHandler_withPackagesTest.java b/core/roboconf-target-docker/src/test/java/net/roboconf/target/docker/internal/DockerHandler_withPackagesTest.java
index 1af092e7..20bc18c2 100644
--- a/core/roboconf-target-docker/src/test/java/net/roboconf/target/docker/internal/DockerHandler_withPackagesTest.java
+++ b/core/roboconf-target-docker/src/test/java/net/roboconf/target/docker/internal/DockerHandler_withPackagesTest.java
@@ -39,7 +39,7 @@
import java.util.logging.Level;
import java.util.logging.Logger;
-import junit.framework.Assert;
+import org.junit.Assert;
import net.roboconf.core.internal.tests.TestUtils;
import net.roboconf.core.model.beans.Instance;
import net.roboconf.core.model.helpers.InstanceHelpers;
diff --git a/core/roboconf-target-docker/src/test/java/net/roboconf/target/docker/internal/DockerHandler_withoutContainerTest.java b/core/roboconf-target-docker/src/test/java/net/roboconf/target/docker/internal/DockerHandler_withoutContainerTest.java
index e7690d2f..0bf9c650 100644
--- a/core/roboconf-target-docker/src/test/java/net/roboconf/target/docker/internal/DockerHandler_withoutContainerTest.java
+++ b/core/roboconf-target-docker/src/test/java/net/roboconf/target/docker/internal/DockerHandler_withoutContainerTest.java
@@ -27,7 +27,7 @@
import java.util.HashMap;
-import junit.framework.Assert;
+import org.junit.Assert;
import net.roboconf.target.api.TargetException;
import org.junit.Test;
diff --git a/core/roboconf-target-docker/src/test/java/net/roboconf/target/docker/internal/DockerTestUtils.java b/core/roboconf-target-docker/src/test/java/net/roboconf/target/docker/internal/DockerTestUtils.java
index 066b51e4..66cbd37e 100644
--- a/core/roboconf-target-docker/src/test/java/net/roboconf/target/docker/internal/DockerTestUtils.java
+++ b/core/roboconf-target-docker/src/test/java/net/roboconf/target/docker/internal/DockerTestUtils.java
@@ -37,7 +37,7 @@
import java.util.Map;
import java.util.logging.Logger;
-import junit.framework.Assert;
+import org.junit.Assert;
import net.roboconf.core.model.beans.Instance;
import net.roboconf.core.utils.ProgramUtils;
import net.roboconf.core.utils.Utils;
diff --git a/core/roboconf-target-docker/src/test/java/net/roboconf/target/docker/internal/DockerUtilsTest.java b/core/roboconf-target-docker/src/test/java/net/roboconf/target/docker/internal/DockerUtilsTest.java
index adaea5da..1ca831bc 100644
--- a/core/roboconf-target-docker/src/test/java/net/roboconf/target/docker/internal/DockerUtilsTest.java
+++ b/core/roboconf-target-docker/src/test/java/net/roboconf/target/docker/internal/DockerUtilsTest.java
@@ -31,7 +31,7 @@
import java.util.List;
import java.util.Map;
-import junit.framework.Assert;
+import org.junit.Assert;
import net.roboconf.target.api.TargetException;
import org.junit.Test;
diff --git a/core/roboconf-target-docker/src/test/java/net/roboconf/target/docker/internal/DockerfileGeneratorTest.java b/core/roboconf-target-docker/src/test/java/net/roboconf/target/docker/internal/DockerfileGeneratorTest.java
index 3b4e70a1..2cf3b543 100644
--- a/core/roboconf-target-docker/src/test/java/net/roboconf/target/docker/internal/DockerfileGeneratorTest.java
+++ b/core/roboconf-target-docker/src/test/java/net/roboconf/target/docker/internal/DockerfileGeneratorTest.java
@@ -30,7 +30,7 @@
import java.util.ArrayList;
import java.util.List;
-import junit.framework.Assert;
+import org.junit.Assert;
import net.roboconf.core.utils.Utils;
import org.junit.Rule;
diff --git a/core/roboconf-target-embedded/src/test/java/net/roboconf/target/embedded/internal/EmbeddedHandlerTest.java b/core/roboconf-target-embedded/src/test/java/net/roboconf/target/embedded/internal/EmbeddedHandlerTest.java
index 2d8c4781..8ccb5ec9 100644
--- a/core/roboconf-target-embedded/src/test/java/net/roboconf/target/embedded/internal/EmbeddedHandlerTest.java
+++ b/core/roboconf-target-embedded/src/test/java/net/roboconf/target/embedded/internal/EmbeddedHandlerTest.java
@@ -27,7 +27,7 @@
import java.util.HashMap;
-import junit.framework.Assert;
+import org.junit.Assert;
import net.roboconf.core.model.beans.Instance;
import org.junit.Test;
diff --git a/core/roboconf-target-iaas-azure/src/test/java/net/roboconf/target/azure/internal/AzureIaasHandlerTest.java b/core/roboconf-target-iaas-azure/src/test/java/net/roboconf/target/azure/internal/AzureIaasHandlerTest.java
index a4e6f311..d20fa11a 100644
--- a/core/roboconf-target-iaas-azure/src/test/java/net/roboconf/target/azure/internal/AzureIaasHandlerTest.java
+++ b/core/roboconf-target-iaas-azure/src/test/java/net/roboconf/target/azure/internal/AzureIaasHandlerTest.java
@@ -28,7 +28,7 @@
import java.util.HashMap;
import java.util.Map;
-import junit.framework.Assert;
+import org.junit.Assert;
import net.roboconf.target.api.TargetException;
import org.junit.Test;
diff --git a/core/roboconf-target-iaas-ec2/src/test/java/net/roboconf/target/ec2/internal/Ec2IaasHandlerTest.java b/core/roboconf-target-iaas-ec2/src/test/java/net/roboconf/target/ec2/internal/Ec2IaasHandlerTest.java
index 457a7052..8750b293 100644
--- a/core/roboconf-target-iaas-ec2/src/test/java/net/roboconf/target/ec2/internal/Ec2IaasHandlerTest.java
+++ b/core/roboconf-target-iaas-ec2/src/test/java/net/roboconf/target/ec2/internal/Ec2IaasHandlerTest.java
@@ -28,7 +28,7 @@
import java.util.HashMap;
import java.util.Map;
-import junit.framework.Assert;
+import org.junit.Assert;
import net.roboconf.target.api.TargetException;
import org.junit.Test;
diff --git a/core/roboconf-target-iaas-ec2/src/test/java/net/roboconf/target/ec2/internal/ToRunByHand.java b/core/roboconf-target-iaas-ec2/src/test/java/net/roboconf/target/ec2/internal/ToRunByHand.java
index f236021f..278d4076 100644
--- a/core/roboconf-target-iaas-ec2/src/test/java/net/roboconf/target/ec2/internal/ToRunByHand.java
+++ b/core/roboconf-target-iaas-ec2/src/test/java/net/roboconf/target/ec2/internal/ToRunByHand.java
@@ -26,7 +26,7 @@
package net.roboconf.target.ec2.internal;
import static net.roboconf.messaging.api.MessagingConstants.MESSAGING_TYPE_PROPERTY;
-import static net.roboconf.messaging.api.MessagingConstants.TEST_FACTORY_TYPE;
+import static net.roboconf.messaging.api.MessagingConstants.FACTORY_TEST;
import java.io.File;
import java.util.Collections;
@@ -58,7 +58,7 @@ public static void main( String args[] ) throws Exception {
Ec2IaasHandler target = new Ec2IaasHandler();
String serverId = null;
try {
- Map msgCfg = Collections.singletonMap(MESSAGING_TYPE_PROPERTY, TEST_FACTORY_TYPE);
+ Map msgCfg = Collections.singletonMap(MESSAGING_TYPE_PROPERTY, FACTORY_TEST);
serverId = target.createMachine( conf, msgCfg, "root", "app" );
target.configureMachine( conf, msgCfg, serverId, "root", "app", new Instance( "root" ));
diff --git a/core/roboconf-target-iaas-openstack/src/test/java/net/roboconf/target/openstack/internal/OpenstackIaasHandlerTest.java b/core/roboconf-target-iaas-openstack/src/test/java/net/roboconf/target/openstack/internal/OpenstackIaasHandlerTest.java
index 81972cff..9c5a6e87 100644
--- a/core/roboconf-target-iaas-openstack/src/test/java/net/roboconf/target/openstack/internal/OpenstackIaasHandlerTest.java
+++ b/core/roboconf-target-iaas-openstack/src/test/java/net/roboconf/target/openstack/internal/OpenstackIaasHandlerTest.java
@@ -29,7 +29,7 @@
import java.util.Map;
import java.util.UUID;
-import junit.framework.Assert;
+import org.junit.Assert;
import net.roboconf.target.api.TargetException;
import org.junit.Test;
diff --git a/core/roboconf-target-iaas-openstack/src/test/java/net/roboconf/target/openstack/internal/ToRunByHand.java b/core/roboconf-target-iaas-openstack/src/test/java/net/roboconf/target/openstack/internal/ToRunByHand.java
index afb9a13a..77a97d57 100644
--- a/core/roboconf-target-iaas-openstack/src/test/java/net/roboconf/target/openstack/internal/ToRunByHand.java
+++ b/core/roboconf-target-iaas-openstack/src/test/java/net/roboconf/target/openstack/internal/ToRunByHand.java
@@ -26,7 +26,7 @@
package net.roboconf.target.openstack.internal;
import static net.roboconf.messaging.api.MessagingConstants.MESSAGING_TYPE_PROPERTY;
-import static net.roboconf.messaging.api.MessagingConstants.TEST_FACTORY_TYPE;
+import static net.roboconf.messaging.api.MessagingConstants.FACTORY_TEST;
import java.io.File;
import java.util.Collections;
@@ -62,7 +62,7 @@ public static void main( String args[] ) throws Exception {
target.start();
String serverId = null;
try {
- Map msgCfg = Collections.singletonMap(MESSAGING_TYPE_PROPERTY, TEST_FACTORY_TYPE);
+ Map msgCfg = Collections.singletonMap(MESSAGING_TYPE_PROPERTY, FACTORY_TEST);
serverId = target.createMachine( conf, msgCfg, "root", "app" );
target.configureMachine( conf, msgCfg, serverId, "root", "app", new Instance( "root" ));
diff --git a/core/roboconf-target-iaas-vmware/src/test/java/net/roboconf/target/vmware/internal/VmwareIaasHandlerTest.java b/core/roboconf-target-iaas-vmware/src/test/java/net/roboconf/target/vmware/internal/VmwareIaasHandlerTest.java
index 2823ecf9..dfb1a06d 100644
--- a/core/roboconf-target-iaas-vmware/src/test/java/net/roboconf/target/vmware/internal/VmwareIaasHandlerTest.java
+++ b/core/roboconf-target-iaas-vmware/src/test/java/net/roboconf/target/vmware/internal/VmwareIaasHandlerTest.java
@@ -25,7 +25,7 @@
package net.roboconf.target.vmware.internal;
-import junit.framework.Assert;
+import org.junit.Assert;
import org.junit.Test;
diff --git a/core/roboconf-target-in-memory/src/test/java/net/roboconf/target/in_memory/InMemoryHandler_mockedIPojoTest.java b/core/roboconf-target-in-memory/src/test/java/net/roboconf/target/in_memory/InMemoryHandler_mockedIPojoTest.java
index 5e17dcda..877536e9 100644
--- a/core/roboconf-target-in-memory/src/test/java/net/roboconf/target/in_memory/InMemoryHandler_mockedIPojoTest.java
+++ b/core/roboconf-target-in-memory/src/test/java/net/roboconf/target/in_memory/InMemoryHandler_mockedIPojoTest.java
@@ -32,7 +32,7 @@
import java.util.List;
import java.util.Map;
-import junit.framework.Assert;
+import org.junit.Assert;
import net.roboconf.core.internal.tests.TestApplication;
import net.roboconf.dm.management.ManagedApplication;
import net.roboconf.dm.management.Manager;
diff --git a/core/roboconf-target-in-memory/src/test/java/net/roboconf/target/in_memory/InMemoryHandler_realManagerTest.java b/core/roboconf-target-in-memory/src/test/java/net/roboconf/target/in_memory/InMemoryHandler_realManagerTest.java
index 77a95a7c..bbede853 100644
--- a/core/roboconf-target-in-memory/src/test/java/net/roboconf/target/in_memory/InMemoryHandler_realManagerTest.java
+++ b/core/roboconf-target-in-memory/src/test/java/net/roboconf/target/in_memory/InMemoryHandler_realManagerTest.java
@@ -32,7 +32,7 @@
import java.util.Map;
import java.util.Timer;
-import junit.framework.Assert;
+import org.junit.Assert;
import net.roboconf.core.internal.tests.TestApplication;
import net.roboconf.core.internal.tests.TestUtils;
import net.roboconf.core.model.beans.Instance.InstanceStatus;
@@ -87,7 +87,7 @@ public void before() throws Exception {
this.handler.manager = this.manager;
// Configure the manager
- this.manager.setMessagingType( MessagingConstants.TEST_FACTORY_TYPE );
+ this.manager.setMessagingType( MessagingConstants.FACTORY_TEST );
this.manager.configurationMngr().setWorkingDirectory( this.folder.newFolder());
this.manager.start();
diff --git a/core/roboconf-target-in-memory/src/test/java/net/roboconf/target/in_memory/InMemoryHandler_withoutIPojoTest.java b/core/roboconf-target-in-memory/src/test/java/net/roboconf/target/in_memory/InMemoryHandler_withoutIPojoTest.java
index 9e9838ce..bdc332b9 100644
--- a/core/roboconf-target-in-memory/src/test/java/net/roboconf/target/in_memory/InMemoryHandler_withoutIPojoTest.java
+++ b/core/roboconf-target-in-memory/src/test/java/net/roboconf/target/in_memory/InMemoryHandler_withoutIPojoTest.java
@@ -29,7 +29,7 @@
import java.util.LinkedHashMap;
import java.util.Map;
-import junit.framework.Assert;
+import org.junit.Assert;
import net.roboconf.core.model.beans.Instance;
import net.roboconf.messaging.api.factory.MessagingClientFactoryRegistry;
import net.roboconf.target.api.TargetException;
diff --git a/core/roboconf-target-jclouds/src/test/java/net/roboconf/target/jclouds/internal/JCloudsHandlerTest.java b/core/roboconf-target-jclouds/src/test/java/net/roboconf/target/jclouds/internal/JCloudsHandlerTest.java
index 46adc958..5f10cd88 100644
--- a/core/roboconf-target-jclouds/src/test/java/net/roboconf/target/jclouds/internal/JCloudsHandlerTest.java
+++ b/core/roboconf-target-jclouds/src/test/java/net/roboconf/target/jclouds/internal/JCloudsHandlerTest.java
@@ -29,7 +29,7 @@
import java.util.Map;
import java.util.UUID;
-import junit.framework.Assert;
+import org.junit.Assert;
import net.roboconf.target.api.TargetException;
import org.junit.Test;
diff --git a/core/roboconf-target-jclouds/src/test/java/net/roboconf/target/jclouds/internal/ToRunByHand.java b/core/roboconf-target-jclouds/src/test/java/net/roboconf/target/jclouds/internal/ToRunByHand.java
index 2300ce2d..15665822 100644
--- a/core/roboconf-target-jclouds/src/test/java/net/roboconf/target/jclouds/internal/ToRunByHand.java
+++ b/core/roboconf-target-jclouds/src/test/java/net/roboconf/target/jclouds/internal/ToRunByHand.java
@@ -26,7 +26,7 @@
package net.roboconf.target.jclouds.internal;
import static net.roboconf.messaging.api.MessagingConstants.MESSAGING_TYPE_PROPERTY;
-import static net.roboconf.messaging.api.MessagingConstants.TEST_FACTORY_TYPE;
+import static net.roboconf.messaging.api.MessagingConstants.FACTORY_TEST;
import java.io.File;
import java.io.FileInputStream;
@@ -72,7 +72,7 @@ public static void main( String args[] ) throws Exception {
JCloudsHandler target = new JCloudsHandler();
String serverId = null;
try {
- Map msgCfg = Collections.singletonMap(MESSAGING_TYPE_PROPERTY, TEST_FACTORY_TYPE);
+ Map msgCfg = Collections.singletonMap(MESSAGING_TYPE_PROPERTY, FACTORY_TEST);
serverId = target.createMachine( conf, msgCfg, "root", "app" );
target.configureMachine( conf, msgCfg, serverId, "root", "app", new Instance( "root" ));
diff --git a/karaf/roboconf-karaf-commands-dm/src/test/java/net/roboconf/karaf/commands/dm/targets/InstallTargetCommandTest.java b/karaf/roboconf-karaf-commands-dm/src/test/java/net/roboconf/karaf/commands/dm/targets/InstallTargetCommandTest.java
index bd926d2c..5dd86f0b 100644
--- a/karaf/roboconf-karaf-commands-dm/src/test/java/net/roboconf/karaf/commands/dm/targets/InstallTargetCommandTest.java
+++ b/karaf/roboconf-karaf-commands-dm/src/test/java/net/roboconf/karaf/commands/dm/targets/InstallTargetCommandTest.java
@@ -29,7 +29,7 @@
import java.io.PrintStream;
import java.lang.reflect.Field;
-import junit.framework.Assert;
+import org.junit.Assert;
import org.apache.karaf.shell.api.console.Session;
import org.junit.Test;
diff --git a/karaf/roboconf-karaf-commands-dm/src/test/java/net/roboconf/karaf/commands/dm/targets/SupportedTargetTest.java b/karaf/roboconf-karaf-commands-dm/src/test/java/net/roboconf/karaf/commands/dm/targets/SupportedTargetTest.java
index 657d8f5d..b90d16a1 100644
--- a/karaf/roboconf-karaf-commands-dm/src/test/java/net/roboconf/karaf/commands/dm/targets/SupportedTargetTest.java
+++ b/karaf/roboconf-karaf-commands-dm/src/test/java/net/roboconf/karaf/commands/dm/targets/SupportedTargetTest.java
@@ -27,7 +27,7 @@
import java.util.List;
-import junit.framework.Assert;
+import org.junit.Assert;
import org.junit.Test;
diff --git a/karaf/roboconf-karaf-commands-dm/src/test/java/net/roboconf/karaf/commands/dm/targets/TargetCompleterTest.java b/karaf/roboconf-karaf-commands-dm/src/test/java/net/roboconf/karaf/commands/dm/targets/TargetCompleterTest.java
index a1786cb2..2d425f6e 100644
--- a/karaf/roboconf-karaf-commands-dm/src/test/java/net/roboconf/karaf/commands/dm/targets/TargetCompleterTest.java
+++ b/karaf/roboconf-karaf-commands-dm/src/test/java/net/roboconf/karaf/commands/dm/targets/TargetCompleterTest.java
@@ -28,7 +28,7 @@
import java.util.ArrayList;
import java.util.List;
-import junit.framework.Assert;
+import org.junit.Assert;
import org.apache.karaf.shell.api.console.CommandLine;
import org.apache.karaf.shell.api.console.Session;
diff --git a/karaf/roboconf-karaf-dist-agent/pom.xml b/karaf/roboconf-karaf-dist-agent/pom.xml
index 340e25ab..aeee0997 100644
--- a/karaf/roboconf-karaf-dist-agent/pom.xml
+++ b/karaf/roboconf-karaf-dist-agent/pom.xml
@@ -109,6 +109,7 @@
sshbundleconfig
+ waripojo-allroboconf-agent
diff --git a/karaf/roboconf-karaf-dist-agent/src/main/resources/etc/net.roboconf.agent.configuration.cfg b/karaf/roboconf-karaf-dist-agent/src/main/resources/etc/net.roboconf.agent.configuration.cfg
index a92cf0d2..13bc6b6d 100644
--- a/karaf/roboconf-karaf-dist-agent/src/main/resources/etc/net.roboconf.agent.configuration.cfg
+++ b/karaf/roboconf-karaf-dist-agent/src/main/resources/etc/net.roboconf.agent.configuration.cfg
@@ -19,8 +19,9 @@
# The messaging parameters
######################################
-# The type of messaging we use: RabbitMQ.
-messaging-type = rabbitmq
+# The type of messaging to use.
+# Possible values: rabbimq, http or in-memory
+messaging-type = http
######################################
diff --git a/karaf/roboconf-karaf-dist-agent/src/main/resources/etc/net.roboconf.messaging.http.cfg b/karaf/roboconf-karaf-dist-agent/src/main/resources/etc/net.roboconf.messaging.http.cfg
new file mode 100644
index 00000000..7e878f3c
--- /dev/null
+++ b/karaf/roboconf-karaf-dist-agent/src/main/resources/etc/net.roboconf.messaging.http.cfg
@@ -0,0 +1,24 @@
+###########################################################################
+#
+# Copyright 2014 Linagora, Université Joseph Fourier
+#
+# 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.
+###########################################################################
+
+######################################
+# The HTTP messaging parameters
+######################################
+
+# The IP address (or hostname) and port of the HTTP server.
+net.roboconf.messaging.http.server.ip = localhost
+net.roboconf.messaging.http.server.port = 8181
diff --git a/karaf/roboconf-karaf-dist-dm/src/main/resources/etc/net.roboconf.dm.configuration.cfg b/karaf/roboconf-karaf-dist-dm/src/main/resources/etc/net.roboconf.dm.configuration.cfg
index a38e5857..46675a96 100644
--- a/karaf/roboconf-karaf-dist-dm/src/main/resources/etc/net.roboconf.dm.configuration.cfg
+++ b/karaf/roboconf-karaf-dist-dm/src/main/resources/etc/net.roboconf.dm.configuration.cfg
@@ -15,8 +15,9 @@
# limitations under the License.
###########################################################################
-# The type of messaging we use: RabbitMQ.
-messaging-type = rabbitmq
+# The type of messaging to use.
+# Possible values: rabbimq, http or in-memory
+messaging-type = http
# The maximal number of root instances / VM the autonomic can create.
autonomic-max-roots = 5
diff --git a/karaf/roboconf-karaf-dist-dm/src/main/resources/etc/net.roboconf.messaging.http.cfg b/karaf/roboconf-karaf-dist-dm/src/main/resources/etc/net.roboconf.messaging.http.cfg
new file mode 100644
index 00000000..4a52b965
--- /dev/null
+++ b/karaf/roboconf-karaf-dist-dm/src/main/resources/etc/net.roboconf.messaging.http.cfg
@@ -0,0 +1,26 @@
+###########################################################################
+#
+# Copyright 2014 Linagora, Université Joseph Fourier
+#
+# 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.
+###########################################################################
+
+######################################
+# The HTTP messaging parameters
+######################################
+
+# The IP address (or hostname) and port of the HTTP server.
+# Although the DM does not connect to itself with this messaging implementation,
+# this file is used to propagate this messaging configuration to agents.
+net.roboconf.messaging.http.server.ip = localhost
+net.roboconf.messaging.http.server.port = 8181
diff --git a/karaf/roboconf-karaf-feature-agent/src/main/feature/feature.xml b/karaf/roboconf-karaf-feature-agent/src/main/feature/feature.xml
index 1d57bf69..d073908a 100644
--- a/karaf/roboconf-karaf-feature-agent/src/main/feature/feature.xml
+++ b/karaf/roboconf-karaf-feature-agent/src/main/feature/feature.xml
@@ -15,6 +15,7 @@
mvn:net.roboconf/roboconf-core/${project.version}mvn:net.roboconf/roboconf-messaging-api/${project.version}mvn:net.roboconf/roboconf-messaging-rabbitmq/${project.version}
+ mvn:net.roboconf/roboconf-messaging-http/${project.version}mvn:net.roboconf/roboconf-agent/${project.version}mvn:net.roboconf/roboconf-agent-default/${project.version}mvn:net.roboconf/roboconf-agent-monitoring-api/${project.version}
diff --git a/karaf/roboconf-karaf-feature-dm/src/main/feature/feature.xml b/karaf/roboconf-karaf-feature-dm/src/main/feature/feature.xml
index ae77dd3d..d546c4e8 100644
--- a/karaf/roboconf-karaf-feature-dm/src/main/feature/feature.xml
+++ b/karaf/roboconf-karaf-feature-dm/src/main/feature/feature.xml
@@ -17,6 +17,7 @@
mvn:net.roboconf/roboconf-core/${project.version}mvn:net.roboconf/roboconf-messaging-api/${project.version}mvn:net.roboconf/roboconf-messaging-rabbitmq/${project.version}
+ mvn:net.roboconf/roboconf-messaging-http/${project.version}mvn:net.roboconf/roboconf-dm-rest-commons/${project.version}mvn:net.roboconf/roboconf-dm-rest-services/${project.version}mvn:net.roboconf/roboconf-dm/${project.version}
diff --git a/miscellaneous/roboconf-dm-rest-client/src/test/java/net/roboconf/dm/rest/client/delegates/ApplicationWsDelegateTest.java b/miscellaneous/roboconf-dm-rest-client/src/test/java/net/roboconf/dm/rest/client/delegates/ApplicationWsDelegateTest.java
index a7b7af53..0582b74d 100644
--- a/miscellaneous/roboconf-dm-rest-client/src/test/java/net/roboconf/dm/rest/client/delegates/ApplicationWsDelegateTest.java
+++ b/miscellaneous/roboconf-dm-rest-client/src/test/java/net/roboconf/dm/rest/client/delegates/ApplicationWsDelegateTest.java
@@ -33,7 +33,7 @@
import javax.ws.rs.core.UriBuilder;
-import junit.framework.Assert;
+import org.junit.Assert;
import net.roboconf.core.internal.tests.TestApplication;
import net.roboconf.core.internal.tests.TestUtils;
import net.roboconf.core.model.beans.Component;
@@ -49,7 +49,7 @@
import net.roboconf.dm.rest.client.exceptions.ApplicationWsException;
import net.roboconf.dm.rest.services.internal.RestApplication;
import net.roboconf.messaging.api.MessagingConstants;
-import net.roboconf.messaging.api.internal.client.test.TestClientDm;
+import net.roboconf.messaging.api.internal.client.test.TestClient;
import net.roboconf.messaging.api.messages.Message;
import net.roboconf.messaging.api.messages.from_dm_to_agent.MsgCmdChangeBinding;
import net.roboconf.messaging.api.messages.from_dm_to_agent.MsgCmdChangeInstanceState;
@@ -81,7 +81,7 @@ public class ApplicationWsDelegateTest {
private WsClient client;
private HttpServer httpServer;
- private TestClientDm msgClient;
+ private TestClient msgClient;
@After
@@ -101,7 +101,7 @@ public void before() throws Exception {
// Create the manager
this.manager = new Manager();
- this.manager.setMessagingType( MessagingConstants.TEST_FACTORY_TYPE );
+ this.manager.setMessagingType( MessagingConstants.FACTORY_TEST );
this.manager.setTargetResolver( new TestTargetResolver());
this.manager.configurationMngr().setWorkingDirectory( this.folder.newFolder());
this.manager.start();
@@ -112,8 +112,8 @@ public void before() throws Exception {
this.manager.reconfigure();
// Get the messaging client
- this.msgClient = (TestClientDm) this.managerWrapper.getInternalMessagingClient();
- this.msgClient.sentMessages.clear();
+ this.msgClient = (TestClient) this.managerWrapper.getInternalMessagingClient();
+ this.msgClient.clearMessages();
// Disable the messages timer for predictability
TestUtils.getInternalField( this.manager, "timer", Timer.class).cancel();
@@ -181,12 +181,12 @@ public void testChangeState_deployRoot_success() throws Exception {
@Test
public void testChangeState_deploy_success() throws Exception {
- Assert.assertEquals( 0, this.msgClient.sentMessages.size());
+ Assert.assertEquals( 0, this.msgClient.allSentMessages.size());
Assert.assertEquals( 0, this.ma.removeAwaitingMessages( this.app.getTomcatVm()).size());
String instancePath = InstanceHelpers.computeInstancePath( this.app.getTomcat());
this.client.getApplicationDelegate().changeInstanceState( this.app.getName(), InstanceStatus.DEPLOYED_STOPPED, instancePath );
- Assert.assertEquals( 0, this.msgClient.sentMessages.size());
+ Assert.assertEquals( 0, this.msgClient.allSentMessages.size());
List messages = this.ma.removeAwaitingMessages( this.app.getTomcatVm());
Assert.assertEquals( 1, messages.size());
@@ -216,12 +216,12 @@ public void testSetDescription_noApp() throws Exception {
@Test
public void testStopAll() throws Exception {
- Assert.assertEquals( 0, this.msgClient.sentMessages.size());
+ Assert.assertEquals( 0, this.msgClient.allSentMessages.size());
Assert.assertEquals( 0, this.ma.removeAwaitingMessages( this.app.getTomcatVm()).size());
String instancePath = InstanceHelpers.computeInstancePath( this.app.getTomcat());
this.client.getApplicationDelegate().stopAll( this.app.getName(), instancePath );
- Assert.assertEquals( 0, this.msgClient.sentMessages.size());
+ Assert.assertEquals( 0, this.msgClient.allSentMessages.size());
List messages = this.ma.removeAwaitingMessages( this.app.getTomcatVm());
Assert.assertEquals( 1, messages.size());
@@ -241,12 +241,12 @@ public void testStopAll_invalidApp() throws Exception {
@Test
public void testUndeployAll() throws Exception {
- Assert.assertEquals( 0, this.msgClient.sentMessages.size());
+ Assert.assertEquals( 0, this.msgClient.allSentMessages.size());
Assert.assertEquals( 0, this.ma.removeAwaitingMessages( this.app.getTomcatVm()).size());
String instancePath = InstanceHelpers.computeInstancePath( this.app.getTomcat());
this.client.getApplicationDelegate().undeployAll( this.app.getName(), instancePath );
- Assert.assertEquals( 0, this.msgClient.sentMessages.size());
+ Assert.assertEquals( 0, this.msgClient.allSentMessages.size());
List messages = this.ma.removeAwaitingMessages( this.app.getTomcatVm());
Assert.assertEquals( 1, messages.size());
@@ -266,12 +266,12 @@ public void testUndeployAll_invalidApp() throws Exception {
@Test
public void testDeployAndStartAll() throws Exception {
- Assert.assertEquals( 0, this.msgClient.sentMessages.size());
+ Assert.assertEquals( 0, this.msgClient.allSentMessages.size());
Assert.assertEquals( 0, this.ma.removeAwaitingMessages( this.app.getTomcatVm()).size());
String instancePath = InstanceHelpers.computeInstancePath( this.app.getTomcat());
this.client.getApplicationDelegate().deployAndStartAll( this.app.getName(), instancePath );
- Assert.assertEquals( 0, this.msgClient.sentMessages.size());
+ Assert.assertEquals( 0, this.msgClient.allSentMessages.size());
List messages = this.ma.removeAwaitingMessages( this.app.getTomcatVm());
Assert.assertEquals( 2, messages.size());
@@ -504,7 +504,7 @@ public void testResynchronize_success() throws ApplicationWsException {
this.client.getApplicationDelegate().resynchronize( this.app.getName() );
// Check a MsgCmdResynchronize has been sent to each agent.
- final List sentMessages = this.msgClient.sentMessages;
+ final List sentMessages = this.msgClient.allSentMessages;
Assert.assertEquals( rootInstances.size(), sentMessages.size() );
for( Message message : sentMessages )
Assert.assertTrue( message instanceof MsgCmdResynchronize );
@@ -568,19 +568,19 @@ public void testBindApplication_success() throws Exception {
this.managerWrapper.getNameToManagedApplication().put( app2.getName(), new ManagedApplication( app2 ));
// Bind and check
- Assert.assertEquals( 0, this.msgClient.sentMessages.size());
+ Assert.assertEquals( 0, this.msgClient.allSentMessages.size());
Assert.assertEquals( 0, this.ma.removeAwaitingMessages( this.app.getTomcatVm()).size());
Assert.assertEquals( 0, this.ma.removeAwaitingMessages( this.app.getMySqlVm()).size());
this.client.getApplicationDelegate().bindApplication( this.ma.getName(), app2.getTemplate().getExternalExportsPrefix(), app2.getName());
- Assert.assertEquals( 0, this.msgClient.sentMessages.size());
+ Assert.assertEquals( 0, this.msgClient.allSentMessages.size());
List messages = this.ma.removeAwaitingMessages( this.app.getTomcatVm());
Assert.assertEquals( 1, messages.size());
messages.addAll( this.ma.removeAwaitingMessages( this.app.getMySqlVm()));
Assert.assertEquals( 2, messages.size());
- for( Message m : this.msgClient.sentMessages ) {
+ for( Message m : this.msgClient.allSentMessages ) {
Assert.assertEquals( MsgCmdChangeBinding.class, m.getClass());
MsgCmdChangeBinding msg = (MsgCmdChangeBinding) m;
diff --git a/miscellaneous/roboconf-dm-rest-client/src/test/java/net/roboconf/dm/rest/client/delegates/DebugWsDelegateTest.java b/miscellaneous/roboconf-dm-rest-client/src/test/java/net/roboconf/dm/rest/client/delegates/DebugWsDelegateTest.java
index 2215bcb1..e9a8e840 100644
--- a/miscellaneous/roboconf-dm-rest-client/src/test/java/net/roboconf/dm/rest/client/delegates/DebugWsDelegateTest.java
+++ b/miscellaneous/roboconf-dm-rest-client/src/test/java/net/roboconf/dm/rest/client/delegates/DebugWsDelegateTest.java
@@ -31,7 +31,7 @@
import javax.ws.rs.core.UriBuilder;
-import junit.framework.Assert;
+import org.junit.Assert;
import net.roboconf.core.internal.tests.TestApplication;
import net.roboconf.core.internal.tests.TestUtils;
import net.roboconf.core.model.beans.Instance;
@@ -88,7 +88,7 @@ public void before() throws Exception {
// Create the manager
this.manager = new Manager();
- this.manager.setMessagingType(MessagingConstants.TEST_FACTORY_TYPE);
+ this.manager.setMessagingType(MessagingConstants.FACTORY_TEST);
this.manager.setTargetResolver( new TestTargetResolver());
this.manager.configurationMngr().setWorkingDirectory( this.folder.newFolder());
this.manager.start();
diff --git a/miscellaneous/roboconf-dm-rest-client/src/test/java/net/roboconf/dm/rest/client/delegates/ManagementWsDelegateTest.java b/miscellaneous/roboconf-dm-rest-client/src/test/java/net/roboconf/dm/rest/client/delegates/ManagementWsDelegateTest.java
index d4c9b009..6b30c3e0 100644
--- a/miscellaneous/roboconf-dm-rest-client/src/test/java/net/roboconf/dm/rest/client/delegates/ManagementWsDelegateTest.java
+++ b/miscellaneous/roboconf-dm-rest-client/src/test/java/net/roboconf/dm/rest/client/delegates/ManagementWsDelegateTest.java
@@ -34,7 +34,7 @@
import javax.ws.rs.core.Response.Status;
import javax.ws.rs.core.UriBuilder;
-import junit.framework.Assert;
+import org.junit.Assert;
import net.roboconf.core.internal.tests.TestApplication;
import net.roboconf.core.internal.tests.TestApplicationTemplate;
import net.roboconf.core.internal.tests.TestUtils;
@@ -93,7 +93,7 @@ public void before() throws Exception {
// Create the manager
this.manager = new Manager();
this.manager.setTargetResolver( new TestTargetResolver());
- this.manager.setMessagingType(MessagingConstants.TEST_FACTORY_TYPE);
+ this.manager.setMessagingType(MessagingConstants.FACTORY_TEST);
this.manager.configurationMngr().setWorkingDirectory( this.folder.newFolder());
this.manager.start();
diff --git a/miscellaneous/roboconf-dm-rest-client/src/test/java/net/roboconf/dm/rest/client/delegates/TargetWsDelegateTest.java b/miscellaneous/roboconf-dm-rest-client/src/test/java/net/roboconf/dm/rest/client/delegates/TargetWsDelegateTest.java
index a9387df0..888a9d91 100644
--- a/miscellaneous/roboconf-dm-rest-client/src/test/java/net/roboconf/dm/rest/client/delegates/TargetWsDelegateTest.java
+++ b/miscellaneous/roboconf-dm-rest-client/src/test/java/net/roboconf/dm/rest/client/delegates/TargetWsDelegateTest.java
@@ -31,7 +31,7 @@
import javax.ws.rs.core.UriBuilder;
-import junit.framework.Assert;
+import org.junit.Assert;
import net.roboconf.core.internal.tests.TestApplication;
import net.roboconf.core.internal.tests.TestUtils;
import net.roboconf.core.model.beans.Application;
@@ -90,7 +90,7 @@ public void before() throws Exception {
// Create the manager
this.manager = new Manager();
- this.manager.setMessagingType(MessagingConstants.TEST_FACTORY_TYPE);
+ this.manager.setMessagingType(MessagingConstants.FACTORY_TEST);
this.manager.setTargetResolver( new TestTargetResolver());
this.manager.configurationMngr().setWorkingDirectory( this.folder.newFolder());
this.manager.start();
diff --git a/miscellaneous/roboconf-doc-generator/src/test/java/net/roboconf/doc/generator/AbstractTestForRendererManager.java b/miscellaneous/roboconf-doc-generator/src/test/java/net/roboconf/doc/generator/AbstractTestForRendererManager.java
index 4ab83087..c9797158 100644
--- a/miscellaneous/roboconf-doc-generator/src/test/java/net/roboconf/doc/generator/AbstractTestForRendererManager.java
+++ b/miscellaneous/roboconf-doc-generator/src/test/java/net/roboconf/doc/generator/AbstractTestForRendererManager.java
@@ -27,7 +27,7 @@
import java.io.File;
-import junit.framework.Assert;
+import org.junit.Assert;
import net.roboconf.core.internal.tests.TestUtils;
import net.roboconf.core.model.RuntimeModelIo;
import net.roboconf.core.model.RuntimeModelIo.ApplicationLoadResult;
diff --git a/miscellaneous/roboconf-doc-generator/src/test/java/net/roboconf/doc/generator/RendererManagerHtmlTest.java b/miscellaneous/roboconf-doc-generator/src/test/java/net/roboconf/doc/generator/RendererManagerHtmlTest.java
index 4782124d..f332d898 100644
--- a/miscellaneous/roboconf-doc-generator/src/test/java/net/roboconf/doc/generator/RendererManagerHtmlTest.java
+++ b/miscellaneous/roboconf-doc-generator/src/test/java/net/roboconf/doc/generator/RendererManagerHtmlTest.java
@@ -34,7 +34,7 @@
import java.util.List;
import java.util.Map;
-import junit.framework.Assert;
+import org.junit.Assert;
import net.roboconf.core.internal.tests.TestUtils;
import net.roboconf.core.model.beans.Component;
import net.roboconf.core.model.beans.Instance;
diff --git a/miscellaneous/roboconf-doc-generator/src/test/java/net/roboconf/doc/generator/RendererManagerInternationalizationTest.java b/miscellaneous/roboconf-doc-generator/src/test/java/net/roboconf/doc/generator/RendererManagerInternationalizationTest.java
index 4cd92243..48f2c42d 100644
--- a/miscellaneous/roboconf-doc-generator/src/test/java/net/roboconf/doc/generator/RendererManagerInternationalizationTest.java
+++ b/miscellaneous/roboconf-doc-generator/src/test/java/net/roboconf/doc/generator/RendererManagerInternationalizationTest.java
@@ -29,7 +29,7 @@
import java.util.HashMap;
import java.util.Map;
-import junit.framework.Assert;
+import org.junit.Assert;
import net.roboconf.core.utils.Utils;
import net.roboconf.doc.generator.RenderingManager.Renderer;
diff --git a/miscellaneous/roboconf-doc-generator/src/test/java/net/roboconf/doc/generator/RendererManagerMarkdownTest.java b/miscellaneous/roboconf-doc-generator/src/test/java/net/roboconf/doc/generator/RendererManagerMarkdownTest.java
index 8299592c..77c52c44 100644
--- a/miscellaneous/roboconf-doc-generator/src/test/java/net/roboconf/doc/generator/RendererManagerMarkdownTest.java
+++ b/miscellaneous/roboconf-doc-generator/src/test/java/net/roboconf/doc/generator/RendererManagerMarkdownTest.java
@@ -29,7 +29,7 @@
import java.util.HashMap;
import java.util.Map;
-import junit.framework.Assert;
+import org.junit.Assert;
import net.roboconf.core.utils.Utils;
import net.roboconf.doc.generator.RenderingManager.Renderer;
diff --git a/miscellaneous/roboconf-doc-generator/src/test/java/net/roboconf/doc/generator/RendererManagerMultiRenderersTest.java b/miscellaneous/roboconf-doc-generator/src/test/java/net/roboconf/doc/generator/RendererManagerMultiRenderersTest.java
index 5e7be15f..0f8d907f 100644
--- a/miscellaneous/roboconf-doc-generator/src/test/java/net/roboconf/doc/generator/RendererManagerMultiRenderersTest.java
+++ b/miscellaneous/roboconf-doc-generator/src/test/java/net/roboconf/doc/generator/RendererManagerMultiRenderersTest.java
@@ -31,7 +31,7 @@
import java.util.List;
import java.util.Map;
-import junit.framework.Assert;
+import org.junit.Assert;
import net.roboconf.doc.generator.RenderingManager.Renderer;
import org.junit.Test;
diff --git a/miscellaneous/roboconf-doc-generator/src/test/java/net/roboconf/doc/generator/RendererManagerRecipeTest.java b/miscellaneous/roboconf-doc-generator/src/test/java/net/roboconf/doc/generator/RendererManagerRecipeTest.java
index f919555c..59e13645 100644
--- a/miscellaneous/roboconf-doc-generator/src/test/java/net/roboconf/doc/generator/RendererManagerRecipeTest.java
+++ b/miscellaneous/roboconf-doc-generator/src/test/java/net/roboconf/doc/generator/RendererManagerRecipeTest.java
@@ -31,7 +31,7 @@
import java.util.List;
import java.util.Map;
-import junit.framework.Assert;
+import org.junit.Assert;
import net.roboconf.core.internal.tests.TestUtils;
import net.roboconf.core.model.RuntimeModelIo;
import net.roboconf.core.model.RuntimeModelIo.ApplicationLoadResult;
diff --git a/miscellaneous/roboconf-doc-generator/src/test/java/net/roboconf/doc/generator/internal/GraphUtilsTest.java b/miscellaneous/roboconf-doc-generator/src/test/java/net/roboconf/doc/generator/internal/GraphUtilsTest.java
index 20c537bc..fade5aa7 100644
--- a/miscellaneous/roboconf-doc-generator/src/test/java/net/roboconf/doc/generator/internal/GraphUtilsTest.java
+++ b/miscellaneous/roboconf-doc-generator/src/test/java/net/roboconf/doc/generator/internal/GraphUtilsTest.java
@@ -27,7 +27,7 @@
import java.awt.Color;
-import junit.framework.Assert;
+import org.junit.Assert;
import org.junit.Test;
diff --git a/miscellaneous/roboconf-doc-generator/src/test/java/net/roboconf/doc/generator/internal/nls/MessagesTest.java b/miscellaneous/roboconf-doc-generator/src/test/java/net/roboconf/doc/generator/internal/nls/MessagesTest.java
index caade8ed..70e0fca1 100644
--- a/miscellaneous/roboconf-doc-generator/src/test/java/net/roboconf/doc/generator/internal/nls/MessagesTest.java
+++ b/miscellaneous/roboconf-doc-generator/src/test/java/net/roboconf/doc/generator/internal/nls/MessagesTest.java
@@ -25,7 +25,7 @@
package net.roboconf.doc.generator.internal.nls;
-import junit.framework.Assert;
+import org.junit.Assert;
import org.junit.Test;
diff --git a/miscellaneous/roboconf-integration-tests/pom.xml b/miscellaneous/roboconf-integration-tests/pom.xml
index dda1a0f1..ee881982 100644
--- a/miscellaneous/roboconf-integration-tests/pom.xml
+++ b/miscellaneous/roboconf-integration-tests/pom.xml
@@ -40,7 +40,8 @@
Roboconf :: Integration Tests
- 4.6.0
+
+ 4.7.02.4.1
@@ -88,7 +89,14 @@
${project.version}test
-
+
+
+ net.roboconf
+ roboconf-messaging-http
+ ${project.version}
+ test
+
+
net.roboconfroboconf-target-api
@@ -134,7 +142,7 @@
test-jartest
-
+
net.roboconfroboconf-target-docker
diff --git a/miscellaneous/roboconf-integration-tests/src/test/java/net/roboconf/integration/probes/AgentTest.java b/miscellaneous/roboconf-integration-tests/src/test/java/net/roboconf/integration/probes/AgentTest.java
index 86735319..3cff17a1 100644
--- a/miscellaneous/roboconf-integration-tests/src/test/java/net/roboconf/integration/probes/AgentTest.java
+++ b/miscellaneous/roboconf-integration-tests/src/test/java/net/roboconf/integration/probes/AgentTest.java
@@ -26,6 +26,7 @@
package net.roboconf.integration.probes;
import net.roboconf.integration.tests.internal.ItUtils;
+import net.roboconf.integration.tests.internal.parametrized.RabbitMqConfiguration;
import org.ops4j.pax.exam.Configuration;
import org.ops4j.pax.exam.Option;
@@ -39,6 +40,6 @@ public abstract class AgentTest {
@Configuration
public Option[] config() throws Exception {
ItConfigurationBean bean = new ItConfigurationBean( "roboconf-karaf-dist-agent", "agent" );
- return ItUtils.getBaseOptions( bean );
+ return ItUtils.getBaseOptions( bean, new RabbitMqConfiguration());
}
}
diff --git a/miscellaneous/roboconf-integration-tests/src/test/java/net/roboconf/integration/probes/DmTest.java b/miscellaneous/roboconf-integration-tests/src/test/java/net/roboconf/integration/probes/DmTest.java
index c99932bc..13b912eb 100644
--- a/miscellaneous/roboconf-integration-tests/src/test/java/net/roboconf/integration/probes/DmTest.java
+++ b/miscellaneous/roboconf-integration-tests/src/test/java/net/roboconf/integration/probes/DmTest.java
@@ -26,6 +26,7 @@
package net.roboconf.integration.probes;
import net.roboconf.integration.tests.internal.ItUtils;
+import net.roboconf.integration.tests.internal.parametrized.RabbitMqConfiguration;
import org.ops4j.pax.exam.Configuration;
import org.ops4j.pax.exam.Option;
@@ -39,6 +40,6 @@ public abstract class DmTest {
@Configuration
public Option[] config() throws Exception {
ItConfigurationBean bean = new ItConfigurationBean( "roboconf-karaf-dist-dm", "dm" );
- return ItUtils.getBaseOptions( bean );
+ return ItUtils.getBaseOptions( bean, new RabbitMqConfiguration());
}
}
diff --git a/miscellaneous/roboconf-integration-tests/src/test/java/net/roboconf/integration/probes/DmWithAgentInMemoryTest.java b/miscellaneous/roboconf-integration-tests/src/test/java/net/roboconf/integration/probes/DmWithAgentInMemoryTest.java
index 32e8812d..f8fccaa1 100644
--- a/miscellaneous/roboconf-integration-tests/src/test/java/net/roboconf/integration/probes/DmWithAgentInMemoryTest.java
+++ b/miscellaneous/roboconf-integration-tests/src/test/java/net/roboconf/integration/probes/DmWithAgentInMemoryTest.java
@@ -33,6 +33,7 @@
import net.roboconf.dm.management.Manager;
import net.roboconf.dm.management.api.ITargetHandlerResolver;
import net.roboconf.integration.tests.internal.ItUtils;
+import net.roboconf.integration.tests.internal.parametrized.RabbitMqConfiguration;
import net.roboconf.target.api.TargetException;
import net.roboconf.target.api.TargetHandler;
@@ -56,7 +57,7 @@ public abstract class DmWithAgentInMemoryTest {
@Configuration
public Option[] config() throws Exception {
- return ItUtils.getOptionsForInMemory( true );
+ return ItUtils.getOptionsForInMemory( true, new RabbitMqConfiguration());
}
diff --git a/miscellaneous/roboconf-integration-tests/src/test/java/net/roboconf/integration/probes/ItConfigurationBean.java b/miscellaneous/roboconf-integration-tests/src/test/java/net/roboconf/integration/probes/ItConfigurationBean.java
index 8e53312d..2cc1fb94 100644
--- a/miscellaneous/roboconf-integration-tests/src/test/java/net/roboconf/integration/probes/ItConfigurationBean.java
+++ b/miscellaneous/roboconf-integration-tests/src/test/java/net/roboconf/integration/probes/ItConfigurationBean.java
@@ -117,6 +117,7 @@ public boolean areLogsHidden() {
/**
* @param hideLogs the hideLogs to set
+ * @return this
*/
public ItConfigurationBean hideLogs( boolean hideLogs ) {
this.hideLogs = hideLogs;
diff --git a/miscellaneous/roboconf-integration-tests/src/test/java/net/roboconf/integration/tests/internal/ItUtils.java b/miscellaneous/roboconf-integration-tests/src/test/java/net/roboconf/integration/tests/internal/ItUtils.java
index fec12072..d4b0170f 100644
--- a/miscellaneous/roboconf-integration-tests/src/test/java/net/roboconf/integration/tests/internal/ItUtils.java
+++ b/miscellaneous/roboconf-integration-tests/src/test/java/net/roboconf/integration/tests/internal/ItUtils.java
@@ -39,11 +39,12 @@
import java.net.URI;
import java.util.ArrayList;
import java.util.List;
+import java.util.logging.Logger;
import net.roboconf.core.internal.tests.TestUtils;
import net.roboconf.core.utils.UriUtils;
import net.roboconf.integration.probes.ItConfigurationBean;
-import net.roboconf.messaging.rabbitmq.RabbitMqConstants;
+import net.roboconf.integration.tests.internal.parametrized.IMessagingConfiguration;
import org.ops4j.pax.exam.MavenUtils;
import org.ops4j.pax.exam.Option;
@@ -63,7 +64,6 @@ private ItUtils() {
}
- public static final long PLATFORM_TIMEOUT = 30000;
private static final String[] LOGGERS = {
// Loggers configured in our custom distributions
"net.roboconf",
@@ -77,7 +77,7 @@ private ItUtils() {
/**
* @return a non-null list of options to run Karaf from this test
*/
- public static List
+ *
+ * This class has parameters so that this test is run with
+ * several Roboconf messaging implementations.
+ *
*
* @author Vincent Zurczak - Linagora
*/
+//@RunWith( ParameterizedProbeRunner.class )
@RunWith( RoboconfPaxRunner.class )
@ExamReactorStrategy( PerMethod.class )
public class AgentInMemoryTest extends DmWithAgentInMemoryTest {
@@ -74,6 +85,8 @@ public class AgentInMemoryTest extends DmWithAgentInMemoryTest {
@Inject
@Filter( "(factory.name=roboconf-agent-in-memory)" )
private Factory agentFactory;
+ private final IMessagingConfiguration messagingConfiguration;
+
@ProbeBuilder
@@ -89,15 +102,54 @@ public TestProbeBuilder probeConfiguration( TestProbeBuilder probe ) {
}
+ @Parameters( name = "{method} {index}: agent in memory with {1}" )
+ public static List