#region Disclaimer / License
// Copyright (C) 2009, 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.Net;
using System.Xml;
using System.Collections.Specialized;
using System.Collections;
using System.Text;
namespace OSGeo.MapGuide.MaestroAPI
{
///
/// Primary http based connection to the MapGuide Server
///
public class HttpServerConnection : ServerConnectionBase, ServerConnectionI, IDisposable
{
private WebClient m_wc;
private RequestBuilder m_reqBuilder;
//These only change after server reboot, so it is probably safe to cache them
private FeatureProviderRegistry m_featureProviders = null;
private Hashtable m_cachedProviderCapabilities = null;
private Version m_siteVersion;
private bool mAnonymousUser = false;
internal HttpServerConnection()
: base()
{
m_wc = new WebClient();
m_cachedProviderCapabilities = new Hashtable();
}
///
/// Gets whether this connection was initialised with an Anonymous login. If it was, it will return true.
/// If this was not, or it was initialised from an existing session id, then it will return false.
///
public bool IsAnonymous { get { return mAnonymousUser; } }
public const string PARAM_URL = "Url";
public const string PARAM_SESSION = "SessionId";
public const string PARAM_LOCALE = "Locale";
public const string PARAM_UNTESTED = "AllowUntestedVersion";
public const string PARAM_USERNAME = "Username";
public const string PARAM_PASSWORD = "Password";
private void InitConnection(Uri hosturl, string sessionid, string locale, bool allowUntestedVersion)
{
m_reqBuilder = new RequestBuilder(hosturl, locale, sessionid);
string req = m_reqBuilder.GetSiteVersion();
SiteVersion sv = null;
try
{
sv = (SiteVersion)DeserializeObject(typeof(SiteVersion), m_wc.OpenRead(req));
}
catch (Exception ex)
{
sv = null;
bool ok = false;
try
{
//Retry, and append missing path, if applicable
if (!hosturl.ToString().EndsWith("/mapagent/mapagent.fcgi"))
{
string tmp = hosturl.ToString();
if (!tmp.EndsWith("/"))
tmp += "/";
hosturl = new Uri(tmp + "mapagent/mapagent.fcgi");
m_reqBuilder = new RequestBuilder(hosturl, locale, sessionid);
req = m_reqBuilder.GetSiteVersion();
sv = (SiteVersion)DeserializeObject(typeof(SiteVersion), m_wc.OpenRead(req));
ok = true;
}
}
catch { }
if (!ok) //Report original error
throw new Exception("Failed to connect, perhaps session is expired?\nExtended error info: " + ex.Message, ex);
}
if (!allowUntestedVersion)
ValidateVersion(sv);
m_siteVersion = new Version(sv.Version);
}
private void InitConnection(Uri hosturl, string username, string password, string locale, bool allowUntestedVersion)
{
m_reqBuilder = new RequestBuilder(hosturl, locale);
m_wc.Credentials = new NetworkCredential(username, password);
string req = m_reqBuilder.CreateSession();
m_username = username;
m_password = password;
mAnonymousUser = (username == "Anonymous");
try
{
this.RestartSession();
}
catch (Exception ex)
{
string msg = NestedExceptionMessageProcessor.GetFullMessage(ex);
throw new Exception("Failed to connect, please check network connection and login information.\nExtended error info: " + msg, ex);
}
if (!allowUntestedVersion)
ValidateVersion(m_siteVersion);
m_username = username;
m_password = password;
}
//This is the constructor used by ConnectionProviderRegistry.CreateConnection
internal HttpServerConnection(NameValueCollection initParams)
: this()
{
if (initParams[PARAM_URL] == null)
throw new ArgumentException("Missing required connection parameter: " + PARAM_URL);
string locale = null;
bool allowUntestedVersion = true;
if (initParams[PARAM_LOCALE] != null)
locale = initParams[PARAM_LOCALE];
if (initParams[PARAM_UNTESTED] != null)
bool.TryParse(initParams[PARAM_UNTESTED], out allowUntestedVersion);
if (initParams[PARAM_SESSION] != null)
{
string sessionid = initParams[PARAM_SESSION];
InitConnection(new Uri(initParams[PARAM_URL]), sessionid, locale, allowUntestedVersion);
}
else //Assuming username/password combination
{
string pwd = initParams[PARAM_PASSWORD] ?? string.Empty;
if (initParams[PARAM_USERNAME] == null)
throw new ArgumentException("Missing required connection parameter: " + PARAM_USERNAME);
InitConnection(new Uri(initParams[PARAM_URL]), initParams[PARAM_USERNAME], pwd, locale, allowUntestedVersion);
}
}
[Obsolete("This will be removed in the future. Use ConnectionProviderRegistry.CreateHttpConnection() instead")]
public HttpServerConnection(Uri hosturl, string sessionid, string locale, bool allowUntestedVersion)
: this()
{
InitConnection(hosturl, sessionid, locale, allowUntestedVersion);
}
[Obsolete("This will be removed in the future. Use ConnectionProviderRegistry.CreateHttpConnection() instead")]
public HttpServerConnection(Uri hosturl, string username, string password, string locale, bool allowUntestedVersion)
: this()
{
InitConnection(hosturl, username, password, locale, allowUntestedVersion);
}
public override string SessionID
{
get { return m_reqBuilder.SessionID; }
}
public ResourceList RepositoryResources
{
get
{
return GetRepositoryResources();
}
}
public override ResourceList GetRepositoryResources(string startingpoint, string type, int depth, bool computeChildren)
{
string req = m_reqBuilder.EnumerateResources(startingpoint, depth, type, computeChildren);
//TODO: Cache?
return (ResourceList)DeserializeObject(typeof(ResourceList), this.OpenRead(req));
}
public override FeatureProviderRegistryFeatureProviderCollection FeatureProviders
{
get
{
string req = m_reqBuilder.GetFeatureProviders();
if (m_featureProviders == null)
m_featureProviders = (FeatureProviderRegistry)DeserializeObject(typeof(FeatureProviderRegistry), this.OpenRead(req));
return m_featureProviders.FeatureProvider;
}
}
internal WebClient WebClient { get { return m_wc; } }
public override string TestConnection(string featuresource)
{
string req = m_reqBuilder.TestConnection(featuresource);
string result = string.Empty;
try
{
byte[] x = this.DownloadData(req);
result = Encoding.UTF8.GetString(x);
}
catch (WebException wex)
{
if (wex.Response != null)
{
try
{
using (System.IO.MemoryStream ms = new System.IO.MemoryStream())
{
Utility.CopyStream(wex.Response.GetResponseStream(), ms);
result = System.Text.Encoding.UTF8.GetString(ms.ToArray(), 0, (int)ms.Length);
}
if (result.ToLower().IndexOf("
") > 0)
result = result.Substring(result.ToLower().IndexOf("") + 6);
if (result.ToLower().IndexOf("") > 0)
result = result.Substring(0, result.ToLower().IndexOf(""));
return result;
}
catch
{
}
}
if (wex.InnerException == null)
return wex.Message;
else
return wex.InnerException.Message;
}
catch (Exception ex)
{
result = NestedExceptionMessageProcessor.GetFullMessage(ex);
}
return result;
}
public string TestConnection(string providername, NameValueCollection parameters)
{
string req = m_reqBuilder.TestConnection(providername, parameters);
//System.IO.MemoryStream msx = new System.IO.MemoryStream();
//System.Net.WebRequest reqp = m_reqBuilder.TestConnectionPost(providername, parameters, msx);
try
{
/*msx.Position = 0;
Utility.CopyStream(msx, reqp.GetRequestStream());
reqp.GetRequestStream().Flush();
int f = reqp.GetResponse().GetResponseStream().ReadByte();*/
byte[] x = this.DownloadData(req);
}
catch (WebException wex)
{
if (wex.Response != null)
{
try
{
string result = "";
using (System.IO.MemoryStream ms = new System.IO.MemoryStream())
{
Utility.CopyStream(wex.Response.GetResponseStream(), ms);
result = System.Text.Encoding.UTF8.GetString(ms.ToArray(), 0, (int)ms.Length);
}
if (result.ToLower().IndexOf("") > 0)
result = result.Substring(result.ToLower().IndexOf("") + 6);
if (result.ToLower().IndexOf("") > 0)
result = result.Substring(0, result.ToLower().IndexOf(""));
return result;
}
catch
{
}
}
if (wex.InnerException == null)
return wex.Message;
else
return wex.InnerException.Message;
}
catch (Exception ex)
{
return NestedExceptionMessageProcessor.GetFullMessage(ex);
}
return string.Empty;
}
///
/// Placeholder for actual method call
///
public void DescribeSchema()
{
throw new NotImplementedException();
}
public OSGeo.MapGuide.MaestroAPI.FdoProviderCapabilities GetProviderCapabilities(string provider)
{
if (m_cachedProviderCapabilities == null)
m_cachedProviderCapabilities = new Hashtable();
if (m_cachedProviderCapabilities.ContainsKey(provider))
return (FdoProviderCapabilities)m_cachedProviderCapabilities[provider];
string req = m_reqBuilder.GetProviderCapabilities(provider);
//TODO: Cache?
FdoProviderCapabilities o = (FdoProviderCapabilities)DeserializeObject(typeof(FdoProviderCapabilities), this.OpenRead(req));
return o;
}
public override System.IO.MemoryStream GetResourceData(string resourceID, string dataname)
{
string req = m_reqBuilder.GetResourceData(resourceID, dataname);
System.IO.MemoryStream ms = new System.IO.MemoryStream();
Utility.CopyStream(this.OpenRead(req), ms);
#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);
#endif
ms.Position = 0;
return ms;
}
public WebHeaderCollection LastResponseHeaders
{
get
{
return m_wc.ResponseHeaders;
}
}
public override byte[] GetResourceXmlData(string resourceID)
{
ResourceIdentifier.Validate(resourceID, ResourceTypes.FeatureSource);
string req = m_reqBuilder.GetResourceContent(resourceID);
System.IO.MemoryStream ms = new System.IO.MemoryStream();
using(System.IO.Stream s = this.OpenRead(req))
return Utility.StreamAsArray(s);
}
/*public object DeserializeItem(System.IO.Stream s)
{
if (!s.CanSeek)
{
System.IO.MemoryStream ms = new System.IO.MemoryStream();
Utility.CopyStream(s, ms);
s = ms;
}
XmlTextReader xtr = new XmlTextReader(s);
string r;
if(xtr.Read())
r = xtr.Name;
else
return null;
return null;
}*/
public System.IO.Stream GetMapDWF(string resourceID)
{
ResourceIdentifier.Validate(resourceID, ResourceTypes.MapDefinition);
string req = m_reqBuilder.GetMapDWF(resourceID);
return this.OpenRead(req);
}
public override void SetResourceData(string resourceid, string dataname, ResourceDataType datatype, System.IO.Stream stream, Utility.StreamCopyProgressDelegate callback)
{
#if DEBUG_LASTMESSAGE
using (System.IO.Stream s = System.IO.File.Open("lastSaveData.bin", System.IO.FileMode.Create, System.IO.FileAccess.Write, System.IO.FileShare.None))
Utility.CopyStream(stream, s);
#endif
if (stream.CanSeek)
stream.Position = 0;
System.IO.MemoryStream outStream = new System.IO.MemoryStream();
#if DEBUG_LASTMESSAGE
try
{
#endif
System.Net.WebRequest req = m_reqBuilder.SetResourceData(resourceid, dataname, datatype, outStream, stream, callback);
req.Credentials = m_wc.Credentials;
outStream.Position = 0;
//Protect against session expired
if (this.m_autoRestartSession && m_username != null && m_password != null)
this.DownloadData(m_reqBuilder.GetSiteVersion());
//TODO: We need a progress bar for the upload....
req.Timeout = 1000 * 60 * 15;
using(System.IO.Stream rs = req.GetRequestStream())
{
Utility.CopyStream(outStream, rs);
rs.Flush();
}
using (System.IO.Stream resp = req.GetResponse().GetResponseStream())
{
//Do nothing... there is no return value
}
#if DEBUG_LASTMESSAGE
}
catch
{
using (System.IO.Stream s = System.IO.File.OpenWrite("lastPost.txt"))
Utility.CopyStream(outStream, s);
throw;
}
#endif
}
public override void SetResourceXmlData(string resourceid, System.IO.Stream content, System.IO.Stream header)
{
System.IO.MemoryStream outStream = new System.IO.MemoryStream();
#if DEBUG_LASTMESSAGE
try
{
#endif
//Protect against session expired
if (this.m_autoRestartSession && m_username != null && m_password != null)
this.DownloadData(m_reqBuilder.GetSiteVersion());
System.Net.WebRequest req = m_reqBuilder.SetResource(resourceid, outStream, content, header);
req.Credentials = m_wc.Credentials;
outStream.Position = 0;
try
{
using (System.IO.Stream rs = req.GetRequestStream())
{
Utility.CopyStream(outStream, rs);
rs.Flush();
}
using (System.IO.Stream resp = req.GetResponse().GetResponseStream())
{
//Do nothing... there is no return value
}
}
catch (Exception ex)
{
Exception ex2 = Utility.ThrowAsWebException(ex);
if (ex2 != ex)
throw ex2;
else
throw;
}
#if DEBUG_LASTMESSAGE
}
catch
{
if (outStream.CanSeek)
outStream.Position = 0;
using (System.IO.Stream s = System.IO.File.OpenWrite("lastPost.txt"))
Utility.CopyStream(outStream, s);
throw;
}
#endif
}
public FeatureSetReader ExecuteSqlQuery(string featureSourceID, string sql)
{
ResourceIdentifier.Validate(featureSourceID, ResourceTypes.FeatureSource);
string req = m_reqBuilder.ExecuteSqlQuery(featureSourceID, sql);
return new XmlFeatureSetReader(this.OpenRead(req));
}
public FeatureSetReader QueryFeatureSource(string resourceID, string schema, string query)
{
return QueryFeatureSource(resourceID, schema, query, null);
}
public FeatureSetReader QueryFeatureSource(string resourceID, string schema)
{
return QueryFeatureSource(resourceID, schema, null, null);
}
public FeatureSetReader QueryFeatureSource(string resourceID, string schema, string query, string[] columns)
{
return QueryFeatureSource(resourceID, schema, query, columns, null);
}
public FeatureSetReader QueryFeatureSource(string resourceID, string schema, string query, string[] columns, NameValueCollection computedProperties)
{
return QueryFeatureSourceCore(false, resourceID, schema, query, columns, computedProperties);
}
private FeatureSetReader QueryFeatureSourceCore(bool aggregate, string resourceID, string schema, string query, string[] columns, NameValueCollection computedProperties)
{
//The request may execeed the url limit of the server, especially when using GeomFromText('...')
ResourceIdentifier.Validate(resourceID, ResourceTypes.FeatureSource);
System.IO.MemoryStream ms = new System.IO.MemoryStream();
System.Net.WebRequest req = m_reqBuilder.SelectFeatures(aggregate, resourceID, schema, query, columns, computedProperties, ms);
req.Timeout = 200 * 1000;
ms.Position = 0;
#if DEBUG
string xq = m_reqBuilder.reqAsUrl(resourceID, schema, query, columns);
#endif
try
{
using (System.IO.Stream rs = req.GetRequestStream())
{
Utility.CopyStream(ms, rs);
rs.Flush();
}
return new XmlFeatureSetReader(req.GetResponse().GetResponseStream());
}
catch (Exception ex)
{
try
{
if (this.IsSessionExpiredException(ex) && this.AutoRestartSession && this.RestartSession(false))
return this.QueryFeatureSource(resourceID, schema, query, columns);
}
catch
{
//Throw the original exception, not the secondary one
}
Exception ex2 = Utility.ThrowAsWebException(ex);
if (ex2 != ex)
throw ex2;
else
throw;
}
}
public override FeatureSetReader AggregateQueryFeatureSource(string resourceID, string schema, string filter, string[] columns)
{
return QueryFeatureSourceCore(true, resourceID, schema, filter, columns, null);
}
public override FeatureSetReader AggregateQueryFeatureSource(string resourceID, string schema, string filter, NameValueCollection aggregateFunctions)
{
return QueryFeatureSourceCore(true, resourceID, schema, filter, null, aggregateFunctions);
}
public override FeatureSourceDescription DescribeFeatureSource(string resourceID)
{
return DescribeFeatureSource(resourceID, "");
}
public override FeatureSourceDescription DescribeFeatureSource(string resourceID, string schema)
{
if (schema != null && schema.IndexOf(":") > 0)
schema = schema.Substring(0, schema.IndexOf(":"));
ResourceIdentifier.Validate(resourceID, ResourceTypes.FeatureSource);
string req = m_reqBuilder.DescribeSchema(resourceID, schema);
try
{
return new FeatureSourceDescription(this.OpenRead(req));
}
catch (Exception ex)
{
try
{
if (this.IsSessionExpiredException(ex) && this.AutoRestartSession && this.RestartSession(false))
return this.DescribeFeatureSource(resourceID, schema);
}
catch
{
//Throw the original exception, not the secondary one
}
Exception ex2 = Utility.ThrowAsWebException(ex);
if (ex2 != ex)
throw ex2;
else
throw;
}
}
///
/// Creates a runtime map on the server
///
/// The target resource id for the runtime map
/// The mapdefinition to base the map on
public override void CreateRuntimeMap(string resourceID, string mapdefinition)
{
ResourceIdentifier.Validate(resourceID, ResourceTypes.RuntimeMap);
MapDefinition map = this.GetMapDefinition(mapdefinition);
CreateRuntimeMap(resourceID, map);
}
///
/// Creates a runtime map on the server
///
/// The target resource id for the runtime map
/// The mapdefinition to base the map on
public void CreateRuntimeMap(string resourceID, MapDefinition map)
{
ResourceIdentifier.Validate(resourceID, ResourceTypes.RuntimeMap);
RuntimeClasses.RuntimeMap m = new RuntimeClasses.RuntimeMap(map);
CreateRuntimeMap(resourceID, m);
}
///
/// Creates a runtime map on the server
///
/// The target resource id for the runtime map
/// The mapdefinition to base the map on
public void CreateRuntimeMap(string resourceID, RuntimeClasses.RuntimeMap map)
{
ResourceIdentifier.Validate(resourceID, ResourceTypes.RuntimeMap);
string selectionID = resourceID.Substring(0, resourceID.LastIndexOf(".")) + ".Selection";
SetResourceXmlData(resourceID, new System.IO.MemoryStream(System.Text.Encoding.UTF8.GetBytes(RUNTIMEMAP_XML)));
SetResourceXmlData(selectionID, new System.IO.MemoryStream(System.Text.Encoding.UTF8.GetBytes(RUNTIMEMAP_SELECTION_XML)));
System.IO.MemoryStream ms = new System.IO.MemoryStream();
BinarySerializer.MgBinarySerializer serializer = new BinarySerializer.MgBinarySerializer(ms, m_siteVersion);
RuntimeClasses.Selection sel = new RuntimeClasses.Selection();
sel.Serialize(serializer);
ms.Position = 0;
SetResourceData(selectionID, "RuntimeData", ResourceDataType.Stream, ms);
SaveRuntimeMap(resourceID, map);
}
///
/// Updates an existing runtime map
///
/// The target resource id for the runtime map
/// The runtime map to update with
public void SaveRuntimeMap(string resourceID, RuntimeClasses.RuntimeMap map)
{
ResourceIdentifier.Validate(resourceID, ResourceTypes.RuntimeMap);
if (!resourceID.StartsWith("Session:" + this.m_reqBuilder.SessionID + "//") || !resourceID.EndsWith(".Map"))
throw new Exception("Runtime maps must be in the current session repository");
if (map == null)
throw new ArgumentNullException("map");
System.IO.MemoryStream ms = new System.IO.MemoryStream();
System.IO.MemoryStream ms2 = null;
//Apparently the name is used to reconstruct the resourceId rather than pass it around
//inside the map server
string r = map.Name;
string t = map.ResourceID;
string mapname = resourceID.Substring(resourceID.IndexOf("//") + 2);
mapname = mapname.Substring(0, mapname.LastIndexOf("."));
map.Name = mapname;
map.ResourceID = resourceID;
try
{
map.Serialize(new BinarySerializer.MgBinarySerializer(ms, this.SiteVersion));
if (this.SiteVersion >= SiteVersions.GetVersion(KnownSiteVersions.MapGuideOS1_2))
{
ms2 = new System.IO.MemoryStream();
map.SerializeLayerData(new BinarySerializer.MgBinarySerializer(ms2, this.SiteVersion));
}
SetResourceData(resourceID, "RuntimeData", ResourceDataType.Stream, ms);
if (ms2 != null)
SetResourceData(resourceID, "LayerGroupData", ResourceDataType.Stream, ms2);
if (map.HasLoadedSelectionXml)
SetSelectionXml(resourceID, map.Selection.ToXml());
}
finally
{
map.Name = r;
map.ResourceID = t;
}
}
public void DeleteResourceData(string resourceID, string dataname)
{
string req = m_reqBuilder.DeleteResourceData(resourceID, dataname);
using (System.IO.Stream resp = this.OpenRead(req))
resp.ReadByte();
//Do nothing... there is no return value
}
public ResourceDataList EnumerateResourceData(string resourceID)
{
string req = m_reqBuilder.EnumerateResourceData(resourceID);
using (System.IO.Stream resp = this.OpenRead(req))
return (ResourceDataList)DeserializeObject(typeof(ResourceDataList), resp);
}
public override void DeleteResource(string resourceID)
{
string req = m_reqBuilder.DeleteResource(resourceID);
using (System.IO.Stream resp = this.OpenRead(req))
resp.ReadByte();
//Do nothing... there is no return value
}
public void DeleteFolder(string folderPath)
{
folderPath = FixAndValidateFolderPath(folderPath);
string req = m_reqBuilder.DeleteResource(folderPath);
using (System.IO.Stream resp = this.OpenRead(req))
resp.ReadByte();
//Do nothing... there is no return value
}
public RuntimeClasses.RuntimeMap GetRuntimeMap(string resourceID)
{
if (!resourceID.StartsWith("Session:" + this.m_reqBuilder.SessionID + "//") || !resourceID.EndsWith(".Map"))
throw new Exception("Runtime maps must be in the current session repository");
RuntimeClasses.RuntimeMap m = new RuntimeClasses.RuntimeMap();
m.Deserialize(new BinarySerializer.MgBinaryDeserializer(this.GetResourceData(resourceID, "RuntimeData"), this.SiteVersion));
if (this.SiteVersion >= SiteVersions.GetVersion(KnownSiteVersions.MapGuideOS1_2))
m.DeserializeLayerData(new BinarySerializer.MgBinaryDeserializer(this.GetResourceData(resourceID, "LayerGroupData"), this.SiteVersion));
m.CurrentConnection = this;
return m;
}
public override Version SiteVersion { get { return m_siteVersion; } }
private ICoordinateSystemCatalog m_coordsys = null;
//TODO: Figure out a strategy for cache invalidation
//TODO: Figure out if this can work with MapGuide EP 1.0 (just exclude it?)
public ICoordinateSystemCatalog CoordinateSystemCatalog
{
get
{
if (m_siteVersion < OSGeo.MapGuide.MaestroAPI.SiteVersions.GetVersion(OSGeo.MapGuide.MaestroAPI.KnownSiteVersions.MapGuideOS1_1))
return null;
else
{
if (m_coordsys == null)
m_coordsys = new HttpCoordinateSystemCatalog(this, m_reqBuilder);
return m_coordsys;
}
}
}
public System.IO.Stream ExecuteOperation(System.Collections.Specialized.NameValueCollection param)
{
return this.OpenRead(m_reqBuilder.BuildRequest(param));
}
// public void CreateFolder(string folderpath)
// {
// folderpath = FixAndValidateFolderPath(folderpath);
// System.IO.MemoryStream outStream = new System.IO.MemoryStream();
// System.Net.WebRequest req = m_reqBuilder.SetResource(folderpath, outStream, null, null);
// req.Credentials = m_wc.Credentials;
// outStream.Position = 0;
// using(System.IO.Stream rs = req.GetRequestStream())
// {
// Utility.CopyStream(outStream, rs);
// rs.Flush();
// }
// using (System.IO.Stream resp = req.GetResponse().GetResponseStream())
// {
// //Do nothing... there is no return value
// }
// }
///
/// Returns the Uri for the mapagent
///
public string ServerURI { get { return m_reqBuilder.HostURI; } }
///
/// Gets a string that can be used to identify the server by a user
///
public string DisplayName
{
get
{
string s = m_reqBuilder.HostURI;
if (s.ToLower().EndsWith("/mapagent/mapagent.fcgi"))
s = s.Substring(0, s.Length - "/mapagent/mapagent.fcgi".Length);
else if (s.ToLower().EndsWith("/mapagent/mapagent.exe"))
s = s.Substring(0, s.Length - "/mapagent/mapagent.exe".Length);
/*if (m_wc.Credentials as NetworkCredential != null)
s += " [" + (m_wc.Credentials as NetworkCredential).UserName + "]"; */
return s;
}
}
public override ResourceReferenceList EnumerateResourceReferences(string resourceid)
{
string req = m_reqBuilder.EnumerateResourceReferences(resourceid);
using (System.IO.Stream resp = this.OpenRead(req))
return (ResourceReferenceList)DeserializeObject(typeof(ResourceReferenceList), resp);
}
public override void CopyResource(string oldpath, string newpath, bool overwrite)
{
string req = m_reqBuilder.CopyResource(oldpath, newpath, overwrite);
using (System.IO.Stream resp = this.OpenRead(req))
resp.ReadByte();
//Do nothing... there is no return value
}
public override void CopyFolder(string oldpath, string newpath, bool overwrite)
{
oldpath = FixAndValidateFolderPath(oldpath);
newpath = FixAndValidateFolderPath(newpath);
string req = m_reqBuilder.CopyResource(oldpath, newpath, overwrite);
using (System.IO.Stream resp = this.OpenRead(req))
resp.ReadByte();
//Do nothing... there is no return value
}
public override void MoveResource(string oldpath, string newpath, bool overwrite)
{
string req = m_reqBuilder.MoveResource(oldpath, newpath, overwrite);
using (System.IO.Stream resp = this.OpenRead(req))
resp.ReadByte();
//Do nothing... there is no return value
}
public override void MoveFolder(string oldpath, string newpath, bool overwrite)
{
oldpath = FixAndValidateFolderPath(oldpath);
newpath = FixAndValidateFolderPath(newpath);
string req = m_reqBuilder.MoveResource(oldpath, newpath, overwrite);
using (System.IO.Stream resp = this.OpenRead(req))
resp.ReadByte();
//Do nothing... there is no return value
}
public override System.IO.Stream RenderRuntimeMap(string resourceId, double x, double y, double scale, int width, int height, int dpi, string format, bool clip)
{
ResourceIdentifier.Validate(resourceId, ResourceTypes.RuntimeMap);
string mapname = resourceId.Substring(resourceId.IndexOf("//") + 2);
mapname = mapname.Substring(0, mapname.LastIndexOf("."));
#if DEBUG
string s = m_reqBuilder.GetMapImageUrl(mapname, format, null, x, y, scale, dpi, width, height, clip, null, null, null, null);
return new System.IO.MemoryStream(this.DownloadData(s));
#else
System.IO.MemoryStream ms = new System.IO.MemoryStream();
System.Net.WebRequest req = m_reqBuilder.GetMapImage(mapname, format, null, x, y, scale, dpi, width, height, clip, null, null, null, null, ms);
//Maksim reported that the rendering times out frequently, so now we wait 5 minutes
req.Timeout = 5 * 60 * 1000;
using(System.IO.Stream rs = req.GetRequestStream())
{
Utility.CopyStream(ms, rs);
rs.Flush();
return req.GetResponse().GetResponseStream();
}
#endif
}
public override System.IO.Stream RenderRuntimeMap(string resourceId, double x1, double y1, double x2, double y2, int width, int height, int dpi, string format, bool clip)
{
ResourceIdentifier.Validate(resourceId, ResourceTypes.RuntimeMap);
string mapname = resourceId.Substring(resourceId.IndexOf("//") + 2);
mapname = mapname.Substring(0, mapname.LastIndexOf("."));
#if DEBUG
string s = m_reqBuilder.GetMapImageUrl(mapname, format, null, x1, y1, x2, y2, dpi, width, height, clip, null, null, null, null);
return new System.IO.MemoryStream(this.DownloadData(s));
#else
System.IO.MemoryStream ms = new System.IO.MemoryStream();
System.Net.WebRequest req = m_reqBuilder.GetMapImage(mapname, format, null, x1, y1, x2, y2, dpi, width, height, clip, null, null, null, null, ms);
//Maksim reported that the rendering times out frequently, so now we wait 5 minutes
req.Timeout = 5 * 60 * 1000;
using(System.IO.Stream rs = req.GetRequestStream())
{
Utility.CopyStream(ms, rs);
rs.Flush();
return req.GetResponse().GetResponseStream();
}
#endif
}
/* ///
/// Selects features from a runtime map, returning a selection Xml.
///
/// The map to query. NOT a resourceID, only the map name!
/// The WKT of the geometry to query with (always uses intersection)
/// True if the selection should be saved in the runtime map, false otherwise.
/// The selection Xml, or an empty string if there were no data.
public string QueryMapFeatures(string runtimemap, string wkt, bool persist)
{
return QueryMapFeatures(runtimemap, wkt, persist, QueryMapFeaturesLayerAttributes.Default, false);
}*/
///
/// Selects features from a runtime map, returning a selection Xml.
///
/// The map to query. NOT a resourceID, only the map name!
/// The WKT of the geometry to query with (always uses intersection)
/// True if the selection should be saved in the runtime map, false otherwise.
/// The type of layer to include in the query
/// True if the result should contain the tooltip and link info
/// The selection Xml, or an empty string if there were no data.
public override string QueryMapFeatures(string runtimemap, string wkt, bool persist, QueryMapFeaturesLayerAttributes attributes, bool raw)
{
//The request may execeed the url limit of the server, when large geometries
System.IO.MemoryStream ms = new System.IO.MemoryStream();
System.Net.WebRequest req = m_reqBuilder.QueryMapFeatures(runtimemap, persist, wkt, ms, attributes);
req.Timeout = 200 * 1000;
ms.Position = 0;
using(System.IO.Stream rs = req.GetRequestStream())
{
Utility.CopyStream(ms, rs);
rs.Flush();
}
System.Xml.XmlDocument doc = new System.Xml.XmlDocument();
#if DEBUG
System.IO.MemoryStream xms = new System.IO.MemoryStream();
Utility.CopyStream(req.GetResponse().GetResponseStream(), xms);
xms.Position = 0;
string f = System.Text.Encoding.UTF8.GetString(xms.ToArray());
if (raw)
return f;
xms.Position = 0;
doc.Load(xms);
#else
if (raw)
{
System.IO.MemoryStream xms = new System.IO.MemoryStream();
Utility.CopyStream(req.GetResponse().GetResponseStream(), xms);
return System.Text.Encoding.UTF8.GetString(xms.ToArray());
}
doc.Load(req.GetResponse().GetResponseStream());
#endif
if (doc.SelectSingleNode("FeatureInformation/FeatureSet") != null && doc["FeatureInformation"]["FeatureSet"].ChildNodes.Count > 0)
return "" + doc["FeatureInformation"]["FeatureSet"].InnerXml + "";
else
return "";
}
public override bool IsSessionExpiredException(Exception ex)
{
if (ex != null && ex.GetType() == typeof(System.Net.WebException))
{
System.Net.WebException wex = (System.Net.WebException)ex;
if (wex.Message.ToLower().IndexOf("session expired") >= 0 || wex.Message.ToLower().IndexOf("session not found") >= 0 || wex.Message.ToLower().IndexOf("mgsessionexpiredexception") >= 0)
return true;
}
return false;
}
///
/// Returns the avalible application templates on the server
///
/// The avalible application templates on the server
public override ApplicationDefinitionTemplateInfoSet GetApplicationTemplates()
{
//TODO: Caching these should be safe
return (ApplicationDefinitionTemplateInfoSet)base.DeserializeObject(typeof(ApplicationDefinitionTemplateInfoSet), this.OpenRead(m_reqBuilder.EnumerateApplicationTemplates()));
}
///
/// Returns the avalible application widgets on the server
///
/// The avalible application widgets on the server
public override ApplicationDefinitionWidgetInfoSet GetApplicationWidgets()
{
//TODO: Caching these should be safe
return (ApplicationDefinitionWidgetInfoSet)base.DeserializeObject(typeof(ApplicationDefinitionWidgetInfoSet), this.OpenRead(m_reqBuilder.EnumerateApplicationWidgets()));
}
///
/// Returns the avalible widget containers on the server
///
/// The avalible widget containers on the server
public override ApplicationDefinitionContainerInfoSet GetApplicationContainers()
{
//TODO: Caching these should be safe
return (ApplicationDefinitionContainerInfoSet)base.DeserializeObject(typeof(ApplicationDefinitionContainerInfoSet), this.OpenRead(m_reqBuilder.EnumerateApplicationContainers()));
}
///
/// Returns the spatial info for a given featuresource
///
/// The ID of the resource to query
/// Query only active items
/// A list of spatial contexts
public override FdoSpatialContextList GetSpatialContextInfo(string resourceID, bool activeOnly)
{
string req = m_reqBuilder.GetSpatialContextInfo(resourceID, activeOnly);
FdoSpatialContextList o = (FdoSpatialContextList)DeserializeObject(typeof(FdoSpatialContextList), this.OpenRead(req));
return o;
}
///
/// 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
public override string[] GetIdentityProperties(string resourceID, string classname)
{
string[] parts = classname.Split(':');
string req;
if (parts.Length == 2)
req = m_reqBuilder.GetIdentityProperties(resourceID, parts[0], parts[1]);
else if (parts.Length == 1)
req = m_reqBuilder.GetIdentityProperties(resourceID, null, parts[0]);
else
throw new Exception("Unable to parse classname into class and schema: " + classname);
XmlDocument doc = new XmlDocument();
doc.Load(this.OpenRead(req));
XmlNodeList lst = doc.SelectNodes("/PropertyDefinitions/PropertyDefinition/Name");
string[] ids = new string[lst.Count];
for(int i = 0; i < lst.Count; i++)
ids[i] = lst[i].InnerText;
return ids;
}
///
/// 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
public override bool RestartSession(bool throwException)
{
if (m_username == null || m_password == null)
if (throwException)
throw new Exception("Cannot recreate session, because connection was not opened with username and password");
else
return false;
Uri hosturl = new Uri(m_reqBuilder.HostURI);
string locale = m_reqBuilder.Locale;
try
{
RequestBuilder reqb = new RequestBuilder(hosturl, locale);
WebClient wc = new WebClient();
wc.Credentials = new NetworkCredential(m_username, m_password);
string req = reqb.CreateSession();
try
{
reqb.SessionID = System.Text.Encoding.Default.GetString(wc.DownloadData(req));
if (reqb.SessionID.IndexOf("<") >= 0)
throw new Exception("Invalid server token recieved: " + reqb.SessionID);
}
catch (Exception ex)
{
reqb.SessionID = null;
bool ok = false;
try
{
//Retry, and append missing path, if applicable
if (!hosturl.ToString().EndsWith("/mapagent/mapagent.fcgi"))
{
string tmp = hosturl.ToString();
if (!tmp.EndsWith("/"))
tmp += "/";
hosturl = new Uri(tmp + "mapagent/mapagent.fcgi");
reqb = new RequestBuilder(hosturl, locale);
req = reqb.CreateSession();
reqb.SessionID = System.Text.Encoding.Default.GetString(wc.DownloadData(req));
if (reqb.SessionID.IndexOf("<") >= 0)
throw new Exception("Invalid server token recieved: " + reqb.SessionID);
ok = true;
}
}
catch {}
if (!ok)
{
if (throwException) //Report original error
throw new Exception("Failed to connect, perhaps session is expired?\nExtended error info: " + ex.Message, ex);
else
return false;
}
}
//Reset cached items
m_siteVersion = new Version(((SiteVersion)DeserializeObject(typeof(SiteVersion), wc.OpenRead(reqb.GetSiteVersion()))).Version);
m_featureProviders = null;
m_cachedProviderCapabilities = null;
m_reqBuilder = reqb;
//This ensures we do not hit the connection limit in .Net
try { m_wc.Dispose(); }
catch { }
m_wc = wc;
return true;
}
catch
{
if (throwException)
throw;
else
return false;
}
}
///
/// Downloads data as a byte array. Wrapper function that automatically recreates the session if it has expired.
///
/// The request URI
/// The data at the given location
protected byte[] DownloadData(string req)
{
string prev_session = m_reqBuilder.SessionID;
try
{
return m_wc.DownloadData(req);
}
catch (Exception ex)
{
if (!this.m_autoRestartSession || !this.IsSessionExpiredException(ex) || !this.RestartSession(false))
{
Exception ex2 = Utility.ThrowAsWebException(ex);
if (ex2 != ex)
throw ex2;
else
throw;
}
else
//Do not try more than once
return m_wc.DownloadData(req.Replace(prev_session, m_reqBuilder.SessionID));
}
}
///
/// Opens a stream for reading. Wrapper function that automatically recreates the session if it has expired.
///
/// The request URI
/// The data at the given location
protected System.IO.Stream OpenRead(string req)
{
string prev_session = m_reqBuilder.SessionID;
try
{
return m_wc.OpenRead(req);
}
catch (Exception ex)
{
if (!this.m_autoRestartSession || !this.IsSessionExpiredException(ex) || !this.RestartSession(false))
{
Exception ex2 = Utility.ThrowAsWebException(ex);
if (ex2 != ex)
throw ex2;
else
throw;
}
else
//Do not try more than once
return m_wc.OpenRead(req.Replace(prev_session, m_reqBuilder.SessionID));
}
}
///
/// Sets the selection of a map
///
/// The resourceID of the runtime map
/// The selection xml
public override void SetSelectionXml(string runtimeMap, string selectionXml)
{
ResourceIdentifier.Validate(runtimeMap, ResourceTypes.RuntimeMap);
string selectionID = runtimeMap.Substring(0, runtimeMap.LastIndexOf(".")) + ".Selection";
//Assumes the runtime map is created, and has the selection resource
//SetResourceXmlData(selectionID, new System.IO.MemoryStream(System.Text.Encoding.UTF8.GetBytes(RUNTIMEMAP_SELECTION_XML)));
System.IO.MemoryStream ms = new System.IO.MemoryStream();
BinarySerializer.MgBinarySerializer serializer = new BinarySerializer.MgBinarySerializer(ms, m_siteVersion);
RuntimeClasses.Selection sel = new RuntimeClasses.Selection(selectionXml);
sel.Serialize(serializer);
ms.Position = 0;
SetResourceData(selectionID, "RuntimeData", ResourceDataType.Stream, ms);
}
///
/// Gets the selection from a map
///
/// The resourceID of the runtime map
/// The selection xml
public override string GetSelectionXml(string runtimeMap)
{
ResourceIdentifier.Validate(runtimeMap, ResourceTypes.RuntimeMap);
string selectionID = runtimeMap.Substring(0, runtimeMap.LastIndexOf(".")) + ".Selection";
System.IO.MemoryStream ms = GetResourceData(selectionID, "RuntimeData");
BinarySerializer.MgBinaryDeserializer deserializer = new BinarySerializer.MgBinaryDeserializer(ms, m_siteVersion);
RuntimeClasses.Selection sel = new RuntimeClasses.Selection();
sel.Deserialize(deserializer);
return sel.SelectionXml;
}
///
/// 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
public override UnmanagedDataList EnumerateUnmanagedData(string startpath, string filter, bool recursive, UnmanagedDataTypes type)
{
string req = m_reqBuilder.EnumerateUnmanagedData(startpath, filter, recursive, type);
System.IO.MemoryStream ms = new System.IO.MemoryStream();
using(System.IO.Stream s = this.OpenRead(req))
Utility.CopyStream(s, ms);
ms.Position = 0;
return (UnmanagedDataList)DeserializeObject(typeof(UnmanagedDataList), ms);
}
///
/// Gets the base url, ea.: http://localhost/mapguide/
///
public string BaseURL
{
get
{
string baseurl = this.ServerURI;
if (baseurl.ToLower().EndsWith("/mapagent.fcgi"))
baseurl = baseurl.Substring(0, baseurl.Length - "mapagent.fcgi".Length);
if (baseurl.ToLower().EndsWith("/mapagent/"))
baseurl = baseurl.Substring(0, baseurl.Length - "mapagent/".Length);
else if (baseurl.ToLower().EndsWith("/mapagent"))
baseurl = baseurl.Substring(0, baseurl.Length - "mapagent".Length);
return baseurl;
}
}
///
/// Renders a minature bitmap of the layers style
///
/// The scale for the bitmap to match
/// The layer the image should represent
/// If the layer is themed, this gives the theme index, otherwise set to 0
/// The geometry type, 1 for point, 2 for line, 3 for area, 4 for composite
/// The minature bitmap
public override System.Drawing.Image GetLegendImage(double scale, string layerdefinition, int themeIndex, int type)
{
string param = m_reqBuilder.GetLegendImage(scale, layerdefinition, themeIndex, type);
return new System.Drawing.Bitmap(this.OpenRead(param));
}
///
/// Upload a MapGuide Package file to the server
///
/// Name of the file to upload
/// A callback argument used to display progress. May be null.
public override void UploadPackage(string filename, Utility.StreamCopyProgressDelegate callback)
{
try
{
using (System.IO.FileStream fs = new System.IO.FileStream(filename, System.IO.FileMode.Open, System.IO.FileAccess.Read, System.IO.FileShare.Read))
{
System.Net.WebRequest req = m_reqBuilder.ApplyPackage(fs, callback);
req.Credentials = m_wc.Credentials;
req.GetRequestStream().Flush();
req.GetRequestStream().Close();
byte[] buf = new byte[1];
System.IO.Stream s = req.GetResponse().GetResponseStream();
s.Read(buf, 0, 1);
s.Close();
}
}
catch (Exception ex)
{
Exception ex2 = Utility.ThrowAsWebException(ex);
if (ex2 != ex)
throw ex2;
else
throw;
}
}
public override void UpdateRepository(string resourceId, ResourceFolderHeaderType header)
{
try
{
System.Net.WebRequest req = m_reqBuilder.UpdateRepository(resourceId, this.SerializeObject(header));
req.Credentials = m_wc.Credentials;
req.GetRequestStream().Flush();
req.GetRequestStream().Close();
byte[] buf = new byte[1];
System.IO.Stream s = req.GetResponse().GetResponseStream();
s.Read(buf, 0, 1);
s.Close();
}
catch (Exception ex)
{
Exception ex2 = Utility.ThrowAsWebException(ex);
if (ex2 != ex)
throw ex2;
else
throw;
}
}
public override object GetFolderOrResourceHeader(string resourceID)
{
string req = m_reqBuilder.GetResourceHeader(resourceID);
using(System.IO.Stream s = this.OpenRead(req))
if (ResourceIdentifier.IsFolderResource(resourceID))
return this.DeserializeObject(s);
else
return this.DeserializeObject(s);
}
///
/// Gets a list of users in a group
///
/// The group to retrieve the users from
/// The list of users
public override UserList EnumerateUsers(string group)
{
if (m_cachedUserList == null)
{
string req = m_reqBuilder.EnumerateUsers(group);
using (System.IO.Stream s = this.OpenRead(req))
m_cachedUserList = this.DeserializeObject(s);
}
return m_cachedUserList;
}
///
/// Gets a list of all groups on the server
///
/// The list of groups
public override GroupList EnumerateGroups()
{
if (m_cachedGroupList == null)
{
string req = m_reqBuilder.EnumerateGroups();
using (System.IO.Stream s = this.OpenRead(req))
m_cachedGroupList = this.DeserializeObject(s);
}
return m_cachedGroupList;
}
public override bool ResourceExists(string resourceid)
{
try
{
string req = m_reqBuilder.ResourceExists(resourceid);
using (System.IO.Stream s = this.OpenRead(req))
using (System.IO.StreamReader sr = new System.IO.StreamReader(s))
return sr.ReadToEnd().Trim().Equals("true", StringComparison.InvariantCultureIgnoreCase);
}
catch (Exception ex)
{
try { return base.ResourceExists(resourceid); }
catch { throw ex; } //Throw original error
}
}
public string[] GetConnectionPropertyValues(string providerName, string propertyName, string partialConnectionString)
{
string req = m_reqBuilder.GetConnectionPropertyValues(providerName, propertyName, partialConnectionString);
using (System.IO.Stream s = this.OpenRead(req))
{
StringCollection strc = this.DeserializeObject(s);
return strc.Item.ToArray();
}
}
#region IDisposable Members
public override void Dispose()
{
if (m_featureProviders != null)
m_featureProviders = null;
if (m_cachedProviderCapabilities != null)
m_cachedProviderCapabilities = null;
if (m_wc != null)
{
try { m_wc.Dispose(); }
catch { }
m_wc = null;
}
}
#endregion
public override System.IO.Stream GetTile(string mapdefinition, string baselayergroup, int col, int row, int scaleindex, string format)
{
string req = string.Empty;
if (mAnonymousUser)
req = m_reqBuilder.GetTileAnonymous(mapdefinition, baselayergroup, row, col, scaleindex, format);
else
req = m_reqBuilder.GetTile(mapdefinition, baselayergroup, row, col, scaleindex, format, m_wc.Credentials == null);
return this.OpenRead(req);
}
///
/// Gets or sets the agent reported to MapGuide.
/// Free form text, will appear in the log files.
/// Default is MapGuide Maestro API
///
public string UserAgent
{
get { return m_reqBuilder.UserAgent; }
set { m_reqBuilder.UserAgent = value; }
}
public bool SupportsResourcePreviews
{
get { return true; }
}
}
}