All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.foreach.common.filemanager.services.CachingFileRepository Maven / Gradle / Ivy

Go to download

A number of general purpose libraries for Java. Dependencies are kept minimal but Spring framework is considered a base requirement for most libraries.

The newest version!
/*
 * Copyright 2014 the original author or authors
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.foreach.common.filemanager.services;

import com.foreach.common.filemanager.business.FileDescriptor;
import com.foreach.common.filemanager.business.FileResource;
import lombok.Builder;
import lombok.Getter;
import lombok.NonNull;
import lombok.extern.slf4j.Slf4j;

import java.util.function.BiFunction;
import java.util.function.Function;

/**
 * {@link FileRepository} implementation which deals out cached file resources.
 * Wraps around an existing file repository and will take its identity.
 * When a resource is fetched, a cache resource will be created as well from another repository,
 * identified by {@link #getCacheRepositoryId()}. A {@link CachedFileResource} will then be returned
 * which caches the target file resource in the one returned from the cache repository.
 * 

* This is mainly useful when you know that a file resource will be used several times once it is * fetched, and the actual target repository is slow (usually a remote repository, for example {@link AmazonS3FileRepository}). * Using a fast {@link LocalFileRepository} as cache repository can gain significant performance improvement. *

* Internally this implementation builds on {@link AbstractExpiringFileRepository}, where the actual cached item is the * one that expires (and is removed when it expires). See also {@link FileManagerModuleSettings#getExpiration()} for periodic expiration. *

* If file resource updates happen only through the {@link FileManager}, keeping target and cache in sync should * not be much of a problem. Multi-instance applications can use a {@link #withTranslatedFileDescriptor()} strategy * to ensure optimal cache use (for example with shared network storage). *

* NOTE: Developers should only register the caching version of the repository in their application. * * @author Arne Vandamme * @see CachedFileResource * @see #withGeneratedFileDescriptor() * @see #withTranslatedFileDescriptor() * @see ExpiringFileRepository * @since 1.4.0 */ @Slf4j public class CachingFileRepository extends AbstractExpiringFileRepository { /** * The id of the of the repository which contains the actual cache file resources. * Usually this will refer to a {@link LocalFileRepository} though this is not a requirement. */ @Getter private final String cacheRepositoryId; /** * Function used to resolve the file resource which should be used as the resource for the cache. * Takes the original {@link FileDescriptor} and the resolved cache {@link FileRepository} as input. */ private final BiFunction cacheFileResourceResolver; private FileManager fileManager; @Builder private CachingFileRepository( @NonNull FileRepository targetFileRepository, @NonNull String cacheRepositoryId, @NonNull BiFunction cacheFileResourceResolver, boolean expireOnShutdown, boolean expireOnEvict, int maxItemsToTrack, @NonNull Function expirationStrategy ) { super( targetFileRepository, expireOnShutdown, expireOnEvict, maxItemsToTrack, expirationStrategy ); this.cacheRepositoryId = cacheRepositoryId; this.cacheFileResourceResolver = cacheFileResourceResolver; } @Override public void setFileManager( FileManager fileManager ) { super.setFileManager( fileManager ); this.fileManager = fileManager; } @Override protected CachedFileResource createExpiringFileResource( FileDescriptor descriptor, FileResource targetFileResource ) { FileRepository cacheRepository = fileManager.getRepository( cacheRepositoryId ); FileResource cacheFileResource = cacheFileResourceResolver.apply( descriptor, cacheRepository ); return new CachedFileResource( targetFileResource, cacheFileResource, this ); } @Override protected void expire( CachedFileResource fileResource ) { fileResource.flushCache(); } /** * Pre-configures a caching file repository that generates a new file resource in the cache repository. * The cache file resource will always be different, even for the same target file resource. * This means that across applications or VM restarts, new cache resources will be created. * The builder is also preconfigured to remove all cached files on shutdown or eviction. *

* This strategy is the best approach if you are not using shared file storage across applications, * or if you explicitly do not want to reuse pre-existing cache files. * See {@link #withTranslatedFileDescriptor()} if you want to do the exact opposite. *

* By default only 100 file resources are cached and they are removed on {@link #expireTrackedItems()} * if they have not been accessed for longer than one hour. * * @return caching file repository builder * @see #withTranslatedFileDescriptor() */ @SuppressWarnings("WeakerAccess") public static CachingFileRepositoryBuilder withGeneratedFileDescriptor() { return builder().cacheFileResourceResolver( ( fd, repository ) -> repository.createFileResource() ) .expireOnEvict( true ) .expireOnShutdown( true ); } /** * Pre-configures a caching file repository which translates the target file descriptor into * a file descriptor in the cache repository. Both folder id and file name of the target file descriptor * will be kept. This means that the same target file descriptor will always result in the same cache file descriptor. * This builder is also preconfigured to NOT remove the actual cached files on shutdown or evictions. * It is assumed they will be reused whenever the target file descriptor is requested again. *

* Use this strategy if you have multiple applications and want to share the same cache file storage across them, * or if you want to reuse pre-existing cache files (useful for long-lived, rarely changing files). * See {@link #withGeneratedFileDescriptor()} if you want to have a more aggressive strategy which * renews its cache file resources more frequently. *

* By default only 100 file resources are cached and they are removed on {@link #expireTrackedItems()} * if they have not been accessed for longer than one hour. * * @return caching file repository builder * @see #withGeneratedFileDescriptor() */ @SuppressWarnings("WeakerAccess") public static CachingFileRepositoryBuilder withTranslatedFileDescriptor() { return builder() .cacheFileResourceResolver( ( fd, repository ) -> repository.getFileResource( FileDescriptor.of( repository.getRepositoryId(), fd.getFolderId(), fd.getFileId() ) ) ) .expireOnEvict( false ) .expireOnShutdown( false ); } @SuppressWarnings({ "unused", "squid:S1068" }) public static class CachingFileRepositoryBuilder { private String cacheRepositoryId = FileManager.TEMP_REPOSITORY; private boolean expireOnShutdown = true; private boolean expireOnEvict = true; private int maxItemsToTrack = 100; public CachingFileRepositoryBuilder() { timeBasedExpiration( 60 * 60 * 1000L, 0 ); } /** * Configures a time-based expiration strategy which expires resources * if they have not been accessed for longer than {@code maxUnusedDuration} or if their * creation time was longer than {@code maxAge} ago. Whichever condition matches. *

* Both time durations are in milliseconds. The reference for access time is {@link ExpiringFileResource#getLastAccessTime()}, * the reference for age is {@link ExpiringFileResource#getCreationTime()}. *

* Specifying zero or less will skip that condition. * * @param maxUnusedDuration maximum number of milliseconds that is allowed since last access time * @param maxAge maximum number of milliseconds that is allowed since cache has been created * @return builder */ @SuppressWarnings({ "UnusedReturnValue" }) public CachingFileRepositoryBuilder timeBasedExpiration( long maxUnusedDuration, long maxAge ) { return expirationStrategy( timeBasedExpirationStrategy( maxUnusedDuration, maxAge ) ); } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy