/*
* 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.groupbasedpolicy.renderer.ofoverlay.sf;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import com.google.common.base.Strings;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ClassifierDefinitionId;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.subject.feature.definitions.ClassifierDefinition;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.subject.feature.instance.ParameterValue;
import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.renderer.rev151103.renderers.renderer.capabilities.supported.classifier.definition.SupportedParameterValues;
/**
* Represent a classifier definition, and provide tools for generating flow
* rules based on the classifier
*/
public abstract class Classifier {
// Messages for exceptions (also for exception tests)
public static final String MSG_CLASSIFICATION_CONFLICT_DETECTED = "Classification conflict detected";
public static final String MSG_NOT_SPECIFIED = "not specified";
public static final String MSG_PARAMETER_IS_NOT_PRESENT = "parameter is not present";
public static final String MSG_MUTUALLY_EXCLUSIVE = "mutually exclusive";
public static final String MSG_RANGE_VALUE_MISMATCH = "Range value mismatch.";
public static final String MSG_NOT_SUPPORTED = "not supported";
public static final String MSG_IS_MISSING = "is missing";
public static final String MSG_NOT_PRESENT = "not present";
protected final Classifier parent;
public static final EtherTypeClassifier ETHER_TYPE_CL = new EtherTypeClassifier(null);
public static final IpProtoClassifier IP_PROTO_CL = new IpProtoClassifier(ETHER_TYPE_CL);
public static final L4Classifier L4_CL = new L4Classifier(IP_PROTO_CL);
protected Classifier(Classifier parent) {
this.parent = parent;
}
/**
* Get the classifier definition id for this classifier
*
* @return the {@link ClassifierDefinitionId} for this classifier
*/
public abstract ClassifierDefinitionId getId();
/**
* Get the classifier definition for this classifier
*
* @return the {@link ClassifierDefinition} for this classifier
*/
public abstract ClassifierDefinition getClassifierDefinition();
/**
* @return parent classifier, see {@link Classifier}
*/
public final Classifier getParent() {
return parent;
}
/**
* The result represents supported parameters for the classifier by renderer
*
* @return list of supported parameters by the classifier
*/
public abstract List<SupportedParameterValues> getSupportedParameterValues();
/**
* Template method for resolving {@code matches}.
*
* @param matches list of builders containing {@code matches} to update
* @param params parameters of classifier-instance inserted by user
* @return result, which indicates if all the matching fields were updated successfully and
* contain updated {@code matches}, see {@link ClassificationResult}
*/
public final ClassificationResult updateMatch(List<MatchBuilder> matches, Map<String, ParameterValue> params) {
if (params == null) {
return new ClassificationResult(
"Classifier-instance with classifier-definition-id: " + this.getId() + ". No parameters present.");
}
List<MatchBuilder> matchBuilders = matches;
try {
checkPresenceOfRequiredParams(params);
matchBuilders = this.update(matchBuilders, params);
Classifier parent = this.getParent();
List<Classifier> updatedClassifiers = new ArrayList<>();
updatedClassifiers.add(this);
while (parent != null) {
boolean hasReqParams = true;
try {
parent.checkPresenceOfRequiredParams(params);
} catch (IllegalArgumentException e) {
hasReqParams = false;
}
if (hasReqParams) {
matchBuilders = parent.update(matchBuilders, params);
updatedClassifiers.add(parent);
}
parent = parent.getParent();
}
for (Classifier updatedClassifier : updatedClassifiers) {
updatedClassifier.checkPrereqs(matchBuilders);
}
} catch (IllegalArgumentException e) {
if (!Strings.isNullOrEmpty(e.getMessage())) {
return new ClassificationResult(e.getMessage());
} else
return new ClassificationResult("Classifier-instance with classifier-definition-id: " + this.getId()
+ ". Classification was not successful.");
}
return new ClassificationResult(matchBuilders);
}
/**
* Checks presence of required {@code params} in order to decide if classifier can update
* {@code matches} properly
* in method {@link #update(List, Map)}
*
* @param params inserted parameters, not null
* @throws IllegalArgumentException when any of required {@code params} is not present, see
* {@link #updateMatch(List, Map)}
*/
protected abstract void checkPresenceOfRequiredParams(Map<String, ParameterValue> params);
/**
* Resolves {@code matches} from inserted {@code params} and updates them.
* <p>
* Updates fields in {@code matches} or it can creates new matches. If it creates new matches it
* has to always use match from {@code matches} as parameter in constructor
* {@code MatchBuilder(Match base)}
*
* @param matches - fields to update
* @param params - input parameters
* @return updated {@code matches}. It is allowed to return new object.
* @throws IllegalArgumentException when update fails because of bad input
* (e.g. overriding existing matches with different values is not permitted)
*/
protected abstract List<MatchBuilder> update(List<MatchBuilder> matches, Map<String, ParameterValue> params);
/**
* Checks whether prerequisites (required {@code matches}) for the match that this classifier
* updates are present
* according to Openflow specifications.
*
* @param matches input list of matches to check
* @throws IllegalArgumentException when any of prerequisites is not present
*/
protected abstract void checkPrereqs(List<MatchBuilder> matches);
}