jump to navigation

Continuous Integration with Flex, Hudson, and ArcGIS Server-Part V December 11, 2009

Posted by ruprict in Continuous Integration, Flex.
add a comment

(Part 1, Part 2, Part 3,Part 3, Part 4)

In what I hope is the last post in this particular series, we will get Hudson up, building our project and running our tests. Let’s get to it.

Get Hudson

Download Hudson from here. This will download hudson.war, which is a java web archive. Oh, and I presume that you have a java SDK installed somewhere. If you don’t go to java.com and get one.

Start Hudson

Hudson is super easy to get up and running. I suggest you copy the hudson.war file to c:\hudson and open a command prompt to that directory. Type:

java -jar hudson.war

This will start the Hudson service on port 8080. If you have anything already running on this port (I did) you need to shut it down or pass the –httpPort= to the command with the port you wish to use.

Talk to Hudson

Open up a browser to http://localhost:8080 and you’ll see this:
Hudson Dashboard

We need to create a job for our Flex project. Click New Job put in a job name (I am using “AGSFlexBuild”) and select “Build a free-style software project” and Click OK. This will bring up the main configuration of the build. The first item we will set up is the Subversion repository. The high-level process that Hudson will follow is:

  1. Poll Subversion for changes
  2. When a change is detected, run an SVN updte to get the latest version
  3. Build the project
  4. On a successful build, run the tests

So, the first thing we should do is setup our Subversion repository information.

Hudson SVN

Put your repository URL in as shown in the above image. In the “Build Triggers” section select “Poll SCM” and put “* * * * *” in the “Schedule” text box. This will cause Hudson to poll SVN every minute.

Now we have to add the build step. Since we have already set up our ant build script, this part is easy. Click “Add Build Step” and select “Invoke Ant”, then fill out the text box as shown here:
Hudson Build Step

At this point if we ran the build from Hudson, we’d get an error complaining about ${deploy_dir}. The reason for this is we don’t have a local.properties file on the server (remember when we did that?). There are several possible solutions to this issue.

  • Create a ci.properties file, check it in to SVN, and pass a parameter to the build step in Hudson.
  • Create an ant task that copies the local.properties.template file to local.properties, then add a build step in Hudson that runs before the build-flex-project step.
  • Default the properties in the build.xml file.

The last option is the ickiest, but the first two are about the same, in my opinion. I took the second option, creating an ant task and adding it to my Hudson configuration.
Hudson Build Step 2
I leave the creation of the ant task as an exercise for the reader.

The final build step to be configured will run the tests. Add another build “Invoke Ant” build step that invokes the “test” ant task. At the bottom of the page, click the “Save” button. This will take you to the AGSFlexBuild Project page.

Run the build

Click “Build Now” on the left hand side of the page and the build will be scheduled. The build should run successfully. Click on the hyperlink with the build date and time, which will take you to the details of the build. If you click on “Console Output”, the entire build log is displayed. When things go awry in the build, you’ll likely go here first.

A continuous integration process is incomplete without some kind of notification when the build fails. There are a couple of options for notification: e-mail, CCTray, or twitter, just to name a few. E-mail is available in the base Hudson package (see Manage Hudson, Configure System, put in SMTP information). CCTray allegedly works, but I don’t use it and can’t find it. Twitter is available as a Hudson plugin.

Speaking of plugins, there are TONS of them. Twitter, Git, Windows Authentication, etc. You can find them in the Hudson configration pages of the site. I reccommend you look through them and find what you need.  Finally, it’s super easy to get Hudson running as a Windows service, as there is a “Install as Windows Service” option in the Manage Hudson configuration area.

It’s difficult to find a stopping place when discussing Hudson, so if you have questions, send me an e-mail or leave a comment. The code for this series can be found on github (you could fork it and test using Hudson with git, just for fun…. ;) ) I hope someone found this series useful.

Continuous Integration with Flex, Hudson, and ArcGIS Server, Part IV September 30, 2009

Posted by ruprict in ArcDeveloper, Continuous Integration, Flex.
Tags: ,
add a comment

(Part 1, Part 2, Part 3)

(Note:  I have started moving our builds to rake, the Ruby build DSL.  It is, howyousay, fantastic.  I see more posts in our series….)

Now that the school year has begun, I can get back into this series.  Last we left, we had ant running the build and the scripts.  Now it’s time to make the build portable, which means that our build.properties file needs to well, go away.  All this really means is taking build.properties and copying it to build.properties.template.  Then deleting build.properties out of source control.  Anyone getting our build our of source control will have to create a local build.properties file, complete with all the settings that make the build go.  This is a “best practice” and stops developers from overwriting each others’ properties when they check in the build file.

So, do that.  Rename build.properties to build.properties.template.  If you ant build-all now, the build throws an error, something about ${wrapper.dir} not found.  That’s because the build couldn’t pull in the properties file.  Copying build.properties.template to build.properties fixes the build.  However, we aren’t done with the renaming.  I want to introduce the concept of build environments to my build.  That way, I can have different properties files for named environments.  I may want to set up different SDK builds, etc. as well, and environments will help me do that.  All I need to do is add a property to the top of the build.xml file to hold my environment name.  It looks like:

<property name="env" value="local"/>

This means that, by default, I’ll be running in the local environment.  This also means that build.properties.template becomes local.properties.template.  Now, I have to copy local.properties.template to local.properties to get the build going.  Another change to the build.xml file is to the line that pulls in our properties file.  It changes from:

<property file='build.properties'/>
to
<property file='${env}.properties'/>

The cool thing is that I can add another file called (for example) 34SDK.properties that points to the Flex 3.4 SDK.  Then to run that build, I can write:

ant build-all -Denv=34SDK

and it will overwrite our env variable and look for a 34SDK.properties file.  Flexibility is fun.

The SCMelephant in the Room

Up to this point, I have committed a cardinal sin.  No source control.  I know, bad developer.   However, I want to get the directory structure set up in a more CI friendly manner before I involve an SCM, so there is a method to the madness.  Let’s do that now.  There are roughly 1, 233, 443 articles on a developer’s workspace or CI directory structure.  I am going to use one that I’ve borrowed (and slightly modified) from Vish.  He is smarter than me, so it must be the way to go.  Here is the structure, in pictures:

3479c0f09a281e0fc8655d29fcba313b

You can ignore the .metadata folder, as that is a Flex Builder thing and I won’t put it in source control.   The build folder will hold the output of our build, docs is self-explanatory, src is where our Flex Builder project lives, and tools holds stuff we need to run the build.  In this case, we need the FluintAirTestRunner.exe, which I’ll copy into my tools dir.  The build file lives in the root of our project space, which means it has moved up relative to the Flex Builder project.  We need to change some things in the build.properties file to get our build going again.

#Copy this file locally to local.properties and change below for your env

# change this to your Flex SDK directory path
FLEX_HOME=C:/Program Files (x86)/Adobe/Flex Builder 3/sdks/3.2.0

# this points to your project's src directory
# {$basedir} is a default variable that can be used in any Antscript
# and it points to the project's root folder [ flex_ant_pt1_Tasks ]
# in this case
srcpath.dir =${basedir}/src/FlexAGSCI/src

# points to the project's libs directory
libs.dir =${basedir}/src/FlexAGSCI/libs

