package org.infinispan.functional.impl; import java.io.IOException; import java.io.ObjectInput; import java.io.ObjectOutput; import java.util.Optional; import java.util.Set; import java.util.concurrent.TimeUnit; import org.infinispan.commons.api.functional.MetaParam; import org.infinispan.commons.api.functional.MetaParam.MetaCreated; import org.infinispan.commons.api.functional.MetaParam.MetaEntryVersion; import org.infinispan.commons.api.functional.MetaParam.MetaLastUsed; import org.infinispan.commons.api.functional.MetaParam.MetaLifespan; import org.infinispan.commons.api.functional.MetaParam.MetaMaxIdle; import org.infinispan.commons.marshall.AbstractExternalizer; import org.infinispan.commons.util.Experimental; import org.infinispan.commons.util.Util; import org.infinispan.container.versioning.EntryVersion; import org.infinispan.container.versioning.FunctionalEntryVersionAdapter; import org.infinispan.marshall.core.Ids; import org.infinispan.metadata.InternalMetadata; import org.infinispan.metadata.Metadata; /** * Metadata parameters backed internal metadata representation. * * @since 8.0 */ @Experimental public final class MetaParamsInternalMetadata implements InternalMetadata, MetaParam.Lookup { final MetaParams params; public static Metadata from(MetaParams params) { return new MetaParamsInternalMetadata(params); } private MetaParamsInternalMetadata(MetaParams params) { this.params = params; } @Override public long created() { return params.find(MetaCreated.class).map(mc -> mc.get()).orElse(0L); } @Override public long lastUsed() { return params.find(MetaLastUsed.class).map(ml -> ml.get()).orElse(0L); } @Override public boolean isExpired(long now) { long expiryTime = expiryTime(); return expiryTime >= 0 && expiryTime <= now; } @Override public long expiryTime() { long deadline = -1; long lifespan = lifespan(); if (lifespan >= 0) { deadline = created() + lifespan; } long maxIdle = maxIdle(); if (maxIdle >= 0) { if (deadline < 0) { deadline = lastUsed() + maxIdle; } else { deadline = Math.min(deadline, lastUsed() + maxIdle); } } return deadline; } @Override public long lifespan() { return params.find(MetaLifespan.class) .orElse(MetaLifespan.defaultValue()).get(); } @Override public long maxIdle() { return params.find(MetaMaxIdle.class) .orElse(MetaMaxIdle.defaultValue()).get(); } @Override public EntryVersion version() { return params.find(MetaEntryVersion.class).map(MetaParamsInternalMetadata::versionOrNull).orElse(null); } private static EntryVersion versionOrNull(MetaEntryVersion mev) { org.infinispan.commons.api.functional.EntryVersion entryVersion = mev.get(); return entryVersion instanceof FunctionalEntryVersionAdapter ? ((FunctionalEntryVersionAdapter) entryVersion).get() : null; } @Override public Builder builder() { return new Builder(params.copy()); } @Override public <T> Optional<T> findMetaParam(Class<T> type) { return params.find(type); } @Override public String toString() { return "MetaParamsInternalMetadata{" + "params=" + params + '}'; } public static class Builder implements Metadata.Builder { private final MetaParams params; public Builder(MetaParams params) { this.params = params; } @Override public Metadata.Builder lifespan(long time, TimeUnit unit) { params.add(new MetaLifespan(unit.toMillis(time))); return this; } @Override public Metadata.Builder lifespan(long time) { params.add(new MetaLifespan(time)); return this; } @Override public Metadata.Builder maxIdle(long time, TimeUnit unit) { params.add(new MetaMaxIdle(unit.toMillis(time))); return this; } @Override public Metadata.Builder maxIdle(long time) { params.add(new MetaMaxIdle(time)); return this; } @Override public Metadata.Builder version(EntryVersion version) { params.add(new MetaEntryVersion<>(new FunctionalEntryVersionAdapter(version))); return this; } @Override public Metadata build() { return new MetaParamsInternalMetadata(params); } @Override public Metadata.Builder merge(Metadata metadata) { if (metadata instanceof MetaParamsInternalMetadata) { params.merge(((MetaParamsInternalMetadata) metadata).params); } else { if (!params.find(MetaLifespan.class).isPresent()) { lifespan(metadata.lifespan()); } if (!params.find(MetaMaxIdle.class).isPresent()) { maxIdle(metadata.maxIdle()); } if (!params.find(MetaEntryVersion.class).isPresent()) { version(metadata.version()); } } return this; } } public static final class Externalizer extends AbstractExternalizer<MetaParamsInternalMetadata> { @Override public void writeObject(ObjectOutput oo, MetaParamsInternalMetadata o) throws IOException { oo.writeObject(o.params); } @Override public MetaParamsInternalMetadata readObject(ObjectInput input) throws IOException, ClassNotFoundException { MetaParams params = (MetaParams) input.readObject(); return new MetaParamsInternalMetadata(params); } @Override public Set<Class<? extends MetaParamsInternalMetadata>> getTypeClasses() { return Util.<Class<? extends MetaParamsInternalMetadata>>asSet(MetaParamsInternalMetadata.class); } @Override public Integer getId() { return Ids.META_PARAMS_INTERNAL_METADATA; } } }