From 46969a5f7c79b2493b964c137560a521dd649618 Mon Sep 17 00:00:00 2001 From: Atanas Atanasov Date: Tue, 15 Oct 2024 10:09:27 +0300 Subject: [PATCH 01/10] introduce the common module, abstract some literals Signed-off-by: Atanas Atanasov --- .../kotlin/com.hedera.block.common.gradle.kts | 25 +++++++++++ common/build.gradle.kts | 24 +++++++++++ .../constants/ErrorMessageConstants.java | 30 +++++++++++++ .../common/constants/StringConstants.java | 42 +++++++++++++++++++ common/src/main/java/module-info.java | 5 +++ settings.gradle.kts | 1 + 6 files changed, 127 insertions(+) create mode 100644 buildSrc/src/main/kotlin/com.hedera.block.common.gradle.kts create mode 100644 common/build.gradle.kts create mode 100644 common/src/main/java/com/hedera/block/common/constants/ErrorMessageConstants.java create mode 100644 common/src/main/java/com/hedera/block/common/constants/StringConstants.java create mode 100644 common/src/main/java/module-info.java diff --git a/buildSrc/src/main/kotlin/com.hedera.block.common.gradle.kts b/buildSrc/src/main/kotlin/com.hedera.block.common.gradle.kts new file mode 100644 index 000000000..f5361b330 --- /dev/null +++ b/buildSrc/src/main/kotlin/com.hedera.block.common.gradle.kts @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2024 Hedera Hashgraph, LLC + * + * 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. + */ + +plugins { + id("application") + id("com.hedera.block.conventions") + id("me.champeau.jmh") +} + +val maven = publishing.publications.create("maven") { from(components["java"]) } + +signing.sign(maven) diff --git a/common/build.gradle.kts b/common/build.gradle.kts new file mode 100644 index 000000000..97636aeb8 --- /dev/null +++ b/common/build.gradle.kts @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2024 Hedera Hashgraph, LLC + * + * 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. + */ + +plugins { + id("application") + id("com.hedera.block.common") +} + +description = "Commons module with logic that could be abstracted and reused." + +testModuleInfo { requiresStatic("com.github.spotbugs.annotations") } diff --git a/common/src/main/java/com/hedera/block/common/constants/ErrorMessageConstants.java b/common/src/main/java/com/hedera/block/common/constants/ErrorMessageConstants.java new file mode 100644 index 000000000..417da6a6c --- /dev/null +++ b/common/src/main/java/com/hedera/block/common/constants/ErrorMessageConstants.java @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2024 Hedera Hashgraph, LLC + * + * 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 com.hedera.block.common.constants; + +import edu.umd.cs.findbugs.annotations.NonNull; + +/** A class that holds common error message {@link String} literals that are used across projects */ +public final class ErrorMessageConstants { + @NonNull + public static final String CREATING_INSTANCES_NOT_SUPPORTED = + "Creating instances is not supported!"; + + private ErrorMessageConstants() { + throw new UnsupportedOperationException(CREATING_INSTANCES_NOT_SUPPORTED); + } +} diff --git a/common/src/main/java/com/hedera/block/common/constants/StringConstants.java b/common/src/main/java/com/hedera/block/common/constants/StringConstants.java new file mode 100644 index 000000000..9d94e3750 --- /dev/null +++ b/common/src/main/java/com/hedera/block/common/constants/StringConstants.java @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2024 Hedera Hashgraph, LLC + * + * 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 com.hedera.block.common.constants; + +import static com.hedera.block.common.constants.ErrorMessageConstants.CREATING_INSTANCES_NOT_SUPPORTED; + +import edu.umd.cs.findbugs.annotations.NonNull; + +/** A class that hold common {@link String} literals used across projects. */ +public final class StringConstants { + // FILES + @NonNull public static final String APPLICATION_PROPERTIES = "app.properties"; + @NonNull public static final String LOGGING_PROPERTIES = "logging.properties"; + + // FILE EXTENSIONS + @NonNull public static final String BLOCK_FILE_EXTENSION = ".blk"; + @NonNull public static final String GZ_FILE_EXTENSION = ".gz"; + + // PROJECT RELATED + @NonNull public static final String SERVICE_NAME = "BlockStreamService"; + @NonNull public static final String CLIENT_STREAMING_METHOD_NAME = "publishBlockStream"; + @NonNull public static final String SERVER_STREAMING_METHOD_NAME = "subscribeBlockStream"; + @NonNull public static final String SINGLE_BLOCK_METHOD_NAME = "singleBlock"; + + private StringConstants() { + throw new UnsupportedOperationException(CREATING_INSTANCES_NOT_SUPPORTED); + } +} diff --git a/common/src/main/java/module-info.java b/common/src/main/java/module-info.java new file mode 100644 index 000000000..d11a39b91 --- /dev/null +++ b/common/src/main/java/module-info.java @@ -0,0 +1,5 @@ +module com.hedera.block.common { + exports com.hedera.block.common.constants; + + requires static com.github.spotbugs.annotations; +} diff --git a/settings.gradle.kts b/settings.gradle.kts index 9dd268f44..e1441bb3a 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -19,6 +19,7 @@ plugins { } // Include the subprojects +include(":common") include(":suites") include(":stream") include(":server") From ea0d11b61c6442f607ca55dc70cb70912baafae6 Mon Sep 17 00:00:00 2001 From: Atanas Atanasov Date: Tue, 15 Oct 2024 10:44:59 +0300 Subject: [PATCH 02/10] abstract logic from existing utility classes Signed-off-by: Atanas Atanasov --- .../hedera/block/common/utils/FileUtils.java | 117 ++++++++++++++++++ .../block/common/utils/HashingUtils.java | 45 +++++++ 2 files changed, 162 insertions(+) create mode 100644 common/src/main/java/com/hedera/block/common/utils/FileUtils.java create mode 100644 common/src/main/java/com/hedera/block/common/utils/HashingUtils.java diff --git a/common/src/main/java/com/hedera/block/common/utils/FileUtils.java b/common/src/main/java/com/hedera/block/common/utils/FileUtils.java new file mode 100644 index 000000000..5517ccfd8 --- /dev/null +++ b/common/src/main/java/com/hedera/block/common/utils/FileUtils.java @@ -0,0 +1,117 @@ +/* + * Copyright (C) 2024 Hedera Hashgraph, LLC + * + * 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 com.hedera.block.common.utils; + +import com.hedera.block.common.constants.ErrorMessageConstants; +import com.hedera.block.common.constants.StringConstants; +import edu.umd.cs.findbugs.annotations.NonNull; +import java.io.IOException; +import java.io.InputStream; +import java.lang.System.Logger; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.attribute.FileAttribute; +import java.nio.file.attribute.PosixFilePermission; +import java.nio.file.attribute.PosixFilePermissions; +import java.util.Objects; +import java.util.Set; +import java.util.zip.GZIPInputStream; + +/** A utility class that deals with logic related to dealing with files. */ +public final class FileUtils { + private static final Logger LOGGER = System.getLogger(FileUtils.class.getName()); + + /** + * Default file permissions defines the file and directory for the storage package. + * + *

Default permissions are set to: rwxr-xr-x + */ + @NonNull + public static final FileAttribute> DEFAULT_PERMS = + PosixFilePermissions.asFileAttribute( + Set.of( + PosixFilePermission.OWNER_READ, + PosixFilePermission.OWNER_WRITE, + PosixFilePermission.OWNER_EXECUTE, + PosixFilePermission.GROUP_READ, + PosixFilePermission.GROUP_EXECUTE, + PosixFilePermission.OTHERS_READ, + PosixFilePermission.OTHERS_EXECUTE)); + + /** + * Use this to create a Dir if it does not exist with the given permissions and log the result. + * + * @param blockNodePath the path to create + * @param logLevel the log level to use + * @param perms the permissions to use when creating the directory + * @throws IOException if the directory cannot be created + */ + public static void createPathIfNotExists( + @NonNull final Path blockNodePath, + @NonNull final System.Logger.Level logLevel, + @NonNull final FileAttribute> perms) + throws IOException { + Objects.requireNonNull(blockNodePath); + Objects.requireNonNull(logLevel); + Objects.requireNonNull(perms); + // Initialize the Block directory if it does not exist + if (Files.notExists(blockNodePath)) { + Files.createDirectory(blockNodePath, perms); + LOGGER.log(logLevel, "Created block node root directory: " + blockNodePath); + } else { + LOGGER.log(logLevel, "Using existing block node root directory: " + blockNodePath); + } + } + + /** + * Read a GZIP file and return the content as a byte array. + * + * @param filePath Path to the GZIP file + * @return byte array of the content of the GZIP file + * @throws IOException if an I/O error occurs + */ + public static byte[] readGzFile(@NonNull final Path filePath) throws IOException { + try (final InputStream fileInputStream = + Files.newInputStream(Objects.requireNonNull(filePath)); + final GZIPInputStream gzipInputStream = new GZIPInputStream(fileInputStream)) { + return gzipInputStream.readAllBytes(); + } + } + + /** + * Read a file and return the content as a byte array. + * + * @param filePath Path to the file + * @return byte array of the content of the file or null if the file extension is not supported + * @throws IOException if an I/O error occurs + */ + public static byte[] readFileBytes(@NonNull final Path filePath) throws IOException { + final String filePathAsString = Objects.requireNonNull(filePath).toString(); + if (filePathAsString.endsWith(StringConstants.GZ_FILE_EXTENSION)) { + return readGzFile(filePath); + } else if (filePathAsString.endsWith(StringConstants.BLOCK_FILE_EXTENSION)) { + return Files.readAllBytes(filePath); + } else { + return null; + } + } + + private FileUtils() { + throw new UnsupportedOperationException( + ErrorMessageConstants.CREATING_INSTANCES_NOT_SUPPORTED); + } +} diff --git a/common/src/main/java/com/hedera/block/common/utils/HashingUtils.java b/common/src/main/java/com/hedera/block/common/utils/HashingUtils.java new file mode 100644 index 000000000..1f4cd2392 --- /dev/null +++ b/common/src/main/java/com/hedera/block/common/utils/HashingUtils.java @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2024 Hedera Hashgraph, LLC + * + * 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 com.hedera.block.common.utils; + +import com.hedera.block.common.constants.ErrorMessageConstants; +import edu.umd.cs.findbugs.annotations.NonNull; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.util.Objects; + +/** A utility class that deals with logic related to hashing */ +public final class HashingUtils { + /** + * Gets a fake hash for the given block item. This is a placeholder and should be replaced with + * real hash functionality once the hedera-protobufs types are integrated. + * + * @param bytes to get the fake hash for + * @return the fake hash for the given block item + * @throws NoSuchAlgorithmException thrown if the SHA-384 algorithm is not available + */ + public static byte[] getFakeHash(@NonNull final byte[] bytes) throws NoSuchAlgorithmException { + Objects.requireNonNull(bytes); + final MessageDigest digest = MessageDigest.getInstance("SHA-384"); + return digest.digest(bytes); + } + + private HashingUtils() { + throw new UnsupportedOperationException( + ErrorMessageConstants.CREATING_INSTANCES_NOT_SUPPORTED); + } +} From bd7798fb0cded0083f625c8ee1c48755a15aeae4 Mon Sep 17 00:00:00 2001 From: Atanas Atanasov Date: Tue, 15 Oct 2024 11:35:49 +0300 Subject: [PATCH 03/10] abstracting of more logic Signed-off-by: Atanas Atanasov --- .../block/common/utils/HashingUtils.java | 10 +- .../hedera/block/common/utils/Translator.java | 218 ++++++++++++++++++ common/src/main/java/module-info.java | 3 + 3 files changed, 227 insertions(+), 4 deletions(-) create mode 100644 common/src/main/java/com/hedera/block/common/utils/Translator.java diff --git a/common/src/main/java/com/hedera/block/common/utils/HashingUtils.java b/common/src/main/java/com/hedera/block/common/utils/HashingUtils.java index 1f4cd2392..f2bd49258 100644 --- a/common/src/main/java/com/hedera/block/common/utils/HashingUtils.java +++ b/common/src/main/java/com/hedera/block/common/utils/HashingUtils.java @@ -17,6 +17,7 @@ package com.hedera.block.common.utils; import com.hedera.block.common.constants.ErrorMessageConstants; +import com.hedera.hapi.block.stream.BlockItem; import edu.umd.cs.findbugs.annotations.NonNull; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; @@ -28,14 +29,15 @@ public final class HashingUtils { * Gets a fake hash for the given block item. This is a placeholder and should be replaced with * real hash functionality once the hedera-protobufs types are integrated. * - * @param bytes to get the fake hash for + * @param blockItem to get the fake hash for * @return the fake hash for the given block item * @throws NoSuchAlgorithmException thrown if the SHA-384 algorithm is not available */ - public static byte[] getFakeHash(@NonNull final byte[] bytes) throws NoSuchAlgorithmException { - Objects.requireNonNull(bytes); + public static byte[] getFakeHash(@NonNull final BlockItem blockItem) + throws NoSuchAlgorithmException { + Objects.requireNonNull(blockItem); final MessageDigest digest = MessageDigest.getInstance("SHA-384"); - return digest.digest(bytes); + return digest.digest(BlockItem.PROTOBUF.toBytes(blockItem).toByteArray()); } private HashingUtils() { diff --git a/common/src/main/java/com/hedera/block/common/utils/Translator.java b/common/src/main/java/com/hedera/block/common/utils/Translator.java new file mode 100644 index 000000000..99d6e5ad2 --- /dev/null +++ b/common/src/main/java/com/hedera/block/common/utils/Translator.java @@ -0,0 +1,218 @@ +/* + * Copyright (C) 2024 Hedera Hashgraph, LLC + * + * 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 com.hedera.block.common.utils; + +import static java.lang.System.Logger; +import static java.lang.System.Logger.Level.ERROR; +import static java.util.Objects.requireNonNull; + +import com.google.protobuf.InvalidProtocolBufferException; +import com.hedera.block.common.constants.ErrorMessageConstants; +import com.hedera.hapi.block.PublishStreamRequest; +import com.hedera.hapi.block.PublishStreamResponse; +import com.hedera.hapi.block.SingleBlockResponse; +import com.hedera.hapi.block.SubscribeStreamRequest; +import com.hedera.hapi.block.SubscribeStreamResponse; +import com.hedera.hapi.block.stream.BlockItem; +import com.hedera.pbj.runtime.Codec; +import com.hedera.pbj.runtime.ParseException; +import com.hedera.pbj.runtime.io.buffer.Bytes; +import com.hedera.pbj.runtime.io.stream.WritableStreamingData; +import edu.umd.cs.findbugs.annotations.NonNull; +import java.io.ByteArrayOutputStream; +import java.io.IOException; + +/** + * Translator class to convert between PBJ and google protoc objects. + * + *

TODO: Remove this class once the Helidon PBJ gRPC work is integrated. + */ +public final class Translator { + private static final Logger LOGGER = System.getLogger(Translator.class.getName()); + + private static final String INVALID_BUFFER_MESSAGE = + "Invalid protocol buffer converting %s from PBJ to protoc for %s"; + + /** + * Converts a {@link BlockItem} to a {@link com.hedera.hapi.block.stream.protoc.BlockItem}. + * + * @param blockItem the {@link BlockItem} to convert + * @return the converted {@link com.hedera.hapi.block.stream.protoc.BlockItem} + */ + @NonNull + public static com.hedera.hapi.block.stream.protoc.BlockItem fromPbj( + @NonNull final BlockItem blockItem) { + try { + final byte[] pbjBytes = + asBytes(com.hedera.hapi.block.stream.BlockItem.PROTOBUF, blockItem); + return com.hedera.hapi.block.stream.protoc.BlockItem.parseFrom(pbjBytes); + } catch (final InvalidProtocolBufferException e) { + final String message = + INVALID_BUFFER_MESSAGE.formatted("SingleBlockResponse", blockItem); + LOGGER.log(ERROR, message); + throw new RuntimeException(message, e); + } + } + + /** + * Converts a {@link SingleBlockResponse} to a {@link + * com.hedera.hapi.block.protoc.SingleBlockResponse}. + * + * @param singleBlockResponse the {@link SingleBlockResponse} to convert + * @return the converted {@link com.hedera.hapi.block.protoc.SingleBlockResponse} + */ + @NonNull + public static com.hedera.hapi.block.protoc.SingleBlockResponse fromPbj( + @NonNull final SingleBlockResponse singleBlockResponse) { + try { + final byte[] pbjBytes = asBytes(SingleBlockResponse.PROTOBUF, singleBlockResponse); + return com.hedera.hapi.block.protoc.SingleBlockResponse.parseFrom(pbjBytes); + } catch (final InvalidProtocolBufferException e) { + final String message = + INVALID_BUFFER_MESSAGE.formatted("SingleBlockResponse", singleBlockResponse); + LOGGER.log(ERROR, message); + throw new RuntimeException(message, e); + } + } + + /** + * Converts a {@link PublishStreamResponse} to a {@link + * com.hedera.hapi.block.protoc.PublishStreamResponse}. + * + * @param publishStreamResponse the {@link PublishStreamResponse} to convert + * @return the converted {@link com.hedera.hapi.block.protoc.PublishStreamResponse} + */ + @NonNull + public static com.hedera.hapi.block.protoc.PublishStreamResponse fromPbj( + @NonNull final PublishStreamResponse publishStreamResponse) { + try { + final byte[] pbjBytes = asBytes(PublishStreamResponse.PROTOBUF, publishStreamResponse); + return com.hedera.hapi.block.protoc.PublishStreamResponse.parseFrom(pbjBytes); + } catch (final InvalidProtocolBufferException e) { + final String message = + INVALID_BUFFER_MESSAGE.formatted( + "PublishStreamResponse", publishStreamResponse); + LOGGER.log(ERROR, message); + throw new RuntimeException(message, e); + } + } + + /** + * Converts a {@link PublishStreamRequest} to a {@link + * com.hedera.hapi.block.protoc.PublishStreamRequest}. + * + * @param publishStreamRequest the {@link PublishStreamRequest} to convert + * @return the converted {@link com.hedera.hapi.block.protoc.PublishStreamRequest} + */ + @NonNull + public static com.hedera.hapi.block.protoc.PublishStreamRequest fromPbj( + @NonNull final PublishStreamRequest publishStreamRequest) { + try { + final byte[] pbjBytes = asBytes(PublishStreamRequest.PROTOBUF, publishStreamRequest); + return com.hedera.hapi.block.protoc.PublishStreamRequest.parseFrom(pbjBytes); + } catch (final InvalidProtocolBufferException e) { + final String message = + INVALID_BUFFER_MESSAGE.formatted("PublishStreamRequest", publishStreamRequest); + LOGGER.log(ERROR, message); + throw new RuntimeException(message, e); + } + } + + /** + * Converts a {@link SubscribeStreamResponse} to a {@link + * com.hedera.hapi.block.protoc.SubscribeStreamResponse}. + * + * @param subscribeStreamResponse the {@link SubscribeStreamResponse} to convert + * @return the converted {@link com.hedera.hapi.block.protoc.SubscribeStreamResponse} + */ + @NonNull + public static com.hedera.hapi.block.protoc.SubscribeStreamResponse fromPbj( + @NonNull final SubscribeStreamResponse subscribeStreamResponse) { + try { + final byte[] pbjBytes = + asBytes(SubscribeStreamResponse.PROTOBUF, subscribeStreamResponse); + return com.hedera.hapi.block.protoc.SubscribeStreamResponse.parseFrom(pbjBytes); + } catch (final InvalidProtocolBufferException e) { + final String message = + INVALID_BUFFER_MESSAGE.formatted( + "SubscribeStreamResponse", subscribeStreamResponse); + LOGGER.log(ERROR, message); + throw new RuntimeException(message, e); + } + } + + /** + * Converts a {@link SubscribeStreamRequest} to a {@link + * com.hedera.hapi.block.protoc.SubscribeStreamRequest}. + * + * @param subscribeStreamRequest the {@link SubscribeStreamRequest} to convert + * @return the converted {@link com.hedera.hapi.block.protoc.SubscribeStreamRequest} + */ + @NonNull + public static com.hedera.hapi.block.protoc.SubscribeStreamRequest fromPbj( + @NonNull final SubscribeStreamRequest subscribeStreamRequest) { + try { + final byte[] pbjBytes = + asBytes(SubscribeStreamRequest.PROTOBUF, subscribeStreamRequest); + return com.hedera.hapi.block.protoc.SubscribeStreamRequest.parseFrom(pbjBytes); + } catch (final InvalidProtocolBufferException e) { + final String message = + INVALID_BUFFER_MESSAGE.formatted( + "SubscribeStreamRequest", subscribeStreamRequest); + LOGGER.log(ERROR, message); + throw new RuntimeException(message, e); + } + } + + /** + * Converts protoc bytes to a PBJ record of the same type. + * + * @param the type of PBJ record to convert to + * @param codec the record codec to convert the bytes to a PBJ record + * @param bytes the protoc bytes to convert to a PBJ record + * @return the converted PBJ record + * @throws ParseException if the conversion between the protoc bytes and PBJ objects fails + */ + @NonNull + public static T toPbj( + @NonNull final Codec codec, @NonNull final byte[] bytes) throws ParseException { + requireNonNull(codec); + requireNonNull(bytes); + return codec.parse(Bytes.wrap(bytes)); + } + + @NonNull + private static byte[] asBytes( + @NonNull final Codec codec, @NonNull final T tx) { + requireNonNull(codec); + requireNonNull(tx); + try (final ByteArrayOutputStream baos = new ByteArrayOutputStream(); + final WritableStreamingData wsd = new WritableStreamingData(baos)) { + // TODO: should 'baos' and 'wsd' be used like that (autoclosed) here? Probably yes, but + // maybe something I do not know? + codec.write(tx, wsd); + return baos.toByteArray(); + } catch (final IOException e) { + throw new RuntimeException("Unable to convert from PBJ to bytes", e); + } + } + + private Translator() { + throw new UnsupportedOperationException( + ErrorMessageConstants.CREATING_INSTANCES_NOT_SUPPORTED); + } +} diff --git a/common/src/main/java/module-info.java b/common/src/main/java/module-info.java index d11a39b91..4e2ba7bcd 100644 --- a/common/src/main/java/module-info.java +++ b/common/src/main/java/module-info.java @@ -1,5 +1,8 @@ module com.hedera.block.common { exports com.hedera.block.common.constants; + requires com.hedera.block.stream; + requires com.google.protobuf; + requires com.hedera.pbj.runtime; requires static com.github.spotbugs.annotations; } From 887e763274cb2c5278ccbad5c989455137c6652f Mon Sep 17 00:00:00 2001 From: Atanas Atanasov Date: Tue, 15 Oct 2024 14:11:04 +0300 Subject: [PATCH 04/10] addressing comment Signed-off-by: Atanas Atanasov --- .../hedera/block/common/utils/FileUtils.java | 38 +++++++++++----- .../block/common/utils/StringUtils.java | 45 +++++++++++++++++++ 2 files changed, 71 insertions(+), 12 deletions(-) create mode 100644 common/src/main/java/com/hedera/block/common/utils/StringUtils.java diff --git a/common/src/main/java/com/hedera/block/common/utils/FileUtils.java b/common/src/main/java/com/hedera/block/common/utils/FileUtils.java index 5517ccfd8..0ecd8df32 100644 --- a/common/src/main/java/com/hedera/block/common/utils/FileUtils.java +++ b/common/src/main/java/com/hedera/block/common/utils/FileUtils.java @@ -53,27 +53,41 @@ public final class FileUtils { PosixFilePermission.OTHERS_EXECUTE)); /** - * Use this to create a Dir if it does not exist with the given permissions and log the result. + * Use this to create a Dir or File if it does not exist with the given permissions and log the + * result. * - * @param blockNodePath the path to create - * @param logLevel the log level to use - * @param perms the permissions to use when creating the directory + * @param toCreate valid, non-null instance of {@link Path} to be created + * @param logLevel valid, non-null instance of {@link System.Logger.Level} to use + * @param perms valid, non-null instance of {@link FileAttribute} permissions to use when + * creating the path + * @param semanticPathName valid, non-blank {@link String} used for logging that represents the + * desired path semantically + * @param createDir {@link Boolean} value if we should create a directory or a file * @throws IOException if the directory cannot be created */ public static void createPathIfNotExists( - @NonNull final Path blockNodePath, + @NonNull final Path toCreate, @NonNull final System.Logger.Level logLevel, - @NonNull final FileAttribute> perms) + @NonNull final FileAttribute> perms, + final String semanticPathName, + final boolean createDir) throws IOException { - Objects.requireNonNull(blockNodePath); + Objects.requireNonNull(toCreate); Objects.requireNonNull(logLevel); Objects.requireNonNull(perms); - // Initialize the Block directory if it does not exist - if (Files.notExists(blockNodePath)) { - Files.createDirectory(blockNodePath, perms); - LOGGER.log(logLevel, "Created block node root directory: " + blockNodePath); + StringUtils.requireNotBlank(semanticPathName); + final String type = createDir ? "directory" : "file"; + if (Files.notExists(toCreate)) { + if (createDir) { + Files.createDirectories(toCreate, perms); + } else { + Files.createFile(toCreate, perms); + } + LOGGER.log(logLevel, "Created " + type + " [" + semanticPathName + "] at:" + toCreate); } else { - LOGGER.log(logLevel, "Using existing block node root directory: " + blockNodePath); + LOGGER.log( + logLevel, + "Using existing " + type + " [" + semanticPathName + "] at:" + toCreate); } } diff --git a/common/src/main/java/com/hedera/block/common/utils/StringUtils.java b/common/src/main/java/com/hedera/block/common/utils/StringUtils.java new file mode 100644 index 000000000..63dcb9daa --- /dev/null +++ b/common/src/main/java/com/hedera/block/common/utils/StringUtils.java @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2024 Hedera Hashgraph, LLC + * + * 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 com.hedera.block.common.utils; + +import com.hedera.block.common.constants.ErrorMessageConstants; +import java.util.Objects; + +/** A utility class that deals with logic related to {@link String}s. */ +public final class StringUtils { + /** + * This method checks if a given {@link String} is blank, meaning if it is {@code null} or + * contains only whitespaces as defined by {@link String#isBlank()}. If the given {@link String} + * is not blank, then we return it, else we throw {@link IllegalArgumentException}. + * + * @param toCheck a {@link String} to be checked if is blank as defined above + * @return the {@link String} to be checked if it is not blank as defined above + * @throws IllegalArgumentException if the input {@link String} to be checked is blank + */ + public static String requireNotBlank(final String toCheck) { + if (Objects.isNull(toCheck) || toCheck.isBlank()) { + throw new IllegalArgumentException("String is required not blank!"); + } else { + return toCheck; + } + } + + private StringUtils() { + throw new UnsupportedOperationException( + ErrorMessageConstants.CREATING_INSTANCES_NOT_SUPPORTED); + } +} From e1c9160c2c758d43d69a33e26ec47a2a02979966 Mon Sep 17 00:00:00 2001 From: Atanas Atanasov Date: Tue, 15 Oct 2024 14:16:50 +0300 Subject: [PATCH 05/10] add todo Signed-off-by: Atanas Atanasov --- .../main/java/com/hedera/block/common/utils/FileUtils.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/common/src/main/java/com/hedera/block/common/utils/FileUtils.java b/common/src/main/java/com/hedera/block/common/utils/FileUtils.java index 0ecd8df32..1406f77b5 100644 --- a/common/src/main/java/com/hedera/block/common/utils/FileUtils.java +++ b/common/src/main/java/com/hedera/block/common/utils/FileUtils.java @@ -63,13 +63,14 @@ public final class FileUtils { * @param semanticPathName valid, non-blank {@link String} used for logging that represents the * desired path semantically * @param createDir {@link Boolean} value if we should create a directory or a file - * @throws IOException if the directory cannot be created + * @throws IOException if the path cannot be created */ public static void createPathIfNotExists( @NonNull final Path toCreate, @NonNull final System.Logger.Level logLevel, @NonNull final FileAttribute> perms, - final String semanticPathName, + @NonNull final String semanticPathName, + // TODO: String should be @NotBlank if we could introduce jakarta.validations? final boolean createDir) throws IOException { Objects.requireNonNull(toCreate); From 764bfc44db00b4128f9fe9e53e8b4b5845ef48a5 Mon Sep 17 00:00:00 2001 From: Atanas Atanasov Date: Tue, 15 Oct 2024 19:35:12 +0300 Subject: [PATCH 06/10] resolved todo Signed-off-by: Atanas Atanasov --- .../src/main/java/com/hedera/block/common/utils/FileUtils.java | 1 - 1 file changed, 1 deletion(-) diff --git a/common/src/main/java/com/hedera/block/common/utils/FileUtils.java b/common/src/main/java/com/hedera/block/common/utils/FileUtils.java index 1406f77b5..8ff583575 100644 --- a/common/src/main/java/com/hedera/block/common/utils/FileUtils.java +++ b/common/src/main/java/com/hedera/block/common/utils/FileUtils.java @@ -70,7 +70,6 @@ public static void createPathIfNotExists( @NonNull final System.Logger.Level logLevel, @NonNull final FileAttribute> perms, @NonNull final String semanticPathName, - // TODO: String should be @NotBlank if we could introduce jakarta.validations? final boolean createDir) throws IOException { Objects.requireNonNull(toCreate); From 6bbfba21607001bc8966358a0384065741705d9d Mon Sep 17 00:00:00 2001 From: Atanas Atanasov Date: Tue, 15 Oct 2024 20:18:15 +0300 Subject: [PATCH 07/10] address some comments Signed-off-by: Atanas Atanasov --- .../constants/ErrorMessageConstants.java | 5 +---- .../common/constants/StringConstants.java | 20 +++++++++---------- .../hedera/block/common/utils/FileUtils.java | 1 - .../block/common/utils/StringUtils.java | 2 +- 4 files changed, 11 insertions(+), 17 deletions(-) diff --git a/common/src/main/java/com/hedera/block/common/constants/ErrorMessageConstants.java b/common/src/main/java/com/hedera/block/common/constants/ErrorMessageConstants.java index 417da6a6c..44c4676f3 100644 --- a/common/src/main/java/com/hedera/block/common/constants/ErrorMessageConstants.java +++ b/common/src/main/java/com/hedera/block/common/constants/ErrorMessageConstants.java @@ -16,11 +16,8 @@ package com.hedera.block.common.constants; -import edu.umd.cs.findbugs.annotations.NonNull; - -/** A class that holds common error message {@link String} literals that are used across projects */ +/** A class that holds common error message literals that are used across projects */ public final class ErrorMessageConstants { - @NonNull public static final String CREATING_INSTANCES_NOT_SUPPORTED = "Creating instances is not supported!"; diff --git a/common/src/main/java/com/hedera/block/common/constants/StringConstants.java b/common/src/main/java/com/hedera/block/common/constants/StringConstants.java index 9d94e3750..0401c6805 100644 --- a/common/src/main/java/com/hedera/block/common/constants/StringConstants.java +++ b/common/src/main/java/com/hedera/block/common/constants/StringConstants.java @@ -18,23 +18,21 @@ import static com.hedera.block.common.constants.ErrorMessageConstants.CREATING_INSTANCES_NOT_SUPPORTED; -import edu.umd.cs.findbugs.annotations.NonNull; - -/** A class that hold common {@link String} literals used across projects. */ +/** A class that hold common String literals used across projects. */ public final class StringConstants { // FILES - @NonNull public static final String APPLICATION_PROPERTIES = "app.properties"; - @NonNull public static final String LOGGING_PROPERTIES = "logging.properties"; + public static final String APPLICATION_PROPERTIES = "app.properties"; + public static final String LOGGING_PROPERTIES = "logging.properties"; // FILE EXTENSIONS - @NonNull public static final String BLOCK_FILE_EXTENSION = ".blk"; - @NonNull public static final String GZ_FILE_EXTENSION = ".gz"; + public static final String BLOCK_FILE_EXTENSION = ".blk"; + public static final String GZ_FILE_EXTENSION = ".gz"; // PROJECT RELATED - @NonNull public static final String SERVICE_NAME = "BlockStreamService"; - @NonNull public static final String CLIENT_STREAMING_METHOD_NAME = "publishBlockStream"; - @NonNull public static final String SERVER_STREAMING_METHOD_NAME = "subscribeBlockStream"; - @NonNull public static final String SINGLE_BLOCK_METHOD_NAME = "singleBlock"; + public static final String SERVICE_NAME = "BlockStreamService"; + public static final String CLIENT_STREAMING_METHOD_NAME = "publishBlockStream"; + public static final String SERVER_STREAMING_METHOD_NAME = "subscribeBlockStream"; + public static final String SINGLE_BLOCK_METHOD_NAME = "singleBlock"; private StringConstants() { throw new UnsupportedOperationException(CREATING_INSTANCES_NOT_SUPPORTED); diff --git a/common/src/main/java/com/hedera/block/common/utils/FileUtils.java b/common/src/main/java/com/hedera/block/common/utils/FileUtils.java index 8ff583575..ca1b77b8f 100644 --- a/common/src/main/java/com/hedera/block/common/utils/FileUtils.java +++ b/common/src/main/java/com/hedera/block/common/utils/FileUtils.java @@ -40,7 +40,6 @@ public final class FileUtils { * *

Default permissions are set to: rwxr-xr-x */ - @NonNull public static final FileAttribute> DEFAULT_PERMS = PosixFilePermissions.asFileAttribute( Set.of( diff --git a/common/src/main/java/com/hedera/block/common/utils/StringUtils.java b/common/src/main/java/com/hedera/block/common/utils/StringUtils.java index 63dcb9daa..95dfdba2d 100644 --- a/common/src/main/java/com/hedera/block/common/utils/StringUtils.java +++ b/common/src/main/java/com/hedera/block/common/utils/StringUtils.java @@ -19,7 +19,7 @@ import com.hedera.block.common.constants.ErrorMessageConstants; import java.util.Objects; -/** A utility class that deals with logic related to {@link String}s. */ +/** A utility class that deals with logic related to Strings. */ public final class StringUtils { /** * This method checks if a given {@link String} is blank, meaning if it is {@code null} or From b0f09e9ea91749d5979458c13f0aa5902d176550 Mon Sep 17 00:00:00 2001 From: Atanas Atanasov Date: Tue, 15 Oct 2024 20:23:42 +0300 Subject: [PATCH 08/10] address more comments Signed-off-by: Atanas Atanasov --- buildSrc/src/main/kotlin/com.hedera.block.common.gradle.kts | 2 +- common/build.gradle.kts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/buildSrc/src/main/kotlin/com.hedera.block.common.gradle.kts b/buildSrc/src/main/kotlin/com.hedera.block.common.gradle.kts index f5361b330..5fdfbba27 100644 --- a/buildSrc/src/main/kotlin/com.hedera.block.common.gradle.kts +++ b/buildSrc/src/main/kotlin/com.hedera.block.common.gradle.kts @@ -15,7 +15,7 @@ */ plugins { - id("application") + id("java-library") id("com.hedera.block.conventions") id("me.champeau.jmh") } diff --git a/common/build.gradle.kts b/common/build.gradle.kts index 97636aeb8..af82a2868 100644 --- a/common/build.gradle.kts +++ b/common/build.gradle.kts @@ -15,7 +15,7 @@ */ plugins { - id("application") + id("java-library") id("com.hedera.block.common") } From 0d3475bf166400e5e804ecd437fcb1985aa79b32 Mon Sep 17 00:00:00 2001 From: Atanas Atanasov Date: Tue, 15 Oct 2024 21:52:40 +0300 Subject: [PATCH 09/10] address pr comments based on new agreements Signed-off-by: Atanas Atanasov --- .../common/constants/StringConstants.java | 40 ---- ...rrorMessageConstants.java => Strings.java} | 13 +- .../hedera/block/common/utils/FileUtils.java | 46 ++-- .../block/common/utils/HashingUtils.java | 47 ---- .../block/common/utils/StringUtils.java | 6 +- .../hedera/block/common/utils/Translator.java | 218 ------------------ common/src/main/java/module-info.java | 3 - 7 files changed, 30 insertions(+), 343 deletions(-) delete mode 100644 common/src/main/java/com/hedera/block/common/constants/StringConstants.java rename common/src/main/java/com/hedera/block/common/constants/{ErrorMessageConstants.java => Strings.java} (63%) delete mode 100644 common/src/main/java/com/hedera/block/common/utils/HashingUtils.java delete mode 100644 common/src/main/java/com/hedera/block/common/utils/Translator.java diff --git a/common/src/main/java/com/hedera/block/common/constants/StringConstants.java b/common/src/main/java/com/hedera/block/common/constants/StringConstants.java deleted file mode 100644 index 0401c6805..000000000 --- a/common/src/main/java/com/hedera/block/common/constants/StringConstants.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (C) 2024 Hedera Hashgraph, LLC - * - * 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 com.hedera.block.common.constants; - -import static com.hedera.block.common.constants.ErrorMessageConstants.CREATING_INSTANCES_NOT_SUPPORTED; - -/** A class that hold common String literals used across projects. */ -public final class StringConstants { - // FILES - public static final String APPLICATION_PROPERTIES = "app.properties"; - public static final String LOGGING_PROPERTIES = "logging.properties"; - - // FILE EXTENSIONS - public static final String BLOCK_FILE_EXTENSION = ".blk"; - public static final String GZ_FILE_EXTENSION = ".gz"; - - // PROJECT RELATED - public static final String SERVICE_NAME = "BlockStreamService"; - public static final String CLIENT_STREAMING_METHOD_NAME = "publishBlockStream"; - public static final String SERVER_STREAMING_METHOD_NAME = "subscribeBlockStream"; - public static final String SINGLE_BLOCK_METHOD_NAME = "singleBlock"; - - private StringConstants() { - throw new UnsupportedOperationException(CREATING_INSTANCES_NOT_SUPPORTED); - } -} diff --git a/common/src/main/java/com/hedera/block/common/constants/ErrorMessageConstants.java b/common/src/main/java/com/hedera/block/common/constants/Strings.java similarity index 63% rename from common/src/main/java/com/hedera/block/common/constants/ErrorMessageConstants.java rename to common/src/main/java/com/hedera/block/common/constants/Strings.java index 44c4676f3..bdd36a084 100644 --- a/common/src/main/java/com/hedera/block/common/constants/ErrorMessageConstants.java +++ b/common/src/main/java/com/hedera/block/common/constants/Strings.java @@ -16,12 +16,11 @@ package com.hedera.block.common.constants; -/** A class that holds common error message literals that are used across projects */ -public final class ErrorMessageConstants { - public static final String CREATING_INSTANCES_NOT_SUPPORTED = - "Creating instances is not supported!"; +/** A class that hold common String literals used across projects. */ +public final class Strings { + // FILES + public static final String APPLICATION_PROPERTIES = "app.properties"; + public static final String LOGGING_PROPERTIES = "logging.properties"; - private ErrorMessageConstants() { - throw new UnsupportedOperationException(CREATING_INSTANCES_NOT_SUPPORTED); - } + private Strings() {} } diff --git a/common/src/main/java/com/hedera/block/common/utils/FileUtils.java b/common/src/main/java/com/hedera/block/common/utils/FileUtils.java index ca1b77b8f..355ccdd57 100644 --- a/common/src/main/java/com/hedera/block/common/utils/FileUtils.java +++ b/common/src/main/java/com/hedera/block/common/utils/FileUtils.java @@ -16,8 +16,6 @@ package com.hedera.block.common.utils; -import com.hedera.block.common.constants.ErrorMessageConstants; -import com.hedera.block.common.constants.StringConstants; import edu.umd.cs.findbugs.annotations.NonNull; import java.io.IOException; import java.io.InputStream; @@ -105,26 +103,28 @@ public static byte[] readGzFile(@NonNull final Path filePath) throws IOException } } - /** - * Read a file and return the content as a byte array. - * - * @param filePath Path to the file - * @return byte array of the content of the file or null if the file extension is not supported - * @throws IOException if an I/O error occurs - */ - public static byte[] readFileBytes(@NonNull final Path filePath) throws IOException { - final String filePathAsString = Objects.requireNonNull(filePath).toString(); - if (filePathAsString.endsWith(StringConstants.GZ_FILE_EXTENSION)) { - return readGzFile(filePath); - } else if (filePathAsString.endsWith(StringConstants.BLOCK_FILE_EXTENSION)) { - return Files.readAllBytes(filePath); - } else { - return null; - } - } + // TODO the below code required the .gz and .blk file extension strings that we agreed to remove + // please remove the method if you think it should not exist here, if it should, then should the + // string literals .gz and .blk be back in the Strings constants class, or introduced here + // directly + // /** + // * Read a file and return the content as a byte array. + // * + // * @param filePath Path to the file + // * @return byte array of the content of the file or null if the file extension is not + // supported + // * @throws IOException if an I/O error occurs + // */ + // public static byte[] readFileBytes(@NonNull final Path filePath) throws IOException { + // final String filePathAsString = Objects.requireNonNull(filePath).toString(); + // if (filePathAsString.endsWith(Strings.GZ_FILE_EXTENSION)) { + // return readGzFile(filePath); + // } else if (filePathAsString.endsWith(Strings.BLOCK_FILE_EXTENSION)) { + // return Files.readAllBytes(filePath); + // } else { + // return null; + // } + // } - private FileUtils() { - throw new UnsupportedOperationException( - ErrorMessageConstants.CREATING_INSTANCES_NOT_SUPPORTED); - } + private FileUtils() {} } diff --git a/common/src/main/java/com/hedera/block/common/utils/HashingUtils.java b/common/src/main/java/com/hedera/block/common/utils/HashingUtils.java deleted file mode 100644 index f2bd49258..000000000 --- a/common/src/main/java/com/hedera/block/common/utils/HashingUtils.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright (C) 2024 Hedera Hashgraph, LLC - * - * 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 com.hedera.block.common.utils; - -import com.hedera.block.common.constants.ErrorMessageConstants; -import com.hedera.hapi.block.stream.BlockItem; -import edu.umd.cs.findbugs.annotations.NonNull; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; -import java.util.Objects; - -/** A utility class that deals with logic related to hashing */ -public final class HashingUtils { - /** - * Gets a fake hash for the given block item. This is a placeholder and should be replaced with - * real hash functionality once the hedera-protobufs types are integrated. - * - * @param blockItem to get the fake hash for - * @return the fake hash for the given block item - * @throws NoSuchAlgorithmException thrown if the SHA-384 algorithm is not available - */ - public static byte[] getFakeHash(@NonNull final BlockItem blockItem) - throws NoSuchAlgorithmException { - Objects.requireNonNull(blockItem); - final MessageDigest digest = MessageDigest.getInstance("SHA-384"); - return digest.digest(BlockItem.PROTOBUF.toBytes(blockItem).toByteArray()); - } - - private HashingUtils() { - throw new UnsupportedOperationException( - ErrorMessageConstants.CREATING_INSTANCES_NOT_SUPPORTED); - } -} diff --git a/common/src/main/java/com/hedera/block/common/utils/StringUtils.java b/common/src/main/java/com/hedera/block/common/utils/StringUtils.java index 95dfdba2d..f9ed90669 100644 --- a/common/src/main/java/com/hedera/block/common/utils/StringUtils.java +++ b/common/src/main/java/com/hedera/block/common/utils/StringUtils.java @@ -16,7 +16,6 @@ package com.hedera.block.common.utils; -import com.hedera.block.common.constants.ErrorMessageConstants; import java.util.Objects; /** A utility class that deals with logic related to Strings. */ @@ -38,8 +37,5 @@ public static String requireNotBlank(final String toCheck) { } } - private StringUtils() { - throw new UnsupportedOperationException( - ErrorMessageConstants.CREATING_INSTANCES_NOT_SUPPORTED); - } + private StringUtils() {} } diff --git a/common/src/main/java/com/hedera/block/common/utils/Translator.java b/common/src/main/java/com/hedera/block/common/utils/Translator.java deleted file mode 100644 index 99d6e5ad2..000000000 --- a/common/src/main/java/com/hedera/block/common/utils/Translator.java +++ /dev/null @@ -1,218 +0,0 @@ -/* - * Copyright (C) 2024 Hedera Hashgraph, LLC - * - * 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 com.hedera.block.common.utils; - -import static java.lang.System.Logger; -import static java.lang.System.Logger.Level.ERROR; -import static java.util.Objects.requireNonNull; - -import com.google.protobuf.InvalidProtocolBufferException; -import com.hedera.block.common.constants.ErrorMessageConstants; -import com.hedera.hapi.block.PublishStreamRequest; -import com.hedera.hapi.block.PublishStreamResponse; -import com.hedera.hapi.block.SingleBlockResponse; -import com.hedera.hapi.block.SubscribeStreamRequest; -import com.hedera.hapi.block.SubscribeStreamResponse; -import com.hedera.hapi.block.stream.BlockItem; -import com.hedera.pbj.runtime.Codec; -import com.hedera.pbj.runtime.ParseException; -import com.hedera.pbj.runtime.io.buffer.Bytes; -import com.hedera.pbj.runtime.io.stream.WritableStreamingData; -import edu.umd.cs.findbugs.annotations.NonNull; -import java.io.ByteArrayOutputStream; -import java.io.IOException; - -/** - * Translator class to convert between PBJ and google protoc objects. - * - *

TODO: Remove this class once the Helidon PBJ gRPC work is integrated. - */ -public final class Translator { - private static final Logger LOGGER = System.getLogger(Translator.class.getName()); - - private static final String INVALID_BUFFER_MESSAGE = - "Invalid protocol buffer converting %s from PBJ to protoc for %s"; - - /** - * Converts a {@link BlockItem} to a {@link com.hedera.hapi.block.stream.protoc.BlockItem}. - * - * @param blockItem the {@link BlockItem} to convert - * @return the converted {@link com.hedera.hapi.block.stream.protoc.BlockItem} - */ - @NonNull - public static com.hedera.hapi.block.stream.protoc.BlockItem fromPbj( - @NonNull final BlockItem blockItem) { - try { - final byte[] pbjBytes = - asBytes(com.hedera.hapi.block.stream.BlockItem.PROTOBUF, blockItem); - return com.hedera.hapi.block.stream.protoc.BlockItem.parseFrom(pbjBytes); - } catch (final InvalidProtocolBufferException e) { - final String message = - INVALID_BUFFER_MESSAGE.formatted("SingleBlockResponse", blockItem); - LOGGER.log(ERROR, message); - throw new RuntimeException(message, e); - } - } - - /** - * Converts a {@link SingleBlockResponse} to a {@link - * com.hedera.hapi.block.protoc.SingleBlockResponse}. - * - * @param singleBlockResponse the {@link SingleBlockResponse} to convert - * @return the converted {@link com.hedera.hapi.block.protoc.SingleBlockResponse} - */ - @NonNull - public static com.hedera.hapi.block.protoc.SingleBlockResponse fromPbj( - @NonNull final SingleBlockResponse singleBlockResponse) { - try { - final byte[] pbjBytes = asBytes(SingleBlockResponse.PROTOBUF, singleBlockResponse); - return com.hedera.hapi.block.protoc.SingleBlockResponse.parseFrom(pbjBytes); - } catch (final InvalidProtocolBufferException e) { - final String message = - INVALID_BUFFER_MESSAGE.formatted("SingleBlockResponse", singleBlockResponse); - LOGGER.log(ERROR, message); - throw new RuntimeException(message, e); - } - } - - /** - * Converts a {@link PublishStreamResponse} to a {@link - * com.hedera.hapi.block.protoc.PublishStreamResponse}. - * - * @param publishStreamResponse the {@link PublishStreamResponse} to convert - * @return the converted {@link com.hedera.hapi.block.protoc.PublishStreamResponse} - */ - @NonNull - public static com.hedera.hapi.block.protoc.PublishStreamResponse fromPbj( - @NonNull final PublishStreamResponse publishStreamResponse) { - try { - final byte[] pbjBytes = asBytes(PublishStreamResponse.PROTOBUF, publishStreamResponse); - return com.hedera.hapi.block.protoc.PublishStreamResponse.parseFrom(pbjBytes); - } catch (final InvalidProtocolBufferException e) { - final String message = - INVALID_BUFFER_MESSAGE.formatted( - "PublishStreamResponse", publishStreamResponse); - LOGGER.log(ERROR, message); - throw new RuntimeException(message, e); - } - } - - /** - * Converts a {@link PublishStreamRequest} to a {@link - * com.hedera.hapi.block.protoc.PublishStreamRequest}. - * - * @param publishStreamRequest the {@link PublishStreamRequest} to convert - * @return the converted {@link com.hedera.hapi.block.protoc.PublishStreamRequest} - */ - @NonNull - public static com.hedera.hapi.block.protoc.PublishStreamRequest fromPbj( - @NonNull final PublishStreamRequest publishStreamRequest) { - try { - final byte[] pbjBytes = asBytes(PublishStreamRequest.PROTOBUF, publishStreamRequest); - return com.hedera.hapi.block.protoc.PublishStreamRequest.parseFrom(pbjBytes); - } catch (final InvalidProtocolBufferException e) { - final String message = - INVALID_BUFFER_MESSAGE.formatted("PublishStreamRequest", publishStreamRequest); - LOGGER.log(ERROR, message); - throw new RuntimeException(message, e); - } - } - - /** - * Converts a {@link SubscribeStreamResponse} to a {@link - * com.hedera.hapi.block.protoc.SubscribeStreamResponse}. - * - * @param subscribeStreamResponse the {@link SubscribeStreamResponse} to convert - * @return the converted {@link com.hedera.hapi.block.protoc.SubscribeStreamResponse} - */ - @NonNull - public static com.hedera.hapi.block.protoc.SubscribeStreamResponse fromPbj( - @NonNull final SubscribeStreamResponse subscribeStreamResponse) { - try { - final byte[] pbjBytes = - asBytes(SubscribeStreamResponse.PROTOBUF, subscribeStreamResponse); - return com.hedera.hapi.block.protoc.SubscribeStreamResponse.parseFrom(pbjBytes); - } catch (final InvalidProtocolBufferException e) { - final String message = - INVALID_BUFFER_MESSAGE.formatted( - "SubscribeStreamResponse", subscribeStreamResponse); - LOGGER.log(ERROR, message); - throw new RuntimeException(message, e); - } - } - - /** - * Converts a {@link SubscribeStreamRequest} to a {@link - * com.hedera.hapi.block.protoc.SubscribeStreamRequest}. - * - * @param subscribeStreamRequest the {@link SubscribeStreamRequest} to convert - * @return the converted {@link com.hedera.hapi.block.protoc.SubscribeStreamRequest} - */ - @NonNull - public static com.hedera.hapi.block.protoc.SubscribeStreamRequest fromPbj( - @NonNull final SubscribeStreamRequest subscribeStreamRequest) { - try { - final byte[] pbjBytes = - asBytes(SubscribeStreamRequest.PROTOBUF, subscribeStreamRequest); - return com.hedera.hapi.block.protoc.SubscribeStreamRequest.parseFrom(pbjBytes); - } catch (final InvalidProtocolBufferException e) { - final String message = - INVALID_BUFFER_MESSAGE.formatted( - "SubscribeStreamRequest", subscribeStreamRequest); - LOGGER.log(ERROR, message); - throw new RuntimeException(message, e); - } - } - - /** - * Converts protoc bytes to a PBJ record of the same type. - * - * @param the type of PBJ record to convert to - * @param codec the record codec to convert the bytes to a PBJ record - * @param bytes the protoc bytes to convert to a PBJ record - * @return the converted PBJ record - * @throws ParseException if the conversion between the protoc bytes and PBJ objects fails - */ - @NonNull - public static T toPbj( - @NonNull final Codec codec, @NonNull final byte[] bytes) throws ParseException { - requireNonNull(codec); - requireNonNull(bytes); - return codec.parse(Bytes.wrap(bytes)); - } - - @NonNull - private static byte[] asBytes( - @NonNull final Codec codec, @NonNull final T tx) { - requireNonNull(codec); - requireNonNull(tx); - try (final ByteArrayOutputStream baos = new ByteArrayOutputStream(); - final WritableStreamingData wsd = new WritableStreamingData(baos)) { - // TODO: should 'baos' and 'wsd' be used like that (autoclosed) here? Probably yes, but - // maybe something I do not know? - codec.write(tx, wsd); - return baos.toByteArray(); - } catch (final IOException e) { - throw new RuntimeException("Unable to convert from PBJ to bytes", e); - } - } - - private Translator() { - throw new UnsupportedOperationException( - ErrorMessageConstants.CREATING_INSTANCES_NOT_SUPPORTED); - } -} diff --git a/common/src/main/java/module-info.java b/common/src/main/java/module-info.java index 4e2ba7bcd..d11a39b91 100644 --- a/common/src/main/java/module-info.java +++ b/common/src/main/java/module-info.java @@ -1,8 +1,5 @@ module com.hedera.block.common { exports com.hedera.block.common.constants; - requires com.hedera.block.stream; - requires com.google.protobuf; - requires com.hedera.pbj.runtime; requires static com.github.spotbugs.annotations; } From a1723d2ac4f41cd8c3ec5587c7828deb96a81934 Mon Sep 17 00:00:00 2001 From: Joseph Sinclair Date: Tue, 15 Oct 2024 16:31:41 -0700 Subject: [PATCH 10/10] Addressed review and other items * Fixed todo item by overloading method and moving default to local constant * Fixed some formatting issues * Fixed string utility to match more typical conventions * Modified "default" file permissions to not make everything executable * Renamed "abbreviated" classes to use full names * Renamed unsafe file methods to add "Unsafe" at the end * Documented why "unsafe" methods are not safe for production use * General cleanup Fixed a build headache * Modified spotless conventions to remove javadoc formatting for now * This was creating issues and conflicts between different tools; we'll need to add a proper _separate_ javadoc format once we can figure out how to do so within the ultra-strict spotless "write a new plugin" approach. Signed-off-by: Joseph Sinclair --- ...block.spotless-java-conventions.gradle.kts | 11 +- .../{Strings.java => StringsConstants.java} | 12 +- .../block/common/utils/FileUtilities.java | 221 ++++++++++++++++++ .../hedera/block/common/utils/FileUtils.java | 130 ----------- ...{StringUtils.java => StringUtilities.java} | 11 +- common/src/main/java/module-info.java | 1 + 6 files changed, 246 insertions(+), 140 deletions(-) rename common/src/main/java/com/hedera/block/common/constants/{Strings.java => StringsConstants.java} (82%) create mode 100644 common/src/main/java/com/hedera/block/common/utils/FileUtilities.java delete mode 100644 common/src/main/java/com/hedera/block/common/utils/FileUtils.java rename common/src/main/java/com/hedera/block/common/utils/{StringUtils.java => StringUtilities.java} (79%) diff --git a/buildSrc/src/main/kotlin/com.hedera.block.spotless-java-conventions.gradle.kts b/buildSrc/src/main/kotlin/com.hedera.block.spotless-java-conventions.gradle.kts index 54f051165..248a8c9a2 100644 --- a/buildSrc/src/main/kotlin/com.hedera.block.spotless-java-conventions.gradle.kts +++ b/buildSrc/src/main/kotlin/com.hedera.block.spotless-java-conventions.gradle.kts @@ -19,11 +19,18 @@ plugins { id("com.diffplug.spotless") } spotless { java { targetExclude("build/generated/**/*.java", "build/generated/**/*.proto") - // enable toggle comment support + // Enables the spotless:on and spotless:off comments toggleOffOn() // don't need to set target, it is inferred from java // apply a specific flavor of google-java-format - googleJavaFormat("1.17.0").aosp().reflowLongStrings() + // also reflow long strings, and do not format javadoc + // because the default setup is _very_ bad for javadoc + // We need to figure out a "correct" _separate_ setup for that. + googleJavaFormat("1.17.0").aosp().reflowLongStrings().formatJavadoc(false) + // Fix some left-out items from the google plugin + indentWithSpaces(4) + trimTrailingWhitespace() + endWithNewline() // make sure every file has the following copyright header. // optionally, Spotless can set copyright years by digging // through git history (see "license" section below). diff --git a/common/src/main/java/com/hedera/block/common/constants/Strings.java b/common/src/main/java/com/hedera/block/common/constants/StringsConstants.java similarity index 82% rename from common/src/main/java/com/hedera/block/common/constants/Strings.java rename to common/src/main/java/com/hedera/block/common/constants/StringsConstants.java index bdd36a084..4aa7a0b7b 100644 --- a/common/src/main/java/com/hedera/block/common/constants/Strings.java +++ b/common/src/main/java/com/hedera/block/common/constants/StringsConstants.java @@ -17,10 +17,16 @@ package com.hedera.block.common.constants; /** A class that hold common String literals used across projects. */ -public final class Strings { - // FILES +public final class StringsConstants { + /** + * File name for application properties + */ public static final String APPLICATION_PROPERTIES = "app.properties"; + + /** + * File name for logging properties + */ public static final String LOGGING_PROPERTIES = "logging.properties"; - private Strings() {} + private StringsConstants() {} } diff --git a/common/src/main/java/com/hedera/block/common/utils/FileUtilities.java b/common/src/main/java/com/hedera/block/common/utils/FileUtilities.java new file mode 100644 index 000000000..d8dd9ae60 --- /dev/null +++ b/common/src/main/java/com/hedera/block/common/utils/FileUtilities.java @@ -0,0 +1,221 @@ +/* + * Copyright (C) 2024 Hedera Hashgraph, LLC + * + * 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 com.hedera.block.common.utils; + +import edu.umd.cs.findbugs.annotations.NonNull; +import java.io.IOException; +import java.lang.System.Logger; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.attribute.FileAttribute; +import java.nio.file.attribute.PosixFilePermission; +import java.nio.file.attribute.PosixFilePermissions; +import java.util.Objects; +import java.util.Set; +import java.util.zip.GZIPInputStream; + +/** A utility class that deals with logic related to dealing with files. */ +public final class FileUtilities { + private static final Logger LOGGER = System.getLogger(FileUtilities.class.getName()); + + /** + * The default file permissions for new files. + *

+ * Default permissions are set to: rw-r--r-- + */ + private static final FileAttribute> DEFAULT_FILE_PERMISSIONS = + PosixFilePermissions.asFileAttribute( + Set.of( + PosixFilePermission.OWNER_READ, + PosixFilePermission.OWNER_WRITE, + PosixFilePermission.GROUP_READ, + PosixFilePermission.OTHERS_READ)); + + /** + * Default folder permissions for new folders. + *

+ * Default permissions are set to: rwxr-xr-x + */ + private static final FileAttribute> DEFAULT_FOLDER_PERMISSIONS = + PosixFilePermissions.asFileAttribute( + Set.of( + PosixFilePermission.OWNER_READ, + PosixFilePermission.OWNER_WRITE, + PosixFilePermission.OWNER_EXECUTE, + PosixFilePermission.GROUP_READ, + PosixFilePermission.GROUP_EXECUTE, + PosixFilePermission.OTHERS_READ, + PosixFilePermission.OTHERS_EXECUTE)); + + /** + * Log message template used when a path is not created because a file + * or folder already exists at the requested path. + */ + private static final String PRE_EXISTING_FOLDER_MESSAGE = + "Requested %s [%s] not created because %s already exists at %s"; + + /** + * Create a new path (folder or file) if it does not exist. + * Any folders or files created will use default permissions. + * + * @param toCreate valid, non-null instance of {@link Path} to be created + * @param logLevel valid, non-null instance of {@link System.Logger.Level} to use + * @param semanticPathName valid, non-blank {@link String} used for logging that represents the + * desired path semantically + * @param createDir {@link Boolean} value if we should create a directory or a file + * @throws IOException if the path cannot be created + */ + public static void createPathIfNotExists( + @NonNull final Path toCreate, + @NonNull final System.Logger.Level logLevel, + @NonNull final String semanticPathName, + final boolean createDir) + throws IOException { + createPathIfNotExists( + toCreate, + logLevel, + DEFAULT_FILE_PERMISSIONS, + DEFAULT_FOLDER_PERMISSIONS, + semanticPathName, + createDir); + } + + /** + * Create a new path (folder or file) if it does not exist. + * + * @param toCreate The path to be created. + * @param logLevel The logging level to use when logging this event. + * @param filePermissions Permissions to use when creating a new file. + * @param folderPermissions Permissions to use when creating a new folder. + * @param semanticPathName A name to represent the path in a logging + * statement. + * @param createDir A flag indicating we should create a directory + * (true) or a file (false) + * @throws IOException if the path cannot be created due to a filesystem + * error. + */ + public static void createPathIfNotExists( + @NonNull final Path toCreate, + @NonNull final System.Logger.Level logLevel, + @NonNull final FileAttribute> filePermissions, + @NonNull final FileAttribute> folderPermissions, + @NonNull final String semanticPathName, + final boolean createDir) + throws IOException { + Objects.requireNonNull(toCreate); + Objects.requireNonNull(logLevel); + Objects.requireNonNull(filePermissions); + Objects.requireNonNull(folderPermissions); + StringUtilities.requireNotBlank(semanticPathName); + final String requestedType = createDir ? "directory" : "file"; + if (Files.notExists(toCreate)) { + if (createDir) { + Files.createDirectories(toCreate, folderPermissions); + } else { + Files.createFile(toCreate, filePermissions); + } + final String logMessage = + "Created %s [%s] at %s".formatted(requestedType, semanticPathName, toCreate); + LOGGER.log(logLevel, logMessage); + } else { + final String actualType = Files.isDirectory(toCreate) ? "directory" : "file"; + final String logMessage = + PRE_EXISTING_FOLDER_MESSAGE.formatted( + requestedType, semanticPathName, actualType, toCreate); + LOGGER.log(logLevel, logMessage); + } + } + + /** + * Read a GZIP file and return the content as a byte array. + *

+ * This method is _unsafe_ because it reads the entire file content into + * a single byte array, which can cause memory issues, and may fail if the + * file contains a large amount of data. + * + * @param filePath Path to the GZIP file. + * @return byte array containing the _uncompressed_ content of the GZIP file. + * @throws IOException if unable to read the file. + * @throws OutOfMemoryError if a byte array large enough to contain the + * file contents cannot be allocated (either because it exceeds MAX_INT + * bytes or exceeds available heap memory). + */ + public static byte[] readGzipFileUnsafe(@NonNull final Path filePath) throws IOException { + Objects.requireNonNull(filePath); + try (final var gzipInputStream = new GZIPInputStream(Files.newInputStream(filePath))) { + return gzipInputStream.readAllBytes(); + } + } + + /** + * Read a file and return the content as a byte array. + *

+ * This method uses default extensions for gzip and block files. + *

+ * This method is _unsafe_ because it reads the entire file content into + * a single byte array, which can cause memory issues, and may fail if the + * file contains a large amount of data. + * + * @param filePath Path to the file + * @return byte array of the content of the file or null if the file extension is not + * supported + * @throws IOException if unable to read the file. + * @throws OutOfMemoryError if a byte array large enough to contain the + * file contents cannot be allocated (either because it exceeds MAX_INT + * bytes or exceeds available heap memory). + */ + public static byte[] readFileBytesUnsafe(@NonNull final Path filePath) throws IOException { + return readFileBytesUnsafe(filePath, ".blk", ".gz"); + } + + /** + * Read a file and return the content as a byte array. + *

+ * This method is _unsafe_ because it reads the entire file content into + * a single byte array, which can cause memory issues, and may fail if the + * file contains a large amount of data. + * + * @param filePath Path to the file to read. + * @param blockFileExtension A file extension for block files. + * @param gzipFileExtension A file extension for gzip files. + * @return A byte array with the full contents of the file, or null if the + * file extension requested does not match at least one of the + * extensions provided (GZip or Block). + * @throws IOException if unable to read the file. + * @throws OutOfMemoryError if a byte array large enough to contain the + * file contents cannot be allocated (either because it exceeds MAX_INT + * bytes or exceeds available heap memory). + */ + public static byte[] readFileBytesUnsafe( + @NonNull final Path filePath, + @NonNull final String blockFileExtension, + @NonNull final String gzipFileExtension) + throws IOException { + final String filePathAsString = Objects.requireNonNull(filePath).toString(); + Objects.requireNonNull(blockFileExtension); + Objects.requireNonNull(gzipFileExtension); + if (filePathAsString.endsWith(gzipFileExtension)) { + return readGzipFileUnsafe(filePath); + } else if (filePathAsString.endsWith(blockFileExtension)) { + return Files.readAllBytes(filePath); + } else { + return null; + } + } + + private FileUtilities() {} +} diff --git a/common/src/main/java/com/hedera/block/common/utils/FileUtils.java b/common/src/main/java/com/hedera/block/common/utils/FileUtils.java deleted file mode 100644 index 355ccdd57..000000000 --- a/common/src/main/java/com/hedera/block/common/utils/FileUtils.java +++ /dev/null @@ -1,130 +0,0 @@ -/* - * Copyright (C) 2024 Hedera Hashgraph, LLC - * - * 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 com.hedera.block.common.utils; - -import edu.umd.cs.findbugs.annotations.NonNull; -import java.io.IOException; -import java.io.InputStream; -import java.lang.System.Logger; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.attribute.FileAttribute; -import java.nio.file.attribute.PosixFilePermission; -import java.nio.file.attribute.PosixFilePermissions; -import java.util.Objects; -import java.util.Set; -import java.util.zip.GZIPInputStream; - -/** A utility class that deals with logic related to dealing with files. */ -public final class FileUtils { - private static final Logger LOGGER = System.getLogger(FileUtils.class.getName()); - - /** - * Default file permissions defines the file and directory for the storage package. - * - *

Default permissions are set to: rwxr-xr-x - */ - public static final FileAttribute> DEFAULT_PERMS = - PosixFilePermissions.asFileAttribute( - Set.of( - PosixFilePermission.OWNER_READ, - PosixFilePermission.OWNER_WRITE, - PosixFilePermission.OWNER_EXECUTE, - PosixFilePermission.GROUP_READ, - PosixFilePermission.GROUP_EXECUTE, - PosixFilePermission.OTHERS_READ, - PosixFilePermission.OTHERS_EXECUTE)); - - /** - * Use this to create a Dir or File if it does not exist with the given permissions and log the - * result. - * - * @param toCreate valid, non-null instance of {@link Path} to be created - * @param logLevel valid, non-null instance of {@link System.Logger.Level} to use - * @param perms valid, non-null instance of {@link FileAttribute} permissions to use when - * creating the path - * @param semanticPathName valid, non-blank {@link String} used for logging that represents the - * desired path semantically - * @param createDir {@link Boolean} value if we should create a directory or a file - * @throws IOException if the path cannot be created - */ - public static void createPathIfNotExists( - @NonNull final Path toCreate, - @NonNull final System.Logger.Level logLevel, - @NonNull final FileAttribute> perms, - @NonNull final String semanticPathName, - final boolean createDir) - throws IOException { - Objects.requireNonNull(toCreate); - Objects.requireNonNull(logLevel); - Objects.requireNonNull(perms); - StringUtils.requireNotBlank(semanticPathName); - final String type = createDir ? "directory" : "file"; - if (Files.notExists(toCreate)) { - if (createDir) { - Files.createDirectories(toCreate, perms); - } else { - Files.createFile(toCreate, perms); - } - LOGGER.log(logLevel, "Created " + type + " [" + semanticPathName + "] at:" + toCreate); - } else { - LOGGER.log( - logLevel, - "Using existing " + type + " [" + semanticPathName + "] at:" + toCreate); - } - } - - /** - * Read a GZIP file and return the content as a byte array. - * - * @param filePath Path to the GZIP file - * @return byte array of the content of the GZIP file - * @throws IOException if an I/O error occurs - */ - public static byte[] readGzFile(@NonNull final Path filePath) throws IOException { - try (final InputStream fileInputStream = - Files.newInputStream(Objects.requireNonNull(filePath)); - final GZIPInputStream gzipInputStream = new GZIPInputStream(fileInputStream)) { - return gzipInputStream.readAllBytes(); - } - } - - // TODO the below code required the .gz and .blk file extension strings that we agreed to remove - // please remove the method if you think it should not exist here, if it should, then should the - // string literals .gz and .blk be back in the Strings constants class, or introduced here - // directly - // /** - // * Read a file and return the content as a byte array. - // * - // * @param filePath Path to the file - // * @return byte array of the content of the file or null if the file extension is not - // supported - // * @throws IOException if an I/O error occurs - // */ - // public static byte[] readFileBytes(@NonNull final Path filePath) throws IOException { - // final String filePathAsString = Objects.requireNonNull(filePath).toString(); - // if (filePathAsString.endsWith(Strings.GZ_FILE_EXTENSION)) { - // return readGzFile(filePath); - // } else if (filePathAsString.endsWith(Strings.BLOCK_FILE_EXTENSION)) { - // return Files.readAllBytes(filePath); - // } else { - // return null; - // } - // } - - private FileUtils() {} -} diff --git a/common/src/main/java/com/hedera/block/common/utils/StringUtils.java b/common/src/main/java/com/hedera/block/common/utils/StringUtilities.java similarity index 79% rename from common/src/main/java/com/hedera/block/common/utils/StringUtils.java rename to common/src/main/java/com/hedera/block/common/utils/StringUtilities.java index f9ed90669..4977fdcae 100644 --- a/common/src/main/java/com/hedera/block/common/utils/StringUtils.java +++ b/common/src/main/java/com/hedera/block/common/utils/StringUtilities.java @@ -16,10 +16,11 @@ package com.hedera.block.common.utils; +import edu.umd.cs.findbugs.annotations.NonNull; import java.util.Objects; /** A utility class that deals with logic related to Strings. */ -public final class StringUtils { +public final class StringUtilities { /** * This method checks if a given {@link String} is blank, meaning if it is {@code null} or * contains only whitespaces as defined by {@link String#isBlank()}. If the given {@link String} @@ -29,13 +30,13 @@ public final class StringUtils { * @return the {@link String} to be checked if it is not blank as defined above * @throws IllegalArgumentException if the input {@link String} to be checked is blank */ - public static String requireNotBlank(final String toCheck) { - if (Objects.isNull(toCheck) || toCheck.isBlank()) { - throw new IllegalArgumentException("String is required not blank!"); + public static String requireNotBlank(@NonNull final String toCheck) { + if (Objects.requireNonNull(toCheck).isBlank()) { + throw new IllegalArgumentException("A String required to be non-blank is blank."); } else { return toCheck; } } - private StringUtils() {} + private StringUtilities() {} } diff --git a/common/src/main/java/module-info.java b/common/src/main/java/module-info.java index d11a39b91..a6f56aab4 100644 --- a/common/src/main/java/module-info.java +++ b/common/src/main/java/module-info.java @@ -1,5 +1,6 @@ module com.hedera.block.common { exports com.hedera.block.common.constants; + exports com.hedera.block.common.utils; requires static com.github.spotbugs.annotations; }