/* * Copyright (c) 2014 EMC Corporation * All Rights Reserved */ package com.emc.storageos.db.client; import java.net.URI; import java.net.URISyntaxException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.List; import java.util.UUID; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.apache.commons.lang.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.emc.storageos.db.client.model.DataObject; import com.emc.storageos.db.client.model.VirtualDataCenter; import com.emc.storageos.db.client.util.KeyspaceUtil; import com.emc.storageos.db.common.VdcUtil; public class URIUtil { private static final Logger log = LoggerFactory.getLogger(URIUtil.class); private static final int UUID_PARTS_COUNT = 3; private static final int VDC_PARTS_COUNT = 4; private static final String[] MODEL_PACKAGES = new String[] { "com.emc.storageos.db.client.model", "com.emc.storageos.db.client.model.UnManagedDiscoveredObjects", "com.emc.storageos.db.client.model.uimodels" }; /** Pattern for finding the 'type' from an ID. */ private static final Pattern TYPE_PATTERN = Pattern.compile("urn\\:storageos\\:([^\\:]+)"); /** Null URI to use to unassign certain values. */ public static final URI NULL_URI = uri("null"); /** * creates a URI for an object of type clazz * * @param clazz * @return */ public static URI createId(Class<? extends DataObject> clazz) { return newId(clazz, getLocation(clazz)); } public static URI createId(Class<? extends DataObject> clazz, String uuid) { return newId(clazz, uuid, getLocation(clazz)); } /** * Creates an ID for a particular class with a well known identifier. Used for creating identifiers for * internal objects that don't change throughout the lifetime of the system. */ public static URI createInternalID(Class<? extends DataObject> clazz, String identifier) { return newId(clazz, identifier, ""); } /** * creates a URI for an VirtualDataCenter object. no vdc short id required * * @return */ public static URI createVirtualDataCenterId(String vdcId) { return newId(VirtualDataCenter.class, vdcId); } private static URI newId(Class<? extends DataObject> clazz, String vdcId) { return newId(clazz, UUID.randomUUID().toString(), vdcId); } private static URI newId(Class<? extends DataObject> clazz, String uuid, String vdcId) { return URI.create(String.format("urn:storageos:%1$s:%2$s:%3$s", clazz.getSimpleName(), uuid, vdcId)); } public static Class getModelClass(URI id) { String typeName = getTypeName(id); for (String modelPackage : MODEL_PACKAGES) { try { return Thread.currentThread().getContextClassLoader().loadClass(modelPackage + "." + typeName); } catch (ClassNotFoundException ignore) { log.debug("load class failed: ", ignore); } } throw new RuntimeException("Unable to find Model Class for " + id); } @SuppressWarnings("rawtypes") public static boolean isType(URI uri, Class clazz) { String simpleName = clazz.getSimpleName(); return uri.toString().startsWith("urn:storageos:" + simpleName); } /** * @return true if the string represents a valid URI and the URI is a valid ViPR URL else false */ public static boolean isValid(String uri) { try { return isValid(new URI(uri)); } catch (URISyntaxException e) { log.error("URISyntaxException : uri passed is {} ", uri, e); return false; } } /** * @return true if the uri represents a valid ViPR URI regardless of class */ public static boolean isValid(final URI uri) { if (uri == null || uri.getScheme() == null || uri.getSchemeSpecificPart() == null || !uri.getScheme().equals("urn") || !uri.getSchemeSpecificPart().startsWith("storageos")) { return false; } /* * (?i) - ignores case of letters in following parentheses * urn:storageos: - matches exact stting, this is consistent for all ViPR uris * [A-Z]+: - This will match the class with any number of letters followed by a colon * [A-F0-9]{8} - used for matchin UUID, This segment is 8 hex characters. * The full UUID pattern is all Hex characters seperated by '-' in specific quantities * :([A-Z0-9]+)? - any amount of letters or numbers preceded by a colon * * Only legal characters (letters(any case), numbers, '-', ':') */ return uri.toString().matches("(?i)(urn:storageos:" + "[A-Z]+:" + "[A-F0-9]{8}-[A-F0-9]{4}-[A-F0-9]{4}-[A-F0-9]{4}-[A-F0-9]{12}" + ":([A-Z0-9]+)?)"); } public static List<URI> toURIList(Collection<String> stringList) { List<URI> uriList = null; if (stringList != null && !stringList.isEmpty()) { uriList = new ArrayList<>(); for (String uriStr : stringList) { uriList.add(URI.create(uriStr)); } } return uriList; } public static String getTypeName(URI id) { return getTypeName(id.toString()); } public static String getTypeName(String id) { Matcher m = TYPE_PATTERN.matcher(id); if (m.find()) { return m.group(1); } return null; } public static String[] splitURI(URI id) { if (!isValid(id)) { return null; } return TYPE_PATTERN.split(id.toString())[1].split(":"); } /** * Get the UUID embedded in the URI string, or null if none * * @param id a DataObject URI string * @return the uuid */ public static String parseUUIDFromURI(URI id) { return (id != null) ? parsePartFromURI(id.toString(), UUID_PARTS_COUNT) : null; } /** * Get the VDC Id embedded in the URI string, or null if none * * @param id a DataObject URI string * @return the vdc id */ public static String parseVdcIdFromURI(URI id) { return (id != null) ? parseVdcIdFromURI(id.toString()) : null; } /** * Get the VDC Id embedded in the URI, or null if none * * @param id a DataObject URI * @return the vdc id */ public static String parseVdcIdFromURI(String id) { return parsePartFromURI(id, VDC_PARTS_COUNT); } /** * Get a part of Id embedded in the URI under given index, or null if none * * @param id a DataObject URI * @param index an index of the part * @return the vdc id */ private static String parsePartFromURI(String id, int index) { String vdcId = null; if (id != null) { String[] segments = StringUtils.split(id, ':'); if ((segments.length > index) && StringUtils.isNotBlank(segments[index])) { vdcId = segments[index]; } } return vdcId; } public static <T extends DataObject> String getLocation(Class<T> clazz) { return KeyspaceUtil.isLocal(clazz) ? VdcUtil.getLocalShortVdcId() : KeyspaceUtil.GLOBAL; } /** * Gets the value of the URI as a string, returns null if the URI is null. * * @param value * the URI. * @return the string value of the URI. */ public static String asString(URI value) { return value != null ? value.toString() : null; } /** * Converts a collection of URIs to a list of strings, null safe. * * @param values * the URI values. * @return the String(s) */ public static List<String> asStrings(Collection<URI> values) { List<String> results = new ArrayList<>(); if (values != null) { for (URI value : values) { if (value != null) { results.add(value.toString()); } } } return results; } /** * Converts a string to a URI, null safe. * * @param value * the string value. * @return the URI. */ public static URI uri(String value) { return (value != null && value.length() > 0) ? URI.create(value) : null; } /** * Converts a collection of strings to a list of URIs, null safe. * * @param values * the string values. * @return the URIs. */ public static List<URI> uris(Collection<String> values) { List<URI> results = new ArrayList<URI>(); if (values != null) { for (String value : values) { URI uri = uri(value); if (uri != null) { results.add(uri); } } } return results; } /** * Converts an array of strings to a list of URIs, null safe. * * @param values * the string values. * @return the URIs. */ public static List<URI> uris(String... values) { if (values != null) { return uris(Arrays.asList(values)); } else { return new ArrayList<URI>(); } } /** * Determines if the IDs are equal (and non-null). * * @param first * the first ID. * @param second * the second ID. * @return true if and only if the IDs are non-null and equal. */ public static boolean identical(URI first, URI second) { if ((first != null) && (second != null)) { return first.equals(second); } return false; } /** * Checks if the ID is null (or matches the NULL_URI). * * @param id * the ID. * @return true if the ID is null. */ public static boolean isNull(URI id) { return (id == null) || NULL_URI.equals(id); } /** * Returns uris for list of data objects. * * @param dataObjects * @return list of uris */ public static List<URI> toUris(List<? extends DataObject> dataObjects) { List<URI> uris = new ArrayList<>(); if (dataObjects != null) { for (DataObject dataObject : dataObjects) { uris.add(dataObject.getId()); } } return uris; } /** * Filter a list of URIs for a specific type * * @param uris * list of URIs of any type * @param clazz * class to filter in * @return a list of URIs of that type, or an empty list */ public static List<URI> getURIsofType(Collection<URI> uris, Class clazz) { List<URI> returnIds = new ArrayList<URI>(); if (uris == null) { return returnIds; } for (URI uri : uris) { if (URIUtil.isType(uri, clazz)) { returnIds.add(uri); } } return returnIds; } }