# this is the folder we want to publish the swf to
deploypath.dir = ${basedir}/build

wrapper.dir=${basedir}/src/FlexAGSCI/html-template

version.major =0
version.minor=9
version.revision = 0
APP_TITLE = Flex Solution
APP_WIDTH = 100%
APP_HEIGHT =100%
locale = en_US
html.file=${deploypath.dir}/index.html
application.name=FlexAGSCI

#Fluint vars
fluint.dir = ${basedir}/tools/FluintAIRTestRunner
report.dir = ${deploypath.dir}/reports

Now, running ‘ant’ at the project space root builds the project, and running ant test builds the test module and runs the test.  We copy this file to local.properties.template, and we are ready to import this project into source control.

I found a couple of posts that show how to import an existing directory into Subversion and make that directory your working copy, which is snazzy. It’s all here.  If you know anything about svn, that is a pretty straightforward post.

That’s that.  We are now ready for Hudson.  in the next post, we’ll get Hudson up, running, building our stuff, and running our test.

Continuous Integration with Flex, Hudson, and ArcGIS Server, Part 3 August 24, 2009

Posted by ruprict in Uncategorized.
6 comments

(Part 1Part 2Part 4)

One of the tenets of continuous integration is automated testing.  The most basic form of testing, in this context, is unit testing, where each class or method is tested without running the other bits of the application.  Unit testing is focused and, hopefully, simple.  In this post, I am going to add unit testing to our application and get ant to run the tests.  There are several unit testing frameworks out there, and we’re going to use Fluint. Fluint and FlexUnit have kinda merged into FlexUnit4, which is in alpha.  FlexUnit4 is, howyousay, super-fantastic, but it doesn’t currently offer any ant tasks.  When it does, I’ll be moving to it post haste.

Go get Fluint from here.  Put the fluint-1.1.1.swc file in the libs folder of your project.  We are now ready to start with some simple Test Driven Development.  Let’s add a button that zooms the map one level in, shall we?  As all examples, it’s contrived, but the point is to focus on the process.   The process here will follow simple TDD: write a test, watch it fail, write the code to make it pass.  In order to be able to watch the test fail, we’re need a bit of a foundation.  For the sake of this article, I have made a “tests” folder in the src directory where I will store the test bits.  Also, we will need a test runner for when we want to manually run our test suite.  That can be downloaded from here and copied to the src directory as well.  Once the runner (FlexTestRunner.mxml) is in the src dir, be sure to go into the project properties and add it to the list of Flex Applications for the project.  if you’ve done all that properly, then you will be able to run the FlexTestRunner application, which runs the Fluint test suites, by default.

image

We don’t want to run the framework tests, so remove all mentions of FrameworkSuite from the code in FlexTestRunner.mxml.  In Fluint, a test runner runs test suites and test suites are composed of test cases.  We will make our own test suite, called ZoomButtonTestSuite, and our own test case called (you guessed it) ZoomButtonTestCase.  These live in the aforementioned “tests” dir.

The test suite is simple:

package tests
{
    import net.digitalprimates.fluint.tests.TestSuite;
    public class ZoomButtonTestSuite extends TestSuite
    {
        public function ZoomButtonTestSuite()
        {
            addTestCase(new ZoomButtonTestCase());
        }

    }
}

All we do is pull in our test case, which looks like:

package tests
{
    import net.digitalprimates.fluint.tests.TestCase;

    public class ZoomButtonTestCase extends TestCase
    {
        public function ZoomButtonTestCase()
        {
            super();
        }
    }
}

Before we go on, go back to FlexTestRunner.mxml and add ZoomButtonTestSuite to the suiteArray in startTestProcess, so it looks like:

protected function startTestProcess( event:Event ) : void
{
    var suiteArray:Array = new Array();
    suiteArray.push( new ZoomButtonTestSuite() );

    testRunner.startTests( suiteArray );
}

We should be ready to right our first test.  For the ZoomButton, here are the specs:

  • When the user clicks the button, zoom the map in one level.

Pretty complicated, eh?  Here’s the test:

public function testZoomIn():void{
    var button:ZoomButton = new ZoomButton();
    var beforeLevel:uint= button.map.level;
    button.doZoom();

    assertTrue(button.map.level < beforeLevel);
}

I have started with the button API design, which is the real aim of our test.  Just from this test, you can see that:

  • The button is it’s own class.
  • The button has a property called map.
  • The button has a method called doZoom() (it has to be public for this example…not sure i like that)
  • The doZoom() method changes the map level.

This won’t even compile, so let’s get that happening.

package widgits
{
    import com.esri.ags.Map;
    import mx.controls.Button;

    public class ZoomButton extends Button
    {
        public var map:Map;
        public function ZoomButton()
        {
            super();
        }
        public function doZoom():void{

        }
    }
}

OK.  The ZoomButton extends the Button class, has a map property (setter/getter not used for brevity) and a doZoom() method.  Launch the test runner, and you’ll see:

image

About what we’d expect.  The button.map property is null.  However, I don’t want to create a full blown ESRI map for my tests.  It will be clunky and slow and difficult.  We need to fake the map.  This is where Mocks come in.

Mocking What We Don’t (need to) Understand

Just like unit testing frameworks, there are quite a few mocking frameworks in Flex land.  For this article, I am going to use MockAS3. (You have to build from source.  Or you can leave a comment with an e-mail and I’ll send you my copy).  Mock AS3 is nice, as it lets us mock a class and not just an interface.  ESRI does not implement an interface with its controls (like Map) for reasons that I don’t know, but I wish they would.  Also, this unit test is an interaction-based test, meaning we are going to set expectation of how we expect the ZoomButton and the map to interact, then verify those expectations as part of the test.  This is what mocking is, testing interactions and expectations presuming all dependent objects do what they are supposed to do.

So, what do we expect the ZoomButton to do in the doZoom() method?  We expect it to call map.zoomIn(), right?  Our first, naive test was testing properties on the map.  While this is testing a valid post-condition, it bleeds too far into testing the ESRI Map control and not the ZoomButton.  After all, the ZoomButton does not set the map level, it just calls a method on the map. If it does that, we are happy with our ZoomButton.  Any issues outside of it are not related to the ZoomButton and its purpose.  With this in mind, our new test looks like:

public function testZoomIn():void{
        var button:ZoomButton = new ZoomButton();
        var mapMock:MapMock = new MapMock();
        mapMock.mock.method('zoomIn').once;

        button.doZoom();

        mapMock.mock.verify();
}

The new test now creates a mock object for the ZoomButton.map property and tells it to expect the “zoomIn” method to be called one time.  We then test the doZoom method, followed by asking the mock to verify that our expectation was met.  Here is the mock:

package tests.mocks
{
    import com.anywebcam.mock.Mock;
    import com.esri.ags.Map;
    public class MapMock extends Map
    {
        public var mock:Mock;
        override public function MapMock()
        {
            mock = new Mock(this);
        }

        override public function zoomIn():void{
            mock.zoomIn();
        }

    }
}

This follows the pretty-good documentation on the Mock AS3 Google Code site for mocking classes.  We only need to mock the methods on which we are setting expectations.  Build and launch the test runner again.

image

Test still fails, but we get a new error:  Verifying Mock Failed. We haven’t coded our doZoom() method yet.

public function doZoom():void{
    if (map)
        map.zoomIn();
    else
        throw new Error("Map is not set");
}

