#region Disclaimer / License
// Copyright (C) 2006, Kenneth Skovhede
// http://www.hexad.dk, opensource@hexad.dk
//
// 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
using System;
using System.Collections;
namespace OSGeo.MapGuide.MaestroAPI
{
///
/// Summary description for ServerConnectionBase.
///
public abstract class ServerConnectionBase
{
///
/// A resource lookup table, for converting resourceID's into types.
///
protected Hashtable m_resourceTypeLookup;
///
/// A list of cached serializers
///
protected Hashtable m_serializers;
///
/// The current XML validator
///
protected XMLValidator m_validator;
///
/// The path of Xsd schemas
///
protected string m_schemasPath;
///
/// A lookup table for Xsd Schemas
///
protected Hashtable m_cachedSchemas;
///
/// A flag indicating if Xsd validation is perfomed
///
protected bool m_disableValidation = false;
///
/// A flag that indicates if a session will be automatically restarted
///
protected bool m_autoRestartSession = false;
///
/// A dummy resource, used for the runtime map
///
internal const string RUNTIMEMAP_XML = "";
///
/// A dummy resource, used for the runtime map
///
internal const string RUNTIMEMAP_SELECTION_XML = "";
///
/// The username used to open this connection, if any
///
protected string m_username;
///
/// The password used to open this connection, if any
///
protected string m_password;
protected ServerConnectionBase()
{
m_serializers = new Hashtable();
m_validator = new XMLValidator();
m_cachedSchemas = new Hashtable();
m_resourceTypeLookup = new Hashtable();
m_resourceTypeLookup.Add("LayerDefinition", typeof(LayerDefinition));
m_resourceTypeLookup.Add("MapDefinition", typeof(MapDefinition));
m_resourceTypeLookup.Add("WebLayout", typeof(WebLayout));
m_resourceTypeLookup.Add("FeatureSource", typeof(FeatureSource));
m_resourceTypeLookup.Add("ApplicationDefinition", typeof(ApplicationDefinition.ApplicationDefinitionType));
m_schemasPath = System.IO.Path.Combine(System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location), "Schemas");
m_username = null;
m_password = null;
}
///
/// Gets a full list of resources in the permanent server repository (Library).
/// This method returns the full catalog and should be used sparringly.
///
/// A list of contained resources
virtual public ResourceList GetRepositoryResources()
{
return GetRepositoryResources("Library://", null, -1);
}
///
/// Gets a list of resources in the permanent server repository (Library).
/// This method limits folder recursion to the specified depth.
///
/// The max depth to recurse. Use -1 for no limit.
/// A list of contained resources
virtual public ResourceList GetRepositoryResources(int depth)
{
return GetRepositoryResources("Library://", null, depth);
}
///
/// Gets a list of resources in the permanent server repository (Library).
/// This method limits folder recursion to the specified depth.
///
/// The folder from which to return items. Use null for "Library://"
/// The max depth to recurse. Use -1 for no limit.
/// A list of contained resources
virtual public ResourceList GetRepositoryResources(string startingpoint, int depth)
{
return GetRepositoryResources(startingpoint, null, depth);
}
///
/// Gets a list of resources in the permanent server repository (Library).
/// This method limits folder recursion to the specified depth.
///
/// The folder from which to return items. Use null for "Library://"
/// A list of contained resources
virtual public ResourceList GetRepositoryResources(string startingpoint)
{
return GetRepositoryResources(startingpoint, null, -1);
}
///
/// Gets a list of resources in the permanent server repository (Library).
/// This method limits folder recursion to the specified depth.
///
/// The folder from which to return items. Use null for "Library://"
/// The type of resource to look for. Basically this is the resource extension, like ".MapDefinition". Use null for all resources.
/// A list of contained resources
virtual public ResourceList GetRepositoryResources(string startingpoint, string type)
{
return GetRepositoryResources(startingpoint, type, -1);
}
///
/// Gets a list of resources in the permanent server repository (Library).
/// This method limits folder recursion to the specified depth.
///
/// The folder from which to return items. Use null for "Library://"
/// The type of resource to look for. Basically this is the resource extension, like ".MapDefinition". Use null for all resources.
/// The max depth to recurse. Use -1 for no limit.
/// A list of contained resources
abstract public ResourceList GetRepositoryResources(string startingpoint, string type, int depth);
///
/// Gets the current SessionID.
///
abstract public string SessionID { get; }
///
/// Builds a resource Identifier, using path info
///
/// The initial absolute path, not including type or repository info, ea. Test/MyResource
/// The type of the resource
/// True if the item is found in the session
/// A string representing the resource identifier
virtual public string GetResourceIdentifier(string path, ResourceTypes type, bool fromSession)
{
if (fromSession)
return "Session:" + SessionID + "//" + path + EnumHelper.ResourceName(type, true);
else
return "Library://" + path + EnumHelper.ResourceName(type, true);
}
///
/// Validates a resource identifier. Only validates the string, not the existence of the resource
///
/// The full resource identifier
/// The type of resource that is identified
virtual public void ValidateResourceID(string resourceid, ResourceTypes type)
{
}
///
/// Deserializes an object from a stream.
///
/// The expected object type
/// The stream containing the object
/// The deserialized object
virtual public object DeserializeObject(Type type, System.IO.Stream data)
{
//Must copy stream, because we will be reading it twice :(
//Once for validation, and once for deserialization
System.IO.MemoryStream ms = new System.IO.MemoryStream();
Utility.CopyStream(data, ms);
ms.Position = 0;
#if DEBUG_LASTMESSAGE
//Save us a copy for later investigation
using (System.IO.FileStream fs = System.IO.File.Open("lastResponse.xml", System.IO.FileMode.Create, System.IO.FileAccess.ReadWrite, System.IO.FileShare.None))
Utility.CopyStream(ms, fs);
ms.Position = 0;
#endif
//TODO: Find out why the "xs:include" doesn't work with validator
//Validation is quite important, as we otherwise may end up injecting malicious code
// if (!m_disableValidation)
// {
// m_validator.Validate(ms, GetSchema(type));
// ms.Position = 0;
// }
try
{
return GetSerializer(type).Deserialize(ms);
}
catch (Exception ex)
{
string s = ex.Message;
throw;
}
}
///
/// Serialize an object into a new memory stream.
///
/// The object to serialize
/// A memorystream with the serialized object
virtual public System.IO.MemoryStream SerializeObject(object o)
{
System.IO.MemoryStream ms = new System.IO.MemoryStream();
SerializeObject(o, ms);
return Utility.RemoveUTF8BOM(ms);
}
///
/// Serializes an object into a stream
///
/// The object to serialize
/// The stream to serialize into
virtual public void SerializeObject(object o, System.IO.Stream stream)
{
//The Utf8 writer makes sure the Utf8 tag is in place + sets encoding to Utf8
//This is needed because the server fails when rendering maps using non utf8 xml documents
//And the XmlSerializer sytem in .Net does not have a method to set the encoding attribute
GetSerializer(o.GetType()).Serialize(new Utf8XmlWriter(stream), o);
}
///
/// Returns an XmlSerializer for the given type
///
/// The object type to serialize
/// An XmlSerializer for the given type
virtual protected System.Xml.Serialization.XmlSerializer GetSerializer(Type type)
{
if (m_serializers[type] == null)
m_serializers[type] = new System.Xml.Serialization.XmlSerializer(type);
return (System.Xml.Serialization.XmlSerializer)m_serializers[type];
}
///
/// Gets the highest version the API is currently tested againts
///
virtual public Version MaxTestedVersion
{
get { return SiteVersions.GetVersion(KnownSiteVersions.MapGuideEP2009); }
}
///
/// Validates the current server version against the highest tested version.
///
/// The version to validate
virtual protected void ValidateVersion(SiteVersion version)
{
ValidateVersion(new Version(version.Version));
}
///
/// Validates the current server version against the highest tested version.
///
/// The version to validate
virtual protected void ValidateVersion(Version version)
{
if (version > this.MaxTestedVersion)
throw new Exception("Untested with MapGuide Build > " + this.MaxTestedVersion.ToString());
}
///
/// Returns raw data from the server a byte array
///
/// The full resourceID to get data from
/// Raw data from the given resource
abstract public byte[] GetResourceXmlData(string resourceID);
///
/// Returns a WebLayout from the server.
///
/// The full resourceID of the WebLayout.
/// The WebLayout with the given ResourceID
virtual public WebLayout GetWebLayout(string resourceID)
{
return (WebLayout) GetResource(resourceID);
}
///
/// Returns a MapDefinition from the server.
///
/// The full resourceID of the MapDefinition.
/// The MapDefinition with the given ResourceID
virtual public MapDefinition GetMapDefinition(string resourceID)
{
return (MapDefinition) GetResource(resourceID);
}
///
/// Returns a LayerDefinition from the server.
///
/// The full resourceID of the LayerDefinition.
/// The LayerDefinition with the given ResourceID
virtual public LayerDefinition GetLayerDefinition(string resourceID)
{
return (LayerDefinition) GetResource(resourceID);
}
///
/// Returns a FeatureSource from the server.
///
/// The full resourceID of the FeatureSource.
/// The FeatureSource with the given ResourceID
virtual public FeatureSource GetFeatureSource(string resourceID)
{
return (FeatureSource) GetResource(resourceID);
}
///
/// Returns a ApplicationDefinition from the server.
///
/// The full resourceID of the ApplicationDefinition.
/// The ApplicationDefinition with the given ResourceID
virtual public ApplicationDefinition.ApplicationDefinitionType GetApplicationDefinition(string resourceID)
{
return (ApplicationDefinition.ApplicationDefinitionType) GetResource(resourceID);
}
///
/// Returns an object deserialized from server data.
/// Uses the ResourceID to infer the object type.
///
/// The full resourceID of the item to retrieve.
/// A deserialized object.
virtual public object GetResource(string resourceID)
{
Type type = GetResourceType(resourceID);
object o = DeserializeObject(type, new System.IO.MemoryStream(GetResourceXmlData(resourceID)));
System.Reflection.MethodInfo mi = type.GetMethod("SetResourceId");
if (mi != null)
mi.Invoke(o, new object[] {resourceID});
mi = type.GetMethod("SetConnection");
if (mi != null)
mi.Invoke(o, new object[] {this});
System.Reflection.PropertyInfo pi = type.GetProperty("ResourceId");
if (pi != null && pi.CanWrite)
pi.SetValue(o, resourceID, null);
pi = type.GetProperty("CurrentConnection");
if (pi != null && pi.CanWrite)
pi.SetValue(o, this, null);
return o;
}
///
/// Removes the version numbers from a providername
///
/// The name of the provider, with or without version numbers
/// The provider name without version numbers
virtual public string RemoveVersionFromProviderName(string providername)
{
double x;
string[] parts = providername.Split('.');
for(int i = parts.Length - 1; i >= 0; i--)
{
if (!double.TryParse(parts[i], System.Globalization.NumberStyles.Integer, null, out x))
{
if (i != 0)
return string.Join(".", parts, 0, i + 1);
break;
}
}
return providername;
}
///
/// Gets or sets a hashtable where the key is resourceID extensions, and values are System.Type values.
///
virtual public Hashtable ResourceTypeLookup
{
get { return m_resourceTypeLookup; }
set { m_resourceTypeLookup = value; }
}
///
/// Gets an object type from the resourceID.
/// Use the ResourceTypeLookup to add or remove types.
///
/// The resourceID for the resource
/// The type of the given item, throws an exception if the type does not exist
virtual public Type GetResourceType(string resourceID)
{
string extension = resourceID.Substring(resourceID.LastIndexOf(".") + 1);
return (Type)ResourceTypeLookup[extension];
}
///
/// Gets an object type from the resourceID.
/// Use the ResourceTypeLookup to add or remove types.
///
/// The resourceID for the resource
/// The type of the given item, returns null if no such type exists
virtual public Type TryGetResourceType(string resourceID)
{
try
{
string extension = resourceID.Substring(resourceID.LastIndexOf(".") + 1);
if (ResourceTypeLookup.ContainsKey(extension))
return (Type)ResourceTypeLookup[extension];
}
catch
{
}
return null;
}
///
/// Returns an installed provider, given the name of the provider
///
/// The name of the provider
/// The first matching provider or null
virtual public FeatureProviderRegistryFeatureProvider GetFeatureProvider(string providername)
{
string pname = RemoveVersionFromProviderName(providername).ToLower();
foreach(FeatureProviderRegistryFeatureProvider p in this.FeatureProviders)
if (RemoveVersionFromProviderName(p.Name).ToLower().Equals(pname.ToLower()))
return p;
return null;
}
public virtual string TestConnection(FeatureSource feature)
{
string f = GetResourceIdentifier(Guid.NewGuid().ToString(), ResourceTypes.FeatureSource, true);
try
{
SaveResourceAs(feature, f);
/*if (resources != null)
foreach(Stream s in resources)
SetResourceData(f, "", "", s);*/
return TestConnection(f);
}
finally
{
try { DeleteResource(f); }
catch {}
}
}
public abstract string TestConnection(string featuresource);
public abstract void DeleteResource(string resourceid);
///
/// Writes an object into a resourceID
///
/// The resource to write into
/// The resourcec to write
virtual public void WriteResource(string resourceid, object resource)
{
System.IO.MemoryStream ms = SerializeObject(resource);
ms.Position = 0;
//Validate that our data is correctly formated
/*if (!m_disableValidation)
{
m_validator.Validate(ms, GetSchema(resource.GetType()));
ms.Position = 0;
}*/
#if DEBUG_LASTMESSAGE
using (System.IO.Stream s = System.IO.File.Open("lastSave.xml", System.IO.FileMode.Create, System.IO.FileAccess.Write, System.IO.FileShare.None))
Utility.CopyStream(ms, s);
ms.Position = 0;
#endif
SetResourceXmlData(resourceid, ms);
}
///
/// Writes raw data into a resource.
///
/// The resourceID to write into
/// The stream containing the data to write.
abstract public void SetResourceXmlData(string resourceid, System.IO.Stream stream);
///
/// Gets the Xsd schema for a given type.
///
/// The type to get the schema for
/// The schema for the given type
virtual protected System.Xml.Schema.XmlSchema GetSchema(Type type)
{
if (m_cachedSchemas[type] == null)
{
System.Reflection.FieldInfo fi = type.GetField("SchemaName", System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.Public );
if (fi == null)
throw new Exception("Type " + type + ", does not contain Schema Info");
string xsd = (string)fi.GetValue(null);
using (System.IO.FileStream fs = System.IO.File.Open(System.IO.Path.Combine(m_schemasPath, xsd), System.IO.FileMode.Open, System.IO.FileAccess.Read, System.IO.FileShare.Read))
m_cachedSchemas.Add(type, System.Xml.Schema.XmlSchema.Read(fs, null));
}
return (System.Xml.Schema.XmlSchema)m_cachedSchemas[type];
}
///
/// Gets or sets the collection of cached schemas. Use the object type for key, and an XmlSchema instance for value.
///
virtual public Hashtable CachedSchemas
{
get { return m_cachedSchemas; }
set { m_cachedSchemas = value; }
}
///
/// Returns a boolean indicating if a given resource exists
///
/// The resource to look for
/// True if the resource exists false otherwise. Also returns false on error.
public bool ResourceExists(string resourceid)
{
try
{
string sourcefolder;
if (resourceid.EndsWith("/"))
sourcefolder = resourceid.Substring(0, resourceid.Substring(0, resourceid.Length-1).LastIndexOf("/") + 1);
else
sourcefolder = resourceid.Substring(0, resourceid.LastIndexOf("/") + 1);
ResourceList lst = GetRepositoryResources(sourcefolder, 1);
foreach(object o in lst.Items)
if (o.GetType() == typeof(ResourceListResourceFolder) && ((ResourceListResourceFolder)o).ResourceId == resourceid)
return true;
else if (o.GetType() == typeof(ResourceListResourceDocument) && ((ResourceListResourceDocument)o).ResourceId == resourceid)
return true;
return false;
}
catch
{
return false;
}
}
///
/// Updates all resource references inside an object.
///
/// The object in which the resource references are to be updated
/// The current resource path, the one updating from
/// The new resource path, the one updating to
/// True if the old and new resource path identifiers are folders, false otherwise
protected void UpdateResourceReferences(object o, string oldresourcepath, string newresourcepath, bool folderupdates)
{
UpdateResourceReferences(o, oldresourcepath, newresourcepath, folderupdates, new Hashtable());
}
///
/// Updates all resource references inside an object.
///
/// The object in which the resource references are to be updated
/// The current resource path, the one updating from
/// The new resource path, the one updating to
/// True if the old and new resource path identifiers are folders, false otherwise
/// A hashtable with objects previously visited. Used for recursion, leave as null when calling from outside the API.
protected void UpdateResourceReferences(object o, string oldresourcepath, string newresourcepath, bool folderupdates, Hashtable visited)
{
if (o == null)
return;
if (visited == null)
visited = new Hashtable();
//Prevent infinite recursion
if (o as string == null && !o.GetType().IsPrimitive)
{
if (visited.ContainsKey(o))
return;
else
visited.Add(o, null);
}
if (folderupdates)
{
if (!oldresourcepath.EndsWith("/"))
oldresourcepath += "/";
if (!newresourcepath.EndsWith("/"))
newresourcepath += "/";
}
foreach(System.Reflection.PropertyInfo pi in o.GetType().GetProperties())
{
if (!pi.CanRead || !pi.CanWrite || pi.GetIndexParameters().Length != 0 || pi.GetValue(o, null) == null)
continue;
if (pi.Name == "ResourceId")
{
object v = pi.GetValue(o, null);
string current = v as string;
if (current != null)
{
if (folderupdates && current.StartsWith(oldresourcepath))
pi.SetValue(o, newresourcepath + current.Substring(oldresourcepath.Length), null);
else if (current == oldresourcepath)
pi.SetValue(o, newresourcepath, null);
}
}
else if (pi.GetValue(o, null).GetType().GetInterface(typeof(System.Collections.ICollection).FullName) != null)
{
System.Collections.ICollection srcList = (System.Collections.ICollection)pi.GetValue(o, null);
foreach(object ox in srcList)
UpdateResourceReferences(ox, oldresourcepath, newresourcepath, folderupdates, visited);
}
else if (pi.GetValue(o, null).GetType().IsArray)
{
System.Array sourceArr = (System.Array)pi.GetValue(o, null);
for(int i = 0; i < sourceArr.Length; i++)
UpdateResourceReferences(sourceArr.GetValue(i), oldresourcepath, newresourcepath, folderupdates, visited);
}
else if (pi.PropertyType.IsClass)
UpdateResourceReferences(pi.GetValue(o, null), oldresourcepath, newresourcepath, folderupdates, visited);
}
}
///
/// Moves a resource, and subsequently updates all resources pointing to the old resource path
///
/// The current resource path, the one moving from
/// The new resource path, the one moving to
/// A callback delegate, being called for non progress reporting events.
/// A callback delegate, being called for progress reporting events.
///
public bool MoveResourceWithReferences(string oldpath, string newpath, LengthyOperationCallBack callback, LengthyOperationProgressCallBack progress)
{
LengthyOperationProgressArgs la = new LengthyOperationProgressArgs("Moving resource...", -1);
if (progress != null)
progress(this, la);
if (la.Cancel)
return false;
MoveResource(oldpath, newpath, true);
la.Progress = 100;
if (progress != null)
progress(this, la);
if (la.Cancel)
return false;
la.Progress = -1;
if (progress != null)
progress(this, la);
if (la.Cancel)
return false;
ArrayList items = new ArrayList();
Hashtable paths = new Hashtable();
//The old path does not exist, but luckily the call works anyway
ResourceReferenceList rlf = EnumerateResourceReferences(oldpath);
foreach(string s in rlf.ResourceId)
if (!paths.ContainsKey(s))
{
items.Add(new LengthyOperationCallbackArgs.LengthyOperationItem(s));
paths.Add(s, null);
}
la.Progress = 100;
if (progress != null)
progress(this, la);
if (la.Cancel)
return false;
LengthyOperationCallbackArgs args = new LengthyOperationCallbackArgs((LengthyOperationCallbackArgs.LengthyOperationItem[])items.ToArray(typeof(LengthyOperationCallbackArgs.LengthyOperationItem)));
if (callback != null)
callback(this, args);
if (args.Cancel)
return false;
if (args.Index > args.Items.Length)
return true;
if (args.Items.Length == 0)
return true;
do
{
LengthyOperationCallbackArgs.LengthyOperationItem item = args.Items[args.Index];
item.Status = LengthyOperationCallbackArgs.LengthyOperationItem.OperationStatus.Pending;
if (callback != null)
{
callback(this, args);
if (args.Cancel) return false;
}
try
{
object o = GetResource(item.Itempath);
UpdateResourceReferences(o, oldpath, newpath, false);
SaveResourceAs(o, item.Itempath);
item.Status = LengthyOperationCallbackArgs.LengthyOperationItem.OperationStatus.Success;
}
catch (Exception ex)
{
string s = ex.Message;
item.Status = LengthyOperationCallbackArgs.LengthyOperationItem.OperationStatus.Failure;
}
if (callback != null)
{
callback(this, args);
if (args.Cancel) return false;
}
args.Index++;
} while(!args.Cancel && args.Index < args.Items.Length);
return !args.Cancel;
}
///
/// Moves a folder, and subsequently updates all resources pointing to the old resource path
///
/// The current folder path, the one moving from
/// The new folder path, the one moving to
/// A callback delegate, being called for non progress reporting events.
/// A callback delegate, being called for progress reporting events.
///
public bool MoveFolderWithReferences(string oldpath, string newpath, LengthyOperationCallBack callback, LengthyOperationProgressCallBack progress)
{
oldpath = FixAndValidateFolderPath(oldpath);
newpath = FixAndValidateFolderPath(newpath);
LengthyOperationProgressArgs la = new LengthyOperationProgressArgs("Moving folder...", -1);
if (progress != null)
progress(this, la);
if (la.Cancel)
return false;
MoveFolder(oldpath, newpath, true);
la.Progress = 100;
if (progress != null)
progress(this, la);
if (la.Cancel)
return false;
int pg = 0;
la.Progress = 0;
la.StatusMessage = "Finding folder references...";
if (progress != null)
progress(this, la);
if (la.Cancel)
return false;
ResourceList lst = GetRepositoryResources(newpath);
Hashtable items = new Hashtable();
foreach(object o in lst.Items)
{
if (o.GetType() == typeof(ResourceListResourceDocument))
{
//The old path does not exist, but we need to enumerate references at the old location
string resource_oldpath = ((ResourceListResourceDocument)o).ResourceId;
resource_oldpath = oldpath + resource_oldpath.Substring(newpath.Length);
ResourceReferenceList rlf = EnumerateResourceReferences(resource_oldpath);
foreach(string s in rlf.ResourceId)
if (!items.Contains(s))
items.Add(s, new LengthyOperationCallbackArgs.LengthyOperationItem(s));
}
pg++;
la.Progress = Math.Max(Math.Min(99, (int)(((double)pg / (double)lst.Items.Count) * (double)100)), 0);
if (progress != null)
progress(this, la);
if (la.Cancel)
return false;
}
la.Progress = 100;
if (progress != null)
progress(this, la);
if (la.Cancel)
return false;
LengthyOperationCallbackArgs.LengthyOperationItem[] vi = new LengthyOperationCallbackArgs.LengthyOperationItem[items.Values.Count];
items.Values.CopyTo(vi, 0);
LengthyOperationCallbackArgs args = new LengthyOperationCallbackArgs(vi);
if (callback != null)
callback(this, args);
if (args.Cancel)
return false;
if (args.Index > args.Items.Length)
return true;
if (args.Items.Length == 0)
return true;
do
{
LengthyOperationCallbackArgs.LengthyOperationItem item = args.Items[args.Index];
item.Status = LengthyOperationCallbackArgs.LengthyOperationItem.OperationStatus.Pending;
if (callback != null)
{
callback(this, args);
if (args.Cancel)
return false;
}
try
{
object o = GetResource(item.Itempath);
UpdateResourceReferences(o, oldpath, newpath, true);
SaveResourceAs(o, item.Itempath);
item.Status = LengthyOperationCallbackArgs.LengthyOperationItem.OperationStatus.Success;
}
catch (Exception ex)
{
string s = ex.Message;
item.Status = LengthyOperationCallbackArgs.LengthyOperationItem.OperationStatus.Failure;
}
if (callback != null)
{
callback(this, args);
if (args.Cancel)
return false;
}
args.Index++;
} while(!args.Cancel && args.Index < args.Items.Length);
return !args.Cancel;
}
///
/// Copies folder, and subsequently updates all resources within the folder to use the new folder path instead of the originating one.
///
/// The current folder path, the one copying from
/// The new folder path, the one copying to
/// A callback delegate, being called for non progress reporting events.
/// A callback delegate, being called for progress reporting events.
///
public bool CopyFolderWithReferences(string oldpath, string newpath, LengthyOperationCallBack callback, LengthyOperationProgressCallBack progress)
{
oldpath = FixAndValidateFolderPath(oldpath);
newpath = FixAndValidateFolderPath(newpath);
ResourceList lst = GetRepositoryResources(oldpath);
LengthyOperationProgressArgs la = new LengthyOperationProgressArgs("Copying folder...", -1);
if (progress != null)
progress(this, la);
if (la.Cancel)
return false;
CopyFolder(oldpath, newpath, true);
la.Progress = 100;
if (progress != null)
progress(this, la);
if (la.Cancel)
return false;
la.Progress = 0;
la.StatusMessage = "Finding folder references...";
int pg = 0;
if (progress != null)
progress(this, la);
if (la.Cancel)
return false;
ArrayList items = new ArrayList();
Hashtable paths = new Hashtable();
foreach(object o in lst.Items)
{
if (o.GetType() == typeof(ResourceListResourceDocument))
{
ResourceReferenceList rlf = EnumerateResourceReferences(((ResourceListResourceDocument)o).ResourceId);
foreach(string s in rlf.ResourceId)
if (s.StartsWith(oldpath))
{
string dest = newpath + s.Substring(oldpath.Length);
if (!paths.ContainsKey(dest))
{
items.Add(new LengthyOperationCallbackArgs.LengthyOperationItem(dest));
paths.Add(dest, null);
}
}
}
pg++;
la.Progress = Math.Max(Math.Min(99, (int)(((double)pg / (double)lst.Items.Count) * (double)100)), 0);
if (progress != null)
progress(this, la);
if (la.Cancel)
return false;
}
la.Progress = 100;
if (progress != null)
progress(this, la);
if (la.Cancel)
return false;
LengthyOperationCallbackArgs args = new LengthyOperationCallbackArgs((LengthyOperationCallbackArgs.LengthyOperationItem[])items.ToArray(typeof(LengthyOperationCallbackArgs.LengthyOperationItem)));
if (callback != null)
callback(this, args);
if (args.Cancel)
return false;
if (args.Index > args.Items.Length)
return true;
if (args.Items.Length == 0)
return true;
do
{
LengthyOperationCallbackArgs.LengthyOperationItem item = args.Items[args.Index];
item.Status = LengthyOperationCallbackArgs.LengthyOperationItem.OperationStatus.Pending;
if (callback != null)
{
callback(this, args);
if (args.Cancel) return false;
}
try
{
object o = GetResource(item.Itempath);
UpdateResourceReferences(o, oldpath, newpath, true);
SaveResourceAs(o, item.Itempath);
item.Status = LengthyOperationCallbackArgs.LengthyOperationItem.OperationStatus.Success;
}
catch (Exception ex)
{
string s = ex.Message;
item.Status = LengthyOperationCallbackArgs.LengthyOperationItem.OperationStatus.Failure;
}
if (callback != null)
{
callback(this, args);
if (args.Cancel) return false;
}
args.Index++;
} while(!args.Cancel && args.Index < args.Items.Length);
return !args.Cancel;
}
///
/// Validates the origin of the folder, and ensures the folder path has a trailing slash.
///
/// The path to validate and fix
/// The fixed path
virtual protected string FixAndValidateFolderPath(string folderpath)
{
if (! folderpath.StartsWith("Library://") && ! folderpath.StartsWith("Session:" + this.SessionID + "//"))
throw new Exception("Invalid folder path, must be either library or session");
if (!folderpath.EndsWith("/"))
folderpath += "/";
return folderpath;
}
///
/// Creates a folder on the server
///
/// The path of the folder to create
virtual public void CreateFolder(string resourceID)
{
resourceID = FixAndValidateFolderPath(resourceID);
SetResourceXmlData(resourceID, new System.IO.MemoryStream());
}
///
/// Returns a value indicating if a given folder exists
///
/// The path of the folder
/// True if the folder exists, false otherwise. Also returns false on error.
virtual public bool HasFolder(string folderpath)
{
folderpath = FixAndValidateFolderPath(folderpath);
try
{
ResourceList l = this.GetRepositoryResources(folderpath, 1);
return true;
}
catch
{
return false;
}
}
///
/// Enumereates all references to a given resource
///
/// The resource to enumerate references for
/// A list of resources that reference the given resourceID
abstract public ResourceReferenceList EnumerateResourceReferences(string resourceid);
///
/// Copies a resource from one location to another. This does not update any references.
///
/// The current resource path, the one copying from
/// The new resource path, the one copying to
/// True if the copy can overwrite an existing resource, false otherwise
abstract public void CopyResource(string oldpath, string newpath, bool overwrite);
///
/// Copies a folder and all its content. This does not update any references.
///
/// The current folder path, the one copying from
/// The new folder path, the one copying to
/// True if the copy can overwrite an existing folder, false otherwise
abstract public void CopyFolder(string oldpath, string newpath, bool overwrite);
///
/// Moves a resource from one location to another. This does not update any references.
///
/// The current resource path, the one moving from
/// The new resource path, the one moving to
/// True if the move can overwrite an existing resource, false otherwise
abstract public void MoveResource(string oldpath, string newpath, bool overwrite);
///
/// Moves a folder and its content from one location to another. This does not update any references.
///
/// The current folder path, the one moving from
/// The new folder path, the one moving to
/// True if the move can overwrite an existing folder, false otherwise
abstract public void MoveFolder(string oldpath, string newpath, bool overwrite);
///
/// Returns data from a resource as a memorystream
///
/// The id of the resource to fetch data from
/// The name of the associated data item
/// A stream containing the references resource data
abstract public System.IO.MemoryStream GetResourceData(string resourceID, string dataname);
///
/// Uploads data to a resource
///
/// The id of the resource to update
/// The name of the data to update or create
/// The type of data
/// A stream containing the new content of the resource data
abstract public void SetResourceData(string resourceid, string dataname, ResourceDataType datatype, System.IO.Stream stream);
///
/// Saves a WebLayout, using its originating resourceId
///
/// The WebLayout to save
public void SaveResource(WebLayout resource)
{
if (resource.ResourceId == null)
throw new Exception("Cannot save weblayout when no resourceid has been set, use SaveAs instead");
SaveResourceAs(resource, resource.ResourceId);
}
///
/// Saves a FeatureSource, using its originating resourceId
///
/// The FeatureSource to save
public void SaveResource(FeatureSource resource)
{
if (resource.ResourceId == null)
throw new Exception("Cannot save featuresource when no resourceid has been set, use SaveAs instead");
SaveResourceAs(resource, resource.ResourceId);
}
///
/// Saves a LayerDefinition, using its originating resourceId
///
/// The LayerDefinition to save
public void SaveResource(LayerDefinition resource)
{
if (resource.ResourceId == null)
throw new Exception("Cannot save layer when no resourceid has been set, use SaveAs instead");
SaveResourceAs(resource, resource.ResourceId);
}
///
/// Saves a MapDefinition, using its originating resourceId
///
/// The MapDefintion to save
public void SaveResource(MapDefinition resource)
{
if (resource.ResourceId == null)
throw new Exception("Cannot save map when no resourceid has been set, use SaveAs instead");
SaveResourceAs(resource, resource.ResourceId);
}
///
/// Saves an object into the repository
///
/// The object to save
/// The resourceId to save the object as
public void SaveResourceAs(object resource, string resourceid)
{
LayerDefinition ldef = resource as LayerDefinition;
if (ldef != null)
{
if (ldef.version == "1.1.0" && this.SiteVersion <= SiteVersions.GetVersion(KnownSiteVersions.MapGuideEP1_1))
ldef.version = "1.0.0";
bool version1 = ldef.version == "1.0.0";
VectorLayerDefinitionType vldef = ldef.Item as VectorLayerDefinitionType;
if (vldef != null)
{
if (vldef.ToolTip == null)
vldef.ToolTip = "";
if (vldef.Url == null)
vldef.Url = "";
if (vldef.Filter == null)
vldef.Filter = "";
foreach(VectorScaleRangeType vsc in vldef.VectorScaleRange)
{
for(int i= vsc.Items.Count-1; i >= 0; i--)
{
object o = vsc.Items[i];
if (o as PointTypeStyleType != null)
{
if (((PointTypeStyleType)vsc.Items[i]).PointRule != null)
{
if (((PointTypeStyleType)vsc.Items[i]).PointRule.Count == 0 )
vsc.Items.RemoveAt(i);
else
foreach(PointRuleType pr in ((PointTypeStyleType)vsc.Items[i]).PointRule)
{
if (pr.LegendLabel == null)
pr.LegendLabel = "";
if (pr.Item != null && pr.Item.Item != null)
{
if (pr.Item.Item as MarkSymbolType != null)
{
MarkSymbolType mks = pr.Item.Item as MarkSymbolType;
if (mks.Edge != null)
{
if (version1)
mks.Edge.SizeContext = SizeContextType.Default;
else if (mks.Edge.SizeContext == SizeContextType.Default)
mks.Edge.SizeContext = SizeContextType.MappingUnits;
}
if (mks.Fill != null)
{
}
}
/*if (version1)
pr.Item.Item.SizeContext = SizeContextType.Default;
else*/ if (pr.Item.Item.SizeContext == SizeContextType.Default)
pr.Item.Item.SizeContext = SizeContextType.MappingUnits;
}
}
}
}
else if (o as LineTypeStyleType != null)
{
if (((LineTypeStyleType)vsc.Items[i]).LineRule != null)
{
if ( ((LineTypeStyleType)vsc.Items[i]).LineRule.Count == 0 )
vsc.Items.RemoveAt(i);
else
foreach(LineRuleType lr in ((LineTypeStyleType)vsc.Items[i]).LineRule)
{
if (lr.LegendLabel == null)
lr.LegendLabel = "";
if (lr.Items != null)
{
foreach(StrokeType st in lr.Items)
if (version1)
st.SizeContext = SizeContextType.Default;
else if (st.SizeContext == SizeContextType.Default)
st.SizeContext = SizeContextType.MappingUnits;
}
}
}
}
else if (o as AreaTypeStyleType != null)
{
if (((AreaTypeStyleType)vsc.Items[i]).AreaRule != null && ((AreaTypeStyleType)vsc.Items[i]).AreaRule.Count == 0 )
vsc.Items.RemoveAt(i);
foreach(AreaRuleType ar in ((AreaTypeStyleType)vsc.Items[i]).AreaRule)
{
if (ar.LegendLabel == null)
ar.LegendLabel = "";
if (ar.Item != null && ar.Item.Stroke != null)
{
if (version1)
ar.Item.Stroke.SizeContext = SizeContextType.Default;
else if (ar.Item.Stroke.SizeContext == SizeContextType.Default)
ar.Item.Stroke.SizeContext = SizeContextType.MappingUnits;
}
}
}
}
}
}
GridLayerDefinitionType gld = ldef.Item as GridLayerDefinitionType;
if (gld != null)
{
if (gld.GridScaleRange != null)
foreach(GridScaleRangeType gs in gld.GridScaleRange)
if (gs.ColorStyle != null && gs.ColorStyle.ColorRule != null)
foreach(GridColorRuleType gc in gs.ColorStyle.ColorRule)
if (gc.LegendLabel == null)
gc.LegendLabel = "";
}
//TODO: Clear any data that is not supported under the current version
if (ldef.version == "1.0.0")
{}
else if (ldef.version == "1.1.0")
{}
}
MapDefinition mdef = resource as MapDefinition;
if (mdef != null)
{
if (mdef.BaseMapDefinition != null)
if (mdef.BaseMapDefinition.BaseMapLayerGroup == null)
mdef.BaseMapDefinition = null;
else if (mdef.BaseMapDefinition.BaseMapLayerGroup.Count == 0)
mdef.BaseMapDefinition = null;
if (mdef.Layers != null)
foreach(MapLayerType mlt in mdef.Layers)
if (mlt.LegendLabel == null)
mlt.LegendLabel = "";
}
WebLayout wl = resource as WebLayout;
if (wl != null)
{
if (wl.CommandSet != null)
foreach(CommandType cmd in wl.CommandSet)
{
if (cmd.Name == null)
cmd.Name = "";
if (cmd.Label == null)
cmd.Label = "";
/*if (cmd as TargetedCommandType != null)
if ((cmd as TargetedCommandType).TargetFrame == null)
(cmd as TargetedCommandType).TargetFrame = "";*/
if (cmd as SearchCommandType != null)
{
SearchCommandType sc = cmd as SearchCommandType;
if (sc.Layer == null)
sc.Layer = "";
if (sc.Prompt == null)
sc.Prompt = "";
if (sc.ResultColumns != null && sc.ResultColumns.Count == 0)
sc.ResultColumns = null;
}
if (cmd as InvokeURLCommandType != null)
{
InvokeURLCommandType sc = cmd as InvokeURLCommandType;
if (sc.URL == null)
sc.URL = "";
}
if (cmd as InvokeScriptCommandType != null)
{
InvokeScriptCommandType sc = cmd as InvokeScriptCommandType;
if (sc.Script == null)
sc.Script = "";
}
}
}
//TODO: Extract ResourceType from resource.GetType(), and validate
//ValidateResourceID(resourceid, ResourceTypes.MapDefinition);
System.IO.MemoryStream ms = SerializeObject(resource);
SetResourceXmlData(resourceid, ms);
}
///
/// Saves a MapDefinition under a different resourceID
///
/// The MapDefinition to save
/// The new path of the MapDefinition
virtual public void SaveResourceAs(MapDefinition resource, string resourceid)
{
SaveResourceAs((object)resource, resourceid);
}
///
/// Saves a LayerDefinition under a different resourceID
///
/// The LayerDefinition to save
/// The new path of the LayerDefinition
virtual public void SaveResourceAs(LayerDefinition resource, string resourceid)
{
SaveResourceAs((object)resource, resourceid);
}
///
/// Saves a FeatureSource under a different resourceID
///
/// The FeatureSource to save
/// The new path of the FeatureSource
virtual public void SaveResourceAs(FeatureSource resource, string resourceid)
{
SaveResourceAs((object)resource, resourceid);
}
///
/// Saves a WebLayout under a different resourceID
///
/// The WebLayout to save
/// The new path of the WebLayout
virtual public void SaveResourceAs(WebLayout resource, string resourceid)
{
SaveResourceAs((object)resource, resourceid);
}
///
/// Gets a list of installed feature providers
///
abstract public FeatureProviderRegistryFeatureProviderCollection FeatureProviders { get; }
///
/// Gets or sets a flag that indicates if the Xml resources are validated before leaving and entering the server.
///
public bool DisableValidation
{
get {return m_disableValidation; }
set { m_disableValidation = value; }
}
///
/// Gets the name of a resource, given its identifier
///
/// The identifier to look for
/// True if path information should be include, false otherwise
/// The name of the resource
public string GetResourceName(string identifier, bool includePath)
{
int begin;
if (includePath)
{
if (identifier.IndexOf("//") < 0)
throw new Exception("Not valid identifier");
begin = identifier.IndexOf("//") + 2;
}
else
{
if (identifier.IndexOf("/") < 0)
throw new Exception("Not valid identifier");
begin = identifier.LastIndexOf("/") + 1;
}
int end = identifier.LastIndexOf(".");
if (end < begin)
throw new Exception("Not valid identifier");
return identifier.Substring(begin, end - begin);
}
///
/// Gets or sets a value indicating if the session should automatically be restarted if it expires
///
virtual public bool AutoRestartSession
{
get { return m_autoRestartSession; }
set { m_autoRestartSession = value; }
}
abstract public Version SiteVersion { get; }
///
/// Determines if an exception is a "Session Expired" exception.
///
/// The exception to evaluate
/// True if the exception is a session expired exception
abstract public bool IsSessionExpiredException(Exception ex);
///
/// Returns the avalible application templates on the server
///
/// The avalible application templates on the server
abstract public ApplicationDefinitionTemplateInfoSet GetApplicationTemplates();
///
/// Returns the avalible application widgets on the server
///
/// The avalible application widgets on the server
abstract public ApplicationDefinitionWidgetInfoSet GetApplicationWidgets();
///
/// Returns the avalible widget containers on the server
///
/// The avalible widget containers on the server
abstract public ApplicationDefinitionContainerInfoSet GetApplicationContainers();
///
/// Returns the spatial info for a given featuresource
///
/// The ID of the resource to query
/// Query only active items
/// A list of spatial contexts
abstract public FdoSpatialContextList GetSpatialContextInfo(string resourceID, bool activeOnly);
///
/// Gets the names of the identity properties from a feature
///
/// The resourceID for the FeatureSource
/// The classname of the feature, including schema
/// A string array with the found identities
abstract public string[] GetIdentityProperties(string resourceID, string classname);
///
/// Restarts the server session, and creates a new session ID
///
public void RestartSession()
{
RestartSession(true);
}
///
/// Restarts the server session, and creates a new session ID
///
/// If set to true, the call throws an exception if the call failed
/// True if the creation succeed, false otherwise
abstract public bool RestartSession(bool throwException);
///
/// Sets the selection of a map
///
/// The resourceID of the runtime map
/// The selection xml
abstract public void SetSelectionXml(string runtimeMap, string selectionXml);
///
/// Gets the selection from a map
///
/// The resourceID of the runtime map
/// The selection xml
abstract public string GetSelectionXml(string runtimeMap);
///
/// Enumerates all unmanaged folders, meaning alias'ed folders
///
/// The type of data to return
/// A filter applied to the items
/// True if the list should contains recursive results
/// The path to retrieve the data from
/// A list of unmanaged data
abstract public UnmanagedDataList EnumerateUnmanagedData(string startpath, string filter, bool recursive, UnmanagedDataTypes type);
}
}