001/* 002 * SPDX-License-Identifier: Apache-2.0 003 * 004 * Copyright 2025-2026 The Enola <https://enola.dev> Authors 005 * 006 * Licensed under the Apache License, Version 2.0 (the "License"); 007 * you may not use this file except in compliance with the License. 008 * You may obtain a copy of the License at 009 * 010 * https://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018package dev.enola.common.io.resource; 019 020import dev.enola.common.ByteSeq; 021 022/** 023 * Change Token ("Tag") for {@link ReadableResource#changeToken()}. 024 * 025 * <p>This is named a "change token" and not "version" (or "revision") because that might imply 026 * something “numeric” - but this is explicitly NOT intended to be used for “is it newer or older” 027 * comparison, only “has it changed”. It's also not called a "fingerprint" because that might imply 028 * it's derived only from the content itself (like a hash), whereas this may be based on more than 029 * that, e.g. additional metadata. 030 */ 031// TODO Should implementations also hold and compare the ReadableResource? Or even just its IRI? 032public interface ChangeToken { // skipcq: JAVA-E1041 033 034 /** 035 * Check is this ChangeToken is different from that other ChangeToken. 036 * 037 * <p>If it's not sure, prefer "erring on the side of caution" by returning true instead of 038 * false. That's why two {@link #NOT_AVAILABLE} are considered representing (possibly) different 039 * resource contents (returns true). 040 */ 041 boolean isDifferent(ChangeToken other); 042 043 /** 044 * String representation of this ChangeToken, (only) for {@link 045 * ReadableResource#isDifferent(String)}. 046 * 047 * <p>Do not interpret the content of this String. It's intended to be used completely "opaque", 048 * and only for before & after comparison, on a Resource from the same URI. Implementations 049 * are encouraged to return strings which do not (directly) "look like something familiar", to 050 * avoid users relying on implementation details. 051 */ 052 String toString(); 053 054 ByteSeq toBytes(); 055 056 /** 057 * Constant (singleton) for "not available" change tokens. 058 * 059 * <p>Returned by {@link ReadableResource#changeToken()} when it's impossible to obtain a {@link 060 * ChangeToken} e.g. due to internal technical errors, including because the URI points to a 061 * non-existing resource. Its {@link #isDifferent(ChangeToken)} always returns true. 062 */ 063 ChangeToken NOT_AVAILABLE = 064 new ChangeToken() { 065 @Override 066 public boolean isDifferent(ChangeToken other) { 067 return true; 068 } 069 070 @Override 071 public String toString() { 072 return "N/A"; 073 } 074 075 @Override 076 public ByteSeq toBytes() { 077 return ByteSeq.EMPTY; 078 } 079 080 @Override 081 public boolean equals(Object obj) { 082 return obj == NOT_AVAILABLE; 083 } 084 085 @Override 086 public int hashCode() { 087 return System.identityHashCode(this); 088 } 089 }; 090}