Now, running the tests gives us sweet green….

image

Test Ant, Test Ant…

Now, we need to get these tests running with ant.  Luckily, Fluint ships with ant tasks (which are not available for FlexUnit4 at the time of this writing, but they assure me they are coming)  However, the ant tasks will not use the FlexTestRunner.mxml.  They use a different test runner with is Adobe AIR based, called (you guessed it) AirTestRunner, which you can download from here.  Double clicking on the .air files will launch the AIR installer.  Just follow all the prompts and it will install the FlexAirTestRunner to C:\Program Files\FluintAIRTestRunner.  In that directory you’ll see a .EXE file as well as a .SWF file, which is the actual test runner.  Another caveat to running the Fluint tests with ant is that the AIR test runner requires the use of Flex Modules.  What this means is that you have to create one or more Flex Modules for your tests, depending on how you want to structure the tests.  Basically, each module acts like a container for TestSuites that you want to run, then add the module to the ant task.  Enough talk.   A sample test module can be downloaded from the Fluint Google Code site, here or can be easily written.  A Fluint test module implements the ITestModule interface, which has a single method: getTestSuites().  Here is ours:

<?xml version="1.0" encoding="utf-8"?>
<mx:Module xmlns:mx="http://www.adobe.com/2006/mxml" implements="net.digitalprimates.fluint.modules.ITestSuiteModule">
    <mx:Script>
        <![CDATA[

            public function getTestSuites() : Array
            {
                 var suiteArray : Array = new Array();
                suiteArray.push( new ZoomButtonTestSuite());
                return suiteArray;
            }
        ]]>
    </mx:Script>
</mx:Module>

Looks a lot like the FlexTestRunner.mxml, huh?  The only thing we have left to do now is add a test target to our ant script.  As some of you might have guessed, we need to add the Fluint ant tasks to our build.xml file.  The easiest (read: not necessarily RIGHT) way to do this is copy them into the c:\ant\lib directory.  You can get the JAR file with the ant tasks here.   Once they are in the ant lib directory, add the following line to your build.xml (right under the flexTasks is a good spot)

<taskdef name='fluint' classname='net.digitalprimates.ant.tasks.fluint.Fluint'  />

There, now we can use our Fluint tasks in the ant file.  Since the tests are using Flex modules, we’ll want to have a couple of targets in the build script: one that builds the module, and one that executes the test.  Heres’ the target that builds the module:

<target name="build-test-module">
     <echo>Building test module</echo>
    <mxmlc file='${srcpath.dir}/tests/ZoomButtonTestModule.mxml'  target-player="10.0.0"
        output='${deploypath.dir}/tests/ZoomButtonTestModule.swf' >
         <load-config filename='${FLEX_HOME}/frameworks/flex-config.xml' />
         <source-path path-element='${FLEX_HOME}/frameworks'/>
         <!-- source paths -->
         <compiler.source-path path-element='${srcpath.dir}'/>
        <!-- add external libraries -->
        <include-libraries file='${libs.dir}' />
    </mxmlc>
</target>

If you go to the command line and type ‘ant build-test—module’, it will build the module and copy it to our bin-debug directory. Now, we just need to tell the Fluint task to go find that module and run the test.  Here’s the target:

<target name='test'>
    <fluint
       debug='true'
       headless='true'
       failOnError='true'
       workingDir='${fluint.dir}'
       testRunner='${fluint.dir}/FluintAIRTestRunner.exe'
       outputDir='${report.dir}'>

       <fileset dir='${deploypath.dir}/tests'>
          <include name='**/*TestModule.swf'/>
       </fileset>
    </fluint>
</target>

You may have noticed the two new build variables: fluint.dir and report.dir.  The Fluint task needs to know where the FluintAirTestRunner.exe file resides, which is the former.  The latter tells fluint where to write the report of how the tests faired.   I added this to the bottom of the build.properties file:

#Fluint vars
fluint.dir = C:/Program Files (x86)/FluintAIRTestRunner
report.dir = ${basedir}/reports

Now, running ‘ant test’ at the command line will run our test and generate the test report.  It’s an XML file that looks like:

<testsuites status="true" failureCount="0" errorCount="0" testCount="1">
  <testsuite name="tests.ZoomButtonTestCase" errors="0" failures="0" tests="1" time="0.237">
    <properties/>
    <testcase name="testZoomIn" time="0.237" className="tests.ZoomButtonTestCase"/>
  </testsuite>
</testsuites>

So, our ant file is now running our tests.  We are well on our way to continuous integration with Flex.  Coming up, we’ll need to get some of the hardcoding out of the build file, look at our project directory structure, format our test reports to be more readable, and bring Hudson into the mix.  We have a lot to do.

I hope you find this useful.

Continuous Integration with Flex, Hudson, and ArcGIS Server, Part 2 August 4, 2009

Posted by ruprict in Agile, Continuous Integration, Flex.
3 comments

(Part 1Part 3Part 4)

In the last post, I talked about the very basics of getting a Flex project going with Flex Builder and ant.  The current ant script we have just builds the SWF file, which leaves out a bunch of files that Flex Builder uses, and that is bad as defined by what I am trying to blog about here.  So, let’s get going on pulling over the rest of the files.  Well, at least, the important ones.  The most important one is likely the HTML file that wraps our SWF.  If we are going to deploy this SWF in any meaningful (read: web) manner, we need that HTML file.  Actually, we need one that we make ourselves and pull into our build process, but that will left as an assignment for the reader.  For the sake of this series, we’ll just reuse the HTML file that Flex Builder was kind enough to generate.

In the default Flex Builder project, one of the folders is html-template, that looks like:

image

Not much to it, really.  I am not gonna go into the meat of what the files are, if you want that go here.  In a nutshell, what we need to do here is copy this whole directory to our output folder (our ${deploy.dir} for you sharp ones following along).  There is a slight caveat here, tho, and that’s the contents of the index.template.html.  If you open that file in a text editor, you’ll see snippets like:

AC_FL_RunContent(
        "src", "playerProductInstall",
        "FlashVars", "MMredirectURL="+MMredirectURL+'&MMplayerType='+MMPlayerType+'&MMdoctitle='+MMdoctitle+"",
        "width", "${width}",
        "height", "${height}",
        "align", "middle",
        "id", "${application}",
        "quality", "high",
        "bgcolor", "${bgcolor}",
        "name", "${application}",
        "allowScriptAccess","sameDomain",
        "type", "application/x-shockwave-flash",
        "pluginspage", "http://www.adobe.com/go/getflashplayer"
    );

where you may notice the now familiar ${} variables.  So, now our simple copy has turned into a copy and replace all the ${} tokens with their appropriate values.  Nothing is ever as simple as it should be.

The good news is that it’s not so hard either.  Breaking down what we need to do, I think it looks something like this:

  1. Copy the html-template contents.
  2. Parse the index.template.html and replace the tokens.

Let’s create our ant task to get this done.  I’ll it create-html-wrapper, and it looks like this:

<target name='create-html-wrapper'>
    <copy todir='${deploypath.dir}' overwrite="true">
      <fileset dir='${wrapper.dir}'>
         <exclude name='**/index.template.html' />
     <exclude name='**/index.template.html.svntmp' />
         <exclude name='.svn' />
      </fileset>
</copy>

