#region Disclaimer / License
// Copyright (C) 2014, Jackie Ng
// http://trac.osgeo.org/mapguide/wiki/maestro, jumpinjackie@gmail.com
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
//
#endregion Disclaimer / License
using System;
namespace OSGeo.MapGuide.ObjectModels
{
///
/// This class contains all the required code for maintaining resource identifiers.
/// It has implicit conversions to and from a string, which makes it much easier to use.
/// It has both static methods that operate on strings, as well as a class that can be manipulated.
///
public class ResourceIdentifier
{
///
/// The actual ResourceID
///
private string m_id;
///
/// Constructs a new ResourceIdentifier with the given full path
///
/// The path of the resource to refence
public ResourceIdentifier(string resourceId)
{
m_id = resourceId;
}
///
/// Constructs a new ResourceIdentifier, based on an existing one.
///
/// The resource identifier to copy
public ResourceIdentifier(ResourceIdentifier id)
{
m_id = id.m_id;
}
///
/// Constructs a new library based resource identifier
///
/// The name of the resource, may include path information with the \"/\" character
/// The type of resource the identifier names
public ResourceIdentifier(string name, ResourceTypes type)
{
if (string.IsNullOrEmpty(name))
throw new ArgumentNullException(nameof(name)); //NOXLATE
if (name.IndexOf(".") > 0 || name.IndexOf("//") > 0 || name.IndexOf(":") > 0) //NOXLATE
throw new ArgumentException(Strings.ErrorResourceIdentifierInvalidChars, nameof(name)); //NOXLATE
if (!Enum.IsDefined(typeof(ResourceTypes), type))
throw new ArgumentException(Strings.ErrorUnknownResourceType, nameof(type)); //NOXLATE
m_id = ROOT_IDENTIFIER + name + ResourceName(type, true);
}
private static string ResourceName(ResourceTypes type)
{
return ResourceName(type, false);
}
private static string ResourceName(ResourceTypes type, bool prefixWithDot)
{
if (type == ResourceTypes.Folder || !prefixWithDot)
return type.ToString();
else
return "." + type.ToString(); //NOXLATE
}
private const string ROOT_IDENTIFIER = "Library://"; //NOXLATE
///
/// Constructs a new session based resource identifier
///
/// The name of the resource, may include path information with the \"/\" character
/// The type of resource the identifier names
/// The session id to use
public ResourceIdentifier(string name, ResourceTypes type, string sessionId)
: this(name, type)
{
this.ConvertToSession(sessionId);
}
///
/// Gets a value indicating if the resource is blank
///
public bool IsEmpty { get { return string.IsNullOrEmpty(m_id); } }
///
/// Gets or sets the name of the resource
///
public string Name
{
get { return GetName(m_id); }
set { m_id = SetName(m_id, value); }
}
///
/// Gets or sets the name and extension of the resource
///
public string Fullname
{
get { return GetFullname(m_id); }
set { m_id = SetName(m_id, value); }
}
///
/// Gets or sets the extension of the resourceId
///
public string Extension
{
get { return GetExtension(m_id); }
set { m_id = SetExtension(m_id, value); }
}
///
/// Gets the full path of the resource, that is the path without repository information
///
public string Fullpath
{
get { return GetFullpath(m_id); }
set { m_id = SetPath(m_id, value); }
}
///
/// Gets the path of the resource, that is the path without repository information and no extension
///
public string Path
{
get { return GetPath(m_id); }
set { m_id = SetPath(m_id, value); }
}
///
/// Gets or sets the path to the resource, including the repository
///
public string RepositoryPath
{
get { return GetRepositoryPath(m_id); }
set { m_id = SetRepositoryPath(m_id, value); }
}
///
/// Gets a value indicating if the resource is in the library repository
///
public bool IsInLibrary
{
get { return GetRepository(m_id) == ROOT_IDENTIFIER; }
}
///
/// Gets a value indicating if the resource is in the session repository
///
public bool IsInSessionRepository
{
get { return !this.IsInLibrary; }
}
///
/// Converts this instance to be in the library repository
///
public void ConvertToLibrary()
{
m_id = ResourceIdentifier.ConvertToLibrary(m_id);
}
///
/// Converts this instance to be in the session repository
///
/// The sessionid
public void ConvertToSession(string sessionId)
{
m_id = ResourceIdentifier.ConvertToSession(m_id, sessionId);
}
///
/// Helper operator that makes using the resource identifiers easier
///
/// The id to convert to a string
/// The converted string
public static implicit operator string(ResourceIdentifier id)
{
return id == null ? null : id.m_id;
}
///
/// Helper operator that makes using the resource identifiers easier
///
/// The id to convert into a resource indetifier class
/// The resource identifier
public static implicit operator ResourceIdentifier(string id)
{
return new ResourceIdentifier(id);
}
///
/// Returns the full resource id as a string
///
/// The full resource id as a string
public override string ToString()
{
return m_id;
}
///
/// Gets the resource type
///
public string ResourceType
{
get { return GetResourceTypeAsString(m_id); }
}
///
/// Gets the length of the resource identifier as a string
///
public int Length { get { return m_id == null ? 0 : m_id.Length; } }
///
/// Gets or sets the full resource identifier
///
public string ResourceId
{
get { return m_id; }
set { m_id = value; }
}
///
/// Gets a value indicating if the resource identifier points to a folder
///
public bool IsFolder
{
get { return ResourceIdentifier.IsFolderResource(m_id); }
}
///
/// Gets a value indicating if the resource identifier is valid
///
public bool IsValid
{
get { return ResourceIdentifier.Validate(m_id); }
}
///
/// Normalizes the identifier, that is prepends a slash if the identifier points to a folder
///
public void Normalize()
{
m_id = ResourceIdentifier.Normalize(m_id);
}
///
/// Gets the containing folder path for the resource, including the repository
///
public string ParentFolder
{
get { return ResourceIdentifier.GetParentFolder(m_id, true /* Because it was initialized with a ResourceTypes enum */); }
}
#region Static handlers
///
/// Gets the name of a resource, given its identifier
///
/// The identifier to look for
/// The name of the resource
public static string GetName(string identifier)
{
if (string.IsNullOrEmpty(identifier))
throw new ArgumentNullException(nameof(identifier)); //NOXLATE
string temp = GetPath(identifier);
if (string.IsNullOrEmpty(temp))
throw new ArgumentException(Strings.ErrorInvalidResourceIdentifier, nameof(identifier)); //NOXLATE
return temp.Substring(temp.LastIndexOf("/") + 1); //NOXLATE
}
///
/// Sets the name of the resource, with or without the extension
///
/// The identifier to give a new name
/// The new name to assign
/// The renamed identifier
public static string SetName(string identifier, string newname)
{
string temp = GetPath(identifier);
if (identifier.EndsWith("/")) //NOXLATE
{
if (!newname.EndsWith("/")) //NOXLATE
newname += "/"; //NOXLATE
}
else
newname += "." + GetExtension(identifier); //NOXLATE
if (newname.IndexOf("/") > 0) //NOXLATE
throw new ArgumentException(Strings.ErrorResourceIdentifierNameInvalidChars, nameof(newname));
temp = temp.Substring(0, temp.Length - GetName(identifier).Length) + newname;
return GetRepository(identifier) + temp;
}
///
/// Sets the path of the identifier, with or without the extension
///
/// The identifier to update
/// The new path to user, with or without the extension
/// The new identifier
public static string SetPath(string identifier, string newpath)
{
string temp = GetPath(identifier);
if (!identifier.EndsWith("/")) //NOXLATE
newpath += "." + GetExtension(identifier); //NOXLATE
return GetRepository(identifier) + newpath + (identifier.EndsWith("/") ? "/" : ""); //NOXLATE
}
///
/// Changes the extension of the given resource
///
/// The identifier to change the extension for
/// The new extension to use
/// The renmaed identifier
public static string SetExtension(string identifier, string newextension)
{
if (identifier.EndsWith("/")) //NOXLATE
throw new Exception(Strings.ErrorResourceIdCannotChangeExtensionForFolder);
if (!newextension.StartsWith(".")) //NOXLATE
newextension = "." + newextension; //NOXLATE
if (newextension.LastIndexOf(".") > 0) //NOXLATE
throw new ArgumentException(Strings.ErrorResourceIdInvalidExtension, nameof(newextension)); //NOXLATE
return identifier.Substring(0, identifier.Length - GetExtension(identifier).Length - 1) + newextension;
}
///
/// Gets the repository part of a resource identifier, eg.: "Library://" or "Session:xxxx//"
///
///
///
public static string GetRepository(string identifier)
{
if (string.IsNullOrEmpty(identifier))
throw new ArgumentNullException(nameof(identifier)); //NOXLATE
int ix = identifier.IndexOf("//"); //NOXLATE
if (ix <= 0)
throw new ArgumentException(Strings.ErrorInvalidResourceIdentifier, nameof(identifier)); //NOXLATE
string repo = identifier.Substring(0, ix);
if (repo != "Library:" && !repo.StartsWith("Session:")) //NOXLATE
throw new ArgumentException(Strings.ErrorInvalidResourceIdentifierType, nameof(identifier)); //NOXLATE
return repo + "//"; //NOXLATE
}
///
/// Returns the full path of the resource, that is the resourceId without the repository information
///
/// The identifier to get the path from
/// The path of the identifier
public static string GetFullpath(string identifier)
{
if (string.IsNullOrEmpty(identifier))
throw new ArgumentNullException(nameof(identifier)); //NOXLATE
return identifier.Substring(GetRepository(identifier).Length);
}
///
/// Returns the path of the resource, that is the resourceId without the repository information and extension
///
/// The identifier to get the path from
/// The path of the identifier
public static string GetPath(string identifier)
{
if (string.IsNullOrEmpty(identifier))
throw new ArgumentNullException(nameof(identifier)); //NOXLATE
return identifier.Substring(GetRepository(identifier).Length, identifier.Length - GetExtension(identifier).Length - GetRepository(identifier).Length - 1);
}
///
/// Gets the type of this resource.
///
/// Use this method over if the Maestro API may not be aware of the new resource type
///
///
public static string GetResourceTypeAsString(string identifier)
{
return GetExtension(identifier);
}
///
/// Gets the known type of the resource.
///
/// The identifier.
///
private static ResourceTypes GetResourceType(string identifier)
{
var ext = GetExtension(identifier);
if (ext == "Map") //NOXLATE
return ResourceTypes.Map;
else
return (ResourceTypes)Enum.Parse(typeof(ResourceTypes), ext);
}
///
/// Returns the extension of a resource identifier
///
/// The identifier to get the extension from
/// The extension of the identifier
private static string GetExtension(string identifier)
{
if (string.IsNullOrEmpty(identifier))
throw new ArgumentNullException(nameof(identifier)); //NOXLATE
if (identifier.EndsWith("/")) //NOXLATE
return string.Empty;
int ix = identifier.LastIndexOf("."); //NOXLATE
if (ix <= 0)
throw new ArgumentException(Strings.ErrorInvalidResourceIdentifier, nameof(identifier)); //NOXLATE
return identifier.Substring(ix + 1);
}
///
/// Converts a resource id to be placed in the library
///
/// The identifier to convert
/// The converted identifier
public static string ConvertToLibrary(string identifier)
{
return ROOT_IDENTIFIER + identifier.Substring(GetRepository(identifier).Length);
}
///
/// Converts a resource id to be placed in the library
///
/// The identifier to convert
/// The session id of the repository it should be placed in
/// The converted identifier
public static string ConvertToSession(string identifier, string sessionId)
{
return "Session:" + sessionId + "//" + identifier.Substring(GetRepository(identifier).Length); //NOXLATE
}
///
/// Gets the name and extension of the identifier
///
/// The identifier to extract the information from
/// The full name of the identifier
public static string GetFullname(string identifier)
{
if (identifier.EndsWith("/")) //NOXLATE
return GetName(identifier);
else
return GetName(identifier) + "." + GetExtension(identifier); //NOXLATE
}
///
/// Determines if a resource identifier is valid
///
/// The identifier to validate
/// If true, will check if the type of the resource id is one that is supported by Maestro
/// A value indicating if the identifier is valid
public static bool Validate(string identifier, bool strict = true)
{
try
{
GetRepository(identifier);
if (identifier.IndexOf(".") < 0 && !identifier.EndsWith("/")) //NOXLATE
return false;
if (identifier == ROOT_IDENTIFIER)
return true;
if (IsFolderResource(identifier))
return true;
if (strict)
{
var rt = GetResourceType(identifier);
}
}
catch
{
return false;
}
return true;
}
///
/// Returns a value indicating if the resource points to a folder
///
/// The identifier to evaluate
/// A value indicating if the resource points to a folder
public static bool IsFolderResource(string identifier)
{
return identifier.EndsWith("/"); //NOXLATE
}
///
/// Normalizes a identifier, that is prepends a slash if it is a folder resource
///
/// The identifier to normalize
/// The normalized identifier
public static string Normalize(string identifier)
{
if (identifier.LastIndexOf(".") <= identifier.LastIndexOf("/") && !identifier.EndsWith("/")) //NOXLATE
return identifier + "/"; //NOXLATE
else
return identifier;
}
///
/// Determines if a resource identifier is valid and of the desired type
///
/// The identifier to validate
/// The type the resource identifer must be
/// A value indicating if the identifier is valid
public static bool Validate(string identifier, ResourceTypes type)
{
if (!Validate(identifier))
return false;
if (type == ResourceTypes.Folder)
return IsFolderResource(identifier);
else
return ResourceName(type) == GetExtension(identifier);
}
///
/// Returns the path that contains the resource, including the repository
///
/// The resource identifier to use
/// The folder for the identifier
public static string GetRepositoryPath(string identifier)
{
if (!Validate(identifier))
throw new Exception("Invalid resource id: " + identifier); //NOXLATE
identifier = Normalize(identifier);
return identifier.Substring(0, identifier.LastIndexOf("/", identifier.Length)) + "/"; //NOXLATE
}
///
/// Sets the path including the repository to the given value
///
/// The identifier to change the folder for
/// The new folder
/// An identifier in the new folder
public static string SetRepositoryPath(string identifier, string folder)
{
if (!folder.StartsWith("Library:") && !folder.StartsWith("Session:")) //NOXLATE
{
string res = identifier.EndsWith("/") ? string.Empty : GetFullname(identifier); //NOXLATE
string repo = GetRepository(identifier);
if (!folder.EndsWith("/") && !string.IsNullOrEmpty(folder)) //NOXLATE
folder += "/"; //NOXLATE
return repo + folder + res;
}
else if (GetExtension(identifier) == string.Empty)
{
if (!folder.EndsWith("/")) //NOXLATE
folder += "/"; //NOXLATE
return folder;
}
else
{
if (!folder.EndsWith("/")) //NOXLATE
folder += "/"; //NOXLATE
return folder + GetFullname(identifier);
}
}
///
/// Gets the parent folder.
///
/// The identifier.
///
public static string GetParentFolder(string identifier)
{
return GetParentFolder(identifier, false);
}
///
/// Gets the parent folder.
///
/// The identifier.
/// If true, the type of the identifier must be one that is supported by Maestro
///
private static string GetParentFolder(string identifier, bool strict)
{
if (!Validate(identifier, strict))
throw new Exception(Strings.ErrorInvalidResourceIdentifier);
identifier = Normalize(identifier);
if (identifier == GetRepository(identifier))
return identifier;
if (identifier.EndsWith("/")) //NOXLATE
identifier = identifier.Remove(identifier.Length - 1);
identifier = identifier.Remove(identifier.LastIndexOf("/") + 1); //NOXLATE
return identifier;
}
#endregion Static handlers
///
/// Determines whether this resource id is session-based
///
/// The resource ID.
///
/// true if this resource id is session-based; otherwise, false.
///
public static bool IsSessionBased(string resourceID)
{
return resourceID.StartsWith("Session:"); //NOXLATE
}
}
}