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

de.codesourcery.versiontracker.common.IVersionStorage Maven / Gradle / Ivy

There is a newer version: 1.0.28
Show newest version
/**
 * Copyright 2018 Tobias Gierke 
 *
 * 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 de.codesourcery.versiontracker.common;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import java.io.IOException;
import java.time.Duration;
import java.time.ZonedDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.regex.Pattern;

/**
 * Responsible for handling persistence of artifact metadata.
 *
 * @author [email protected]
 */
public interface IVersionStorage extends AutoCloseable
{
    Logger STORAGE_LOG = LogManager.getLogger(IVersionStorage.class);

    final class StorageStatistics
    {
        public ZonedDateTime lastStatisticsReset = ZonedDateTime.now();

        public int totalArtifactCount;
        public int totalVersionCount;

        public long storageSizeInBytes;

        public RequestsPerHour reads = new RequestsPerHour();
        public RequestsPerHour writes = new RequestsPerHour();

        /** Most recent time a user requested meta-data for an artifact */
        public ZonedDateTime mostRecentRequested = null;
        /** Most recent time meta-data for an artifact could not be retrieved from the repository */
        public ZonedDateTime mostRecentFailure = null;
        /** Most recent time meta-data for an artifact was retrieved successfully from the repository */
        public ZonedDateTime mostRecentSuccess = null;

        public StorageStatistics() {
        }

        public void reset()
        {
            totalArtifactCount = 0;
            totalVersionCount = 0;
            storageSizeInBytes = 0;

            reads.reset();
            writes.reset();

            mostRecentRequested = null;
            mostRecentFailure = null;
            mostRecentSuccess = null;

            lastStatisticsReset = ZonedDateTime.now();
        }

        public Optional mostRecentRequested() {
            return Optional.ofNullable( mostRecentRequested );
        }

        public Optional mostRecentFailure() {
            return Optional.ofNullable( mostRecentFailure );
        }

        public Optional mostRecentSuccess() {
            return Optional.ofNullable( mostRecentSuccess );
        }

        public StorageStatistics(StorageStatistics other) {
            this.totalArtifactCount = other.totalArtifactCount;
            this.totalVersionCount = other.totalVersionCount;
            this.storageSizeInBytes = other.storageSizeInBytes;
            this.mostRecentRequested = other.mostRecentRequested;
            this.mostRecentFailure = other.mostRecentFailure;
            this.mostRecentSuccess = other.mostRecentSuccess;
            this.reads = other.reads.createCopy();
            this.writes = other.writes.createCopy();
            this.lastStatisticsReset = other.lastStatisticsReset;
        }

        public StorageStatistics createCopy() {
            return new StorageStatistics(this);
        }
    }

    /**
     * Retrieves metadata for all artifacts.
     * 
     * @return
     * @throws IOException
     */
    List getAllVersions() throws IOException;

    /**
     * Retrieves metadata for all artifacts.
     *
     * @return
     * @throws IOException
     */
    default List getAllVersions(String groupRegEx, String artifactRegEx) throws IOException {

        final Pattern groupPattern = Pattern.compile( groupRegEx );
        final Pattern artifactPattern = Pattern.compile( artifactRegEx );
        return getAllVersions().stream().filter( v -> groupPattern.matcher( v.artifact.groupId ).matches() &&
                artifactPattern.matcher( v.artifact.artifactId ).matches() )
            .toList();
    }

    /**
     * Returns statistics about this storage.
     *
     * @return
     * @see #resetStatistics()
     */
    StorageStatistics getStatistics();

    /**
     * Reset internal statistics.
     * @see #getStatistics()
     */
    void resetStatistics();

    /**
     * Returns all artifact metadata that either has never been requested at all
     * or , last successful request happened more than lastSuccessDuration
     * time ago or last failed request happened more than lastFailureDuration
     * ago (whatever happened last takes precedence here).
     * 
     * @param lastSuccessDuration
     * @param lastFailureDuration
     * @return
     * @throws IOException
     */
    default List getAllStaleVersions(Duration lastSuccessDuration, Duration lastFailureDuration,ZonedDateTime now) throws IOException
    {
        final List result = new ArrayList<>();
        for ( VersionInfo info : getAllVersions() )
        {
            if ( isStaleVersion(info,lastSuccessDuration,lastFailureDuration,now) ) {
                result.add( info );
            }
        }
        return result;
    }    
    