The copy ant task is a standard task from the ant library.  We are excluding some items here:  we don’t want any source control artifacts to end up in the deploy directory.  I am using subversion here, so I explicitly exclude those.  The one that may look odd is the exclusion of index.template.html.  The reason that file is excluded is because we want to rename it.  I don’t want my HTML file to be named index.template.html, do you?

(NOTE:  The Flex ant tasks include an html-wrapper task, but I found it lacking for reasons that now escape me.  I think the parsing of the HTML files was either not there or crappy.  Either way, I dumped it for some very valid reason, I am sure.)

For the index.template.html, we can use another cool ant ask that uses regular expressions to replace content within a file.  The name of that task is replaceregexp, and it’s dead sexy.  Here is the copy command, and it’s a bit of a doozy.  I am not gonna go through each token, as that would be REALLY boring (not super exciting like the rest of this post)

<!-- Copy and rename the index.template.html -->
<copy file='${wrapper.dir}/index.template.html'
tofile='${html.file}' />
<!-- Copy and rename the index.template.html --> <copy file='${wrapper.dir}/index.template.html' tofile='${html.file}' /> <replaceregexp file='${html.file}' flags='gs' match='\$\{width\}' replace='100%'/> <replaceregexp file='${html.file}' flags='gs' match='\$\{height\}' replace='100%'/> <replaceregexp file='${html.file}' flags='gs' match='\$\{title\}' replace='${APP_TITLE}' encoding='utf-8'/> <replaceregexp file='${html.file}' flags='gs' match='\$\{version_major\}' replace='${version.major}'/> <replaceregexp file='${html.file}' flags='gs' match='\$\{version_minor\}' replace='${version.minor}'/> <replaceregexp file='${html.file}' flags='gs' match='\$\{version_revision\}' replace='${version.revision}'/> <replaceregexp file='${html.file}' flags='gs' match='\$\{application\}' replace='${APP_TITLE}'/> <replaceregexp file='${html.file}' flags='gs' match='\$\{bgcolor\}' replace='#FFFFFF'/> <replaceregexp file='${html.file}' flags='gs' match='\$\{swf\}' replace='${application.name}'/>
(BTW, the replaceregexp stuff I blatantly stole from here, which is a GREAT post on using ant with Flex.  Also goes to show you that I am a couple of years behind the cool kids.)

Finally, let’s take another look at our build.properties file, which added quite a bit of properties for this task.

#Copy this file locally to build.properties and change below for your env

# change this to your Flex SDK directory path
FLEX_HOME=C:/Program Files (x86)/Adobe/Flex Builder 3/sdks/3.2.0

# this points to your project's src directory
# {$basedir} is a default variable that can be used in any Antscript
# and it points to the project's root folder [ flex_ant_pt1_Tasks ]
# in this case
srcpath.dir =${basedir}/src

# points to the project's libs directory
libs.dir =${basedir}/libs

# this is the folder we want to publish the swf to
deploypath.dir = ${basedir}/bin-debug

wrapper.dir=${basedir}/html-template

version.major =0
version.minor=9
version.revision = 0
APP_TITLE = Flex Solution
APP_WIDTH = 100%
APP_HEIGHT =100%
locale = en_US
html.file=${deploypath.dir}/index.html
application.name=FlexAGSCI

We have some of our HTML tokens, like width and height, a new directory (wrapper.dir) and the name of our HTML file.  For the ant build, I rename it to index.html because I plan on using ant to actually deploy the application to a web server and I want a default document name to be used.

So, next post will concentrate on adding a unit testing framework and getting ant to run our tests too.  I know the first couple of posts were mongo-basic, but I wanted to lay a bit of a foundation before getting into the cooler stuff.  We’ll get there.  I am about to head off on a mini-vacation, so it might be a week or more before I get to it.  I hope you can manage until then….

Oh, and here’s our build.xml, in full, just for fun:

<project name='Flex Ant Tasks Build Script' default='build-flex-project'>
    <!-- load properties file -->
    <property file='build.properties'/>

    <!-- points to are flexTasks.jar -->
    <taskdef resource='flexTasks.tasks' />    

    <!-- delete and redeploy -->
    <target name='init'>
        <delete includeemptydirs='true'>
            <fileset dir='bin-debug' includes='**\*' excludes='**\.svn'/>
        </delete>

    </target>
    <target name='build-flex-project' depends='init,create-html-wrapper'>
        <mxmlc file='${srcpath.dir}/${application.name}.mxml' output='${deploypath.dir}/${application.name}.swf'>
            <load-config filename='${FLEX_HOME}/frameworks/flex-config.xml'/>
            <include-libraries file='${libs.dir}' />
        </mxmlc>

    </target>

    <target name='create-html-wrapper'>
        <copy todir='${deploypath.dir}' overwrite="true">
              <fileset dir='${wrapper.dir}'>
               <exclude name='**/index.template.html' />
               <exclude name='**/index.template.html.svntmp' />
               <exclude name='.svn' />
              </fileset>
        </copy>
          <!-- Copy and rename the index.template.html -->
         <copy file='${wrapper.dir}/index.template.html'
              tofile='${html.file}' />
          <replaceregexp
              file='${html.file}'
              flags='gs'
              match='\$\{width\}'
              replace='100%'/>
           <replaceregexp
              file='${html.file}'
              flags='gs'
              match='\$\{height\}'
              replace='100%'/>
         <replaceregexp
              file='${html.file}'
              flags='gs'
              match='\$\{title\}'
              replace='${APP_TITLE}'
              encoding='utf-8'/>
         <replaceregexp
              file='${html.file}'
              flags='gs'
              match='\$\{version_major\}'
              replace='${version.major}'/>
         <replaceregexp
              file='${html.file}'
              flags='gs'
              match='\$\{version_minor\}'
              replace='${version.minor}'/>
           <replaceregexp
              file='${html.file}'
              flags='gs'
              match='\$\{version_revision\}'
              replace='${version.revision}'/>
         <replaceregexp
              file='${html.file}'
              flags='gs'
              match='\$\{application\}'
              replace='${APP_TITLE}'/>
          <replaceregexp
              file='${html.file}'
              flags='gs'
              match='\$\{bgcolor\}'
              replace='#FFFFFF'/>
         <replaceregexp
              file='${html.file}'
              flags='gs'
              match='\$\{swf\}'
              replace='${application.name}'/> 

    </target>
</project>

Continuous Integration with Flex, Hudson, and ArcGIS Server, Part 1 July 31, 2009

Posted by ruprict in Agile, Flex.
Tags: ,
14 comments

(Part 2, Part 3, Part 4)

I’ve been meaning to blog about our findings with getting CI going for Flex, since I took time to whinge about it earlier.  It was a bit of a journey, but all in all, not that bad.  Much of the thanks goes to Hudson, which is, how you say?, super-fantastic.  I plan to break this into a few blog posts rather than one big-old doozy.   The parts (I think) will be along the lines of:

  1. Getting your Fles project building with ant and Flex Builder, parts 1 and 2.
  2. Setting up unit testing with Fluint.
  3. Setting up Hudson.

Whachoo Need (OOH)

This post is focused on getting your Flex Builder project building with ant.  As such, I presume you are using Flex Builder, but if you aren’t and just want to build with ant, you should be OK. Oh, and I am doing this on Winders, even though ant is usually the domain of the Unix-based Java wanks (I mean “wanks” as a term of endearment, like “I love those wanks”)

