When creating orcascipt, usually I start from the existing PBT file which contains the huge lib list:

LibList “myapp_appl.pbl\\myapp_appl.pbl;myapp_attachment.pbl\\myapp_attachment.pbl;myapp_br.pbl\\myapp_br.pbl;myapp_casefile.pbl\\myapp_casefile.pbl;myapp_casefile_related.pbl\\myapp_casefile_related.pbl;myapp_dddw.pbl\\myapp_dddw.pbl;myapp_disciplinary_action.pbl\\myapp_disciplinary_action.pbl;myapp_licensee.pbl\\myapp_licensee.pbl;myapp_list.pbl\\myapp_list.pbl;myapp_mass_entry.pbl\\myapp_mass_entry.pbl;myapp_registration.pbl\\myapp_registration.pbl;myapp_report.pbl\\myapp_report.pbl;myapp_resource.pbl\\myapp_resource.pbl;myapp_schedule.pbl\\myapp_schedule.pbl;myapp_security.pbl\\myapp_security.pbl;myapp_ticket.pbl\\myapp_ticket.pbl;im_lls_rc_dws.pbl\\im_lls_rc_dws.pbl;im_lls_rc_rpt_dws.pbl\\im_lls_rc_rpt_dws.pbl;pies_shared.pbl\\pies_shared.pbl;reg_01.pbl\\reg_01.pbl;”

I want the orca format like this:

build executable “myapp.exe” “myapp.ico” “myapp.pbr” “yyyyyyyyyyyyyyyyyyy”

build Library “myapp_appl.pbl\myapp_appl.pbl” “” PBD
build Library “myapp_attachment.pbl\myapp_attachment.pbl” “” PBD
build Library “myapp_br.pbl\myapp_br.pbl” “” PBD
build Library “myapp_casefile.pbl\myapp_casefile.pbl” “” PBD
build Library “myapp_casefile_related.pbl\myapp_casefile_related.pbl” “” PBD
build Library “myapp_dddw.pbl\myapp_dddw.pbl” “” PBD
build Library “myapp_disciplinary_action.pbl\myapp_disciplinary_action.pbl” “” PBD
build Library “myapp_licensee.pbl\myapp_licensee.pbl” “” PBD
build Library “myapp_list.pbl\myapp_list.pbl” “” PBD
build Library “myapp_mass_entry.pbl\myapp_mass_entry.pbl” “” PBD
build Library “myapp_registration.pbl\myapp_registration.pbl” “” PBD
build Library “myapp_report.pbl\myapp_report.pbl” “” PBD
build Library “myapp_resource.pbl\myapp_resource.pbl” “” PBD
build Library “myapp_schedule.pbl\myapp_schedule.pbl” “” PBD
build Library “myapp_security.pbl\myapp_security.pbl” “” PBD
build Library “myapp_ticket.pbl\myapp_ticket.pbl” “” PBD
build Library “im_lls_rc_dws.pbl\im_lls_rc_dws.pbl” “” PBD
build Library “im_lls_rc_rpt_dws.pbl\im_lls_rc_rpt_dws.pbl” “” PBD
build Library “pies_shared.pbl\pies_shared.pbl” “” PBD
build Library “reg_01.pbl\reg_01.pbl” “” PBD

Here is how I did it in minutes of work, using NotePad++ relace with regexp:

  1. Replace step 1, this is easy, replace all \\ with \, and ‘;’ with “\n”
  2. Replace step 2, using regexp, replace all
    ^(.*)
    with
    build Library “\1″ “” PBD
  3. Done.

Notepad++ reference: http://notepad-plus.sourceforge.net/uk/regExpList.php

I wish we could use JIRA for generating release file in build result. cc.net does have a ModificationHistory publisher, but for some reason, the version CCConfig I have doesn’t work for this. (Somebody filed the bug already, I did a vote.)

The workaround I’m using:

  1. Enable ModificationWriterTask in cc.net project publisher, this will generate a file named modifications.xml in artifact folder, which only contains the changes since last build.
  2. Create a NAnt task to merge modifications info into a modificationHistory.xml file. (idea from here)
  3. Create another NAnt task to transform the xml into a text file.
	<target name="publish.mod.history" depends="merge.mod.history" >
		<style style="${build.dir}\modifications.xsl"
			in="${CCNetArtifactDirectory}\modificationHistory.xml"
			out="${CCNetArtifactDirectory}\${application.version}\modifications.txt">
	    <parameters>
	        <parameter name="reportType" namespaceuri="" value="Plain" />
	    </parameters>
		</style>
	</target>

	<target name="merge.mod.history" description="add the new mod list to an existing xml file">
		<property name="xmlnodes" value=""/>
		<xmlpeek xpath="//ArrayOfModification" file="${CCNetArtifactDirectory}\modificationHistory.xml" property="xmlnodes"></xmlpeek>
		<property name="newnode" value="" />
		<xmlpeek xpath="//ArrayOfModification" file="${CCNetArtifactDirectory}\modifications.xml" property="newnode"></xmlpeek>
		<property name="xmlnodes" value="${newnode}${xmlnodes}" />
		<xmlpoke file="${CCNetArtifactDirectory}\modificationHistory.xml" xpath="//ArrayOfModification" value="${xmlnodes}" />
	</target>

