Skip to content
This repository has been archived by the owner on Sep 30, 2024. It is now read-only.

Commit

Permalink
Abstract away FileIdGenerator implementations
Browse files Browse the repository at this point in the history
  • Loading branch information
QubitPi committed Apr 25, 2024
1 parent da2e200 commit 913d2ac
Show file tree
Hide file tree
Showing 5 changed files with 113 additions and 29 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,8 @@
*/
package io.github.qubitpi.athena.application;

import io.github.qubitpi.athena.config.SystemConfig;
import io.github.qubitpi.athena.config.SystemConfigFactory;
import io.github.qubitpi.athena.file.identifier.FileIdGenerator;
import io.github.qubitpi.athena.file.identifier.FileNameAndUploadedTimeBasedIdGenerator;
import io.github.qubitpi.athena.file.identifier.FileIdGeneratorFactory;
import io.github.qubitpi.athena.filestore.FileStore;
import io.github.qubitpi.athena.metadata.MetaData;
import io.github.qubitpi.athena.metastore.MetaStore;
Expand All @@ -28,31 +26,17 @@
import org.glassfish.hk2.api.TypeLiteral;
import org.glassfish.hk2.utilities.Binder;
import org.glassfish.hk2.utilities.binding.AbstractBinder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import graphql.schema.DataFetcher;
import jakarta.validation.constraints.NotNull;

import java.security.NoSuchAlgorithmException;

/**
* {@link AbstractBinderFactory} implements standard buildBinder functionality.
* <p>
* It is left to individual projects to subclass, providing {@link FileStore} and {@link MetaStore} classes, etc.
*/
public abstract class AbstractBinderFactory implements BinderFactory {

private static final Logger LOG = LoggerFactory.getLogger(AbstractBinderFactory.class);
private static final SystemConfig SYSTEM_CONFIG = SystemConfigFactory.getInstance();

private static final String FILE_ID_HASHING_ALGORITHM_KEY = "file_id_hashing_algorithm";
private static final String FILE_ID_HASHING_ALGORITHM_DEFAULT = "MD5";

private static final String FILE_ID_HASHING_ALGORITHM = SYSTEM_CONFIG.getStringProperty(
SYSTEM_CONFIG.getPackageVariableName(FILE_ID_HASHING_ALGORITHM_KEY)
).orElse(FILE_ID_HASHING_ALGORITHM_DEFAULT);

@Override
public Binder buildBinder() {
return new AbstractBinder() {
Expand Down Expand Up @@ -126,16 +110,7 @@ public void afterRegistration(final ResourceConfig resourceConfig) {
*/
@NotNull
protected FileIdGenerator buildFileIdGenerator() {
try {
return FileNameAndUploadedTimeBasedIdGenerator.algorithm(FILE_ID_HASHING_ALGORITHM);
} catch (final NoSuchAlgorithmException exception) {
final String message = String.format(
"'%s' is not a valid message digest algorithm name",
FILE_ID_HASHING_ALGORITHM
);
LOG.error(message, exception);
throw new IllegalStateException(message, exception);
}
return FileIdGeneratorFactory.getInstance();
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@
/**
* {@link FileIdGenerator} is responsible for generating unique identifiers as strings for any types of files.
* <p>
* To generate ID of arbitrary file, use {@link #apply(Object)}
* To generate ID of arbitrary file, use {@link #apply(Object)}. Please use {@link FileIdGeneratorFactory} to get
* instance of this type.
* <p>
* This is a functional interface and can therefore be used as the assignment target for a lambda expression or method
* reference.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
/*
* Copyright 2024 Jiaqi Liu
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.github.qubitpi.athena.file.identifier;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import io.github.qubitpi.athena.application.AbstractBinderFactory;
import io.github.qubitpi.athena.config.SystemConfig;
import io.github.qubitpi.athena.config.SystemConfigFactory;
import jakarta.validation.constraints.NotNull;
import net.jcip.annotations.Immutable;
import net.jcip.annotations.ThreadSafe;

import java.security.NoSuchAlgorithmException;

/**
* {@link FileIdGeneratorFactory} is an abstraction layer that hides the details of {@link FileIdGenerator} instance
* creation.
* <p>
* Please use {@link #getInstance()} always to get instance of {@link FileIdGenerator} whenever needed.
*/
@Immutable
@ThreadSafe
public class FileIdGeneratorFactory {

private static final Logger LOG = LoggerFactory.getLogger(AbstractBinderFactory.class);

private static final SystemConfig SYSTEM_CONFIG = SystemConfigFactory.getInstance();

private static final String FILE_ID_HASHING_ALGORITHM_KEY = "file_id_hashing_algorithm";
private static final String FILE_ID_HASHING_ALGORITHM_DEFAULT = "MD5";

private static final String FILE_ID_HASHING_ALGORITHM = SYSTEM_CONFIG.getStringProperty(
SYSTEM_CONFIG.getPackageVariableName(FILE_ID_HASHING_ALGORITHM_KEY)
).orElse(FILE_ID_HASHING_ALGORITHM_DEFAULT);

private static FileIdGenerator instance = null;

/**
* Returns a cached and fully initialized {@link FileIdGenerator} object with the "MD5" as the default hashing
* algorithm.
* <p>
* One can override the hashing algorithm by setting a {@link SystemConfig config property} whose key is
* {@code file_id_hashing_algorithm}.
*
* @return the same instance
*
* @throws IllegalStateException if the particular cryptographic algorithm is requested but is not available in the
* environment.
*/
@NotNull
public static FileIdGenerator getInstance() {
if (instance == null) {
try {
instance = FileNameAndUploadedTimeBasedIdGenerator.algorithm(FILE_ID_HASHING_ALGORITHM);
} catch (final NoSuchAlgorithmException exception) {
final String message = String.format(
"'%s' is not a valid message digest algorithm name",
FILE_ID_HASHING_ALGORITHM
);
LOG.error(message, exception);
throw new IllegalStateException(message, exception);
}
}

return instance;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
*/
@Immutable
@ThreadSafe
public class FileNameAndUploadedTimeBasedIdGenerator implements FileIdGenerator {
class FileNameAndUploadedTimeBasedIdGenerator implements FileIdGenerator {

private final MessageDigest messageDigest;

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/*
* Copyright Jiaqi Liu
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.github.qubitpi.athena.file.identifier

import spock.lang.Specification

class FileIdGeneratorFactorySpec extends Specification {

def "Factory produces singleton"() {
expect:
FileIdGeneratorFactory.getInstance() is FileIdGeneratorFactory.getInstance()
}
}

0 comments on commit 913d2ac

Please sign in to comment.