Go get the following and download to your computer:

  • ANT - The original builder.  It can carry, like, 10,000 times its own weight in builds.  Unzip it to c:\ant.
  • Flex Ant Tasks – These come with the Flex SDK, which comes with Flex Builder.  You can find them in C:\Program Files (x86)\Adobe\Flex Builder 3\sdks\3.2.0\ant\lib\flexTasks.jar.  If you don’t have Flex Builder, go download the SDK and put it somewhere.
  • ArcGIS Server Flex API – So we can get our map on, know what I’m saying? (I am using 1.2)

Create the Project

Open Flex Builder and create a new project.  I am presuming that your local workspace is c:\projects\FlexCI, though it really doesn’t matter.

So, we’ll start by creating a new Flex Project in Flex Builder.

Create Flex Project

Hit ‘Next’ in the project wizard and we have our project.  Copy the AGS Flex API swc into your libs folder (see pic).

flexapi

Now we can make a map and stuff.  Add the following code to your app:

<esri:Map>
     <esri:ArcGISTiledMapServiceLayer
          url="http://server.arcgisonline.com/ArcGIS/rest/services/ESRI_StreetMap_World_2D/MapServer"/>
</esri:Map>

Now we have our map.  In Flex Builder, build (Ctrl+B, unless you are using ‘Build Automatically’) the site and run it, you should see a map of our world.  Building with Flex Builder works, which was a requirement for me.  I wanted people to be able to build and debug in the IDE, but also quickly build from the command line with ant.  I like Flexibility, #rimshot.

High Apple Pie in the Sky Hopes

In order to build with ant, we need a couple of items

  • A build file, we will call build.xml
  • A properties file, we will call build.properties

I am not about to go into the gory details of how ant works, but presume you know the basics, which is all I know.  We need to define a build target that compiles our Flex project.  The steps the build file will go through are:

  1. Clean out the build dir.
  2. Build the project.

In ant-speak, that is two targets.  I will call them ‘init’ and ‘build-flex-project’.  For the init target, we just need to delete everything in the directory that Flex Builder set up as the deploy location, which is (by default) the bin-debug directory.  Create a build.xml file in your Flex Project root, has the following XML:

<project name='Flex Ant Tasks Build Script' default=”init”'>
    <!-- delete and redeploy -->
    <target name='init'>
        <delete includeemptydirs='true'>
            <fileset dir='bin-debug' includes='**\*' />
        </delete>
    </target>
</project>

This is a fully-functional ant script now.  Test it by opening a command prompt, switching to the project directory, and typing ‘c:\ant\bin\ant’ (minus the quotes, of course)  You should see something like:

firstant

Also, your bin-debug directory should be empty.  WOOHOO!  If you build with Flex Builder again (you may have to “Clean” since FB won’t build unless it detects a change) the files will go back into the bin-debug dir.  Right, now let’s get the build part going.  Adobe was nice enough to create ant tasks that will build Flex projects.  The easiest way to make them available to your ant script is to:

  1. Copy the flexTasks.jar file into your c:\ant\lib folder.
  2. Reference these tasks in your build.xml file.

The second part is done by adding the following code to the top of the build.xml file:

<!-- points to are flexTasks.jar -->
<taskdef resource='flexTasks.tasks' />

That’ll do it.  (NOTE:  In a real CI scenario, which we’ll get to, we would not copy the jar into the ant\lib folder, but make it part of the project artifacts and reference it locally.  Bear with me, baby steps on the bus…)

Now, let’s add the build-flex-project target, which uses the mxmlc Flex ant task.

<target name='build-flex-project' depends='init'>
     <mxmlc file='${srcpath.dir}/${application.name}.mxml' output='${deploypath.dir}/${application.name}.swf'>
           <load-config filename='${FLEX_HOME}/frameworks/flex-config.xml'/>
           <include-libraries file='${libs.dir}' />
     </mxmlc>
</target>

WHOA!  OK, so I’ve jumped ahead a bit, so lemme ‘splain.  First off, we tell ant that this target depends on the init target, so it will run init before running the build.  Second, those funky ${} items that you see are properties.  So, you can see that I have one for”:

  • srcpath.dir – the source directory, so we knows what to build.
  • FLEX_HOME – this is where our SDK lives
  • deploypath.dir – where to put the build output
  • libs.dir – where are external libraries (like the AGS Flex API) live
  • application.name – What do we want our SWF to be called.

Now we need to put these properties somewhere, and the aforementioned build.properties file is where they belong.  Looks like:

#Copy this file locally to build.properties and change below for your env

# change this to your Flex SDK directory path
FLEX_HOME=C:/Program Files (x86)/Adobe/Flex Builder 3/sdks/3.2.0

# this points to your project's src directory
# {$basedir} is a default variable that can be used in any Antscript
# and it points to the project's root folder [ flex_ant_pt1_Tasks ]
# in this case
srcpath.dir =${basedir}/src

# points to the project's libs directory
libs.dir =${basedir}/libs

# this is the folder we want to publish the swf to
deploypath.dir = ${basedir}/bin-debug

application.name=FlexAGSCI

We need to tell our build.xml file about the build properties file, and we do so by adding this to the top (meaning, first thing under the <project> opening tag):

<!-- load properties file -->
<property file='build.properties'/>

The last thing we need before running the build again is to change the default target to build-flex-project.  You’ll find the default attribute on the root project element.

Now, running ‘c:\ant\bin\ant’ (btw, putting c:\ant\bin in your PATH is advisable, then you could just type ‘ant’) at the command line, gives:

secondant

Look in your bin-debug folder, and you’ll see the SWF file, which should be fully functional.

I think I’ll stop today’s post there.  It has gotten a bit long on me (they always do).  The next post will cover how to get the rest of the files that Flex Builder creates, like the HTML wrapper and Flash-detecting javascript files, incorporated into the build.

Hope this is useful.

Adding Drag/Drop Reorder to ArcGIS Flex Viewer TOC May 14, 2009

Posted by ruprict in ArcDeveloper, Flex.
Tags: ,
7 comments

Wow, that is a long, clumsy title.  Google will like it, though.

Anyway, I’ve been neck-deep in the world of Flex, focusing on the ArcGIS Server Flex API the last couple of months.  We delivered a map viewer based on Flex to a client recently, and it was a great learning experience.  ESRI released a Sample Flex Viewer component that includes the Table of Contents (TOC) sample from the code gallery.  The TOC component was originally built by Tom Hill at ESRI.  He and I have traded a couple of e-mails about adding drag and drop reorder functionality, so I thought I’d run through the basics of what it takes to get it working.

Download the Flex Viewer

If you haven’t already, download the flex viewer from here.  Extract the sample SOURCE (there are two zips, binary and source…we are using the source archive)  to your development area.  I am using FlexBuilder, so my life is easy, as I can just import the existing project into the IDE.  You don’t have to have FlexBuilder, but I am going to presume you know how to edit source files and compile the project.

Modify the LiveMapsWidget

The TOC component is used by the com.esri.solutions.flexviewer.widgets.LiveMapsWidget MXML component.  Open the source for that bad boy (the namespace==the directory).   Find the TOC component, which looks like