Modifications.xsl:

<?xml version="1.0"?><!-- DWXMLSource="modificationHistory0.xml" -->
<xsl:stylesheet
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"

     version="1.0">

    <xsl:output method="text"/>

    <xsl:variable name="modification.list" select="ArrayOfModification/Modification"/>

    <xsl:template match="/">
Modifications since last build (<xsl:value-of select="count($modification.list)"/>)
    <xsl:apply-templates select="$modification.list">
        <xsl:sort select="date" order="descending" data-type="text" />
    </xsl:apply-templates>
    </xsl:template>

    <!-- Modifications template -->
    <xsl:template match="Modification">
 (Revision:<xsl:value-of select="ChangeNumber"/>) <xsl:value-of select="FolderName"/>/<xsl:value-of select="FileName"/>, <xsl:value-of select="UserName"/> on <xsl:value-of select='substring(ModifiedTime, 0, 11)'/>, <xsl:value-of select="Comment"/>
    </xsl:template>

</xsl:stylesheet>

Result:

Modifications since last build (14)

(Revision:15) /trunk/build/modificationHistory0.xml, FMao on 2009-10-15,
(Revision:15) /trunk/build/modifications.xsl, FMao on 2009-10-15,
(Revision:12) /trunk/build/default.build, FMao on 2009-10-15, added new task to merge mod hist and transform xml
(Revision:12) /trunk/pbunit_demo.pbw, FMao on 2009-10-15, added new task to merge mod hist and transform xml

I wish WCF can provide something like this:

instead of

[PrincipalPermission(SecurityAction.Demand, Role ="Administrators")]

We can use

