<feature version='[3.3.0,4.0.0)'>odl-lmax</feature>
<!-- FIXME: Bug 4202: Add MD-SAL provided odl-mdsal-binding-adapter -->
<!-- FIXME: Bug 4202: Add MD-SAL provided odl-mdsal-dom-broker -->
+ <feature version='${mdsal.version}'>odl-mdsal-eos-dom</feature>
<bundle>mvn:org.opendaylight.controller/sal-core-api/{{VERSION}}</bundle>
<bundle>mvn:org.opendaylight.controller/sal-core-spi/{{VERSION}}</bundle>
<bundle start-level="70">mvn:org.opendaylight.controller/sal-schema-service/{{VERSION}}</bundle>
<groupId>com.lmax</groupId>
<artifactId>disruptor</artifactId>
</dependency>
+ <dependency>
+ <groupId>org.opendaylight.mdsal</groupId>
+ <artifactId>mdsal-eos-dom-api</artifactId>
+ </dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-common-impl</artifactId>
<!-- TODO Remove sal.broker.impl from export when SchemaAwareRpcRegistry is not used in connector anymore -->
org.opendaylight.controller.md.sal.dom.broker.impl,
org.opendaylight.controller.md.sal.dom.broker.impl.*,
+ org.opendaylight.controller.md.sal.dom.clustering.impl,
</Export-Package>
<Import-Package>*</Import-Package>
</instructions>
--- /dev/null
+/*
+ * Copyright (c) 2016 Brocade Communications 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.controller.md.sal.dom.clustering.impl;
+
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+import javax.annotation.Nonnull;
+import org.opendaylight.controller.md.sal.common.api.clustering.CandidateAlreadyRegisteredException;
+import org.opendaylight.controller.md.sal.common.api.clustering.Entity;
+import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipCandidateRegistration;
+import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipChange;
+import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipListener;
+import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipListenerRegistration;
+import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipService;
+import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipState;
+import org.opendaylight.mdsal.eos.dom.api.DOMEntity;
+import org.opendaylight.mdsal.eos.dom.api.DOMEntityOwnershipCandidateRegistration;
+import org.opendaylight.mdsal.eos.dom.api.DOMEntityOwnershipChange;
+import org.opendaylight.mdsal.eos.dom.api.DOMEntityOwnershipListener;
+import org.opendaylight.mdsal.eos.dom.api.DOMEntityOwnershipListenerRegistration;
+import org.opendaylight.mdsal.eos.dom.api.DOMEntityOwnershipService;
+import org.opendaylight.yangtools.concepts.AbstractObjectRegistration;
+
+/**
+ * Adapter that bridges between the legacy pre-Boron EntityOwnershipService and DOMEntityOwnershipService interfaces.
+ *
+ * @author Thomas Pantelis
+ */
+public class LegacyEntityOwnershipServiceAdapter implements EntityOwnershipService, AutoCloseable {
+ private final DOMEntityOwnershipService domService;
+
+ public LegacyEntityOwnershipServiceAdapter(@Nonnull DOMEntityOwnershipService domService) {
+ this.domService = Preconditions.checkNotNull(domService);
+ }
+
+ @Override
+ public EntityOwnershipCandidateRegistration registerCandidate(Entity entity)
+ throws CandidateAlreadyRegisteredException {
+ try {
+ return new EntityOwnershipCandidateRegistrationAdapter(domService.registerCandidate(
+ toDOMEntity(entity)), entity);
+ } catch(org.opendaylight.mdsal.eos.common.api.CandidateAlreadyRegisteredException e) {
+ throw new CandidateAlreadyRegisteredException(entity);
+ }
+ }
+
+ @Override
+ public EntityOwnershipListenerRegistration registerListener(String entityType, EntityOwnershipListener listener) {
+ return new EntityOwnershipListenerRegistrationAdapter(entityType, listener,
+ domService.registerListener(entityType, new DOMEntityOwnershipListenerAdapter(listener)));
+ }
+
+ @Override
+ public Optional<EntityOwnershipState> getOwnershipState(Entity forEntity) {
+ return toEntityOwnershipState(domService.getOwnershipState(toDOMEntity(forEntity)));
+ }
+
+ @Override
+ public boolean isCandidateRegistered(Entity entity) {
+ return domService.isCandidateRegistered(toDOMEntity(entity));
+ }
+
+ @Override
+ public void close() {
+ }
+
+ private DOMEntity toDOMEntity(Entity from) {
+ return new DOMEntity(from.getType(), from.getId());
+ }
+
+ private Optional<EntityOwnershipState> toEntityOwnershipState(
+ Optional<org.opendaylight.mdsal.eos.common.api.EntityOwnershipState> from) {
+ if(!from.isPresent()) {
+ return Optional.absent();
+ }
+
+ org.opendaylight.mdsal.eos.common.api.EntityOwnershipState fromState = from.get();
+ return Optional.of(new EntityOwnershipState(
+ fromState == org.opendaylight.mdsal.eos.common.api.EntityOwnershipState.IS_OWNER,
+ fromState != org.opendaylight.mdsal.eos.common.api.EntityOwnershipState.NO_OWNER));
+ }
+
+ private static class EntityOwnershipCandidateRegistrationAdapter extends AbstractObjectRegistration<Entity>
+ implements EntityOwnershipCandidateRegistration {
+ private final DOMEntityOwnershipCandidateRegistration domRegistration;
+
+ EntityOwnershipCandidateRegistrationAdapter(DOMEntityOwnershipCandidateRegistration domRegistration,
+ Entity entity) {
+ super(entity);
+ this.domRegistration = Preconditions.checkNotNull(domRegistration);
+ }
+
+ @Override
+ protected void removeRegistration() {
+ domRegistration.close();
+ }
+ }
+
+ private static class EntityOwnershipListenerRegistrationAdapter extends AbstractObjectRegistration<EntityOwnershipListener>
+ implements EntityOwnershipListenerRegistration {
+ private final String entityType;
+ private final DOMEntityOwnershipListenerRegistration domRegistration;
+
+ EntityOwnershipListenerRegistrationAdapter(String entityType, EntityOwnershipListener listener,
+ DOMEntityOwnershipListenerRegistration domRegistration) {
+ super(listener);
+ this.entityType = Preconditions.checkNotNull(entityType);
+ this.domRegistration = Preconditions.checkNotNull(domRegistration);
+ }
+
+ @Override
+ public String getEntityType() {
+ return entityType;
+ }
+
+ @Override
+ protected void removeRegistration() {
+ domRegistration.close();
+ }
+ }
+
+ private static class DOMEntityOwnershipListenerAdapter implements DOMEntityOwnershipListener {
+ private final EntityOwnershipListener delegateListener;
+
+ DOMEntityOwnershipListenerAdapter(EntityOwnershipListener delegateListener) {
+ this.delegateListener = Preconditions.checkNotNull(delegateListener);
+ }
+
+ @Override
+ public void ownershipChanged(DOMEntityOwnershipChange ownershipChange) {
+ Entity entity = new Entity(ownershipChange.getEntity().getType(), ownershipChange.getEntity().
+ getIdentifier());
+ delegateListener.ownershipChanged(new EntityOwnershipChange(entity,
+ ownershipChange.getState().wasOwner(), ownershipChange.getState().isOwner(),
+ ownershipChange.getState().hasOwner(), ownershipChange.inJeopardy()));
+ }
+ }
+}
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"
+ xmlns:odl="http://opendaylight.org/xmlns/blueprint/v1.0.0">
+
+<!-- <reference id="domEntityOwnershipService" interface="org.opendaylight.mdsal.dom.api.clustering.DOMEntityOwnershipService" /> -->
+
+<!-- <bean id="legacyEntityOwnershipService" class="org.opendaylight.controller.md.sal.common.impl.clustering.LegacyEntityOwnershipServiceAdapter" -->
+<!-- destroy-method="close"> -->
+<!-- <argument ref="domEntityOwnershipService"/> -->
+<!-- </bean> -->
+
+<!-- <service ref="legacyEntityOwnershipService" interface="org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipService" -->
+<!-- odl:type="default"/> -->
+</blueprint>
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (c) 2016 Brocade Communications 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.controller.md.sal.dom.clustering.impl;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import com.google.common.base.Optional;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.opendaylight.controller.md.sal.common.api.clustering.CandidateAlreadyRegisteredException;
+import org.opendaylight.controller.md.sal.common.api.clustering.Entity;
+import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipCandidateRegistration;
+import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipChange;
+import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipListener;
+import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipListenerRegistration;
+import org.opendaylight.mdsal.eos.common.api.EntityOwnershipChangeState;
+import org.opendaylight.mdsal.eos.common.api.EntityOwnershipState;
+import org.opendaylight.mdsal.eos.dom.api.DOMEntity;
+import org.opendaylight.mdsal.eos.dom.api.DOMEntityOwnershipCandidateRegistration;
+import org.opendaylight.mdsal.eos.dom.api.DOMEntityOwnershipChange;
+import org.opendaylight.mdsal.eos.dom.api.DOMEntityOwnershipListener;
+import org.opendaylight.mdsal.eos.dom.api.DOMEntityOwnershipListenerRegistration;
+import org.opendaylight.mdsal.eos.dom.api.DOMEntityOwnershipService;
+
+/**
+ * Unit tests for PreBoronEntityOwnershipServiceAdapter.
+ *
+ * @author Thomas Pantelis
+ */
+public class LegacyEntityOwnershipServiceAdapterTest {
+ static Entity LEGACY_ENTITY = new Entity("foo", "bar");
+ static DOMEntity DOM_ENTITY = new DOMEntity("foo", LEGACY_ENTITY.getId());
+
+ @Mock
+ private DOMEntityOwnershipService mockDOMService;
+
+ private LegacyEntityOwnershipServiceAdapter adapter;
+
+ @Before
+ public void setup() {
+ MockitoAnnotations.initMocks(this);
+ adapter = new LegacyEntityOwnershipServiceAdapter(mockDOMService);
+ }
+
+ @Test
+ public void testRegisterCandidate() throws Exception {
+ DOMEntityOwnershipCandidateRegistration mockDOMReg = mock(DOMEntityOwnershipCandidateRegistration.class);
+ doNothing().when(mockDOMReg).close();
+ doReturn(mockDOMReg).when(mockDOMService).registerCandidate(DOM_ENTITY);
+
+ EntityOwnershipCandidateRegistration reg = adapter.registerCandidate(LEGACY_ENTITY);
+
+ assertNotNull("registerCandidate returned null", reg);
+ assertEquals("getInstance", LEGACY_ENTITY, reg.getInstance());
+
+ reg.close();
+ verify(mockDOMReg).close();
+ }
+
+ @Test(expected=CandidateAlreadyRegisteredException.class)
+ public void testAlreadyRegisteredCandidate() throws Exception {
+ doThrow(new org.opendaylight.mdsal.eos.common.api.CandidateAlreadyRegisteredException(DOM_ENTITY)).
+ when(mockDOMService).registerCandidate(DOM_ENTITY);
+
+ adapter.registerCandidate(LEGACY_ENTITY);
+ }
+
+ @Test
+ public void testRegisterListener() {
+ DOMEntityOwnershipListenerRegistration mockDOMReg = mock(DOMEntityOwnershipListenerRegistration.class);
+ doNothing().when(mockDOMReg).close();
+ doReturn(mockDOMReg).when(mockDOMService).registerListener(eq(DOM_ENTITY.getType()),
+ any(DOMEntityOwnershipListener.class));
+ EntityOwnershipListener mockListener = mock(EntityOwnershipListener.class);
+ doNothing().when(mockListener).ownershipChanged(any(EntityOwnershipChange.class));
+
+ EntityOwnershipListenerRegistration reg = adapter.registerListener(LEGACY_ENTITY.getType(), mockListener);
+
+ assertNotNull("registerListener returned null", reg);
+ assertEquals("getInstance", mockListener, reg.getInstance());
+ assertEquals("getEntityType", LEGACY_ENTITY.getType(), reg.getEntityType());
+
+ ArgumentCaptor<DOMEntityOwnershipListener> domListenerCaptor = ArgumentCaptor.forClass(DOMEntityOwnershipListener.class);
+ verify(mockDOMService).registerListener(eq(DOM_ENTITY.getType()), domListenerCaptor.capture());
+
+ DOMEntityOwnershipChange domOwnershipChange = new DOMEntityOwnershipChange(DOM_ENTITY,
+ EntityOwnershipChangeState.LOCAL_OWNERSHIP_GRANTED);
+ domListenerCaptor.getValue().ownershipChanged(domOwnershipChange );
+
+ ArgumentCaptor<EntityOwnershipChange> ownershipChangeCaptor = ArgumentCaptor.forClass(EntityOwnershipChange.class);
+ verify(mockListener).ownershipChanged(ownershipChangeCaptor.capture());
+
+ EntityOwnershipChange change = ownershipChangeCaptor.getValue();
+ assertEquals("getEntity", LEGACY_ENTITY, change.getEntity());
+ assertEquals("wasOwner", false, change.wasOwner());
+ assertEquals("isOwner", true, change.isOwner());
+ assertEquals("hasOwner", true, change.hasOwner());
+
+ reg.close();
+ verify(mockDOMReg).close();
+ }
+
+ @Test
+ public void testGetOwnershipState() {
+ testGetOwnershipState(EntityOwnershipState.IS_OWNER, true, true);
+ testGetOwnershipState(EntityOwnershipState.OWNED_BY_OTHER, false, true);
+ testGetOwnershipState(EntityOwnershipState.NO_OWNER, false, false);
+
+ doReturn(Optional.absent()).when(mockDOMService).getOwnershipState(DOM_ENTITY);
+ assertEquals("isPresent", false, adapter.getOwnershipState(LEGACY_ENTITY).isPresent());
+ }
+
+ @Test
+ public void testIsCandidateRegistered() {
+ doReturn(true).when(mockDOMService).isCandidateRegistered(DOM_ENTITY);
+ assertEquals("isCandidateRegistered", true, adapter.isCandidateRegistered(LEGACY_ENTITY));
+ }
+
+ private void testGetOwnershipState(EntityOwnershipState state, boolean expIsOwner, boolean expHasOwner) {
+ doReturn(Optional.of(state)).when(mockDOMService).getOwnershipState(DOM_ENTITY);
+
+ Optional<org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipState> actualState =
+ adapter.getOwnershipState(LEGACY_ENTITY);
+
+ assertEquals("isPresent", true, actualState.isPresent());
+ assertEquals("isOwner", expIsOwner, actualState.get().isOwner());
+ assertEquals("hasOwner", expHasOwner, actualState.get().hasOwner());
+
+ }
+
+}
<groupId>org.opendaylight.controller</groupId>
<artifactId>config-api</artifactId>
</dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>sal-common-api</artifactId>
+ </dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-core-api</artifactId>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<extensions>true</extensions>
+ <configuration>
+ <instructions>
+ <Import-Package>*,com.google.common.base</Import-Package>
+ </instructions>
+ </configuration>
</plugin>
<plugin>
<groupId>org.opendaylight.yangtools</groupId>
--- /dev/null
+/*
+ * Copyright (c) 2016 Brocade Communications 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.controller.config.yang.config.legacy_entity_ownership_service_provider;
+
+import com.google.common.reflect.AbstractInvocationHandler;
+import com.google.common.reflect.Reflection;
+import java.lang.reflect.Method;
+import org.opendaylight.controller.config.api.DependencyResolver;
+import org.opendaylight.controller.config.api.ModuleIdentifier;
+import org.opendaylight.controller.config.api.osgi.WaitingServiceTracker;
+import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipService;
+import org.osgi.framework.BundleContext;
+
+/**
+ * @deprecated Replaced by blueprint wiring
+ */
+@Deprecated
+public class LegacyEntityOwnershipServiceProviderModule extends AbstractLegacyEntityOwnershipServiceProviderModule {
+ private BundleContext bundleContext;
+
+ public LegacyEntityOwnershipServiceProviderModule(ModuleIdentifier identifier, DependencyResolver dependencyResolver) {
+ super(identifier, dependencyResolver);
+ }
+
+ public LegacyEntityOwnershipServiceProviderModule(ModuleIdentifier identifier, DependencyResolver dependencyResolver,
+ LegacyEntityOwnershipServiceProviderModule oldModule, java.lang.AutoCloseable oldInstance) {
+ super(identifier, dependencyResolver, oldModule, oldInstance);
+ }
+
+ @Override
+ public void customValidation() {
+ // add custom validation form module attributes here.
+ }
+
+ @Override
+ public AutoCloseable createInstance() {
+ final WaitingServiceTracker<EntityOwnershipService> tracker = WaitingServiceTracker.create(
+ EntityOwnershipService.class, bundleContext);
+ final EntityOwnershipService service = tracker.waitForService(WaitingServiceTracker.FIVE_MINUTES);
+
+ return Reflection.newProxy(AutoCloseableEntityOwnershipService.class, new AbstractInvocationHandler() {
+ @Override
+ protected Object handleInvocation(Object proxy, Method method, Object[] args) throws Throwable {
+ if (method.getName().equals("close")) {
+ tracker.close();
+ return null;
+ } else {
+ return method.invoke(service, args);
+ }
+ }
+ });
+ }
+
+ public void setBundleContext(final BundleContext bundleContext) {
+ this.bundleContext = bundleContext;
+ }
+
+ private static interface AutoCloseableEntityOwnershipService extends EntityOwnershipService, AutoCloseable {
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2016 Brocade Communications 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.controller.config.yang.config.legacy_entity_ownership_service_provider;
+
+import org.opendaylight.controller.config.api.DependencyResolver;
+import org.opendaylight.controller.config.api.DynamicMBeanWithInstance;
+import org.opendaylight.controller.config.spi.Module;
+import org.osgi.framework.BundleContext;
+
+/**
+ * @deprecated Replaced by blueprint wiring
+ */
+@Deprecated
+public class LegacyEntityOwnershipServiceProviderModuleFactory extends AbstractLegacyEntityOwnershipServiceProviderModuleFactory {
+ @Override
+ public Module createModule(String instanceName, DependencyResolver dependencyResolver, BundleContext bundleContext) {
+ LegacyEntityOwnershipServiceProviderModule module = (LegacyEntityOwnershipServiceProviderModule) super.createModule(instanceName, dependencyResolver, bundleContext);
+ module.setBundleContext(bundleContext);
+ return module;
+ }
+
+ @Override
+ public Module createModule(String instanceName, DependencyResolver dependencyResolver, DynamicMBeanWithInstance old, BundleContext bundleContext) throws Exception {
+ LegacyEntityOwnershipServiceProviderModule module = (LegacyEntityOwnershipServiceProviderModule) super.createModule(instanceName, dependencyResolver, old, bundleContext);
+ module.setBundleContext(bundleContext);
+ return module;
+ }
+}
--- /dev/null
+module opendaylight-legacy-entity-ownership-service-provider {
+ yang-version 1;
+ namespace "urn:opendaylight:params:xml:ns:yang:controller:config:legacy-entity-ownership-service-provider";
+ prefix "legacy-entity-ownership-service";
+
+ import config { prefix config; revision-date 2013-04-05; }
+ import opendaylight-entity-ownership-service { prefix legacy-eos-spi; }
+
+ description "Legacy EntityOwnershipService implementation";
+
+ revision "2016-02-26" {
+ description "Initial revision";
+ }
+
+ identity legacy-entity-ownership-service-provider {
+ base config:module-type;
+ config:provided-service legacy-eos-spi:entity-ownership-service;
+ config:java-name-prefix LegacyEntityOwnershipServiceProvider;
+ }
+
+ augment "/config:modules/config:module/config:configuration" {
+ case legacy-entity-ownership-service-provider {
+ when "/config:modules/config:module/config:type = 'legacy-entity-ownership-service-provider'";
+ }
+ }
+}