<toccomp:TOC id="toc" width="100%" height="100%"/>

We want to enable dragging on the component.  The TOC component extends the core Flex Tree component, so enabled drag drop is as simple as adding

dragEnabled=true

to the element.  If you do that and the run the viewer, you’ll notice you can open the Live Maps widget (in the Globe menu)  and drag the “Lousiana Landbase” layer around.  It doesn’t do much, but you can drag it.  In fact, you get a rex “X” while you drag, which means you can’t drop it anywhere.  So, how do we get rid of that pesky red “X”?   We have to tell the DragManager that the TOC will accept a drag/drop.  The DragManager is a Flex class that maanged drag and drop operations.  Google it for more info (sorry, but I have to constrain the post ot it will go War and Peace on me)   The time to tell the DragManager about the openness of the TOC is when something is dragged (?  drug?) over it.  We do this with the dragEnter event.  So, adddragEnter

dragEnter="onDragEnter(event)"

to the toc element.  Now we have to write the onDragEnter  method.  In the mx:Script area of LiveMapsWidget.mxml, copy this code:

			private function onDragEnter(event:DragEvent):void{
				DragManager.acceptDragDrop(event.currentTarget as TOC);
				if ((event.currentTarget as TOC)==null)
				{
					DragManager.showFeedback(DragManager.NONE);
					event.preventDefault();
				}

			}

This function fires when we drag something over the TOC and tells it that we are open for business. Business is, of course, things that can be dragged and dropped. You could put more logic in here to filter out non TOCItems, etc, but that is left as a lesson for the reader.

OK,  so our red “X” is gone over the TOC (but still there if you drag a layer over the map, cool!)  but now we want it to do something when we drop the layer.  Specifically, we want it to reorder the layers.  But we only have 1 layer, so let’s quickly add another.  Open up the config.xml in the src directory and add the following tag to the <livemaps> element:

<mapservice label="Louisville Public Records" type="dynamic" visible="false" alpha="0.4">http://sampleserver1.arcgisonline.com/ArcGIS/rest/services/Louisville/LOJIC_PublicSafety_Louisville/MapServer</mapservice>

Now we have two layers, making a drag/drop scenario much more compelling.  If you run the viewer you will see both our layers in the LiveMapsWidget.   Now, just like we had to tell Flex to enabled dragging on the TOC, we have to tell it to enabled dropping.  You guessed it, add

dropEnabled="true"

to the toc element.  Now, when you drag/drop a layer, they will reorder in the TOC, which is nice.  The map layers don’t do anything, but we’ll get there.  We have a problem now, though.  The Tree component makes no distinctions between services (roots, in this case) and the layers that make up those services.  This results in the ability of the user to be able to drop a map service under another map service, which is bad.  You can do a lot of checking when the drop occurs to make sure that the user hasn’t dropped one service as a child of another.  I am gonna go an easier route and collapse all the roots (map services) on drag start so those crafty users can’t do it.  They may not like it, but life is sometimes hard.  So, let’s add a dragStart function:

(on the toc)

dragStart = "onDragStart(event)"

(the function)

			private function onDragStart(event:DragEvent):void{
				//Close the dragged item
				_draggedLayer=toc.selectedItem  as TocMapLayerItem;
				var openItems:Array = toc.openItems as Array;
				for each(var o:Object in openItems){
					toc.expandItem(o,false);
				}
				//setInfoText(resourceManager.getString("resource","toc-layer-reorder"));
			}

K…we’re getting there.  Now to the meat of what needs to happen.  When we drop the service, we need to calculate it’s new index in the map, then tell the map to reorder the services.  It took me awhile to find an algorithm that worked for this, and here is why:

  • The basemaps.  The TOC doesn’t have the basemaps, so you have to take that into account when calculating the new index.
  • If the layer is dragged down, then you have to account for that.
  • The TOC indices are reversed form the map services.  So index 0 in the map is the lowest, but it’s the topmost node in the TOC.

So, nothing overwhelming, but details.    Let’s add the event to the TOC element:

dragComplete = "onDragComplete(event)"

and the code:


private function onDragComplete(event:DragEvent):void{
 if (event.action!="move")
 return;
 var _roots:ArrayCollection = toc.dataProvider as ArrayCollection;
 //Unclear why I have to do this....but I need the selectedIndex later
 toc.selectedItem = _draggedLayer;
 var dropIndex:uint=toc.calculateDropIndex(event);
 // I've seen thie calculated drop index be > than the number of
 // services.  This usually happens when a service node is expanded,
 // but let's just make sure.  We'll put it at the bottom of the list
 // in this cse.
 if (dropIndex>_roots.length)
 dropIndex=_roots.length;

 var ind:int=0;
 // Set in onDragStart....if it's null, get outta dogdge
 if (_draggedLayer==null)
 return;
 var delta:int = _roots.length-dropIndex;

 ind = delta + 1;//We have two base layers....HACK...THIS IS BAD, MAKE IT BETTER

 // If the selected item is dragged down, then the index needs to account for that
 if (toc.selectedIndex>dropIndex)
 ind=ind-1;

 toc.map.reorderLayer(_draggedLayer.layer.id,ind);

 }

The comments in that function go through what I am trying to do.  I’ll be the first to admit that it isn’t the prettiest code at the ball, but it’s the one I brought so I am dancing with it (Note to self:  work on better analogies)

So, you’d expect it to work now, woudln’t you?  Well, it doesn’t.  We have to make a minor change to the TOC to handle the layer reorder.   In the TOC.as (in src\com\esri\solutions\flexviewer\components\toc) the onLayerReorder function looks like:


private function onLayerReorder( event:MapEvent ):void
 {
 var layer:Layer = event.layer;
 var index:int = event.index;

 for (var i:int = 0; i < _tocRoots.length; i++) {
 var item:Object = _tocRoots[i];
 if (item is TocMapLayerItem && TocMapLayerItem(item).layer === layer) {
 _tocRoots.removeItemAt(i);
 _tocRoots.addItemAt(item, _tocRoots.length - index - 1);
 break;
 }
 }
 }

Modify the TOC Code (Just a little…)

When you run the viewer now, you’ll get RangeErrors on the addItemAt line above.   So, my approach was to calculate the new TOC index by figuring out the difference between the number of layers and the new index.  Then, make sure somethign didn’t go haywire and we are out of range.  See below:

private function onLayerReorder( event:MapEvent ):void
 {
 var layer:Layer = event.layer;
 var index:int = event.index;
 //How far did we move?
 var addbackind:int=(map.layerIds.length-1) - event.index;
 for (var i:int = 0; i < _tocRoots.length; i++) {
 var item:Object = _tocRoots[i];
 if (item is TocMapLayerItem && TocMapLayerItem(item).layer === layer) {
 _tocRoots.removeItemAt(i);

 // If we are out of range on the high end, rein it in
 if (addbackind>_tocRoots.length)
 addbackind=_tocRoots.length-1;
 // If we are out of range on the low end, rein it in
 if (addbackind<0)
 addbackind=0;
 _tocRoots.addItemAt(item,addbackind);
 break;
 }
 }
 }

May not be the prettiest…etc, etc.  But it works.  You should now have drag/drop reoder working like a champ.  Obviously, this code could still be improved.  The biggest example is accounting for the basemaps in a cleaner fashion.  I will tell you that we used the Specification Pattern to determine if a service was a basemap, allowing the TOC to ask the specification.  I liked that, but didn’t include it here to try and keep this post focused.