[PrincipalPermission(SecurityAction.Demand, RoleProvider = typeof(MyAuthorizationChecker)]

So developers won’t care if security requirement changed.

I posted before about explicitly calling

permissionSet.Demand()

right in service method, it works, but it would be nice to use service behavior attribute to make code looks cleaner.

Extending WCF service is not that hard, thanks to this post.

    public class CheckAuthorizationBehaviorAttribute : Attribute, IOperationBehavior
    {
        public string MethodName { get; set; }

        public void Validate(OperationDescription operationDescription)
        {
        }

        public void ApplyDispatchBehavior(OperationDescription operationDescription, DispatchOperation dispatchOperation)
        {
            dispatchOperation.Invoker = new AuthorizationChecker(dispatchOperation.Invoker
                , MethodName);
        }

        public void ApplyClientBehavior(OperationDescription operationDescription, ClientOperation clientOperation)
        {

        }

        public void AddBindingParameters(OperationDescription operationDescription, BindingParameterCollection bindingParameters)
        {

        }
    }

    public class AuthorizationChecker : IOperationInvoker
    {
        private readonly IOperationInvoker _invoker;
        private readonly string _methodName;

        public AuthorizationChecker(IOperationInvoker invoker, string methodName)
        {
            _invoker = invoker;
            _methodName = methodName;
        }

        public object[] AllocateInputs()
        {
            return _invoker.AllocateInputs();
        }

        public object Invoke(object instance, object[] inputs, out object[] outputs)
        {
             Console.WriteLine("Checking permission on methodname {0}.{1}", instance.ToString(),_methodName);

            if (!.....(my authorization logic here ))
                throw new FaultException<SecurityAccessDeniedException>(new SecurityAccessDeniedException("No access"))
                ;

            string value;
            value = (string)_invoker.Invoke(instance, inputs, out outputs);
            return value;

        }

        public IAsyncResult InvokeBegin(object instance, object[] inputs, AsyncCallback callback, object state)
        {
            return _invoker.InvokeBegin(instance, inputs, callback, state);
        }

        public object InvokeEnd(object instance, out object[] outputs, IAsyncResult result)
        {
            return _invoker.InvokeEnd(instance, out outputs, result);
        }

        public bool IsSynchronous
        {
            get { return _invoker.IsSynchronous; }
        }
    }

Then my service contract is just like this:

        [ServiceContract]
        public interface ITestService
        {
            [CheckAuthorizationBehavior(MethodName = "PingWithUserName")]
            [OperationContract]
            void Ping(string username);

I was having difficult to get the method name inside invoker, the methodname is hide in the private syncInvoker class, so I had to add the public attribute to my behavior. Later I found out this might be a better idea, because what if the method is an overload one?

Still, it would be nice to set the default method name to the one we just attached. Hope I can figure this out soon.

This should be a simple configuration trick, just do it, increasing client side app.config.

            var binding = new WSHttpBinding();
            binding.MaxReceivedMessageSize = 2147483647;
            XmlDictionaryReaderQuotas readerQuotas = XmlDictionaryReaderQuotas.Max;

            binding.ReaderQuotas = readerQuotas;
            channelFactory = new ChannelFactory<IRequestManagementService>(
                binding,
                new EndpointAddress(_url));

             var _proxy = channelFactory.CreateChannel();

But this isn’t enough, you need to change the same setting on serverside as well. Unfortunately, the default web.config auto-generated by VS doesn’t have binding section at all, so you have to add this by your own. Here is an example:

  <system.serviceModel>
    <services>
      <service behaviorConfiguration="..."
        name="..."
               >
        <endpoint address="" binding="wsHttpBinding"
                  bindingConfiguration="maxStringBinding"
                  contract="I...Service">

          <identity>
            <dns value="localhost" />
          </identity>
        </endpoint>
        <endpoint address="soap" binding="basicHttpBinding" contract="I...Service" />
        <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />

      </service>
    </services>
    <behaviors>
      <serviceBehaviors>
        <behavior>...        </behavior>
      </serviceBehaviors>
    </behaviors>
    <bindings>
      <wsHttpBinding>
        <binding
         name="maxStringBinding"
         maxReceivedMessageSize="2147483647">
          <readerQuotas
            maxDepth="2147483647"
            maxStringContentLength="2147483647"
            maxArrayLength="2147483647"
            maxBytesPerRead="2147483647"
            maxNameTableCharCount="2147483647" />
        </binding>
      </wsHttpBinding>
    </bindings>
  </system.serviceModel>

When using Cruisecontrol.net + EAserver, we want to use pull instead of push style to deploy packages upto EAServer. Because the Cruisecontrol stores all the build result into the artifacts folder, what we need is a dos command can pull the specific version then deploy to EAServer. Here is the command I created:


@echo off
set artifacts_dir=\\ccnet\Work_Dir\Artifacts\my_project
cls
echo *****************************************
echo Please type in the version to deploy:
echo *****************************************
set /p version_number=
echo *****************************************
echo Starting to deploy %version_number%
echo *****************************************
if  "%version_number%"=="" goto help

pause

call jagtool -local delete Package:MyPackage
call jagtool -local deploy -type jagjar -jagjartype Package  %artifacts_dir%\%version_number%\jar\MyPackage.jar

pause

exit /b

:help
echo You need to specify the version to deploy
pause

EAserver acts as a client to consume WCF SOAP WebService, wrap it in WebDatawindow accessed by JSP web user.

Powerbuilder richclient can also directly consume WCF SOAP webservice, or access the EAF component which calls WebService.

Hybrid_app

The PB we are using 11.2 still have some limitation on webservice datawindow:

  1. Doesn’t support long type parameter, we had to change it to string.
  2. wsdl is wrapped in datawindow is not configurable, might be better if can change it through ini or dw property.

When deploying webservice datawindwo upto EAServer, should copy those auto-gened dlls to EAServer/bin folder, not /dll.

How to switch wsdl in dw?

  1. dw.Describe/Modify or dw.Create(syntax) won’t work for EAF/component, it keeps killing EAServer.
  2. Re-compile the auto-gened temp proxy cs file, like this post did. The interesting part is, the proxy’s ctor is already trying to read default configuration from some ini/config file:
    public RequestManagementService() {
                string urlSetting = System.Configuration.ConfigurationManager.AppSettings["EndpointURL"];
                if ((urlSetting != null)) {
                    this.Url = urlSetting;
                }
                else {
                    this.Url = "http://appdev01/RequestManagement/RequestService.svc/soap";
                }
            }
    

    My question is, can’t we create a config file to intercept this ctor reading?

    
    <configuration>
         <appSettings>
              <add key="EndpointURL" value="http://appdev02/RequestManagement/RequestService.svc/soap" />
         </appSettings>
    </configuration>
    

    Yes, that’s the place you can control to switch wsdl, not the one shown in dw syntax. In fact, if you change the wsdl in dw to an invalid one, it still works!

    How to control it? Create a config file named as your_app.exe.config, paste the configuration content in it. That’s it.
    Thanks to this post helping me out by showing how to get the current configuration file path: AppDomain.CurrentDomain.SetupInformation.ConfigurationFile

I’m using PBUnit, so the config file for testing is called pbunit.exe.config, when I deployed it upto EAserver, the config file should rename to jagsrv.exe.config.

If the whole EAServer is only using one webservice, this solution works; if you have multiple webservice wsdl to consume, you have to add more config settings by re-compiling this temp proxy file in /TmpWebService folder.

This broken upgrade drove us crazy, make sure you set this in your eclipse.

eclipse_14

We build framework, you build application.

This should be the motto for Microsoft, and any framework provider. But thing is different in WPF world, try google how many people are working so hard to make ListView header click sortable.

I don’t like code behind, the classic event hook up isn’t a clean solution at all. There are a few smart guys using attached property to implement this sort feature, xaml can be much simpler, and we can slowly build our own WPF framewrok extension. (?)

The idea can be found from this post, but the attached source code are missing, this post uses same technology with full version of source code. In fact, I think Thomas’ solution is better, he is using a technique called Adorner, which is cleaner than the other one using switching template. The only part I don’t like is the extra GridViewSort.PropertyName in his xmal to set the sorting property name. Why not just use the native binding name? like this:

propertyName = ((System.Windows.Data.Binding)headerClicked.Column.DisplayMemberBinding).Path.Path;

That’s for click-header-sorting.

How about double-click to trigger event/command in view model? Check this post.

Is there an open source project somewhere called WPF contrib? Yes, check out the WPF tool kit on codeplex, at least the click-header-sorting is supported, including some other fancy feature, such as the alternate row color.

Using Exception in Wcf should be very caucious, as I blogged before, wcf exception should be marked as Serializable, and implement all 4 ctor from base exception class. An unit-test for each exception might be overkill, but it’s worth to try.

In-proc wcf host is neat for this purpose, by using channel Factory, client side doesn’t need configuration either.

    [TestFixture]
    public class MyDataNotFoundExceptionSpecs
    {
        private readonly ServiceHost _host;
        private const string _url = "net.tcp://localhost:9000/TestException";

        public MyDataNotFoundExceptionSpecs()
        {
            _host = new ServiceHost(typeof(TestService));

            _host.AddServiceEndpoint(typeof(ITestService),
                new NetTcpBinding(), _url);
            _host.Open();
            Console.WriteLine("wcf service started.");
        }

        ~MyDataNotFoundExceptionSpecs()
        {
            _host.Close();
        }
            private ChannelFactory<ITestService> channelFactory;
            [SetUp]
            public void SetupChannelFacotry()
            {
                channelFactory = new ChannelFactory<ITestService>(
                   new NetTcpBinding(),
                   new EndpointAddress(_url));
            }
            [TearDown]
            public void CleanUpChannelFacotry()
            {
                    channelFactory.Abort();
            }
        [Test]
        [ExpectedException(typeof(FaultException<MyDataNotFoundException>))]
        public void should_passed_to_client()
        {
            ITestService proxy = channelFactory.CreateChannel();

            proxy.Ping("Frank");

          }

    }

    public class TestService : ITestService
    {
        public void Ping(string user)
        {
            throw new FaultException<MyDataNotFoundException>(new MyDataNotFoundException());
        }
    }

    [ServiceContract]
    public interface ITestService
    {
        [OperationContract]
        [FaultContract(typeof(MyDataNotFoundException))]
        void Ping(string user);
    }

I was coding ruby for the past few days, RubyMine 1.1 released means my free evaluation period finished. Because I just code ruby for fun,  $400+ doesn’t make sense to me. Had to switch back to the free NetBeans 5.7.1.

(I still use SciTe on my slow laptop as Ruby IDE, and it’s a very handy lightweight editor, the only thing drove me crazy is switch between editing file can also change the current path of shell, I’m tired of adding and removing ‘test/’  before my rb file. I could use absolute path, but is there any better solution?)

Fortunately, NetBeans also supports subversion. At first I wasn’t happy with the way it forced me to create a default project structure, e.g., all source code supposed be in /lib/ folder, which obviously is an industry standard, but I missed that part.

Another good thing is that NetBeans created a standard Rakefile at the root folder. Simplely throw all my test rb files into /test/ folder, running “rake test”, I got my local build script!

Why didn’t RubyMine create this?

Mock in Ruby, I end up with using Mocha as my mock framework because I still on test:unitest mode. But gem install won’t bring the mocha rb into my ruby search path, had to manually copy mocha into my site_ruby folder, woala, it works.

Recently I found the book The Ruby Way 2nd edition is very good book, but I badly need a book can cover some ruby project management p&p.

Currently I’m the only developer to my ruby project, CI might be overkill, but someday I will need it. I’m supprised that CruiseControl.rb isn’t that popular in ruby community, so many choices, Hudson, cerberus, etc, including CruiseControl.net. I know this is an open/free teamcity ci server somewhere, can it support ruby project?