/*
* 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.openflowplugin.openflow.md.core.sal.convertor.common;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
import org.opendaylight.openflowplugin.openflow.md.core.sal.convertor.ConvertorExecutor;
import org.opendaylight.yangtools.yang.binding.DataContainer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Processes source and return result based on convertor cases added to this processor.
*
* @param <FROM> the source type
* @param <TO> the result type
* @param <DATA> the type of convertor data
*/
public class ConvertorProcessor<FROM extends DataContainer, TO, DATA extends ConvertorData> {
private static final short OFP_VERSION_ALL = 0x00;
private static final Logger LOG = LoggerFactory.getLogger(ConvertorProcessor.class);
private final Map<Short, Map<Class<?>, ConvertorCase<?, TO, DATA>>> conversions = new ConcurrentHashMap<>();
private ConvertorCase<?, TO, DATA> defaultCase;
/**
* Add convertor processor case.
*
* @param processorCase the processor case
* @return the convertor processor
*/
public ConvertorProcessor<FROM, TO, DATA> addCase(final ConvertorCase<?, TO, DATA> processorCase) {
if (processorCase.getSupportedVersions().isEmpty()) {
getCasesForVersion(OFP_VERSION_ALL).putIfAbsent(processorCase.getType(), processorCase);
} else {
for (short supportedVersion : processorCase.getSupportedVersions()) {
getCasesForVersion(supportedVersion).putIfAbsent(processorCase.getType(), processorCase);
}
}
return this;
}
/**
* Process source and return result based on convertor cases, or empty if no match is found.
*
* @param source the source
* @param convertorExecutor convertor executor
* @return the optional
*/
public Optional<TO> process(final FROM source, final ConvertorExecutor convertorExecutor) {
return process(source, null, convertorExecutor);
}
/**
* Process source and return result based on convertor cases, or empty if no match is found.
*
* @param source the source
* @param data the data
* @param convertorExecutor convertor executor
* @return the optional
*/
public Optional<TO> process(final FROM source, final DATA data, final ConvertorExecutor convertorExecutor) {
Optional<TO> result = Optional.empty();
final short version = data != null ? data.getVersion() : OFP_VERSION_ALL;
if (Objects.isNull(source)) {
LOG.trace("Failed to convert null for version {}", version);
return result;
}
final Class<?> clazz = source.getImplementedInterface();
final Optional<ConvertorCase<?, TO, DATA>> caseOptional = Optional
.ofNullable(getCasesForVersion(version).get(clazz));
final ConvertorCase<?, TO, DATA> processorCase = caseOptional.orElse(defaultCase);
if (Objects.nonNull(processorCase)) {
result = processorCase.processRaw(source, data, convertorExecutor);
if (processorCase.isErrorOnEmpty() && !result.isPresent()) {
LOG.warn("Failed to process {} for version {}", clazz, version);
}
} else {
LOG.trace("Failed to process {} for version {}", clazz, version);
}
return result;
}
/**
* Sets default case, what will be used when we do not find any matching convertor case for source.
*
* @param defaultCase the default case
* @return the default case
*/
public ConvertorProcessor<FROM, TO, DATA> setDefaultCase(final ConvertorCase<?, TO, DATA> defaultCase) {
this.defaultCase = defaultCase;
return this;
}
private Map<Class<?>, ConvertorCase<?, TO, DATA>> getCasesForVersion(final short version) {
final Map<Class<?>, ConvertorCase<?, TO, DATA>> casesForVersion =
conversions.getOrDefault(version, new ConcurrentHashMap<>());
conversions.putIfAbsent(version, casesForVersion);
return casesForVersion;
}
}