Archive for the ‘ArcIMS’ Category

ArcGIS Server Virtual Earth Tile Server vs. ArcIMS

February 4, 2008

Time to change the name Dave.

     

using System;
using System.Text;
using ArcDeveloper.TileServer.Interfaces;
using System.Net;
using System.IO;
using System.Xml;
using System.Drawing;
using System.Drawing.Imaging;   

namespace ArcDeveloper.TileServer.ArcIMS
{
    public class ArcImsTileProvider : ITileProvider
    {
        ///
        /// Private member containing the web service url
        ///
        private string _webServiceUrl = "";   

        ///
        /// Constructor that takes a web service Url
        ///
        ///
        public ArcImsTileProvider(string webServiceUrl)
        {
            _webServiceUrl = webServiceUrl;
        }   

        ///
        /// Get the tile image
        ///
        ///
        ///
        ///
        /// Tile data stream
        public System.IO.MemoryStream GetTile(ITileExtent extent, int tileHeight, int tileWidth)
        {
            MemoryStream returnStream = null;   

            try
            {
                string axl = getAXL(extent, tileHeight, tileWidth);
                Stream responseStream = PostData(_webServiceUrl, axl);
                XmlDocument xd = new XmlDocument();
                xd.Load(responseStream);
                string imgURL = xd.GetElementsByTagName("OUTPUT")[0].Attributes["url"].Value;
                responseStream.Close();   

                Bitmap bm = new Bitmap(new WebClient().OpenRead(imgURL));
                returnStream = new MemoryStream();
                bm.Save(returnStream, ImageFormat.Png);
            }
            catch(Exception e)
            {
                Bitmap bm = GetMessageTile(e.Message);
                returnStream = new MemoryStream();
                bm.Save(returnStream, ImageFormat.Png);
            }   

            return returnStream;
        }   

        ///
        /// Gets the ArcIMS GetImage AXL request.
        ///
        ///
        ///
        ///
        /// GetImage ArcIMS AXL request
        private string getAXL(ITileExtent extent, int tileHeight, int tileWidth)
        {
            StringBuilder sb = new StringBuilder();
            sb.Append("<?xml version=\"1.0\" encoding=\"UTF-8\" ?>");
            sb.Append("<ARCXML version=\"1.1\">");
            sb.Append("<REQUEST>");
            sb.Append("<GET_IMAGE>");
            sb.Append("<PROPERTIES>");
            sb.Append("<ENVELOPE minx=\"" + extent.lon2 + "\" miny=\"" + extent.lat2 + "\" maxx=\"" + extent.lon + "\" maxy=\"" + extent.lat + "\" />");
            sb.Append("<IMAGESIZE height=\"" + tileHeight + "\" width=\"" + tileWidth + "\" />");
            sb.Append("</PROPERTIES>");
            sb.Append("</GET_IMAGE>");
            sb.Append("</REQUEST>");
            sb.Append("</ARCXML>");
            return sb.ToString();
        }   

        ///
        /// Gets a tile with an error message burned into it.
        ///
        /// The message.
        /// An error message PNG
        private Bitmap GetMessageTile(string message)
        {
            Bitmap tile = new Bitmap(Properties.Resources.blankTile);
            Graphics graphics = Graphics.FromImage(tile);
            Font drawFont = new Font("Arial", 12);
            SolidBrush drawBrush = new SolidBrush(System.Drawing.Color.Black);
            SizeF len = graphics.MeasureString(message, drawFont);
            graphics.DrawString(message, drawFont, drawBrush, new PointF(10, 10));
            graphics.Dispose();
            return tile;
        }   

        ///
        /// Does an HTTP Post, returning a stream.
        ///
        /// The URL to post to
        /// The data to post
        /// The Http response stream
        private Stream PostData(string sURL, string postData)
        {
            HttpWebRequest webReq = null;
            HttpWebResponse response = null;
            Stream requestStream = null;
            StreamWriter writer = null;
            Stream responseStream = null;
            try
            {
                webReq = (HttpWebRequest)WebRequest.Create(sURL);
                webReq.Method = "POST";
                webReq.ContentType = "application/x-www-form-urlencoded";
                webReq.Timeout = 0xea60;
                webReq.AllowAutoRedirect = true;
                requestStream = webReq.GetRequestStream();
                writer = new StreamWriter(requestStream);
                writer.Write(postData);
                writer.Flush();
                writer.Close();
                requestStream.Close();
                response = (HttpWebResponse)webReq.GetResponse();
                responseStream = ((HttpWebResponse)webReq.GetResponse()).GetResponseStream();
            }
            finally
            {
                if (writer != null) writer.Close();
            }
            return responseStream;
        }   

    }
}   

