Skip to content

Commit

Permalink
Set up checker framework and checkstyle tests.
Browse files Browse the repository at this point in the history
  • Loading branch information
bmarwell committed May 19, 2019
1 parent 26eb1bf commit 346dc22
Show file tree
Hide file tree
Showing 9 changed files with 275 additions and 81 deletions.
8 changes: 6 additions & 2 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,10 @@ env:
- TRAVIS_JDK=adopt-openj9@1.11.28-0

before_install: curl -Ls https://git.io/jabba | bash && . ~/.jabba/jabba.sh
install: jabba install "$TRAVIS_JDK" && jabba use $_ && java -Xmx32m -version

install:
- jabba install "$TRAVIS_JDK" && jabba use $_ && java -Xmx32m -version
- mvn dependency:resolve

stages:
- validations
Expand All @@ -19,8 +22,9 @@ stages:
jobs:
include:
- stage: validations
script: mvn -B clean install -DskipTests=true
name: "Code validations (format, binary compatibilty, whitesource, etc.)"
script: mvn -B clean install -DskipTests=true -Pcheckstyle
- script: mvn -B clean install -DskipTests=true -Pchecker

cache:
directories:
Expand Down
8 changes: 8 additions & 0 deletions build/checker/stubs/java.lang.Class.astub
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package java.lang;

import org.checkerframework.checker.nullness.qual.*;