Anyway, try it out and see how it goes.  If you have improvments or suggestions, hit me in the comments.  Here is a link to the final LiveMapWidgets.mxml I used for this post.

Creating a REST Service with WCF and Windsor May 11, 2009

Posted by ruprict in WCF, Windsor.
Tags: , ,
add a comment

Following on from my previous post, here is a short post showing how quickly you can create a REST based service using the WCF Facility for Castle Windsor.   We will use the same service contract and implementation as the last post, with some very minor changes (only one, actually).    The list of steps to expose our service from the previous post with a REST endpoint consists of:

  1. Create a new .svc file for the second endpoint.
  2. Add an attribute to the operation contract to specify what HTTP verbs are allowed.

That’s it.  Please note that we are not replacing our SOAP endpoint from before, nor are we changing the configuration of the WCF Facility, nor are we touching the web.config.  The changes below will highlight how little we need to do.  Here is the new service endpoint (.svc file):

<%@ ServiceHost Service="my service"
Factory="Castle.Facilities.WcfIntegration.WindsorServiceHostFactory`1[[Castle.Facilities.WcfIntegration.Rest.RestServiceModel,
Castle.Facilities.WcfIntegration]], Castle.Facilities.WcfIntegration" %>

All we have done here is replace our factory with the REST aware service model from the WCF Facility.  We are using the Service attribute to point to the same component as the SOAP endpoing.

And the new service contract:

[ServiceContract]

public interface IMyService

{

[OperationContract]

[WebGet]

string MyOperation1(string myValue);

}

We’ve added the System.ServiceModel.Web attribute [WebGet] to allow HTTP GET to this endpoint.  Now, our operation is availalbe as a REST endpoint, using a URL like so:

http://server/site/rest.svc/MyOperation1?myValue=I%20am%20RESTful

which returns

<string>A WCF Facility Service says I am RESTful</string>

It’s likely that you wouldn’t want applicaiton/xml to be the default return content-type, but the point of this post is not to show a best practice with REST, but to show how bleeding easy it is to expose a REST endpoint.  We are also now exposing TWO endpoints (SOAP and REST) with a singular service implementation, a detail worthy of note.  In the real world, you would likely have a service manager that registered service implementations and formatters, allowing the clients to specify a return type (XML, JSON, etc) and amending the content-type accordingly.

This, however, is my blog and could not be farther from the real world. ;)

WCF and Castle Windsor Update May 7, 2009

Posted by ruprict in Castle, WCF, Windsor.
Tags: ,
1 comment so far

My old post about the Castle Windsor WCF facility is a bit long in the tooth, as Mr. Craig Neuwirt and others have been hard at work improving the facility.  The release of Windsor 2.0 inspired me to attempt to go over the facility and highlight some of the new items.  In the process, I’ll cover some basics, as even those have changed a bit.   I have written most of the new documentation for the WCF facility, which needs to be reviewed by Craig since some of the new stuff is above my pay grade.  The good news is that, when released, the facility will have some good documentation as well.

The best place to see the new facility in action is to grab Castle’s trunk and go thorugh the WCF Facility unit tests.  They are comprehensive and give a great example of the new features of the facility.  This post, and the documentation I wrote, are almost entirely based on those tests.  Now, on to some examples.

Basic Server Quick Start

The basic steps to using the WCF Facility are the same, and consist of:

  1. Create your WCF service and data contracts.
  2. Create a service type, implementing your contract.
  3. Create your .svc file for your service.
  4. Configure Windsor to use the WCF Facility for your service.

Create WCF Service and Data Contracts

In this very simple example, I am only going to use a service contract.  Here is my contract:

namespace MyService.Core.Interfaces

{

[ServiceContract]

public interface IMyService

{

[OperationContract]

string MyOperation1(string myValue);

}

}

Reblog this post [with Zemanta]So, all my operation contract does is take in a string and return a string. No big whoop.

Implement the Contract

namespace MyService.Core

{

public class TheService : IMyService

{

public string Prefix { get; set; }

public TheService(string prefix)

{

Prefix = prefix;

}

 

#region IMyService Members

public string MyOperation1(string myValue)

{

return String.Format(“{0} {1}”,Prefix, myValue);

}

#endregion

}

}

Create your SVC file

Presuming you have a web application to host your service, all raring to go, we need to tell the framework how to creaate your service.  That’s what the .svc file does:

<%@ ServiceHost Service="my service"
Factory="Castle.Facilities.WcfIntegration.DefaultServiceHostFactory, Castle.Facilities.WcfIntegration" %>

As with the previous version of the facility, you have to use a custom ServiceHostFactory, which has changed to Castle.Facilities.WcfIntegration.DefaultServiceHostFactory.  Also, the Service attribute in the .svc file needs to point to the component name in your Windsor configuration, which brings us to…

Configure Windsor

In my last post, I used Boo to configure the container.  This time around, I am going to use the fluent API that Craig has created because it is kick ass.  The container needs to be configured on application start, so we put the following in the Global.asax file:

#region IContainerAccessor Members

public IWindsorContainer Container { get; private set; }

#endregion

 

protected void Application_Start(object sender, EventArgs e)

{

ServiceMetadataBehavior metadata = new ServiceMetadataBehavior();

metadata.HttpGetEnabled = true;

 

Container = new WindsorContainer()

.AddFacility<WcfFacility>()

.Register(

Component.For<IServiceBehavior>().Instance(metadata),

Component.For<IMyService>()

.Named(“my service”)

.ImplementedBy<TheService>()

.DependsOn(new {prefix = “A WCF Facility Service says”})

);

}

Here, lemme ’splain.  As with any web application that uses Windsor, the container lives on the Global Application object.   Here, I first add the WcfFacility followed by adding a service behavior (ServiceMetadataBehavior).  This behavior will be added to all services registered with the container, however, new to the facility is the ability to explicitly scope a behavior.  You can scope a behavior to:  all services, all clients, or to explicit clients/services.  I know that feature was oft-requested by the community and Craig is the man for getting it done.  Back to our example, the service is registered is a IMyService named “my service” (remember our .svc file) and implemented by the TheService type.  Finally, I pass in my constructor argument, which is a string.  Oh, and in order to use the facility, you’ll need a reference to the following assemblies:

  • Castle.Core
  • Castle.Windsor
  • Castle.MicroKernel
  • Castle.Facilities.WcfIntegration
  • Castle.DynamicProxy2

That’s it!   The service is ready to run.  You’ll notice (or maybe you didn’t), that I did not even open the web.config.  You can use the web.config if you like, but I didn’t here because I am lazy.  You also may have noticed that I did not specify an endpoint or binding, so the facility created a default endpoint with BasicHttpBinding.  Again, I am lazy, but that is cool.

Show Me the Service

The image here shows what the service looks like in the WCFTestClient.exe application.

Easy peasy

Easy peasy

The default protocol is SOAP (does anyone use SOAP anymore?) but you could easily create a REST endpoint.  Maybe I’ll show that in my next post about this stuff.   This post only covers the very basics, so if you have more complicated stuff, I can take a stab at it or maybe ask Craig.

Just to be complete, here are most of the  big time new features:

  • Scoped Behaviors
  • The ability to create service hosts and control the host life cycle (see IServiceHostAware)
  • Fluent API

Speaking of which, lemme know if there is anything specific you want to see concerning the WCF Facility.  As I mentioned, the unit tests in the castle trunk are pretty comprehensive and the forthcoming documentation will have tons of configuration examples.  Try it out, it makes managing dependencies with WCF a breeze.

ArcGIS Server: “Cannot authenticate supplied identity” Error May 6, 2009

Posted by ruprict in ArcDeveloper.
Tags:
add a comment

So, I get this error from time to time in a dev environment or, occasionally, on a client’s server. It used to be very, very frustrating to solve, so I created a checklist of things that worked. I am writing it here to help others, hopefully, and make sure I never forget these steps.  I always try them in the following order.

  1. Make sure the ArcGISWebServices account password has not expired.  If you are comfortable with it, set this password to never expire.  This, more often than not, is the root cause of the issue.
  2. We have seen an issue where having the I_USR account in the “Guests” group on the box caused this error.  Not sure why, but the SA couldn’t tell me why that user was in that group either.Add ArcGISWebServices user to the Power Users group and restart the WWW service.  Again, this may be out of your security comfort zone.  If it is the problem, then you’ll need to mess with the privileges of that account until you find the issue.  Also, I’ve seen this not work until I deleted the user, reran the Post Install and THEN added them to the group.
  3. If it’s still an issue, time to get nasty.  Delete your ArcGISWebServices user and rerun the Web Applications Post Install.  This will force you to create a new ArcGISWebServices user.
  4. Last resort.  Do all the stuff in this thread, as well as the thread that is linked therein.  This is the “throw all the crap against the wall and hope something sticks” step.

Hopefully, that’ll get it done.  If not, and you find something else that works, please let me know.  I don’t run into this issue very often any more (but I did today and step 1 fixed it) but when I do, I am glad I have a checklist.

Cruise: The Next CI Framework? April 16, 2009

Posted by ruprict in Continuous Integration, Flex.
Tags:
2 comments

I’ve been looking at Cruise, which is a continuous integration framework from ThoughtWorks recently. I have belly-ached in past posts about a need to get CI running for our Flex projects, an undone task that slaps me around daily, reminding me of my folly and hypocrisy. The issue with Flex and CI is that it seems to be relatively new ground.   Sure, some folks are doing it (almost all using Hudson) but there aren’t a lot of them. And they are all java people so they are comfy-cozy in the Hudson-Maven-jar land.   I am a measly .NET person that pulls my knees to my chest and hides my face from their nerdy superiority.
I read a couple of posts on Cruise, and decided to give it a go.   It is free for a two-agent (more on agents in a bit) install. I’ve no idea what the cost is after that, but I’ve asked TW.   Cruise consist of 2 or more parts. Part one is a server. It’s a one-click install (I am using Windows) and it creates a service called Cruise Server. Parts two or more are agents, also a one-click install, and also creates a service called Cruise Agent.   The idea behind agents is to create a “build grid”, using agents to distribute the load of building and testing your code.   You can make an agent out of any box (Win, Mac, Linux) which also allows testing of the code in different environments.   Scalability and multiple environments puts Cruise ahead of any CI framework I’ve used (CC.NET is the only one).  Very cool.

Cruise’s over-arching approach to CI is the pipeline. You create a pipeline, which seems to often be an atomic project.    A pipeline has one or more stages, which are things like Build, Test, Deploy to UA, etc. To be clear, the stages are defined by you, so there isn’t a finite list of what the stages can be.   In essence, a stage is a container of one or more jobs.  Jobs are where the rubber hits the road.   A job is a discrete bit of execution. A job can use one of ant, nant, rake, or exec, so anything with a command line interface, basically.  Therein lies the simplicity of Cruise.  It allows the build and test tools to handle the building and testing,  while it handles the scaling and pipeline.
One of the items provided by Cruise Server is a dashboard, which is very simple (see screen shot).

Cruise Dashboard

Cruise Dashboard

As you might expect, you can start a pipeline, or a stage of a pipeline.   You can look at the current activity or administer your CI server.  The administration of Cruise is based on a simple XML schema ( I know, I know, XML…but it’s not “bad” XML)  The initial setup of an item (pipeline, stage, job, agent, etc) can be point-and-click driven, but any changes after that are editing the XML.  You can do it right in place and Cruise picks up the changes on-the-fly.   In my testing I made a pipeline that had a Test stage feeding into a Build stage.  I wanted to switch them around, so I just cut the XML element and pasted it back into the pipeline where I wanted it to run, and it was done.  Very easy.  I like easy.

Creating a pipeline requires two pieces of infomation: The type of builder (ant, nant, rake, exec) and the location and type of your source control.    It supports Git, Mercurial, Perforce, and Subversion out of the box.  With your pipeline created, you can add stages using

<stage name="Build"></stage>

“Build” above is the name I chose, so it coudl be anything.  Then you add jobs to the stage in a similar manner.  For an ant builder, you would specify the build file and target.    Also, jobs can have artifacts, so if you have a task that generates documentation, Cruise will upload it to the server.  A better example might be unit test reports that are generated by your testing framework.  Just tell Cruise where they are,  and it will upload them to the server.  You can, in fact, create a tab on the job output that will show the test reports (it’s an iframe, nothing fancy) with very little configuration.

You can look at a pipeline in a couple of different ways, the coolest is the “Pipeline Activity”.

Cruise Pipeline Activity

Cruise Pipeline Activity

You can visit or rerun any of the past stages my clicking on them.  Also, you can define manual transitions, which you would kick off from this interface.  An example of when you might want a manual transition is a deployment to UAT, which you wouldn’t do on every build (would you?)

In my initial testing, I wanted to get a Flex build going in Cruise with automated tests using Fluint.  The lion share of the work was defining the ant script.   Flex and Fluint have ant tasks already, so building the ant script was relatively simple.  I defined a stage called “Build” with a ant buld job and a stage called “Test” with a single artifact (my test report) and ant build job.  This gave me a functioning CI Server that builds on each check in to SVN and runs all the Fluint tests, then uploads the test reports so I can see them on the build output.  Here is the XML for that:

<pipeline name="FlexBuildTest">
  <materials>
    <svn url="http://svnserver/svn/svnRepo1/trunk" username="svnuser" password="svnpwed" />
  </materials>
  <stage name="Build">
    <jobs>
      <job name="AntBuild">
        <tasks>
          <ant buildfile="build.xml" />
        </tasks>
      </job>
    </jobs>
  </stage>
  <stage name="Test">
    <jobs>
      <job name="AntTestBuild">
        <artifacts>
          <test src="deploy/reports" dest="test-reports" />
        </artifacts>
        <tasks>
          <ant buildfile="build.xml" target="test" />
        </tasks>
      </job>
    </jobs>
  </stage>
</pipeline>
I am pretty impressed so far.  We are just about to set up our build environment for a new project, and I plan on using Cruise.  We can use it for our Flex and .NET stuff, which is a bonus.  It’s simple to setup and maintain.  I’ll try to come back and blog about any other issues/cool things we find.
Meanwhile, head over to ThoughtWorks and check it out.  They have regularly scheduled webcasts to demo Cruise (I saw one today) so you can get a better idea of how Cruise functions.
Reblog this post [with Zemanta]