.setType(etherType);
targetEthMatchBuild.setEthernetType(ethType.build());
}
- if((sourceMatch.getField(DL_SRC) != null && sourceMatch.getField(DL_SRC).getValue() != null) ||
- (sourceMatch.getField(DL_DST) != null && sourceMatch.getField(DL_DST).getValue() != null)||
+ if((sourceMatch.getField(DL_SRC) != null && sourceMatch.getField(DL_SRC).getValue() != null) ||
+ (sourceMatch.getField(DL_DST) != null && sourceMatch.getField(DL_DST).getValue() != null)||
dataLinkType != null ) {
- return targetEthMatchBuild.build();
- }
+ return targetEthMatchBuild.build();
+ }
return null;
}
.toAddrString(inetDestAddress);
layer4MatchBuild
.setIpv4Destination(new Ipv4Prefix(inetDstAddressString));
- }
+ }
return layer4MatchBuild.build();
}
}
if(inetDestAddress != null) {
String inetDstAddressString = InetAddresses
- .toAddrString(inetDestAddress);
+ .toAddrString(inetDestAddress);
layer6MatchBuild
.setIpv6Destination(new Ipv6Prefix(inetDstAddressString));
}
return layer6MatchBuild.build();
}
-
+
public static boolean flowEquals(Flow statsFlow, Flow storedFlow) {
if (statsFlow.getClass() != storedFlow.getClass()) {
return false;
public static List<org.opendaylight.controller.sal.action.Action> actionFrom(List<Action> actions, Node node) {
List<org.opendaylight.controller.sal.action.Action> targetAction = new ArrayList<>();
for (Action action : actions) {
- org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.Action sourceAction = action
+ org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.Action sourceAction = action
.getAction();
if (sourceAction instanceof ControllerActionCase) {
}
return macAddress;
}
-
+
public static byte[] bytesFromDpid(long dpid) {
byte[] mac = new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
{(byte) 0x7f, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff},
{(byte) 0x76, (byte) 0x4a, (byte) 0xe9, (byte) 0xac, (byte) 0xe6, (byte) 0x5a}
};
-
+
Assert.assertEquals(expectedMacs.length, nodeIds.length);
for (int i = 0; i < expectedMacs.length; i++) {
boolean b) {
int numOfFoundActions = 0;
for (org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action action : actions) {
- org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.Action innerAction = action
+ org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.Action innerAction = action
.getAction();
if (cl.isInstance(innerAction)) {
numOfFoundActions++;
public void testToSalConversion() throws ConstructionException {
FlowAddedBuilder odNodeFlowBuilder = new FlowAddedBuilder();
odNodeFlowBuilder = prepareOdFlowCommon();
-
+
Node node = new Node(NodeIDType.OPENFLOW,(long)1);
-
+
Flow salFlow = ToSalConversionsUtils.toFlow(prepareOdFlow(odNodeFlowBuilder, MtchType.other), node);
checkSalMatch(salFlow.getMatch(), MtchType.other);
private void checkSalMatch(org.opendaylight.controller.sal.match.Match match, MtchType mt) {
switch (mt) {
case other:
- /*assertNotNull("DL_DST isn't equal.", "3C:A9:F4:00:E0:C8",
+ /*assertNotNull("DL_DST isn't equal.", "3C:A9:F4:00:E0:C8",
new String((byte[]) match.getField(MatchType.DL_DST).getValue()));
assertEquals("DL_SRC isn't equal.", "24:77:03:7C:C5:F1",
new String((byte[]) match.getField(MatchType.DL_SRC).getValue()));
odActions.add(new ActionBuilder().setAction(setVlanPcpActionBuilder.build()).build());
odActions.add(new ActionBuilder().setAction(swPathActionBuilder.build()).build());
-
+
ApplyActionsCase innerInst = new ApplyActionsCaseBuilder().setApplyActions(new ApplyActionsBuilder().setAction(odActions).build()).build();
Instruction applyActions = new InstructionBuilder().setInstruction(innerInst).build();
List<Instruction> instructions = Collections.singletonList(applyActions );
InstructionsBuilder instBuilder = new InstructionsBuilder();
-
+
instBuilder.setInstruction(instructions);
-
+
return instBuilder.build();
}
private void prepareActionSetNwDst(List<Action> odActions) {
// test case for IPv4
-
+
SetNwDstActionBuilder setNwDstActionBuilderIpv4 = new SetNwDstActionBuilder();
setNwDstActionBuilderIpv4.setAddress(prapareIpv4Address("192.168.100.101"));
odActions.add(new ActionBuilder().setAction(new SetNwDstActionCaseBuilder().setSetNwDstAction(setNwDstActionBuilderIpv4.build()).build()).build());
/**
* Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
- *
+ *
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v1.0 which accompanies this distribution,
* and is available at http://www.eclipse.org/legal/epl-v10.html
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
/**
- *
+ *
* @author <a href="mailto:vdemcak@cisco.com">Vaclav Demcak</a>
*
*/
public void onDataChanged(DataChangeEvent<InstanceIdentifier<?>, DataObject> changeEvent) {
this.transactionId = this.newTransactionIdentifier().toString();
- final Set<Entry<InstanceIdentifier<? extends DataObject>, DataObject>> createdEntries =
+ final Set<Entry<InstanceIdentifier<? extends DataObject>, DataObject>> createdEntries =
changeEvent.getCreatedConfigurationData().entrySet();
- final Set<Entry<InstanceIdentifier<? extends DataObject>, DataObject>> updatedEntries =
+ final Set<Entry<InstanceIdentifier<? extends DataObject>, DataObject>> updatedEntries =
new HashSet<Entry<InstanceIdentifier<? extends DataObject>, DataObject>>();
- Set<Entry<InstanceIdentifier<? extends DataObject>, DataObject>> updateConfigEntrySet =
+ Set<Entry<InstanceIdentifier<? extends DataObject>, DataObject>> updateConfigEntrySet =
changeEvent.getUpdatedConfigurationData().entrySet();
updatedEntries.addAll(updateConfigEntrySet);
updatedEntries.removeAll(createdEntries);
- final Set<InstanceIdentifier<? extends DataObject>> removeEntriesInstanceIdentifiers =
+ final Set<InstanceIdentifier<? extends DataObject>> removeEntriesInstanceIdentifiers =
changeEvent.getRemovedConfigurationData();
for (final Entry<InstanceIdentifier<? extends DataObject>, DataObject> createdEntry : createdEntries) {
}
for (final Entry<InstanceIdentifier<?>, DataObject> updatedEntrie : updatedEntries) {
- Map<InstanceIdentifier<? extends DataObject>, DataObject> origConfigData =
+ Map<InstanceIdentifier<? extends DataObject>, DataObject> origConfigData =
changeEvent.getOriginalConfigurationData();
InstanceIdentifier<? extends Object> u_key = updatedEntrie.getKey();
}
for (final InstanceIdentifier<?> instanceId : removeEntriesInstanceIdentifiers) {
- Map<InstanceIdentifier<? extends DataObject>, DataObject> origConfigData =
+ Map<InstanceIdentifier<? extends DataObject>, DataObject> origConfigData =
changeEvent.getOriginalConfigurationData();
final DataObject removeValue = origConfigData.get(instanceId);
/**
* Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
- *
+ *
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v1.0 which accompanies this distribution,
* and is available at http://www.eclipse.org/legal/epl-v10.html
private final static Logger LOG = LoggerFactory.getLogger(FRMActivator.class);
- private static FlowProvider flowProvider = new FlowProvider();
+ private static FlowProvider flowProvider = new FlowProvider();
private static GroupProvider groupProvider = new GroupProvider();
private static MeterProvider meterProvider = new MeterProvider();
-
+
@Override
public void onSessionInitiated(final ProviderContext session) {
DataProviderService flowSalService = session.<DataProviderService>getSALService(DataProviderService.class);
FRMActivator.meterProvider.setSalMeterService(rpcMeterSalService);
FRMActivator.meterProvider.start();
}
-
+
@Override
protected void stopImpl(final BundleContext context) {
try {
/**
* Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
- *
+ *
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v1.0 which accompanies this distribution,
* and is available at http://www.eclipse.org/legal/epl-v10.html
import org.slf4j.LoggerFactory;
/**
- *
+ *
* @author <a href="mailto:vdemcak@cisco.com">Vaclav Demcak</a>
*
*/
public SalFlowService getSalFlowService() {
return this.salFlowService;
}
-
+
public FlowChangeListener(final SalFlowService manager) {
this.salFlowService = manager;
}
@Override
protected void remove(InstanceIdentifier<? extends DataObject> identifier, DataObject removeDataObj) {
if ((removeDataObj instanceof Flow)) {
-
+
final Flow flow = ((Flow) removeDataObj);
final InstanceIdentifier<Table> tableInstanceId = identifier.<Table> firstIdentifierOf(Table.class);
final InstanceIdentifier<Node> nodeInstanceId = identifier.<Node> firstIdentifierOf(Node.class);
final RemoveFlowInputBuilder builder = new RemoveFlowInputBuilder(flow);
-
+
builder.setFlowRef(new FlowRef(identifier));
builder.setNode(new NodeRef(nodeInstanceId));
builder.setFlowTable(new FlowTableRef(tableInstanceId));
-
+
Uri uri = new Uri(this.getTransactionId());
builder.setTransactionUri(uri);
this.salFlowService.removeFlow((RemoveFlowInput) builder.build());
@Override
protected void update(InstanceIdentifier<? extends DataObject> identifier, DataObject original, DataObject update) {
if (original instanceof Flow && update instanceof Flow) {
-
+
final Flow originalFlow = ((Flow) original);
final Flow updatedFlow = ((Flow) update);
final InstanceIdentifier<Node> nodeInstanceId = identifier.<Node>firstIdentifierOf(Node.class);
final UpdateFlowInputBuilder builder = new UpdateFlowInputBuilder();
-
+
builder.setNode(new NodeRef(nodeInstanceId));
builder.setFlowRef(new FlowRef(identifier));
-
+
Uri uri = new Uri(this.getTransactionId());
builder.setTransactionUri(uri);
-
+
builder.setUpdatedFlow((UpdatedFlow) (new UpdatedFlowBuilder(updatedFlow)).build());
builder.setOriginalFlow((OriginalFlow) (new OriginalFlowBuilder(originalFlow)).build());
-
+
this.salFlowService.updateFlow((UpdateFlowInput) builder.build());
LOG.debug("Transaction {} - Update Flow has updated flow {} with {}", new Object[]{uri, original, update});
}
@Override
protected void add(InstanceIdentifier<? extends DataObject> identifier, DataObject addDataObj) {
if ((addDataObj instanceof Flow)) {
-
+
final Flow flow = ((Flow) addDataObj);
final InstanceIdentifier<Table> tableInstanceId = identifier.<Table> firstIdentifierOf(Table.class);
final InstanceIdentifier<Node> nodeInstanceId = identifier.<Node> firstIdentifierOf(Node.class);
final AddFlowInputBuilder builder = new AddFlowInputBuilder(flow);
-
+
builder.setNode(new NodeRef(nodeInstanceId));
builder.setFlowRef(new FlowRef(identifier));
builder.setFlowTable(new FlowTableRef(tableInstanceId));
-
+
Uri uri = new Uri(this.getTransactionId());
builder.setTransactionUri(uri);
this.salFlowService.addFlow((AddFlowInput) builder.build());
/**
* Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
- *
+ *
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v1.0 which accompanies this distribution,
* and is available at http://www.eclipse.org/legal/epl-v10.html
InstanceIdentifierBuilder<Table> tableChild = augmentFlowCapNode.<Table> child(Table.class);
InstanceIdentifierBuilder<Flow> flowChild = tableChild.<Flow> child(Flow.class);
final InstanceIdentifier<? extends DataObject> flowDataObjectPath = flowChild.toInstance();
-
+
/* DataChangeListener registration */
this.flowDataChangeListener = new FlowChangeListener(this.salFlowService);
this.flowDataChangeListenerRegistration = this.dataService.registerDataChangeListener(flowDataObjectPath, flowDataChangeListener);
/**
* Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
- *
+ *
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v1.0 which accompanies this distribution,
* and is available at http://www.eclipse.org/legal/epl-v10.html
/**
* Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
- *
+ *
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v1.0 which accompanies this distribution,
* and is available at http://www.eclipse.org/legal/epl-v10.html
import org.slf4j.LoggerFactory;
/**
- *
+ *
* @author <a href="mailto:vdemcak@cisco.com">Vaclav Demcak</a>
*
*/
public SalGroupService getSalGroupService() {
return this.salGroupService;
}
-
+
public GroupChangeListener(final SalGroupService manager) {
this.salGroupService = manager;
}
@Override
protected void remove(InstanceIdentifier<? extends DataObject> identifier, DataObject removeDataObj) {
if ((removeDataObj instanceof Group)) {
-
+
final Group group = ((Group) removeDataObj);
final InstanceIdentifier<Node> nodeInstanceId = identifier.<Node> firstIdentifierOf(Node.class);
final RemoveGroupInputBuilder builder = new RemoveGroupInputBuilder(group);
-
+
builder.setNode(new NodeRef(nodeInstanceId));
builder.setGroupRef(new GroupRef(identifier));
-
+
Uri uri = new Uri(this.getTransactionId());
builder.setTransactionUri(uri);
this.salGroupService.removeGroup((RemoveGroupInput) builder.build());
@Override
protected void update(InstanceIdentifier<? extends DataObject> identifier, DataObject original, DataObject update) {
if (original instanceof Group && update instanceof Group) {
-
+
final Group originalGroup = ((Group) original);
final Group updatedGroup = ((Group) update);
final InstanceIdentifier<Node> nodeInstanceId = identifier.<Node> firstIdentifierOf(Node.class);
final UpdateGroupInputBuilder builder = new UpdateGroupInputBuilder();
-
+
builder.setNode(new NodeRef(nodeInstanceId));
builder.setGroupRef(new GroupRef(identifier));
-
+
Uri uri = new Uri(this.getTransactionId());
builder.setTransactionUri(uri);
-
+
builder.setUpdatedGroup((UpdatedGroup) (new UpdatedGroupBuilder(updatedGroup)).build());
builder.setOriginalGroup((OriginalGroup) (new OriginalGroupBuilder(originalGroup)).build());
-
+
this.salGroupService.updateGroup((UpdateGroupInput) builder.build());
LOG.debug("Transaction {} - Update Group has updated group {} with group {}", new Object[]{uri, original, update});
}
final Group group = ((Group) addDataObj);
final InstanceIdentifier<Node> nodeInstanceId = identifier.<Node> firstIdentifierOf(Node.class);
final AddGroupInputBuilder builder = new AddGroupInputBuilder(group);
-
+
builder.setNode(new NodeRef(nodeInstanceId));
builder.setGroupRef(new GroupRef(identifier));
-
+
Uri uri = new Uri(this.getTransactionId());
builder.setTransactionUri(uri);
this.salGroupService.addGroup((AddGroupInput) builder.build());
/**
* Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
- *
+ *
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v1.0 which accompanies this distribution,
* and is available at http://www.eclipse.org/legal/epl-v10.html
this.groupDataChangeListenerRegistration = this.dataService.registerDataChangeListener(groupDataObjectPath, groupDataChangeListener);
LOG.info("Group Config Provider started.");
}
-
+
protected DataModificationTransaction startChange() {
return this.dataService.beginTransaction();
}
-
+
public void close() throws Exception {
if(groupDataChangeListenerRegistration != null){
groupDataChangeListenerRegistration.close();
/**
* Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
- *
+ *
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v1.0 which accompanies this distribution,
* and is available at http://www.eclipse.org/legal/epl-v10.html
import org.slf4j.LoggerFactory;
/**
- *
+ *
* @author <a href="mailto:vdemcak@cisco.com">Vaclav Demcak</a>
*
*/
public SalMeterService getSalMeterService() {
return this.salMeterService;
}
-
+
public MeterChangeListener(final SalMeterService manager) {
this.salMeterService = manager;
}
@Override
protected void remove(InstanceIdentifier<? extends DataObject> identifier, DataObject removeDataObj) {
if ((removeDataObj instanceof Meter)) {
-
+
final Meter meter = ((Meter) removeDataObj);
final InstanceIdentifier<Node> nodeInstanceId = identifier.<Node> firstIdentifierOf(Node.class);
final RemoveMeterInputBuilder builder = new RemoveMeterInputBuilder(meter);
-
+
builder.setNode(new NodeRef(nodeInstanceId));
builder.setMeterRef(new MeterRef(identifier));
-
+
Uri uri = new Uri(this.getTransactionId());
builder.setTransactionUri(uri);
this.salMeterService.removeMeter((RemoveMeterInput) builder.build());
@Override
protected void update(InstanceIdentifier<? extends DataObject> identifier, DataObject original, DataObject update) {
if (original instanceof Meter && update instanceof Meter) {
-
+
final Meter originalMeter = ((Meter) original);
final Meter updatedMeter = ((Meter) update);
final InstanceIdentifier<Node> nodeInstanceId = identifier.<Node> firstIdentifierOf(Node.class);
final UpdateMeterInputBuilder builder = new UpdateMeterInputBuilder();
-
+
builder.setNode(new NodeRef(nodeInstanceId));
builder.setMeterRef(new MeterRef(identifier));
-
+
Uri uri = new Uri(this.getTransactionId());
builder.setTransactionUri(uri);
-
+
builder.setUpdatedMeter((UpdatedMeter) (new UpdatedMeterBuilder(updatedMeter)).build());
builder.setOriginalMeter((OriginalMeter) (new OriginalMeterBuilder(originalMeter)).build());
-
+
this.salMeterService.updateMeter((UpdateMeterInput) builder.build());
LOG.debug("Transaction {} - Update Meter has updated meter {} with {}", new Object[]{uri, original, update});
}
@Override
protected void add(InstanceIdentifier<? extends DataObject> identifier, DataObject addDataObj) {
if ((addDataObj instanceof Meter)) {
-
+
final Meter meter = ((Meter) addDataObj);
final InstanceIdentifier<Node> nodeInstanceId = identifier.<Node> firstIdentifierOf(Node.class);
final AddMeterInputBuilder builder = new AddMeterInputBuilder(meter);
-
+
builder.setNode(new NodeRef(nodeInstanceId));
builder.setMeterRef(new MeterRef(identifier));
-
+
Uri uri = new Uri(this.getTransactionId());
builder.setTransactionUri(uri);
this.salMeterService.addMeter((AddMeterInput) builder.build());
/**
* Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
- *
+ *
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v1.0 which accompanies this distribution,
* and is available at http://www.eclipse.org/legal/epl-v10.html
this.meterDataChangeListenerRegistration = this.dataService.registerDataChangeListener(meterDataObjectPath, meterDataChangeListener);
LOG.info("Meter Config Provider started.");
}
-
+
protected DataModificationTransaction startChange() {
return this.dataService.beginTransaction();
}
Future<RpcResult<TransactionStatus>> commitResult = it.commit();
listenOnTransactionState(it.getIdentifier(), commitResult, "node update", ref.getValue());
}
-
+
/**
* @param txId transaction identificator
* @param future transaction result
private static void listenOnTransactionState(final Object txId, Future<RpcResult<TransactionStatus>> future,
final String action, final InstanceIdentifier<?> nodeConnectorPath) {
Futures.addCallback(JdkFutureAdapters.listenInPoolThread(future),new FutureCallback<RpcResult<TransactionStatus>>() {
-
+
@Override
public void onFailure(Throwable t) {
LOG.error("Action {} [{}] failed for Tx:{}", action, nodeConnectorPath, txId, t);
-
+
}
-
+
@Override
public void onSuccess(RpcResult<TransactionStatus> result) {
if(!result.isSuccessful()) {
private ServiceTracker<BindingAwareBroker, BindingAwareBroker> tracker;
private BindingAwareBroker broker;
private ServiceTrackerCustomizer<BindingAwareBroker, BindingAwareBroker> customizer = new ServiceTrackerCustomizer<BindingAwareBroker, BindingAwareBroker>() {
-
+
@Override
public BindingAwareBroker addingService(ServiceReference<BindingAwareBroker> reference) {
broker = context.getService(reference);
mdActivationPool.execute(new Runnable() {
-
+
@Override
public void run() {
onBrokerAvailable(broker, context);;
});
return broker;
}
-
+
@Override
public void modifiedService(ServiceReference<BindingAwareBroker> reference, BindingAwareBroker service) {
// TODO Auto-generated method stub
-
+
}
@Override
public void removedService(ServiceReference<BindingAwareBroker> reference, BindingAwareBroker service) {
// TODO Auto-generated method stub
-
+
}
};
-
-
+
+
@Override
public final void start(BundleContext context) throws Exception {
this.context = context;
startImpl(context);
tracker = new ServiceTracker<>(context, BindingAwareBroker.class, customizer);
tracker.open();
-
+
}
-
+
@Override
public final void stop(BundleContext context) throws Exception {
tracker.close();
stopImpl(context);
}
-
-
+
+
/**
* Called when this bundle is started (before
* {@link #onSessionInitiated(ProviderContext)} so the Framework can perform
* the bundle-specific activities necessary to start this bundle. This
* method can be used to register services or to allocate any resources that
* this bundle needs.
- *
+ *
* <p>
* This method must complete and return to its caller in a timely manner.
- *
+ *
* @param context
* The execution context of the bundle being started.
* @throws Exception
* started. There should be no active threads that were started by this
* bundle when this bundle returns. A stopped bundle must not call any
* Framework objects.
- *
+ *
* <p>
* This method must complete and return to its caller in a timely manner.
- *
+ *
* @param context The execution context of the bundle being stopped.
* @throws Exception If this method throws an exception, the bundle is still
* marked as stopped, and the Framework will remove the bundle's
protected void stopImpl(BundleContext context) {
// NOOP
}
-
+
protected abstract void onBrokerAvailable(BindingAwareBroker broker, BundleContext context);
-
+
protected void onBrokerRemoved(BindingAwareBroker broker, BundleContext context) {
-
+
}
}
import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ConsumerContext;
/**
- *
+ *
* Defines the component of controller and supplies additional metadata. A
* component of the controller or application supplies a concrete implementation
* of this interface.
- *
+ *
* A user-implemented component (application) which facilitates the SAL and SAL
* services to access infrastructure services or providers' functionality.
- *
- *
- *
+ *
+ *
+ *
*/
public interface BindingAwareConsumer {
/**
* Callback signaling initialization of the consumer session to the SAL.
- *
+ *
* The consumer MUST use the session for all communication with SAL or
* retrieving SAL infrastructure services.
- *
+ *
* This method is invoked by
* {@link BindingAwareBroker#registerConsumer(BindingAwareConsumer)}
- *
+ *
* @param session
* Unique session between consumer and SAL.
*/
import org.opendaylight.yangtools.yang.binding.RpcService;
/**
- *
+ *
* Defines the component of controller and supplies additional metadata. A
* component of the controller or application supplies a concrete implementation
* of this interface.
- *
+ *
* <p>
* A user-implemented component (application) which facilitates the SAL and SAL
* services to access infrastructure services and to provide functionality to
* {@link Consumer}s and other providers.
- *
- *
+ *
+ *
*/
public interface BindingAwareProvider {
/**
* Returns a set of provided implementations of YANG modules and their rpcs.
- *
- *
+ *
+ *
* @return Set of provided implementation of YANG modules and their Rpcs
*/
Collection<? extends RpcService> getImplementations();
/**
* Gets a set of implementations of provider functionality to be registered
* into system during the provider registration to the SAL.
- *
+ *
* <p>
* This method is invoked by {@link Broker#registerProvider(Provider)} to
* learn the initial provided functionality
- *
+ *
* @return Set of provider's functionality.
*/
Collection<? extends ProviderFunctionality> getFunctionality();
/**
* Functionality provided by the {@link BindingAwareProvider}
- *
+ *
* <p>
* Marker interface used to mark the interfaces describing specific
* functionality which could be exposed by providers to other components.
- *
- *
- *
+ *
+ *
+ *
*/
public interface ProviderFunctionality {
import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ConsumerContext;
/**
- *
+ *
* Session-specific instance of the broker functionality.
- *
+ *
* <p>
* BindingAwareService is marker interface for infrastructure services provided
* by the SAL. These services are session-specific, each
* {@link BindingAwareConsumer} and {@link BindingAwareProvider} usually has own
* instance of the service with it's own context.
- *
+ *
* <p>
* The consumer's (or provider's) instance of specific service could be obtained
* by invoking {@link ConsumerContext#getSALService(Class)} method on session
* assigned to the consumer.
- *
+ *
* <p>
* {@link BindingAwareService} and {@link BindingAwareProvider} may seem
* similar, but provider provides YANG model-based functionality and
* to implement specific functionality of YANG and to reuse it in the
* development of {@link BindingAwareConsumer}s and {@link BindingAwareProvider}
* s.
- *
- *
- *
+ *
+ *
+ *
*/
public interface BindingAwareService {
* @param <T> Notification type
*/
public interface NotificationListener<T extends Notification> extends EventListener {
- /**
- * Invoked to deliver the notification. Note that this method may be invoked
- * from a shared thread pool, so implementations SHOULD NOT perform CPU-intensive
- * operations and they definitely MUST NOT invoke any potentially blocking
- * operations.
- *
- * @param notification Notification being delivered.
- */
+ /**
+ * Invoked to deliver the notification. Note that this method may be invoked
+ * from a shared thread pool, so implementations SHOULD NOT perform CPU-intensive
+ * operations and they definitely MUST NOT invoke any potentially blocking
+ * operations.
+ *
+ * @param notification Notification being delivered.
+ */
void onNotification(T notification);
}
/**
* Base interface defining contract for retrieving MD-SAL
* version of RpcServices
- *
+ *
*/
public interface RpcConsumerRegistry extends BindingAwareService {
/**
* Returns a session specific instance (implementation) of requested
* YANG module implementation / service provided by consumer.
- *
+ *
* @return Session specific implementation of service
*/
<T extends RpcService> T getRpcService(Class<T> module);
* @return new blank data modification transaction.
*/
@Override
- DataModificationTransaction beginTransaction();
+ DataModificationTransaction beginTransaction();
/**
* Reads data subtree from configurational store.
* Provider's version of Mount Point, this version allows access to MD-SAL
* services specific for this mountpoint and registration / provision of
* interfaces for mount point.
- *
+ *
* @author ttkacik
- *
+ *
*/
public interface MountProviderInstance //
extends //
public final Class<? extends RpcService> rpcService;
public final Class<? extends BaseIdentity> routingContext;
-
+
private RpcContextIdentifier(Class<? extends RpcService> rpcService, Class<? extends BaseIdentity> routingContext) {
super();
this.rpcService = rpcService;
public Class<? extends BaseIdentity> getRoutingContext() {
return routingContext;
}
-
+
public static final RpcContextIdentifier contextForGlobalRpc(Class<? extends RpcService> serviceType) {
return new RpcContextIdentifier(serviceType, null);
}
-
+
public static final RpcContextIdentifier contextFor(Class<? extends RpcService> serviceType,Class<? extends BaseIdentity> routingContext) {
return new RpcContextIdentifier(serviceType, routingContext);
}
/**
* Updates route for particular path to specified instance of
* {@link RpcService}.
- *
+ *
* @param path
* Path for which RpcService routing is to be updated
* @param service
/**
* Deletes a route for particular path
- *
+ *
* @param path
* Path for which
*/
void removeRoute(InstanceIdentifier<?> path);
/**
- *
+ *
*/
S getRoute(InstanceIdentifier<?> nodeInstance);
/**
- *
+ *
* @return
*/
Map<InstanceIdentifier<?>, S> getRoutes();
*/
public class BindingBrokerImplModuleFactory extends org.opendaylight.controller.config.yang.md.sal.binding.impl.AbstractBindingBrokerImplModuleFactory {
-
+
@Override
public Module createModule(String instanceName, DependencyResolver dependencyResolver, BundleContext bundleContext) {
BindingBrokerImplModule module = (BindingBrokerImplModule) super.createModule(instanceName, dependencyResolver, bundleContext);
module.setBundleContext(bundleContext);
return module;
}
-
+
@Override
public Module createModule(String instanceName, DependencyResolver dependencyResolver,
DynamicMBeanWithInstance old, BundleContext bundleContext) throws Exception {
/**
* Returns an instance of provided RpcService type which delegates all calls
* to the delegate.
- *
+ *
* <p>
* Returned instance:
* <ul>
* all calls are delegated.
* <li>{@link DelegateProxy#setDelegate(Object)} - sets the delegate for
* particular instance
- *
+ *
* </ul>
- *
+ *
* @param serviceType
* - Subclass of RpcService for which direct proxy is to be
* generated.
* @return Instance of RpcService of provided serviceType which implements
* and {@link DelegateProxy}
* @throws IllegalArgumentException
- *
+ *
*/
<T extends RpcService> T getDirectProxyFor(Class<T> serviceType) throws IllegalArgumentException;
/**
* Returns an instance of provided RpcService type which routes all calls to
* other instances selected on particular input field.
- *
+ *
* <p>
* Returned instance:
* <ul>
* is not present on any field invocation will be delegated to default
* service {@link RpcRouter#getDefaultService()}.
* </ul>
- *
+ *
* @param serviceType
* - Subclass of RpcService for which Router is to be generated.
* @return Instance of RpcService of provided serviceType which implements
LOG.info("Starting Binding Aware Broker: {}", identifier);
controllerRoot = new RootSalInstance(getRpcProviderRegistry(), getNotificationBroker(), getDataBroker());
-
+
supportedConsumerServices = ImmutableClassToInstanceMap.<BindingAwareService> builder()
.put(NotificationService.class, getRoot()) //
public void close() throws Exception {
// FIXME: Close all sessions
}
-
+
@Override
public <T extends RpcService> RoutedRpcRegistration<T> addRoutedRpcImplementation(Class<T> type, T implementation)
throws IllegalStateException {
return getRoot().addRoutedRpcImplementation(type, implementation);
}
-
+
@Override
public <T extends RpcService> RpcRegistration<T> addRpcImplementation(Class<T> type, T implementation)
throws IllegalStateException {
return getRoot().addRpcImplementation(type, implementation);
}
-
+
@Override
public <T extends RpcService> T getRpcService(Class<T> module) {
return getRoot().getRpcService(module);
L arg0) {
return getRoot().registerRouteChangeListener(arg0);
}
-
+
public class RootSalInstance extends
AbstractBindingSalProviderInstance<DataProviderService, NotificationProviderService, RpcProviderRegistry> {
connector.startDataForwarding();
}
- public static void startNotificationForwarding(BindingIndependentConnector connector,
+ public static void startNotificationForwarding(BindingIndependentConnector connector,
NotificationProviderService baService, NotificationPublishService domService) {
if(connector.isNotificationForwarding()) {
return;
DomForwardedBroker forwardedSource = (DomForwardedBroker) source;
DomForwardedBroker forwardedTarget = (DomForwardedBroker) target;
reuseForwardingFrom(forwardedTarget, forwardedSource);
-
+
}
private static void reuseForwardingFrom(DomForwardedBroker target, DomForwardedBroker source) {
package org.opendaylight.controller.sal.binding.spi;
public interface DelegateProxy<T> {
-
+
void setDelegate(T delegate);
T getDelegate();
}
public interface RemoteRpcRouter {
-
-
-
-
+
+
+
+
ListenerRegistration<RouteChangeListener> registerRouteChangeListener(RouteChangeListener listener);
-
-
+
+
}
import org.opendaylight.yangtools.yang.data.api.CompositeNode;
public class UnionSerializationTest extends AbstractDataServiceTest {
-
+
public static final String PREFIX_STRING = "192.168.0.1/32";
-
-
+
+
@Test
public void testPrefixSerialization() throws Exception {
-
+
Ipv4Prefix ipv4prefix = new Ipv4Prefix(PREFIX_STRING);
IpPrefix ipPrefix = new IpPrefix(ipv4prefix);
Prefix prefix = new PrefixBuilder().setPrefix(ipPrefix).build();
-
+
CompositeNode serialized = testContext.getBindingToDomMappingService().toDataDom(prefix);
assertNotNull(serialized);
assertNotNull(serialized.getFirstSimpleByName(Prefix.QNAME));
assertEquals(PREFIX_STRING, serialized.getFirstSimpleByName(Prefix.QNAME).getValue());
-
+
Prefix deserialized = (Prefix) testContext.getBindingToDomMappingService().dataObjectFromDataDom(Prefix.class, serialized);
assertNotNull(deserialized);
assertNotNull(deserialized.getPrefix());
public interface BarListener extends NotificationListener {
void onBarUpdate(BarUpdate notification);
-
+
void onFlowDelete(FlowDelete notification);
}
public interface FooListener extends NotificationListener {
void onFooUpdate(FooUpdate notification);
-
+
}
import org.opendaylight.yangtools.yang.common.RpcResult;
public interface FooService extends RpcService {
-
+
Future<RpcResult<Void>> foo();
-
+
Future<RpcResult<Void>> simple(SimpleInput obj);
-
+
Future<RpcResult<Void>> inheritedContext(InheritedContextInput obj);
}
public class RpcRegistrationNullPointer {
-
-
-
+
+
+
}
/**
* We create transaction no 2
- *
+ *
*/
DataModificationTransaction removalTransaction = baDataService.beginTransaction();
assertNotNull(transaction);
/**
* We remove node 1
- *
+ *
*/
removalTransaction.removeConfigurationData(node1.getValue());
registration.unregisterPath(context, path);
return this;
}
-
+
public static MessageCapturingFlowService create() {
return new MessageCapturingFlowService();
}
-
+
public static MessageCapturingFlowService create(RpcProviderRegistry registry) {
MessageCapturingFlowService ret = new MessageCapturingFlowService();
ret.registerTo(registry);
return ret;
}
-
-
+
+
}
public interface RegistrationListener<T extends Registration<?>> extends EventListener {
void onRegister(T registration);
-
+
void onUnregister(T registration);
}
public interface DataProvisionService<P extends Path<P> , D> {
public Registration<DataCommitHandler<P, D>> registerCommitHandler(P path, DataCommitHandler<P, D> commitHandler);
-
- public ListenerRegistration<RegistrationListener<DataCommitHandlerRegistration<P, D>>>
+
+ public ListenerRegistration<RegistrationListener<DataCommitHandlerRegistration<P, D>>>
registerCommitHandlerListener(RegistrationListener<DataCommitHandlerRegistration<P, D>> commitHandlerListener);
}
public interface NotificationPublishService<N> {
void publish(N notification);
-
+
void publish(N notification,ExecutorService executor);
}
import org.opendaylight.yangtools.concepts.Path;
public interface MutableRoutingTable<C, P extends Path<P>, T> extends RoutingTable<C,P,T>, Mutable {
-
+
void setDefaultRoute(T target);
void updateRoute(P path,T target);
void removeRoute(P path);
public interface Route<C,P> extends Immutable {
C getType();
-
+
P getPath();
}
public interface RoutingTable<C, P extends Path<P>, T> {
C getIdentifier();
-
+
T getDefaultRoute();
-
+
Map<P,T> getRoutes();
-
+
T getRoute(P path);
}
/**
* Base abstract implementation of DataReadRouter, which performs
* a read operation on multiple data readers and then merges result.
- *
+ *
* @param <P>
* @param <D>
*/
/**
* Merges data readed by reader instances from specified path
- *
+ *
* @param path Path on which read was performed
* @param data Data which was returned by read operation.
* @return Merged result.
/**
* Returns a function which performs configuration read for supplied path
- *
+ *
* @param path
* @return function which performs configuration read for supplied path
*/
-
+
private Function<DataReader<P, D>, D> configurationRead(final P path) {
return new Function<DataReader<P, D>, D>() {
@Override
/**
* Returns a function which performs operational read for supplied path
- *
+ *
* @param path
* @return function which performs operational read for supplied path
*/
/**
* Register's a reader for operational data.
- *
+ *
* @param path Path which is served by this reader
* @param reader Reader instance which is responsible for reading particular subpath.
- * @return
+ * @return
*/
public Registration<DataReader<P, D>> registerOperationalReader(P path, DataReader<P, D> reader) {
OperationalDataReaderRegistration<P, D> ret = new OperationalDataReaderRegistration<>(path, reader);
}
private Predicate<? super Entry<P, DataReaderRegistration<P, D>>> affects(final P path) {
-
+
return new Predicate<Entry<P, DataReaderRegistration<P, D>>>() {
-
+
@Override
public boolean apply(Entry<P, DataReaderRegistration<P, D>> input) {
final P key = input.getKey();
return key.contains(path) || ((P) path).contains(key);
}
-
+
};
}
private final D updatedOperationalSubtree;
private final D updatedConfigurationSubtree;
-
-
-
+
+
+
public DataChangeEventImpl(DataChange<P, D> dataChange, D originalConfigurationSubtree,
D originalOperationalSubtree, D updatedOperationalSubtree, D updatedConfigurationSubtree) {
super();
updatedConfigurationData = Collections.emptyMap();
updatedOperationalData = Collections.emptyMap();
}
-
+
public InitialDataChangeEventImpl(D configTree, D operTree, Map<P, D> updatedCfgData, Map<P, D> updatedOperData) {
updatedConfigurationTree = configTree;
updatedOperationalTree = operTree;
updatedConfigurationData = updatedCfgData;
updatedOperationalData = updatedOperData;
}
-
+
@Override
public Map<P, D> getCreatedConfigurationData() {
return Collections.emptyMap();
}
-
+
@Override
public Map<P, D> getCreatedOperationalData() {
return Collections.emptyMap();
}
-
+
@Override
public Map<P, D> getOriginalConfigurationData() {
return Collections.emptyMap();
public Map<P, D> getUpdatedConfigurationData() {
return updatedConfigurationData;
}
-
+
@Override
public D getUpdatedConfigurationSubtree() {
return updatedConfigurationTree;
public D getUpdatedOperationalSubtree() {
return updatedOperationalTree;
}
-
+
@Override
public D getOriginalConfigurationSubtree() {
return updatedConfigurationTree;
}
-
+
@Override
public D getOriginalOperationalSubtree() {
return updatedOperationalTree;
}
-
+
@Override
public Map<P, D> getUpdatedOperationalData() {
return updatedOperationalData;
}
-
+
}
package org.opendaylight.controller.md.sal.common.impl.util.compat;
public class DataNormalizationException extends Exception {
- private static final long serialVersionUID = 1L;
+ private static final long serialVersionUID = 1L;
- public DataNormalizationException(String message) {
- super(message);
- }
+ public DataNormalizationException(String message) {
+ super(message);
+ }
- public DataNormalizationException(String message, Throwable cause) {
- super(message, cause);
- }
+ public DataNormalizationException(String message, Throwable cause) {
+ super(message, cause);
+ }
}
public class CommitHandlerTransactions {
private static class AllwaysSuccessfulTransaction<P extends Path<P>,D> implements DataCommitTransaction<P, D> {
-
+
private final DataModification<P, D> modification;
public AllwaysSuccessfulTransaction(DataModification<P, D> modification) {
public RpcResult<Void> finish() throws IllegalStateException {
return Rpcs.<Void>getRpcResult(true, null, Collections.<RpcError>emptyList());
}
-
+
@Override
public DataModification<P, D> getModification() {
return modification;
}
}
-
+
public static final <P extends Path<P>,D> AllwaysSuccessfulTransaction<P, D> allwaysSuccessfulTransaction(DataModification<P, D> modification) {
return new AllwaysSuccessfulTransaction<>(modification);
}
*
*/
public class RpcErrors {
-
+
/**
* @param applicationTag
* @param tag
* @param info
* @param severity
* @param message
- * @param errorType
- * @param cause
+ * @param errorType
+ * @param cause
* @return {@link RpcError} implementation
*/
public static RpcError getRpcError(String applicationTag, String tag, String info,
ErrorSeverity severity, String message, ErrorType errorType, Throwable cause) {
- RpcErrorTO ret = new RpcErrorTO(applicationTag, tag, info, severity, message,
+ RpcErrorTO ret = new RpcErrorTO(applicationTag, tag, info, severity, message,
errorType, cause);
return ret;
}
public Throwable getCause() {
return cause;
}
-
+
@Override
public ErrorType getErrorType() {
return errorType;
public class ToSalPropertyClassUtils {
public static Bandwidth salAdvertisedBandwidthFrom(NodeConnector nodeConnector) {
- FlowCapableNodeConnector flowCapNodeConn = nodeConnector.getAugmentation(FlowCapableNodeConnector.class);
+ FlowCapableNodeConnector flowCapNodeConn = nodeConnector.getAugmentation(FlowCapableNodeConnector.class);
PortFeatures portFeatures = flowCapNodeConn.getAdvertisedFeatures();
return new AdvertisedBandwidth(resolveBandwidth(portFeatures));
}
public static Bandwidth salPeerBandwidthFrom(NodeConnector nodeConnector) {
- FlowCapableNodeConnector flowCapNodeConn = nodeConnector.getAugmentation(FlowCapableNodeConnector.class);
+ FlowCapableNodeConnector flowCapNodeConn = nodeConnector.getAugmentation(FlowCapableNodeConnector.class);
PortFeatures portFeatures = flowCapNodeConn.getPeerFeatures();
return new PeerBandwidth(resolveBandwidth(portFeatures));
}
public static Bandwidth salSupportedBandwidthFrom(NodeConnector nodeConnector) {
- FlowCapableNodeConnector flowCapNodeConn = nodeConnector.getAugmentation(FlowCapableNodeConnector.class);
+ FlowCapableNodeConnector flowCapNodeConn = nodeConnector.getAugmentation(FlowCapableNodeConnector.class);
PortFeatures portFeatures = flowCapNodeConn.getSupported();
return new SupportedBandwidth(resolveBandwidth(portFeatures));
}
public static MacAddress salMacAddressFrom(NodeConnector nodeConnector) {
- FlowCapableNodeConnector flowCapNodeConn = nodeConnector.getAugmentation(FlowCapableNodeConnector.class);
+ FlowCapableNodeConnector flowCapNodeConn = nodeConnector.getAugmentation(FlowCapableNodeConnector.class);
String hwAddress = flowCapNodeConn.getHardwareAddress().getValue();
- return new MacAddress(bytesFrom(hwAddress));
+ return new MacAddress(bytesFrom(hwAddress));
}
-
-
+
+
public static Name salNameFrom(NodeConnector nodeConnector) {
- FlowCapableNodeConnector flowCapNodeConn = nodeConnector.getAugmentation(FlowCapableNodeConnector.class);
+ FlowCapableNodeConnector flowCapNodeConn = nodeConnector.getAugmentation(FlowCapableNodeConnector.class);
return new Name(flowCapNodeConn.getName());
}
-
-
+
+
private static byte[] bytesFrom(String hwAddress) {
String[] mac = hwAddress.split(":");
/**
* Java class name of Rpc Context
- *
- *
+ *
+ *
*/
@Override
public String getContext() {
/**
* String representation of route e.g. node-id
- *
+ *
*/
@Override
public String getRoute() {
/**
* Java class name of Rpc Type e.g org.opendaylight.AddFlowInput
- *
+ *
*/
@Override
public String getType() {
public class BindingAwareZeroMqRpcRouter implements BindingAwareRpcRouter {
BindingAwareRpcRouter mdSalRouter;
-
+
public BindingAwareRpcRouter getMdSalRouter() {
return mdSalRouter;
}
// Write message down to the wire
return null;
}
-
+
// Receiver part - invoked when request is received and deserialized
private Future<RpcReply<byte[]>> receivedRequest(RpcRequest<String, String, String, byte[]> input) {
-
+
return mdSalRouter.sendRpc(input);
}
public interface Connector extends RpcImplementation, NotificationListener {
-
-
+
+
Set<InstanceIdentifier> getConfigurationPrefixes();
Set<InstanceIdentifier> getRuntimePrefixes();
-
+
void registerListener(ConnectorListener listener);
void unregisterListener(ConnectorListener listener);
}
import java.util.concurrent.Future;
/**
- *
+ *
* @author ttkacik
*
* @param <C> Routing Context Identifier
*/
public interface RpcRouter<C,T,R,D> {
-
-
+
+
Future<RpcReply<D>> sendRpc(RpcRequest<C, T, R, D> input);
-
-
+
+
/**
- *
- * @author
+ *
+ * @author
*
* @param <C> Routing Context Identifier
* @param <R> Route Type
RouteIdentifier<C,T,R> getRoutingInformation();
D getPayload();
}
-
+
public interface RouteIdentifier<C,T,R> {
-
+
C getContext(); // defines a routing table (e.g. NodeContext)
T getType(); // rpc type
R getRoute(); // e.g. (node identity)
}
-
+
public interface RpcReply<D> {
D getPayload();
}
public abstract class AbstractConsumer implements Consumer, BundleActivator,ServiceTrackerCustomizer<Broker, Broker> {
-
-
-
+
+
+
private BundleContext context;
private ServiceTracker<Broker, Broker> tracker;
private Broker broker;
return Collections.emptySet();
}
-
+
@Override
public Broker addingService(ServiceReference<Broker> reference) {
if(broker == null) {
broker.registerConsumer(this, context);
return broker;
}
-
+
return null;
}
-
+
@Override
public void modifiedService(ServiceReference<Broker> reference, Broker service) {
// NOOP
}
-
+
@Override
public void removedService(ServiceReference<Broker> reference, Broker service) {
stopImpl(context);
import org.opendaylight.controller.sal.core.api.Broker.ConsumerSession;
/**
- *
+ *
* Session-specific instance of the broker functionality.
- *
+ *
* <p>
* BrokerService is marker interface for infrastructure services provided by the
* SAL. These services are session-specific, each {@link Provider} and
* {@link Consumer} usually has own instance of the service with it's own
* context.
- *
+ *
* <p>
* The consumer's (or provider's) instance of specific service could be obtained
* by invoking {@link ConsumerSession#getService(Class)} method on session
* assigned to the consumer.
- *
+ *
* <p>
* {@link BrokerService} and {@link Provider} may seem similar, but provider
* provides YANG model-based functionality and {@link BrokerService} exposes the
* necessary supporting functionality to implement specific functionality of
* YANG and to reuse it in the development of {@link Consumer}s and
* {@link Provider}s.
- *
- *
+ *
+ *
*/
public interface BrokerService {
import org.opendaylight.controller.sal.core.api.Broker.ConsumerSession;
/**
- *
+ *
* Defines the component of controller and supplies additional metadata. A
* component of the controller or application supplies a concrete implementation
* of this interface.
- *
+ *
* A user-implemented component (application) which facilitates the SAL and SAL
* services to access infrastructure services or providers' functionality.
- *
- *
+ *
+ *
*/
public interface Consumer {
/**
* Callback signaling initialization of the consumer session to the SAL.
- *
+ *
* The consumer MUST use the session for all communication with SAL or
* retrieving SAL infrastructure services.
- *
+ *
* This method is invoked by {@link Broker#registerConsumer(Consumer)}
- *
+ *
* @param session
* Unique session between consumer and SAL.
*/
/**
* Get a set of implementations of consumer functionality to be registered
* into system during the consumer registration to the SAL.
- *
+ *
* This method is invoked by {@link Broker#registerConsumer(Consumer)}.
- *
+ *
* @return Set of consumer functionality.
*/
public Collection<ConsumerFunctionality> getConsumerFunctionality();
/**
* The marker interface for the interfaces describing the consumer
* functionality contracts.
- *
- *
+ *
+ *
*/
public interface ConsumerFunctionality {
import org.opendaylight.controller.sal.core.api.Broker.ProviderSession;
/**
- *
+ *
* Defines the component of controller and supplies additional metadata. A
* component of the controller or application supplies a concrete implementation
* of this interface.
- *
+ *
* <p>
* A user-implemented component (application) which facilitates the SAL and SAL
* services to access infrastructure services and to provide functionality to
* {@link Consumer}s and other providers.
- *
- *
+ *
+ *
*/
public interface Provider {
/**
* Callback signaling initialization of the provider session to the SAL.
- *
+ *
* <p>
* The provider <b>MUST use the session</b> for all communication with SAL
* or retrieving SAL infrastructure services.
- *
+ *
* <p>
* This method is invoked by {@link Broker#registerConsumer(Consumer)}
- *
+ *
* @param session
* Unique session between provider and SAL.
*/
/**
* Gets a set of implementations of provider functionality to be registered
* into system during the provider registration to the SAL.
- *
+ *
* <p>
* This method is invoked by {@link Broker#registerProvider(Provider)} to
* learn the initial provided functionality
- *
+ *
* @return Set of provider's functionality.
*/
public Collection<ProviderFunctionality> getProviderFunctionality();
/**
* Functionality provided by the {@link Provider}
- *
+ *
* <p>
* Marker interface used to mark the interfaces describing specific
* functionality which could be exposed by providers to other components.
- *
+ *
- *
+ *
*/
public interface ProviderFunctionality {
public interface RpcConsumptionRegistry {
/**
* Sends an RPC to other components registered to the broker.
- *
+ *
* @see RpcImplementation
* @param rpc
* Name of RPC
/**
* Registers an implementation of the rpc.
- *
+ *
* <p>
* The registered rpc functionality will be available to all other
* consumers and providers registered to the broker, which are aware of
* the {@link QName} assigned to the rpc.
- *
+ *
* <p>
* There is no assumption that rpc type is in the set returned by
* invoking {@link RpcImplementation#getSupportedRpcs()}. This allows
* for dynamic rpc implementations.
- *
+ *
* @param rpcType
* Name of Rpc
* @param implementation
*/
RpcRegistration addRpcImplementation(QName rpcType, RpcImplementation implementation)
throws IllegalArgumentException;
-
+
ListenerRegistration<RpcRegistrationListener> addRpcRegistrationListener(RpcRegistrationListener listener);
RoutedRpcRegistration addRoutedRpcImplementation(QName rpcType, RpcImplementation implementation);
import org.opendaylight.yangtools.yang.common.QName;
public interface RpcRegistrationListener extends EventListener {
-
+
public void onRpcImplementationAdded(QName name);
-
+
public void onRpcImplementationRemoved(QName name);
}
public class RpcRoutingContext implements Immutable, Serializable {
/**
- *
+ *
*/
private static final long serialVersionUID = -9079324728075883325L;
-
+
private final QName context;
private final QName rpc;
-
-
+
+
private RpcRoutingContext(QName context, QName rpc) {
super();
this.context = context;
this.rpc = rpc;
}
-
+
public static final RpcRoutingContext create(QName context, QName rpc) {
return new RpcRoutingContext(context, rpc);
}
/**
* DataBrokerService provides unified access to the data stores available in the
* system.
- *
- *
+ *
+ *
* @see DataProviderService
- *
+ *
*/
-public interface DataBrokerService extends
+public interface DataBrokerService extends
BrokerService, //
DataReader<InstanceIdentifier, CompositeNode>, //
DataModificationTransactionFactory<InstanceIdentifier, CompositeNode>, //
import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
import org.opendaylight.controller.md.sal.common.api.data.DataReader;;
-public interface DataProviderService extends
+public interface DataProviderService extends
DataBrokerService, //
DataProvisionService<InstanceIdentifier, CompositeNode>
{
/**
* Adds {@link DataValidator} for specified Data Store
- *
+ *
* @param store
* Data Store
* @param validator
/**
* Removes {@link DataValidator} from specified Data Store
- *
+ *
* @param store
* @param validator
* Validator
/**
* Adds {@link DataRefresher} for specified data store
- *
+ *
* @param store
* @param refresher
*/
/**
* Removes {@link DataRefresher} from specified data store
- *
+ *
* @param store
* @param refresher
*/
void removeRefresher(DataStoreIdentifier store, DataRefresher refresher);
-
+
Registration<DataReader<InstanceIdentifier, CompositeNode>> registerConfigurationReader(InstanceIdentifier path, DataReader<InstanceIdentifier, CompositeNode> reader);
Registration<DataReader<InstanceIdentifier, CompositeNode>> registerOperationalReader(InstanceIdentifier path, DataReader<InstanceIdentifier, CompositeNode> reader);
-
+
public interface DataRefresher extends Provider.ProviderFunctionality {
/**
* Fired when some component explicitly requested the data refresh.
- *
+ *
* The provider which exposed the {@link DataRefresher} should republish
* its provided data by editing the data in all affected data stores.
*/
public interface DataStore extends //
DataReader<InstanceIdentifier, CompositeNode>,
DataCommitHandler<InstanceIdentifier, CompositeNode> {
-
-
+
+
Iterable<InstanceIdentifier> getStoredConfigurationPaths();
Iterable<InstanceIdentifier> getStoredOperationalPaths();
-
+
boolean containsConfigurationPath(InstanceIdentifier path);
boolean containsOperationalPath(InstanceIdentifier path);
/**
* {@link Provider}-supplied Validator of the data.
- *
+ *
* <p>
* The registration could be done by :
* <ul>
* as arguments to the
* {@link DataProviderService#addValidator(DataStoreIdentifier, DataValidator)}
* </ul>
- *
+ *
**/
public interface DataValidator extends Provider.ProviderFunctionality {
/**
* A set of Data Stores supported by implementation.
- *
+ *
* The set of {@link DataStoreIdentifier}s which identifies target data
* stores which are supported by this implementation. This set is used, when
* {@link Provider} is registered to the SAL, to register and expose the
* validation functionality to affected data stores.
- *
+ *
* @return Set of Data Store identifiers
*/
Set<DataStoreIdentifier> getSupportedDataStores();
/**
* Performs validation on supplied data.
- *
+ *
* @param toValidate
* Data to validate
* @return Validation result. The
public interface NotificationListener extends Consumer.ConsumerFunctionality, EventListener {
/**
* A set of notification types supported by listeners.
- *
+ *
* The set of notification {@link QName}s which are supported by this
* listener. This set is used, when {@link Consumer} is registered to the
* SAL, to automatically register the listener.
- *
+ *
* @return Set of QNames identifying supported notifications.
*/
Set<QName> getSupportedNotifications();
/**
* Fired when the notification occurs.
- *
+ *
* The type of the notification could be learned by
* <code>QName type = notification.getNodeType();</code>
- *
+ *
* @param notification
* Notification content
*/
/**
* Notification Publishing Service
- *
+ *
* The simplified process of the notification publishing is following:
- *
+ *
* <ol>
* <li> {@link Provider} invokes {@link #sendNotification(CompositeNode)}
* <li> {@link Broker} finds {@link NotificationListener}s which subscribed for
* the notification type.
- *
+ *
* <li>For each subscriber {@link Broker} invokes
* {@link NotificationListener#onNotification(CompositeNode)}
* </ol>
public interface NotificationPublishService extends NotificationService {
/**
* Publishes a notification.
- *
+ *
* Notification type is determined by the
* {@link CompositeNode#getNodeType()} of the
* <code>notification<code> parameter.
- *
+ *
* @param notification
* Notification to publish
*/
/**
* NotificationService provides access to the notification functionality of the
* SAL.
- *
+ *
* NotificationService allows for consumption of notifications by registering
* implementations of NotificationListener.
- *
+ *
* The registration of notification listeners could be done by:
* <ul>
* <li>returning an instance of implementation in the return value of
* arguments to the
* {@link ProviderSession#addRpcImplementation(QName, RpcImplementation)}
* </ul>
- *
- *
+ *
+ *
*/
public interface NotificationService extends BrokerService {
/**
* Registers a notification listener for supplied notification type.
- *
+ *
* @param notification
* @param listener
*/
public class DomBrokerRuntimeMXBeanImpl implements
DomBrokerImplRuntimeMXBean {
-
+
private final DataBrokerImpl dataService;
private final Transactions transactions = new Transactions();
private final Data data = new Data();
-
+
public DomBrokerRuntimeMXBeanImpl(DataBrokerImpl dataService) {
- this.dataService = dataService;
+ this.dataService = dataService;
}
public Transactions getTransactions() {
/**
* In-memory DOM Data Store
- *
+ *
* Implementation of {@link DOMStore} which uses {@link DataTree} and other
* classes such as {@link SnapshotBackedWriteTransaction}.
* {@link SnapshotBackedReadTransaction} and {@link ResolveDataChangeEventsTask}
* to implement {@link DOMStore} contract.
- *
+ *
*/
public class InMemoryDOMDataStore implements DOMStore, Identifiable<String>, SchemaContextListener,
TransactionReadyPrototype {
/*
* Make sure commit is not occurring right now. Listener has to be
* registered and its state capture enqueued at a consistent point.
- *
+ *
* FIXME: improve this to read-write lock, such that multiple listener
* registrations can occur simultaneously
*/
* Implementation of Write transaction which is backed by
* {@link DataTreeSnapshot} and executed according to
* {@link TransactionReadyPrototype}.
- *
+ *
*/
class SnapshotBackedWriteTransaction extends AbstractDOMStoreTransaction implements DOMStoreWriteTransaction {
/**
* Creates new write-only transaction.
- *
+ *
* @param identifier
* transaction Identifier
* @param snapshot
/**
* Prototype implementation of
* {@link #ready(SnapshotBackedWriteTransaction)}
- *
+ *
* This class is intended to be implemented by Transaction factories
* responsible for allocation of {@link SnapshotBackedWriteTransaction} and
* providing underlying logic for applying implementation.
- *
+ *
*/
public static interface TransactionReadyPrototype {
/**
* Returns a commit coordinator associated with supplied transactions.
- *
+ *
* This call must not fail.
- *
+ *
* @param tx
* Transaction on which ready was invoked.
* @return DOMStoreThreePhaseCommitCohort associated with transaction
* Factory interface for creating data trees.
*/
public interface DataTreeFactory {
- /**
- * Create a new data tree.
- *
- * @return A data tree instance.
- */
- DataTree create();
+ /**
+ * Create a new data tree.
+ *
+ * @return A data tree instance.
+ */
+ DataTree create();
}
/**
* Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
- *
+ *
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v1.0 which accompanies this distribution,
* and is available at http://www.eclipse.org/legal/epl-v10.html
private AtomicLong nextTransaction = new AtomicLong();
private final AtomicLong createdTransactionsCount = new AtomicLong();
-
+
public DataBrokerImpl() {
setDataReadRouter(new DataReaderRouter());
setExecutor(MoreExecutors.sameThreadExecutor());
}
-
+
public AtomicLong getCreatedTransactionsCount() {
return createdTransactionsCount;
}
-
+
@Override
public DataTransactionImpl beginTransaction() {
String transactionId = "DOM-" + nextTransaction.getAndIncrement();
@Override
public void close() throws Exception {
-
+
}
}
import org.opendaylight.yangtools.yang.data.api.CompositeNode;
import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
-public class DataTransactionImpl extends AbstractDataTransaction<InstanceIdentifier, CompositeNode>
+public class DataTransactionImpl extends AbstractDataTransaction<InstanceIdentifier, CompositeNode>
implements DataModificationTransaction {
private final ListenerRegistry<DataTransactionListener> listeners = new ListenerRegistry<DataTransactionListener>();
-
-
-
+
+
+
public DataTransactionImpl(Object identifier,DataBrokerImpl dataBroker) {
super(identifier,dataBroker);
}
public DataModificationTransaction beginTransaction() {
return getDelegate().beginTransaction();
}
-
-
+
+
}
public void removeValidator(DataStoreIdentifier store, DataValidator validator) {
getDelegate().removeValidator(store, validator);
}
-
+
@Override
public ListenerRegistration<RegistrationListener<DataCommitHandlerRegistration<InstanceIdentifier, CompositeNode>>> registerCommitHandlerListener(
RegistrationListener<DataCommitHandlerRegistration<InstanceIdentifier, CompositeNode>> commitHandlerListener) {
/**
* Registers a notification listener for supplied notification type.
- *
+ *
* @param notification
* @param listener
*/
// TODO Auto-generated constructor stub
}
-
-
+
+
public static Map<Map<QName,Object>,CompositeNode> toIndexMap(List<CompositeNode> nodes,List<QName> keys) {
ConcurrentHashMap<Map<QName,Object>,CompositeNode> ret = new ConcurrentHashMap<>();
for(CompositeNode node : nodes) {
checkArgument(keyNode != null,"Node must contains all keys.");
Object value = keyNode.getValue();
map.put(key, value);
-
+
}
return map;
}
public class YangSchemaUtils {
private static final Function<PathArgument, QName> QNAME_FROM_PATH_ARGUMENT = new Function<PathArgument, QName>(){
-
+
@Override
public QName apply(PathArgument input) {
if(input == null) {
private YangSchemaUtils() {
throw new UnsupportedOperationException("Utility class.");
}
-
-
+
+
public static DataSchemaNode getSchemaNode(SchemaContext schema,InstanceIdentifier path) {
checkArgument(schema != null,"YANG Schema must not be null.");
checkArgument(path != null,"Path must not be null.");
return getSchemaNode(schema, FluentIterable.from(path.getPath()).transform(QNAME_FROM_PATH_ARGUMENT));
}
-
+
public static DataSchemaNode getSchemaNode(SchemaContext schema,Iterable<QName> path) {
checkArgument(schema != null,"YANG Schema must not be null.");
checkArgument(path != null,"Path must not be null.");
if(!path.iterator().hasNext()){
return toRootDataNode(schema);
}
-
+
QName firstNode = path.iterator().next();
DataNodeContainer previous = schema.findModuleByNamespaceAndRevision(firstNode.getNamespace(),
firstNode.getRevision());
Iterator<QName> iterator = path.iterator();
-
+
while (iterator.hasNext()) {
checkArgument(previous!= null, "Supplied path does not resolve into valid schema node.");
QName arg = iterator.next();
}
private static final class NetconfDataRootNode implements ContainerSchemaNode {
-
+
public NetconfDataRootNode(SchemaContext schema) {
// TODO Auto-generated constructor stub
}
-
+
@Override
public Set<TypeDefinition<?>> getTypeDefinitions() {
// TODO Auto-generated method stub
return null;
}
-
+
@Override
public Set<DataSchemaNode> getChildNodes() {
// TODO Auto-generated method stub
return null;
}
-
+
@Override
public Set<GroupingDefinition> getGroupings() {
// TODO Auto-generated method stub
return null;
}
-
+
@Override
public DataSchemaNode getDataChildByName(QName name) {
// TODO Auto-generated method stub
return null;
}
-
+
@Override
public DataSchemaNode getDataChildByName(String name) {
// TODO Auto-generated method stub
return null;
}
-
+
@Override
public Set<UsesNode> getUses() {
// TODO Auto-generated method stub
return null;
}
-
+
@Override
public Set<AugmentationSchema> getAvailableAugmentations() {
// TODO Auto-generated method stub
return null;
}
-
+
@Override
public boolean isAugmenting() {
// TODO Auto-generated method stub
return false;
}
-
+
@Override
public boolean isAddedByUses() {
// TODO Auto-generated method stub
return false;
}
-
+
@Override
public boolean isConfiguration() {
// TODO Auto-generated method stub
return false;
}
-
+
@Override
public ConstraintDefinition getConstraints() {
// TODO Auto-generated method stub
return null;
}
-
+
@Override
public QName getQName() {
// TODO Auto-generated method stub
return null;
}
-
+
@Override
public SchemaPath getPath() {
// TODO Auto-generated method stub
return null;
}
-
+
@Override
public String getDescription() {
// TODO Auto-generated method stub
return null;
}
-
+
@Override
public String getReference() {
// TODO Auto-generated method stub
return null;
}
-
+
@Override
public Status getStatus() {
// TODO Auto-generated method stub
return null;
}
-
+
@Override
public List<UnknownSchemaNode> getUnknownSchemaNodes() {
// TODO Auto-generated method stub
return null;
}
-
+
@Override
public boolean isPresenceContainer() {
// TODO Auto-generated method stub
return false;
}
-
+
}
}
DOMStoreReadWriteTransaction writeTx = domStore.newReadWriteTransaction();
assertNotNull(writeTx);
/**
- *
+ *
* Writes /test in writeTx
- *
+ *
*/
writeTx.write(TestModel.TEST_PATH, ImmutableNodes.containerNode(TestModel.TEST_QNAME));
/**
- *
+ *
* Reads /test from writeTx Read should return container.
- *
+ *
*/
ListenableFuture<Optional<NormalizedNode<?, ?>>> writeTxContainer = writeTx.read(TestModel.TEST_PATH);
assertTrue(writeTxContainer.get().isPresent());
/**
- *
+ *
* Reads /test from readTx Read should return Absent.
- *
+ *
*/
ListenableFuture<Optional<NormalizedNode<?, ?>>> readTxContainer = readTx.read(TestModel.TEST_PATH);
assertFalse(readTxContainer.get().isPresent());
DOMStoreReadWriteTransaction writeTx = domStore.newReadWriteTransaction();
assertNotNull(writeTx);
/**
- *
+ *
* Writes /test in writeTx
- *
+ *
*/
writeTx.write(TestModel.TEST_PATH, ImmutableNodes.containerNode(TestModel.TEST_QNAME));
/**
- *
+ *
* Reads /test from writeTx Read should return container.
- *
+ *
*/
ListenableFuture<Optional<NormalizedNode<?, ?>>> writeTxContainer = writeTx.read(TestModel.TEST_PATH);
assertTrue(writeTxContainer.get().isPresent());
/**
* We alocate new read-write transaction and write /test
- *
- *
+ *
+ *
*/
DOMStoreReadWriteTransaction firstTx = txChain.newReadWriteTransaction();
assertTestContainerWrite(firstTx);
DOMStoreReadTransaction secondReadTx = txChain.newReadOnlyTransaction();
/**
- *
+ *
* We test if we are able to read data from tx, read should not fail
* since we are using chained transaction.
- *
- *
+ *
+ *
*/
assertTestContainerExists(secondReadTx);
/**
- *
+ *
* We alocate next transaction, which is still based on first one, but
* is read-write.
- *
+ *
*/
DOMStoreReadWriteTransaction thirdDeleteTx = txChain.newReadWriteTransaction();
/**
* We test existence of /test in third transaction container should
* still be visible from first one (which is still uncommmited).
- *
- *
+ *
+ *
*/
assertTestContainerExists(thirdDeleteTx);
/**
* We commit first transaction
- *
+ *
*/
assertThreePhaseCommit(firstWriteTxCohort);
assertTestContainerExists(storeReadTx);
/**
* We commit third transaction
- *
+ *
*/
assertThreePhaseCommit(thirdDeleteTxCohort);
}
private static Optional<NormalizedNode<?, ?>> assertTestContainerWrite(final DOMStoreReadWriteTransaction writeTx)
throws InterruptedException, ExecutionException {
/**
- *
+ *
* Writes /test in writeTx
- *
+ *
*/
writeTx.write(TestModel.TEST_PATH, ImmutableNodes.containerNode(TestModel.TEST_QNAME));
}
/**
- *
+ *
* Reads /test from readTx Read should return container.
- *
+ *
*/
private static Optional<NormalizedNode<?, ?>> assertTestContainerExists(DOMStoreReadTransaction readTx)
throws InterruptedException, ExecutionException {
module.setBundleContext(bundleContext);
return module;
}
-
+
@Override
public Module createModule(String instanceName, DependencyResolver dependencyResolver,
DynamicMBeanWithInstance old, BundleContext bundleContext) throws Exception {
private Message _message;
private ZMQ.Socket _receiveSocket;
-
+
public MessageWrapper(Message message, ZMQ.Socket receiveSocket) {
this._message = message;
this._receiveSocket = receiveSocket;
}
return false;
}
-
+
// Adds a child SimpleNode containing the value "success" to the input CompositeNode
private CompositeNode addSuccessNode(CompositeNode input) {
List<Node<?>> list = new ArrayList<Node<?>>(input.getChildren());
@Inject
@Filter(timeout=60*1000)
Broker broker;
-
+
private ZMQ.Context zmqCtx = ZMQ.context(1);
//private Server router;
//private ExampleProvider provider;
return msg;
}
-
+
private void printState(){
Bundle[] b = ctx.getBundles();
_logger.debug("\n\nNumber of bundles [{}]\n\n]", b.length);
* <ul>
* <li><b>/restconf</b> - {@link #getRoot()}
* <ul>
- * <li><b>/config</b> - {@link #readConfigurationData(String)}
+ * <li><b>/config</b> - {@link #readConfigurationData(String)}
* {@link #updateConfigurationData(String, CompositeNode)}
* {@link #createConfigurationData(CompositeNode)}
* {@link #createConfigurationData(String, CompositeNode)}
* {@link #deleteConfigurationData(String)}
- * <li><b>/operational</b> - {@link #readOperationalData(String)}
+ * <li><b>/operational</b> - {@link #readOperationalData(String)}
* <li>/modules - {@link #getModules()}
* <ul>
* <li>/module
Draft02.MediaTypes.DATA+JSON, Draft02.MediaTypes.DATA+XML,
MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, MediaType.TEXT_XML})
public StructuredData invokeRpc(@Encoded @PathParam("identifier") String identifier, CompositeNode payload);
-
+
@POST
@Path("/operations/{identifier:.+}")
@Produces({Draft02.MediaTypes.OPERATION+JSON, Draft02.MediaTypes.OPERATION+XML,
Draft02.MediaTypes.DATA+JSON, Draft02.MediaTypes.DATA+XML,
MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, MediaType.TEXT_XML})
public StructuredData invokeRpc(@Encoded @PathParam("identifier") String identifier, @DefaultValue("") String noPayload);
-
+
@GET
@Path("/config/{identifier:.+}")
- @Produces({Draft02.MediaTypes.DATA+JSON,Draft02.MediaTypes.DATA+XML,
+ @Produces({Draft02.MediaTypes.DATA+JSON,Draft02.MediaTypes.DATA+XML,
MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, MediaType.TEXT_XML})
public StructuredData readConfigurationData(@Encoded @PathParam("identifier") String identifier);
@GET
@Path("/operational/{identifier:.+}")
- @Produces({Draft02.MediaTypes.DATA+JSON,Draft02.MediaTypes.DATA+XML,
+ @Produces({Draft02.MediaTypes.DATA+JSON,Draft02.MediaTypes.DATA+XML,
MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, MediaType.TEXT_XML})
public StructuredData readOperationalData(@Encoded @PathParam("identifier") String identifier);
@PUT
@Path("/config/{identifier:.+}")
- @Consumes({Draft02.MediaTypes.DATA+JSON,Draft02.MediaTypes.DATA+XML,
+ @Consumes({Draft02.MediaTypes.DATA+JSON,Draft02.MediaTypes.DATA+XML,
MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, MediaType.TEXT_XML})
public Response updateConfigurationData(@Encoded @PathParam("identifier") String identifier, CompositeNode payload);
@POST
@Path("/config/{identifier:.+}")
- @Consumes({Draft02.MediaTypes.DATA+JSON,Draft02.MediaTypes.DATA+XML,
+ @Consumes({Draft02.MediaTypes.DATA+JSON,Draft02.MediaTypes.DATA+XML,
MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, MediaType.TEXT_XML})
public Response createConfigurationData(@Encoded @PathParam("identifier") String identifier, CompositeNode payload);
@POST
@Path("/config")
- @Consumes({Draft02.MediaTypes.DATA+JSON,Draft02.MediaTypes.DATA+XML,
+ @Consumes({Draft02.MediaTypes.DATA+JSON,Draft02.MediaTypes.DATA+XML,
MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, MediaType.TEXT_XML})
public Response createConfigurationData(CompositeNode payload);
import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
public final class RestUtil {
-
+
public static final String SQUOTE = "'";
public static final String DQUOTE = "\"";
private static final Pattern PREDICATE_PATTERN = Pattern.compile("\\[(.*?)\\]");
IdentityValuesDTO identityValuesDTO = new IdentityValuesDTO(value);
for (int i = 1; i < xPathParts.length; i++) {
String xPathPartTrimmed = xPathParts[i].trim();
-
+
String xPathPartStr = getIdAndPrefixAsStr(xPathPartTrimmed);
IdentityValue identityValue = toIdentity(xPathPartStr, prefixMap);
if (identityValue == null) {
return null;
}
-
+
List<Predicate> predicates = toPredicates(xPathPartTrimmed, prefixMap);
if (predicates == null) {
return null;
}
identityValue.setPredicates(predicates);
-
+
identityValuesDTO.add(identityValue);
}
return identityValuesDTO.getValuesWithNamespaces().isEmpty() ? null : identityValuesDTO;
}
-
+
private static String getIdAndPrefixAsStr(String pathPart) {
int predicateStartIndex = pathPart.indexOf("[");
return predicateStartIndex == -1 ? pathPart : pathPart.substring(0, predicateStartIndex);
}
-
+
private static IdentityValue toIdentity(String xPathPart, PrefixesMaping prefixMap) {
String xPathPartTrimmed = xPathPart.trim();
if (xPathPartTrimmed.isEmpty()) {
import com.google.common.base.Preconditions;
public final class EmptyNodeWrapper implements NodeWrapper<Node<?>>, Node<Void> {
-
+
private Node<?> unwrapped;
-
+
private String localName;
private URI namespace;
private QName name;
public boolean isComposite() {
return composite;
}
-
+
public void setComposite(boolean composite) {
this.composite = composite;
}
-
+
public EmptyNodeWrapper(URI namespace, String localName) {
this.localName = Preconditions.checkNotNull(localName);
this.namespace = namespace;
}
-
+
@Override
public void setQname(QName name) {
Preconditions.checkState(unwrapped == null, "Cannot change the object, due to data inconsistencies.");
this.name = name;
}
-
+
@Override
public QName getQname() {
return name;
}
-
+
@Override
public String getLocalName() {
if (unwrapped != null) {
}
return localName;
}
-
+
@Override
public URI getNamespace() {
if (unwrapped != null) {
elementData.add(new IdentityValue(namespace, value, prefix));
this.originValue = originValue;
}
-
+
public IdentityValuesDTO(String originValue) {
this.originValue = originValue;
}
-
+
public IdentityValuesDTO() {
originValue = null;
}
public void add(String namespace, String value, String prefix) {
elementData.add(new IdentityValue(namespace, value, prefix));
}
-
+
public void add(IdentityValue identityValue) {
elementData.add(identityValue);
}
-
+
public List<IdentityValue> getValuesWithNamespaces() {
return Collections.unmodifiableList(elementData);
}
-
+
@Override
public String toString() {
return elementData.toString();
}
-
+
public String getOriginValue() {
return originValue;
}
public void setPredicates(List<Predicate> predicates) {
this.predicates = predicates;
}
-
+
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
}
}
-
+
public static final class Predicate {
-
+
private final IdentityValue name;
private final String value;
-
+
public Predicate(IdentityValue name, String value) {
super();
this.name = name;
this.value = value;
}
-
+
public IdentityValue getName() {
return name;
}
-
+
public String getValue() {
return value;
}
}
return sb.toString();
}
-
+
public boolean isLeafList() {
return name == null ? true : false;
}
-
+
}
}
public interface NodeWrapper<T extends Node<?>> {
void setQname(QName name);
-
+
QName getQname();
-
+
T unwrap();
-
+
boolean isChangeAllowed();
-
+
URI getNamespace();
void setNamespace(URI namespace);
-
+
String getLocalName();
}
import org.slf4j.LoggerFactory;
public class RestCodec {
-
+
private static final Logger logger = LoggerFactory.getLogger(RestCodec.class);
private RestCodec() {
logger.info("Idenetityref will be translated as NULL for data - {}", String.valueOf(valueWithNamespace));
return null;
}
-
+
return QName.create(module.getNamespace(), module.getRevision(), valueWithNamespace.getValue());
}
}
}
}
-
+
return result.isEmpty() ? null : new InstanceIdentifier(result);
}
return null;
}
}
-
+
private static Module getModuleByNamespace(String namespace, MountInstance mountPoint) {
URI validNamespace = resolveValidNamespace(namespace, mountPoint);
}
return module;
}
-
+
private static URI resolveValidNamespace(String namespace, MountInstance mountPoint) {
URI validNamespace;
if (mountPoint != null) {
import com.google.common.base.Preconditions;
public final class SimpleNodeWrapper implements NodeWrapper<SimpleNode<?>>, SimpleNode<Object> {
-
+
private SimpleNode<Object> simpleNode;
-
+
private String localName;
private Object value;
private URI namespace;
this.localName = Preconditions.checkNotNull(localName);
this.value = value;
}
-
+
public SimpleNodeWrapper(URI namespace, String localName, Object value) {
this(localName, value);
this.namespace = namespace;
}
-
+
@Override
public void setQname(QName name) {
Preconditions.checkState(simpleNode == null, "Cannot change the object, due to data inconsistencies.");
this.name = name;
}
-
+
@Override
public QName getQname() {
return name;
}
-
+
@Override
public String getLocalName() {
if (simpleNode != null) {
}
return localName;
}
-
+
@Override
public URI getNamespace() {
if (simpleNode != null) {
name = new QName(namespace, localName);
}
simpleNode = NodeFactory.createImmutableSimpleNode(name, null, value);
-
+
value = null;
namespace = null;
localName = null;
public Object setValue(Object value) {
return unwrap().setValue(value);
}
-
+
}
*/
public class ListenerAdapter implements DataChangeListener {
- private static final Logger logger = LoggerFactory
- .getLogger(ListenerAdapter.class);
- private final XmlMapper xmlMapper = new XmlMapper();
- private final SimpleDateFormat rfc3339 = new SimpleDateFormat(
- "yyyy-MM-dd'T'hh:mm:ssZ");
-
- private final InstanceIdentifier path;
- private ListenerRegistration<DataChangeListener> registration;
- private final String streamName;
- private Set<Channel> subscribers = new ConcurrentSet<>();
- private final EventBus eventBus;
- private final EventBusChangeRecorder eventBusChangeRecorder;
-
- /**
- * Creates new {@link ListenerAdapter} listener specified by path and stream
- * name.
- *
- * @param path
- * Path to data in data store.
- * @param streamName
- * The name of the stream.
- */
- ListenerAdapter(InstanceIdentifier path, String streamName) {
- Preconditions.checkNotNull(path);
- Preconditions
- .checkArgument(streamName != null && !streamName.isEmpty());
- this.path = path;
- this.streamName = streamName;
- eventBus = new AsyncEventBus(Executors.newSingleThreadExecutor());
- eventBusChangeRecorder = new EventBusChangeRecorder();
- eventBus.register(eventBusChangeRecorder);
- }
-
- @Override
- public void onDataChanged(
- DataChangeEvent<InstanceIdentifier, CompositeNode> change) {
- if (!change.getCreatedConfigurationData().isEmpty()
- || !change.getCreatedOperationalData().isEmpty()
- || !change.getUpdatedConfigurationData().isEmpty()
- || !change.getUpdatedOperationalData().isEmpty()
- || !change.getRemovedConfigurationData().isEmpty()
- || !change.getRemovedOperationalData().isEmpty()) {
- String xml = prepareXmlFrom(change);
- Event event = new Event(EventType.NOTIFY);
- event.setData(xml);
- eventBus.post(event);
- }
- }
-
- /**
- * Tracks events of data change by customer.
- */
- private final class EventBusChangeRecorder {
- @Subscribe
- public void recordCustomerChange(Event event) {
- if (event.getType() == EventType.REGISTER) {
- Channel subscriber = event.getSubscriber();
- if (!subscribers.contains(subscriber)) {
- subscribers.add(subscriber);
- }
- } else if (event.getType() == EventType.DEREGISTER) {
- subscribers.remove(event.getSubscriber());
- Notificator
- .removeListenerIfNoSubscriberExists(ListenerAdapter.this);
- } else if (event.getType() == EventType.NOTIFY) {
- for (Channel subscriber : subscribers) {
- if (subscriber.isActive()) {
- logger.debug("Data are sent to subscriber {}:",
- subscriber.remoteAddress());
- subscriber.writeAndFlush(new TextWebSocketFrame(event
- .getData()));
- } else {
- logger.debug(
- "Subscriber {} is removed - channel is not active yet.",
- subscriber.remoteAddress());
- subscribers.remove(subscriber);
- }
- }
- }
- }
- }
-
- /**
- * Represents event of specific {@link EventType} type, holds data and
- * {@link Channel} subscriber.
- */
- private final class Event {
- private final EventType type;
- private Channel subscriber;
- private String data;
-
- /**
- * Creates new event specified by {@link EventType} type.
- *
- * @param type
- * EventType
- */
- public Event(EventType type) {
- this.type = type;
- }
-
- /**
- * Gets the {@link Channel} subscriber.
- *
- * @return Channel
- */
- public Channel getSubscriber() {
- return subscriber;
- }
-
- /**
- * Sets subscriber for event.
- *
- * @param subscriber
- * Channel
- */
- public void setSubscriber(Channel subscriber) {
- this.subscriber = subscriber;
- }
-
- /**
- * Gets event data.
- *
- * @return String representation of event data.
- */
- public String getData() {
- return data;
- }
-
- /**
- * Sets event data.
- *
- * @param String
- * data.
- */
- public void setData(String data) {
- this.data = data;
- }
-
- /**
- * Gets event type.
- *
- * @return The type of the event.
- */
- public EventType getType() {
- return type;
- }
- }
-
- /**
- * Type of the event.
- */
- private enum EventType {
- REGISTER, DEREGISTER, NOTIFY;
- }
-
- /**
- * Prepare data in printable form and transform it to String.
- *
- * @param change
- * DataChangeEvent
- * @return Data in printable form.
- */
- private String prepareXmlFrom(
- DataChangeEvent<InstanceIdentifier, CompositeNode> change) {
- Document doc = createDocument();
- Element notificationElement = doc.createElementNS(
- "urn:ietf:params:xml:ns:netconf:notification:1.0",
- "notification");
- doc.appendChild(notificationElement);
-
- Element eventTimeElement = doc.createElement("eventTime");
- eventTimeElement.setTextContent(toRFC3339(new Date()));
- notificationElement.appendChild(eventTimeElement);
-
- Element dataChangedNotificationEventElement = doc.createElementNS(
- "urn:opendaylight:params:xml:ns:yang:controller:md:sal:remote",
- "data-changed-notification");
- addValuesToDataChangedNotificationEventElement(doc,
- dataChangedNotificationEventElement, change);
- notificationElement.appendChild(dataChangedNotificationEventElement);
-
- try {
- ByteArrayOutputStream out = new ByteArrayOutputStream();
- TransformerFactory tf = TransformerFactory.newInstance();
- Transformer transformer = tf.newTransformer();
- transformer
- .setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "no");
- transformer.setOutputProperty(OutputKeys.METHOD, "xml");
- transformer.setOutputProperty(OutputKeys.INDENT, "yes");
- transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
- transformer.setOutputProperty(
- "{http://xml.apache.org/xslt}indent-amount", "4");
- transformer.transform(new DOMSource(doc), new StreamResult(
- new OutputStreamWriter(out, "UTF-8")));
- byte[] charData = out.toByteArray();
- return new String(charData, "UTF-8");
- } catch (TransformerException | UnsupportedEncodingException e) {
- String msg = "Error during transformation of Document into String";
- logger.error(msg, e);
- return msg;
- }
- }
-
- /**
- * Formats data specified by RFC3339.
- *
- * @param d
- * Date
- * @return Data specified by RFC3339.
- */
- private String toRFC3339(Date d) {
- return rfc3339.format(d).replaceAll("(\\d\\d)(\\d\\d)$", "$1:$2");
- }
-
- /**
- * Creates {@link Document} document.
- *
- * @return {@link Document} document.
- */
- private Document createDocument() {
- DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
- Document doc = null;
- try {
- DocumentBuilder bob = dbf.newDocumentBuilder();
- doc = bob.newDocument();
- } catch (ParserConfigurationException e) {
- return null;
- }
- return doc;
- }
-
- /**
- * Adds values to data changed notification event element.
- *
- * @param doc
- * {@link Document}
- * @param dataChangedNotificationEventElement
- * {@link Element}
- * @param change
- * {@link DataChangeEvent}
- */
- private void addValuesToDataChangedNotificationEventElement(Document doc,
- Element dataChangedNotificationEventElement,
- DataChangeEvent<InstanceIdentifier, CompositeNode> change) {
- addValuesFromDataToElement(doc, change.getCreatedConfigurationData(),
- dataChangedNotificationEventElement, Store.CONFIG,
- Operation.CREATED);
- addValuesFromDataToElement(doc, change.getCreatedOperationalData(),
- dataChangedNotificationEventElement, Store.OPERATION,
- Operation.CREATED);
- if (change.getCreatedConfigurationData().isEmpty()) {
- addValuesFromDataToElement(doc,
- change.getUpdatedConfigurationData(),
- dataChangedNotificationEventElement, Store.CONFIG,
- Operation.UPDATED);
- }
- if (change.getCreatedOperationalData().isEmpty()) {
- addValuesFromDataToElement(doc, change.getUpdatedOperationalData(),
- dataChangedNotificationEventElement, Store.OPERATION,
- Operation.UPDATED);
- }
- addValuesFromDataToElement(doc, change.getRemovedConfigurationData(),
- dataChangedNotificationEventElement, Store.CONFIG,
- Operation.DELETED);
- addValuesFromDataToElement(doc, change.getRemovedOperationalData(),
- dataChangedNotificationEventElement, Store.OPERATION,
- Operation.DELETED);
- }
-
- /**
- * Adds values from data to element.
- *
- * @param doc
- * {@link Document}
- * @param data
- * Set of {@link InstanceIdentifier}.
- * @param element
- * {@link Element}
- * @param store
- * {@link Store}
- * @param operation
- * {@link Operation}
- */
- private void addValuesFromDataToElement(Document doc,
- Set<InstanceIdentifier> data, Element element, Store store,
- Operation operation) {
- if (data == null || data.isEmpty()) {
- return;
- }
- for (InstanceIdentifier path : data) {
- Node node = createDataChangeEventElement(doc, path, null, store,
- operation);
- element.appendChild(node);
- }
- }
-
- /**
- * Adds values from data to element.
- *
- * @param doc
- * {@link Document}
- * @param data
- * Map of {@link InstanceIdentifier} and {@link CompositeNode}.
- * @param element
- * {@link Element}
- * @param store
- * {@link Store}
- * @param operation
- * {@link Operation}
- */
- private void addValuesFromDataToElement(Document doc,
- Map<InstanceIdentifier, CompositeNode> data, Element element,
- Store store, Operation operation) {
- if (data == null || data.isEmpty()) {
- return;
- }
- for (Entry<InstanceIdentifier, CompositeNode> entry : data.entrySet()) {
- Node node = createDataChangeEventElement(doc, entry.getKey(),
- entry.getValue(), store, operation);
- element.appendChild(node);
- }
- }
-
- /**
- * Creates changed event element from data.
- *
- * @param doc
- * {@link Document}
- * @param path
- * Path to data in data store.
- * @param data
- * {@link CompositeNode}
- * @param store
- * {@link Store}
- * @param operation
- * {@link Operation}
- * @return {@link Node} node represented by changed event element.
- */
- private Node createDataChangeEventElement(Document doc,
- InstanceIdentifier path, CompositeNode data, Store store,
- Operation operation) {
- Element dataChangeEventElement = doc.createElement("data-change-event");
-
- Element pathElement = doc.createElement("path");
- addPathAsValueToElement(path, pathElement);
- dataChangeEventElement.appendChild(pathElement);
-
- Element storeElement = doc.createElement("store");
- storeElement.setTextContent(store.value);
- dataChangeEventElement.appendChild(storeElement);
-
- Element operationElement = doc.createElement("operation");
- operationElement.setTextContent(operation.value);
- dataChangeEventElement.appendChild(operationElement);
-
- if (data != null) {
- Element dataElement = doc.createElement("data");
- Node dataAnyXml = translateToXml(path, data);
- Node adoptedNode = doc.adoptNode(dataAnyXml);
- dataElement.appendChild(adoptedNode);
- dataChangeEventElement.appendChild(dataElement);
- }
-
- return dataChangeEventElement;
- }
-
- /**
- * Translates {@link CompositeNode} data to XML format.
- *
- * @param path
- * Path to data in data store.
- * @param data
- * {@link CompositeNode}
- * @return Data in XML format.
- */
- private Node translateToXml(InstanceIdentifier path, CompositeNode data) {
- DataNodeContainer schemaNode = ControllerContext.getInstance()
- .getDataNodeContainerFor(path);
- if (schemaNode == null) {
- logger.info(
- "Path '{}' contains node with unsupported type (supported type is Container or List) or some node was not found.",
- path);
- return null;
- }
- try {
- Document xml = xmlMapper.write(data, schemaNode);
- return xml.getFirstChild();
- } catch (UnsupportedDataTypeException e) {
- logger.error(
- "Error occured during translation of notification to XML.",
- e);
- return null;
- }
- }
-
- /**
- * Adds path as value to element.
- *
- * @param path
- * Path to data in data store.
- * @param element
- * {@link Element}
- */
- private void addPathAsValueToElement(InstanceIdentifier path,
- Element element) {
- // Map< key = namespace, value = prefix>
- Map<String, String> prefixes = new HashMap<>();
- InstanceIdentifier instanceIdentifier = path;
- StringBuilder textContent = new StringBuilder();
- for (PathArgument pathArgument : instanceIdentifier.getPath()) {
- textContent.append("/");
- writeIdentifierWithNamespacePrefix(element, textContent,
- pathArgument.getNodeType(), prefixes);
- if (pathArgument instanceof NodeIdentifierWithPredicates) {
- Map<QName, Object> predicates = ((NodeIdentifierWithPredicates) pathArgument)
- .getKeyValues();
- for (QName keyValue : predicates.keySet()) {
- String predicateValue = String.valueOf(predicates
- .get(keyValue));
- textContent.append("[");
- writeIdentifierWithNamespacePrefix(element, textContent,
- keyValue, prefixes);
- textContent.append("='");
- textContent.append(predicateValue);
- textContent.append("'");
- textContent.append("]");
- }
- } else if (pathArgument instanceof NodeWithValue) {
- textContent.append("[.='");
- textContent.append(((NodeWithValue) pathArgument).getValue());
- textContent.append("'");
- textContent.append("]");
- }
- }
- element.setTextContent(textContent.toString());
- }
-
- /**
- * Writes identifier that consists of prefix and QName.
- *
- * @param element
- * {@link Element}
- * @param textContent
- * StringBuilder
- * @param qName
- * QName
- * @param prefixes
- * Map of namespaces and prefixes.
- */
- private static void writeIdentifierWithNamespacePrefix(Element element,
- StringBuilder textContent, QName qName, Map<String, String> prefixes) {
- String namespace = qName.getNamespace().toString();
- String prefix = prefixes.get(namespace);
- if (prefix == null) {
- prefix = qName.getPrefix();
- if (prefix == null || prefix.isEmpty()
- || prefixes.containsValue(prefix)) {
- prefix = generateNewPrefix(prefixes.values());
- }
- }
-
- element.setAttribute("xmlns:" + prefix, namespace);
- textContent.append(prefix);
- prefixes.put(namespace, prefix);
-
- textContent.append(":");
- textContent.append(qName.getLocalName());
- }
-
- /**
- * Generates new prefix which consists of four random characters <a-z>.
- *
- * @param prefixes
- * Collection of prefixes.
- * @return New prefix which consists of four random characters <a-z>.
- */
- private static String generateNewPrefix(Collection<String> prefixes) {
- StringBuilder result = null;
- Random random = new Random();
- do {
- result = new StringBuilder();
- for (int i = 0; i < 4; i++) {
- int randomNumber = 0x61 + (Math.abs(random.nextInt()) % 26);
- result.append(Character.toChars(randomNumber));
- }
- } while (prefixes.contains(result.toString()));
-
- return result.toString();
- }
-
- /**
- * Gets path pointed to data in data store.
- *
- * @return Path pointed to data in data store.
- */
- public InstanceIdentifier getPath() {
- return path;
- }
-
- /**
- * Sets {@link ListenerRegistration} registration.
- *
- * @param registration
- * ListenerRegistration<DataChangeListener>
- */
- public void setRegistration(
- ListenerRegistration<DataChangeListener> registration) {
- this.registration = registration;
- }
-
- /**
- * Gets the name of the stream.
- *
- * @return The name of the stream.
- */
- public String getStreamName() {
- return streamName;
- }
-
- /**
- * Removes all subscribers and unregisters event bus change recorder form
- * event bus.
- */
- public void close() throws Exception {
- subscribers = new ConcurrentSet<>();
- registration.close();
- registration = null;
- eventBus.unregister(eventBusChangeRecorder);
- }
-
- /**
- * Checks if {@link ListenerRegistration} registration exist.
- *
- * @return True if exist, false otherwise.
- */
- public boolean isListening() {
- return registration == null ? false : true;
- }
-
- /**
- * Creates event of type {@link EventType#REGISTER}, set {@link Channel}
- * subscriber to the event and post event into event bus.
- *
- * @param subscriber
- * Channel
- */
- public void addSubscriber(Channel subscriber) {
- if (!subscriber.isActive()) {
- logger.debug("Channel is not active between websocket server and subscriber {}"
- + subscriber.remoteAddress());
- }
- Event event = new Event(EventType.REGISTER);
- event.setSubscriber(subscriber);
- eventBus.post(event);
- }
-
- /**
- * Creates event of type {@link EventType#DEREGISTER}, sets {@link Channel}
- * subscriber to the event and posts event into event bus.
- *
- * @param subscriber
- */
- public void removeSubscriber(Channel subscriber) {
- logger.debug("Subscriber {} is removed.", subscriber.remoteAddress());
- Event event = new Event(EventType.DEREGISTER);
- event.setSubscriber(subscriber);
- eventBus.post(event);
- }
-
- /**
- * Checks if exists at least one {@link Channel} subscriber.
- *
- * @return True if exist at least one {@link Channel} subscriber, false
- * otherwise.
- */
- public boolean hasSubscribers() {
- return !subscribers.isEmpty();
- }
-
- /**
- * Consists of two types {@link Store#CONFIG} and {@link Store#OPERATION}.
- */
- private static enum Store {
- CONFIG("config"), OPERATION("operation");
-
- private final String value;
-
- private Store(String value) {
- this.value = value;
- }
- }
-
- /**
- * Consists of three types {@link Operation#CREATED},
- * {@link Operation#UPDATED} and {@link Operation#DELETED}.
- */
- private static enum Operation {
- CREATED("created"), UPDATED("updated"), DELETED("deleted");
-
- private final String value;
-
- private Operation(String value) {
- this.value = value;
- }
- }
+ private static final Logger logger = LoggerFactory
+ .getLogger(ListenerAdapter.class);
+ private final XmlMapper xmlMapper = new XmlMapper();
+ private final SimpleDateFormat rfc3339 = new SimpleDateFormat(
+ "yyyy-MM-dd'T'hh:mm:ssZ");
+
+ private final InstanceIdentifier path;
+ private ListenerRegistration<DataChangeListener> registration;
+ private final String streamName;
+ private Set<Channel> subscribers = new ConcurrentSet<>();
+ private final EventBus eventBus;
+ private final EventBusChangeRecorder eventBusChangeRecorder;
+
+ /**
+ * Creates new {@link ListenerAdapter} listener specified by path and stream
+ * name.
+ *
+ * @param path
+ * Path to data in data store.
+ * @param streamName
+ * The name of the stream.
+ */
+ ListenerAdapter(InstanceIdentifier path, String streamName) {
+ Preconditions.checkNotNull(path);
+ Preconditions
+ .checkArgument(streamName != null && !streamName.isEmpty());
+ this.path = path;
+ this.streamName = streamName;
+ eventBus = new AsyncEventBus(Executors.newSingleThreadExecutor());
+ eventBusChangeRecorder = new EventBusChangeRecorder();
+ eventBus.register(eventBusChangeRecorder);
+ }
+
+ @Override
+ public void onDataChanged(
+ DataChangeEvent<InstanceIdentifier, CompositeNode> change) {
+ if (!change.getCreatedConfigurationData().isEmpty()
+ || !change.getCreatedOperationalData().isEmpty()
+ || !change.getUpdatedConfigurationData().isEmpty()
+ || !change.getUpdatedOperationalData().isEmpty()
+ || !change.getRemovedConfigurationData().isEmpty()
+ || !change.getRemovedOperationalData().isEmpty()) {
+ String xml = prepareXmlFrom(change);
+ Event event = new Event(EventType.NOTIFY);
+ event.setData(xml);
+ eventBus.post(event);
+ }
+ }
+
+ /**
+ * Tracks events of data change by customer.
+ */
+ private final class EventBusChangeRecorder {
+ @Subscribe
+ public void recordCustomerChange(Event event) {
+ if (event.getType() == EventType.REGISTER) {
+ Channel subscriber = event.getSubscriber();
+ if (!subscribers.contains(subscriber)) {
+ subscribers.add(subscriber);
+ }
+ } else if (event.getType() == EventType.DEREGISTER) {
+ subscribers.remove(event.getSubscriber());
+ Notificator
+ .removeListenerIfNoSubscriberExists(ListenerAdapter.this);
+ } else if (event.getType() == EventType.NOTIFY) {
+ for (Channel subscriber : subscribers) {
+ if (subscriber.isActive()) {
+ logger.debug("Data are sent to subscriber {}:",
+ subscriber.remoteAddress());
+ subscriber.writeAndFlush(new TextWebSocketFrame(event
+ .getData()));
+ } else {
+ logger.debug(
+ "Subscriber {} is removed - channel is not active yet.",
+ subscriber.remoteAddress());
+ subscribers.remove(subscriber);
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Represents event of specific {@link EventType} type, holds data and
+ * {@link Channel} subscriber.
+ */
+ private final class Event {
+ private final EventType type;
+ private Channel subscriber;
+ private String data;
+
+ /**
+ * Creates new event specified by {@link EventType} type.
+ *
+ * @param type
+ * EventType
+ */
+ public Event(EventType type) {
+ this.type = type;
+ }
+
+ /**
+ * Gets the {@link Channel} subscriber.
+ *
+ * @return Channel
+ */
+ public Channel getSubscriber() {
+ return subscriber;
+ }
+
+ /**
+ * Sets subscriber for event.
+ *
+ * @param subscriber
+ * Channel
+ */
+ public void setSubscriber(Channel subscriber) {
+ this.subscriber = subscriber;
+ }
+
+ /**
+ * Gets event data.
+ *
+ * @return String representation of event data.
+ */
+ public String getData() {
+ return data;
+ }
+
+ /**
+ * Sets event data.
+ *
+ * @param String
+ * data.
+ */
+ public void setData(String data) {
+ this.data = data;
+ }
+
+ /**
+ * Gets event type.
+ *
+ * @return The type of the event.
+ */
+ public EventType getType() {
+ return type;
+ }
+ }
+
+ /**
+ * Type of the event.
+ */
+ private enum EventType {
+ REGISTER, DEREGISTER, NOTIFY;
+ }
+
+ /**
+ * Prepare data in printable form and transform it to String.
+ *
+ * @param change
+ * DataChangeEvent
+ * @return Data in printable form.
+ */
+ private String prepareXmlFrom(
+ DataChangeEvent<InstanceIdentifier, CompositeNode> change) {
+ Document doc = createDocument();
+ Element notificationElement = doc.createElementNS(
+ "urn:ietf:params:xml:ns:netconf:notification:1.0",
+ "notification");
+ doc.appendChild(notificationElement);
+
+ Element eventTimeElement = doc.createElement("eventTime");
+ eventTimeElement.setTextContent(toRFC3339(new Date()));
+ notificationElement.appendChild(eventTimeElement);
+
+ Element dataChangedNotificationEventElement = doc.createElementNS(
+ "urn:opendaylight:params:xml:ns:yang:controller:md:sal:remote",
+ "data-changed-notification");
+ addValuesToDataChangedNotificationEventElement(doc,
+ dataChangedNotificationEventElement, change);
+ notificationElement.appendChild(dataChangedNotificationEventElement);
+
+ try {
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ TransformerFactory tf = TransformerFactory.newInstance();
+ Transformer transformer = tf.newTransformer();
+ transformer
+ .setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "no");
+ transformer.setOutputProperty(OutputKeys.METHOD, "xml");
+ transformer.setOutputProperty(OutputKeys.INDENT, "yes");
+ transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
+ transformer.setOutputProperty(
+ "{http://xml.apache.org/xslt}indent-amount", "4");
+ transformer.transform(new DOMSource(doc), new StreamResult(
+ new OutputStreamWriter(out, "UTF-8")));
+ byte[] charData = out.toByteArray();
+ return new String(charData, "UTF-8");
+ } catch (TransformerException | UnsupportedEncodingException e) {
+ String msg = "Error during transformation of Document into String";
+ logger.error(msg, e);
+ return msg;
+ }
+ }
+
+ /**
+ * Formats data specified by RFC3339.
+ *
+ * @param d
+ * Date
+ * @return Data specified by RFC3339.
+ */
+ private String toRFC3339(Date d) {
+ return rfc3339.format(d).replaceAll("(\\d\\d)(\\d\\d)$", "$1:$2");
+ }
+
+ /**
+ * Creates {@link Document} document.
+ *
+ * @return {@link Document} document.
+ */
+ private Document createDocument() {
+ DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
+ Document doc = null;
+ try {
+ DocumentBuilder bob = dbf.newDocumentBuilder();
+ doc = bob.newDocument();
+ } catch (ParserConfigurationException e) {
+ return null;
+ }
+ return doc;
+ }
+
+ /**
+ * Adds values to data changed notification event element.
+ *
+ * @param doc
+ * {@link Document}
+ * @param dataChangedNotificationEventElement
+ * {@link Element}
+ * @param change
+ * {@link DataChangeEvent}
+ */
+ private void addValuesToDataChangedNotificationEventElement(Document doc,
+ Element dataChangedNotificationEventElement,
+ DataChangeEvent<InstanceIdentifier, CompositeNode> change) {
+ addValuesFromDataToElement(doc, change.getCreatedConfigurationData(),
+ dataChangedNotificationEventElement, Store.CONFIG,
+ Operation.CREATED);
+ addValuesFromDataToElement(doc, change.getCreatedOperationalData(),
+ dataChangedNotificationEventElement, Store.OPERATION,
+ Operation.CREATED);
+ if (change.getCreatedConfigurationData().isEmpty()) {
+ addValuesFromDataToElement(doc,
+ change.getUpdatedConfigurationData(),
+ dataChangedNotificationEventElement, Store.CONFIG,
+ Operation.UPDATED);
+ }
+ if (change.getCreatedOperationalData().isEmpty()) {
+ addValuesFromDataToElement(doc, change.getUpdatedOperationalData(),
+ dataChangedNotificationEventElement, Store.OPERATION,
+ Operation.UPDATED);
+ }
+ addValuesFromDataToElement(doc, change.getRemovedConfigurationData(),
+ dataChangedNotificationEventElement, Store.CONFIG,
+ Operation.DELETED);
+ addValuesFromDataToElement(doc, change.getRemovedOperationalData(),
+ dataChangedNotificationEventElement, Store.OPERATION,
+ Operation.DELETED);
+ }
+
+ /**
+ * Adds values from data to element.
+ *
+ * @param doc
+ * {@link Document}
+ * @param data
+ * Set of {@link InstanceIdentifier}.
+ * @param element
+ * {@link Element}
+ * @param store
+ * {@link Store}
+ * @param operation
+ * {@link Operation}
+ */
+ private void addValuesFromDataToElement(Document doc,
+ Set<InstanceIdentifier> data, Element element, Store store,
+ Operation operation) {
+ if (data == null || data.isEmpty()) {
+ return;
+ }
+ for (InstanceIdentifier path : data) {
+ Node node = createDataChangeEventElement(doc, path, null, store,
+ operation);
+ element.appendChild(node);
+ }
+ }
+
+ /**
+ * Adds values from data to element.
+ *
+ * @param doc
+ * {@link Document}
+ * @param data
+ * Map of {@link InstanceIdentifier} and {@link CompositeNode}.
+ * @param element
+ * {@link Element}
+ * @param store
+ * {@link Store}
+ * @param operation
+ * {@link Operation}
+ */
+ private void addValuesFromDataToElement(Document doc,
+ Map<InstanceIdentifier, CompositeNode> data, Element element,
+ Store store, Operation operation) {
+ if (data == null || data.isEmpty()) {
+ return;
+ }
+ for (Entry<InstanceIdentifier, CompositeNode> entry : data.entrySet()) {
+ Node node = createDataChangeEventElement(doc, entry.getKey(),
+ entry.getValue(), store, operation);
+ element.appendChild(node);
+ }
+ }
+
+ /**
+ * Creates changed event element from data.
+ *
+ * @param doc
+ * {@link Document}
+ * @param path
+ * Path to data in data store.
+ * @param data
+ * {@link CompositeNode}
+ * @param store
+ * {@link Store}
+ * @param operation
+ * {@link Operation}
+ * @return {@link Node} node represented by changed event element.
+ */
+ private Node createDataChangeEventElement(Document doc,
+ InstanceIdentifier path, CompositeNode data, Store store,
+ Operation operation) {
+ Element dataChangeEventElement = doc.createElement("data-change-event");
+
+ Element pathElement = doc.createElement("path");
+ addPathAsValueToElement(path, pathElement);
+ dataChangeEventElement.appendChild(pathElement);
+
+ Element storeElement = doc.createElement("store");
+ storeElement.setTextContent(store.value);
+ dataChangeEventElement.appendChild(storeElement);
+
+ Element operationElement = doc.createElement("operation");
+ operationElement.setTextContent(operation.value);
+ dataChangeEventElement.appendChild(operationElement);
+
+ if (data != null) {
+ Element dataElement = doc.createElement("data");
+ Node dataAnyXml = translateToXml(path, data);
+ Node adoptedNode = doc.adoptNode(dataAnyXml);
+ dataElement.appendChild(adoptedNode);
+ dataChangeEventElement.appendChild(dataElement);
+ }
+
+ return dataChangeEventElement;
+ }
+
+ /**
+ * Translates {@link CompositeNode} data to XML format.
+ *
+ * @param path
+ * Path to data in data store.
+ * @param data
+ * {@link CompositeNode}
+ * @return Data in XML format.
+ */
+ private Node translateToXml(InstanceIdentifier path, CompositeNode data) {
+ DataNodeContainer schemaNode = ControllerContext.getInstance()
+ .getDataNodeContainerFor(path);
+ if (schemaNode == null) {
+ logger.info(
+ "Path '{}' contains node with unsupported type (supported type is Container or List) or some node was not found.",
+ path);
+ return null;
+ }
+ try {
+ Document xml = xmlMapper.write(data, schemaNode);
+ return xml.getFirstChild();
+ } catch (UnsupportedDataTypeException e) {
+ logger.error(
+ "Error occured during translation of notification to XML.",
+ e);
+ return null;
+ }
+ }
+
+ /**
+ * Adds path as value to element.
+ *
+ * @param path
+ * Path to data in data store.
+ * @param element
+ * {@link Element}
+ */
+ private void addPathAsValueToElement(InstanceIdentifier path,
+ Element element) {
+ // Map< key = namespace, value = prefix>
+ Map<String, String> prefixes = new HashMap<>();
+ InstanceIdentifier instanceIdentifier = path;
+ StringBuilder textContent = new StringBuilder();
+ for (PathArgument pathArgument : instanceIdentifier.getPath()) {
+ textContent.append("/");
+ writeIdentifierWithNamespacePrefix(element, textContent,
+ pathArgument.getNodeType(), prefixes);
+ if (pathArgument instanceof NodeIdentifierWithPredicates) {
+ Map<QName, Object> predicates = ((NodeIdentifierWithPredicates) pathArgument)
+ .getKeyValues();
+ for (QName keyValue : predicates.keySet()) {
+ String predicateValue = String.valueOf(predicates
+ .get(keyValue));
+ textContent.append("[");
+ writeIdentifierWithNamespacePrefix(element, textContent,
+ keyValue, prefixes);
+ textContent.append("='");
+ textContent.append(predicateValue);
+ textContent.append("'");
+ textContent.append("]");
+ }
+ } else if (pathArgument instanceof NodeWithValue) {
+ textContent.append("[.='");
+ textContent.append(((NodeWithValue) pathArgument).getValue());
+ textContent.append("'");
+ textContent.append("]");
+ }
+ }
+ element.setTextContent(textContent.toString());
+ }
+
+ /**
+ * Writes identifier that consists of prefix and QName.
+ *
+ * @param element
+ * {@link Element}
+ * @param textContent
+ * StringBuilder
+ * @param qName
+ * QName
+ * @param prefixes
+ * Map of namespaces and prefixes.
+ */
+ private static void writeIdentifierWithNamespacePrefix(Element element,
+ StringBuilder textContent, QName qName, Map<String, String> prefixes) {
+ String namespace = qName.getNamespace().toString();
+ String prefix = prefixes.get(namespace);
+ if (prefix == null) {
+ prefix = qName.getPrefix();
+ if (prefix == null || prefix.isEmpty()
+ || prefixes.containsValue(prefix)) {
+ prefix = generateNewPrefix(prefixes.values());
+ }
+ }
+
+ element.setAttribute("xmlns:" + prefix, namespace);
+ textContent.append(prefix);
+ prefixes.put(namespace, prefix);
+
+ textContent.append(":");
+ textContent.append(qName.getLocalName());
+ }
+
+ /**
+ * Generates new prefix which consists of four random characters <a-z>.
+ *
+ * @param prefixes
+ * Collection of prefixes.
+ * @return New prefix which consists of four random characters <a-z>.
+ */
+ private static String generateNewPrefix(Collection<String> prefixes) {
+ StringBuilder result = null;
+ Random random = new Random();
+ do {
+ result = new StringBuilder();
+ for (int i = 0; i < 4; i++) {
+ int randomNumber = 0x61 + (Math.abs(random.nextInt()) % 26);
+ result.append(Character.toChars(randomNumber));
+ }
+ } while (prefixes.contains(result.toString()));
+
+ return result.toString();
+ }
+
+ /**
+ * Gets path pointed to data in data store.
+ *
+ * @return Path pointed to data in data store.
+ */
+ public InstanceIdentifier getPath() {
+ return path;
+ }
+
+ /**
+ * Sets {@link ListenerRegistration} registration.
+ *
+ * @param registration
+ * ListenerRegistration<DataChangeListener>
+ */
+ public void setRegistration(
+ ListenerRegistration<DataChangeListener> registration) {
+ this.registration = registration;
+ }
+
+ /**
+ * Gets the name of the stream.
+ *
+ * @return The name of the stream.
+ */
+ public String getStreamName() {
+ return streamName;
+ }
+
+ /**
+ * Removes all subscribers and unregisters event bus change recorder form
+ * event bus.
+ */
+ public void close() throws Exception {
+ subscribers = new ConcurrentSet<>();
+ registration.close();
+ registration = null;
+ eventBus.unregister(eventBusChangeRecorder);
+ }
+
+ /**
+ * Checks if {@link ListenerRegistration} registration exist.
+ *
+ * @return True if exist, false otherwise.
+ */
+ public boolean isListening() {
+ return registration == null ? false : true;
+ }
+
+ /**
+ * Creates event of type {@link EventType#REGISTER}, set {@link Channel}
+ * subscriber to the event and post event into event bus.
+ *
+ * @param subscriber
+ * Channel
+ */
+ public void addSubscriber(Channel subscriber) {
+ if (!subscriber.isActive()) {
+ logger.debug("Channel is not active between websocket server and subscriber {}"
+ + subscriber.remoteAddress());
+ }
+ Event event = new Event(EventType.REGISTER);
+ event.setSubscriber(subscriber);
+ eventBus.post(event);
+ }
+
+ /**
+ * Creates event of type {@link EventType#DEREGISTER}, sets {@link Channel}
+ * subscriber to the event and posts event into event bus.
+ *
+ * @param subscriber
+ */
+ public void removeSubscriber(Channel subscriber) {
+ logger.debug("Subscriber {} is removed.", subscriber.remoteAddress());
+ Event event = new Event(EventType.DEREGISTER);
+ event.setSubscriber(subscriber);
+ eventBus.post(event);
+ }
+
+ /**
+ * Checks if exists at least one {@link Channel} subscriber.
+ *
+ * @return True if exist at least one {@link Channel} subscriber, false
+ * otherwise.
+ */
+ public boolean hasSubscribers() {
+ return !subscribers.isEmpty();
+ }
+
+ /**
+ * Consists of two types {@link Store#CONFIG} and {@link Store#OPERATION}.
+ */
+ private static enum Store {
+ CONFIG("config"), OPERATION("operation");
+
+ private final String value;
+
+ private Store(String value) {
+ this.value = value;
+ }
+ }
+
+ /**
+ * Consists of three types {@link Operation#CREATED},
+ * {@link Operation#UPDATED} and {@link Operation#DELETED}.
+ */
+ private static enum Operation {
+ CREATED("created"), UPDATED("updated"), DELETED("deleted");
+
+ private final String value;
+
+ private Operation(String value) {
+ this.value = value;
+ }
+ }
}
public class Notificator {
private static Map<String, ListenerAdapter> listenersByStreamName = new ConcurrentHashMap<>();
- private static Map<InstanceIdentifier, ListenerAdapter> listenersByInstanceIdentifier = new ConcurrentHashMap<>();
- private static final Lock lock = new ReentrantLock();
+ private static Map<InstanceIdentifier, ListenerAdapter> listenersByInstanceIdentifier = new ConcurrentHashMap<>();
+ private static final Lock lock = new ReentrantLock();
- private Notificator() {
- }
+ private Notificator() {
+ }
/**
* Returns list of all stream names
}
- /**
- * Gets {@link ListenerAdapter} specified by stream name.
- *
- * @param streamName
- * The name of the stream.
- * @return {@link ListenerAdapter} specified by stream name.
- */
- public static ListenerAdapter getListenerFor(String streamName) {
- return listenersByStreamName.get(streamName);
- }
-
- /**
- * Gets {@link ListenerAdapter} listener specified by
- * {@link InstanceIdentifier} path.
- *
- * @param path
- * Path to data in data repository.
- * @return ListenerAdapter
- */
- public static ListenerAdapter getListenerFor(InstanceIdentifier path) {
- return listenersByInstanceIdentifier.get(path);
- }
-
- /**
- * Checks if the listener specified by {@link InstanceIdentifier} path
- * exist.
- *
- * @param path
- * Path to data in data repository.
- * @return True if the listener exist, false otherwise.
- */
- public static boolean existListenerFor(InstanceIdentifier path) {
- return listenersByInstanceIdentifier.containsKey(path);
- }
-
- /**
- * Creates new {@link ListenerAdapter} listener from
- * {@link InstanceIdentifier} path and stream name.
- *
- * @param path
- * Path to data in data repository.
- * @param streamName
- * The name of the stream.
- * @return New {@link ListenerAdapter} listener from
- * {@link InstanceIdentifier} path and stream name.
- */
- public static ListenerAdapter createListener(InstanceIdentifier path,
- String streamName) {
- ListenerAdapter listener = new ListenerAdapter(path, streamName);
- try {
- lock.lock();
- listenersByInstanceIdentifier.put(path, listener);
- listenersByStreamName.put(streamName, listener);
- } finally {
- lock.unlock();
- }
- return listener;
- }
-
- /**
- * Looks for listener determined by {@link InstanceIdentifier} path and
- * removes it.
- *
- * @param path
- * InstanceIdentifier
- */
- public static void removeListener(InstanceIdentifier path) {
- ListenerAdapter listener = listenersByInstanceIdentifier.get(path);
- deleteListener(listener);
- }
-
- /**
- * Creates String representation of stream name from URI. Removes slash from
- * URI in start and end position.
- *
- * @param uri
- * URI for creation stream name.
- * @return String representation of stream name.
- */
- public static String createStreamNameFromUri(String uri) {
- if (uri == null) {
- return null;
- }
- String result = uri;
- if (result.startsWith("/")) {
- result = result.substring(1);
- }
- if (result.endsWith("/")) {
- result = result.substring(0, result.length());
- }
- return result;
- }
-
- /**
- * Removes all listeners.
- */
- public static void removeAllListeners() {
- for (ListenerAdapter listener : listenersByInstanceIdentifier.values()) {
- try {
- listener.close();
- } catch (Exception e) {
- }
- }
- try {
- lock.lock();
- listenersByStreamName = new ConcurrentHashMap<>();
- listenersByInstanceIdentifier = new ConcurrentHashMap<>();
- } finally {
- lock.unlock();
- }
- }
-
- /**
- * Checks if listener has at least one subscriber. In case it doesn't have any, delete
- * listener.
- *
- * @param listener
- * ListenerAdapter
- */
- public static void removeListenerIfNoSubscriberExists(
- ListenerAdapter listener) {
- if (!listener.hasSubscribers()) {
- deleteListener(listener);
- }
- }
-
- /**
- * Delete {@link ListenerAdapter} listener specified in parameter.
- *
- * @param listener
- * ListenerAdapter
- */
- private static void deleteListener(ListenerAdapter listener) {
- if (listener != null) {
- try {
- listener.close();
- } catch (Exception e) {
- }
- try {
- lock.lock();
- listenersByInstanceIdentifier.remove(listener.getPath());
- listenersByStreamName.remove(listener.getStreamName());
- } finally {
- lock.unlock();
- }
- }
- }
+ /**
+ * Gets {@link ListenerAdapter} specified by stream name.
+ *
+ * @param streamName
+ * The name of the stream.
+ * @return {@link ListenerAdapter} specified by stream name.
+ */
+ public static ListenerAdapter getListenerFor(String streamName) {
+ return listenersByStreamName.get(streamName);
+ }
+
+ /**
+ * Gets {@link ListenerAdapter} listener specified by
+ * {@link InstanceIdentifier} path.
+ *
+ * @param path
+ * Path to data in data repository.
+ * @return ListenerAdapter
+ */
+ public static ListenerAdapter getListenerFor(InstanceIdentifier path) {
+ return listenersByInstanceIdentifier.get(path);
+ }
+
+ /**
+ * Checks if the listener specified by {@link InstanceIdentifier} path
+ * exist.
+ *
+ * @param path
+ * Path to data in data repository.
+ * @return True if the listener exist, false otherwise.
+ */
+ public static boolean existListenerFor(InstanceIdentifier path) {
+ return listenersByInstanceIdentifier.containsKey(path);
+ }
+
+ /**
+ * Creates new {@link ListenerAdapter} listener from
+ * {@link InstanceIdentifier} path and stream name.
+ *
+ * @param path
+ * Path to data in data repository.
+ * @param streamName
+ * The name of the stream.
+ * @return New {@link ListenerAdapter} listener from
+ * {@link InstanceIdentifier} path and stream name.
+ */
+ public static ListenerAdapter createListener(InstanceIdentifier path,
+ String streamName) {
+ ListenerAdapter listener = new ListenerAdapter(path, streamName);
+ try {
+ lock.lock();
+ listenersByInstanceIdentifier.put(path, listener);
+ listenersByStreamName.put(streamName, listener);
+ } finally {
+ lock.unlock();
+ }
+ return listener;
+ }
+
+ /**
+ * Looks for listener determined by {@link InstanceIdentifier} path and
+ * removes it.
+ *
+ * @param path
+ * InstanceIdentifier
+ */
+ public static void removeListener(InstanceIdentifier path) {
+ ListenerAdapter listener = listenersByInstanceIdentifier.get(path);
+ deleteListener(listener);
+ }
+
+ /**
+ * Creates String representation of stream name from URI. Removes slash from
+ * URI in start and end position.
+ *
+ * @param uri
+ * URI for creation stream name.
+ * @return String representation of stream name.
+ */
+ public static String createStreamNameFromUri(String uri) {
+ if (uri == null) {
+ return null;
+ }
+ String result = uri;
+ if (result.startsWith("/")) {
+ result = result.substring(1);
+ }
+ if (result.endsWith("/")) {
+ result = result.substring(0, result.length());
+ }
+ return result;
+ }
+
+ /**
+ * Removes all listeners.
+ */
+ public static void removeAllListeners() {
+ for (ListenerAdapter listener : listenersByInstanceIdentifier.values()) {
+ try {
+ listener.close();
+ } catch (Exception e) {
+ }
+ }
+ try {
+ lock.lock();
+ listenersByStreamName = new ConcurrentHashMap<>();
+ listenersByInstanceIdentifier = new ConcurrentHashMap<>();
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ /**
+ * Checks if listener has at least one subscriber. In case it doesn't have any, delete
+ * listener.
+ *
+ * @param listener
+ * ListenerAdapter
+ */
+ public static void removeListenerIfNoSubscriberExists(
+ ListenerAdapter listener) {
+ if (!listener.hasSubscribers()) {
+ deleteListener(listener);
+ }
+ }
+
+ /**
+ * Delete {@link ListenerAdapter} listener specified in parameter.
+ *
+ * @param listener
+ * ListenerAdapter
+ */
+ private static void deleteListener(ListenerAdapter listener) {
+ if (listener != null) {
+ try {
+ listener.close();
+ } catch (Exception e) {
+ }
+ try {
+ lock.lock();
+ listenersByInstanceIdentifier.remove(listener.getPath());
+ listenersByStreamName.remove(listener.getStreamName());
+ } finally {
+ lock.unlock();
+ }
+ }
+ }
}
*/
public class WebSocketServer implements Runnable {
- private static final Logger logger = LoggerFactory
- .getLogger(WebSocketServer.class);
-
- public static final int PORT = 8181;
- private EventLoopGroup bossGroup;
- private EventLoopGroup workerGroup;
-
- @Override
- public void run() {
- bossGroup = new NioEventLoopGroup();
- workerGroup = new NioEventLoopGroup();
- try {
- ServerBootstrap b = new ServerBootstrap();
- b.group(bossGroup, workerGroup)
- .channel(NioServerSocketChannel.class)
- .childHandler(new WebSocketServerInitializer());
-
- Channel ch = b.bind(PORT).sync().channel();
- logger.info("Web socket server started at port {}.", PORT);
-
- ch.closeFuture().sync();
- } catch (InterruptedException e) {
- // NOOP
- } finally {
- stop();
- }
- }
-
- /**
- * Stops the web socket server and removes all listeners.
- */
- private void stop() {
- Notificator.removeAllListeners();
- if (bossGroup != null) {
- bossGroup.shutdownGracefully();
- }
- if (workerGroup != null) {
- workerGroup.shutdownGracefully();
- }
- }
+ private static final Logger logger = LoggerFactory
+ .getLogger(WebSocketServer.class);
+
+ public static final int PORT = 8181;
+ private EventLoopGroup bossGroup;
+ private EventLoopGroup workerGroup;
+
+ @Override
+ public void run() {
+ bossGroup = new NioEventLoopGroup();
+ workerGroup = new NioEventLoopGroup();
+ try {
+ ServerBootstrap b = new ServerBootstrap();
+ b.group(bossGroup, workerGroup)
+ .channel(NioServerSocketChannel.class)
+ .childHandler(new WebSocketServerInitializer());
+
+ Channel ch = b.bind(PORT).sync().channel();
+ logger.info("Web socket server started at port {}.", PORT);
+
+ ch.closeFuture().sync();
+ } catch (InterruptedException e) {
+ // NOOP
+ } finally {
+ stop();
+ }
+ }
+
+ /**
+ * Stops the web socket server and removes all listeners.
+ */
+ private void stop() {
+ Notificator.removeAllListeners();
+ if (bossGroup != null) {
+ bossGroup.shutdownGracefully();
+ }
+ if (workerGroup != null) {
+ workerGroup.shutdownGracefully();
+ }
+ }
}
*/
public class WebSocketServerHandler extends SimpleChannelInboundHandler<Object> {
- private static final Logger logger = LoggerFactory
- .getLogger(WebSocketServerHandler.class);
-
- private WebSocketServerHandshaker handshaker;
-
- @Override
- protected void channelRead0(ChannelHandlerContext ctx, Object msg)
- throws Exception {
- if (msg instanceof FullHttpRequest) {
- handleHttpRequest(ctx, (FullHttpRequest) msg);
- } else if (msg instanceof WebSocketFrame) {
- handleWebSocketFrame(ctx, (WebSocketFrame) msg);
- }
- }
-
- /**
- * Checks if HTTP request method is GET and if is possible to decode HTTP
- * result of request.
- *
- * @param ctx
- * ChannelHandlerContext
- * @param req
- * FullHttpRequest
- */
- private void handleHttpRequest(ChannelHandlerContext ctx,
- FullHttpRequest req) throws Exception {
- // Handle a bad request.
- if (!req.getDecoderResult().isSuccess()) {
- sendHttpResponse(ctx, req, new DefaultFullHttpResponse(HTTP_1_1,
- BAD_REQUEST));
- return;
- }
-
- // Allow only GET methods.
- if (req.getMethod() != GET) {
- sendHttpResponse(ctx, req, new DefaultFullHttpResponse(HTTP_1_1,
- FORBIDDEN));
- return;
- }
-
- String streamName = Notificator.createStreamNameFromUri(req.getUri());
- ListenerAdapter listener = Notificator.getListenerFor(streamName);
- if (listener != null) {
- listener.addSubscriber(ctx.channel());
- logger.debug("Subscriber successfully registered.");
- } else {
- logger.error("Listener for stream with name '{}' was not found.",
- streamName);
- sendHttpResponse(ctx, req, new DefaultFullHttpResponse(HTTP_1_1,
- INTERNAL_SERVER_ERROR));
- }
-
- // Handshake
- WebSocketServerHandshakerFactory wsFactory = new WebSocketServerHandshakerFactory(
- getWebSocketLocation(req), null, false);
- handshaker = wsFactory.newHandshaker(req);
- if (handshaker == null) {
- WebSocketServerHandshakerFactory
- .sendUnsupportedWebSocketVersionResponse(ctx.channel());
- } else {
- handshaker.handshake(ctx.channel(), req);
- }
-
- }
-
- /**
- * Checks response status, send response and close connection if necessary
- *
- * @param ctx
- * ChannelHandlerContext
- * @param req
- * HttpRequest
- * @param res
- * FullHttpResponse
- */
- private static void sendHttpResponse(ChannelHandlerContext ctx,
- HttpRequest req, FullHttpResponse res) {
- // Generate an error page if response getStatus code is not OK (200).
- if (res.getStatus().code() != 200) {
- ByteBuf buf = Unpooled.copiedBuffer(res.getStatus().toString(),
- CharsetUtil.UTF_8);
- res.content().writeBytes(buf);
- buf.release();
- setContentLength(res, res.content().readableBytes());
- }
-
- // Send the response and close the connection if necessary.
- ChannelFuture f = ctx.channel().writeAndFlush(res);
- if (!isKeepAlive(req) || res.getStatus().code() != 200) {
- f.addListener(ChannelFutureListener.CLOSE);
- }
- }
-
- /**
- * Handles web socket frame.
- *
- * @param ctx
- * {@link ChannelHandlerContext}
- * @param frame
- * {@link WebSocketFrame}
- */
- private void handleWebSocketFrame(ChannelHandlerContext ctx,
- WebSocketFrame frame) throws IOException {
- if (frame instanceof CloseWebSocketFrame) {
- handshaker.close(ctx.channel(),
- (CloseWebSocketFrame) frame.retain());
- String streamName = Notificator
- .createStreamNameFromUri(((CloseWebSocketFrame) frame)
- .reasonText());
- ListenerAdapter listener = Notificator.getListenerFor(streamName);
- if (listener != null) {
- listener.removeSubscriber(ctx.channel());
- logger.debug("Subscriber successfully registered.");
- }
- Notificator.removeListenerIfNoSubscriberExists(listener);
- return;
- } else if (frame instanceof PingWebSocketFrame) {
- ctx.channel().write(
- new PongWebSocketFrame(frame.content().retain()));
- return;
- }
- }
-
- @Override
- public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause)
- throws Exception {
- if (cause instanceof java.nio.channels.ClosedChannelException == false) {
- // cause.printStackTrace();
- }
- ctx.close();
- }
-
- /**
- * Get web socket location from HTTP request.
- *
- * @param req
- * HTTP request from which the location will be returned
- * @return String representation of web socket location.
- */
- private static String getWebSocketLocation(HttpRequest req) {
- return "http://" + req.headers().get(HOST) + req.getUri();
- }
+ private static final Logger logger = LoggerFactory
+ .getLogger(WebSocketServerHandler.class);
+
+ private WebSocketServerHandshaker handshaker;
+
+ @Override
+ protected void channelRead0(ChannelHandlerContext ctx, Object msg)
+ throws Exception {
+ if (msg instanceof FullHttpRequest) {
+ handleHttpRequest(ctx, (FullHttpRequest) msg);
+ } else if (msg instanceof WebSocketFrame) {
+ handleWebSocketFrame(ctx, (WebSocketFrame) msg);
+ }
+ }
+
+ /**
+ * Checks if HTTP request method is GET and if is possible to decode HTTP
+ * result of request.
+ *
+ * @param ctx
+ * ChannelHandlerContext
+ * @param req
+ * FullHttpRequest
+ */
+ private void handleHttpRequest(ChannelHandlerContext ctx,
+ FullHttpRequest req) throws Exception {
+ // Handle a bad request.
+ if (!req.getDecoderResult().isSuccess()) {
+ sendHttpResponse(ctx, req, new DefaultFullHttpResponse(HTTP_1_1,
+ BAD_REQUEST));
+ return;
+ }
+
+ // Allow only GET methods.
+ if (req.getMethod() != GET) {
+ sendHttpResponse(ctx, req, new DefaultFullHttpResponse(HTTP_1_1,
+ FORBIDDEN));
+ return;
+ }
+
+ String streamName = Notificator.createStreamNameFromUri(req.getUri());
+ ListenerAdapter listener = Notificator.getListenerFor(streamName);
+ if (listener != null) {
+ listener.addSubscriber(ctx.channel());
+ logger.debug("Subscriber successfully registered.");
+ } else {
+ logger.error("Listener for stream with name '{}' was not found.",
+ streamName);
+ sendHttpResponse(ctx, req, new DefaultFullHttpResponse(HTTP_1_1,
+ INTERNAL_SERVER_ERROR));
+ }
+
+ // Handshake
+ WebSocketServerHandshakerFactory wsFactory = new WebSocketServerHandshakerFactory(
+ getWebSocketLocation(req), null, false);
+ handshaker = wsFactory.newHandshaker(req);
+ if (handshaker == null) {
+ WebSocketServerHandshakerFactory
+ .sendUnsupportedWebSocketVersionResponse(ctx.channel());
+ } else {
+ handshaker.handshake(ctx.channel(), req);
+ }
+
+ }
+
+ /**
+ * Checks response status, send response and close connection if necessary
+ *
+ * @param ctx
+ * ChannelHandlerContext
+ * @param req
+ * HttpRequest
+ * @param res
+ * FullHttpResponse
+ */
+ private static void sendHttpResponse(ChannelHandlerContext ctx,
+ HttpRequest req, FullHttpResponse res) {
+ // Generate an error page if response getStatus code is not OK (200).
+ if (res.getStatus().code() != 200) {
+ ByteBuf buf = Unpooled.copiedBuffer(res.getStatus().toString(),
+ CharsetUtil.UTF_8);
+ res.content().writeBytes(buf);
+ buf.release();
+ setContentLength(res, res.content().readableBytes());
+ }
+
+ // Send the response and close the connection if necessary.
+ ChannelFuture f = ctx.channel().writeAndFlush(res);
+ if (!isKeepAlive(req) || res.getStatus().code() != 200) {
+ f.addListener(ChannelFutureListener.CLOSE);
+ }
+ }
+
+ /**
+ * Handles web socket frame.
+ *
+ * @param ctx
+ * {@link ChannelHandlerContext}
+ * @param frame
+ * {@link WebSocketFrame}
+ */
+ private void handleWebSocketFrame(ChannelHandlerContext ctx,
+ WebSocketFrame frame) throws IOException {
+ if (frame instanceof CloseWebSocketFrame) {
+ handshaker.close(ctx.channel(),
+ (CloseWebSocketFrame) frame.retain());
+ String streamName = Notificator
+ .createStreamNameFromUri(((CloseWebSocketFrame) frame)
+ .reasonText());
+ ListenerAdapter listener = Notificator.getListenerFor(streamName);
+ if (listener != null) {
+ listener.removeSubscriber(ctx.channel());
+ logger.debug("Subscriber successfully registered.");
+ }
+ Notificator.removeListenerIfNoSubscriberExists(listener);
+ return;
+ } else if (frame instanceof PingWebSocketFrame) {
+ ctx.channel().write(
+ new PongWebSocketFrame(frame.content().retain()));
+ return;
+ }
+ }
+
+ @Override
+ public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause)
+ throws Exception {
+ if (cause instanceof java.nio.channels.ClosedChannelException == false) {
+ // cause.printStackTrace();
+ }
+ ctx.close();
+ }
+
+ /**
+ * Get web socket location from HTTP request.
+ *
+ * @param req
+ * HTTP request from which the location will be returned
+ * @return String representation of web socket location.
+ */
+ private static String getWebSocketLocation(HttpRequest req) {
+ return "http://" + req.headers().get(HOST) + req.getUri();
+ }
}
* {@link ChannelPipeline} of a {@link Channel}.
*/
public class WebSocketServerInitializer extends
- ChannelInitializer<SocketChannel> {
+ ChannelInitializer<SocketChannel> {
- @Override
- protected void initChannel(SocketChannel ch) throws Exception {
- ChannelPipeline pipeline = ch.pipeline();
- pipeline.addLast("codec-http", new HttpServerCodec());
- pipeline.addLast("aggregator", new HttpObjectAggregator(65536));
- pipeline.addLast("handler", new WebSocketServerHandler());
- }
+ @Override
+ protected void initChannel(SocketChannel ch) throws Exception {
+ ChannelPipeline pipeline = ch.pipeline();
+ pipeline.addLast("codec-http", new HttpServerCodec());
+ pipeline.addLast("aggregator", new HttpObjectAggregator(65536));
+ pipeline.addLast("handler", new WebSocketServerHandler());
+ }
}
</init-param>
<init-param>
<param-name>cors.allowed.headers</param-name>
- <param-value>Content-Type,X-Requested-With,accept,authorization,
+ <param-value>Content-Type,X-Requested-With,accept,authorization,
origin,Origin,Access-Control-Request-Method,Access-Control-Request-Headers</param-value>
</init-param>
<init-param>
* Test when some data are in one case node and other in another. This isn't
* correct. Next Json validator should return error because nodes has to be
* from one case below concrete choice.
- *
+ *
*/
@Test
public void nodeSchemasOnVariousChoiceCasePathTest() {
* Additionally data are loadef from various choices. This isn't correct.
* Next Json validator should return error because nodes has to be from one
* case below concrete choice.
- *
+ *
*/
@Test
public void nodeSchemasOnVariousChoiceCasePathAndMultipleChoicesTest() {
}
/**
- *
+ *
*/
@Test
public void nodeSchemasInMultipleChoicesTest() {
import org.opendaylight.yangtools.yang.data.api.CompositeNode;
/**
- *
+ *
* All tests are commented now because leafref isn't supported now
- *
+ *
*/
public class CnSnToJsonLeafrefType extends YangAndXmlAndDataSchemaLoader {
import org.opendaylight.yangtools.yang.data.api.CompositeNode;
/**
- *
+ *
* CnSn = Composite node and Simple node data structure Class contains test of
* serializing simple nodes data values according data types from YANG schema to
* XML file
- *
+ *
*/
public class CnSnInstanceIdentifierToXmlTest extends YangAndXmlAndDataSchemaLoader {
-
+
@BeforeClass
public static void initialization() throws URISyntaxException {
dataLoad("/instanceidentifier/yang", 4, "instance-identifier-module", "cont");
// String output =
// String.format("<data>" +
-// "\n<cont_m1>" +
-// "\n\t<lf1_m1>" +
-// "\n\t\tlf1 m1 value" +
-// "\n\t</lf1_m1>" +
+// "\n<cont_m1>" +
+// "\n\t<lf1_m1>" +
+// "\n\t\tlf1 m1 value" +
+// "\n\t</lf1_m1>" +
// "\n</cont_m1>" +
// "\n<cont_m2>" +
// "\n\t<lf1_m2>" +
regex.append(".*<data.*");
regex.append(".*xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\"");
regex.append(".*>");
-
-
+
+
regex.append(".*<contB_m1.*\\/>");
regex.append(".*xmlns=\"module:one\"");
regex.append(".*>");
SimpleNodeWrapper lf1_m1 = new SimpleNodeWrapper(uriModule1, "lf1_m1", "lf1 m1 value");
cont_m1.addValue(lf1_m1);
CompositeNodeWrapper contB_m1 = new CompositeNodeWrapper(uriModule1, "contB_m1");
-
+
data.addValue(contB_m1);
data.addValue(cont_m1);
import org.opendaylight.yangtools.yang.common.RpcResult;
public class DummyFuture implements Future<RpcResult<TransactionStatus>> {
-
+
private final boolean cancel;
private final boolean isCancelled;
private final boolean isDone;
private final RpcResult<TransactionStatus> result;
-
+
public DummyFuture() {
cancel = false;
isCancelled = false;
isDone = false;
result = null;
}
-
+
private DummyFuture(Builder builder) {
cancel = builder.cancel;
isCancelled = builder.isCancelled;
isDone = builder.isDone;
result = builder.result;
}
-
+
public static Builder builder() {
return new DummyFuture.Builder();
}
ExecutionException, TimeoutException {
return result;
}
-
+
public static class Builder {
-
+
private boolean cancel;
private boolean isCancelled;
private boolean isDone;
this.cancel = cancel;
return this;
}
-
+
public Builder isCancelled(boolean isCancelled) {
this.isCancelled = isCancelled;
return this;
}
-
+
public Builder isDone(boolean isDone) {
this.isDone = isDone;
return this;
}
-
+
public Builder rpcResult(RpcResult<TransactionStatus> result) {
this.result = result;
return this;
}
-
+
public Future<RpcResult<TransactionStatus>> build() {
return new DummyFuture(this);
}
when(brokerFacade.commitConfigurationDataDelete(any(InstanceIdentifier.class))).thenReturn(dummyFuture);
Response response = target(uri).request(MediaType.APPLICATION_XML).delete();
assertEquals(200, response.getStatus());
-
+
dummyFuture = createFuture(TransactionStatus.FAILED);
when(brokerFacade.commitConfigurationDataDelete(any(InstanceIdentifier.class))).thenReturn(dummyFuture);
response = target(uri).request(MediaType.APPLICATION_XML).delete();
assertEquals(500, response.getStatus());
}
-
+
private Future<RpcResult<TransactionStatus>> createFuture(TransactionStatus statusName) {
RpcResult<TransactionStatus> rpcResult = new DummyRpcResult.Builder<TransactionStatus>().result(statusName).build();
return DummyFuture.builder().rpcResult(rpcResult).build();
}
/**
- *
+ *
* Fill missing data (namespaces) and build correct data type in
* {@code compositeNode} according to {@code dataSchemaNode}. The method
* {@link RestconfImpl#createConfigurationData createConfigurationData} is
* Searches module with name {@code searchedModuleName} in {@code modules}.
* If module name isn't specified and module set has only one element then
* this element is returned.
- *
+ *
*/
public static Module resolveModule(String searchedModuleName, Set<Module> modules) {
assertNotNull("Modules can't be null.", modules);
Lf lf2 = new Lf("name", "value");
Lf lf3 = new Lf("name1", "value");
Lf lf4 = new Lf("name", "value1");
-
+
assertTrue(lf1.equals(lf2));
assertFalse(lf1.equals(lf3));
assertFalse(lf1.equals(lf4));
loadAndNormalizeData("/common/augment/xml/dataa.xml", "/common/augment/yang", "main","cont");
loadAndNormalizeData("/common/augment/xml/datab.xml", "/common/augment/yang", "main","cont");
}
-
+
private void loadAndNormalizeData(String xmlPath, String yangPath, String topLevelElementName, String moduleName) {
CompositeNode compNode = TestUtils.readInputToCnSn(xmlPath, false,
XmlToCompositeNodeProvider.INSTANCE);
<cont>
- <lf1>lf1</lf1>
- <lf2>lf2</lf2>
- <cont1>
- <lf11>lf11</lf11>
- </cont1>
- <lst1>
- <lf11>lf1_1</lf11>
- </lst1>
- <lst1>
- <lf11>lf1_2</lf11>
- </lst1>
- <lflst1>lflst1_1</lflst1>
- <lflst1>lflst1_2</lflst1>
- <lflst1>lflst1_3</lflst1>
+ <lf1>lf1</lf1>
+ <lf2>lf2</lf2>
+ <cont1>
+ <lf11>lf11</lf11>
+ </cont1>
+ <lst1>
+ <lf11>lf1_1</lf11>
+ </lst1>
+ <lst1>
+ <lf11>lf1_2</lf11>
+ </lst1>
+ <lflst1>lflst1_1</lflst1>
+ <lflst1>lflst1_2</lflst1>
+ <lflst1>lflst1_3</lflst1>
</cont>
\ No newline at end of file
<cont>
- <e1>45</e1>
- <lf2b>lf2b val</lf2b>
+ <e1>45</e1>
+ <lf2b>lf2b val</lf2b>
</cont>
\ No newline at end of file
<cont>
- <cont1c>
- <lf11c>lf11c val</lf11c>
- </cont1c>
+ <cont1c>
+ <lf11c>lf11c val</lf11c>
+ </cont1c>
</cont>
\ No newline at end of file
<cont>
- <lflst1d>lflst1d_1 val</lflst1d>
- <lflst1d>lflst1d_2 val</lflst1d>
+ <lflst1d>lflst1d_1 val</lflst1d>
+ <lflst1d>lflst1d_2 val</lflst1d>
</cont>
\ No newline at end of file
<cont>
- <lst1b>
- <lf11b>lf11b_1 val</lf11b>
- </lst1b>
- <lst1b>
- <lf11b>lf11b_2 val</lf11b>
- </lst1b>
+ <lst1b>
+ <lf11b>lf11b_1 val</lf11b>
+ </lst1b>
+ <lst1b>
+ <lf11b>lf11b_2 val</lf11b>
+ </lst1b>
</cont>
\ No newline at end of file
<cont>
- <cont1c>
- <lf11c>lf11c val</lf11c>
- </cont1c>
- <lf2b>lf2b value</lf2b>
+ <cont1c>
+ <lf11c>lf11c val</lf11c>
+ </cont1c>
+ <lf2b>lf2b value</lf2b>
</cont>
\ No newline at end of file
<cont>
- <cont1c>
- <lf11c>lf11c val</lf11c>
- </cont1c>
- <lf2b>lf2b value</lf2b>
- <lf2a>lf2b value</lf2a>
+ <cont1c>
+ <lf11c>lf11c val</lf11c>
+ </cont1c>
+ <lf2b>lf2b value</lf2b>
+ <lf2a>lf2b value</lf2a>
</cont>
\ No newline at end of file
<cont>
- <lf1>lf1 val</lf1>
- <lf1a>121</lf1a>
- <lf1ab>lf1ab val</lf1ab>
+ <lf1>lf1 val</lf1>
+ <lf1a>121</lf1a>
+ <lf1ab>lf1ab val</lf1ab>
</cont>
\ No newline at end of file
<cont>
- <lf1aa>lf1aa val</lf1aa>
- <lf1>lf1 val</lf1>
- <lf1a>121</lf1a>
- <lf1aaa>lf1aaa val</lf1aaa>
+ <lf1aa>lf1aa val</lf1aa>
+ <lf1>lf1 val</lf1>
+ <lf1a>121</lf1a>
+ <lf1aaa>lf1aaa val</lf1aaa>
</cont>
\ No newline at end of file
<cont>
- <lf1aaa>lf1aaa value</lf1aaa>
- <lf2b>lf2b value</lf2b>
- <lst4a>
- <lf4ab>33</lf4ab>
- </lst4a>
- <lst4a>
- <lf4ab>33</lf4ab>
- </lst4a>
- <lst4a>
- <lf4ab>37</lf4ab>
- </lst4a>
+ <lf1aaa>lf1aaa value</lf1aaa>
+ <lf2b>lf2b value</lf2b>
+ <lst4a>
+ <lf4ab>33</lf4ab>
+ </lst4a>
+ <lst4a>
+ <lf4ab>33</lf4ab>
+ </lst4a>
+ <lst4a>
+ <lf4ab>37</lf4ab>
+ </lst4a>
</cont>
\ No newline at end of file
<cont>
- <lf1aa>lf1aa val</lf1aa>
- <lf1>lf1 val</lf1>
- <lf1a>121</lf1a>
- <lf1ab>lf1ab value</lf1ab>
+ <lf1aa>lf1aa val</lf1aa>
+ <lf1>lf1 val</lf1>
+ <lf1a>121</lf1a>
+ <lf1ab>lf1ab value</lf1ab>
</cont>
\ No newline at end of file
<cont>
- <cont1>
- <lf11>true</lf11>
- </cont1>
- <lf3>true</lf3>
+ <cont1>
+ <lf11>true</lf11>
+ </cont1>
+ <lf3>true</lf3>
</cont>
\ No newline at end of file
<cont>
- <lf7>200</lf7>
+ <lf7>200</lf7>
</cont>
\ No newline at end of file
<cont>
- <lf5>137</lf5>
+ <lf5>137</lf5>
</cont>
\ No newline at end of file
<cont>
- <lf6>44.33</lf6>
+ <lf6>44.33</lf6>
</cont>
\ No newline at end of file
<cont>
- <lflst1>345</lflst1>
- <lflst1>346</lflst1>
- <lflst1>347</lflst1>
+ <lflst1>345</lflst1>
+ <lflst1>346</lflst1>
+ <lflst1>347</lflst1>
</cont>
\ No newline at end of file
<cont>
- <lf1>121</lf1>
- <lf2>121</lf2>
+ <lf1>121</lf1>
+ <lf2>121</lf2>
</cont>
\ No newline at end of file
<cont>
- <lfnint8Min>-128</lfnint8Min>
- <lfnint8Max>127</lfnint8Max>
- <lfnint16Min>-32768</lfnint16Min>
- <lfnint16Max>32767</lfnint16Max>
- <lfnint32Min>-2147483648</lfnint32Min>
- <lfnint32Max>2147483647</lfnint32Max>
- <lfnint64Min>-9223372036854775808</lfnint64Min>
- <lfnint64Max>9223372036854775807</lfnint64Max>
- <lfnuint8Max>255</lfnuint8Max>
- <lfnuint16Max>65535</lfnuint16Max>
- <lfnuint32Max>4294967295</lfnuint32Max>
- <lfstr>lfstr</lfstr>
- <lfstr1></lfstr1>
- <lfbool1>true</lfbool1>
- <lfbool2>false</lfbool2>
- <lfbool3>bla</lfbool3>
- <lfdecimal1>43.32</lfdecimal1>
- <lfdecimal2>-0.43</lfdecimal2>
- <lfdecimal3>43</lfdecimal3>
- <lfdecimal4>43E3</lfdecimal4>
- <lfdecimal6>33.12345</lfdecimal6>
- <lfenum>enum3</lfenum>
- <lfbits>bit3 bit2</lfbits>
- <lfbinary>ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz</lfbinary>
- <lfempty />
- <lfunion1>324</lfunion1>
- <lfunion2>33.3</lfunion2>
- <lfunion3>55</lfunion3>
- <lfunion4>true</lfunion4>
- <lfunion5>true</lfunion5>
- <lfunion6>10</lfunion6>
- <lfunion7></lfunion7>
- <lfunion8></lfunion8>
- <lfunion9></lfunion9>
- <lfunion10>bt1</lfunion10>
- <lfunion11>33</lfunion11>
- <lfunion12>false</lfunion12>
- <lfunion13>b1</lfunion13>
- <lfunion14>zero</lfunion14>
- <identityref1 xmlns:x="simple:data:types">x:iden</identityref1>
+ <lfnint8Min>-128</lfnint8Min>
+ <lfnint8Max>127</lfnint8Max>
+ <lfnint16Min>-32768</lfnint16Min>
+ <lfnint16Max>32767</lfnint16Max>
+ <lfnint32Min>-2147483648</lfnint32Min>
+ <lfnint32Max>2147483647</lfnint32Max>
+ <lfnint64Min>-9223372036854775808</lfnint64Min>
+ <lfnint64Max>9223372036854775807</lfnint64Max>
+ <lfnuint8Max>255</lfnuint8Max>
+ <lfnuint16Max>65535</lfnuint16Max>
+ <lfnuint32Max>4294967295</lfnuint32Max>
+ <lfstr>lfstr</lfstr>
+ <lfstr1></lfstr1>
+ <lfbool1>true</lfbool1>
+ <lfbool2>false</lfbool2>
+ <lfbool3>bla</lfbool3>
+ <lfdecimal1>43.32</lfdecimal1>
+ <lfdecimal2>-0.43</lfdecimal2>
+ <lfdecimal3>43</lfdecimal3>
+ <lfdecimal4>43E3</lfdecimal4>
+ <lfdecimal6>33.12345</lfdecimal6>
+ <lfenum>enum3</lfenum>
+ <lfbits>bit3 bit2</lfbits>
+ <lfbinary>ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz</lfbinary>
+ <lfempty />
+ <lfunion1>324</lfunion1>
+ <lfunion2>33.3</lfunion2>
+ <lfunion3>55</lfunion3>
+ <lfunion4>true</lfunion4>
+ <lfunion5>true</lfunion5>
+ <lfunion6>10</lfunion6>
+ <lfunion7></lfunion7>
+ <lfunion8></lfunion8>
+ <lfunion9></lfunion9>
+ <lfunion10>bt1</lfunion10>
+ <lfunion11>33</lfunion11>
+ <lfunion12>false</lfunion12>
+ <lfunion13>b1</lfunion13>
+ <lfunion14>zero</lfunion14>
+ <identityref1 xmlns:x="simple:data:types">x:iden</identityref1>
</cont>
\ No newline at end of file
<cont1>
- <lf11>lf</lf11>
- <lflst11>56</lflst11>
- <lflst11>55</lflst11>
- <lflst11>57</lflst11>
- <lflst12>lflst12 str3</lflst12>
- <lst11>
- <lst112>
- <lf1121>lf1121 str22</lf1121>
- </lst112>
- <lf111>141</lf111>
- <lf112>lf112 str2</lf112>
- <lst111>
- <lf1111>55</lf1111>
- </lst111>
- <cont111>
- <lflst1111>4097</lflst1111>
- <lflst1111>2049</lflst1111>
- <lflst1111>1025</lflst1111>
- <lst1111>
- <lf1111A>lf1111A str22</lf1111A>
- <lf1111B>8</lf1111B>
- </lst1111>
- <lf1111>lf1111 str2</lf1111>
- <lst1111>
- <lf1111B>5</lf1111B>
- <lf1111A>lf1111A str21</lf1111A>
- </lst1111>
- </cont111>
- <lst111>
- <lf1111>56</lf1111>
- </lst111>
- <lst112>
- <lf1121>lf1121 str21</lf1121>
- </lst112>
- </lst11>
- <lflst12>lflst12 str1</lflst12>
- <lst11>
- <lf111>140</lf111>
- <lf112>lf112 str</lf112>
- <cont111>
- <lf1111>lf1111 str</lf1111>
- <lflst1111>2048</lflst1111>
- <lflst1111>1024</lflst1111>
- <lflst1111>4096</lflst1111>
- <lst1111>
- <lf1111A>lf1111A str11</lf1111A>
- <lf1111B>4</lf1111B>
- </lst1111>
- <lst1111>
- <lf1111A>lf1111A str12</lf1111A>
- <lf1111B>7</lf1111B>
- </lst1111>
- </cont111>
- <lst111>
- <lf1111>65</lf1111>
- </lst111>
- <lst112>
- <lf1121>lf1121 str11</lf1121>
- </lst112>
- </lst11>
- <lflst12>lflst12 str2</lflst12>
+ <lf11>lf</lf11>
+ <lflst11>56</lflst11>
+ <lflst11>55</lflst11>
+ <lflst11>57</lflst11>
+ <lflst12>lflst12 str3</lflst12>
+ <lst11>
+ <lst112>
+ <lf1121>lf1121 str22</lf1121>
+ </lst112>
+ <lf111>141</lf111>
+ <lf112>lf112 str2</lf112>
+ <lst111>
+ <lf1111>55</lf1111>
+ </lst111>
+ <cont111>
+ <lflst1111>4097</lflst1111>
+ <lflst1111>2049</lflst1111>
+ <lflst1111>1025</lflst1111>
+ <lst1111>
+ <lf1111A>lf1111A str22</lf1111A>
+ <lf1111B>8</lf1111B>
+ </lst1111>
+ <lf1111>lf1111 str2</lf1111>
+ <lst1111>
+ <lf1111B>5</lf1111B>
+ <lf1111A>lf1111A str21</lf1111A>
+ </lst1111>
+ </cont111>
+ <lst111>
+ <lf1111>56</lf1111>
+ </lst111>
+ <lst112>
+ <lf1121>lf1121 str21</lf1121>
+ </lst112>
+ </lst11>
+ <lflst12>lflst12 str1</lflst12>
+ <lst11>
+ <lf111>140</lf111>
+ <lf112>lf112 str</lf112>
+ <cont111>
+ <lf1111>lf1111 str</lf1111>
+ <lflst1111>2048</lflst1111>
+ <lflst1111>1024</lflst1111>
+ <lflst1111>4096</lflst1111>
+ <lst1111>
+ <lf1111A>lf1111A str11</lf1111A>
+ <lf1111B>4</lf1111B>
+ </lst1111>
+ <lst1111>
+ <lf1111A>lf1111A str12</lf1111A>
+ <lf1111B>7</lf1111B>
+ </lst1111>
+ </cont111>
+ <lst111>
+ <lf1111>65</lf1111>
+ </lst111>
+ <lst112>
+ <lf1121>lf1121 str11</lf1121>
+ </lst112>
+ </lst11>
+ <lflst12>lflst12 str2</lflst12>
</cont1>
<cont1>
- <lst11>
- <lf111>1</lf111>
- <lst111></lst111>
- <lst111></lst111>
- <lst111>
- <lf1111></lf1111>
- </lst111>
- <lst111>
- <lf1111>35</lf1111>
- </lst111>
- <cont111></cont111>
- </lst11>
- <lst11>
- <lf111>2</lf111>
- <cont111>
- <lf1111></lf1111>
- <lflst1111></lflst1111>
- <lflst1111>1024</lflst1111>
- <lflst1111>4096</lflst1111>
- <lst1111>
- <lf1111B>4</lf1111B>
- </lst1111>
- <lst1111>
- <lf1111A>lf1111A str12</lf1111A>
- </lst1111>
- </cont111>
- <lst112></lst112>
- </lst11>
- <lst11>
- <lf111>3</lf111>
- <cont111>
- <lf1111></lf1111>
- <lflst1111></lflst1111>
- <lflst1111></lflst1111>
- <lst1111></lst1111>
- <lst1111></lst1111>
- </cont111>
- </lst11>
+ <lst11>
+ <lf111>1</lf111>
+ <lst111></lst111>
+ <lst111></lst111>
+ <lst111>
+ <lf1111></lf1111>
+ </lst111>
+ <lst111>
+ <lf1111>35</lf1111>
+ </lst111>
+ <cont111></cont111>
+ </lst11>
+ <lst11>
+ <lf111>2</lf111>
+ <cont111>
+ <lf1111></lf1111>
+ <lflst1111></lflst1111>
+ <lflst1111>1024</lflst1111>
+ <lflst1111>4096</lflst1111>
+ <lst1111>
+ <lf1111B>4</lf1111B>
+ </lst1111>
+ <lst1111>
+ <lf1111A>lf1111A str12</lf1111A>
+ </lst1111>
+ </cont111>
+ <lst112></lst112>
+ </lst11>
+ <lst11>
+ <lf111>3</lf111>
+ <cont111>
+ <lf1111></lf1111>
+ <lflst1111></lflst1111>
+ <lflst1111></lflst1111>
+ <lst1111></lst1111>
+ <lst1111></lst1111>
+ </cont111>
+ </lst11>
</cont1>
<input xmlns="test:module">
- <cont>
- <cont1>
- <lf11>lf1 data</lf11>
- <lf12>lf2 data</lf12>
- </cont1>
- </cont>
+ <cont>
+ <cont1>
+ <lf11>lf1 data</lf11>
+ <lf12>lf2 data</lf12>
+ </cont1>
+ </cont>
</input>
\ No newline at end of file
<cont xmlns="instance:identifier:module">
<cont1>
- <lst11 xmlns="augment:module" xmlns:c="augment:augment:module">
- <keyvalue111>value1</keyvalue111>
- <keyvalue112>value2</keyvalue112>
- <lf111 xmlns="augment:augment:module" xmlns:a="instance:identifier:module" xmlns:b="augment:module" >/a:cont/a:cont1/b:lst11[b:keyvalue111="value1"][b:keyvalue112="value2"]/c:lf112</lf111>
- <lf112 xmlns="augment:augment:module">lf112 value</lf112>
- </lst11>
+ <lst11 xmlns="augment:module" xmlns:c="augment:augment:module">
+ <keyvalue111>value1</keyvalue111>
+ <keyvalue112>value2</keyvalue112>
+ <lf111 xmlns="augment:augment:module" xmlns:a="instance:identifier:module" xmlns:b="augment:module" >/a:cont/a:cont1/b:lst11[b:keyvalue111="value1"][b:keyvalue112="value2"]/c:lf112</lf111>
+ <lf112 xmlns="augment:augment:module">lf112 value</lf112>
+ </lst11>
</cont1>
</cont>
<interfaces xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces" >
- <interface>
- <name>eth0</name>
- <type>ethernetCsmacd</type>
- <enabled>false</enabled>
- <description>some interface</description>
- </interface>
+ <interface>
+ <name>eth0</name>
+ <type>ethernetCsmacd</type>
+ <enabled>false</enabled>
+ <description>some interface</description>
+ </interface>
</interfaces>
\ No newline at end of file
<cont>
- <lf1>str0</lf1>
- <lf2></lf2>
- <lf3/>
- <lflst1>121</lflst1>
- <lflst1>131</lflst1>
- <lflst1>str1</lflst1>
- <lst1>
- <lf11>str2</lf11>
- </lst1>
- <cont1>
- <lf11>100</lf11>
- </cont1>
+ <lf1>str0</lf1>
+ <lf2></lf2>
+ <lf3/>
+ <lflst1>121</lflst1>
+ <lflst1>131</lflst1>
+ <lflst1>str1</lflst1>
+ <lst1>
+ <lf11>str2</lf11>
+ </lst1>
+ <cont1>
+ <lf11>100</lf11>
+ </cont1>
</cont>
<cont>
- <lst1>
- <lf11>str0</lf11>
- <lflst11>121</lflst11>
- <lflst11>131</lflst11>
- <lflst11>str1</lflst11>
- <lst11>
- <lf111>str2</lf111>
- </lst11>
- <cont11>
- <lf111>100</lf111>
- </cont11>
- </lst1>
- <lst1>
- <lflst11>221</lflst11>
- <cont11>
- <lf111>100</lf111>
- </cont11>
- </lst1>
- <lf1>lf1</lf1>
+ <lst1>
+ <lf11>str0</lf11>
+ <lflst11>121</lflst11>
+ <lflst11>131</lflst11>
+ <lflst11>str1</lflst11>
+ <lst11>
+ <lf111>str2</lf111>
+ </lst11>
+ <cont11>
+ <lf111>100</lf111>
+ </cont11>
+ </lst1>
+ <lst1>
+ <lflst11>221</lflst11>
+ <cont11>
+ <lf111>100</lf111>
+ </cont11>
+ </lst1>
+ <lf1>lf1</lf1>
</cont>
<cont>
- <lf1></lf1>
- <lflst1></lflst1>
- <lflst1></lflst1>
- <lst1>
- <lf11></lf11>
- </lst1>
+ <lf1></lf1>
+ <lflst1></lflst1>
+ <lflst1></lflst1>
+ <lst1>
+ <lf11></lf11>
+ </lst1>
</cont>
<cont xmlns="general:module" xmlns:x="x:namespace" xmlns:y="y:namespace">
- <cont1 xmlns:z="z:namespace" xmlns:a="a:namespace" xmlns:b="b:namespace">
- <lf11 xmlns="identityref:module" xmlns:c="c:namespace">iden</lf11>
+ <cont1 xmlns:z="z:namespace" xmlns:a="a:namespace" xmlns:b="b:namespace">
+ <lf11 xmlns="identityref:module" xmlns:c="c:namespace">iden</lf11>
</cont1>
</cont>
\ No newline at end of file
<cont xmlns:x="x:namespace" xmlns:y="y:namespace">
- <cont1 xmlns="identityref:module" xmlns:z="z:namespace" xmlns:a="a:namespace" xmlns:b="b:namespace">
- <lf11 xmlns:c="c:namespace">iden</lf11>
+ <cont1 xmlns="identityref:module" xmlns:z="z:namespace" xmlns:a="a:namespace" xmlns:b="b:namespace">
+ <lf11 xmlns:c="c:namespace">iden</lf11>
</cont1>
</cont>
\ No newline at end of file
<cont xmlns="identityref:module" xmlns:x="x:namespace" xmlns:y="y:namespace">
- <cont1 xmlns:c="identity:module" xmlns:z="z:namespace" xmlns:a="a:namespace" xmlns:b="b:namespace">
- <lf11>z:iden</lf11>
+ <cont1 xmlns:c="identity:module" xmlns:z="z:namespace" xmlns:a="a:namespace" xmlns:b="b:namespace">
+ <lf11>z:iden</lf11>
</cont1>
</cont>
\ No newline at end of file
<cont>
- <cont1>
- <lf11>x:iden</lf11>
+ <cont1>
+ <lf11>x:iden</lf11>
</cont1>
</cont>
\ No newline at end of file
<cont>
<cont1>
- <lf11>iden</lf11>
+ <lf11>iden</lf11>
</cont1>
</cont>
\ No newline at end of file
for(DataSchemaNode childNode : childNodes){
JSONObject moduleJSON=null;
String filename = childNode.getQName().getLocalName();
- /*
- * For every container in the module
- */
+ /*
+ * For every container in the module
+ */
if(childNode instanceof ContainerSchemaNode) {
moduleJSON = processContainer((ContainerSchemaNode)childNode, moduleName, true, models);
}
childSchema.put(TYPE_KEY, OBJECT_TYPE);
childSchema.put(PROPERTIES_KEY, childSchemaProperties);
- /*
- * Due to a limitation of the RAML--->JAX-RS tool, sub-properties
- * must be in a separate JSON schema file. Hence, we have to write
- * some properties to a new file, while continuing to process the rest.
- */
+ /*
+ * Due to a limitation of the RAML--->JAX-RS tool, sub-properties
+ * must be in a separate JSON schema file. Hence, we have to write
+ * some properties to a new file, while continuing to process the rest.
+ */
//writeToFile(fileName, childSchema.toString(2), moduleName);
childSchema.put("id", fileName);
models.put(fileName, childSchema);
</init-param>
<init-param>
<param-name>cors.allowed.headers</param-name>
- <param-value>Content-Type,X-Requested-With,accept,authorization,
+ <param-value>Content-Type,X-Requested-With,accept,authorization,
origin,Origin,Access-Control-Request-Method,Access-Control-Request-Headers</param-value>
</init-param>
<init-param>
<type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-data-broker</type>
<name>ref_binding-data-broker</name>
</data-broker>
-
+
<notification-service>
<type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">
binding:binding-notification-service
final OpendaylightGroupStatisticsService groupStatsService,
final OpendaylightMeterStatisticsService meterStatsService,
final OpendaylightPortStatisticsService portStatsService,
- final OpendaylightQueueStatisticsService queueStatsService,
+ final OpendaylightQueueStatisticsService queueStatsService,
final StatisticsRequestScheduler srScheduler) {
this.dps = Preconditions.checkNotNull(dps);
this.targetNodeKey = Preconditions.checkNotNull(nodeKey);
this.srScheduler.addRequestToSchedulerQueue(flowTableStats);
this.srScheduler.addRequestToSchedulerQueue(flowStats);
-
+
this.srScheduler.addRequestToSchedulerQueue(nodeConnectorStats);
-
+
this.srScheduler.addRequestToSchedulerQueue(groupStats);
-
+
this.srScheduler.addRequestToSchedulerQueue(groupDescStats);
-
+
this.srScheduler.addRequestToSchedulerQueue(meterStats);
-
+
this.srScheduler.addRequestToSchedulerQueue(meterConfigStats);
-
+
this.srScheduler.addRequestToSchedulerQueue(queueStats);
}
-
+
public synchronized void start(final Timer timer) {
flowStats.start(dps);
groupDescStats.start(dps);
meterStats.close();
queueStats.close();
- //Clean up queued statistics request from scheduler queue
+ //Clean up queued statistics request from scheduler queue
srScheduler.removeRequestsFromSchedulerQueue(this.getNodeRef());
logger.debug("Statistics handler for {} shut down", targetNodeKey.getId());
private OpendaylightFlowTableStatisticsService flowTableStatsService;
private OpendaylightQueueStatisticsService queueStatsService;
-
+
private final StatisticsRequestScheduler srScheduler;
public StatisticsProvider(final DataProviderService dataService) {
flowTableStatsService = rpcRegistry.getRpcService(OpendaylightFlowTableStatisticsService.class);
queueStatsService = rpcRegistry.getRpcService(OpendaylightQueueStatisticsService.class);
this.srScheduler.start();
-
+
// Start receiving notifications
this.listenerRegistration = nps.registerNotificationListener(this.updateCommiter);
/**
* Main responsibility of the class is to check the MD-SAL data store read/write
- * transaction accumulation level and send statistics request if number of pending
+ * transaction accumulation level and send statistics request if number of pending
* read/write transactions are zero.
* @author avishnoi@in.ibm.com
*
private final Timer timer = new Timer("request-monitor", true);
// We need ordered retrieval, and O(1) contains operation
- private final Map<AbstractStatsTracker,Integer> requestQueue =
+ private final Map<AbstractStatsTracker,Integer> requestQueue =
Collections.synchronizedMap(new LinkedHashMap<AbstractStatsTracker,Integer>());
-
+
private Long PendingTransactions;
-
+
private long lastRequestTime = System.nanoTime();
-
+
private static final long REQUEST_MONITOR_INTERVAL = 1000;
-
+
private final TimerTask task = new TimerTask() {
@Override
public void run() {
public StatisticsRequestScheduler(){
PendingTransactions = (long) 0;
}
-
+
public void addRequestToSchedulerQueue(AbstractStatsTracker statsRequest){
requestQueue.put(statsRequest, null);
}
-
+
public void removeRequestsFromSchedulerQueue(NodeRef node){
AbstractStatsTracker stats = null;
synchronized(requestQueue){
}
@Override
public void onStatusUpdated(DataModificationTransaction transaction, TransactionStatus status) {
-
+
AbstractStatsTracker stats = null;
synchronized(PendingTransactions){
switch(status){
}
sendStatsRequest(stats);
}
-
+
private void sendStatsRequest(AbstractStatsTracker stats){
if(stats != null){
try{
LLDPDiscoveryListener(LLDPDiscoveryProvider manager) {
this.manager = manager;
}
-
+
public void onPacketReceived(PacketReceived lldp) {
NodeConnectorRef src = LLDPDiscoveryUtils.lldpToNodeConnectorRef(lldp.getPayload());
if(src != null) {
ldb.setDestination(lldp.getIngress());
ldb.setSource(new NodeConnectorRef(src));
LinkDiscovered ld = ldb.build();
-
+
manager.getNotificationService().publish(ld);
LLDPLinkAger.getInstance().put(ld);
}
}
-
+
}
public static LLDPLinkAger getInstance() {
return instance;
}
-
+
public void put(LinkDiscovered link) {
Date expires = new Date();
expires.setTime(expires.getTime() + LLDPDiscoveryUtils.LLDP_EXPIRATION_TIME);
linkToDate.put(link, expires);
}
-
+
public void close() {
timer.cancel();
}
-
+
private class LLDPAgingTask extends TimerTask {
@Override
}
}
}
-
+
}
-
+
}
}
public class LLDPDiscoveryUtils {
static Logger LOG = LoggerFactory.getLogger(LLDPDiscoveryUtils.class);
-
+
public static final Long LLDP_INTERVAL = (long) (1000*5); // Send LLDP every five seconds
public static final Long LLDP_EXPIRATION_TIME = LLDP_INTERVAL*3; // Let up to three intervals pass before we decide we are expired.
-
+
public static String macToString(byte[] mac) {
StringBuilder b = new StringBuilder();
for (int i = 0; i < mac.length; i++) {
return b.toString();
}
-
+
public static NodeConnectorRef lldpToNodeConnectorRef(byte[] payload) {
Ethernet ethPkt = new Ethernet();
try {
if (ethPkt.getPayload() instanceof LLDP) {
LLDP lldp = (LLDP) ethPkt.getPayload();
-
+
try {
NodeId srcNodeId = null;
NodeConnectorId srcNodeConnectorId = null;
import static org.opendaylight.md.controller.topology.manager.FlowCapableNodeMapping.toTopologyNode;
import static org.opendaylight.md.controller.topology.manager.FlowCapableNodeMapping.toTopologyNodeId;
-import java.util.concurrent.Future;
-
import org.opendaylight.controller.md.sal.binding.util.TypeSafeDataReader;
-import org.opendaylight.controller.md.sal.common.api.TransactionStatus;
import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction;
-import org.opendaylight.controller.sal.binding.api.data.DataProviderService;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeConnectorUpdated;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeUpdated;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.topology.discovery.rev130819.FlowTopologyDiscoveryListener;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeUpdated;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.OpendaylightInventoryListener;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey;
-import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology;
import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
-import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TopologyId;
import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TpId;
import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
-import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyBuilder;
-import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey;
import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Link;
import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeKey;
import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPoint;
import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPointKey;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
-import org.opendaylight.yangtools.yang.common.RpcResult;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import com.google.common.util.concurrent.FutureCallback;
-import com.google.common.util.concurrent.Futures;
-import com.google.common.util.concurrent.JdkFutureAdapters;
-
-class FlowCapableTopologyExporter implements //
- FlowTopologyDiscoveryListener, //
- OpendaylightInventoryListener //
-{
- protected final static Logger LOG = LoggerFactory.getLogger(FlowCapableTopologyExporter.class);
- public static TopologyKey topology = new TopologyKey(new TopologyId("flow:1"));
+import com.google.common.base.Preconditions;
- // FIXME: Flow capable topology exporter should use transaction chaining API
- private DataProviderService dataService;
+class FlowCapableTopologyExporter implements FlowTopologyDiscoveryListener, OpendaylightInventoryListener {
+ private final InstanceIdentifier<Topology> topology;
+ private final OperationProcessor processor;
- public DataProviderService getDataService() {
- return dataService;
- }
-
- public void setDataService(final DataProviderService dataService) {
- this.dataService = dataService;
- }
-
- private InstanceIdentifier<Topology> topologyPath;
-
- public void start() {
- TopologyBuilder tb = new TopologyBuilder();
- tb.setKey(topology);
- topologyPath = InstanceIdentifier.builder(NetworkTopology.class).child(Topology.class, topology).build();
- Topology top = tb.build();
- DataModificationTransaction tx = dataService.beginTransaction();
- tx.putOperationalData(topologyPath, top);
- listenOnTransactionState(tx.getIdentifier(),tx.commit());
+ FlowCapableTopologyExporter(final OperationProcessor processor, final InstanceIdentifier<Topology> topology) {
+ this.processor = Preconditions.checkNotNull(processor);
+ this.topology = Preconditions.checkNotNull(topology);
}
@Override
- public synchronized void onNodeRemoved(final NodeRemoved notification) {
- NodeId nodeId = toTopologyNodeId(getNodeKey(notification.getNodeRef()).getId());
- InstanceIdentifier<Node> nodeInstance = toNodeIdentifier(notification.getNodeRef());
-
- DataModificationTransaction tx = dataService.beginTransaction();
- tx.removeOperationalData(nodeInstance);
- removeAffectedLinks(tx, nodeId);
- listenOnTransactionState(tx.getIdentifier(),tx.commit());
+ public void onNodeRemoved(final NodeRemoved notification) {
+ processor.enqueueOperation(new TopologyOperation() {
+ @Override
+ public void applyOperation(final DataModificationTransaction transaction) {
+ NodeId nodeId = toTopologyNodeId(getNodeKey(notification.getNodeRef()).getId());
+ InstanceIdentifier<Node> nodeInstance = toNodeIdentifier(notification.getNodeRef());
+ transaction.removeOperationalData(nodeInstance);
+ removeAffectedLinks(transaction, nodeId);
+ }
+ });
}
@Override
- public synchronized void onNodeUpdated(final NodeUpdated notification) {
+ public void onNodeUpdated(final NodeUpdated notification) {
FlowCapableNodeUpdated fcnu = notification.getAugmentation(FlowCapableNodeUpdated.class);
if (fcnu != null) {
- Node node = toTopologyNode(toTopologyNodeId(notification.getId()), notification.getNodeRef());
- InstanceIdentifier<Node> path = getNodePath(toTopologyNodeId(notification.getId()));
- DataModificationTransaction tx = dataService.beginTransaction();
- tx.putOperationalData(path, node);
- listenOnTransactionState(tx.getIdentifier(),tx.commit());
+ processor.enqueueOperation(new TopologyOperation() {
+ @Override
+ public void applyOperation(final DataModificationTransaction transaction) {
+ Node node = toTopologyNode(toTopologyNodeId(notification.getId()), notification.getNodeRef());
+ InstanceIdentifier<Node> path = getNodePath(toTopologyNodeId(notification.getId()));
+ transaction.putOperationalData(path, node);
+ }
+ });
}
}
@Override
- public synchronized void onNodeConnectorRemoved(final NodeConnectorRemoved notification) {
- InstanceIdentifier<TerminationPoint> tpInstance = toTerminationPointIdentifier(notification
- .getNodeConnectorRef());
- TpId tpId = toTerminationPointId(getNodeConnectorKey(notification.getNodeConnectorRef()).getId());
- DataModificationTransaction tx = dataService.beginTransaction();
- tx.removeOperationalData(tpInstance);
- removeAffectedLinks(tx, tpId);
- listenOnTransactionState(tx.getIdentifier(),tx.commit());
+ public void onNodeConnectorRemoved(final NodeConnectorRemoved notification) {
+ processor.enqueueOperation(new TopologyOperation() {
+ @Override
+ public void applyOperation(final DataModificationTransaction transaction) {
+ InstanceIdentifier<TerminationPoint> tpInstance = toTerminationPointIdentifier(notification
+ .getNodeConnectorRef());
+ TpId tpId = toTerminationPointId(getNodeConnectorKey(notification.getNodeConnectorRef()).getId());
+ transaction.removeOperationalData(tpInstance);
+ removeAffectedLinks(transaction, tpId);
+ }
+ });
}
@Override
- public synchronized void onNodeConnectorUpdated(final NodeConnectorUpdated notification) {
- FlowCapableNodeConnectorUpdated fcncu = notification.getAugmentation(FlowCapableNodeConnectorUpdated.class);
+ public void onNodeConnectorUpdated(final NodeConnectorUpdated notification) {
+ final FlowCapableNodeConnectorUpdated fcncu = notification.getAugmentation(FlowCapableNodeConnectorUpdated.class);
if (fcncu != null) {
- NodeId nodeId = toTopologyNodeId(getNodeKey(notification.getNodeConnectorRef()).getId());
- TerminationPoint point = toTerminationPoint(toTerminationPointId(notification.getId()),
- notification.getNodeConnectorRef());
- InstanceIdentifier<TerminationPoint> path = tpPath(nodeId, point.getKey().getTpId());
-
- DataModificationTransaction tx = dataService.beginTransaction();
- tx.putOperationalData(path, point);
- if ((fcncu.getState() != null && fcncu.getState().isLinkDown())
- || (fcncu.getConfiguration() != null && fcncu.getConfiguration().isPORTDOWN())) {
- removeAffectedLinks(tx, point.getTpId());
- }
- listenOnTransactionState(tx.getIdentifier(),tx.commit());
+ processor.enqueueOperation(new TopologyOperation() {
+ @Override
+ public void applyOperation(final DataModificationTransaction transaction) {
+ NodeId nodeId = toTopologyNodeId(getNodeKey(notification.getNodeConnectorRef()).getId());
+ TerminationPoint point = toTerminationPoint(toTerminationPointId(notification.getId()),
+ notification.getNodeConnectorRef());
+ InstanceIdentifier<TerminationPoint> path = tpPath(nodeId, point.getKey().getTpId());
+
+ transaction.putOperationalData(path, point);
+ if ((fcncu.getState() != null && fcncu.getState().isLinkDown())
+ || (fcncu.getConfiguration() != null && fcncu.getConfiguration().isPORTDOWN())) {
+ removeAffectedLinks(transaction, point.getTpId());
+ }
+ }
+ });
}
}
@Override
- public synchronized void onLinkDiscovered(final LinkDiscovered notification) {
- Link link = toTopologyLink(notification);
- InstanceIdentifier<Link> path = linkPath(link);
- DataModificationTransaction tx = dataService.beginTransaction();
- tx.putOperationalData(path, link);
- listenOnTransactionState(tx.getIdentifier(),tx.commit());
-
+ public void onLinkDiscovered(final LinkDiscovered notification) {
+ processor.enqueueOperation(new TopologyOperation() {
+ @Override
+ public void applyOperation(final DataModificationTransaction transaction) {
+ Link link = toTopologyLink(notification);
+ InstanceIdentifier<Link> path = linkPath(link);
+ transaction.putOperationalData(path, link);
+ }
+ });
}
@Override
- public synchronized void onLinkOverutilized(final LinkOverutilized notification) {
+ public void onLinkOverutilized(final LinkOverutilized notification) {
// NOOP
}
@Override
- public synchronized void onLinkRemoved(final LinkRemoved notification) {
- InstanceIdentifier<Link> path = linkPath(toTopologyLink(notification));
- DataModificationTransaction tx = dataService.beginTransaction();
- tx.removeOperationalData(path);
- listenOnTransactionState(tx.getIdentifier(),tx.commit());
+ public void onLinkRemoved(final LinkRemoved notification) {
+ processor.enqueueOperation(new TopologyOperation() {
+ @Override
+ public void applyOperation(final DataModificationTransaction transaction) {
+ transaction.removeOperationalData(linkPath(toTopologyLink(notification)));
+ }
+ });
}
@Override
- public synchronized void onLinkUtilizationNormal(final LinkUtilizationNormal notification) {
+ public void onLinkUtilizationNormal(final LinkUtilizationNormal notification) {
// NOOP
}
- private static InstanceIdentifier<Node> toNodeIdentifier(final NodeRef ref) {
+ private InstanceIdentifier<Node> toNodeIdentifier(final NodeRef ref) {
org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey invNodeKey = getNodeKey(ref);
-
NodeKey nodeKey = new NodeKey(toTopologyNodeId(invNodeKey.getId()));
- return InstanceIdentifier.builder(NetworkTopology.class).child(Topology.class, topology)
- .child(Node.class, nodeKey).build();
+ return topology.child(Node.class, nodeKey);
}
private InstanceIdentifier<TerminationPoint> toTerminationPointIdentifier(final NodeConnectorRef ref) {
private void removeAffectedLinks(final DataModificationTransaction transaction, final NodeId id) {
TypeSafeDataReader reader = TypeSafeDataReader.forReader(transaction);
-
- Topology topologyData = reader.readOperationalData(topologyPath);
- if (topologyData == null) {
- return;
- }
- for (Link link : topologyData.getLink()) {
- if (id.equals(link.getSource().getSourceNode()) || id.equals(link.getDestination().getDestNode())) {
- InstanceIdentifier<Link> path = topologyPath.child(Link.class, link.getKey());
- transaction.removeOperationalData(path);
+ Topology topologyData = reader.readOperationalData(topology);
+ if (topologyData != null) {
+ for (Link link : topologyData.getLink()) {
+ if (id.equals(link.getSource().getSourceNode()) || id.equals(link.getDestination().getDestNode())) {
+ transaction.removeOperationalData(linkPath(link));
+ }
}
}
}
private void removeAffectedLinks(final DataModificationTransaction transaction, final TpId id) {
TypeSafeDataReader reader = TypeSafeDataReader.forReader(transaction);
- Topology topologyData = reader.readOperationalData(topologyPath);
- if (topologyData == null) {
- return;
- }
- for (Link link : topologyData.getLink()) {
- if (id.equals(link.getSource().getSourceTp()) || id.equals(link.getDestination().getDestTp())) {
- InstanceIdentifier<Link> path = topologyPath.child(Link.class, link.getKey());
- transaction.removeOperationalData(path);
+ Topology topologyData = reader.readOperationalData(topology);
+ if (topologyData != null) {
+ for (Link link : topologyData.getLink()) {
+ if (id.equals(link.getSource().getSourceTp()) || id.equals(link.getDestination().getDestTp())) {
+ transaction.removeOperationalData(linkPath(link));
+ }
}
}
}
private InstanceIdentifier<Node> getNodePath(final NodeId nodeId) {
- NodeKey nodeKey = new NodeKey(nodeId);
- return InstanceIdentifier.builder(NetworkTopology.class).child(Topology.class, topology)
- .child(Node.class, nodeKey).build();
+ return topology.child(Node.class, new NodeKey(nodeId));
}
private InstanceIdentifier<TerminationPoint> tpPath(final NodeId nodeId, final TpId tpId) {
NodeKey nodeKey = new NodeKey(nodeId);
TerminationPointKey tpKey = new TerminationPointKey(tpId);
- return InstanceIdentifier.builder(NetworkTopology.class).child(Topology.class, topology)
- .child(Node.class, nodeKey).child(TerminationPoint.class, tpKey).build();
+ return topology.child(Node.class, nodeKey).child(TerminationPoint.class, tpKey);
}
private InstanceIdentifier<Link> linkPath(final Link link) {
- InstanceIdentifier<Link> linkInstanceId = InstanceIdentifier.builder(NetworkTopology.class)
- .child(Topology.class, topology).child(Link.class, link.getKey()).build();
- return linkInstanceId;
- }
-
- /**
- * @param txId transaction identificator
- * @param future transaction result
- */
- private static void listenOnTransactionState(final Object txId, Future<RpcResult<TransactionStatus>> future) {
- Futures.addCallback(JdkFutureAdapters.listenInPoolThread(future),new FutureCallback<RpcResult<TransactionStatus>>() {
-
- @Override
- public void onFailure(Throwable t) {
- LOG.error("Topology export failed for Tx:{}", txId, t);
-
- }
-
- @Override
- public void onSuccess(RpcResult<TransactionStatus> result) {
- if(!result.isSuccessful()) {
- LOG.error("Topology export failed for Tx:{}", txId);
- }
- }
- });
+ return topology.child(Link.class, link.getKey());
}
}
*/
package org.opendaylight.md.controller.topology.manager;
+import java.util.concurrent.ExecutionException;
+
import org.opendaylight.controller.sal.binding.api.AbstractBindingAwareProvider;
import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext;
import org.opendaylight.controller.sal.binding.api.NotificationProviderService;
+import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction;
import org.opendaylight.controller.sal.binding.api.data.DataProviderService;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TopologyId;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyBuilder;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey;
import org.opendaylight.yangtools.concepts.Registration;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
import org.opendaylight.yangtools.yang.binding.NotificationListener;
import org.osgi.framework.BundleContext;
import org.slf4j.Logger;
public class FlowCapableTopologyProvider extends AbstractBindingAwareProvider implements AutoCloseable {
private final static Logger LOG = LoggerFactory.getLogger(FlowCapableTopologyProvider.class);
+ private Registration<NotificationListener> listenerRegistration;
+ private Thread thread;
- private DataProviderService dataService;
-
- public DataProviderService getDataService() {
- return this.dataService;
- }
+ /**
+ * Gets called on start of a bundle.
+ *
+ * @param session
+ */
+ @Override
+ public synchronized void onSessionInitiated(final ProviderContext session) {
+ final DataProviderService dataService = session.getSALService(DataProviderService.class);
+ final NotificationProviderService notificationService = session.getSALService(NotificationProviderService.class);
- public void setDataService(final DataProviderService dataService) {
- this.dataService = dataService;
- }
+ final String name = "flow:1";
+ final TopologyKey key = new TopologyKey(new TopologyId(name));
+ final InstanceIdentifier<Topology> path = InstanceIdentifier
+ .builder(NetworkTopology.class)
+ .child(Topology.class, key)
+ .build();
- private NotificationProviderService notificationService;
+ final OperationProcessor processor = new OperationProcessor(dataService);
+ final FlowCapableTopologyExporter listener = new FlowCapableTopologyExporter(processor, path);
+ this.listenerRegistration = notificationService.registerNotificationListener(listener);
- public NotificationProviderService getNotificationService() {
- return this.notificationService;
- }
+ final DataModificationTransaction tx = dataService.beginTransaction();
+ tx.putOperationalData(path, new TopologyBuilder().setKey(key).build());
+ try {
+ tx.commit().get();
+ } catch (InterruptedException | ExecutionException e) {
+ LOG.warn("Initial topology export failed, continuing anyway", e);
+ }
- public void setNotificationService(final NotificationProviderService notificationService) {
- this.notificationService = notificationService;
+ thread = new Thread(processor);
+ thread.setDaemon(true);
+ thread.setName("FlowCapableTopologyExporter-" + name);
+ thread.start();
}
- private final FlowCapableTopologyExporter exporter = new FlowCapableTopologyExporter();
- private Registration<NotificationListener> listenerRegistration;
-
@Override
- public void close() {
-
- FlowCapableTopologyProvider.LOG.info("FlowCapableTopologyProvider stopped.");
- dataService = null;
- notificationService = null;
+ public synchronized void close() throws InterruptedException {
+ LOG.info("FlowCapableTopologyProvider stopped.");
if (this.listenerRegistration != null) {
try {
this.listenerRegistration.close();
} catch (Exception e) {
- throw new IllegalStateException("Exception during close of listener registration.",e);
+ LOG.error("Failed to close listener registration", e);
}
+ listenerRegistration = null;
+ }
+ if (thread != null) {
+ thread.interrupt();
+ thread.join();
+ thread = null;
}
- }
-
- /**
- * Gets called on start of a bundle.
- *
- * @param session
- */
- @Override
- public void onSessionInitiated(final ProviderContext session) {
- dataService = session.getSALService(DataProviderService.class);
- notificationService = session.getSALService(NotificationProviderService.class);
- this.exporter.setDataService(dataService);
- this.exporter.start();
- this.listenerRegistration = notificationService.registerNotificationListener(this.exporter);
- ;
}
/**
*/
@Override
public void stopImpl(final BundleContext context) {
- this.close();
+ try {
+ this.close();
+ } catch (InterruptedException e) {
+ LOG.error("Failed to stop provider", e);
+ }
}
}
--- /dev/null
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.md.controller.topology.manager;
+
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.LinkedBlockingQueue;
+
+import org.opendaylight.controller.md.sal.common.api.TransactionStatus;
+import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction;
+import org.opendaylight.controller.sal.binding.api.data.DataProviderService;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Preconditions;
+
+final class OperationProcessor implements Runnable {
+ private static final Logger LOG = LoggerFactory.getLogger(OperationProcessor.class);
+ private static final int MAX_TRANSACTION_OPERATIONS = 100;
+ private static final int OPERATION_QUEUE_DEPTH = 500;
+
+ private final BlockingQueue<TopologyOperation> queue = new LinkedBlockingQueue<>(OPERATION_QUEUE_DEPTH);
+ // FIXME: Flow capable topology exporter should use transaction chaining API
+ private final DataProviderService dataService;
+
+ OperationProcessor(final DataProviderService dataService) {
+ this.dataService = Preconditions.checkNotNull(dataService);
+ }
+
+ void enqueueOperation(final TopologyOperation task) {
+ try {
+ queue.put(task);
+ } catch (InterruptedException e) {
+ LOG.warn("Interrupted while submitting task {}", task, e);
+ }
+ }
+
+ @Override
+ public void run() {
+ try {
+ for (;;) {
+ TopologyOperation op = queue.take();
+
+ LOG.debug("New operations available, starting transaction");
+ final DataModificationTransaction tx = dataService.beginTransaction();
+
+ int ops = 0;
+ do {
+ op.applyOperation(tx);
+
+ ops++;
+ if (ops < MAX_TRANSACTION_OPERATIONS) {
+ op = queue.poll();
+ } else {
+ op = null;
+ }
+ } while (op != null);
+
+ LOG.debug("Processed {} operations, submitting transaction", ops);
+
+ try {
+ final RpcResult<TransactionStatus> s = tx.commit().get();
+ if (!s.isSuccessful()) {
+ LOG.error("Topology export failed for Tx:{}", tx.getIdentifier());
+ }
+ } catch (ExecutionException e) {
+ LOG.error("Topology export transaction {} failed", tx.getIdentifier(), e.getCause());
+ }
+ }
+ } catch (InterruptedException e) {
+ LOG.info("Interrupted processing, terminating", e);
+ }
+
+ // Drain all events, making sure any blocked threads are unblocked
+ while (!queue.isEmpty()) {
+ queue.poll();
+ }
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.md.controller.topology.manager;
+
+import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction;
+
+/**
+ * Internal interface for submitted operations. Implementations of this
+ * interface are enqueued and batched into data store transactions.
+ */
+interface TopologyOperation {
+ /**
+ * Execute the operation on top of the transaction.
+ *
+ * @param transaction Datastore transaction
+ */
+ void applyOperation(DataModificationTransaction transaction);
+}
\ No newline at end of file