--- /dev/null
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>sal-parent</artifactId>
+ <version>1.0-SNAPSHOT</version>
+ </parent>
+ <artifactId>sal-binding-api</artifactId>
+ <packaging>bundle</packaging>
+ <scm>
+ <connection>scm:git:ssh://git.opendaylight.org:29418/controller.git</connection>
+ <developerConnection>scm:git:ssh://git.opendaylight.org:29418/controller.git</developerConnection>
+ <url>https://wiki.opendaylight.org/view/OpenDaylight_Controller:MD-SAL</url>
+ </scm>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>yang-common</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>yang-binding</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>sal-common</artifactId>
+ <version>1.0-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>org.osgi</groupId>
+ <artifactId>org.osgi.core</artifactId>
+ <version>${osgi.core.version}</version>
+ </dependency>
+ </dependencies>
+</project>
--- /dev/null
+package org.opendaylight.controller.sal.binding.api;
+
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+
+public abstract class AbstractBindingAwareConsumer implements BindingAwareConsumer,BundleActivator {
+
+ @Override
+ public final void start(BundleContext context) throws Exception {
+ ServiceReference<BindingAwareBroker> brokerRef = context.getServiceReference(BindingAwareBroker.class);
+ BindingAwareBroker broker = context.getService(brokerRef);
+ broker.registerConsumer(this, context);
+ startImpl(context);
+ //context.ungetService(brokerRef);
+ }
+
+ @Deprecated
+ abstract protected void startImpl(BundleContext context);
+
+ @Override
+ public final void stop(BundleContext context) throws Exception {
+ // TODO Auto-generated method stub
+
+ }
+
+}
--- /dev/null
+package org.opendaylight.controller.sal.binding.api;
+
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+
+public abstract class AbstractBindingAwareProvider implements BindingAwareProvider, BundleActivator {
+
+ @Override
+ public final void start(BundleContext context) throws Exception {
+ ServiceReference<BindingAwareBroker> brokerRef = context.getServiceReference(BindingAwareBroker.class);
+ BindingAwareBroker broker = context.getService(brokerRef);
+ broker.registerProvider(this, context);
+ startImpl(context);
+ }
+
+ @Deprecated
+ abstract protected void startImpl(BundleContext context);
+
+ @Override
+ public final void stop(BundleContext context) throws Exception {
+
+
+ }
+}
--- /dev/null
+/*
+ * 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
+ */
+package org.opendaylight.controller.sal.binding.api;
+
+import org.opendaylight.controller.sal.binding.api.data.DataBrokerService;
+import org.opendaylight.controller.sal.binding.api.data.DataProviderService;
+import org.opendaylight.yangtools.yang.binding.RpcService;
+import org.osgi.framework.BundleContext;
+
+/**
+ * Binding-aware core of the SAL layer responsible for wiring the SAL consumers.
+ *
+ * The responsibility of the broker is to maintain registration of SAL
+ * functionality {@link Consumer}s and {@link Provider}s, store provider and
+ * consumer specific context and functionality registration via
+ * {@link ConsumerContext} and provide access to infrastructure services, which
+ * removes direct dependencies between providers and consumers.
+ *
+ * The Binding-aware broker is also responsible for translation from Java
+ * classes modeling the functionality and data to binding-indpenedent form which
+ * is used in SAL Core.
+ *
+ *
+ * <h3>Infrastructure services</h3> Some examples of infrastructure services:
+ *
+ * <ul>
+ * <li>YANG Module service - see {@link ConsumerContext#getRpcService(Class)},
+ * {@link ProviderContext}
+ * <li>Notification Service - see {@link NotificationService} and
+ * {@link NotificationProviderService}
+ * <li>Functionality and Data model
+ * <li>Data Store access and modification - see {@link DataBrokerService} and
+ * {@link DataProviderService}
+ * </ul>
+ *
+ * The services are exposed via session.
+ *
+ * <h3>Session-based access</h3>
+ *
+ * The providers and consumers needs to register in order to use the
+ * binding-independent SAL layer and to expose functionality via SAL layer.
+ *
+ * For more information about session-based access see {@link ConsumerContext}
+ * and {@link ProviderContext}
+ *
+ *
+ *
+ */
+public interface BindingAwareBroker {
+ /**
+ * Registers the {@link BindingAwareConsumer}, which will use the SAL layer.
+ *
+ * <p>
+ * Note that consumer could register additional functionality at later point
+ * by using service and functionality specific APIs.
+ *
+ * <p>
+ * The consumer is required to use returned session for all communication
+ * with broker or one of the broker services. The session is announced to
+ * the consumer by invoking
+ * {@link Consumer#onSessionInitiated(ConsumerContext)}.
+ *
+ * @param cons
+ * Consumer to be registered.
+ * @return a session specific to consumer registration
+ * @throws IllegalArgumentException
+ * If the consumer is <code>null</code>.
+ * @throws IllegalStateException
+ * If the consumer is already registered.
+ */
+ ConsumerContext registerConsumer(BindingAwareConsumer consumer, BundleContext ctx);
+
+ /**
+ * Registers the {@link BindingAwareProvider}, which will use the SAL layer.
+ *
+ * <p>
+ * During the registration, the broker obtains the initial functionality
+ * from consumer, using the
+ * {@link BindingAwareProvider#getImplementations()}, and register that
+ * functionality into system and concrete infrastructure services.
+ *
+ * <p>
+ * Note that provider could register additional functionality at later point
+ * by using service and functionality specific APIs.
+ *
+ * <p>
+ * The consumer is <b>required to use</b> returned session for all
+ * communication with broker or one of the broker services. The session is
+ * announced to the consumer by invoking
+ * {@link BindingAwareProvider#onSessionInitiated(ProviderContext)}.
+ *
+ *
+ * @param prov
+ * Provider to be registered.
+ * @return a session unique to the provider registration.
+ * @throws IllegalArgumentException
+ * If the provider is <code>null</code>.
+ * @throws IllegalStateException
+ * If the consumer is already registered.
+ */
+ ProviderContext registerProvider(BindingAwareProvider provider, BundleContext ctx);
+
+ /**
+ * {@link BindingAwareConsumer} specific access to the SAL functionality.
+ *
+ * <p>
+ * ConsumerSession is {@link BindingAwareConsumer}-specific access to the
+ * SAL functionality and infrastructure services.
+ *
+ * <p>
+ * The session serves to store SAL context (e.g. registration of
+ * functionality) for the consumer and provides access to the SAL
+ * infrastructure services and other functionality provided by
+ * {@link Provider}s.
+ *
+ *
+ *
+ */
+ public interface ConsumerContext {
+
+ /**
+ * Returns a session specific instance (implementation) of requested
+ * binding-aware infrastructural service
+ *
+ * @param service
+ * Broker service
+ * @return Session specific implementation of service
+ */
+ <T extends BindingAwareService> T getSALService(Class<T> service);
+
+ /**
+ * Returns a session specific instance (implementation) of requested
+ * YANG module implentation / service provided by consumer.
+ *
+ * @param service
+ * Broker service
+ * @return Session specific implementation of service
+ */
+ <T extends RpcService> T getRpcService(Class<T> module);
+ }
+
+ /**
+ * {@link BindingAwareProvider} specific access to the SAL functionality.
+ *
+ * <p>
+ * ProviderSession is {@link BindingAwareProvider}-specific access to the
+ * SAL functionality and infrastructure services, which also allows for
+ * exposing the provider's functionality to the other
+ * {@link BindingAwareConsumer}s.
+ *
+ * <p>
+ * The session serves to store SAL context (e.g. registration of
+ * functionality) for the providers and exposes access to the SAL
+ * infrastructure services, dynamic functionality registration and any other
+ * functionality provided by other {@link BindingAwareConsumer}s.
+ *
+ */
+ public interface ProviderContext extends ConsumerContext {
+
+ <T extends RpcService> RpcServiceRegistration<T> addRpcImplementation(Class<T> type, T implementation);
+ }
+
+ public interface RpcServiceRegistration<T extends RpcService> {
+
+ T getService();
+
+ void unregister();
+ }
+}
--- /dev/null
+/*
+ * 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
+ */
+package org.opendaylight.controller.sal.binding.api;
+
+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 faciliates 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.
+ */
+ void onSessionInitialized(ConsumerContext session);
+
+}
--- /dev/null
+/*
+ * 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
+ */
+package org.opendaylight.controller.sal.binding.api;
+
+import java.util.Collection;
+
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ConsumerContext;
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext;
+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 {
+
+ void onSessionInitialized(ConsumerContext session);
+
+ /**
+ * 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 {
+
+ }
+
+ void onSessionInitiated(ProviderContext session);
+
+}
--- /dev/null
+/*
+ * 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
+ */
+package org.opendaylight.controller.sal.binding.api;
+
+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
+ * {@link BindingAwareProvider} exposes the necessary supporting functionality
+ * to implement specific functionality of YANG and to reuse it in the
+ * development of {@link BindingAwareConsumer}s and {@link BindingAwareProvider}
+ * s.
+ *
+ *
+ *
+ */
+public interface BindingAwareService {
+
+}
--- /dev/null
+package org.opendaylight.controller.sal.binding.api;
+
+public interface NotificationListener<T> {
+
+ void onNotification(T notification);
+}
--- /dev/null
+/*
+ * 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
+ */
+package org.opendaylight.controller.sal.binding.api;
+
+import org.opendaylight.yangtools.yang.binding.Notification;
+
+public interface NotificationProviderService extends NotificationService {
+
+ void notify(Notification notification);
+}
--- /dev/null
+/*
+ * 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
+ */
+package org.opendaylight.controller.sal.binding.api;
+
+import org.opendaylight.yangtools.yang.binding.Notification;
+
+public interface NotificationService extends BindingAwareService {
+
+ <T extends Notification> void addNotificationListener(Class<T> notificationType, NotificationListener<T> listener);
+
+ <T extends Notification> void removeNotificationListener(Class<T> notificationType, NotificationListener<T> listener);
+}
--- /dev/null
+/*
+ * 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
+ */
+package org.opendaylight.controller.sal.binding.api.data;
+
+import java.util.concurrent.Future;
+
+import org.opendaylight.controller.sal.binding.api.BindingAwareService;
+import org.opendaylight.controller.sal.common.DataStoreIdentifier;
+import org.opendaylight.yangtools.yang.binding.DataRoot;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+
+/**
+ * DataBrokerService provides unified access to the data stores available in the
+ * system.
+ *
+ *
+ * @see DataProviderService
+ */
+public interface DataBrokerService extends BindingAwareService {
+
+ /**
+ * Returns a data from specified Data Store.
+ *
+ * Returns all the data visible to the consumer from specified Data Store.
+ *
+ * @param <T>
+ * Interface generated from YANG module representing root of data
+ * @param store
+ * Identifier of the store, from which will be data retrieved
+ * @return data visible to the consumer
+ */
+ <T extends DataRoot> T getData(DataStoreIdentifier store, Class<T> rootType);
+
+ /**
+ * Returns a filtered subset of data from specified Data Store.
+ *
+ * <p>
+ * The filter is modeled as an hierarchy of Java TOs starting with
+ * implementation of {@link DataRoot} representing data root. The semantics
+ * of the filter tree is the same as filter semantics defined in the NETCONF
+ * protocol for rpc operations <code>get</code> and <code>get-config</code>
+ * in Section 6 of RFC6241.
+ *
+ *
+ * @see http://tools.ietf.org/html/rfc6241#section-6
+ * @param <T>
+ * Interface generated from YANG module representing root of data
+ * @param store
+ * Identifier of the store, from which will be data retrieved
+ * @param filter
+ * Data tree filter similar to the NETCONF filter
+ * @return
+ */
+ <T extends DataRoot> T getData(DataStoreIdentifier store, T filter);
+
+ /**
+ * Returns a candidate data which are not yet commited.
+ *
+ *
+ * @param <T>
+ * Interface generated from YANG module representing root of data
+ * @param store
+ * Identifier of the store, from which will be data retrieved
+ * @return
+ */
+ <T extends DataRoot> T getCandidateData(DataStoreIdentifier store, Class<T> rootType);
+
+ /**
+ * Returns a filtered subset of candidate data from specified Data Store.
+ *
+ * <p>
+ * The filter is modeled as an hierarchy of {@link Node} starting with
+ * {@link CompositeNode} representing data root. The semantics of the filter
+ * tree is the same as filter semantics defined in the NETCONF protocol for
+ * rpc operations <code>get</code> and <code>get-config</code> in Section 6
+ * of RFC6241.
+ *
+ *
+ * @see http://tools.ietf.org/html/rfc6241#section-6
+ * @param <T>
+ * Interface generated from YANG module representing root of data
+ * @param store
+ * Identifier of the store, from which will be data retrieved
+ * @param filter
+ * A filter data root
+ * @return
+ */
+ <T extends DataRoot> T getCandidateData(DataStoreIdentifier store, T filter);
+
+ /**
+ *
+ * @param <T>
+ * Interface generated from YANG module representing root of data
+ * @param store
+ * Identifier of the store, in which will be the candidate data
+ * modified
+ * @param changeSet
+ * Modification of data tree.
+ * @return Result object containing the modified data tree if the operation
+ * was successful, otherwise list of the encountered errors.
+ */
+ RpcResult<DataRoot> editCandidateData(DataStoreIdentifier store, DataRoot changeSet);
+
+ /**
+ * Initiates a two-phase commit of candidate data.
+ *
+ * <p>
+ * The {@link Consumer} could initiate a commit of candidate data
+ *
+ * <p>
+ * The successful commit changes the state of the system and may affect
+ * several components.
+ *
+ * <p>
+ * The effects of successful commit of data are described in the
+ * specifications and YANG models describing the {@link Provider} components
+ * of controller. It is assumed that {@link Consumer} has an understanding
+ * of this changes.
+ *
+ *
+ * @see DataCommitHandler for further information how two-phase commit is
+ * processed.
+ * @param store
+ * Identifier of the store, where commit should occur.
+ * @return Result of the commit, containing success information or list of
+ * encountered errors, if commit was not successful.
+ */
+ Future<RpcResult<Void>> commit(DataStoreIdentifier store);
+}
--- /dev/null
+/*
+ * 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
+ */
+package org.opendaylight.controller.sal.binding.api.data;
+
+import java.util.Set;
+
+import org.opendaylight.controller.sal.binding.api.BindingAwareProvider;
+import org.opendaylight.controller.sal.binding.api.BindingAwareProvider.ProviderFunctionality;
+import org.opendaylight.controller.sal.common.DataStoreIdentifier;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+
+/**
+ * Two phase commit handler (cohort) of the two-phase commit protocol of data.
+ *
+ * <p>
+ * The provider should expose the implementation of DataCommitHandler if it's
+ * functionality depends on any subset of data stored in data repositories, in
+ * order to participate in {@link DataBrokerService#commit(DataStoreIdentifier)
+ * operation.
+ *
+ * <p>
+ * Operations of two-phase commit handlers should not change data in data store,
+ * this is responsibility of the coordinator (broker or some component of the
+ * broker).
+ *
+ * The commit handlers are responsible for changing the internal state of the
+ * provider to reflect the commited changes in data.
+ *
+ * <h3>Two-phase commit</h3>
+ *
+ * <h4>Commit Request Phase</h4>
+ *
+ * <ol>
+ * <li> <code>Consumer</code> edits data by invocation of
+ * <code>DataBrokerService.editCandidateData(DataStoreIdentifier, DataRoot)</code>
+ * <li> <code>Consumer</code> starts a commit by invoking
+ * <code>DataBrokerService.commit(DataStoreIdentifier)</code>
+ * <li> <code>Broker</code> retrieves a list of all registered
+ * <code>DataCommitHandlers</code>
+ * <li>For each <code>DataCommitHandler</code>
+ * <ol>
+ * <li><code>Broker</code> invokes a
+ * <code>DataCommitHandler.requestCommit(DataStoreIdentifier)</code> operation.
+ * <li><code>DataCommitHandler</code> returns a <code>RpcResult</code> with
+ * <code>CommitTransaction</code>
+ * <li>If the result was successful, broker adds <code>CommitTransaction</code>
+ * to the list of opened transactions. If not, brokers stops a commit request
+ * phase and starts a rollback phase.
+ * </ol>
+ * <li><code>Broker</code> starts a commit finish phase
+ * </ol>
+ *
+ * <h4>Commit Finish Phase</h4>
+ *
+ * <ol>
+ * <li>For each <code>CommitTransaction</code> from Commit Request phase
+ * <ol>
+ * <li><code>Broker</code> broker invokes a
+ * <code>CommitTransaction.finish()</code>
+ * <li>The provider finishes a commit (applies the change) and returns an
+ * <code>RpcResult</code>.
+ * </ol>
+ * <li>
+ * <ul>
+ * <li>If all returned results means successful, the brokers end two-phase
+ * commit by returning a success commit result to the Consumer.
+ * <li>If error occured, the broker starts a commit rollback phase.
+ * </ul>
+ * </ol>
+ *
+ * <h4>Commit Rollback Phase</h4>
+ * <li>For each <code>CommitTransaction</code> from Commit Request phase
+ * <ol>
+ * <li><code>Broker</code>
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ * broker invokes a {@link CommitTransaction#finish()}
+ * <li>The provider rollbacks a commit and returns an {@link RpcResult} of
+ * rollback. </ol>
+ * <li>Broker returns a error result to the consumer.
+ *
+ *
+ * <h3>Registration of functionality</h3>
+ * The registration could be done by :
+ * <ul>
+ * <li>returning an instance of implementation in the return value of
+ * {@link Provider#getProviderFunctionality()}
+ * <li>passing an instance of implementation and {@link DataStoreIdentifier} of
+ * rpc as arguments to the
+ * {@link DataProviderService#addCommitHandler(DataStoreIdentifier, DataCommitHandler)}
+ * </ul>
+ *
+ *
+ *
+ */
+public interface DataCommitHandler extends 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 commit handler. This set is used, when
+ * {@link Provider} is registered to the SAL, to register and expose the
+ * commit handler functionality to affected data stores.
+ *
+ * @return Set of Data Store identifiers
+ */
+ Set<DataStoreIdentifier> getSupportedDataStores();
+
+ /**
+ * The provider (commit handler) starts a commit transaction.
+ *
+ * <p>
+ * The commit handler (provider) prepares an commit scenario, rollback
+ * scenario and validates data.
+ *
+ * <p>
+ * If the provider is aware that at this point the commit would not be
+ * successful, the transaction is not created, but list of errors which
+ * prevented the start of transaction are returned.
+ *
+ * @param store
+ * @return Transaction object representing this commit, errors otherwise.
+ */
+ RpcResult<CommitTransaction> requestCommit(DataStoreIdentifier store);
+
+ public interface CommitTransaction {
+ /**
+ *
+ * @return Data store affected by the transaction
+ */
+ DataStoreIdentifier getDataStore();
+
+ /**
+ * Returns the handler associated with this transaction.
+ *
+ * @return Handler
+ */
+ DataCommitHandler getHandler();
+
+ /**
+ *
+ * Finishes a commit.
+ *
+ * The provider (commit handler) should apply all changes to its state
+ * which are a result of data change-
+ *
+ * @return
+ */
+ RpcResult<Void> finish() throws IllegalStateException;
+
+ /**
+ * Rollbacks a commit.
+ *
+ * @return
+ * @throws IllegalStateException
+ * If the method is invoked after {@link #finish()}
+ */
+ RpcResult<Void> rollback() throws IllegalStateException;
+ }
+
+}
--- /dev/null
+/*
+ * 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
+ */
+package org.opendaylight.controller.sal.binding.api.data;
+
+import org.opendaylight.controller.sal.common.DataStoreIdentifier;
+
+public interface DataProviderService extends DataBrokerService {
+
+ /**
+ * Adds {@link DataValidator} for specified Data Store
+ *
+ * @param store
+ * Data Store
+ * @param validator
+ * Validator
+ */
+ public void addValidator(DataStoreIdentifier store, DataValidator validator);
+
+ /**
+ * Removes {@link DataValidator} from specified Data Store
+ *
+ * @param store
+ * @param validator
+ * Validator
+ */
+ public void removeValidator(DataStoreIdentifier store, DataValidator validator);
+
+ /**
+ * Adds {@link DataCommitHandler} for specified data store
+ *
+ * @param store
+ * @param provider
+ */
+ void addCommitHandler(DataStoreIdentifier store, DataCommitHandler provider);
+
+ /**
+ * Removes {@link DataCommitHandler} from specified data store
+ *
+ * @param store
+ * @param provider
+ */
+ void removeCommitHandler(DataStoreIdentifier store, DataCommitHandler provider);
+
+ /**
+ * Adds {@link DataRefresher} for specified data store
+ *
+ * @param store
+ * @param refresher
+ */
+ void addRefresher(DataStoreIdentifier store, DataRefresher refresher);
+
+ /**
+ * Removes {@link DataRefresher} from specified data store
+ *
+ * @param store
+ * @param refresher
+ */
+ void removeRefresher(DataStoreIdentifier store, DataRefresher refresher);
+
+}
--- /dev/null
+/*
+ * 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
+ */
+package org.opendaylight.controller.sal.binding.api.data;
+
+import org.opendaylight.controller.sal.binding.api.BindingAwareProvider;
+import org.opendaylight.controller.sal.binding.api.BindingAwareProvider.ProviderFunctionality;
+
+/**
+ * Trigger for refreshing of the data exposed by the {@link Provider}
+ *
+ *
+ *
+ */
+public interface DataRefresher extends BindingAwareProvider.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.
+ */
+ void refreshData();
+}
\ No newline at end of file
--- /dev/null
+/*
+ * 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
+ */
+package org.opendaylight.controller.sal.binding.api.data;
+
+import org.opendaylight.controller.sal.binding.api.BindingAwareProvider;
+import org.opendaylight.controller.sal.binding.api.BindingAwareProvider.ProviderFunctionality;
+import org.opendaylight.yangtools.yang.binding.DataRoot;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+
+public interface DataValidator extends ProviderFunctionality {
+
+ RpcResult<Void> validate(DataRoot data);
+}
--- /dev/null
+package org.opendaylight.controller.sal.binding.api.data;
+
+import java.util.Set;
+
+import org.opendaylight.controller.sal.common.DataStoreIdentifier;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.DataRoot;
+
+public interface RuntimeDataProvider {
+
+ Set<DataStoreIdentifier> getSupportedStores();
+
+
+ Set<Class<? extends DataRoot>> getProvidedDataRoots();
+
+
+ /**
+ * Returns a data from specified Data Store.
+ *
+ * Returns all the data visible to the consumer from specified Data Store.
+ *
+ * @param <T>
+ * Interface generated from YANG module representing root of data
+ * @param store
+ * Identifier of the store, from which will be data retrieved
+ * @return data visible to the consumer
+ */
+ <T extends DataRoot> T getData(DataStoreIdentifier store, Class<T> rootType);
+
+ /**
+ * Returns a filtered subset of data from specified Data Store.
+ *
+ * <p>
+ * The filter is modeled as an hierarchy of Java TOs starting with
+ * implementation of {@link DataRoot} representing data root. The semantics
+ * of the filter tree is the same as filter semantics defined in the NETCONF
+ * protocol for rpc operations <code>get</code> and <code>get-config</code>
+ * in Section 6 of RFC6241.
+ *
+ *
+ * @see http://tools.ietf.org/html/rfc6241#section-6
+ * @param <T>
+ * Interface generated from YANG module representing root of data
+ * @param store
+ * Identifier of the store, from which will be data retrieved
+ * @param filter
+ * Data tree filter similar to the NETCONF filter
+ * @return
+ */
+ <T extends DataRoot> T getData(DataStoreIdentifier store, T filter);
+}
--- /dev/null
+/*
+ * 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
+ */
+package org.opendaylight.controller.sal.binding.api;
+
--- /dev/null
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>sal-parent</artifactId>
+ <version>1.0-SNAPSHOT</version>
+ </parent>
+ <artifactId>sal-binding-broker-impl</artifactId>
+ <packaging>bundle</packaging>
+ <scm>
+ <connection>scm:git:ssh://git.opendaylight.org:29418/controller.git</connection>
+ <developerConnection>scm:git:ssh://git.opendaylight.org:29418/controller.git</developerConnection>
+ <url>https://wiki.opendaylight.org/view/OpenDaylight_Controller:MD-SAL</url>
+ </scm>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <extensions>true</extensions>
+ <configuration>
+ <instructions>
+ <Bundle-Name>${project.groupId}.${project.artifactId}</Bundle-Name>
+ <Bundle-Activator>org.opendaylight.controller.sal.binding.impl.BrokerActivator</Bundle-Activator>
+ <Private-Package>
+ org.opendaylight.controller.sal.binding.impl,
+ org.opendaylight.controller.sal.binding.impl.*,
+ org.opendaylight.controller.sal.binding.codegen.*,
+ org.eclipse.xtend2.lib,
+ org.eclipse.xtend.lib,
+ org.eclipse.xtext.xbase.*
+ </Private-Package>
+ </instructions>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.eclipse.xtend</groupId>
+ <artifactId>xtend-maven-plugin</artifactId>
+ <version>2.4.2</version>
+ <executions>
+ <execution>
+ <goals>
+ <goal>compile</goal>
+ </goals>
+ <configuration>
+ <outputDirectory>${basedir}/src/main/xtend-gen</outputDirectory>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <artifactId>maven-clean-plugin</artifactId>
+ <version>2.4.1</version>
+ <configuration>
+ <filesets>
+ <fileset>
+ <directory>${basedir}/src/main/xtend-gen</directory>
+ <includes>
+ <include>**</include>
+ </includes>
+ </fileset>
+ </filesets>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>sal-common-util</artifactId>
+ <version>1.0-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>sal-binding-api</artifactId>
+ <version>1.0-SNAPSHOT</version>
+ </dependency>
+ <!-- >dependency> <groupId>org.opendaylight.controller</groupId>
+ <artifactId>sal-core-api</artifactId> <version>1.0-SNAPSHOT</version> </dependency -->
+
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.osgi</groupId>
+ <artifactId>org.osgi.core</artifactId>
+ <version>${osgi.core.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>com.google.guava</groupId>
+ <artifactId>guava</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.reflections</groupId>
+ <artifactId>reflections</artifactId>
+ <version>0.9.9-RC1</version>
+ </dependency>
+ <dependency>
+ <groupId>org.javassist</groupId>
+ <artifactId>javassist</artifactId>
+ <version>3.17.1-GA</version>
+ </dependency>
+ <dependency>
+ <groupId>org.eclipse.xtend</groupId>
+ <artifactId>org.eclipse.xtend.lib</artifactId>
+ <version>2.4.2</version>
+ </dependency>
+ <dependency>
+ <groupId>org.mockito</groupId>
+ <artifactId>mockito-all</artifactId>
+ </dependency>
+ </dependencies>
+</project>
--- /dev/null
+/xtend-gen
--- /dev/null
+/*
+ * 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
+ */
+package org.opendaylight.controller.sal.binding.codegen
+
+import java.util.Map
+
+import org.opendaylight.yangtools.yang.binding.BaseIdentity
+import org.opendaylight.yangtools.yang.binding.RpcService
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier
+
+import static extension org.opendaylight.controller.sal.binding.codegen.RuntimeCodeSpecification.*
+
+class RuntimeCodeHelper {
+ /**
+ * Helper method to return delegate from ManagedDirectedProxy with use of reflection.
+ *
+ * Note: This method uses reflection, but access to delegate field should be
+ * avoided and called only if neccessary.
+ *
+ */
+ public static def <T extends RpcService> getDelegate(RpcService proxy) {
+ val field = proxy.class.getField(DELEGATE_FIELD)
+ if (field == null) throw new UnsupportedOperationException("Unable to get delegate from proxy");
+ return field.get(proxy) as T
+ }
+
+ /**
+ * Helper method to set delegate to ManagedDirectedProxy with use of reflection.
+ *
+ * Note: This method uses reflection, but setting delegate field should not occur too much
+ * to introduce any significant performance hits.
+ *
+ */
+ public static def void setDelegate(RpcService proxy, RpcService delegate) {
+ val field = proxy.class.getField(DELEGATE_FIELD)
+ if (field == null) throw new UnsupportedOperationException("Unable to set delegate to proxy");
+ if (field.type.isAssignableFrom(delegate.class)) {
+ field.set(proxy, delegate)
+ } else
+ throw new IllegalArgumentException("delegate class is not assignable to proxy");
+ }
+
+ public static def Map<InstanceIdentifier, ? extends RpcService> getRoutingTable(RpcService target,
+ Class<? extends BaseIdentity> tableClass) {
+ val field = target.class.getField(tableClass.routingTableField)
+ if (field == null) throw new UnsupportedOperationException(
+ "Unable to get routing table. Table field does not exists");
+ return field.get(target) as Map<InstanceIdentifier, ? extends RpcService>;
+ }
+
+ public static def void setRoutingTable(RpcService target, Class<? extends BaseIdentity> tableClass,
+ Map<InstanceIdentifier, ? extends RpcService> routingTable) {
+ val field = target.class.getField(tableClass.routingTableField)
+ if (field == null) throw new UnsupportedOperationException(
+ "Unable to set routing table. Table field does not exists");
+ field.set(target,routingTable);
+
+ }
+
+}
--- /dev/null
+/*
+ * 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
+ */
+package org.opendaylight.controller.sal.binding.codegen
+
+import org.opendaylight.yangtools.yang.binding.RpcService
+import org.opendaylight.yangtools.yang.binding.BaseIdentity
+import org.opendaylight.yangtools.yang.binding.NotificationListener
+
+/**
+ *
+ *
+ */
+class RuntimeCodeSpecification {
+
+ public static val PACKAGE_PREFIX = "_gen.";
+
+ public static val DIRECT_PROXY_SUFFIX = "DirectProxy";
+ public static val ROUTER_SUFFIX = "Router";
+ public static val INVOKER_SUFFIX = "Invoker";
+
+ public static val DELEGATE_FIELD = "_delegate"
+ public static val ROUTING_TABLE_FIELD_PREFIX = "_routes_"
+
+ public static def getInvokerName(Class<? extends NotificationListener> listener) {
+ getGeneratedName(listener, INVOKER_SUFFIX);
+ }
+
+ /**
+ * Returns a name for DirectProxy implementation
+ *
+ *
+ */
+ public static def getDirectProxyName(Class<? extends RpcService> base) {
+ getGeneratedName(base, DIRECT_PROXY_SUFFIX);
+ }
+
+ /**
+ * Returns a name for Router implementation
+ *
+ */
+ public static def getRouterName(Class<? extends RpcService> base) {
+ getGeneratedName(base, ROUTER_SUFFIX);
+ }
+
+ /**
+ * Returns a name for generated interface
+ *
+ */
+ public static def getGeneratedName(Class<?> cls, String suffix) {
+ '''«PACKAGE_PREFIX»«cls.package.name».«cls.simpleName»$«suffix»'''.toString()
+ }
+
+ /**
+ * Returns a field name for specified routing context
+ *
+ */
+ public static def getRoutingTableField(Class<? extends BaseIdentity> routingContext) {
+ return '''_routes_«routingContext.simpleName»'''.toString;
+ }
+}
--- /dev/null
+/*
+ * 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
+ */
+package org.opendaylight.controller.sal.binding.codegen
+
+import java.lang.reflect.Method
+import org.opendaylight.yangtools.yang.binding.Notification
+
+public static class YangtoolsMappingHelper {
+
+ public static def boolean isNotificationCallback(Method it) {
+ return name.startsWith("on") && parameterTypes.size === 1 &&
+ Notification.isAssignableFrom(parameterTypes.get(0))
+ }
+}
--- /dev/null
+/*
+ * 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
+ */
+package org.opendaylight.controller.sal.binding.codegen.impl;
+
+import javassist.CtClass;
+import javassist.CtField;
+import javassist.CtMethod;
+
+public class JavassistUtils {
+
+ public static interface ClassGenerator {
+ void process(CtClass cls);
+ }
+
+ public static interface MethodGenerator {
+ void process(CtMethod method);
+ }
+
+ public static interface FieldGenerator {
+ void process(CtField field);
+ }
+}
--- /dev/null
+/*
+ * 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
+ */
+package org.opendaylight.controller.sal.binding.codegen.impl
+
+import org.opendaylight.yangtools.yang.binding.BaseIdentity
+import javassist.CtMethod
+import java.lang.reflect.Method
+
+@Data
+class RoutingPair {
+
+ @Property
+ val Class<? extends BaseIdentity> context;
+ @Property
+ val CtMethod getter;
+}
--- /dev/null
+/*
+ * 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
+ */
+package org.opendaylight.controller.sal.binding.codegen.impl
+
+import javassist.ClassPool
+import org.opendaylight.yangtools.yang.binding.RpcService
+
+import javassist.CtClass
+import static com.google.common.base.Preconditions.*
+
+import javassist.CtField
+import javassist.Modifier
+import javassist.CtMethod
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier
+import org.opendaylight.yangtools.yang.binding.annotations.RoutingContext
+import org.opendaylight.yangtools.yang.binding.BaseIdentity
+
+import java.util.Map
+import java.util.HashMap
+import javassist.NotFoundException
+import javassist.LoaderClassPath
+import org.opendaylight.controller.sal.binding.codegen.impl.JavassistUtils.MethodGenerator
+import org.opendaylight.controller.sal.binding.codegen.impl.JavassistUtils.ClassGenerator
+import org.opendaylight.yangtools.yang.binding.NotificationListener
+import org.opendaylight.yangtools.yang.binding.Notification
+import java.util.Arrays
+
+import static extension org.opendaylight.controller.sal.binding.codegen.YangtoolsMappingHelper.*
+import static extension org.opendaylight.controller.sal.binding.codegen.RuntimeCodeSpecification.*
+
+class RuntimeCodeGenerator {
+
+ val ClassPool classPool;
+
+ public new(ClassPool pool) {
+ classPool = pool;
+ }
+
+ def <T extends RpcService> Class<? extends T> generateDirectProxy(Class<T> iface) {
+ val supertype = iface.asCtClass
+ val targetCls = createClass(iface.directProxyName, supertype) [
+ field(DELEGATE_FIELD, iface);
+ implementMethodsFrom(supertype) [
+ body = '''return ($r) «DELEGATE_FIELD».«it.name»($$);'''
+ ]
+ ]
+ return targetCls.toClass(iface.classLoader)
+ }
+
+ def <T extends RpcService> Class<? extends T> generateRouter(Class<T> iface) {
+ val supertype = iface.asCtClass
+ val targetCls = createClass(iface.routerName, supertype) [
+ //field(ROUTING_TABLE_FIELD,Map)
+ field(DELEGATE_FIELD, iface)
+ val contexts = new HashMap<String, Class<? extends BaseIdentity>>();
+ // We search for routing pairs and add fields
+ supertype.methods.filter[declaringClass == supertype && parameterTypes.size === 1].forEach [ method |
+ val routingPair = method.routingContextInput;
+ if (routingPair !== null)
+ contexts.put(routingPair.context.routingTableField, routingPair.context);
+ ]
+ for (ctx : contexts.entrySet) {
+ field(ctx.key, Map)
+ }
+ implementMethodsFrom(supertype) [
+ if (parameterTypes.size === 1) {
+ val routingPair = routingContextInput;
+ val bodyTmp = '''
+ {
+ final «InstanceIdentifier.name» identifier = $1.«routingPair.getter.name»();
+ «supertype.name» instance = («supertype.name») «routingPair.context.routingTableField».get(identifier);
+ if(instance == null) {
+ instance = «DELEGATE_FIELD»;
+ }
+ return ($r) instance.«it.name»($$);
+ }'''
+ body = bodyTmp
+ } else if (parameterTypes.size === 0) {
+ body = '''return ($r) «DELEGATE_FIELD».«it.name»($$);'''
+ }
+ ]
+ ]
+ return targetCls.toClass(iface.classLoader)
+ }
+
+ def Class<?> generateListenerInvoker(Class<? extends NotificationListener> iface) {
+ val targetCls = createClass(iface.invokerName) [
+ field(DELEGATE_FIELD, iface)
+ it.method(Void, "invoke", Notification) [
+ val callbacks = iface.methods.filter[notificationCallback]
+ body = '''
+ {
+ «FOR callback : callbacks SEPARATOR " else "»
+ if($1 instanceof «val cls = callback.parameterTypes.get(0).name») {
+ «DELEGATE_FIELD».«callback.name»((«cls») $1);
+ return;
+ }
+ «ENDFOR»
+ }
+ '''
+ ]
+ ]
+ return targetCls.toClass(iface.classLoader);
+ }
+
+ def void method(CtClass it, Class<?> returnType, String name, Class<?> parameter, MethodGenerator function1) {
+ val method = new CtMethod(returnType.asCtClass, name, Arrays.asList(parameter.asCtClass), it);
+ function1.process(method);
+ it.addMethod(method);
+ }
+
+ private def routingContextInput(CtMethod method) {
+ val inputClass = method.parameterTypes.get(0);
+ return inputClass.contextInstance;
+ }
+
+ private def RoutingPair getContextInstance(CtClass dataClass) {
+ for (method : dataClass.methods) {
+ if (method.parameterTypes.size === 0 && method.name.startsWith("get")) {
+ for (annotation : method.availableAnnotations) {
+ if (annotation instanceof RoutingContext) {
+ return new RoutingPair((annotation as RoutingContext).value, method)
+ }
+ }
+ }
+ }
+ for (iface : dataClass.interfaces) {
+ val ret = getContextInstance(iface);
+ if (ret != null) return ret;
+ }
+ return null;
+ }
+
+ private def void implementMethodsFrom(CtClass target, CtClass source, MethodGenerator function1) {
+ for (method : source.methods) {
+ if (method.declaringClass == source) {
+ val redeclaredMethod = new CtMethod(method, target, null);
+ function1.process(redeclaredMethod);
+ target.addMethod(redeclaredMethod);
+ }
+ }
+ }
+
+ private def CtClass createClass(String fqn, ClassGenerator cls) {
+ val target = classPool.makeClass(fqn);
+ cls.process(target);
+ return target;
+ }
+
+ private def CtClass createClass(String fqn, CtClass superInterface, ClassGenerator cls) {
+ val target = classPool.makeClass(fqn);
+ target.implementsType(superInterface);
+ cls.process(target);
+ return target;
+ }
+
+ private def void implementsType(CtClass it, CtClass supertype) {
+ checkArgument(supertype.interface, "Supertype must be interface");
+ addInterface(supertype);
+ }
+
+ private def asCtClass(Class<?> class1) {
+ classPool.get(class1);
+ }
+
+ private def CtField field(CtClass it, String name, Class<?> returnValue) {
+ val field = new CtField(returnValue.asCtClass, name, it);
+ field.modifiers = Modifier.PUBLIC
+ addField(field);
+ return field;
+ }
+
+ def get(ClassPool pool, Class<?> cls) {
+ try {
+ return pool.get(cls.name)
+ } catch (NotFoundException e) {
+ pool.appendClassPath(new LoaderClassPath(cls.classLoader));
+ return pool.get(cls.name)
+ }
+ }
+}
--- /dev/null
+/*
+ * 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
+ */
+package org.opendaylight.controller.sal.binding.impl
+
+import org.opendaylight.controller.sal.binding.api.BindingAwareConsumer
+import org.opendaylight.controller.sal.binding.api.BindingAwareProvider
+import org.opendaylight.yangtools.yang.binding.RpcService
+import javassist.ClassPool
+import org.osgi.framework.BundleContext
+import java.util.Map
+import java.util.HashMap
+import javassist.LoaderClassPath
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker
+import java.util.Hashtable
+import static extension org.opendaylight.controller.sal.binding.codegen.RuntimeCodeHelper.*
+
+import org.opendaylight.controller.sal.binding.api.NotificationProviderService
+import org.osgi.framework.ServiceRegistration
+import static org.opendaylight.controller.sal.binding.impl.osgi.Constants.*
+import static extension org.opendaylight.controller.sal.binding.impl.osgi.PropertiesUtils.*
+import org.opendaylight.controller.sal.binding.api.NotificationService
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext
+
+import org.slf4j.LoggerFactory
+import org.opendaylight.controller.sal.binding.codegen.impl.RuntimeCodeGenerator
+
+class BindingAwareBrokerImpl implements BindingAwareBroker {
+ private static val log = LoggerFactory.getLogger(BindingAwareBrokerImpl)
+
+ private val clsPool = ClassPool.getDefault()
+ private var RuntimeCodeGenerator generator;
+ private Map<Class<? extends RpcService>, RpcProxyContext> managedProxies = new HashMap();
+ private var NotificationBrokerImpl notifyBroker
+ private var ServiceRegistration<NotificationProviderService> notifyBrokerRegistration
+
+ @Property
+ var BundleContext brokerBundleContext
+
+ def start() {
+ initGenerator();
+
+ // Initialization of notificationBroker
+ notifyBroker = new NotificationBrokerImpl(null);
+ val brokerProperties = newProperties();
+ notifyBrokerRegistration = brokerBundleContext.registerService(NotificationProviderService, notifyBroker,
+ brokerProperties)
+ brokerBundleContext.registerService(NotificationService, notifyBroker, brokerProperties)
+ }
+
+ def initGenerator() {
+
+ // YANG Binding Class Loader
+ clsPool.appendClassPath(new LoaderClassPath(RpcService.classLoader));
+ generator = new RuntimeCodeGenerator(clsPool);
+ }
+
+ override registerConsumer(BindingAwareConsumer consumer, BundleContext bundleCtx) {
+ val ctx = consumer.createContext(bundleCtx)
+ consumer.onSessionInitialized(ctx)
+ return ctx
+ }
+
+ override registerProvider(BindingAwareProvider provider, BundleContext bundleCtx) {
+ val ctx = provider.createContext(bundleCtx)
+ provider.onSessionInitialized(ctx)
+ provider.onSessionInitiated(ctx as ProviderContext)
+ return ctx
+ }
+
+ private def createContext(BindingAwareConsumer consumer, BundleContext consumerCtx) {
+ new OsgiConsumerContext(consumerCtx, this)
+ }
+
+ private def createContext(BindingAwareProvider provider, BundleContext providerCtx) {
+ new OsgiProviderContext(providerCtx, this)
+ }
+
+ /**
+ * Returns a Managed Direct Proxy for supplied class
+ *
+ * Managed direct proxy is a generated proxy class conforming to the supplied interface
+ * which delegates all calls to the backing delegate.
+ *
+ * Proxy does not do any validation, null pointer checks or modifies data in any way, it
+ * is only use to avoid exposing direct references to backing implementation of service.
+ *
+ * If proxy class does not exist for supplied service class it will be generated automatically.
+ */
+ def <T extends RpcService> getManagedDirectProxy(Class<T> service) {
+
+ var RpcProxyContext existing = null
+ if ((existing = managedProxies.get(service)) != null) {
+ return existing.proxy
+ }
+ val proxyClass = generator.generateDirectProxy(service)
+ val rpcProxyCtx = new RpcProxyContext(proxyClass)
+ val properties = new Hashtable<String, String>()
+ rpcProxyCtx.proxy = proxyClass.newInstance as RpcService
+
+ properties.salServiceType = SAL_SERVICE_TYPE_CONSUMER_PROXY
+ rpcProxyCtx.registration = brokerBundleContext.registerService(service, rpcProxyCtx.proxy as T, properties)
+ managedProxies.put(service, rpcProxyCtx)
+ return rpcProxyCtx.proxy
+ }
+ /**
+ * Registers RPC Implementation
+ *
+ */
+ def <T extends RpcService> registerRpcImplementation(Class<T> type, T service, OsgiProviderContext context,
+ Hashtable<String, String> properties) {
+ val proxy = getManagedDirectProxy(type)
+ if(proxy.delegate != null) {
+ throw new IllegalStateException("Service " + type + "is already registered");
+ }
+ val osgiReg = context.bundleContext.registerService(type, service, properties);
+ proxy.delegate = service;
+ return new RpcServiceRegistrationImpl<T>(type, service, osgiReg);
+ }
+}
--- /dev/null
+/*
+ * 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
+ */
+package org.opendaylight.controller.sal.binding.impl;
+
+import java.util.Hashtable;
+
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker;
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceRegistration;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class BrokerActivator implements BundleActivator {
+
+ private static final Logger log = LoggerFactory.getLogger(BrokerActivator.class);
+ private BindingAwareBrokerImpl baSal;
+ private ServiceRegistration<BindingAwareBroker> baSalRegistration;
+
+
+ @Override
+ public void start(BundleContext context) throws Exception {
+ log.info("Binding Aware Broker initialized");
+ baSal = new BindingAwareBrokerImpl();
+ baSal.setBrokerBundleContext(context);
+ baSal.start();
+
+ BindingAwareBroker baSalService = baSal;
+ Hashtable<String, String> properties = new Hashtable<>();
+ this.baSalRegistration = context.registerService(BindingAwareBroker.class,baSalService, properties);
+
+ }
+
+ @Override
+ public void stop(BundleContext context) throws Exception {
+ log.info("Binding Aware Broker stopped");
+ baSalRegistration.unregister();
+ }
+
+}
--- /dev/null
+/*
+ * 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
+ */
+package org.opendaylight.controller.sal.binding.impl
+
+import org.opendaylight.controller.sal.common.DataStoreIdentifier
+import org.opendaylight.controller.sal.binding.api.data.RuntimeDataProvider
+
+class DataProviderContext {
+
+ @Property
+ var DataStoreIdentifier identifier;
+ @Property
+ var RuntimeDataProvider provider;
+}
--- /dev/null
+/*
+ * 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
+ */
+package org.opendaylight.controller.sal.binding.impl
+
+import org.opendaylight.controller.sal.binding.api.NotificationProviderService
+import org.opendaylight.yangtools.yang.binding.Notification
+import com.google.common.collect.Multimap
+import org.opendaylight.controller.sal.binding.api.NotificationListener
+import com.google.common.collect.HashMultimap
+import java.util.concurrent.ExecutorService
+import java.util.Collection
+
+class NotificationBrokerImpl implements NotificationProviderService {
+
+ val Multimap<Class<? extends Notification>, NotificationListener<?>> listeners;
+ val ExecutorService executor;
+
+ new(ExecutorService executor) {
+ listeners = HashMultimap.create()
+ this.executor = executor;
+ }
+
+ override <T extends Notification> addNotificationListener(Class<T> notificationType,
+ NotificationListener<T> listener) {
+ listeners.put(notificationType, listener)
+ }
+
+ override <T extends Notification> removeNotificationListener(Class<T> notificationType,
+ NotificationListener<T> listener) {
+ listeners.remove(notificationType, listener)
+ }
+
+ override notify(Notification notification) {
+ notification.notificationTypes.forEach [
+ listeners.get(it as Class<? extends Notification>)?.notifyAll(notification)
+ ]
+ }
+
+ def getNotificationTypes(Notification notification) {
+ notification.class.interfaces.filter[it != Notification && Notification.isAssignableFrom(it)]
+ }
+
+ @SuppressWarnings("unchecked")
+ def notifyAll(Collection<NotificationListener<?>> listeners, Notification notification) {
+ listeners.forEach[(it as NotificationListener).onNotification(notification)]
+ }
+}
--- /dev/null
+/*
+ * 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
+ */
+package org.opendaylight.controller.sal.binding.impl
+
+import org.opendaylight.controller.sal.binding.api.NotificationService
+import org.opendaylight.controller.sal.binding.api.NotificationListener
+import org.opendaylight.yangtools.yang.binding.Notification
+import com.google.common.collect.Multimap
+import com.google.common.collect.HashMultimap
+
+class NotificationServiceImpl implements NotificationService {
+ val Multimap<Class<? extends Notification>, NotificationListener<?>> listeners;
+
+ new() {
+ listeners = HashMultimap.create()
+ }
+
+ override <T extends Notification> addNotificationListener(Class<T> notificationType,
+ NotificationListener<T> listener) {
+ listeners.put(notificationType, listener)
+ }
+
+ override <T extends Notification> removeNotificationListener(Class<T> notificationType,
+ NotificationListener<T> listener) {
+ listeners.remove(notificationType, listener)
+ }
+
+}
--- /dev/null
+/*
+ * 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
+ */
+package org.opendaylight.controller.sal.binding.impl;
+
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ConsumerContext;
+import org.opendaylight.controller.sal.binding.api.BindingAwareService;
+import org.opendaylight.yangtools.yang.binding.RpcService;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceReference;
+import org.slf4j.LoggerFactory
+import static org.opendaylight.controller.sal.binding.impl.osgi.Constants.*
+
+class OsgiConsumerContext implements ConsumerContext {
+
+ static val log = LoggerFactory.getLogger(OsgiConsumerContext)
+ protected val BundleContext bundleContext;
+ protected val BindingAwareBrokerImpl broker;
+
+ new(BundleContext ctx, BindingAwareBrokerImpl broker) {
+ this.bundleContext = ctx;
+ this.broker = broker;
+ }
+
+ override def <T extends BindingAwareService> getSALService(Class<T> service) {
+
+ // SAL Services are global
+ var ref = bundleContext.getServiceReference(service);
+ return bundleContext.getService(ref) as T;
+ }
+
+ override def <T extends RpcService> T getRpcService(Class<T> module) {
+ try {
+
+ val services = bundleContext.getServiceReferences(module, getProxyFilter());
+
+ // Proxy service found / using first implementation
+ // FIXME: Add advanced logic to retrieve service with right set of models
+ if (false == services.empty) {
+ val ref = services.iterator().next() as ServiceReference<T>;
+ return bundleContext.getService(ref) as T;
+ }
+ } catch (InvalidSyntaxException e) {
+ log.error("Created filter was invalid:", e.message, e)
+ }
+ return null;
+
+ }
+
+ private def getProxyFilter() {
+ return '''(«SAL_SERVICE_TYPE»=«SAL_SERVICE_TYPE_CONSUMER_PROXY»)'''
+ }
+}
--- /dev/null
+/*
+ * 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
+ */
+package org.opendaylight.controller.sal.binding.impl;
+
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.Map;
+
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext;
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.RpcServiceRegistration;
+import org.opendaylight.yangtools.yang.binding.RpcService;
+import org.osgi.framework.BundleContext;
+
+import static org.opendaylight.controller.sal.binding.impl.osgi.Constants.*;
+import static extension org.opendaylight.controller.sal.binding.impl.osgi.PropertiesUtils.*;
+
+class OsgiProviderContext extends OsgiConsumerContext implements ProviderContext {
+
+ @Property
+ val Map<Class<? extends RpcService>, RpcServiceRegistrationImpl<? extends RpcService>> registeredServices
+
+ new(BundleContext ctx, BindingAwareBrokerImpl broker) {
+ super(ctx, broker);
+ _registeredServices = new HashMap();
+ }
+
+ override def <T extends RpcService> RpcServiceRegistration<T> addRpcImplementation(Class<T> type, T implementation) {
+
+ // TODO Auto-generated method stub
+ val properties = new Hashtable<String, String>();
+ properties.salServiceType = SAL_SERVICE_TYPE_PROVIDER
+
+ // Fill requirements
+ val salReg = broker.registerRpcImplementation(type, implementation, this, properties)
+ registeredServices.put(type, salReg)
+ return salReg;
+ }
+}
--- /dev/null
+/*
+ * 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
+ */
+package org.opendaylight.controller.sal.binding.impl
+
+import org.opendaylight.yangtools.yang.binding.RpcService
+import org.osgi.framework.ServiceRegistration
+
+class RpcProxyContext {
+
+ new(Class<? extends RpcService> proxyClass) {
+ this.proxyClass = proxyClass
+ }
+
+ protected val Class<? extends RpcService> proxyClass;
+
+ @Property
+ protected var RpcService proxy;
+
+ @Property
+ protected var ServiceRegistration<? extends RpcService> registration;
+}
\ No newline at end of file
--- /dev/null
+/*
+ * 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
+ */
+package org.opendaylight.controller.sal.binding.impl
+
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.RpcServiceRegistration
+import org.osgi.framework.ServiceRegistration
+import org.opendaylight.yangtools.yang.binding.RpcService
+
+class RpcServiceRegistrationImpl<T extends RpcService> implements RpcServiceRegistration<T> {
+
+ val ServiceRegistration<T> osgiRegistration;
+ private val T service;
+ val Class<T> cls;
+
+ public new(Class<T> type, T service, ServiceRegistration<T> osgiReg) {
+ this.cls = type;
+ this.osgiRegistration = osgiReg;
+ this.service = service;
+ }
+
+ override getService() {
+ this.service
+ }
+
+ override unregister() {
+ throw new UnsupportedOperationException("TODO: auto-generated method stub")
+ }
+}
--- /dev/null
+/*
+ * 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
+ */
+package org.opendaylight.controller.sal.binding.impl
+
+import org.opendaylight.controller.sal.binding.api.data.DataBrokerService
+import org.opendaylight.controller.sal.common.DataStoreIdentifier
+import org.opendaylight.yangtools.yang.binding.DataRoot
+import org.opendaylight.controller.sal.binding.api.data.DataProviderService
+import org.opendaylight.controller.sal.binding.api.data.DataCommitHandler
+import org.opendaylight.controller.sal.binding.api.data.DataRefresher
+import org.opendaylight.controller.sal.binding.api.data.DataValidator
+import org.opendaylight.yangtools.yang.common.RpcResult
+import org.opendaylight.controller.sal.binding.api.data.RuntimeDataProvider
+import java.util.Map
+
+class _DataBrokerImpl implements DataProviderService {
+
+ Map<DataStoreIdentifier, DataProviderContext> dataProviders;
+ var DataProviderContext defaultDataProvider;
+
+ override <T extends DataRoot> getData(DataStoreIdentifier store, Class<T> rootType) {
+ val dataStore = resolveProvider(store, rootType);
+ return dataStore.provider.getData(store, rootType);
+ }
+
+ override <T extends DataRoot> getData(DataStoreIdentifier store, T filter) {
+ }
+
+ override <T extends DataRoot> T getCandidateData(DataStoreIdentifier store, Class<T> rootType) {
+ throw new UnsupportedOperationException("TODO: auto-generated method stub");
+ }
+
+ override <T extends DataRoot> T getCandidateData(DataStoreIdentifier store, T filter) {
+ throw new UnsupportedOperationException("TODO: auto-generated method stub");
+ }
+
+ override commit(DataStoreIdentifier store) {
+ throw new UnsupportedOperationException("TODO: auto-generated method stub")
+ }
+
+ override editCandidateData(DataStoreIdentifier store, DataRoot changeSet) {
+ throw new UnsupportedOperationException("TODO: auto-generated method stub")
+ }
+
+ override addCommitHandler(DataStoreIdentifier store, DataCommitHandler provider) {
+ throw new UnsupportedOperationException("TODO: auto-generated method stub")
+ }
+
+ override addRefresher(DataStoreIdentifier store, DataRefresher refresher) {
+ throw new UnsupportedOperationException("TODO: auto-generated method stub")
+ }
+
+ override addValidator(DataStoreIdentifier store, DataValidator validator) {
+ throw new UnsupportedOperationException("TODO: auto-generated method stub")
+ }
+
+ override removeRefresher(DataStoreIdentifier store, DataRefresher refresher) {
+ throw new UnsupportedOperationException("TODO: auto-generated method stub")
+ }
+
+ override removeCommitHandler(DataStoreIdentifier store, DataCommitHandler provider) {
+ throw new UnsupportedOperationException("TODO: auto-generated method stub")
+
+ }
+
+ override removeValidator(DataStoreIdentifier store, DataValidator validator) {
+ throw new UnsupportedOperationException("TODO: auto-generated method stub")
+ }
+
+ def DataProviderContext resolveProvider(DataStoreIdentifier store, Class<? extends DataRoot> root) {
+ }
+
+}
--- /dev/null
+/*
+ * 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
+ */
+package org.opendaylight.controller.sal.binding.impl.osgi
+
+class Constants {
+
+ private new() {
+ }
+
+ public static val SAL_SERVICE_TYPE = "salServiceType"
+ public static val SAL_SERVICE_TYPE_CONSUMER_PROXY = "consumerProxy"
+ public static val SAL_SERVICE_TYPE_PROVIDER = "provider"
+ public static val SAL_SERVICE_TYPE_CONNECTOR = "connector"
+}
--- /dev/null
+/*
+ * 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
+ */
+package org.opendaylight.controller.sal.binding.impl.osgi
+
+import java.util.Hashtable
+import static org.opendaylight.controller.sal.binding.impl.osgi.Constants.*
+
+class PropertiesUtils {
+
+ private new() {
+ }
+
+ static def setSalServiceType(Hashtable<String, String> properties, String value) {
+ properties.put(SAL_SERVICE_TYPE, value)
+ return properties
+ }
+
+ static def getSalServiceType(Hashtable<String, String> properties) {
+ return properties.get(SAL_SERVICE_TYPE)
+ }
+
+ static def newProperties() {
+ new Hashtable<String, String>()
+ }
+
+}
--- /dev/null
+/*
+ * 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
+ */
+package org.opendaylight.controller.sal.binding.impl.osgi;
\ No newline at end of file
--- /dev/null
+/*
+ * 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
+ */
+package org.opendaylight.controller.sal.binding.impl;
\ No newline at end of file
--- /dev/null
+package org.opendaylight.controller.sal.binding.test;
+import static org.junit.Assert.*;
+
+import java.util.concurrent.Future;
+
+import org.junit.Test;
+import org.opendaylight.controller.sal.binding.impl.ProxyFactoryGenerator;
+import org.opendaylight.controller.sal.binding.impl.RpcServiceProxy;
+import org.opendaylight.yangtools.yang.binding.RpcService;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+
+
+public class GenerationTest {
+
+ public interface MockService extends RpcService {
+
+ Future<RpcResult<java.lang.Void>> cancelToast();
+
+ Future<RpcResult<java.lang.Void>> makeToast(String input);
+ }
+
+ @Test
+ public void test() {
+ ProxyFactoryGenerator generator = new ProxyFactoryGenerator();
+ Class<? extends RpcServiceProxy<MockService>> ret = generator.generate(MockService.class);
+
+ assertTrue(RpcServiceProxy.class.isAssignableFrom(ret));
+ assertTrue(MockService.class.isAssignableFrom(ret));
+ }
+
+}
--- /dev/null
+package org.opendaylight.controller.sal.binding.test;
+import static org.junit.Assert.*;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+
+import javassist.ClassPool;
+
+import org.junit.Before;
+import org.junit.Test;
+import static org.opendaylight.controller.sal.binding.codegen.RuntimeCodeHelper.*;
+import org.opendaylight.controller.sal.binding.codegen.impl.RuntimeCodeGenerator;
+import org.opendaylight.controller.sal.binding.test.mock.FooService;
+import org.opendaylight.controller.sal.binding.test.mock.ReferencableObject;
+import org.opendaylight.controller.sal.binding.test.mock.ReferencableObjectKey;
+import org.opendaylight.controller.sal.binding.test.mock.SimpleInput;
+import org.opendaylight.yangtools.yang.binding.Augmentation;
+import org.opendaylight.yangtools.yang.binding.BaseIdentity;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.IdentifiableItem;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.PathArgument;
+
+import static org.mockito.Mockito.*;
+
+
+public class RuntimeCodeGeneratorTest {
+
+ private RuntimeCodeGenerator codeGenerator;
+
+
+ @Before
+ public void initialize() {
+ this.codeGenerator = new RuntimeCodeGenerator(ClassPool.getDefault());
+ }
+
+ @Test
+ public void testGenerateDirectProxy() {
+ Class<? extends FooService> product = codeGenerator.generateDirectProxy(FooService.class);
+ assertNotNull(product);
+ }
+
+ @Test
+ public void testGenerateRouter() throws Exception {
+ Class<? extends FooService> product = codeGenerator.generateRouter(FooService.class);
+ assertNotNull(product);
+ assertNotNull(product.getSimpleName());
+ assertEquals("2 fields should be generated.",2,product.getFields().length);
+
+ verifyRouting(product.newInstance());
+ }
+
+ private void verifyRouting(FooService product) {
+ Map<InstanceIdentifier,FooService> routingTable = new HashMap<>();
+ setRoutingTable(product, BaseIdentity.class, routingTable);
+
+ assertSame("Returned routing table should be same instance",routingTable,getRoutingTable(product, BaseIdentity.class));
+
+ int servicesCount = 2;
+ int instancesPerService = 3;
+
+ InstanceIdentifier[][] identifiers = identifiers(servicesCount,instancesPerService);
+ FooService service[] = new FooService[] {
+ mock(FooService.class, "Instance 0"),
+ mock(FooService.class,"Instance 1")
+ };
+
+ for(int i = 0;i<service.length;i++) {
+ for (InstanceIdentifier instance : identifiers[i]) {
+ routingTable.put(instance, service[i]);
+ }
+ }
+
+ assertEquals("All instances should be registered.", servicesCount*instancesPerService, routingTable.size());
+
+ SimpleInput[] instance_0_input = new SimpleInputImpl[] {
+ new SimpleInputImpl(identifiers[0][0]),
+ new SimpleInputImpl(identifiers[0][1]),
+ new SimpleInputImpl(identifiers[0][2])
+ };
+
+ SimpleInput[] instance_1_input = new SimpleInputImpl[] {
+ new SimpleInputImpl(identifiers[1][0]),
+ new SimpleInputImpl(identifiers[1][1]),
+ new SimpleInputImpl(identifiers[1][2])
+ };
+
+ // We test sending mock messages
+
+ product.simple(instance_0_input[0]);
+ verify(service[0]).simple(instance_0_input[0]);
+
+ product.simple(instance_0_input[1]);
+ product.simple(instance_0_input[2]);
+
+ verify(service[0]).simple(instance_0_input[1]);
+ verify(service[0]).simple(instance_0_input[2]);
+
+ product.simple(instance_1_input[0]);
+ verify(service[1]).simple(instance_1_input[0]);
+ }
+
+ private InstanceIdentifier[][] identifiers(int serviceSize, int instancesPerService) {
+ InstanceIdentifier[][] ret = new InstanceIdentifier[serviceSize][];
+ int service = 0;
+ for (int i = 0;i<serviceSize;i++) {
+
+ InstanceIdentifier[] instanceIdentifiers = new InstanceIdentifier[instancesPerService];
+ ret[i] = instanceIdentifiers;
+ for(int id = 0;id<instancesPerService;id++) {
+ instanceIdentifiers[id] = referencableIdentifier(service*instancesPerService+id);
+ }
+ service++;
+ }
+
+ return ret;
+ }
+
+ private InstanceIdentifier referencableIdentifier(int i) {
+ ReferencableObjectKey key = new ReferencableObjectKey(i);
+ IdentifiableItem<ReferencableObject,ReferencableObjectKey> pathArg = new IdentifiableItem<>(ReferencableObject.class,key);
+ return new InstanceIdentifier(Arrays.<PathArgument>asList(pathArg), ReferencableObject.class);
+ }
+
+ private static class SimpleInputImpl implements SimpleInput {
+ private final InstanceIdentifier identifier;
+
+ public SimpleInputImpl(InstanceIdentifier _identifier) {
+ this.identifier = _identifier;
+ }
+
+ @Override
+ public <E extends Augmentation<SimpleInput>> E getAugmentation(Class<E> augmentationType) {
+ return null;
+ }
+
+ @Override
+ public InstanceIdentifier getIdentifier() {
+ return this.identifier;
+ }
+ }
+}
--- /dev/null
+package org.opendaylight.controller.sal.binding.test.mock;
+
+import org.opendaylight.yangtools.yang.binding.Notification;
+
+public interface BarUpdate extends Grouping,Notification {
+
+}
--- /dev/null
+package org.opendaylight.controller.sal.binding.test.mock;
+
+import org.opendaylight.yangtools.yang.binding.NotificationListener;
+
+public interface FooListener extends NotificationListener {
+
+ void onFooUpdate(FooUpdate notification);
+ void onBarUpdate(BarUpdate notification);
+
+}
--- /dev/null
+package org.opendaylight.controller.sal.binding.test.mock;
+
+import java.util.concurrent.Future;
+
+import org.opendaylight.yangtools.yang.binding.RpcService;
+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>> inheritedContextInput(InheritedContextInput obj);
+
+}
--- /dev/null
+package org.opendaylight.controller.sal.binding.test.mock;
+
+import org.opendaylight.yangtools.yang.binding.Notification;
+
+public interface FooUpdate extends Notification {
+
+}
--- /dev/null
+package org.opendaylight.controller.sal.binding.test.mock;
+
+import org.opendaylight.yangtools.yang.binding.BaseIdentity;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.binding.annotations.RoutingContext;
+
+public interface Grouping {
+
+ @RoutingContext(BaseIdentity.class)
+ InstanceIdentifier getInheritedIdentifier();
+}
--- /dev/null
+package org.opendaylight.controller.sal.binding.test.mock;
+
+public interface InheritedContextInput extends Grouping {
+
+}
--- /dev/null
+package org.opendaylight.controller.sal.binding.test.mock;
+
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.Identifiable;
+
+public interface ReferencableObject extends DataObject,Identifiable<ReferencableObjectKey> {
+
+}
--- /dev/null
+package org.opendaylight.controller.sal.binding.test.mock;
+
+import org.opendaylight.yangtools.yang.binding.Identifier;
+
+public class ReferencableObjectKey implements Identifier<ReferencableObject> {
+
+ final Integer value;
+
+ public ReferencableObjectKey(Integer _value) {
+ this.value = _value;
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((value == null) ? 0 : value.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ ReferencableObjectKey other = (ReferencableObjectKey) obj;
+ if (value == null) {
+ if (other.value != null)
+ return false;
+ } else if (!value.equals(other.value))
+ return false;
+ return true;
+ }
+
+ @Override
+ public String toString() {
+ return "ReferencableObjectKey [value=" + value + "]";
+ }
+
+
+}
--- /dev/null
+package org.opendaylight.controller.sal.binding.test.mock;
+
+import org.opendaylight.yangtools.yang.binding.Augmentable;
+import org.opendaylight.yangtools.yang.binding.BaseIdentity;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.binding.annotations.RoutingContext;
+
+public interface SimpleInput extends DataObject,Augmentable<SimpleInput> {
+
+ @RoutingContext(BaseIdentity.class)
+ InstanceIdentifier getIdentifier();
+}
--- /dev/null
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>sal-parent</artifactId>
+ <version>1.0-SNAPSHOT</version>
+ </parent>
+ <artifactId>sal-common-util</artifactId>
+ <scm>
+ <connection>scm:git:ssh://git.opendaylight.org:29418/controller.git</connection>
+ <developerConnection>scm:git:ssh://git.opendaylight.org:29418/controller.git</developerConnection>
+ <url>https://wiki.opendaylight.org/view/OpenDaylight_Controller:MD-SAL</url>
+ </scm>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>yang-common</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>sal-common</artifactId>
+ <version>1.0-SNAPSHOT</version>
+ </dependency>
+ </dependencies>
+
+ <packaging>bundle</packaging>
+</project>
--- /dev/null
+package org.opendaylight.controller.sal.common.util;
+
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+public class Futures {
+
+ private Futures(){}
+
+ public static <T> Future<T> immediateFuture(T result) {
+ return new ImmediateFuture<T>(result);
+ }
+
+ private static class ImmediateFuture<T> implements Future<T> {
+
+ private final T result;
+
+ public ImmediateFuture(T result) {
+ this.result = result;
+ }
+
+ @Override
+ public boolean cancel(boolean mayInterruptIfRunning) {
+ return false;
+ }
+
+ @Override
+ public boolean isCancelled() {
+ return false;
+ }
+
+ @Override
+ public boolean isDone() {
+ return true;
+ }
+
+ @Override
+ public T get() throws InterruptedException, ExecutionException {
+ return result;
+ }
+
+ @Override
+ public T get(long timeout, TimeUnit unit) throws InterruptedException,
+ ExecutionException, TimeoutException {
+ return result;
+ }
+
+ }
+}
--- /dev/null
+/*
+ * 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
+ */
+package org.opendaylight.controller.sal.common.util;
+
+import org.opendaylight.yangtools.yang.common.RpcError;
+import org.opendaylight.yangtools.yang.common.RpcError.ErrorSeverity;
+import org.opendaylight.yangtools.yang.common.RpcError.ErrorType;
+
+/**
+ * @author mirehak
+ *
+ */
+public class RpcErrors {
+
+ /**
+ * @param applicationTag
+ * @param tag
+ * @param info
+ * @param severity
+ * @param message
+ * @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,
+ errorType, cause);
+ return ret;
+ }
+
+ private static class RpcErrorTO implements RpcError {
+
+ private final String applicationTag;
+ private final String tag;
+ private final String info;
+ private final ErrorSeverity severity;
+ private final String message;
+ private final ErrorType errorType;
+ private final Throwable cause;
+
+ /**
+ * @param applicationTag
+ * @param tag
+ * @param info
+ * @param severity
+ * @param message
+ * @param errorType
+ * @param cause
+ */
+ protected RpcErrorTO(String applicationTag, String tag, String info,
+ ErrorSeverity severity, String message, ErrorType errorType, Throwable cause) {
+ super();
+ this.applicationTag = applicationTag;
+ this.tag = tag;
+ this.info = info;
+ this.severity = severity;
+ this.message = message;
+ this.errorType = errorType;
+ this.cause = cause;
+ }
+
+ @Override
+ public String getApplicationTag() {
+ return applicationTag;
+ }
+
+ @Override
+ public String getInfo() {
+ return info;
+ }
+
+ @Override
+ public String getMessage() {
+ return message;
+ }
+
+ @Override
+ public ErrorSeverity getSeverity() {
+ return severity;
+ }
+
+ @Override
+ public String getTag() {
+ return tag;
+ }
+
+ @Override
+ public Throwable getCause() {
+ return cause;
+ }
+
+ @Override
+ public ErrorType getErrorType() {
+ return errorType;
+ }
+ }
+}
--- /dev/null
+/*
+ * 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
+ */
+package org.opendaylight.controller.sal.common.util;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import org.opendaylight.yangtools.yang.common.RpcError;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+
+public class Rpcs {
+ public static <T> RpcResult<T> getRpcResult(boolean successful, T result,
+ Collection<RpcError> errors) {
+ RpcResult<T> ret = new RpcResultTO<T>(successful, result, errors);
+ return ret;
+ }
+
+ private static class RpcResultTO<T> implements RpcResult<T> {
+
+ private final Collection<RpcError> errors;
+ private final T result;
+ private final boolean successful;
+
+ public RpcResultTO(boolean successful, T result,
+ Collection<RpcError> errors) {
+ this.successful = successful;
+ this.result = result;
+ this.errors = Collections.unmodifiableList(new ArrayList<RpcError>(
+ errors));
+ }
+
+ @Override
+ public boolean isSuccessful() {
+ return successful;
+ }
+
+ @Override
+ public T getResult() {
+ return result;
+ }
+
+ @Override
+ public Collection<RpcError> getErrors() {
+ return errors;
+ }
+
+ }
+}
--- /dev/null
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>sal-parent</artifactId>
+ <version>1.0-SNAPSHOT</version>
+ </parent>
+ <artifactId>sal-core-api</artifactId>
+ <scm>
+ <connection>scm:git:ssh://git.opendaylight.org:29418/controller.git</connection>
+ <developerConnection>scm:git:ssh://git.opendaylight.org:29418/controller.git</developerConnection>
+ <url>https://wiki.opendaylight.org/view/OpenDaylight_Controller:MD-SAL</url>
+ </scm>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>sal-common</artifactId>
+ <version>1.0-SNAPSHOT</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>yang-data-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>yang-model-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.osgi</groupId>
+ <artifactId>org.osgi.core</artifactId>
+ <version>5.0.0</version>
+ </dependency>
+ </dependencies>
+</project>
--- /dev/null
+package org.opendaylight.controller.sal.core.api;
+
+import java.util.Collection;
+import java.util.Collections;
+
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+
+public abstract class AbstractConsumer implements Consumer, BundleActivator {
+
+ Broker broker;
+ ServiceReference<Broker> brokerRef;
+ @Override
+ public final void start(BundleContext context) throws Exception {
+ brokerRef = context.getServiceReference(Broker.class);
+ broker = context.getService(brokerRef);
+
+ this.startImpl(context);
+
+ broker.registerConsumer(this,context);
+ }
+
+ public abstract void startImpl(BundleContext context);
+
+ @Override
+ public final void stop(BundleContext context) throws Exception {
+ broker = null;
+ if(brokerRef != null) {
+ context.ungetService(brokerRef);
+ }
+ }
+
+
+ @Override
+ public Collection<ConsumerFunctionality> getConsumerFunctionality() {
+ return Collections.emptySet();
+ }
+
+}
--- /dev/null
+package org.opendaylight.controller.sal.core.api;
+
+import java.util.Collection;
+import java.util.Collections;
+
+import org.opendaylight.controller.sal.core.api.Broker.ProviderSession;
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+
+public abstract class AbstractProvider implements BundleActivator, Provider {
+
+ private ServiceReference<Broker> brokerRef;
+ private Broker broker;
+
+ @Override
+ public Collection<ProviderFunctionality> getProviderFunctionality() {
+ return Collections.emptySet();
+ }
+
+ @Override
+ public final void start(BundleContext context) throws Exception {
+ brokerRef = context.getServiceReference(Broker.class);
+ broker = context.getService(brokerRef);
+
+ this.startImpl(context);
+
+ broker.registerProvider(this,context);
+ }
+
+ public abstract void startImpl(BundleContext context);
+
+ @Override
+ public final void stop(BundleContext context) throws Exception {
+ // TODO Auto-generated method stub
+
+ }
+
+}
--- /dev/null
+/*
+ * 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
+ */
+package org.opendaylight.controller.sal.core.api;
+
+import java.util.concurrent.Future;
+
+import org.opendaylight.controller.sal.core.api.data.DataBrokerService;
+import org.opendaylight.controller.sal.core.api.data.DataProviderService;
+import org.opendaylight.controller.sal.core.api.notify.NotificationProviderService;
+import org.opendaylight.controller.sal.core.api.notify.NotificationService;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.opendaylight.yangtools.yang.data.api.CompositeNode;
+import org.osgi.framework.BundleContext;
+
+
+/**
+ * Core component of the SAL layer responsible for wiring the SAL consumers.
+ *
+ * The responsibility of the broker is to maintain registration of SAL
+ * functionality {@link Consumer}s and {@link Provider}s, store provider and
+ * consumer specific context and functionality registration via
+ * {@link ConsumerSession} and provide access to infrastructure services, which
+ * removes direct dependencies between providers and consumers.
+ *
+ *
+ * <h3>Infrastructure services</h3> Some examples of infrastructure services:
+ *
+ * <ul>
+ * <li>RPC Invocation - see {@link ConsumerSession#rpc(QName, CompositeNode)},
+ * {@link ProviderSession#addRpcImplementation(QName, RpcImplementation)} and
+ * {@link RpcImplementation}
+ * <li>Notification Service - see {@link NotificationService} and
+ * {@link NotificationProviderService}
+ * <li>Functionality and Data model
+ * <li>Data Store access and modification - see {@link DataBrokerService} and
+ * {@link DataProviderService}
+ * </ul>
+ *
+ * The services are exposed via session.
+ *
+ * <h3>Session-based access</h3>
+ *
+ * The providers and consumers needs to register in order to use the
+ * binding-independent SAL layer and to expose functionality via SAL layer.
+ *
+ * For more information about session-based access see {@link ConsumerSession}
+ * and {@link ProviderSession}
+ *
+ *
+ *
+ */
+public interface Broker {
+
+ /**
+ * Registers the {@link Consumer}, which will use the SAL layer.
+ *
+ * <p>
+ * During the registration, the broker obtains the initial functionality
+ * from consumer, using the {@link Consumer#getConsumerFunctionality()}, and
+ * register that functionality into system and concrete infrastructure
+ * services.
+ *
+ * <p>
+ * Note that consumer could register additional functionality at later point
+ * by using service and functionality specific APIs.
+ *
+ * <p>
+ * The consumer is required to use returned session for all communication
+ * with broker or one of the broker services. The session is announced to
+ * the consumer by invoking
+ * {@link Consumer#onSessionInitiated(ConsumerSession)}.
+ *
+ * @param cons
+ * Consumer to be registered.
+ * @param context
+ * @return a session specific to consumer registration
+ * @throws IllegalArgumentException
+ * If the consumer is <code>null</code>.
+ * @throws IllegalStateException
+ * If the consumer is already registered.
+ */
+ ConsumerSession registerConsumer(Consumer cons, BundleContext context);
+
+ /**
+ * Registers the {@link Provider}, which will use the SAL layer.
+ *
+ * <p>
+ * During the registration, the broker obtains the initial functionality
+ * from consumer, using the {@link Provider#getProviderFunctionality()}, and
+ * register that functionality into system and concrete infrastructure
+ * services.
+ *
+ * <p>
+ * Note that consumer could register additional functionality at later point
+ * by using service and functionality specific APIs (e.g.
+ * {@link ProviderSession#addRpcImplementation(QName, RpcImplementation)}
+ *
+ * <p>
+ * The consumer is <b>required to use</b> returned session for all
+ * communication with broker or one of the broker services. The session is
+ * announced to the consumer by invoking
+ * {@link Provider#onSessionInitiated(ProviderSession)}.
+ *
+ *
+ * @param prov
+ * Provider to be registered.
+ * @param context
+ * @return a session unique to the provider registration.
+ * @throws IllegalArgumentException
+ * If the provider is <code>null</code>.
+ * @throws IllegalStateException
+ * If the consumer is already registered.
+ */
+ ProviderSession registerProvider(Provider prov, BundleContext context);
+
+ /**
+ * {@link Consumer} specific access to the SAL functionality.
+ *
+ * <p>
+ * ConsumerSession is {@link Consumer}-specific access to the SAL
+ * functionality and infrastructure services.
+ *
+ * <p>
+ * The session serves to store SAL context (e.g. registration of
+ * functionality) for the consumer and provides access to the SAL
+ * infrastructure services and other functionality provided by
+ * {@link Provider}s.
+ *
+
+ *
+ */
+ public interface ConsumerSession {
+
+ /**
+ * Sends an RPC to other components registered to the broker.
+ *
+ * @see RpcImplementation
+ * @param rpc
+ * Name of RPC
+ * @param input
+ * Input data to the RPC
+ * @return Result of the RPC call
+ */
+ Future<RpcResult<CompositeNode>> rpc(QName rpc, CompositeNode input);
+
+ boolean isClosed();
+
+ /**
+ * Returns a session specific instance (implementation) of requested
+ * service
+ *
+ * @param service
+ * Broker service
+ * @return Session specific implementation of service
+ */
+ <T extends BrokerService> T getService(Class<T> service);
+
+ /**
+ * Closes a session between consumer and broker.
+ *
+ * <p>
+ * The close operation unregisters a consumer and remove all registered
+ * functionality of the consumer from the system.
+ *
+ */
+ void close();
+ }
+
+ /**
+ * {@link Provider} specific access to the SAL functionality.
+ *
+ * <p>
+ * ProviderSession is {@link Provider}-specific access to the SAL
+ * functionality and infrastructure services, which also allows for exposing
+ * the provider's functionality to the other {@link Consumer}s.
+ *
+ * <p>
+ * The session serves to store SAL context (e.g. registration of
+ * functionality) for the providers and exposes access to the SAL
+ * infrastructure services, dynamic functionality registration and any other
+ * functionality provided by other {@link Provider}s.
+ *
+ */
+ public interface ProviderSession extends ConsumerSession {
+ /**
+ * 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
+ * Provider's Implementation of the RPC functionality
+ * @throws IllegalArgumentException
+ * If the name of RPC is invalid
+ */
+ void addRpcImplementation(QName rpcType,
+ RpcImplementation implementation)
+ throws IllegalArgumentException;
+
+ /**
+ * Unregisters an Rpc implementation
+ *
+ * @param rpcType
+ * Name of Rpc
+ * @param implementation
+ * Registered Implementation of the Rpc functionality
+ * @throws IllegalArgumentException
+ */
+ void removeRpcImplementation(QName rpcType,
+ RpcImplementation implementation)
+ throws IllegalArgumentException;
+
+ /**
+ * Closes a session between provider and SAL.
+ *
+ * <p>
+ * The close operation unregisters a provider and remove all registered
+ * functionality of the provider from the system.
+ */
+ @Override
+ public void close();
+
+ @Override
+ boolean isClosed();
+ }
+}
--- /dev/null
+/*
+ * 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
+ */
+package org.opendaylight.controller.sal.core.api;
+
+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 {
+
+ void closeSession();
+}
--- /dev/null
+/*
+ * 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
+ */
+package org.opendaylight.controller.sal.core.api;
+
+import java.util.Collection;
+
+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 faciliates 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.
+ */
+ public void onSessionInitiated(ConsumerSession session);
+
+ /**
+ * 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 {
+
+ }
+}
--- /dev/null
+/*
+ * 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
+ */
+package org.opendaylight.controller.sal.core.api;
+
+import java.util.Collection;
+
+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 faciliates 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.
+ */
+ public void onSessionInitiated(ProviderSession session);
+
+ /**
+ * 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 {
+
+ }
+}
--- /dev/null
+/*
+ * 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
+ */
+package org.opendaylight.controller.sal.core.api;
+
+import java.util.Set;
+
+import org.opendaylight.controller.sal.core.api.Broker.ConsumerSession;
+import org.opendaylight.controller.sal.core.api.Broker.ProviderSession;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.opendaylight.yangtools.yang.data.api.CompositeNode;
+
+/**
+ * {@link Provider}'s implementation of rpc.
+ *
+ * In order to expose the rpc to other components, the provider MUST register
+ * concrete implementation of this interface
+ *
+ * The registration could be done by :
+ * <ul>
+ * <li>returning an instance of implementation in the return value of
+ * {@link Provider#getProviderFunctionality()}
+ * <li>passing an instance of implementation and {@link QName} of rpc as
+ * arguments to the
+ * {@link ProviderSession#addRpcImplementation(QName, RpcImplementation)}
+ * </ul>
+ *
+ * The simplified process of the invocation of rpc is following:
+ *
+ * <ol>
+ * <li> {@link Consumer} invokes
+ * {@link ConsumerSession#rpc(QName, CompositeNode)}
+ * <li> {@link Broker} finds registered {@link RpcImplementation}s
+ * <li> {@link Broker} invokes
+ * {@link RpcImplementation#invokeRpc(QName, CompositeNode)}
+ * <li> {@link RpcImplementation} processes the data and returns a
+ * {@link RpcResult}
+ * <li> {@link Broker} returns the {@link RpcResult} to {@link Consumer}
+ * </ol>
+ *
+ *
+ */
+public interface RpcImplementation extends Provider.ProviderFunctionality {
+
+ /**
+ * A set of rpc types supported by implementation.
+ *
+ * The set of rpc {@link QName}s which are supported by this implementation.
+ * This set is used, when {@link Provider} is registered to the SAL, to
+ * register and expose the implementation of the returned rpcs.
+ *
+ * @return Set of QNames identifying supported RPCs
+ */
+ Set<QName> getSupportedRpcs();
+
+ /**
+ * Invokes a implementation of specified rpc.
+ *
+ *
+ * @param rpc
+ * Rpc to be invoked
+ * @param input
+ * Input data for rpc.
+ *
+ * @throws IllegalArgumentException
+ * <ul>
+ * <li>If rpc is null.
+ * <li>If input is not <code>null</code> and
+ * <code>false == rpc.equals(input.getNodeType)</code>
+ * </ul>
+ * @return RpcResult containing the output of rpc if was executed
+ * successfully, the list of errors otherwise.
+ */
+ RpcResult<CompositeNode> invokeRpc(QName rpc, CompositeNode input);
+
+}
--- /dev/null
+/*
+ * 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
+ */
+package org.opendaylight.controller.sal.core.api.data;
+
+import java.util.Set;
+import java.util.concurrent.Future;
+
+import org.opendaylight.controller.sal.common.DataStoreIdentifier;
+import org.opendaylight.controller.sal.core.api.BrokerService;
+import org.opendaylight.controller.sal.core.api.Consumer;
+import org.opendaylight.controller.sal.core.api.Provider;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.opendaylight.yangtools.yang.data.api.CompositeNode;
+import org.opendaylight.yangtools.yang.data.api.MutableCompositeNode;
+import org.opendaylight.yangtools.yang.data.api.Node;
+
+
+/**
+ * DataBrokerService provides unified access to the data stores available in the
+ * system.
+ *
+ *
+ * @see DataProviderService
+ *
+ */
+public interface DataBrokerService extends BrokerService {
+
+
+ Set<DataStoreIdentifier> getDataStores();
+
+ /**
+ * Returns a data from specified Data Store.
+ *
+ * Returns all the data visible to the consumer from specified Data Store.
+ *
+ * @param store
+ * Identifier of the store, from which will be data retrieved
+ * @return data visible to the consumer
+ */
+ CompositeNode getData(DataStoreIdentifier store);
+
+ /**
+ * Returns a filtered subset of data from specified Data Store.
+ *
+ * <p>
+ * The filter is modeled as an hierarchy of {@link Node} starting with
+ * {@link CompositeNode} representing data root. The semantics of the filter
+ * tree is the same as filter semantics defined in the NETCONF protocol for
+ * rpc operations <code>get</code> and <code>get-config</code> in Section 6
+ * of RFC6241.
+ *
+ *
+ * @see http://tools.ietf.org/html/rfc6241#section-6
+ * @param store
+ * Identifier of the store, from which will be data retrieved
+ * @param filter
+ * Data tree filter similar to the NETCONF filter
+ * @return
+ */
+ CompositeNode getData(DataStoreIdentifier store, CompositeNode filter);
+
+ /**
+ * Returns a candidate data which are not yet commited.
+ *
+ *
+ * @param store
+ * Identifier of the store, from which will be data retrieved
+ * @return
+ */
+ CompositeNode getCandidateData(DataStoreIdentifier store);
+
+ /**
+ * Returns a filtered subset of candidate data from specified Data Store.
+ *
+ * <p>
+ * The filter is modeled as an hierarchy of {@link Node} starting with
+ * {@link CompositeNode} representing data root. The semantics of the filter
+ * tree is the same as filter semantics defined in the NETCONF protocol for
+ * rpc operations <code>get</code> and <code>get-config</code> in Section 6
+ * of RFC6241.
+ *
+ *
+ * @see http://tools.ietf.org/html/rfc6241#section-6
+ * @param store
+ * Identifier of the store, from which will be data retrieved
+ * @param filter
+ * A CompositeNode filter
+ * @return
+ */
+ CompositeNode getCandidateData(DataStoreIdentifier store,
+ CompositeNode filter);
+
+ /**
+ *
+ * @param store
+ * Identifier of the store, in which will be the candidate data
+ * modified
+ * @param changeSet
+ * Modification of data tree.
+ * @return Result object containing the modified data tree if the operation
+ * was successful, otherwise list of the encountered errors.
+ */
+ RpcResult<CompositeNode> editCandidateData(DataStoreIdentifier store,
+ MutableCompositeNode changeSet);
+
+ /**
+ * Initiates a two-phase commit of candidate data.
+ *
+ * <p>
+ * The {@link Consumer} could initiate a commit of candidate data
+ *
+ * <p>
+ * The successful commit changes the state of the system and may affect
+ * several components.
+ *
+ * <p>
+ * The effects of successful commit of data are described in the
+ * specifications and YANG models describing the {@link Provider} components
+ * of controller. It is assumed that {@link Consumer} has an understanding
+ * of this changes.
+ *
+ *
+ * @see DataCommitHandler for further information how two-phase commit is
+ * processed.
+ * @param store
+ * Identifier of the store, where commit should occur.
+ * @return Result of the commit, containing success information or list of
+ * encountered errors, if commit was not successful.
+ */
+ Future<RpcResult<Void>> commit(DataStoreIdentifier store);
+}
--- /dev/null
+/*
+ * 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
+ */
+package org.opendaylight.controller.sal.core.api.data;
+
+import java.util.Set;
+
+import org.opendaylight.controller.sal.common.DataStoreIdentifier;
+import org.opendaylight.controller.sal.core.api.Provider;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+
+
+/**
+ * Two phase commit handler (cohort) of the two-phase commit protocol of data.
+ *
+ * <p>
+ * The provider should expose the implementation of DataCommitHandler if it's
+ * functionality depends on any subset of data stored in data repositories, in
+ * order to participate in {@link DataBrokerService#commit(DataStoreIdentifier)
+ * operation.
+ *
+ * <p>
+ * Operations of two-phase commit handlers should not change data in data store,
+ * this is responsibility of the coordinator (broker or some component of the
+ * broker).
+ *
+ * The commit handlers are responsible for changing the internal state of the
+ * provider to reflect the commited changes in data.
+ *
+ * <h3>Two-phase commit</h3>
+ *
+ * <h4>Commit Request Phase</h4>
+ *
+ * <ol>
+ * <li> <code>Consumer</code> edits data by invocation of
+ * <code>DataBrokerService.editCandidateData(DataStoreIdentifier, CompositeNodeModification)</code>
+ * <li> <code>Consumer</code> starts a commit by invoking
+ * <code>DataBrokerService.commit(DataStoreIdentifier)</code>
+ * <li> <code>Broker</code> retrieves a list of all registered
+ * <code>DataCommitHandlers</code>
+ * <li>For each <code>DataCommitHandler</code>
+ * <ol>
+ * <li><code>Broker</code> invokes a
+ * <code>DataCommitHandler.requestCommit(DataStoreIdentifier)</code> operation.
+ * <li><code>DataCommitHandler</code> returns a <code>RpcResult</code> with
+ * <code>CommitTransaction</code>
+ * <li>If the result was successful, broker adds <code>CommitTransaction</code>
+ * to the list of opened transactions. If not, brokers stops a commit request
+ * phase and starts a rollback phase.
+ * </ol>
+ * <li><code>Broker</code> starts a commit finish phase
+ * </ol>
+ *
+ * <h4>Commit Finish Phase</h4>
+ *
+ * <ol>
+ * <li>For each <code>CommitTransaction</code> from Commit Request phase
+ * <ol>
+ * <li><code>Broker</code> broker invokes a
+ * <code>CommitTransaction.finish()</code>
+ * <li>The provider finishes a commit (applies the change) and returns an
+ * <code>RpcResult</code>.
+ * </ol>
+ * <li>
+ * <ul>
+ * <li>If all returned results means successful, the brokers end two-phase
+ * commit by returning a success commit result to the Consumer.
+ * <li>If error occured, the broker starts a commit rollback phase.
+ * </ul>
+ * </ol>
+ *
+ * <h4>Commit Rollback Phase</h4>
+ * <li>For each <code>CommitTransaction</code> from Commit Request phase
+ * <ol>
+ * <li><code>Broker</code>
+ *
+ * broker invokes a {@link CommitTransaction#finish()}
+ * <li>The provider rollbacks a commit and returns an {@link RpcResult} of
+ * rollback. </ol>
+ * <li>Broker returns a error result to the consumer.
+ *
+ *
+ * <h3>Registration of functionality</h3>
+ * The registration could be done by :
+ * <ul>
+ * <li>returning an instance of implementation in the return value of
+ * {@link Provider#getProviderFunctionality()}
+ * <li>passing an instance of implementation and {@link DataStoreIdentifier} of
+ * rpc as arguments to the
+ * {@link DataProviderService#addCommitHandler(DataStoreIdentifier, DataCommitHandler)}
+ * </ul>
+ *
+ *
+ */
+public interface DataCommitHandler 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 commit handler. This set is used, when
+ * {@link Provider} is registered to the SAL, to register and expose the
+ * commit handler functionality to affected data stores.
+ *
+ * @return Set of Data Store identifiers
+ */
+ Set<DataStoreIdentifier> getSupportedDataStores();
+
+ /**
+ * The provider (commit handler) starts a commit transaction.
+ *
+ * <p>
+ * The commit handler (provider) prepares an commit scenario, rollback
+ * scenario and validates data.
+ *
+ * <p>
+ * If the provider is aware that at this point the commit would not be
+ * successful, the transaction is not created, but list of errors which
+ * prevented the start of transaction are returned.
+ *
+ * @param store
+ * @return Transaction object representing this commit, errors otherwise.
+ */
+ RpcResult<CommitTransaction> requestCommit(DataStoreIdentifier store);
+
+ public interface CommitTransaction {
+ /**
+ *
+ * @return Data store affected by the transaction
+ */
+ DataStoreIdentifier getDataStore();
+
+ /**
+ * Returns the handler associated with this transaction.
+ *
+ * @return Handler
+ */
+ DataCommitHandler getHandler();
+
+ /**
+ *
+ * Finishes a commit.
+ *
+ * The provider (commit handler) should apply all changes to its state
+ * which are a result of data change-
+ *
+ * @return
+ */
+ RpcResult<Void> finish() throws IllegalStateException;
+
+ /**
+ * Rollbacks a commit.
+ *
+ * @return
+ * @throws IllegalStateException
+ * If the method is invoked after {@link #finish()}
+ */
+ RpcResult<Void> rollback() throws IllegalStateException;
+ }
+}
--- /dev/null
+/*
+ * 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
+ */
+package org.opendaylight.controller.sal.core.api.data;
+
+import org.opendaylight.controller.sal.common.DataStoreIdentifier;
+import org.opendaylight.controller.sal.core.api.Provider;
+
+public interface DataProviderService extends DataBrokerService {
+
+ /**
+ * Adds {@link DataValidator} for specified Data Store
+ *
+ * @param store
+ * Data Store
+ * @param validator
+ * Validator
+ */
+ public void addValidator(DataStoreIdentifier store, DataValidator validator);
+
+ /**
+ * Removes {@link DataValidator} from specified Data Store
+ *
+ * @param store
+ * @param validator
+ * Validator
+ */
+ public void removeValidator(DataStoreIdentifier store,
+ DataValidator validator);
+
+ /**
+ * Adds {@link DataCommitHandler} for specified data store
+ *
+ * @param store
+ * @param provider
+ */
+ void addCommitHandler(DataStoreIdentifier store, DataCommitHandler provider);
+
+ /**
+ * Removes {@link DataCommitHandler} from specified data store
+ *
+ * @param store
+ * @param provider
+ */
+ void removeCommitHandler(DataStoreIdentifier store,
+ DataCommitHandler provider);
+
+ /**
+ * Adds {@link DataRefresher} for specified data store
+ *
+ * @param store
+ * @param refresher
+ */
+ void addRefresher(DataStoreIdentifier store, DataRefresher refresher);
+
+ /**
+ * Removes {@link DataRefresher} from specified data store
+ *
+ * @param store
+ * @param refresher
+ */
+ void removeRefresher(DataStoreIdentifier store, DataRefresher refresher);
+
+ 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.
+ */
+ void refreshData();
+ }
+}
--- /dev/null
+/*
+ * 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
+ */
+package org.opendaylight.controller.sal.core.api.data;
+
+import java.util.Set;
+
+import org.opendaylight.controller.sal.common.DataStoreIdentifier;
+import org.opendaylight.controller.sal.core.api.Provider;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.opendaylight.yangtools.yang.data.api.CompositeNode;
+
+
+/**
+ * {@link Provider}-supplied Validator of the data.
+ *
+ * <p>
+ * The registration could be done by :
+ * <ul>
+ * <li>returning an instance of implementation in the return value of
+ * {@link Provider#getProviderFunctionality()}
+ * <li>passing an instance of implementation and {@link DataStoreIdentifier} rpc
+ * 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
+ * <code>{@link RpcResult#isSuccessful()} == true</code> if the data
+ * passed validation, otherwise contains list of errors.
+ */
+ RpcResult<Void> validate(CompositeNode toValidate);
+
+}
--- /dev/null
+/*
+ * 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
+ */
+package org.opendaylight.controller.sal.core.api.data;
\ No newline at end of file
--- /dev/null
+/*
+ * 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
+ */
+package org.opendaylight.controller.sal.core.api.model;
+
+import org.opendaylight.controller.sal.core.api.BrokerService;
+import org.opendaylight.yangtools.yang.model.api.Module;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+
+public interface SchemaService extends BrokerService {
+
+ /**
+ * Registers a YANG module to session and global context
+ *
+ * @param module
+ */
+ void addModule(Module module);
+
+ /**
+ * Unregisters a YANG module from session context
+ *
+ * @param module
+ */
+ void removeModule(Module module);
+
+ /**
+ * Returns session specific YANG schema context
+ * @return
+ */
+ SchemaContext getSessionContext();
+
+ /**
+ * Returns global schema context
+ *
+ * @return
+ */
+ SchemaContext getGlobalContext();
+}
--- /dev/null
+/*
+ * 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
+ */
+package org.opendaylight.controller.sal.core.api.notify;
+
+import java.util.Set;
+
+import org.opendaylight.controller.sal.core.api.Consumer;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.CompositeNode;
+
+
+/**
+ * Notification listener for SAL notifications.
+ */
+public interface NotificationListener extends Consumer.ConsumerFunctionality {
+ /**
+ * 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
+ */
+ void onNotification(CompositeNode notification);
+}
--- /dev/null
+/*
+ * 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
+ */
+package org.opendaylight.controller.sal.core.api.notify;
+
+import org.opendaylight.controller.sal.core.api.Broker;
+import org.opendaylight.controller.sal.core.api.Provider;
+import org.opendaylight.yangtools.yang.data.api.CompositeNode;
+
+
+/**
+ * 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 NotificationProviderService 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
+ */
+ void sendNotification(CompositeNode notification);
+
+}
--- /dev/null
+/*
+ * 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
+ */
+package org.opendaylight.controller.sal.core.api.notify;
+
+import org.opendaylight.controller.sal.core.api.BrokerService;
+import org.opendaylight.controller.sal.core.api.Provider;
+import org.opendaylight.controller.sal.core.api.RpcImplementation;
+import org.opendaylight.controller.sal.core.api.Broker.ProviderSession;
+import org.opendaylight.yangtools.yang.common.QName;
+
+
+/**
+ * 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
+ * {@link Provider#getProviderFunctionality()}
+ * <li>passing an instance of implementation and {@link QName} of rpc as an
+ * 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
+ */
+ void addNotificationListener(QName notification,
+ NotificationListener listener);
+
+ /**
+ * Removes a notification listener for supplied notification type.
+ *
+ * @param notification
+ * @param listener
+ */
+ void removeNotificationListener(QName notification,
+ NotificationListener listener);
+}
--- /dev/null
+/*
+ * 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
+ */
+/**
+ * SAL Notification functionality
+ */
+package org.opendaylight.controller.sal.core.api.notify;
\ No newline at end of file
--- /dev/null
+/*
+ * 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
+ */
+/**
+ * Core binding-independent SAL contracts and components
+ */
+package org.opendaylight.controller.sal.core.api;
--- /dev/null
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"\r
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">\r
+ <modelVersion>4.0.0</modelVersion>\r
+ <parent>\r
+ <groupId>org.opendaylight.controller</groupId>\r
+ <artifactId>sal-parent</artifactId>\r
+ <version>1.0-SNAPSHOT</version>\r
+ </parent>\r
+ <artifactId>sal-broker-impl</artifactId>\r
+ <scm>\r
+ <connection>scm:git:ssh://git.opendaylight.org:29418/controller.git</connection>\r
+ <developerConnection>scm:git:ssh://git.opendaylight.org:29418/controller.git</developerConnection>\r
+ <url>https://wiki.opendaylight.org/view/OpenDaylight_Controller:MD-SAL</url>\r
+ </scm>\r
+\r
+ <dependencies>\r
+ <dependency>\r
+ <groupId>org.opendaylight.controller</groupId>\r
+ <artifactId>sal-core-api</artifactId>\r
+ <version>1.0-SNAPSHOT</version>\r
+ </dependency>\r
+ <dependency>\r
+ <groupId>org.opendaylight.controller</groupId>\r
+ <artifactId>sal-common-util</artifactId>\r
+ <version>1.0-SNAPSHOT</version>\r
+ </dependency>\r
+ <dependency>\r
+ <groupId>org.opendaylight.controller</groupId>\r
+ <artifactId>sal-core-spi</artifactId>\r
+ <version>1.0-SNAPSHOT</version>\r
+ </dependency>\r
+ <dependency>\r
+ <groupId>org.slf4j</groupId>\r
+ <artifactId>slf4j-api</artifactId>\r
+ </dependency>\r
+ <dependency>\r
+ <groupId>com.google.guava</groupId>\r
+ <artifactId>guava</artifactId>\r
+ </dependency>\r
+ </dependencies>\r
+\r
+ <build>\r
+ <plugins>\r
+ <plugin>\r
+ <groupId>org.apache.felix</groupId>\r
+ <artifactId>maven-bundle-plugin</artifactId>\r
+ <extensions>true</extensions>\r
+ <configuration>\r
+ <instructions>\r
+ <Bundle-Name>${project.groupId}.${project.artifactId}</Bundle-Name>\r
+ <Bundle-Activator>org.opendaylight.controller.sal.dom.broker.BrokerActivator</Bundle-Activator>\r
+ </instructions>\r
+ </configuration>\r
+ </plugin>\r
+ </plugins>\r
+ </build>\r
+</project>\r
--- /dev/null
+package org.opendaylight.controller.sal.dom.broker;
+
+import java.util.Hashtable;
+
+import org.opendaylight.controller.sal.core.api.Broker;
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceRegistration;
+
+public class BrokerActivator implements BundleActivator {
+
+ BrokerImpl broker;
+ private ServiceRegistration<Broker> brokerReg;
+
+ @Override
+ public void start(BundleContext context) throws Exception {
+ broker = new BrokerImpl();
+ broker.setBundleContext(context);
+ brokerReg = context.registerService(Broker.class, broker, new Hashtable<String,String>());
+ }
+
+ @Override
+ public void stop(BundleContext context) throws Exception {
+ if(brokerReg != null) {
+ brokerReg.unregister();
+ }
+ }
+}
--- /dev/null
+/*
+ * 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
+ */
+package org.opendaylight.controller.sal.dom.broker;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Future;
+import org.opendaylight.controller.sal.core.api.Broker;
+import org.opendaylight.controller.sal.core.api.BrokerService;
+import org.opendaylight.controller.sal.core.api.Consumer;
+import org.opendaylight.controller.sal.core.api.Provider;
+import org.opendaylight.controller.sal.core.api.RpcImplementation;
+import org.opendaylight.controller.sal.core.spi.BrokerModule;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.opendaylight.yangtools.yang.data.api.CompositeNode;
+import org.osgi.framework.BundleContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class BrokerImpl implements Broker {
+ private static Logger log = LoggerFactory.getLogger(BrokerImpl.class);
+
+ // Broker Generic Context
+ private Set<ConsumerSessionImpl> sessions = Collections
+ .synchronizedSet(new HashSet<ConsumerSessionImpl>());
+ private Set<ProviderSessionImpl> providerSessions = Collections
+ .synchronizedSet(new HashSet<ProviderSessionImpl>());
+ private Set<BrokerModule> modules = Collections
+ .synchronizedSet(new HashSet<BrokerModule>());
+ private Map<Class<? extends BrokerService>, BrokerModule> serviceProviders = Collections
+ .synchronizedMap(new HashMap<Class<? extends BrokerService>, BrokerModule>());
+
+ // RPC Context
+ private Map<QName, RpcImplementation> rpcImpls = Collections
+ .synchronizedMap(new HashMap<QName, RpcImplementation>());
+
+ // Implementation specific
+ private ExecutorService executor;
+
+ private BundleContext bundleContext;
+
+ @Override
+ public ConsumerSession registerConsumer(Consumer consumer,BundleContext ctx) {
+ checkPredicates(consumer);
+ log.info("Registering consumer " + consumer);
+ ConsumerSessionImpl session = newSessionFor(consumer,ctx);
+ consumer.onSessionInitiated(session);
+ sessions.add(session);
+ return session;
+ }
+
+ @Override
+ public ProviderSession registerProvider(Provider provider,BundleContext ctx) {
+ checkPredicates(provider);
+
+ ProviderSessionImpl session = newSessionFor(provider,ctx);
+ provider.onSessionInitiated(session);
+ providerSessions.add(session);
+ return session;
+ }
+
+ public void addModule(BrokerModule module) {
+ log.info("Registering broker module " + module);
+ if (modules.contains(module)) {
+ log.error("Module already registered");
+ throw new IllegalArgumentException("Module already exists.");
+ }
+
+ Set<Class<? extends BrokerService>> provServices = module
+ .getProvidedServices();
+ for (Class<? extends BrokerService> serviceType : provServices) {
+ log.info(" Registering session service implementation: "
+ + serviceType.getCanonicalName());
+ serviceProviders.put(serviceType, module);
+ }
+ }
+
+ public <T extends BrokerService> T serviceFor(Class<T> service,
+ ConsumerSessionImpl session) {
+ BrokerModule prov = serviceProviders.get(service);
+ if (prov == null) {
+ log.warn("Service " + service.toString() + " is not supported");
+ return null;
+ }
+ return prov.getServiceForSession(service, session);
+ }
+
+ // RPC Functionality
+
+ private void addRpcImplementation(QName rpcType,
+ RpcImplementation implementation) {
+ synchronized (rpcImpls) {
+ if (rpcImpls.get(rpcType) != null) {
+ throw new IllegalStateException("Implementation for rpc "
+ + rpcType + " is already registered.");
+ }
+ rpcImpls.put(rpcType, implementation);
+ }
+ // TODO Add notification for availability of Rpc Implementation
+ }
+
+ private void removeRpcImplementation(QName rpcType,
+ RpcImplementation implToRemove) {
+ synchronized (rpcImpls) {
+ if (implToRemove == rpcImpls.get(rpcType)) {
+ rpcImpls.remove(rpcType);
+ }
+ }
+ // TODO Add notification for removal of Rpc Implementation
+ }
+
+ private Future<RpcResult<CompositeNode>> invokeRpc(QName rpc,
+ CompositeNode input) {
+ RpcImplementation impl = rpcImpls.get(rpc);
+ // if()
+
+ Callable<RpcResult<CompositeNode>> call = callableFor(impl,
+ rpc, input);
+ Future<RpcResult<CompositeNode>> result = executor.submit(call);
+
+ return result;
+ }
+
+ // Validation
+
+ private void checkPredicates(Provider prov) {
+ if (prov == null)
+ throw new IllegalArgumentException("Provider should not be null.");
+ for (ProviderSessionImpl session : providerSessions) {
+ if (prov.equals(session.getProvider()))
+ throw new IllegalStateException("Provider already registered");
+ }
+
+ }
+
+ private void checkPredicates(Consumer cons) {
+ if (cons == null)
+ throw new IllegalArgumentException("Consumer should not be null.");
+ for (ConsumerSessionImpl session : sessions) {
+ if (cons.equals(session.getConsumer()))
+ throw new IllegalStateException("Consumer already registered");
+ }
+ }
+
+ // Private Factory methods
+
+ private ConsumerSessionImpl newSessionFor(Consumer provider, BundleContext ctx) {
+ return new ConsumerSessionImpl(provider,ctx);
+ }
+
+ private ProviderSessionImpl newSessionFor(Provider provider, BundleContext ctx) {
+ return new ProviderSessionImpl(provider,ctx);
+ }
+
+ private void consumerSessionClosed(ConsumerSessionImpl consumerSessionImpl) {
+ sessions.remove(consumerSessionImpl);
+ providerSessions.remove(consumerSessionImpl);
+ }
+
+ private static Callable<RpcResult<CompositeNode>> callableFor(
+ final RpcImplementation implemenation, final QName rpc,
+ final CompositeNode input) {
+
+ return new Callable<RpcResult<CompositeNode>>() {
+
+ @Override
+ public RpcResult<CompositeNode> call() throws Exception {
+ return implemenation.invokeRpc(rpc, input);
+ }
+ };
+ }
+
+ private class ConsumerSessionImpl implements ConsumerSession {
+
+ private final Consumer consumer;
+
+ private Map<Class<? extends BrokerService>, BrokerService> instantiatedServices = Collections
+ .synchronizedMap(new HashMap<Class<? extends BrokerService>, BrokerService>());
+ private boolean closed = false;
+
+ private BundleContext context;
+
+ public Consumer getConsumer() {
+ return consumer;
+ }
+
+ public ConsumerSessionImpl(Consumer consumer, BundleContext ctx) {
+ this.consumer = consumer;
+ this.context = ctx;
+ }
+
+ @Override
+ public Future<RpcResult<CompositeNode>> rpc(QName rpc,
+ CompositeNode input) {
+ return BrokerImpl.this.invokeRpc(rpc, input);
+ }
+
+ @Override
+ public <T extends BrokerService> T getService(Class<T> service) {
+ BrokerService potential = instantiatedServices.get(service);
+ if (potential != null) {
+ @SuppressWarnings("unchecked")
+ T ret = (T) potential;
+ return ret;
+ }
+ T ret = BrokerImpl.this.serviceFor(service, this);
+ if (ret != null) {
+ instantiatedServices.put(service, ret);
+ }
+ return ret;
+ }
+
+ @Override
+ public void close() {
+ Collection<BrokerService> toStop = instantiatedServices.values();
+ this.closed = true;
+ for (BrokerService brokerService : toStop) {
+ brokerService.closeSession();
+ }
+ BrokerImpl.this.consumerSessionClosed(this);
+ }
+
+ @Override
+ public boolean isClosed() {
+ return closed;
+ }
+
+ }
+
+ private class ProviderSessionImpl extends ConsumerSessionImpl implements
+ ProviderSession {
+
+ private Provider provider;
+ private Map<QName, RpcImplementation> sessionRpcImpls = Collections.synchronizedMap(new HashMap<QName, RpcImplementation>());
+
+ public ProviderSessionImpl(Provider provider, BundleContext ctx) {
+ super(null,ctx);
+ this.provider = provider;
+ }
+
+ @Override
+ public void addRpcImplementation(QName rpcType,
+ RpcImplementation implementation)
+ throws IllegalArgumentException {
+ if (rpcType == null) {
+ throw new IllegalArgumentException("rpcType must not be null");
+ }
+ if (implementation == null) {
+ throw new IllegalArgumentException(
+ "Implementation must not be null");
+ }
+ BrokerImpl.this.addRpcImplementation(rpcType, implementation);
+ sessionRpcImpls.put(rpcType, implementation);
+ }
+
+ @Override
+ public void removeRpcImplementation(QName rpcType,
+ RpcImplementation implToRemove) throws IllegalArgumentException {
+ RpcImplementation localImpl = rpcImpls.get(rpcType);
+ if (localImpl != implToRemove) {
+ throw new IllegalStateException(
+ "Implementation was not registered in this session");
+ }
+
+ BrokerImpl.this.removeRpcImplementation(rpcType, implToRemove);
+ sessionRpcImpls.remove(rpcType);
+ }
+
+ public Provider getProvider() {
+ return this.provider;
+ }
+
+ }
+
+ public void setBundleContext(BundleContext context) {
+ this.bundleContext = context;
+ }
+}
--- /dev/null
+/*
+ * 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
+ */
+package org.opendaylight.controller.sal.dom.broker;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Future;
+
+import org.opendaylight.controller.sal.common.DataStoreIdentifier;
+import org.opendaylight.controller.sal.common.util.Rpcs;
+import org.opendaylight.controller.sal.core.api.BrokerService;
+import org.opendaylight.controller.sal.core.api.Broker.ConsumerSession;
+import org.opendaylight.controller.sal.core.api.Broker.ProviderSession;
+import org.opendaylight.controller.sal.core.api.Consumer.ConsumerFunctionality;
+import org.opendaylight.controller.sal.core.api.Provider.ProviderFunctionality;
+import org.opendaylight.controller.sal.core.api.data.DataBrokerService;
+import org.opendaylight.controller.sal.core.api.data.DataCommitHandler;
+import org.opendaylight.controller.sal.core.api.data.DataProviderService;
+import org.opendaylight.controller.sal.core.api.data.DataValidator;
+import org.opendaylight.controller.sal.core.api.data.DataCommitHandler.CommitTransaction;
+import org.opendaylight.controller.sal.core.api.data.DataProviderService.DataRefresher;
+import org.opendaylight.controller.sal.core.spi.BrokerModule;
+import org.opendaylight.yangtools.yang.common.RpcError;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.opendaylight.yangtools.yang.data.api.CompositeNode;
+import org.opendaylight.yangtools.yang.data.api.MutableCompositeNode;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.collect.ImmutableSet;
+
+public class DataBrokerModule implements BrokerModule {
+
+ private static final Logger log = LoggerFactory
+ .getLogger(DataBrokerModule.class);
+
+ private static final Set<Class<? extends ProviderFunctionality>> SUPPORTED_PROVIDER_FUNCTIONALITY = ImmutableSet
+ .of((Class<? extends ProviderFunctionality>) DataValidator.class,
+ DataRefresher.class, DataCommitHandler.class);
+
+ private static final Set<Class<? extends BrokerService>> PROVIDED_SESSION_SERVICES = ImmutableSet
+ .of((Class<? extends BrokerService>) DataBrokerService.class,
+ DataProviderService.class);
+
+ private Map<DataStoreIdentifier, StoreContext> storeContext;
+
+ private ExecutorService executor;
+
+ private SequentialCommitHandlerCoordinator coordinator = new SequentialCommitHandlerCoordinator();
+
+ @Override
+ public Set<Class<? extends BrokerService>> getProvidedServices() {
+ return PROVIDED_SESSION_SERVICES;
+ }
+
+ @Override
+ public Set<Class<? extends ProviderFunctionality>> getSupportedProviderFunctionality() {
+ return SUPPORTED_PROVIDER_FUNCTIONALITY;
+ }
+
+ @Override
+ public Set<Class<? extends ConsumerFunctionality>> getSupportedConsumerFunctionality() {
+ return Collections.emptySet();
+ }
+
+ @Override
+ public <T extends BrokerService> T getServiceForSession(Class<T> service,
+ ConsumerSession session) {
+ if (DataProviderService.class.equals(service)
+ && session instanceof ProviderSession) {
+ @SuppressWarnings("unchecked")
+ T ret = (T) newDataProviderService(session);
+ return ret;
+ } else if (DataBrokerService.class.equals(service)) {
+
+ @SuppressWarnings("unchecked")
+ T ret = (T) newDataConsumerService(session);
+ return ret;
+ }
+
+ throw new IllegalArgumentException(
+ "The requested session-specific service is not provided by this module.");
+ }
+
+ private DataProviderService newDataProviderService(ConsumerSession session) {
+ return new DataProviderSession();
+ }
+
+ private DataBrokerService newDataConsumerService(ConsumerSession session) {
+ return new DataConsumerSession();
+ }
+
+ private StoreContext context(DataStoreIdentifier store) {
+ return storeContext.get(store);
+ }
+
+ private static class StoreContext {
+ private Set<DataCommitHandler> commitHandlers = Collections
+ .synchronizedSet(new HashSet<DataCommitHandler>());
+ private Set<DataValidator> validators = Collections
+ .synchronizedSet(new HashSet<DataValidator>());
+ private Set<DataRefresher> refreshers = Collections
+ .synchronizedSet(new HashSet<DataRefresher>());
+ }
+
+ private class DataConsumerSession implements DataBrokerService {
+
+ @Override
+ public CompositeNode getData(DataStoreIdentifier store) {
+ // TODO Implement this method
+ throw new UnsupportedOperationException("Not implemented");
+ }
+
+ @Override
+ public CompositeNode getData(DataStoreIdentifier store,
+ CompositeNode filter) {
+ // TODO Implement this method
+ throw new UnsupportedOperationException("Not implemented");
+ }
+
+ @Override
+ public CompositeNode getCandidateData(DataStoreIdentifier store) {
+ // TODO Implement this method
+ throw new UnsupportedOperationException("Not implemented");
+ }
+
+ @Override
+ public CompositeNode getCandidateData(DataStoreIdentifier store,
+ CompositeNode filter) {
+ // TODO Implement this method
+ throw new UnsupportedOperationException("Not implemented");
+ }
+
+ @Override
+ public RpcResult<CompositeNode> editCandidateData(
+ DataStoreIdentifier store, MutableCompositeNode changeSet) {
+ // TODO Implement this method
+ throw new UnsupportedOperationException("Not implemented");
+ }
+
+ @Override
+ public Future<RpcResult<Void>> commit(DataStoreIdentifier store) {
+ // TODO Implement this method
+ throw new UnsupportedOperationException("Not implemented");
+ }
+
+ @Override
+ public void closeSession() {
+ // TODO Implement this method
+ throw new UnsupportedOperationException("Not implemented");
+ }
+
+ @Override
+ public Set<DataStoreIdentifier> getDataStores() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ }
+
+ private class DataProviderSession extends DataConsumerSession implements
+ DataProviderService {
+
+ private Set<DataCommitHandler> providerCommitHandlers = new HashSet<DataCommitHandler>();
+ private Set<DataValidator> providerValidators = new HashSet<DataValidator>();
+ private Set<DataRefresher> providerRefreshers = new HashSet<DataRefresher>();
+
+ @Override
+ public void addValidator(DataStoreIdentifier store,
+ DataValidator validator) {
+ if (validator == null)
+ throw new IllegalArgumentException(
+ "Validator should not be null");
+
+ providerValidators.add(validator);
+ context(store).validators.add(validator);
+ }
+
+ @Override
+ public void removeValidator(DataStoreIdentifier store,
+ DataValidator validator) {
+ if (validator == null)
+ throw new IllegalArgumentException(
+ "Validator should not be null");
+
+ providerValidators.remove(validator);
+ context(store).validators.remove(validator);
+ }
+
+ @Override
+ public void addCommitHandler(DataStoreIdentifier store,
+ DataCommitHandler provider) {
+ if (provider == null)
+ throw new IllegalArgumentException(
+ "CommitHandler should not be null");
+
+ providerCommitHandlers.add(provider);
+ context(store).commitHandlers.add(provider);
+ }
+
+ @Override
+ public void removeCommitHandler(DataStoreIdentifier store,
+ DataCommitHandler provider) {
+ if (provider == null)
+ throw new IllegalArgumentException(
+ "CommitHandler should not be null");
+
+ providerCommitHandlers.remove(provider);
+ context(store).commitHandlers.remove(provider);
+ }
+
+ @Override
+ public void addRefresher(DataStoreIdentifier store,
+ DataRefresher provider) {
+ if (provider == null)
+ throw new IllegalArgumentException(
+ "Refresher should not be null");
+
+ providerRefreshers.add(provider);
+ context(store).refreshers.add(provider);
+ }
+
+ @Override
+ public void removeRefresher(DataStoreIdentifier store,
+ DataRefresher provider) {
+ if (provider == null)
+ throw new IllegalArgumentException(
+ "Refresher should not be null");
+
+ providerRefreshers.remove(provider);
+ context(store).refreshers.remove(provider);
+ }
+
+ }
+
+ private class SequentialCommitHandlerCoordinator implements
+ DataCommitHandler {
+
+ @Override
+ public RpcResult<CommitTransaction> requestCommit(
+ DataStoreIdentifier store) {
+ List<RpcError> errors = new ArrayList<RpcError>();
+ Set<CommitTransaction> transactions = new HashSet<DataCommitHandler.CommitTransaction>();
+ boolean successful = true;
+
+ for (DataCommitHandler commitHandler : context(store).commitHandlers) {
+ try {
+ RpcResult<CommitTransaction> partialResult = commitHandler
+ .requestCommit(store);
+ successful = partialResult.isSuccessful() & successful;
+ if (partialResult.isSuccessful()) {
+ transactions.add(partialResult.getResult());
+ }
+
+ errors.addAll(partialResult.getErrors());
+ } catch (Exception e) {
+ log.error("Uncaught exception prevented commit request."
+ + e.getMessage(), e);
+ successful = false;
+ // FIXME: Add RPC Error with exception.
+ }
+ if (successful == false)
+ break;
+ }
+ CommitTransaction transaction = new SequentialCommitTransaction(
+ store, transactions);
+ return Rpcs.getRpcResult(successful, transaction, errors);
+ }
+
+ @Override
+ public Set<DataStoreIdentifier> getSupportedDataStores() {
+ return Collections.emptySet();
+ }
+ }
+
+ private class SequentialCommitTransaction implements CommitTransaction {
+
+ final Set<CommitTransaction> transactions;
+ final DataStoreIdentifier store;
+
+ public SequentialCommitTransaction(DataStoreIdentifier s,
+ Set<CommitTransaction> t) {
+ transactions = t;
+ store = s;
+ }
+
+ @Override
+ public RpcResult<Void> finish() {
+ List<RpcError> errors = new ArrayList<RpcError>();
+ boolean successful = true;
+
+ for (CommitTransaction commitHandler : transactions) {
+ try {
+ RpcResult<Void> partialResult = commitHandler.finish();
+ successful = partialResult.isSuccessful() & successful;
+ errors.addAll(partialResult.getErrors());
+ } catch (Exception e) {
+ log.error(
+ "Uncaught exception prevented finishing of commit."
+ + e.getMessage(), e);
+ successful = false;
+ // FIXME: Add RPC Error with exception.
+ }
+ if (successful == false)
+ break;
+ }
+
+ return Rpcs.getRpcResult(successful, null, errors);
+ }
+
+ @Override
+ public RpcResult<Void> rollback() {
+ List<RpcError> errors = new ArrayList<RpcError>();
+ boolean successful = true;
+
+ for (CommitTransaction commitHandler : transactions) {
+ try {
+ RpcResult<Void> partialResult = commitHandler.rollback();
+ successful = partialResult.isSuccessful() & successful;
+ errors.addAll(partialResult.getErrors());
+ } catch (Exception e) {
+ log.error(
+ "Uncaught exception prevented rollback of commit."
+ + e.getMessage(), e);
+ successful = false;
+ // FIXME: Add RPC Error with exception.
+ }
+ if (successful == false)
+ break;
+ }
+
+ return Rpcs.getRpcResult(successful, null, errors);
+ }
+
+ @Override
+ public DataStoreIdentifier getDataStore() {
+ return this.store;
+ }
+
+ @Override
+ public DataCommitHandler getHandler() {
+ return coordinator;
+ }
+ }
+
+ private class ValidationCoordinator implements DataValidator {
+
+ private final DataStoreIdentifier store;
+
+ ValidationCoordinator(DataStoreIdentifier store) {
+ this.store = store;
+ }
+
+ @Override
+ public RpcResult<Void> validate(CompositeNode toValidate) {
+ List<RpcError> errors = new ArrayList<RpcError>();
+ boolean successful = true;
+
+ for (DataValidator validator : context(store).validators) {
+ try {
+ RpcResult<Void> partialResult = validator
+ .validate(toValidate);
+ successful = partialResult.isSuccessful() & successful;
+ errors.addAll(partialResult.getErrors());
+ } catch (Exception e) {
+ log.error(
+ "Uncaught exception prevented validation."
+ + e.getMessage(), e);
+ successful = false;
+ // FIXME: Add RPC Error with exception.
+ }
+ if (successful == false)
+ break;
+ }
+
+ return Rpcs.getRpcResult(successful, null, errors);
+ }
+
+ @Override
+ public Set<DataStoreIdentifier> getSupportedDataStores() {
+ return Collections.emptySet();
+ }
+
+ }
+
+ private class DataRefreshCoordinator implements DataRefresher {
+
+ private final DataStoreIdentifier store;
+
+ DataRefreshCoordinator(DataStoreIdentifier store) {
+ this.store = store;
+ }
+
+ @Override
+ public void refreshData() {
+
+ for (DataRefresher refresher : context(store).refreshers) {
+ try {
+ refresher.refreshData();
+ } catch (Exception e) {
+ log.error(
+ "Uncaught exception during refresh of data: "
+ + e.getMessage(), e);
+ }
+
+ }
+ }
+ }
+}
--- /dev/null
+/*
+ * 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
+ */
+package org.opendaylight.controller.sal.dom.broker;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+
+import org.opendaylight.controller.sal.core.api.BrokerService;
+import org.opendaylight.controller.sal.core.api.Broker.ConsumerSession;
+import org.opendaylight.controller.sal.core.api.Broker.ProviderSession;
+import org.opendaylight.controller.sal.core.api.Consumer.ConsumerFunctionality;
+import org.opendaylight.controller.sal.core.api.Provider.ProviderFunctionality;
+import org.opendaylight.controller.sal.core.api.notify.NotificationListener;
+import org.opendaylight.controller.sal.core.api.notify.NotificationProviderService;
+import org.opendaylight.controller.sal.core.api.notify.NotificationService;
+import org.opendaylight.controller.sal.core.spi.BrokerModule;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.CompositeNode;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.collect.HashMultimap;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Multimap;
+
+public class NotificationModule implements BrokerModule {
+ private static Logger log = LoggerFactory
+ .getLogger(NotificationModule.class);
+
+ private Multimap<QName, NotificationListener> listeners = HashMultimap
+ .create();
+
+ private static final Set<Class<? extends BrokerService>> PROVIDED_SERVICE_TYPE = ImmutableSet
+ .of((Class<? extends BrokerService>) NotificationService.class,
+ NotificationProviderService.class);
+
+ private static final Set<Class<? extends ConsumerFunctionality>> SUPPORTED_CONSUMER_FUNCTIONALITY = ImmutableSet
+ .of((Class<? extends ConsumerFunctionality>) NotificationListener.class,
+ NotificationListener.class); // Workaround: if we use the
+ // version of method with only
+ // one argument, the generics
+ // inference will not work
+
+ @Override
+ public Set<Class<? extends BrokerService>> getProvidedServices() {
+ return PROVIDED_SERVICE_TYPE;
+ }
+
+ @Override
+ public Set<Class<? extends ConsumerFunctionality>> getSupportedConsumerFunctionality() {
+ return SUPPORTED_CONSUMER_FUNCTIONALITY;
+ }
+
+ @Override
+ public <T extends BrokerService> T getServiceForSession(Class<T> service,
+ ConsumerSession session) {
+ if (NotificationProviderService.class.equals(service)
+ && session instanceof ProviderSession) {
+ @SuppressWarnings("unchecked")
+ T ret = (T) newNotificationProviderService(session);
+ return ret;
+ } else if (NotificationService.class.equals(service)) {
+
+ @SuppressWarnings("unchecked")
+ T ret = (T) newNotificationConsumerService(session);
+ return ret;
+ }
+
+ throw new IllegalArgumentException(
+ "The requested session-specific service is not provided by this module.");
+ }
+
+ private void sendNotification(CompositeNode notification) {
+ QName type = notification.getNodeType();
+ Collection<NotificationListener> toNotify = listeners.get(type);
+ log.info("Publishing notification " + type);
+
+ if (toNotify == null) {
+ // No listeners were registered - returns.
+ return;
+ }
+
+ for (NotificationListener listener : toNotify) {
+ try {
+ // FIXME: ensure that notification is immutable
+ listener.onNotification(notification);
+ } catch (Exception e) {
+ log.error("Uncaught exception in NotificationListener", e);
+ }
+ }
+
+ }
+
+ private NotificationService newNotificationConsumerService(
+ ConsumerSession session) {
+ return new NotificationConsumerSessionImpl();
+ }
+
+ private NotificationProviderService newNotificationProviderService(
+ ConsumerSession session) {
+ return new NotificationProviderSessionImpl();
+ }
+
+ private class NotificationConsumerSessionImpl implements
+ NotificationService {
+
+ private Multimap<QName, NotificationListener> consumerListeners = HashMultimap
+ .create();
+ private boolean closed = false;
+
+ @Override
+ public void addNotificationListener(QName notification,
+ NotificationListener listener) {
+ checkSessionState();
+ if (notification == null) {
+ throw new IllegalArgumentException(
+ "Notification type must not be null.");
+ }
+ if (listener == null) {
+ throw new IllegalArgumentException("Listener must not be null.");
+ }
+
+ consumerListeners.put(notification, listener);
+ listeners.put(notification, listener);
+ log.info("Registered listener for notification: " + notification);
+ }
+
+ @Override
+ public void removeNotificationListener(QName notification,
+ NotificationListener listener) {
+ checkSessionState();
+ if (notification == null) {
+ throw new IllegalArgumentException(
+ "Notification type must not be null.");
+ }
+ if (listener == null) {
+ throw new IllegalArgumentException("Listener must not be null.");
+ }
+ consumerListeners.remove(notification, listener);
+ listeners.remove(notification, listener);
+ }
+
+ @Override
+ public void closeSession() {
+ closed = true;
+ Map<QName, Collection<NotificationListener>> toRemove = consumerListeners
+ .asMap();
+ for (Entry<QName, Collection<NotificationListener>> entry : toRemove
+ .entrySet()) {
+ listeners.remove(entry.getKey(), entry.getValue());
+ }
+ }
+
+ protected void checkSessionState() {
+ if (closed)
+ throw new IllegalStateException("Session is closed");
+ }
+ }
+
+ private class NotificationProviderSessionImpl extends
+ NotificationConsumerSessionImpl implements
+ NotificationProviderService {
+
+ @Override
+ public void sendNotification(CompositeNode notification) {
+ checkSessionState();
+ if (notification == null)
+ throw new IllegalArgumentException(
+ "Notification must not be null.");
+ NotificationModule.this.sendNotification(notification);
+ }
+ }
+
+ @Override
+ public Set<Class<? extends ProviderFunctionality>> getSupportedProviderFunctionality() {
+ return Collections.emptySet();
+ }
+}
--- /dev/null
+/*
+ * 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
+ */
+package org.opendaylight.controller.sal.dom.broker;
\ No newline at end of file
--- /dev/null
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">\r
+ <modelVersion>4.0.0</modelVersion>\r
+ <parent>\r
+ <groupId>org.opendaylight.controller</groupId>\r
+ <artifactId>sal-parent</artifactId>\r
+ <version>1.0-SNAPSHOT</version>\r
+ </parent>\r
+ <artifactId>sal-core-spi</artifactId>\r
+ <scm>\r
+ <connection>scm:git:ssh://git.opendaylight.org:29418/controller.git</connection>\r
+ <developerConnection>scm:git:ssh://git.opendaylight.org:29418/controller.git</developerConnection>\r
+ <url>https://wiki.opendaylight.org/view/OpenDaylight_Controller:MD-SAL</url>\r
+ </scm>\r
+ \r
+ <dependencies>\r
+ <dependency>\r
+ <groupId>org.opendaylight.controller</groupId>\r
+ <artifactId>sal-core-api</artifactId>\r
+ <version>1.0-SNAPSHOT</version>\r
+ </dependency>\r
+ </dependencies>\r
+</project>\r
--- /dev/null
+/*\r
+ * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.\r
+ *\r
+ * This program and the accompanying materials are made available under the\r
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,\r
+ * and is available at http://www.eclipse.org/legal/epl-v10.html\r
+ */\r
+package org.opendaylight.controller.sal.core.spi;\r
+\r
+import java.util.Set;\r
+\r
+import org.opendaylight.controller.sal.core.api.BrokerService;\r
+import org.opendaylight.controller.sal.core.api.Broker.ConsumerSession;\r
+import org.opendaylight.controller.sal.core.api.Consumer.ConsumerFunctionality;\r
+import org.opendaylight.controller.sal.core.api.Provider.ProviderFunctionality;\r
+\r
+public interface BrokerModule {\r
+\r
+ Set<Class<? extends BrokerService>> getProvidedServices();\r
+\r
+ Set<Class<? extends ConsumerFunctionality>> getSupportedConsumerFunctionality();\r
+\r
+ <T extends BrokerService> T getServiceForSession(Class<T> service,\r
+ ConsumerSession session);\r
+\r
+ Set<Class<? extends ProviderFunctionality>> getSupportedProviderFunctionality();\r
+}\r
--- /dev/null
+/*\r
+ * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.\r
+ *\r
+ * This program and the accompanying materials are made available under the\r
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,\r
+ * and is available at http://www.eclipse.org/legal/epl-v10.html\r
+ */\r
+package org.opendaylight.controller.sal.core.spi;
\ No newline at end of file