2 * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
8 package org.opendaylight.netconf.nettyutil.handler.exi;
10 import static com.google.common.base.Preconditions.checkArgument;
11 import static java.util.Objects.requireNonNull;
13 import com.google.common.annotations.VisibleForTesting;
14 import java.util.Objects;
15 import org.opendaylight.netconf.api.xml.XmlElement;
16 import org.opendaylight.netconf.shaded.exificient.core.CodingMode;
17 import org.opendaylight.netconf.shaded.exificient.core.EXIFactory;
18 import org.opendaylight.netconf.shaded.exificient.core.EncodingOptions;
19 import org.opendaylight.netconf.shaded.exificient.core.FidelityOptions;
20 import org.opendaylight.netconf.shaded.exificient.core.SchemaIdResolver;
21 import org.opendaylight.netconf.shaded.exificient.core.exceptions.EXIException;
22 import org.opendaylight.netconf.shaded.exificient.core.exceptions.UnsupportedOption;
23 import org.opendaylight.netconf.shaded.exificient.core.helpers.DefaultEXIFactory;
24 import org.slf4j.Logger;
25 import org.slf4j.LoggerFactory;
26 import org.w3c.dom.Element;
27 import org.w3c.dom.NodeList;
29 public final class EXIParameters {
30 private static final Logger LOG = LoggerFactory.getLogger(EXIParameters.class);
32 static final String EXI_PARAMETER_ALIGNMENT = "alignment";
33 private static final String EXI_PARAMETER_BYTE_ALIGNED = "byte-aligned";
34 private static final String EXI_PARAMETER_BIT_PACKED = "bit-packed";
35 private static final String EXI_PARAMETER_COMPRESSED = "compressed";
36 private static final String EXI_PARAMETER_PRE_COMPRESSION = "pre-compression";
38 static final String EXI_PARAMETER_FIDELITY = "fidelity";
39 private static final String EXI_FIDELITY_DTD = "dtd";
40 private static final String EXI_FIDELITY_LEXICAL_VALUES = "lexical-values";
41 private static final String EXI_FIDELITY_COMMENTS = "comments";
42 private static final String EXI_FIDELITY_PIS = "pis";
43 private static final String EXI_FIDELITY_PREFIXES = "prefixes";
45 static final String EXI_PARAMETER_SCHEMAS = "schemas";
47 private static final SchemaIdResolver SCHEMA_RESOLVER = schemaId -> {
48 if (schemaId == null) {
51 if (schemaId.isEmpty()) {
52 return EXISchema.BUILTIN.getGrammar();
54 if (schemaId.equals(EXISchema.BASE_1_1.getOption())) {
55 return EXISchema.BASE_1_1.getGrammar();
58 throw new EXIException("Cannot resolve schema " + schemaId);
61 private static final EncodingOptions ENCODING_OPTIONS;
64 final EncodingOptions opts = EncodingOptions.createDefault();
66 opts.setOption(EncodingOptions.RETAIN_ENTITY_REFERENCE);
67 opts.setOption(EncodingOptions.INCLUDE_OPTIONS);
70 * NETCONF is XML environment, so the use of EXI cookie is not really needed. Adding it
71 * decreases efficiency of encoding by adding human-readable 4 bytes "EXI$" to the head
72 * of the stream. This is really useful, so let's output it now.
74 opts.setOption(EncodingOptions.INCLUDE_COOKIE);
75 } catch (final UnsupportedOption e) {
76 throw new ExceptionInInitializerError(e);
79 ENCODING_OPTIONS = opts;
82 private final FidelityOptions fidelityOptions;
83 private final CodingMode codingMode;
84 private final EXISchema schema;
86 public EXIParameters(final CodingMode codingMode, final FidelityOptions fidelityOptions) {
87 this(codingMode, fidelityOptions, EXISchema.NONE);
90 public EXIParameters(final CodingMode codingMode, final FidelityOptions fidelityOptions, final EXISchema schema) {
91 this.fidelityOptions = requireNonNull(fidelityOptions);
92 this.codingMode = requireNonNull(codingMode);
93 this.schema = requireNonNull(schema);
97 public static EXIParameters empty() {
98 return new EXIParameters(CodingMode.BIT_PACKED, FidelityOptions.createDefault());
101 public static EXIParameters fromXmlElement(final XmlElement root) throws UnsupportedOption {
102 final CodingMode coding;
103 final NodeList alignmentElements = root.getElementsByTagName(EXI_PARAMETER_ALIGNMENT);
104 if (alignmentElements.getLength() > 0) {
105 final Element alignmentElement = (Element) alignmentElements.item(0);
106 final String alignmentTextContent = alignmentElement.getTextContent().trim();
108 switch (alignmentTextContent) {
109 case EXI_PARAMETER_BYTE_ALIGNED:
110 coding = CodingMode.BYTE_PACKED;
112 case EXI_PARAMETER_COMPRESSED:
113 coding = CodingMode.COMPRESSION;
115 case EXI_PARAMETER_PRE_COMPRESSION:
116 coding = CodingMode.PRE_COMPRESSION;
118 case EXI_PARAMETER_BIT_PACKED:
119 coding = CodingMode.BIT_PACKED;
122 LOG.warn("Unexpected value in alignmentTextContent: {} , using default value",
123 alignmentTextContent);
124 coding = CodingMode.BIT_PACKED;
128 coding = CodingMode.BIT_PACKED;
131 final FidelityOptions fidelity = FidelityOptions.createDefault();
132 final NodeList fidelityElements = root.getElementsByTagName(EXI_PARAMETER_FIDELITY);
133 if (fidelityElements.getLength() > 0) {
134 final Element fidelityElement = (Element) fidelityElements.item(0);
136 fidelity.setFidelity(FidelityOptions.FEATURE_DTD,
137 fidelityElement.getElementsByTagName(EXI_FIDELITY_DTD).getLength() > 0);
138 fidelity.setFidelity(FidelityOptions.FEATURE_LEXICAL_VALUE,
139 fidelityElement.getElementsByTagName(EXI_FIDELITY_LEXICAL_VALUES).getLength() > 0);
140 fidelity.setFidelity(FidelityOptions.FEATURE_COMMENT,
141 fidelityElement.getElementsByTagName(EXI_FIDELITY_COMMENTS).getLength() > 0);
142 fidelity.setFidelity(FidelityOptions.FEATURE_PI,
143 fidelityElement.getElementsByTagName(EXI_FIDELITY_PIS).getLength() > 0);
144 fidelity.setFidelity(FidelityOptions.FEATURE_PREFIX,
145 fidelityElement.getElementsByTagName(EXI_FIDELITY_PREFIXES).getLength() > 0);
148 final EXISchema schema;
149 final NodeList schemaElements = root.getElementsByTagName(EXI_PARAMETER_SCHEMAS);
150 if (schemaElements.getLength() > 0) {
151 final Element schemaElement = (Element) schemaElements.item(0);
152 final String schemaName = schemaElement.getTextContent().trim();
153 schema = EXISchema.forOption(schemaName);
154 checkArgument(schema != null, "Unsupported schema name %s", schemaName);
156 schema = EXISchema.NONE;
159 return new EXIParameters(coding, fidelity, schema);
162 public EXIFactory getFactory() {
163 final EXIFactory factory = DefaultEXIFactory.newInstance();
164 factory.setCodingMode(codingMode);
165 factory.setEncodingOptions(ENCODING_OPTIONS);
166 factory.setFidelityOptions(fidelityOptions);
167 factory.setGrammars(schema.getGrammar());
168 factory.setSchemaIdResolver(SCHEMA_RESOLVER);
173 public int hashCode() {
174 return Objects.hash(fidelityOptions, codingMode, schema);
178 public boolean equals(final Object obj) {
182 if (!(obj instanceof EXIParameters)) {
185 final EXIParameters other = (EXIParameters) obj;
186 return codingMode == other.codingMode && schema == other.schema
187 && fidelityOptions.equals(other.fidelityOptions);
190 String getAlignment() {
191 switch (codingMode) {
193 return EXI_PARAMETER_BIT_PACKED;
195 return EXI_PARAMETER_BYTE_ALIGNED;
197 return EXI_PARAMETER_COMPRESSED;
198 case PRE_COMPRESSION:
199 return EXI_PARAMETER_PRE_COMPRESSION;
201 throw new IllegalStateException("Unhandled coding mode " + codingMode);
205 private String fidelityString(final String feature, final String string) {
206 return fidelityOptions.isFidelityEnabled(feature) ? string : null;
209 String getPreserveComments() {
210 return fidelityString(FidelityOptions.FEATURE_COMMENT, EXI_FIDELITY_COMMENTS);
213 String getPreserveDTD() {
214 return fidelityString(FidelityOptions.FEATURE_DTD, EXI_FIDELITY_DTD);
217 String getPreserveLexicalValues() {
218 return fidelityString(FidelityOptions.FEATURE_LEXICAL_VALUE, EXI_FIDELITY_LEXICAL_VALUES);
221 String getPreservePIs() {
222 return fidelityString(FidelityOptions.FEATURE_PI, EXI_FIDELITY_PIS);
225 String getPreservePrefixes() {
226 return fidelityString(FidelityOptions.FEATURE_PREFIX, EXI_FIDELITY_PREFIXES);
230 return schema == EXISchema.NONE ? null : schema.name();