io.syndesis.common.model.DataShape Maven / Gradle / Ivy
/*
* Copyright (C) 2016 Red Hat, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.syndesis.common.model;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.Serializable;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import io.syndesis.common.util.IOStreams;
import org.immutables.value.Value;
@Value.Immutable
@JsonDeserialize(builder = DataShape.Builder.class)
// Immutables generates code that fails these checks
@SuppressWarnings({ "ArrayEquals", "ArrayHashCode", "ArrayToString" })
public interface DataShape extends Serializable, WithName, WithMetadata {
@Override
String getName();
String getDescription();
DataShapeKinds getKind();
String getType();
/**
* The collection type that should be inspected.
*/
Optional getCollectionType();
/**
* The class name that should be inspected.
*/
Optional getCollectionClassName();
String getSpecification();
Optional getExemplar();
@Override
Map getMetadata();
/**
* Holds the variants available for this data shape.
*
* A variant could be the single element inspection of collection
*/
@Value.Default
default List getVariants() {
return Collections.emptyList();
}
default Optional findVariant(Predicate predicate) {
if (predicate.test(this)) {
return Optional.of(this);
}
return getVariants().stream().filter(predicate).findFirst();
}
default Optional findVariantByMeta(String key, String val) {
return findVariant(ds -> {
if (key == null || val == null) {
return false;
}
return Objects.equals(
ds.getMetadata().get(key),
val
);
});
}
class Builder extends ImmutableDataShape.Builder {
public Builder decompress() {
DataShape currentShape = build();
if (shouldDecompress(currentShape.getMetadata())) {
byte[] decoded = Base64.getDecoder().decode(currentShape.getSpecification().getBytes(StandardCharsets.UTF_8));
try (ByteArrayInputStream zipped = new ByteArrayInputStream(decoded);
GZIPInputStream is = new GZIPInputStream(zipped)) {
return new DataShape.Builder()
.createFrom(currentShape)
.putMetadata(DataShapeMetaData.IS_COMPRESSED, Boolean.FALSE.toString())
.variants(currentShape.getVariants()
.stream()
.map(variant -> new DataShape.Builder()
.createFrom(variant)
.decompress()
.build())
.collect(Collectors.toList()))
.specification(IOStreams.readText(is));
} catch (IOException e) {
throw new IllegalStateException("Failed to decompress data shape", e);
}
} else if (shouldCompressAnyVariant(currentShape.getVariants())) {
return new DataShape.Builder()
.createFrom(currentShape)
.variants(currentShape.getVariants()
.stream()
.map(variant -> new DataShape.Builder()
.createFrom(variant)
.decompress()
.build())
.collect(Collectors.toList()));
}
return this;
}
public Builder compress() {
DataShape currentShape = build();
if (shouldCompress(currentShape.getMetadata())) {
try (ByteArrayOutputStream zipped = new ByteArrayOutputStream();
GZIPOutputStream os = new GZIPOutputStream(zipped)) {
os.write(currentShape.getSpecification().getBytes(StandardCharsets.UTF_8));
os.finish();
return new DataShape.Builder()
.createFrom(currentShape)
.putMetadata(DataShapeMetaData.IS_COMPRESSED, Boolean.TRUE.toString())
.variants(currentShape.getVariants()
.stream()
.map(variant -> new DataShape.Builder()
.createFrom(variant)
.compress()
.build())
.collect(Collectors.toList()))
.specification(Base64.getEncoder().encodeToString(zipped.toByteArray()));
} catch (IOException e) {
throw new IllegalStateException("Failed to compress data shape", e);
}
} else if (shouldCompressAnyVariant(currentShape.getVariants())) {
return new DataShape.Builder()
.createFrom(currentShape)
.variants(currentShape.getVariants()
.stream()
.map(variant -> new DataShape.Builder()
.createFrom(variant)
.compress()
.build())
.collect(Collectors.toList()));
}
return this;
}
private static boolean shouldCompress(Map metadata) {
return Boolean.parseBoolean(metadata.get(DataShapeMetaData.SHOULD_COMPRESS)) &&
!Boolean.parseBoolean(metadata.getOrDefault(DataShapeMetaData.IS_COMPRESSED, Boolean.FALSE.toString()));
}
private static boolean shouldDecompress(Map metadata) {
return Boolean.parseBoolean(metadata.get(DataShapeMetaData.SHOULD_COMPRESS)) &&
Boolean.parseBoolean(metadata.getOrDefault(DataShapeMetaData.IS_COMPRESSED, Boolean.TRUE.toString()));
}
private static boolean shouldCompressAnyVariant(List variants) {
return variants.stream().anyMatch(variant -> Boolean.parseBoolean(variant.getMetadata().get(DataShapeMetaData.SHOULD_COMPRESS)));
}
}
}