    static boolean isStaleVersion(VersionInfo info,Duration minUpdateDelayAfterSuccess, Duration minUpdateDelayAfterFailure,ZonedDateTime now)
    {
        boolean isStale;
        if ( info.lastPolledDate() == null ) { // lastSuccessDate AND  lastFailureDate are NULL
            isStale = true;
            if ( STORAGE_LOG.isDebugEnabled() ) {
                STORAGE_LOG.debug("isStaleVersion(): [stale,never successfully polled at all] "+info.artifact);
            }
        } 
        else if ( info.lastSuccessDate != null &&  info.lastFailureDate != null ) // both are not NULL
        {
            if ( info.lastSuccessDate.isAfter( info.lastFailureDate ) ) {
                isStale = Duration.between( info.lastSuccessDate,now ).compareTo( minUpdateDelayAfterSuccess ) > 0;
                if ( isStale && STORAGE_LOG.isDebugEnabled() )
                {
                    STORAGE_LOG.debug("isStaleVersion(): [stale,lastSuccessDate "+info.lastSuccessDate+" is more than "+minUpdateDelayAfterSuccess+" ago] "+info.artifact);
                }                
            } else {
                isStale = Duration.between( info.lastFailureDate,now ).compareTo( minUpdateDelayAfterFailure ) > 0;
                if ( isStale && STORAGE_LOG.isDebugEnabled() )
                {
                    STORAGE_LOG.debug("isStaleVersion(): [stale,lastFailureDate "+info.lastFailureDate+" is more than "+minUpdateDelayAfterFailure+" ago] "+info.artifact);
                }                  
            }

        } else if ( info.lastSuccessDate == null ) { // polling never succeeded yet
            isStale = Duration.between( info.lastFailureDate,now ).compareTo( minUpdateDelayAfterFailure ) > 0;
            if ( isStale && STORAGE_LOG.isDebugEnabled() )
            {
                STORAGE_LOG.debug("isStaleVersion(): [stale,lastFailureDate "+info.lastFailureDate+" is more than "+minUpdateDelayAfterFailure+" ago] "+info.artifact);
            }             
        } else {
            // polling has always succeeded
            isStale = Duration.between( info.lastSuccessDate,now ).compareTo( minUpdateDelayAfterSuccess ) > 0;
            if ( isStale && STORAGE_LOG.isDebugEnabled() )
            {
                STORAGE_LOG.debug("isStaleVersion(): [stale,lastSuccessDate "+info.lastSuccessDate+" is more than "+minUpdateDelayAfterSuccess+" ago] "+info.artifact);
            }             
        } 
        return isStale;
    }
    
    /**
     * Stores or updates existing metadata.
     * 
     * @param info
     * @throws IOException
     * @see #saveOrUpdate(List)
     */
    void saveOrUpdate(VersionInfo info) throws IOException;
    
    /**
     * Tries to load metadata for a given artifact.
     * 
     * @param artifact
     * @return
     * @throws IOException
     */
    default Optional getVersionInfo(Artifact artifact) throws IOException
    {
        return getAllVersions().stream().filter( item -> item.artifact.matchesExcludingVersion( artifact ) ).findFirst();
    }    
    
    default void updateLastRequestDate(Artifact artifact, ZonedDateTime date) throws IOException
    {
        final Optional existing = getVersionInfo(artifact);
        if ( existing.isPresent() ) {
            existing.get().lastRequestDate = date;
            saveOrUpdate( existing.get() );
        }
    }
    
    /**
     * Bulk-storage of new or updated VersionInfo instances.
     * 
     * @param data
     * @throws IOException
     * 
     * @see #saveOrUpdate(VersionInfo)
     */
    void saveOrUpdate(List data) throws IOException;
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy