/** * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0 which accompanies this distribution, * and is available at http://www.eclipse.org/legal/epl-v10.html */ package org.opendaylight.controller.sal.restconf.impl; import com.google.common.util.concurrent.Futures; import java.util.Collections; import java.util.concurrent.Future; import javax.ws.rs.core.Response.Status; import org.opendaylight.controller.md.sal.common.api.TransactionStatus; import org.opendaylight.controller.md.sal.common.api.data.DataReader; import org.opendaylight.controller.sal.common.util.Rpcs; import org.opendaylight.controller.sal.core.api.Broker.ConsumerSession; import org.opendaylight.controller.sal.core.api.data.DataBrokerService; import org.opendaylight.controller.sal.core.api.data.DataChangeListener; import org.opendaylight.controller.sal.core.api.data.DataModificationTransaction; import org.opendaylight.controller.sal.core.api.mount.MountInstance; import org.opendaylight.controller.sal.restconf.impl.RestconfError.ErrorTag; import org.opendaylight.controller.sal.restconf.impl.RestconfError.ErrorType; import org.opendaylight.controller.sal.streams.listeners.ListenerAdapter; import org.opendaylight.yangtools.concepts.ListenerRegistration; import org.opendaylight.yangtools.yang.common.QName; 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.InstanceIdentifier; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class BrokerFacade implements DataReader { private final static Logger LOG = LoggerFactory.getLogger( BrokerFacade.class ); private final static BrokerFacade INSTANCE = new BrokerFacade(); private volatile DataBrokerService dataService; private volatile ConsumerSession context; private BrokerFacade() { } public void setContext( final ConsumerSession context ) { this.context = context; } public void setDataService( final DataBrokerService dataService ) { this.dataService = dataService; } public static BrokerFacade getInstance() { return BrokerFacade.INSTANCE; } private void checkPreconditions() { if( context == null || dataService == null ) { throw new RestconfDocumentedException( Status.SERVICE_UNAVAILABLE ); } } @Override public CompositeNode readConfigurationData( final InstanceIdentifier path ) { this.checkPreconditions(); LOG.trace( "Read Configuration via Restconf: {}", path ); return dataService.readConfigurationData( path ); } public CompositeNode readConfigurationDataBehindMountPoint( final MountInstance mountPoint, final InstanceIdentifier path ) { this.checkPreconditions(); LOG.trace( "Read Configuration via Restconf: {}", path ); return mountPoint.readConfigurationData( path ); } @Override public CompositeNode readOperationalData( final InstanceIdentifier path ) { this.checkPreconditions(); BrokerFacade.LOG.trace( "Read Operational via Restconf: {}", path ); return dataService.readOperationalData( path ); } public CompositeNode readOperationalDataBehindMountPoint( final MountInstance mountPoint, final InstanceIdentifier path ) { this.checkPreconditions(); BrokerFacade.LOG.trace( "Read Operational via Restconf: {}", path ); return mountPoint.readOperationalData( path ); } public Future> invokeRpc( final QName type, final CompositeNode payload ) { this.checkPreconditions(); return context.rpc( type, payload ); } public Future> commitConfigurationDataPut( final InstanceIdentifier path, final CompositeNode payload ) { this.checkPreconditions(); final DataModificationTransaction transaction = dataService.beginTransaction(); BrokerFacade.LOG.trace( "Put Configuration via Restconf: {}", path ); transaction.putConfigurationData( path, payload ); return transaction.commit(); } public Future> commitConfigurationDataPutBehindMountPoint( final MountInstance mountPoint, final InstanceIdentifier path, final CompositeNode payload ) { this.checkPreconditions(); final DataModificationTransaction transaction = mountPoint.beginTransaction(); BrokerFacade.LOG.trace( "Put Configuration via Restconf: {}", path ); transaction.putConfigurationData( path, payload ); return transaction.commit(); } public Future> commitConfigurationDataPost( final InstanceIdentifier path, final CompositeNode payload) { this.checkPreconditions(); final DataModificationTransaction transaction = dataService.beginTransaction(); /* check for available Node in Configuration DataStore by path */ CompositeNode availableNode = transaction.readConfigurationData( path ); if (availableNode != null) { String errMsg = "Post Configuration via Restconf was not executed because data already exists"; BrokerFacade.LOG.warn((new StringBuilder(errMsg)).append(" : ").append(path).toString()); throw new RestconfDocumentedException( "Data already exists for path: " + path, ErrorType.PROTOCOL, ErrorTag.DATA_EXISTS ); } BrokerFacade.LOG.trace( "Post Configuration via Restconf: {}", path ); transaction.putConfigurationData( path, payload ); return transaction.commit(); } public Future> commitConfigurationDataPostBehindMountPoint( final MountInstance mountPoint, final InstanceIdentifier path, final CompositeNode payload ) { this.checkPreconditions(); final DataModificationTransaction transaction = mountPoint.beginTransaction(); /* check for available Node in Configuration DataStore by path */ CompositeNode availableNode = transaction.readConfigurationData( path ); if (availableNode != null) { String errMsg = "Post Configuration via Restconf was not executed because data already exists"; BrokerFacade.LOG.warn((new StringBuilder(errMsg)).append(" : ").append(path).toString()); throw new RestconfDocumentedException( "Data already exists for path: " + path, ErrorType.PROTOCOL, ErrorTag.DATA_EXISTS ); } BrokerFacade.LOG.trace( "Post Configuration via Restconf: {}", path ); transaction.putConfigurationData( path, payload ); return transaction.commit(); } public Future> commitConfigurationDataDelete( final InstanceIdentifier path ) { this.checkPreconditions(); return deleteDataAtTarget(path,dataService.beginTransaction()); } public Future> commitConfigurationDataDeleteBehindMountPoint( final MountInstance mountPoint, final InstanceIdentifier path ) { this.checkPreconditions(); return deleteDataAtTarget(path,mountPoint.beginTransaction()); } private Future> deleteDataAtTarget(final InstanceIdentifier path, final DataModificationTransaction transaction) { LOG.info("Delete Configuration via Restconf: {}", path); CompositeNode redDataAtPath = transaction.readConfigurationData(path); if (redDataAtPath == null) { return Futures.immediateFuture(Rpcs. getRpcResult(true, TransactionStatus.COMMITED, Collections. emptyList())); } transaction.removeConfigurationData(path); return transaction.commit(); } public void registerToListenDataChanges( final ListenerAdapter listener ) { this.checkPreconditions(); if( listener.isListening() ) { return; } InstanceIdentifier path = listener.getPath(); final ListenerRegistration registration = dataService.registerDataChangeListener( path, listener ); listener.setRegistration( registration ); } }