package diskCacheV111.vehicles;
import java.io.IOException;
import java.net.URI;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import diskCacheV111.util.AccessLatency;
import diskCacheV111.util.RetentionPolicy;
import static java.util.stream.Collectors.toMap;
public class GenericStorageInfo
implements StorageInfo
{
private static final long serialVersionUID = 2089636591513548893L;
/*
* to simulate the 'classic' behavior : new files go to tape and, after
* flushing, removed by sweeper if space needed.
*/
@Deprecated
private AccessLatency _accessLatency = StorageInfo.DEFAULT_ACCESS_LATENCY;
@Deprecated
private RetentionPolicy _retentionPolicy = StorageInfo.DEFAULT_RETENTION_POLICY;
private Map<String, String> _keyHash = new HashMap<>();
private List<URI> _locations = new ArrayList<>();
private boolean _setHsm;
private boolean _setStorageClass;
private boolean _setBitFileId;
private boolean _setLocation;
private boolean _isNew = true;
private boolean _isStored;
private String _hsm;
private String _cacheClass;
@Deprecated
private long _fileSize;
private String _storageClass;
@Deprecated
private String _bitfileId;
public GenericStorageInfo() {
}
public GenericStorageInfo(String hsm, String storageClass) {
_storageClass = storageClass;
_hsm = hsm;
}
@Deprecated
public void addKeys(Map<String, String> keys) {
_keyHash.putAll(keys);
}
@Override
public void addLocation(URI newLocation) {
_locations.add(newLocation);
}
@Override
@Deprecated
public String getBitfileId() {
return _bitfileId == null ? "<Unknown>" : _bitfileId;
}
@Override
public String getCacheClass() {
return _cacheClass;
}
@Override
public String getHsm() {
return _hsm;
}
@Override
@Deprecated
public String getKey(String key) {
return _keyHash.get(key);
}
@Override
@Deprecated
public Map<String, String> getMap() {
return new HashMap<>(_keyHash);
}
@Override
public String getStorageClass() {
return _storageClass;
}
@Override
public boolean isCreatedOnly() {
return _isNew;
}
@Override
public boolean isSetAddLocation() {
return _setLocation;
}
@Override
public void isSetAddLocation(boolean isSet) {
_setLocation = isSet;
}
@Override
@Deprecated
public boolean isSetBitFileId() {
return _setBitFileId;
}
@Override
@Deprecated
public void isSetBitFileId(boolean isSet) {
_setBitFileId = isSet;
}
@Override
public void setCacheClass(String newCacheClass) {
_cacheClass = newCacheClass;
}
@Override
public boolean isSetHsm() {
return _setHsm;
}
@Override
public void isSetHsm(boolean isSet) {
_setHsm = isSet;
}
@Override
public boolean isSetStorageClass() {
return _setStorageClass;
}
@Override
public void isSetStorageClass(boolean isSet) {
_setStorageClass = isSet;
}
/**
*
* @return true if locations list is not empty or ( legacy case )
* if value was explicit set by setIsStored(true)
*/
@Override
public boolean isStored() {
/*
* FIXME: _locations!= null is needed to read old SI files
*/
return _isStored || (_locations != null && !_locations.isEmpty());
}
@Override
public List<URI> locations() {
return _locations;
}
@Override
@Deprecated
public void setBitfileId(String bitfileId) {
_bitfileId = bitfileId;
}
@Override
public void setHsm(String newHsm) {
_hsm = newHsm;
}
@Override
public void setIsNew(boolean isNew) {
_isNew = isNew;
}
@Override
@Deprecated
public String setKey(String key, String value) {
if (value == null) {
return _keyHash.remove(key);
} else {
return _keyHash.put(key, value);
}
}
@Override
public void setStorageClass(String newStorageClass) {
_storageClass = newStorageClass;
}
/**
* @Deprecated the result will generated depending on content of locations
*/
@Override
@Deprecated
public void setIsStored( boolean isStored) {
_isStored = isStored;
}
@Override
public String toString() {
String sc = getStorageClass();
String cc = getCacheClass();
String hsm = getHsm();
AccessLatency ac = getLegacyAccessLatency();
RetentionPolicy rp = getLegacyRetentionPolicy();
StringBuilder sb = new StringBuilder();
sb.append("size=").append(getLegacySize()).append(";new=").append(
isCreatedOnly()).append(";stored=").append(isStored()).append(
";sClass=").append(sc == null ? "-" : sc).append(";cClass=")
.append(cc == null ? "-" : cc).append(";hsm=").append(
hsm == null ? "-" : hsm).append(";accessLatency=")
.append(ac == null ? "-" : ac.toString()).append(
";retentionPolicy=").append(
rp == null ? "-" : rp.toString()).append(';');
/*
* FIXME: extra checks are needed to read old SI files
*/
if( _keyHash != null ) {
for (Map.Entry<String, String> entry : _keyHash.entrySet()) {
String key = entry.getKey();
String value = entry.getValue();
sb.append(key).append('=').append(value).append(';');
}
}
if( _locations != null ) {
for(URI location : _locations ) {
sb.append(location).append(';');
}
}
return sb.toString();
}
@Override
public int hashCode() {
Set<URI> ourLocations = new HashSet<>( locations());
return getLegacyAccessLatency().hashCode() ^
getLegacyRetentionPolicy().hashCode() ^
ourLocations.hashCode() ^
(int) getLegacySize() ^
getStorageClass().hashCode() ^
(isStored() ? 1 << 0 : 0) ^
(isCreatedOnly() ? 1 << 1 : 0);
}
@Override
public boolean equals( Object o) {
if ( o == this) {
return true;
}
if( !( o instanceof GenericStorageInfo )) {
return false;
}
GenericStorageInfo other = (GenericStorageInfo)o;
if ( !other.getLegacyAccessLatency().equals( this.getLegacyAccessLatency()) ) {
return false;
}
if ( !other.getLegacyRetentionPolicy().equals( this.getLegacyRetentionPolicy()) ) {
return false;
}
/**
* Any non-zero number of occurrences of a URI are considered equivalent. A necessary
* condition for equality is that, for each location URI in this object, the other
* GenericStorageInfo must have at least one instance of the URI. Having more than one
* is OK.
*/
Set<URI> ourLocations = new HashSet<>( locations());
Set<URI> otherLocations = new HashSet<>( other.locations());
if( ! otherLocations.equals( ourLocations)) {
return false;
}
/**
* If two GenericStorageInfo objects have location URIs specified then we ignore any
* BitfieldId values.
*/
if( this.locations().isEmpty()) {
if ( other.getBitfileId() != null && this.getBitfileId() != null &&
! other.getBitfileId().equals(this.getBitfileId() )) {
return false;
}
if ( other.getBitfileId() != null && this.getBitfileId() == null ) {
return false;
}
if ( other.getBitfileId() == null && this.getBitfileId() != null ) {
return false;
}
}
if (!Objects.equals(other.getHsm(), this.getHsm())) {
return false;
}
if (!Objects.equals(other.getCacheClass(), this.getCacheClass())) {
return false;
}
if (!Objects.equals(other._keyHash, this._keyHash)) {
return false;
}
if (other.getLegacySize() != this.getLegacySize() ) {
return false;
}
if (!Objects.equals(other.getStorageClass(), this.getStorageClass())) {
return false;
}
if (other.isStored() != this.isStored() ) {
return false;
}
if (other.isCreatedOnly() != this.isCreatedOnly() ) {
return false;
}
return true;
}
/**
* Allow pre 1.8 storage info to be read. Allows old persistent storage info
* objects on pools to be read.
*/
Object readResolve() {
if(_accessLatency == null ) {
_accessLatency = AccessLatency.NEARLINE;
}
if(_retentionPolicy == null ) {
_retentionPolicy = RetentionPolicy.CUSTODIAL;
}
if(_locations == null ) {
_locations = new ArrayList<>();
}
return this;
}
@Override
public GenericStorageInfo clone()
{
try {
GenericStorageInfo copy = (GenericStorageInfo) super.clone();
copy._keyHash = new HashMap<>(_keyHash);
copy._locations = new ArrayList<>(_locations);
return copy;
} catch (CloneNotSupportedException e) {
throw new RuntimeException("Failed to clone storage info: " +
e.getMessage());
}
}
/**
* Create a {@link StorageInfo} corresponding to given store unit and cacheClass
*
* @param storeUnit
* @param cacheClass
* @return StorageInfo
* @throws IllegalArgumentException if store unit format do not match to
* x:y@z or equal to '*'
*/
public static StorageInfo valueOf(String storeUnit, String cacheClass)
throws IllegalArgumentException {
StorageInfo si;
if (storeUnit.equals("*")) {
si = new GenericStorageInfo();
} else {
String[] unitParts = storeUnit.split("@");
if (unitParts.length != 2) {
throw new IllegalArgumentException("Invalid format: expected<x:y@z> got <" + storeUnit + '>');
}
si = new GenericStorageInfo(unitParts[1], unitParts[0]);
}
if (!cacheClass.equals("*")) {
si.setCacheClass(cacheClass);
}
return si;
}
@Override
public void setLegacyAccessLatency(AccessLatency al) {
_accessLatency = al;
}
@Override
public AccessLatency getLegacyAccessLatency()
{
return _accessLatency;
}
@Override
public void setLegacyRetentionPolicy(RetentionPolicy rp) {
_retentionPolicy = rp;
}
@Override
public RetentionPolicy getLegacyRetentionPolicy()
{
return _retentionPolicy;
}
@Override
public long getLegacySize() {
return _fileSize;
}
@Override
public void setLegacySize(long fileSize) {
_fileSize = fileSize;
}
private void readObject(java.io.ObjectInputStream stream)
throws IOException, ClassNotFoundException
{
stream.defaultReadObject();
if (_keyHash != null) {
_keyHash = _keyHash.entrySet().stream().collect(toMap(e -> e.getKey().intern(), e -> e.getValue()));
}
if (_storageClass != null) {
_storageClass = _storageClass.intern();
}
if (_cacheClass != null) {
_cacheClass = _cacheClass.intern();
}
if (_hsm != null) {
_hsm = _hsm.intern();
}
}
}