/*
* Copyright (c) 2008-2011 EMC Corporation
* All Rights Reserved
*/
package com.emc.storageos.db.client.model;
import java.net.URI;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import com.emc.storageos.db.client.DbClient;
import com.emc.storageos.db.client.URIUtil;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
/**
* @author burckb
*
*/
public abstract class BlockObject extends DataObject {
// storage controller where this volume is located
private URI _storageController;
// storage controller where this volume is located
private URI _protectionController;
// device native ID for this volume
private String _nativeId;
// native device ID to be indexed - this field is not exposed to client
private String _nativeGuid;
// these will include things like
// thinProvisioned->Y/N, ALU->1,2,3, and raidLevel->RAID-1,RAID-6+2
// may include volumeGroup->name for mapping multiple volumes
private StringMap _extensions;
// Tag for grouping volumes that need to have consistent snapshots
private URI _consistencyGroupId;
// Tag for grouping volumes that need to have consistent snapshots
@Deprecated
private StringSet consistencyGroups;
// storage protocols supported by this volume
private StringSet _protocols;
// virtual array where this volume exists
private URI _virtualArray;
private String _wwn;
private String _deviceLabel;
// This is an alternate name for the block snapshot. It's useful in the case of VNX
// SnapView (RAID GROUP based) snapshots, which usually have a Name like UID+<WWN>.
private String _alternateName;
// This value is an indicator that a the snapshot information is out-of-sync on the
// provider side and an EMCRefresh will be required.
private Boolean _emcRefreshRequired;
// Name reference of replication group that the object belong to.
private String _replicationGroupInstance;
// The storage system type this BlockObject belongs to
private String _systemType;
@AlternateId("AltIdIndex")
@Name("wwn")
public String getWWN() {
return _wwn;
}
public void setWWN(String wwn) {
_wwn = BlockObject.normalizeWWN(wwn);
setChanged("wwn");
}
/**
*
*/
public BlockObject() {
super();
}
@RelationIndex(cf = "RelationIndex", type = StorageSystem.class)
@Name("storageDevice")
public URI getStorageController() {
return _storageController;
}
public void setStorageController(URI storageController) {
_storageController = storageController;
setChanged("storageDevice");
}
@RelationIndex(cf = "RelationIndex", type = ProtectionSystem.class)
@Name("protectionDevice")
public URI getProtectionController() {
return _protectionController;
}
public void setProtectionController(URI protectionController) {
_protectionController = protectionController;
setChanged("protectionDevice");
}
@AlternateId("AltIdIndex")
@Name("nativeId")
public String getNativeId() {
return _nativeId;
}
public void setNativeId(String nativeId) {
_nativeId = nativeId;
setChanged("nativeId");
}
@AlternateId("AltIdIndex")
@Name("nativeGuid")
public String getNativeGuid() {
return _nativeGuid;
}
public void setNativeGuid(String nativeGuid) {
_nativeGuid = nativeGuid;
setChanged("nativeGuid");
}
@Name("extensions")
public StringMap getExtensions() {
return _extensions;
}
/**
* Set extensions map - overwrites existing one
*
* @param map StringMap of extensions to set
*/
public void setExtensions(StringMap map) {
_extensions = map;
setChanged("extensions");
}
@RelationIndex(cf = "RelationIndex", type = BlockConsistencyGroup.class)
@Name("consistencyGroup")
public URI getConsistencyGroup() {
return _consistencyGroupId;
}
public void setConsistencyGroup(URI consistencyGroup) {
_consistencyGroupId = consistencyGroup;
setChanged("consistencyGroup");
}
public boolean hasConsistencyGroup() {
return _consistencyGroupId != null;
}
@Name("consistencyGroups")
@AlternateId("CgAltIdIndex")
@Deprecated
public StringSet getConsistencyGroups() {
return consistencyGroups;
}
@Deprecated
public void setConsistencyGroups(StringSet consistencyGroups) {
this.consistencyGroups = consistencyGroups;
setChanged("consistencyGroups");
}
@Name("protocols")
public StringSet getProtocol() {
return _protocols;
}
public void setProtocol(StringSet protocols) {
_protocols = protocols;
setChanged("protocols");
}
@Name("varray")
@RelationIndex(cf = "RelationIndex", type = VirtualArray.class)
public URI getVirtualArray() {
return _virtualArray;
}
public void setVirtualArray(URI virtualArray) {
_virtualArray = virtualArray;
setChanged("varray");
}
@Name("deviceLabel")
public String getDeviceLabel() {
return _deviceLabel;
}
public void setDeviceLabel(String deviceLabel) {
_deviceLabel = deviceLabel;
setChanged("deviceLabel");
}
public void setAlternateName(String alternateName) {
_alternateName = alternateName;
setChanged("alternateName");
}
@Name("alternateName")
public String getAlternateName() {
return _alternateName;
}
@Name("refreshRequired")
public Boolean getRefreshRequired() {
return (_emcRefreshRequired != null) ? _emcRefreshRequired : Boolean.FALSE;
}
public void setRefreshRequired(Boolean required) {
_emcRefreshRequired = required;
setChanged("refreshRequired");
}
@AlternateId("AltIdIndex")
@Name("replicationGroupInstance")
public String getReplicationGroupInstance() {
return _replicationGroupInstance;
}
public void setReplicationGroupInstance(String replicaGroupInstance) {
_replicationGroupInstance = replicaGroupInstance;
setChanged("replicationGroupInstance");
}
@Name("systemType")
public String getSystemType() {
return _systemType;
}
public void setSystemType(String systemType) {
_systemType = systemType;
setChanged("systemType");
}
/**
* Utility function that would allow you to retrieve any derived BlockObject
* based on its URI (e.g, Volume or BlockSnapshot).
*
* @param dbClient [in] - DbClient object to read from database
* @param blockURI [in] - URI of BlockObject
* @return BlockObject instance that has id 'blockURI'
*/
public static BlockObject fetch(DbClient dbClient, URI blockURI) {
BlockObject block = null;
if (URIUtil.isType(blockURI, Volume.class)) {
block = dbClient.queryObject(Volume.class, blockURI);
} else if (URIUtil.isType(blockURI, BlockSnapshot.class)) {
block = dbClient.queryObject(BlockSnapshot.class, blockURI);
} else if (URIUtil.isType(blockURI, BlockMirror.class)) {
block = dbClient.queryObject(BlockMirror.class, blockURI);
}
return block;
}
/**
* Utility function to retrieve derived BlockObjects based on their URIs (e.g, Volume or BlockSnapshot).
* The block objects need to be of same type
*
* @param dbClient [in] - DbClient object to read from database
* @param blockURIs [in] - URIs of BlockObjects
* @return BlockObject instances
*/
public static List <? extends BlockObject> fetch(DbClient dbClient, List<URI> blockURIs) {
List<? extends BlockObject> blockObjects = null;
if (URIUtil.isType(blockURIs.get(0), Volume.class)) {
blockObjects = dbClient.queryObject(Volume.class, blockURIs);
} else if (URIUtil.isType(blockURIs.get(0), BlockSnapshot.class)) {
blockObjects = dbClient.queryObject(BlockSnapshot.class, blockURIs);
} else if (URIUtil.isType(blockURIs.get(0), BlockMirror.class)) {
blockObjects = dbClient.queryObject(BlockMirror.class, blockURIs);
}
return blockObjects;
}
/**
* Fetch a list of BlockObjects from the database based on their URI.
* The list may contain a mixed collection of BlockObject derived URIs and
* the resulting list will also contain a mixed collection of BlockObject instances.
*
* @param dbClient Database client
* @param blockURIs List of URIs for BlockObject derived instances
* @return List of BlockObject instances
*/
public static List<? extends BlockObject> fetchAll(DbClient dbClient, Collection<URI> blockURIs) {
List<? extends BlockObject> blockObjects = Lists.newArrayList();
Map<Class, List<URI>> boTypeToURIs = Maps.newHashMap();
for (URI blockURI : blockURIs) {
Class modelClass = URIUtil.getModelClass(blockURI);
if (!boTypeToURIs.containsKey(modelClass)) {
boTypeToURIs.put(modelClass, Lists.<URI> newArrayList());
}
boTypeToURIs.get(modelClass).add(blockURI);
}
for (Map.Entry<Class, List<URI>> entry : boTypeToURIs.entrySet()) {
List objects = dbClient.queryObject(entry.getKey(), entry.getValue());
blockObjects.addAll(objects);
}
return blockObjects;
}
/**
* Utility function that normalize the volume wwn, so that it only contains upper case hex numbers
*
* @param wwn the wwn to be normalized
* @return normalized wwn
*/
static public String normalizeWWN(String wwn) {
String result = wwn;
if (wwn != null && !wwn.isEmpty()) {
result = wwn.replaceAll("[^A-Fa-f0-9]", "");
result = result.toUpperCase();
}
return result;
}
/**
* Utility function that allows you to check for RP regardless of the
* object type.
*
* @param dbClient [in] - DbClient object to read from database
* @param blockURI [in] - URI of BlockObject
* @return true if the object is RP
*/
public static boolean checkForRP(DbClient dbClient, URI blockURI) {
if (URIUtil.isType(blockURI, BlockSnapshot.class)) {
BlockSnapshot snapshot = dbClient.queryObject(BlockSnapshot.class, blockURI);
return snapshot.getProtectionController() != null;
} else if (URIUtil.isType(blockURI, Volume.class)) {
Volume volume = dbClient.queryObject(Volume.class, blockURI);
return volume.checkForRp();
}
return false;
}
/**
* Check if the volume is a VPLEX volume.
*
* @param dbClient the db client
* @return true or false
*/
public boolean isVPlexVolume(DbClient dbClient) {
StorageSystem storage = dbClient.queryObject(StorageSystem.class, getStorageController());
return DiscoveredDataObject.Type.vplex.name().equals(storage.getSystemType());
}
@Override
public String toString() {
return _nativeId;
}
/**
* Deprecated - Needed only for 2.1 migration callback.
*
* Convenience method to get a BlockConsistencyGroup by type.
*
* @param dbClient
* @param type
* @return
*/
@Deprecated
public BlockConsistencyGroup fetchConsistencyGroupByType(DbClient dbClient, BlockConsistencyGroup.Types type) {
BlockConsistencyGroup cg = null;
if (getConsistencyGroups() != null && !getConsistencyGroups().isEmpty()) {
// If we only have a single CG, ignore the type and try and return the CG.
// It has to be the one we're looking for. The only use for type right now is for
// RP+VPLEX which would have multiple CGs.
if (getConsistencyGroups().size() == 1) {
cg = dbClient.queryObject(BlockConsistencyGroup.class, URI.create(getConsistencyGroups().iterator().next()));
}
else {
// Multiple CGs, try to find the correct one with the type passed in.
for (String cgUriStr : getConsistencyGroups()) {
cg = dbClient.queryObject(BlockConsistencyGroup.class, URI.create(cgUriStr));
if (cg != null && cg.getType() != null) {
if (cg.getType().equalsIgnoreCase(type.toString())) {
return cg;
}
}
}
}
}
return cg;
}
/**
* Deprecated - Needed only for 2.1 migration callback.
*
* Convenience method to get a consistency group URI by type.
*
* @param dbClient
* @param type
* @return
*/
@Deprecated
public URI fetchConsistencyGroupUriByType(DbClient dbClient, BlockConsistencyGroup.Types type) {
BlockConsistencyGroup cg = fetchConsistencyGroupByType(dbClient, type);
if (cg != null) {
return cg.getId();
}
return null;
}
/**
* Deprecated - Needed only for 2.1 migration callback.
*
* Convenience method to add a consistency group.
*
* @param cgUri
*/
@Deprecated
public void addConsistencyGroup(String cgUri) {
if (getConsistencyGroups() == null) {
setConsistencyGroups(new StringSet());
}
getConsistencyGroups().add(cgUri);
}
}