public class Class<T> {
// it *can* return null, but we only use it for loggers.
public @NonNull String getCanonicalName();
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,21 +16,26 @@

package de.bmarwell.zchunk.compression.api;

import static java.util.stream.Collectors.toList;
import static java.util.stream.Collectors.toMap;

import de.bmarwell.zchunk.compression.algo.unknown.UnknownAlgorithm;
import de.bmarwell.zchunk.compression.api.internal.ReflectionUtil;
import java.util.AbstractMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Stream;
import org.checkerframework.checker.initialization.qual.UnderInitialization;
import org.checkerframework.checker.nullness.qual.EnsuresNonNull;
import org.checkerframework.checker.nullness.qual.Nullable;

public final class CompressionAlgorithmFactory {

private static final Package THIS_PACKAGE = CompressionAlgorithmFactory.class.getPackage();
private static final String ROOT_PACKAGE = THIS_PACKAGE.getName().replaceAll("\\.api$", ".algo");
// do not change this as this would break plugins.
private static final String ROOT_PACKAGE = "io.github.zchunk.compression";

private CompressionAlgorithmFactory() {
// util class.
Expand Down Expand Up @@ -70,17 +75,18 @@ private static Map<Long, Class<CompressionAlgorithm>> getTypeMappings() {

private static class ResourceHolder {

private static ResourceHolder INSTANCE = null;
private static @Nullable ResourceHolder INSTANCE = null;

private final List<Class<CompressionAlgorithm>> implementations;

private final Map<Long, Class<CompressionAlgorithm>> typeMapping;

public ResourceHolder(final String rootPackage) {
this.implementations = ReflectionUtil.loadImplementations(rootPackage, CompressionAlgorithm.class);
this.implementations = loadImplementations(rootPackage, CompressionAlgorithm.class);
this.typeMapping = loadTypeMapping(this.implementations);
}

@EnsuresNonNull({"INSTANCE"})
public static ResourceHolder newInstance(final String rootPackage) {
if (INSTANCE == null) {
INSTANCE = new ResourceHolder(rootPackage);
Expand All @@ -89,9 +95,32 @@ public static ResourceHolder newInstance(final String rootPackage) {
return INSTANCE;
}

private Map<Long, Class<CompressionAlgorithm>> loadTypeMapping(final List<Class<CompressionAlgorithm>> implementations) {
return implementations.stream()
.map(CompressionAlgorithmFactory::mapEntryOrNull)
/**
* Will try to load classes implementing clazz, from any package below rootpackage.
*
* @param rootPackage
* the root package to search in.
* @param clazz
* the class which should be implemented by the found classes.
* @param <T>
* the class type.
* @return a list of classes implementing T / clazz.
*/
public <T> List<Class<T>> loadImplementations(@UnderInitialization ResourceHolder this,
final String rootPackage,
final Class<T> clazz) {
final List<Class<T>> classes = ReflectionUtil.getClasses(rootPackage, clazz);

return classes.stream()
.filter(ReflectionUtil.classImplementsCompressionAlgorithm(clazz))
.collect(toList());
}

private Map<Long, Class<CompressionAlgorithm>> loadTypeMapping(@UnderInitialization ResourceHolder this,
final List<Class<CompressionAlgorithm>> implementations) {
final Stream<@Nullable Entry<Long, Class<CompressionAlgorithm>>> entryStream = implementations.stream()
.map(CompressionAlgorithmFactory::mapEntryOrNull);
return entryStream
.filter(Objects::nonNull)
.collect(toMap(Map.Entry::getKey, Map.Entry::getValue));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
package de.bmarwell.zchunk.compression.api.internal;

import static java.util.Collections.emptyList;
import static java.util.Collections.singletonList;
import static java.util.stream.Collectors.toList;

import java.io.File;
Expand All @@ -33,7 +32,6 @@
import java.util.function.Predicate;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.checkerframework.checker.nullness.qual.Nullable;

public final class ReflectionUtil {

Expand All @@ -43,27 +41,7 @@ private ReflectionUtil() {
// util
}

/**
* Will try to load classes implementing clazz, from any package below rootpackage.
*
* @param rootPackage
* the root package to search in.
* @param clazz
* the class which should be implemented by the found classes.
* @param <T>
* the class type.
* @return a list of classes implementing T / clazz.
*/
public static <T> List<Class<T>> loadImplementations(final String rootPackage, final Class<T> clazz) {
final List<Class<T>> classes = getClasses(rootPackage, clazz);

return classes.stream()
.filter(classImplementsCompressionAlgorithm(clazz))
.collect(toList());
}


private static <T> List<Class<T>> getClasses(final String rootPackage, final Class<T> targetClazz) {
public static <T> List<Class<T>> getClasses(final String rootPackage, final Class<T> targetClazz) {
try {
final ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
final String path = rootPackage.replace('.', '/');
Expand All @@ -84,7 +62,6 @@ private static <T> List<Class<T>> getClasses(final String rootPackage, final Cla
}
}


/**
* Recursive method used to find all classes in a given directory and subdirs.
*
Expand Down Expand Up @@ -118,27 +95,27 @@ private static <T> List<Class<T>> findClasses(final String packageName, final Cl
}

if (file.getName().endsWith(".class")) {
final @Nullable Class<T> aClass = loadClass(packageName, clazzType, file);
if (aClass != null) {
return singletonList(aClass);
}
return loadClass(packageName, clazzType, file)
.map(Collections::singletonList)
.orElseGet(Collections::emptyList);
}

return emptyList();
}

@Nullable
private static <T> Class<T> loadClass(final String packageName, final Class<T> clazzType, final File file) {
private static <T> Optional<Class<T>> loadClass(final String packageName, final Class<T> clazzType, final File file) {
try {
final Class<?> aClass = Class.forName(packageName + '.' + file.getName().substring(0, file.getName().length() - 6));
if (classImplementsCompressionAlgorithm(clazzType).test(aClass)) {
return (Class<T>) aClass;
@SuppressWarnings("unchecked")
final Class<T> castedClass = (Class<T>) aClass;
return Optional.ofNullable(castedClass);
}
} catch (final ClassNotFoundException e) {
LOG.log(Level.WARNING, e, () -> String.format("Class file [%s] found, but unable to create instance.", file.getAbsolutePath()));
}

return null;
return Optional.empty();
}

private static <T> List<T> getListFromArray(final T[] input) {
Expand All @@ -165,7 +142,7 @@ public static <T> Optional<T> newInstance(final Class<T> clazz) {
}
}

private static <T> Predicate<Class<?>> classImplementsCompressionAlgorithm(final Class<T> type) {
public static <T> Predicate<Class<?>> classImplementsCompressionAlgorithm(final Class<T> type) {
return clazz -> getListFromArray(type.getInterfaces()).contains(type);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,15 @@
import de.bmarwell.zchunk.compressedint.CompressedIntUtil;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.Provider;
import java.security.Provider.Service;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable;

public final class ZChunkConstants {

Expand All @@ -50,13 +53,13 @@ private static int getLargestHashSize() {
final String digestClassName = MessageDigest.class.getSimpleName();
final String aliasPrefix = "Alg.Alias." + digestClassName + ".";

return Arrays.stream(getProviders())
final Stream<@Nullable MessageDigest> messageDigestStream = Arrays.stream(getProviders())
.flatMap(prov -> {
final Set<String> algorithms = new HashSet<>(0);

prov.getServices().stream()
.filter(s -> digestClassName.equalsIgnoreCase(s.getType()))
.map(Provider.Service::getAlgorithm)
.map(Service::getAlgorithm)
.collect(Collectors.toCollection(() -> algorithms));

prov.keySet().stream()
Expand All @@ -67,16 +70,25 @@ private static int getLargestHashSize() {

return algorithms.stream();
})
.map(algo -> {
try {
return MessageDigest.getInstance(algo);
} catch (NoSuchAlgorithmException e) {
return null;
}
})
.filter(Objects::nonNull)
.map(ZChunkConstants::instanceOrNull);

return toNonNullStream(messageDigestStream)
.mapToInt(MessageDigest::getDigestLength)
.max().orElse(512 / 8);
}

}

@SuppressWarnings("nullness")
private static Stream<@NonNull MessageDigest> toNonNullStream(final Stream<@Nullable MessageDigest> messageDigestStream) {
return messageDigestStream.filter(Objects::nonNull);
}

private static @Nullable MessageDigest instanceOrNull(final String algo) {
try {
return MessageDigest.getInstance(algo);
} catch (final NoSuchAlgorithmException e) {
return null;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ public static ZChunkHeader fromStream(final InputStream byteStream) {

final ZChunkHeaderPreface headerPreface = readHeaderPreface(completeHeader, lead);

final ZChunkHeaderIndex index = null;
final ZChunkHeaderIndex index = readHeaderIndex(completeHeader, lead, headerPreface);
final ZChunkHeaderSignatures signature = ImmutableZChunkHeaderSignatures.builder()
.signatureCount(CompressedIntFactory.valueOf(0L))
.build();
Expand Down
Loading

0 comments on commit 346dc22

Please # to comment.