*/
package org.opendaylight.yangtools.yang.data.impl.codec;
-import com.google.common.base.Optional;
-import com.google.common.io.BaseEncoding;
-import javax.xml.bind.DatatypeConverter;
+import static java.util.Objects.requireNonNull;
+
+import com.google.common.annotations.Beta;
+import com.google.common.collect.RangeSet;
+import java.util.Base64;
+import org.opendaylight.yangtools.yang.common.RpcError.ErrorType;
import org.opendaylight.yangtools.yang.data.api.codec.BinaryCodec;
+import org.opendaylight.yangtools.yang.data.api.codec.YangInvalidValueException;
import org.opendaylight.yangtools.yang.model.api.type.BinaryTypeDefinition;
+import org.opendaylight.yangtools.yang.model.api.type.LengthConstraint;
+
+/**
+ * Do not use this class outside of yangtools, its presence does not fall into the API stability contract.
+ */
+@Beta
+public abstract class BinaryStringCodec extends TypeDefinitionAwareCodec<byte[], BinaryTypeDefinition>
+ implements BinaryCodec<String> {
+ private static final class Restricted extends BinaryStringCodec {
+ private final LengthConstraint lengthConstraint;
-class BinaryStringCodec extends TypeDefinitionAwareCodec<byte[], BinaryTypeDefinition> implements BinaryCodec<String> {
+ Restricted(final BinaryTypeDefinition typeDef, final LengthConstraint lengthConstraint) {
+ super(typeDef);
+ this.lengthConstraint = requireNonNull(lengthConstraint);
+ }
- protected BinaryStringCodec(final Optional<BinaryTypeDefinition> typeDef) {
- super(typeDef, byte[].class);
+ @Override
+ void validate(final byte[] value) {
+ final RangeSet<Integer> ranges = lengthConstraint.getAllowedRanges();
+ if (!ranges.contains(value.length)) {
+ throw new YangInvalidValueException(ErrorType.APPLICATION, lengthConstraint,
+ "Value length " + value.length + " is not in required ranges " + ranges);
+ }
+ }
}
- static TypeDefinitionAwareCodec<?,BinaryTypeDefinition> from(final BinaryTypeDefinition type) {
- return new BinaryStringCodec(Optional.fromNullable(type));
+ private static final class Unrestricted extends BinaryStringCodec {
+ Unrestricted(final BinaryTypeDefinition typeDef) {
+ super(typeDef);
+ }
+
+ @Override
+ void validate(final byte[] value) {
+ // No-op
+ }
+ }
+
+ BinaryStringCodec(final BinaryTypeDefinition typeDef) {
+ super(requireNonNull(typeDef), byte[].class);
+ }
+
+ public static BinaryStringCodec from(final BinaryTypeDefinition type) {
+ final java.util.Optional<LengthConstraint> optConstraint = type.getLengthConstraint();
+ return optConstraint.isPresent() ? new Restricted(type, optConstraint.get()) : new Unrestricted(type);
}
@Override
- public String serialize(final byte[] data) {
- return data == null ? "" : BaseEncoding.base64().encode(data);
+ public final byte[] deserializeImpl(final String product) {
+ // https://tools.ietf.org/html/rfc4648#section-4 plus lenient to allow for MIME blocks
+ final byte[] ret = Base64.getMimeDecoder().decode(product);
+ validate(ret);
+ return ret;
}
@Override
- public byte[] deserialize(final String stringRepresentation) {
- return stringRepresentation == null ? null : DatatypeConverter.parseBase64Binary(stringRepresentation);
+ protected final String serializeImpl(final byte[] data) {
+ // We do not split data on 76 characters on output
+ return Base64.getEncoder().encodeToString(data);
}
+
+ abstract void validate(byte[] value);
}