import org.opendaylight.controller.md.sal.common.api.data.TransactionChain;
import org.opendaylight.openflowplugin.api.openflow.connection.ConnectionContext;
import org.opendaylight.openflowplugin.api.openflow.device.handlers.MessageHandler;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.OfHeader;
import org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.TableFeatures;
+
import java.math.BigInteger;
+
import org.opendaylight.yangtools.yang.binding.DataObject;
import org.opendaylight.yangtools.yang.common.RpcResult;
+
+import com.google.common.util.concurrent.SettableFuture;
+
import java.util.Collection;
+import java.util.Map;
import java.util.concurrent.Future;
/**
Xid getNextXid();
- <T extends DataObject> Future<RpcResult<T>> sendRequest(DataObject dataObject);
+ <T extends DataObject> Future<RpcResult<T>> sendRequest(Xid xid);
+
+ /**
+ * Method provides requests map
+ * @return
+ */
+ public Map<Xid, RequestFutureContext> getRequests();
+
+ /**
+ * Method writes request context into request context map
+ * @param xid
+ * @param requestFutureContext
+ */
+ public void hookRequestCtx(Xid xid, RequestFutureContext requestFutureContext);
+
+ /**
+ * Method that set future to context in Map
+ * @param xid
+ * @param ofHeader
+ */
+ public void processReply(Xid xid, OfHeader ofHeader);
}
* <p/>
* Created by Martin Bobak <mbobak@cisco.com> on 25.2.2015.
*/
-public interface RequestContext<T extends DataObject> extends RequestFutureContext, AutoCloseable {
+public interface RequestContext<T extends DataObject> extends RequestFutureContext<T>, AutoCloseable {
+ @Override
void close();
* @param <T>
* @return
*/
- <T> SettableFuture<RpcResult<T>> getFuture();
+ SettableFuture<RpcResult<T>> getFuture();
}
import org.opendaylight.yangtools.yang.binding.DataObject;
import org.opendaylight.yangtools.yang.binding.RpcService;
import org.opendaylight.yangtools.yang.common.RpcResult;
-import java.util.concurrent.Future;
/**
* This context is registered with MD-SAL as a routed RPC provider for the inventory node backed by this switch and
<S extends RpcService> void registerRpcServiceImplementation(Class<S> serviceClass, S serviceInstance);
/**
- * Method adds request to request queue which has limited quota. After number of requests exceeds quota limit
- * future will be done immediately and will contain information about exceeded request quota.
- *
+ * Method adds request to request queue which has limited quota. After number of requests exceeds quota limit future
+ * will be done immediately and will contain information about exceeded request quota.
+ *
* @param data
*/
- <T extends DataObject> SettableFuture<RpcResult<T>> storeOrFail(RequestContext data);
+ <T extends DataObject> SettableFuture<RpcResult<T>> storeOrFail(RequestContext<T> data);
/**
* Method for setting request quota value. When the Request Context quota is exceeded, incoming RPCs fail
* immediately, with a well-defined error.
- *
+ *
* @param maxRequestsPerDevice
*/
void setRequestContextQuota(int maxRequestsPerDevice);
- void forgetRequestContext(RequestContext requestContext);
+ <T extends DataObject> void forgetRequestContext(RequestContext<T> requestContext);
/**
* Method provides device context.
+ *
* @return
*/
DeviceContext getDeviceContext();
/**
* Method returns new request context for current request.
+ *
* @return
*/
- <T extends DataObject> RequestContext createRequestContext();
+ <T extends DataObject> RequestContext<T> createRequestContext();
}
*/
package org.opendaylight.openflowplugin.impl.device;
+import java.math.BigInteger;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.Future;
+
import org.opendaylight.controller.md.sal.common.api.data.TransactionChain;
import org.opendaylight.openflowplugin.api.openflow.connection.ConnectionContext;
import org.opendaylight.openflowplugin.api.openflow.device.DeviceContext;
import org.opendaylight.openflowplugin.api.openflow.device.DeviceState;
import org.opendaylight.openflowplugin.api.openflow.device.RequestContext;
+import org.opendaylight.openflowplugin.api.openflow.device.RequestFutureContext;
import org.opendaylight.openflowplugin.api.openflow.device.Xid;
+import org.opendaylight.openflowplugin.api.openflow.device.XidGenerator;
import org.opendaylight.openflowplugin.api.openflow.md.core.SwitchConnectionDistinguisher;
import org.opendaylight.openflowplugin.openflow.md.core.session.SwitchConnectionCookieOFImpl;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.OfHeader;
import org.opendaylight.yang.gen.v1.urn.opendaylight.table.types.rev131026.TableFeatures;
import org.opendaylight.yangtools.yang.binding.ChildOf;
import org.opendaylight.yangtools.yang.binding.DataObject;
import org.opendaylight.yangtools.yang.common.RpcResult;
-import java.math.BigInteger;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.concurrent.Future;
+
+import com.google.common.util.concurrent.SettableFuture;
/**
*
*/
public class DeviceContextImpl implements DeviceContext {
+ private Map<Xid, RequestFutureContext> requests =
+ new HashMap<Xid, RequestFutureContext>();
private final Map<SwitchConnectionDistinguisher, ConnectionContext> auxiliaryConnectionContexts = new HashMap<>();
+ private XidGenerator xidGenerator = new XidGenerator();
@Override
public <M extends ChildOf<DataObject>> void onMessage(M message, RequestContext requestContext) {
// TODO Auto-generated method stub
@Override
public Xid getNextXid() {
- return null;
+ return xidGenerator.generate();
}
@Override
- public <T extends DataObject> Future<RpcResult<T>> sendRequest(final DataObject dataObject) {
+ public <T extends DataObject> Future<RpcResult<T>> sendRequest(Xid xid) {
return null;
}
+ @Override
+ public Map<Xid, RequestFutureContext> getRequests() {
+ // TODO Auto-generated method stub
+ return requests;
+ }
+
+ @Override
+ public void hookRequestCtx(Xid xid, RequestFutureContext requestFutureContext) {
+ // TODO Auto-generated method stub
+ requests.put(xid, requestFutureContext);
+ }
+
+ @Override
+ public void processReply(Xid xid, OfHeader ofHeader) {
+ // TODO Auto-generated method stub
+ SettableFuture replyFuture = getRequests().get(xid).getFuture();
+ replyFuture.set(ofHeader);
+ }
}
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
+import com.google.common.util.concurrent.SettableFuture;
+
import org.opendaylight.openflowplugin.api.openflow.connection.ConnectionContext;
+import org.opendaylight.openflowplugin.api.openflow.device.DeviceContext;
import org.opendaylight.openflowplugin.api.openflow.device.DeviceManager;
import org.opendaylight.openflowplugin.api.openflow.device.RequestContext;
+import org.opendaylight.openflowplugin.api.openflow.device.RequestFutureContext;
import org.opendaylight.openflowplugin.api.openflow.device.Xid;
import org.opendaylight.openflowplugin.api.openflow.device.XidGenerator;
import org.opendaylight.openflowplugin.api.openflow.device.handlers.DeviceContextReadyHandler;
import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.MultipartRequestInputBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.multipart.request.multipart.request.body.MultipartRequestDescCaseBuilder;
import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.common.RpcResult;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+
+import java.util.Map;
import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Future;
/**
*
DeviceContextImpl deviceContextImpl = new DeviceContextImpl();
try {
- FlowCapableNode description = queryDescription(connectionContext, xid.getValue()).get();
+ FlowCapableNode description = queryDescription(connectionContext, deviceContextImpl.getNextXid()).get();
} catch (InterruptedException | ExecutionException e) {
// TODO Auto-generated catch block
/**
* @param connectionContext
- * @param nextXid
+ * @param xid
*/
- private static ListenableFuture<FlowCapableNode> queryDescription(ConnectionContext connectionContext, long nextXid) {
+ private static ListenableFuture<FlowCapableNode> queryDescription(ConnectionContext connectionContext, Xid xid) {
MultipartRequestInputBuilder builder = new MultipartRequestInputBuilder();
builder.setType(MultipartType.OFPMPDESC);
builder.setVersion(connectionContext.getFeatures().getVersion());
builder.setFlags(new MultipartRequestFlags(false));
builder.setMultipartRequestBody(new MultipartRequestDescCaseBuilder()
.build());
- builder.setXid(nextXid);
+ builder.setXid(xid.getValue());
connectionContext.getConnectionAdapter().multipartRequest(builder.build());
//TODO: involve general wait-for-answer mechanism and return future with complete value
/**
* @author joe
*/
-public class RequestContextImpl<T extends DataObject> implements RequestContext {
+public class RequestContextImpl<T extends DataObject> implements RequestContext<T> {
private final RpcContext rpcContext;
private SettableFuture<RpcResult<T>> rpcResultFuture;
package org.opendaylight.openflowplugin.impl.rpc;
import com.google.common.util.concurrent.SettableFuture;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext;
import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.RoutedRpcRegistration;
import org.opendaylight.openflowplugin.api.openflow.device.DeviceContext;
import org.opendaylight.yangtools.yang.common.RpcError;
import org.opendaylight.yangtools.yang.common.RpcResult;
import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
public class RpcContextImpl implements RpcContext {
final ProviderContext providerContext;
// TODO: add private Sal salBroker
- private final List<RequestContext> requestContexts = new ArrayList<>();
- private DeviceContext deviceContext;
+ private final List<RequestContext<? extends DataObject>> requestContexts = new ArrayList<>();
+ private final DeviceContext deviceContext;
private final List<RoutedRpcRegistration> rpcRegistrations = new ArrayList<>();
- private final List<RequestContext> synchronizedRequestsList = Collections.synchronizedList(new ArrayList<RequestContext>());
+ private final List<RequestContext<? extends DataObject>> synchronizedRequestsList = Collections
+ .<RequestContext<? extends DataObject>>synchronizedList(new ArrayList<RequestContext<? extends DataObject>>());
private int maxRequestsPerDevice;
/**
* @see org.opendaylight.openflowplugin.api.openflow.rpc.RpcContext#registerRpcServiceImplementation(java.lang.Class,
- * org.opendaylight.yangtools.yang.binding.RpcService)
+ * org.opendaylight.yangtools.yang.binding.RpcService)
*/
@Override
public <S extends RpcService> void registerRpcServiceImplementation(final Class<S> serviceClass,
- final S serviceInstance) {
+ final S serviceInstance) {
rpcRegistrations.add(providerContext.addRoutedRpcImplementation(serviceClass, serviceInstance));
}
@Override
- public <T extends DataObject> SettableFuture<RpcResult<T>> storeOrFail(RequestContext requestContext) {
+ public <T extends DataObject> SettableFuture<RpcResult<T>> storeOrFail(final RequestContext<T> requestContext) {
final SettableFuture<RpcResult<T>> rpcResultFuture = requestContext.getFuture();
if (synchronizedRequestsList.size() < maxRequestsPerDevice) {
synchronizedRequestsList.add(requestContext);
} else {
- RpcResult rpcResult = RpcResultBuilder.failed().withError(RpcError.ErrorType.APPLICATION, "", "Device's request queue is full.").build();
+ final RpcResult<T> rpcResult = RpcResultBuilder.<T>failed()
+ .withError(RpcError.ErrorType.APPLICATION, "", "Device's request queue is full.").build();
rpcResultFuture.set(rpcResult);
}
return rpcResultFuture;
}
-
/**
* Unregisters all services.
*
}
@Override
- public void forgetRequestContext(final RequestContext requestContext) {
+ public <T extends DataObject> void forgetRequestContext(final RequestContext<T> requestContext) {
requestContexts.remove(requestContext);
}
}
@Override
- public <T extends DataObject> RequestContext createRequestContext() {
+ public <T extends DataObject> RequestContext<T> createRequestContext() {
return new RequestContextImpl<T>(this);
}
--- /dev/null
+package org.opendaylight.openflowplugin.impl.device;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+import java.util.Collections;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.runners.MockitoJUnitRunner;
+import org.opendaylight.openflowplugin.api.OFConstants;
+import org.opendaylight.openflowplugin.api.openflow.device.RequestContext;
+import org.opendaylight.openflowplugin.api.openflow.device.Xid;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.GetAsyncOutput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.GetAsyncOutputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.GetAsyncReply;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.OfHeader;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.async.body.grouping.FlowRemovedMask;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.async.body.grouping.PacketInMask;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.async.body.grouping.PortStatusMask;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.util.concurrent.SettableFuture;
+
+@RunWith(MockitoJUnitRunner.class)
+public class DeviceContextImplTest {
+ private static final Logger LOG = LoggerFactory
+ .getLogger(DeviceContextImplTest.class);
+ Xid xid;
+ DeviceContextImpl deviceContext;
+ @Mock
+ RequestContext<GetAsyncReply> requestContext;
+
+ @Before
+ public void setUp() {
+ deviceContext = new DeviceContextImpl();
+ xid = deviceContext.getNextXid();
+ SettableFuture<RpcResult<GetAsyncReply>> settableFuture = SettableFuture.create();
+ Mockito.when(requestContext.getFuture()).thenReturn(settableFuture);
+ deviceContext.hookRequestCtx(deviceContext.getNextXid(), requestContext);
+ }
+
+ private GetAsyncOutput createAsyncOutput() {
+ GetAsyncOutputBuilder asyncOutputBuilder = new GetAsyncOutputBuilder();
+ asyncOutputBuilder.setFlowRemovedMask(Collections.<FlowRemovedMask> emptyList());
+ asyncOutputBuilder.setPacketInMask(Collections.<PacketInMask> emptyList());
+ asyncOutputBuilder.setPortStatusMask(Collections.<PortStatusMask> emptyList());
+ asyncOutputBuilder.setVersion(OFConstants.OFP_VERSION_1_3);
+ asyncOutputBuilder.setXid(xid.getValue());
+ return asyncOutputBuilder.build();
+ }
+
+ @Test
+ public void testProcessReply() {
+ GetAsyncOutput asyncOutput = createAsyncOutput();
+ LOG.info("Hooking RequestContext");
+ deviceContext.hookRequestCtx(xid, requestContext);
+ Assert.assertEquals(requestContext, deviceContext.getRequests().get(xid));
+
+ Assert.assertFalse(requestContext.getFuture().isDone());
+ LOG.info("Sending reply from device");
+ deviceContext.processReply(xid, asyncOutput);
+ Assert.assertTrue(requestContext.getFuture().isDone());
+
+ LOG.info("Checking RequestContext.future");
+ try {
+ Object object = requestContext.getFuture().get(1L, TimeUnit.SECONDS);
+ GetAsyncOutput getAsyncOutput = (GetAsyncOutput) object;
+ assertEquals(asyncOutput.getVersion(), getAsyncOutput.getVersion());
+ } catch (InterruptedException | ExecutionException | TimeoutException e) {
+ LOG.error("Test failed when checking RequestContext.future", e);
+ fail("fail");
+ }
+ }
+
+}
@Test
public void testAddRequestContextReadyHandler() {
}
+
+ @Test
+ public void testHookRequest() {
+
+ }
}