Winners: Python-fearing .NET folks still using ArcIMS.  All six of you!

Losers: “ArcGIS Server Virtual Earth Tile Server” as a name.  Die.

JSON vs. Flash for Distributed Mapping

June 5, 2007

A few years ago I wrote a “Flash connector” for the ArcIMS HTML Viewer.  This “connector” took advantage of Flash’s security sandbox model, which allows cross-domain data connections under special, protected circumstances.  The point was to allow ArcIMS to get around JavaScript’s “same-domain policy” limitation — to allow distributed web-map calls without a proxy. 

Really the point was to put an ArcIMS HTML viewer on my HTML-only web-resume host, but I digress.

 In the browser, ArcIMS’s JavaScript and Flash communicated via Flash’s “External Interface” methods.  ArcIMS could post ArcXML to and from other domains.  Flash’s security model requires a “crossdomain.xml” be published on the remote-domain.  Jan Bliki’s excellent Flash + ArcIMS work at the EEA offered both the ArcIMS backend and “crossdomain.xml” to test all of this against.

The whole point, again, was to get around JavaScript’s ”same-domain policy” limitation.  Fast forward to 2007 where JSON is commonplace.  One accepted JSON paradigm is On-Demand Javascript – a special case where JSON-encoded data may be accessed across domain boundaries.  Essentially, an HTML <script> tag may be dynamically generated in the DOM, thus loading the JSON data.  There is some debate whether this is a feature, or a bug

For a moment, I considered rewriting my “Flash connector” as a “JSON connector”.  However, the lack of domain restrictions on DOM-based JSON requests does not apply to XmlHttpRequest JSON requests.  This means that JSON data may only be loaded via an HTTP “GET”; you can “POST” information to remote domains.  Hence, Javascript still cannot POST data to remote domains.

Overall?  If you’re not interested in proxying, 2-3 year old Flash technology is still better than JavaScript.  Why?  The security model.  Microsoft has been hinting at giving Silverlight a permissive cross-domain policy.  I suggest they do so.

Let me know in the comments if there is any interest in me posting a “Flash-connector” walk-through.

ArcIMS Emulator

April 24, 2007

Paul Ramsey at Refractions Research has a very interesting little gem called ArcIMS Emulator.

 The basic idea is to allow the impersonation of ArcIMS Image and Feature services by Mapserver.  Much of the gusto here is the cleanest effective documentation of ArcIMS’s binary secret-handshakes.

But why would anyone want to emulate ArcIMS now that ESRI supports WMS services? 

You could say because Mapserver is free, open-source, faster than ArcIMS, and reasonably easier to get improvements / fixes on (“ArcIMS has been moved from an active development effort to a maintenance project”).

I’ll focus on another issues: ArcMap does not support WFS nor authenticated WMS.  New in ArcMap 9.2 is the ability to connect to a secure data service via HTTPS.  Combine secure transport with authentication and you have ESRI’s first usable, secure data-delivery mechanism to ArcMap.

 I’ve previously written how ArcIMS has a rather lame integration of Access Control Lists, and how you can easily route traffic through an authentication proxy.  If you have to proxy ArcIMS to get meaningful authentication anyway, why not proxy Mapserver/WMS/WFS instead? 

 ArcIMS Emulator is 120kb of Perl… I bet you’ll see a 120kb of C# coming soon.  Sean Gillies has already ported it to Python, although “PyIMS”seems to have passed away.  Anybody else interested in seeing secure, open-source data delivery to ArcMap with robust, integrated authentication?

Authenticate ArcIMS Traffic Via an ASP.Net Proxy

April 6, 2007

ArcIMS makes an interesting datasource for ArcMap clients, but I have a hard time liking its login options. That is, it just really doesn’t integrate well with — oh — just about any existing security system.

