/*
* Copyright 2016 the original author or authors.
*
* 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 org.gradle.api.internal.changedetection.state;
import com.google.common.base.Objects;
import org.gradle.api.internal.cache.StringInterner;
import org.gradle.internal.serialize.AbstractSerializer;
import org.gradle.internal.serialize.Decoder;
import org.gradle.internal.serialize.Encoder;
import org.gradle.internal.serialize.HashCodeSerializer;
import java.io.IOException;
import java.util.LinkedHashMap;
import java.util.Map;
public class SnapshotMapSerializer extends AbstractSerializer<Map<String, NormalizedFileSnapshot>> {
private static final byte DIR_SNAPSHOT = 1;
private static final byte MISSING_FILE_SNAPSHOT = 2;
private static final byte REGULAR_FILE_SNAPSHOT = 3;
private static final byte NO_NORMALIZATION = 1;
private static final byte DEFAULT_NORMALIZATION = 2;
private static final byte INDEXED_NORMALIZATION = 3;
private static final byte IGNORED_PATH_NORMALIZATION = 4;
private final HashCodeSerializer hashCodeSerializer = new HashCodeSerializer();
private final StringInterner stringInterner;
public SnapshotMapSerializer(StringInterner stringInterner) {
this.stringInterner = stringInterner;
}
@Override
public Map<String, NormalizedFileSnapshot> read(Decoder decoder) throws Exception {
int snapshotsCount = decoder.readSmallInt();
Map<String, NormalizedFileSnapshot> snapshots = new LinkedHashMap<String, NormalizedFileSnapshot>(snapshotsCount);
for (int i = 0; i < snapshotsCount; i++) {
String absolutePath = stringInterner.intern(decoder.readString());
NormalizedFileSnapshot snapshot = readSnapshot(absolutePath, decoder, stringInterner);
snapshots.put(absolutePath, snapshot);
}
return snapshots;
}
private NormalizedFileSnapshot readSnapshot(String absolutePath, Decoder decoder, StringInterner stringInterner) throws IOException {
byte fileSnapshotKind = decoder.readByte();
FileContentSnapshot snapshot;
switch (fileSnapshotKind) {
case DIR_SNAPSHOT:
snapshot = DirContentSnapshot.getInstance();
break;
case MISSING_FILE_SNAPSHOT:
snapshot = MissingFileContentSnapshot.getInstance();
break;
case REGULAR_FILE_SNAPSHOT:
snapshot = new FileHashSnapshot(hashCodeSerializer.read(decoder));
break;
default:
throw new RuntimeException("Unable to read serialized file snapshot. Unrecognized value found in the data stream.");
}
int normalizedSnapshotKind = decoder.readByte();
switch (normalizedSnapshotKind) {
case NO_NORMALIZATION:
return new NonNormalizedFileSnapshot(absolutePath, snapshot);
case DEFAULT_NORMALIZATION:
String normalizedPath = stringInterner.intern(decoder.readString());
return new DefaultNormalizedFileSnapshot(normalizedPath, snapshot);
case INDEXED_NORMALIZATION:
int index = decoder.readSmallInt();
return new IndexedNormalizedFileSnapshot(absolutePath, index, snapshot);
case IGNORED_PATH_NORMALIZATION:
return new IgnoredPathFileSnapshot(snapshot);
default:
throw new RuntimeException("Unable to read serialized file snapshot. Unrecognized value found in the data stream.");
}
}
@Override
public void write(Encoder encoder, Map<String, NormalizedFileSnapshot> value) throws Exception {
encoder.writeSmallInt(value.size());
for (String key : value.keySet()) {
encoder.writeString(key);
NormalizedFileSnapshot snapshot = value.get(key);
writeSnapshot(encoder, snapshot);
}
}
@Override
public boolean equals(Object obj) {
if (!super.equals(obj)) {
return false;
}
SnapshotMapSerializer rhs = (SnapshotMapSerializer) obj;
return Objects.equal(hashCodeSerializer, rhs.hashCodeSerializer);
}
@Override
public int hashCode() {
return Objects.hashCode(super.hashCode(), hashCodeSerializer);
}
private void writeSnapshot(Encoder encoder, NormalizedFileSnapshot value) throws IOException {
FileContentSnapshot snapshot = value.getSnapshot();
if (snapshot instanceof DirContentSnapshot) {
encoder.writeByte(DIR_SNAPSHOT);
} else if (snapshot instanceof MissingFileContentSnapshot) {
encoder.writeByte(MISSING_FILE_SNAPSHOT);
} else if (snapshot instanceof FileHashSnapshot) {
encoder.writeByte(REGULAR_FILE_SNAPSHOT);
hashCodeSerializer.write(encoder, snapshot.getContentMd5());
} else {
throw new AssertionError();
}
if (value instanceof NonNormalizedFileSnapshot) {
encoder.writeByte(NO_NORMALIZATION);
} else if (value instanceof DefaultNormalizedFileSnapshot) {
encoder.writeByte(DEFAULT_NORMALIZATION);
encoder.writeString(value.getNormalizedPath());
} else if (value instanceof IndexedNormalizedFileSnapshot) {
encoder.writeByte(INDEXED_NORMALIZATION);
encoder.writeSmallInt(((IndexedNormalizedFileSnapshot) value).getIndex());
} else if (value instanceof IgnoredPathFileSnapshot) {
encoder.writeByte(IGNORED_PATH_NORMALIZATION);
} else {
throw new AssertionError();
}
}
}