#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); } }