This is a little mockup showing how you can proxy ArcIMS traffic through an ASP.Net HttpHandler. Moreover, this shows how to force ArcMap clients to authenticate.

I’ve removed much of the guts, but it works. Please forgive the screwy code styling. I’m still learning this blogging thing.

Basic Setup

Create a virtual directory “servlet” as an IIS application, and add the below files there.
Enable basic authentication, but keep anonymous access on.
Add a mapping for “.Esrimap” to .NET’s “aspnet_isapi.dll” handler.


WEB.CONFIG


<?xml version="1.0"?>

<configuration xmlns="http://schemas.microsoft.com/.NetConfiguration/v2.0"><

appSettings><add key="RemoteWebSite" value="10.147.156.69:8080"/></appSettings> 

<system.web>  

<compilation defaultLanguage="c#" />   

<authentication mode="Windows"/>  

<httpHandlers> <add verb="*" path="com.esri.esrimap.Esrimap" type="Proxy, App_Code"/> </httpHandlers>  

</system.web>  

</configuration>



PROXY.CS

using System;
using System.Configuration;using System.Web;
using System.Net;using System.Text;
using System.IO; /// <summary>/// Web Proxy for ArcIMS traffic that employs ASP.NET Authentication mechanisms
/// </summary>public class Proxy : IHttpHandler
{
public void ProcessRequest(HttpContext context){ // Grab our real ArcIMS server's information from the web.config filestring remoteWebSite = ConfigurationManager.AppSettings["RemoteWebSite"];string remoteUrl = "http://" + remoteWebSite + context.Request.RawUrl; 
// Convince ArcMap clients to send credentials
if (!context.Request.IsAuthenticated && context.Request.QueryString.ToString() != "cmd=ping"){context.Response.Status = "401 Unauthorized";context.Response.Write("<?xml version=\"1.0\"?>n<ARCXML><RESPONSE><ERROR>You are not authorized to access this ArcIMS Service.</ERROR></RESPONSE>n</ARCXML>");context.Response.End();
  

return;}   

// Create a web connection to the real ArcIMS server  

HttpWebRequest request = (HttpWebRequest)WebRequest.Create(remoteUrl);request.Method = context.Request.HttpMethod;   

// Post any ArcXML to the real ArcIMS server  

if (context.Request.HttpMethod == "POST"){Stream sendStream = request.GetRequestStream();byte[] buff2 = new byte[1024];
  

int bytes2 = 0;while ((bytes2 = context.Request.InputStream.Read(buff2, 0, 1024)) > 0){sendStream.Write(buff2, 0, bytes2);  

}  

sendStream.Close();  

}  

// Recieve an ArcXML response from the real ArcIMS server  

HttpWebResponse response = (HttpWebResponse)request.GetResponse();Stream receiveStream = response.GetResponseStream();byte[] buff = new byte[1024];int bytes = 0;
  

while ((bytes = receiveStream.Read(buff, 0, 1024)) > 0){context.Response.OutputStream.Write(buff, 0, bytes);  

}  

response.Close();  

context.Response.End();  

}  

public bool IsReusable{get  

{
return true;}}  

}

PsService Batch Files for ArcIMS Administration

March 27, 2007

Dave Bouwman had a post on using the “NET” command for service administration.  Hats off to Dave, but PsService fits much better into my workflow.

Check out http://www.microsoft.com/technet/sysinternals/ProcessesAndThreads/PsService.mspx

Now check out the code below, half stolen, half rewritten:

@echo off

echo **************************************
echo Stopping IMS Services
echo **************************************

psservice \\10.147.156.69 STOP “ArcIMS Tasker 9.2.0″

psservice \\10.147.156.69 STOP “ArcIMS Monitor 9.2.0″

psservice \\10.147.156.69 STOP “ArcIMS Application Server 9.2.0″

pause

cls
echo ***************************
echo Restarting IMS Services
echo ***************************
psservice \\10.147.156.69 start “ArcIMS Application Server 9.2.0″

psservice \\10.147.156.69 start “ArcIMS Monitor 9.2.0″

psservice \\10.147.156.69 start “ArcIMS Tasker 9.2.0″

pause