/* * Copyright (c) 2016 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.groupbasedpolicy.sxp.ep.provider.impl.dao; import com.google.common.base.Function; import com.google.common.base.Optional; import com.google.common.util.concurrent.AsyncFunction; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import java.util.Collection; import java.util.Collections; import javax.annotation.Nonnull; import javax.annotation.Nullable; import org.opendaylight.controller.md.sal.binding.api.DataBroker; import org.opendaylight.controller.md.sal.binding.api.WriteTransaction; import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; import org.opendaylight.groupbasedpolicy.sxp.ep.provider.api.EPPolicyTemplateDaoFacade; import org.opendaylight.groupbasedpolicy.sxp.ep.provider.api.EPPolicyTemplateProvider; import org.opendaylight.groupbasedpolicy.sxp.ep.provider.impl.SgtGeneratorImpl; import org.opendaylight.groupbasedpolicy.sxp.ep.provider.impl.SimpleCachedDao; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.groupbasedpolicy.sxp.integration.sxp.ep.provider.model.rev160302.SxpEpMapper; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.groupbasedpolicy.sxp.integration.sxp.ep.provider.model.rev160302.TemplateGenerated; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.groupbasedpolicy.sxp.integration.sxp.ep.provider.model.rev160302.sxp.ep.mapper.EndpointPolicyTemplateBySgt; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.groupbasedpolicy.sxp.integration.sxp.ep.provider.model.rev160302.sxp.ep.mapper.EndpointPolicyTemplateBySgtBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.groupbasedpolicy.sxp.integration.sxp.ep.provider.model.rev160302.sxp.ep.mapper.EndpointPolicyTemplateBySgtKey; import org.opendaylight.yang.gen.v1.urn.opendaylight.sxp.database.rev160308.Sgt; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Purpose: add template provider fallback to {@link EPPolicyTemplateDaoImpl} */ public class EPPolicyTemplateDaoFacadeImpl implements EPPolicyTemplateDaoFacade { private static final Logger LOG = LoggerFactory.getLogger(EPPolicyTemplateDaoFacadeImpl.class); private final EPPolicyTemplateDaoImpl epPolicyTemplateDao; private final SimpleCachedDao<Sgt, EndpointPolicyTemplateBySgt> epPolicyTemplateCachedDao; private final SgtGeneratorImpl sgtGenerator; private final DataBroker dataBroker; private EPPolicyTemplateProvider templateProvider; public EPPolicyTemplateDaoFacadeImpl(final DataBroker dataBroker, final EPPolicyTemplateDaoImpl epPolicyTemplateDao, final SimpleCachedDao<Sgt, EndpointPolicyTemplateBySgt> epPolicyTemplateCachedDao, final SgtGeneratorImpl sgtGenerator) { this.dataBroker = dataBroker; this.epPolicyTemplateDao = epPolicyTemplateDao; this.epPolicyTemplateCachedDao = epPolicyTemplateCachedDao; this.sgtGenerator = sgtGenerator; } @Override public void setTemplateProvider(final EPPolicyTemplateProvider templateProvider) { this.templateProvider = templateProvider; } @Override public ListenableFuture<Optional<EndpointPolicyTemplateBySgt>> read(@Nonnull final Sgt key) { // read from delegate final ListenableFuture<Optional<EndpointPolicyTemplateBySgt>> templateFu = epPolicyTemplateDao.read(key); // involve fallback if template is absent return Futures.transform(templateFu, new AsyncFunction<Optional<EndpointPolicyTemplateBySgt>, Optional<EndpointPolicyTemplateBySgt>>() { @Override public ListenableFuture<Optional<EndpointPolicyTemplateBySgt>> apply( @Nonnull final Optional<EndpointPolicyTemplateBySgt> templateOpt) throws Exception { return templateOpt.transform(template -> Futures.immediateFuture(templateOpt)) // failed to read template -> invoke fallback if available .or(() -> java.util.Optional.ofNullable(templateProvider) .map(provider -> templateProvider.provideTemplate(key)) .map(template -> rewrapOptionalToGuavaOptional(template)) .orElse(Futures.immediateFuture(Optional.absent())) ); } }); } private <T> ListenableFuture<Optional<T>> rewrapOptionalToGuavaOptional(final ListenableFuture<java.util.Optional<T>> templateFu) { return Futures.transform(templateFu, new Function<java.util.Optional<T>, Optional<T>>() { @Nullable @Override public Optional<T> apply(@Nullable final java.util.Optional<T> input) { return java.util.Optional.ofNullable(input) .map(origNonnullInput -> Optional.fromNullable(origNonnullInput.orElse(null))) .orElse(Optional.absent()); } } ); } private Function<Void, Collection<EndpointPolicyTemplateBySgt>> createStoreOutcomeHandlerToCollection(final EndpointPolicyTemplateBySgt template) { return new Function<Void, Collection<EndpointPolicyTemplateBySgt>>() { @Nullable @Override public Collection<EndpointPolicyTemplateBySgt> apply(@Nullable final Void aVoid) { return Collections.singletonList(template); } }; } @Override public ListenableFuture<Collection<EndpointPolicyTemplateBySgt>> readBy(@Nonnull final EpPolicyTemplateValueKey templateLookupKey) { //TODO: expose to ios-xe renderer, final Collection<EndpointPolicyTemplateBySgt> templatesFromDao = epPolicyTemplateDao.readBy(templateLookupKey); final ListenableFuture<Collection<EndpointPolicyTemplateBySgt>> result; if (!templatesFromDao.isEmpty()) { result = Futures.immediateFuture(templatesFromDao); } else { // generate result = sgtGenerator.generateNextSgt(epPolicyTemplateCachedDao) // build ep-policy-template .map(sgt -> buildEpPolicyTemplate(templateLookupKey, sgt)) // store the template .map(this::storeTemplate) .orElse(Futures.immediateFuture(Collections.emptyList())); } return result; } private ListenableFuture<Collection<EndpointPolicyTemplateBySgt>> storeTemplate(final EndpointPolicyTemplateBySgt template) { final WriteTransaction wTx = dataBroker.newWriteOnlyTransaction(); // store ep-policy-template final Sgt sgt = template.getSgt(); LOG.trace("storing generated epPolicyTemplate: {}", sgt.getValue()); final InstanceIdentifier<EndpointPolicyTemplateBySgt> epPolicyTemplatePath = InstanceIdentifier .create(SxpEpMapper.class) .child(EndpointPolicyTemplateBySgt.class, new EndpointPolicyTemplateBySgtKey(sgt)); wTx.put(LogicalDatastoreType.CONFIGURATION, epPolicyTemplatePath, template, true); return Futures.transform(wTx.submit(), createStoreOutcomeHandlerToCollection(template)); } private EndpointPolicyTemplateBySgt buildEpPolicyTemplate(final EpPolicyTemplateValueKey templateLookupKey, final Sgt sgt) { return new EndpointPolicyTemplateBySgtBuilder() .setOrigin(TemplateGenerated.class) .setTenant(templateLookupKey.getTenantId()) .setSgt(sgt) .setEndpointGroups(templateLookupKey.getEpgId()) .setConditions(templateLookupKey.getConditionName()) .build(); } }