From 40683ca75d5669fff6ac5ecdbc217fcccd2b19bf Mon Sep 17 00:00:00 2001 From: Jakub Morvay Date: Mon, 2 Nov 2015 09:00:20 +0100 Subject: [PATCH] Remote yang text source provider implementation Change-Id: Ie2495b1561ff95508b9a31ffa0aad79ddb59a8c5 Signed-off-by: Jakub Morvay --- .../RemoteYangTextSourceProvider.java | 27 +++++++ .../repository/impl/RemoteSchemaProvider.java | 73 ++++++++++++++++++ .../impl/RemoteYangTextSourceImpl.java | 73 ++++++++++++++++++ ...angTextSchemaSourceSerializationProxy.java | 38 +++++++++ .../impl/RemoteSchemaProviderTest.java | 67 ++++++++++++++++ .../RemoteYangTextSourceProviderImplTest.java | 77 +++++++++++++++++++ .../YangTextSourceSerializationProxyTest.java | 61 +++++++++++++++ 7 files changed, 416 insertions(+) create mode 100644 opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/schema/repository/RemoteYangTextSourceProvider.java create mode 100644 opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/schema/repository/impl/RemoteSchemaProvider.java create mode 100644 opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/schema/repository/impl/RemoteYangTextSourceImpl.java create mode 100644 opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/schema/repository/impl/YangTextSchemaSourceSerializationProxy.java create mode 100644 opendaylight/md-sal/sal-clustering-commons/src/test/java/org/opendaylight/controller/cluster/schema/repository/impl/RemoteSchemaProviderTest.java create mode 100644 opendaylight/md-sal/sal-clustering-commons/src/test/java/org/opendaylight/controller/cluster/schema/repository/impl/RemoteYangTextSourceProviderImplTest.java create mode 100644 opendaylight/md-sal/sal-clustering-commons/src/test/java/org/opendaylight/controller/cluster/schema/repository/impl/YangTextSourceSerializationProxyTest.java diff --git a/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/schema/repository/RemoteYangTextSourceProvider.java b/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/schema/repository/RemoteYangTextSourceProvider.java new file mode 100644 index 0000000000..2b5f9699de --- /dev/null +++ b/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/schema/repository/RemoteYangTextSourceProvider.java @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2015 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.controller.cluster.schema.repository; + +import com.google.common.annotations.Beta; +import java.util.Set; +import javax.annotation.Nonnull; +import org.opendaylight.controller.cluster.schema.repository.impl.YangTextSchemaSourceSerializationProxy; +import org.opendaylight.yangtools.yang.model.repo.api.SourceIdentifier; +import scala.concurrent.Future; + +/** + * A remote yang text source provider provides serializable yang text sources. + */ +@Beta +public interface RemoteYangTextSourceProvider { + + Future> getProvidedSources(); + + Future getYangTextSchemaSource(@Nonnull SourceIdentifier identifier); +} diff --git a/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/schema/repository/impl/RemoteSchemaProvider.java b/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/schema/repository/impl/RemoteSchemaProvider.java new file mode 100644 index 0000000000..6d6fed75ff --- /dev/null +++ b/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/schema/repository/impl/RemoteSchemaProvider.java @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2015 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.controller.cluster.schema.repository.impl; + +import akka.dispatch.OnComplete; +import com.google.common.annotations.Beta; +import com.google.common.util.concurrent.CheckedFuture; +import com.google.common.util.concurrent.Futures; +import com.google.common.util.concurrent.SettableFuture; +import org.opendaylight.controller.cluster.schema.repository.RemoteYangTextSourceProvider; +import org.opendaylight.yangtools.util.concurrent.ExceptionMapper; +import org.opendaylight.yangtools.yang.model.repo.api.SchemaSourceException; +import org.opendaylight.yangtools.yang.model.repo.api.SourceIdentifier; +import org.opendaylight.yangtools.yang.model.repo.api.YangTextSchemaSource; +import org.opendaylight.yangtools.yang.model.repo.spi.SchemaSourceProvider; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import scala.concurrent.ExecutionContext; +import scala.concurrent.Future; + +/** + * Provides schema sources from {@link RemoteYangTextSourceProvider}. + */ +@Beta +public class RemoteSchemaProvider implements SchemaSourceProvider { + + private static final Logger LOG = LoggerFactory.getLogger(RemoteSchemaProvider.class); + + private final RemoteYangTextSourceProvider remoteRepo; + private final ExecutionContext executionContext; + + private static final ExceptionMapper MAPPER = new ExceptionMapper( + "schemaDownload", SchemaSourceException.class) { + @Override + protected SchemaSourceException newWithCause(final String s, final Throwable throwable) { + return new SchemaSourceException(s, throwable); + } + }; + + public RemoteSchemaProvider(RemoteYangTextSourceProvider remoteRepo, ExecutionContext executionContext) { + this.remoteRepo = remoteRepo; + this.executionContext = executionContext; + } + + @Override + public CheckedFuture getSource(SourceIdentifier sourceIdentifier) { + LOG.trace("Getting yang schema source for {}", sourceIdentifier.getName()); + + Future result = remoteRepo.getYangTextSchemaSource(sourceIdentifier); + + final SettableFuture res = SettableFuture.create(); + result.onComplete(new OnComplete() { + @Override + public void onComplete(Throwable throwable, YangTextSchemaSourceSerializationProxy yangTextSchemaSourceSerializationProxy) { + if(yangTextSchemaSourceSerializationProxy != null) { + res.set(yangTextSchemaSourceSerializationProxy.getRepresentation()); + } + if(throwable != null) { + res.setException(throwable); + } + } + + }, executionContext); + + return Futures.makeChecked(res, MAPPER); + } +} diff --git a/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/schema/repository/impl/RemoteYangTextSourceImpl.java b/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/schema/repository/impl/RemoteYangTextSourceImpl.java new file mode 100644 index 0000000000..273aa3895b --- /dev/null +++ b/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/schema/repository/impl/RemoteYangTextSourceImpl.java @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2015 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.controller.cluster.schema.repository.impl; + +import com.google.common.annotations.Beta; +import com.google.common.util.concurrent.CheckedFuture; +import com.google.common.util.concurrent.FutureCallback; +import com.google.common.util.concurrent.Futures; +import java.io.IOException; +import java.util.Set; +import org.opendaylight.controller.cluster.schema.repository.RemoteYangTextSourceProvider; +import org.opendaylight.yangtools.yang.model.repo.api.SchemaRepository; +import org.opendaylight.yangtools.yang.model.repo.api.SourceIdentifier; +import org.opendaylight.yangtools.yang.model.repo.api.YangTextSchemaSource; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import scala.concurrent.Future; +import scala.concurrent.Promise; + +/** + * Remote schema repository implementation backed by local schema repository. + */ +@Beta +public class RemoteYangTextSourceImpl implements RemoteYangTextSourceProvider { + private static final Logger LOG = LoggerFactory.getLogger(RemoteYangTextSourceImpl.class); + + private final SchemaRepository repository; + private final Set providedSources; + + public RemoteYangTextSourceImpl(SchemaRepository repository, Set providedSources) { + this.repository = repository; + this.providedSources = providedSources; + } + + @Override + public Future> getProvidedSources() { + return akka.dispatch.Futures.successful(providedSources); + } + + @Override + public Future getYangTextSchemaSource(SourceIdentifier identifier) { + LOG.trace("Sending yang schema source for {}", identifier); + + final Promise promise = akka.dispatch.Futures.promise(); + CheckedFuture future = repository.getSchemaSource(identifier, YangTextSchemaSource.class); + + Futures.addCallback(future, new FutureCallback() { + @Override + public void onSuccess(YangTextSchemaSource result) { + try { + promise.success(new YangTextSchemaSourceSerializationProxy(result)); + } catch (IOException e) { + LOG.warn("Unable to read schema source for {}", result.getIdentifier(), e); + promise.failure(e); + } + } + + @Override + public void onFailure(Throwable t) { + LOG.warn("Unable to retrieve schema source from repository", t); + promise.failure(t); + } + }); + + return promise.future(); + } +} diff --git a/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/schema/repository/impl/YangTextSchemaSourceSerializationProxy.java b/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/schema/repository/impl/YangTextSchemaSourceSerializationProxy.java new file mode 100644 index 0000000000..8a428377e9 --- /dev/null +++ b/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/schema/repository/impl/YangTextSchemaSourceSerializationProxy.java @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2015 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.controller.cluster.schema.repository.impl; + +import com.google.common.annotations.Beta; +import com.google.common.io.ByteSource; +import java.io.IOException; +import java.io.Serializable; +import org.opendaylight.yangtools.yang.model.repo.api.SourceIdentifier; +import org.opendaylight.yangtools.yang.model.repo.api.YangTextSchemaSource; + +/** + * {@link org.opendaylight.yangtools.yang.model.repo.api.YangTextSchemaSource} serialization proxy. + */ +@Beta +public class YangTextSchemaSourceSerializationProxy implements Serializable { + private static long serialVersionUID = 1L; + + private final byte[] schemaSource; + private final String revision; + private final String name; + + public YangTextSchemaSourceSerializationProxy(final YangTextSchemaSource source) throws IOException { + this.revision = source.getIdentifier().getRevision(); + this.name = source.getIdentifier().getName(); + this.schemaSource = source.read(); + } + + public YangTextSchemaSource getRepresentation() { + return YangTextSchemaSource.delegateForByteSource(new SourceIdentifier(name, revision), ByteSource.wrap(schemaSource)); + } +} diff --git a/opendaylight/md-sal/sal-clustering-commons/src/test/java/org/opendaylight/controller/cluster/schema/repository/impl/RemoteSchemaProviderTest.java b/opendaylight/md-sal/sal-clustering-commons/src/test/java/org/opendaylight/controller/cluster/schema/repository/impl/RemoteSchemaProviderTest.java new file mode 100644 index 0000000000..b74f9d7695 --- /dev/null +++ b/opendaylight/md-sal/sal-clustering-commons/src/test/java/org/opendaylight/controller/cluster/schema/repository/impl/RemoteSchemaProviderTest.java @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2015 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.controller.cluster.schema.repository.impl; + +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import akka.dispatch.ExecutionContexts; +import akka.dispatch.Futures; +import com.google.common.io.ByteSource; +import com.google.common.util.concurrent.CheckedFuture; +import com.google.common.util.concurrent.MoreExecutors; +import java.io.IOException; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mockito; +import org.opendaylight.controller.cluster.schema.repository.RemoteYangTextSourceProvider; +import org.opendaylight.yangtools.yang.model.repo.api.SchemaSourceException; +import org.opendaylight.yangtools.yang.model.repo.api.SourceIdentifier; +import org.opendaylight.yangtools.yang.model.repo.api.YangTextSchemaSource; + +public class RemoteSchemaProviderTest { + + private static final SourceIdentifier ID = new SourceIdentifier("Test", "2015-10-30"); + + private RemoteSchemaProvider remoteSchemaProvider; + private RemoteYangTextSourceProvider mockedRemoteSchemaRepository; + + @Before + public void setUp() { + mockedRemoteSchemaRepository = Mockito.mock(RemoteYangTextSourceProvider.class); + ExecutionContexts.fromExecutorService(MoreExecutors.newDirectExecutorService()); + remoteSchemaProvider = new RemoteSchemaProvider(mockedRemoteSchemaRepository, + ExecutionContexts.fromExecutorService(MoreExecutors.newDirectExecutorService())); + } + + @Test + public void getExistingYangTextSchemaSource() throws IOException, SchemaSourceException { + String source = "Test"; + YangTextSchemaSource schemaSource = YangTextSchemaSource.delegateForByteSource(ID, ByteSource.wrap(source.getBytes())); + YangTextSchemaSourceSerializationProxy sourceProxy = new YangTextSchemaSourceSerializationProxy(schemaSource); + Mockito.when(mockedRemoteSchemaRepository.getYangTextSchemaSource(ID)).thenReturn(Futures.successful(sourceProxy)); + + YangTextSchemaSource providedSource = remoteSchemaProvider.getSource(ID).checkedGet(); + assertEquals(providedSource.getIdentifier(), ID); + assertArrayEquals(providedSource.read(), schemaSource.read()); + } + + @Test(expected = SchemaSourceException.class) + public void getNonExistingSchemaSource() throws Exception { + Futures.failed(new Exception("halo")); + + Mockito.when(mockedRemoteSchemaRepository.getYangTextSchemaSource(ID)).thenReturn( + Futures.failed(new SchemaSourceException("Source not provided"))); + + CheckedFuture sourceFuture = remoteSchemaProvider.getSource(ID); + assertTrue(sourceFuture.isDone()); + sourceFuture.checkedGet(); + } +} \ No newline at end of file diff --git a/opendaylight/md-sal/sal-clustering-commons/src/test/java/org/opendaylight/controller/cluster/schema/repository/impl/RemoteYangTextSourceProviderImplTest.java b/opendaylight/md-sal/sal-clustering-commons/src/test/java/org/opendaylight/controller/cluster/schema/repository/impl/RemoteYangTextSourceProviderImplTest.java new file mode 100644 index 0000000000..8f70cbbf7e --- /dev/null +++ b/opendaylight/md-sal/sal-clustering-commons/src/test/java/org/opendaylight/controller/cluster/schema/repository/impl/RemoteYangTextSourceProviderImplTest.java @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2015 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.controller.cluster.schema.repository.impl; + +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import com.google.common.io.ByteSource; +import com.google.common.util.concurrent.Futures; +import java.util.Collections; +import java.util.Set; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mockito; +import org.opendaylight.yangtools.yang.model.repo.api.SchemaRepository; +import org.opendaylight.yangtools.yang.model.repo.api.SchemaSourceException; +import org.opendaylight.yangtools.yang.model.repo.api.SourceIdentifier; +import org.opendaylight.yangtools.yang.model.repo.api.YangTextSchemaSource; +import scala.concurrent.Await; +import scala.concurrent.Future; +import scala.concurrent.duration.Duration; + +public class RemoteYangTextSourceProviderImplTest { + + private static final SourceIdentifier ID = new SourceIdentifier("Test", "2015-10-30"); + + private RemoteYangTextSourceImpl remoteRepository; + private SchemaRepository mockedLocalRepository; + private Set providedSources = Collections.singleton(ID); + + @Before + public void setUp() { + mockedLocalRepository = Mockito.mock(SchemaRepository.class); + + remoteRepository = new RemoteYangTextSourceImpl(mockedLocalRepository, providedSources); + } + + @Test + public void testGetExistingYangTextSchemaSource() throws Exception { + String source = "Test source."; + YangTextSchemaSource schemaSource = YangTextSchemaSource.delegateForByteSource(ID, ByteSource.wrap(source.getBytes())); + Mockito.when(mockedLocalRepository.getSchemaSource(ID, YangTextSchemaSource.class)).thenReturn( + Futures.immediateCheckedFuture(schemaSource)); + + Future retrievedSourceFuture = remoteRepository.getYangTextSchemaSource(ID); + assertTrue(retrievedSourceFuture.isCompleted()); + YangTextSchemaSource resultSchemaSource = Await.result(retrievedSourceFuture, Duration.Zero()).getRepresentation(); + assertEquals(resultSchemaSource.getIdentifier(), schemaSource.getIdentifier()); + assertArrayEquals(resultSchemaSource.read(), schemaSource.read()); + } + + @Test(expected = SchemaSourceException.class) + public void testGetNonExistentYangTextSchemaSource() throws Exception { + Mockito.when(mockedLocalRepository.getSchemaSource(ID, YangTextSchemaSource.class)).thenReturn( + Futures.immediateFailedCheckedFuture( + new SchemaSourceException("Source is not provided"))); + + + Future retrievedSourceFuture = remoteRepository.getYangTextSchemaSource(ID); + assertTrue(retrievedSourceFuture.isCompleted()); + Await.result(retrievedSourceFuture, Duration.Zero()); + } + + @Test + public void testGetProvidedSources() throws Exception { + Set remoteProvidedSources = Await.result(remoteRepository.getProvidedSources(), Duration.Zero()); + assertEquals(providedSources, remoteProvidedSources); + } + +} diff --git a/opendaylight/md-sal/sal-clustering-commons/src/test/java/org/opendaylight/controller/cluster/schema/repository/impl/YangTextSourceSerializationProxyTest.java b/opendaylight/md-sal/sal-clustering-commons/src/test/java/org/opendaylight/controller/cluster/schema/repository/impl/YangTextSourceSerializationProxyTest.java new file mode 100644 index 0000000000..82b48a0bcd --- /dev/null +++ b/opendaylight/md-sal/sal-clustering-commons/src/test/java/org/opendaylight/controller/cluster/schema/repository/impl/YangTextSourceSerializationProxyTest.java @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2015 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.controller.cluster.schema.repository.impl; + +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; + +import com.google.common.base.Charsets; +import com.google.common.io.ByteSource; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import org.junit.Before; +import org.junit.Test; +import org.opendaylight.yangtools.yang.model.repo.api.SourceIdentifier; +import org.opendaylight.yangtools.yang.model.repo.api.YangTextSchemaSource; + +public class YangTextSourceSerializationProxyTest { + + private YangTextSchemaSource schemaSource; + + @Before + public void setUp() { + String source = "Test source."; + schemaSource = YangTextSchemaSource.delegateForByteSource( + new SourceIdentifier("test", "2015-10-30"), ByteSource.wrap(source.getBytes(Charsets.UTF_8))); + } + + + @Test + public void serializeAndDesrializeProxy() throws ClassNotFoundException, IOException { + YangTextSchemaSourceSerializationProxy proxy = new YangTextSchemaSourceSerializationProxy(schemaSource); + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + ObjectOutputStream oos = new ObjectOutputStream(bos); + + oos.writeObject(proxy); + + ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(bos.toByteArray())); + + YangTextSchemaSourceSerializationProxy deserializedProxy = (YangTextSchemaSourceSerializationProxy) ois.readObject(); + + assertEquals(deserializedProxy.getRepresentation().getIdentifier(), proxy.getRepresentation().getIdentifier()); + assertArrayEquals(deserializedProxy.getRepresentation().read(), proxy.getRepresentation().read()); + } + + @Test + public void testProxyEqualsBackingYangTextSource() throws IOException { + YangTextSchemaSourceSerializationProxy serializationProxy = new YangTextSchemaSourceSerializationProxy(schemaSource); + + assertEquals(serializationProxy.getRepresentation().getIdentifier(), schemaSource.getIdentifier()); + assertArrayEquals(serializationProxy.getRepresentation().read(), schemaSource.read()); + } +} -- 2.36.6