in

 

Bytes of Wisdom

  • Note on sets in hibernate/nHibernate

    I just wanted to share this with anyone who is not aware...

    Caveat:  After reviewing my original post and the comments that follow I had initially elected to change the container tag in the example below from set to list.  After thinking about it further I've returned the tag to 'set', since this is after all what I was trying to illustrate in the first place (although understanding the risk of using set should be understood).  Granted, a list probably should have been used, but this was a solution to a problem relating to an existing system that I'm currently working on.  I apologize if it offends your senses, it sort of does mine too, but the tests do pass and the code does work as expected.  Hopefully others facing similar constraints may find it of use in any case.  Smile

    We are using hibernate of my current project, but this should be the same for nHibernate.  In any case, we ran into a situation where we needed to ensure that a collection (Set) on a class that we were mapping needed to ensure the order of list items when used in the middle tier.  The class had a sequenceNumber field that was used to indicate ordinality in the Set.  The knee-jerk solution proposed was to modify the class to support sorting, but it was work that no one wanted to pick up so the code stayed broken.

    I, being industriously lazy, didn't want to do it either but wanted it done none the less.  I had never set the order-by in the hbm configs before but figured this would be as good a reason to use it as any.  So I made one simple change to our mapping file and the broken unit tests magically started passing.  Here's a code example:

    <set name="myCollectionOfThings" lazy="true" inverse="true" order-by="SEQUENCE_NUMBER ASC" > <key> <column name="THING_HOLDER_FK" /> </key> <one-to-many class="blah.blablah.ThingHolder" /> </set>

    It's the "order-by" attribute in the "set" tag is what is used to define the default OrderBy behavior.  The contents are straight SQL that get's tagged on the end of the rendered prepare statement that is executed against the database.

     

    Hope that's of use!

  • Virtual Joy

    At home I have only my Linux box to work with.  I'm quite content with it, but I do have some DOS and older Windows apps that I like to use.  Unfortunately, by DOS floppy's are now dead (as is my floppy drive) and the MSDN DOS download is for making DOS floppies.  What I really wanted was an ISO for DOS that I could use to install on a VM.  Fortunately, I came across FreeDOS (http://www.freedos.org/)!

    FreeDOS is an open source DOS implementation.  It has been around for some time, but I was pretty excited to find it,  It comes with a huge tool set (much more than I need but includes a MASM compatibale assembler, Pascal interpreter, VIM, etc.) and would have been awesome to have in the early 90s.  If you still play DOS games it's a must.

    Just thought I'd share in the event that you aren't aware of this OS.

     

    Side Note:  If you want a floppy boot images for installing Win95/Win98/NT, These guys have them: http://www.allbootdisks.com/

  • Nested classes with JUnit

    Recently I was playing with JUnit 4.X.  I wanted to be able to define tests in nested classes as I had before with NUnit.  This was to facilitate BDD-ish test definitions, where I break up unit tests by test context.

    My first attempt failed (of course) because JUnit was unable to see the nested classes and the failed to run.  After a bit of digging, I ran across a sparsely documented feature that allowed me to do what I wanted. 

    Namely by using: @RunWith(Enclosed.class)

    Below is an example, hope it's of use:

    package junitSampleTests; import static org.junit.Assert.*; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Enclosed; import junitSample.*; @RunWith(Enclosed.class) public class SimpleFractionTest { public static class WhenConstructingSimpleFractions { protected SimpleFraction f1, f2; @Before public void setUp() throws Exception { f1 = new SimpleFraction(15, 25); f2 = new SimpleFraction(-27, 6); } @Test(expected=InvalidOperationException.class) public void shouldNotAllowZeroForDenominator() throws Exception { f1 = new SimpleFraction(1, 0); } @Test public void shouldEnsureOnlyTheNumeratorHoldsTheFractionSign() throws Exception { f1 = new SimpleFraction(1, -1); assertEquals(-1, f1.getNumerator()); assertEquals(1, f1.getDenominator()); } } public static class WhenUtilizingAccessors { protected SimpleFraction f1, f2; @Before public void setUp() throws Exception { f1 = new SimpleFraction(15, 25); f2 = new SimpleFraction(-27, 6); } @Test public void shouldGetNumerator() { assertEquals(15, f1.getNumerator()); assertEquals(-27, f2.getNumerator()); } @Test public void shouldGetDenominator() { int result = f1.getDenominator(); assertTrue("getDenominator() returned " + result + " instead of 25.", result == 25); result = f2.getDenominator(); assertEquals(6, result); } } public static class WhenSimplifying { protected SimpleFraction f1, f2; @Before public void setUp() throws Exception { f1 = new SimpleFraction(15, 25); f2 = new SimpleFraction(-27, 6); } @Test public void shouldSimplify() { f1.simplify(); assertEquals(3, f1.getNumerator()); assertEquals(5, f1.getDenominator()); } @Test public void shouldSimplifyWhenNoSimplificationIsPossible() throws Exception { f1 = new SimpleFraction(15, 29); f1.simplify(); assertEquals(15, f1.getNumerator()); assertEquals(29, f1.getDenominator()); } @Test public void shouldSimplifyNegativeFractions() { f2.simplify(); assertEquals(-9, f2.getNumerator()); assertEquals(2, f2.getDenominator()); } @Test public void shouldSimplifyWhenNumeratorIsZero() throws Exception { f1 = new SimpleFraction(0, 29); f1.simplify(); assertEquals(0, f1.getNumerator()); assertEquals(29, f1.getDenominator()); } } }
  • Using SSL Websphere MQSeries and .Net

    Hi all, I've haven't posted anything since my last contract...sorry about that (what can I say, I've been busy...Ma, AgileJoe's been abusing me!).  In any case, this is as much for my benefit (and documentation for the current team) as it is for the community at large (I never remember this stuff so I want to be able to google it).  I did see some other blogs that tackle this subject...but alas...the web *** have blocked most technical blogs here.

    I was recently tasked with getting an MQSeries .net client to support mutual authentication.  I'd done the same the week before for a couple of web services (which was relatively easy) and figured this would be a snap.  In reality the only snap was the sound of my morale being crushed.  First off, let me say that we wasted about a week trying to get things working with what was later found to be a mis-configured queue manager.  We tried to get the team responsible for the queues to ensure they were set up correctly but encountered show-stoppers on two occasions before they finally got it right.  Overall, the .Net documentation is spotty and left us to figure out a number of critical steps.  If you yourself are trying to setup SSL/Mutual Authentication for a .Net client, be sure to be familiar with the basics of SSL first.  It helps quite a bit.

    Note: IBM's on-line publication library doesn't update the URL in your address bar, so if you find a useful page and want to bookmark it be sure to get the target URL from the document frame and use that to create the bookmark.

    Initial Skirmish:

    On our end, we were trying to get things set up using the XMS client for 6.0 (we switched to the XMS client later in the game).  We had already integrated the client successfully with an unsecured queue and figured that the following was all we needed to add to get up and running:

    connectionFactory.SetStringProperty(XMSC.WMQ_SSL_CIPHER_SUITE, "SSL_RSA_WITH_NULL_SHA");
    connectionFactory.SetStringProperty(
    XMSC.WMQ_SSL_KEY_REPOSITORY, @"X:\KeyStorePath\key");
    connectionFactory.SetStringProperty(
    XMSC.WMQ_SSL_PEER_NAME, @"CN=SERVER_CERT_COMMON_NAME");

    Simple enough...we used CIPHER_SUITE (instead of CIPHER_SPEC) as a good client should, set the path to the key store(created using the "IBM Key Management" tool that comes with the client, and we caught on fairly quickly to how the Peer Name is used.

    Fog of War:

    The basic client configuration was pretty simple, but we were constantly getting MQExceptions that were akin to getting null pointer exceptions.  The exceptions basically said "Something has gone terribly wrong in your application"...well I figured as much...I'm getting exceptions after all!  Logging the exceptions was useless because we were logging all Exception types.  I later found that the MQExceptions (most, not all...some have the exception reason codes in the message itself) had a couple Properties that gave a bit more information, namely "Reason Code".  Once I started capturing the reason codes I found (after a little digging) a couple of reason code lists that gave a little (often precious little) information about the codes.  One list was useful for client-specific reason codes and the other was for subscriber-specific reason codes.  Also, I found that I couldn't turn on the client trace with the .Net client library, but we did stumble over the Web Sphere client error log(C:\Program Files\IBM\WebSphere MQ\errors), which was often much more useful than any information found in the exceptions (although you still end up using the reason codes).

    Setting up the key store was fun too.  In the aforementioned link, you'll see in Figure 4 the following next to Key Label: "<client identifier of your choice>".  I'm not sure if this is due to our MQ guys, but we had no choice here.  First off, the example was for Self Signed certs, so they didn't really apply in our case.  We were using a pfx (p12) cert store with the client key, the trust cert, and the exported private key.  I soon learned that the IBM Key Manager requires that the pfx is password protected (I know, it's a good practice anyway).  Then we had to ensure that the Peer Name on the server end matched the common name found in the certificate's distinguished name.  Finally, we found that our "client identifier of choice" had to be the string "ibmwebspheremq" followed by the name of the account under which the process was running...all in lower caps...not much of a choice (e.g. ibmwebspheremqsvcacctname).  We probably never would have figured the last one without the help if the MQ team's manager.  If the Key Label isn't set up correctly we get the following:

    CWSMQ0006E: An exception was received during the call to the method ConnectionFactory.CreateConnection: System.AccessViolationException: Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
       at IBM.WMQ.MQClient.MQCONNX(String qMgrName, MQCNO& mqcno, Int32& pHconn, Int32& pCompCode, Int32& pReason)
       at IBM.WMQ.MQClientConnector.MQCONNX(String qMgrName, MQConnectOptions& cno, Int32& hConn, Int32& compCode, Int32& reason)
       at IBM.WMQ.MQQueueManager.Connect(String queueManagerName)
       at IBM.WMQ.MQQueueManager..ctor(String queueManagerName, Hashtable properties)
       at IBM.WMQ.MQSPIQueueManager..ctor(String queueManagerName, Hashtable properties)
       at IBM.XMS.WMQ.WmqConnection.CreateQueueManager(String qmgrName, Boolean isSessionHConn)
       at IBM.XMS.WMQ.WmqConnection.CreateQueueManager(String qmgrName)
       at IBM.XMS.WMQ.WmqConnection..ctor(WmqConnectionFactory cf, String userName, String password)
       at IBM.XMS.WMQ.WmqConnectionFactory.CreateConnection(String userName, String password). During execution of the specified method an exception was thrown by another component. See the linked exception for more information.

    ...Clear as mud...we wasted some time fiddling with directory permissions, recreating the key store, etc.  To make it work with our unit tests (without requiring each developer to set up a private key store for each development workstation that they work on) I threw together an Impersonator class based on an MSDN article.  We configured the Key Label using the service account, included the dev key store in source control, and impersonated the service account in our unit test Setup and Tear Down methods.  Worked like a charm.

    Victory...almost

    Finally, we'd run across something earlier in IBM's document "WebShpere MQ Using .Net Version 6.0" that didn't quite make sense at first.  We had brushed over this until we started getting the following:

    "CWSMQ0046E: An environment error occurred when a connection to specified queue manager was attempted.  Current libraries are not supported with the specified queue manager. Ensure that appropriate libraries and appropriate versions of these libraries are in use."

    Great, I think, I must have downloaded the wrong client.  Before I do anything rash, however, I consult my handy-dandy IBM documentation.  On page 24 you see the following: "The following section does not apply to the fully-managed client."  Okay, so I search for "unmanaged client"...no matches.  Then I search for "fully-managed client"...the only match is the line above and one other place (BTW, if you are using XMS, don't confuse yourself with this document...use the XMS doc first...although the XMS documentation refers you to it for "in-depth information"...lol).  I check "managed client" with a few more IBM docs and finally find what I'm looking for in the XMS documentation ("Message Service Clients for C/C++ and .Net"):

    "XMSC_WMQ_CM_CLIENT_UNMANAGED (for .NET only) A connection to a queue manager which forces an unmanaged client stack."

    I find an answer in the on-line documentation, but am still a little unsure what this means...Are we supposed to use 'unsafe' blocks?...Do I have to rewrite this using pointers?...Do I make external DLL calls like we do with Win32API calls?...What's going on here?!?  Well, in the end it turns out the answer is "not much"  We simply had to set another connection property.  Why this isn't included in the documentation's SSL code examples is another question.  Add this call to your ConnectionFactory instance and the pain will go away:

    connectionFactory.SetIntProperty(XMSC.WMQ_CONNECTION_MODE, XMSC.WMQ_CM_CLIENT_UNMANAGED);

    Okay, now Victory!

    And that's it!  Aside from the Key Store setup and the basic queue configuration that was already complete, all we needed were the four horsemen of MQSeries: 

    1. Make sure you've specified a Cipher Suite that is compatible with the Queue's Cipher Spec
      1. connectionFactory.SetStringProperty(XMSC.WMQ_SSL_CIPHER_SUITE, "SSL_RSA_WITH_NULL_SHA");
    2. Provide a valid path to your Key Store (.kdb)  (and effective know Key Label conventions for the client cert)
      1. connectionFactory.SetStringProperty(XMSC.WMQ_SSL_KEY_REPOSITORY, @"X:\KeyStorePath\key");
      2. Also, we couldn't get the client to work with the Windows cert store...one of you can figure this out and educate me
    3. Setup the Peer Name so that the server certificate will be accepted by the client during the SSL handshake
      1. connectionFactory.SetStringProperty(XMSC.WMQ_SSL_PEER_NAME, @"CN=SERVER_CERT_COMMON_NAME");
    4. Set connection mode to unmanaged so that you can actually use SSL with the queue
      1. connectionFactory.SetIntProperty(XMSC.WMQ_CONNECTION_MODE, XMSC.WMQ_CM_CLIENT_UNMANAGED);

    There's really not much to it...I'm not sure why they didn't just tell me what to do in the documentation.  I know that this is really geared toward a small set of .Net developers, but I hope this can be of use.  This little task was pretty painful and took a couple of weeks to resolve.

    As far as why the documentation for this is so bad...I think, ultimately, that the Java guys basically just hate us.  They are in it with the Canadians (yeah you Scott).  This is all part of their twisted plan to dominate the Earth. 

    In fact, I'll be a Java developer again on my next contract...I'm already starting to hate my .Net self. 

  • Metaphors and Mathematics

    I haven't posted myself in a bit and decided to go ahead and drop a few lines...albeit a little off topic.

    I've been looking for supplemental maths books for both my children.  As you Computer Science types know, texts for elementary Maths (and more advanced maths for that matter) can be painfully dully and often confusing.  In searching for texts for my two kids, daughter 13 and son 10, I wanted to find materials that were more interesting than their usual fare.  This while addressing their wildly differing attitudes toward the subject.

    My son is the easy case, he loves math.  He goes back and forth between wanting to be a doctor (because he loves Biology, Anatomy and Chemistry) and an engineer (because he thinks Physics is pretty cool too).  At 10 he's started his journey into Pre-Algebra.  He tends to grasp topics quickly and will often knock out textbook problem sets in a few minutes and ask to use the rest of his math time to play Legend of Zelda.  I just had to find a book with a large set of challenging problems to push him a bit more and keep him happily occupied.

    My daughter, on the other hand, holds no particular love for Maths.  She wants to be a photo-journalist and has already asked about minimum math requirements for the degree she wants.  She's quite bright (reads at a college level...although she didn't quite have the patience to finish the unabridged version of Les Miserables), but Maths to her present chores to be tolerated and nothing more.  I don't expect her to be a mathematician, but I want her to have a broad enough background so that her future options are not limited (you know, the basics like Algebra, Trig, some Calc).

    Fortunately, I've found two books that I believe may suit her.  The first, titled "Math Doesn't Suck", covers elementary arithmetic mainly but uses mnemonics and metaphors to explain the rules of the game.  It's written by a female mathematician to appeal to young girls.  The book arrived yesterday and my daughter has been tearing through it like a novel.  She read the first 50 or so pages last night and concluded that she loves the book. 

    I'm reading the second book as she goes through the first so that I can tie concepts as presented in the text to her "normal" Maths text.  It's titled "Algebra Unplugged" and is written by the author of my favorite introductory electronics book titled "There Are No Electrons: Electronics for Earthlings" (and co-authored by a maths professor from Denver).  It's also presenting the subject in prose and focuses on understanding fundamental concepts in Algebra rather than presenting things to memorize and long lists of problems to solve.  My favorite quote from the book thus far is, "Reversibility is a god to whom mathematicians bring many bananas and mangos."

    With the help of these two books I'm better equipped to kindle a greater interest of Maths in my daughter.  That's because they both effectively use metaphors to maintain her interest and present topics in familiar lights.  They also attempt to speak in a language that she can relate to.  We Computer Science types, on the other hand, tend to gravitate toward the language of Mathematics (or at least something similar to it).  The language that we love to use is also the language that we utilize when talking to the Business types.

    In the early days of Agile...we had to walk 10 miles a day for the sake of our projects, barefoot, over hot coals and razors!  Just kidding.  In the early days (XP in particular), agile key practices included the use of Metaphor to better communicate technical concepts to the customer/business.  Over the years the use of Metaphor has loss emphasis and has even been ignored by many as a key practice.  Many of us have forgotten that our customers do not necessarily speak the same language we do. 

    To illustrate my point I have an mp3 click from a focus group meeting that took place during a DoD project that I was working on.  The customer asked our project manager, "Do your developers, software developers, talk to real people or do they just talk to themselves?"  Brilliant question.  On this project we failed utterly to effectively communicate with the customer.  We had generated tomes of requirements and design docs using dashing technical jargon and probably the most complete UML model that I've ever seen (Thanks Rational Rose!...ugh).  We did all the "right stuff" but left our customer confused, frustrated, and ultimately failed to discern what the system truly needed to do.  We were really good at talking to ourselves, but talking to "real people" was another matter.

    Now I have just as much difficulty in effectively communicating to customers as the next guy.  When I took the "Which Computer Language Are You?" test I got "Binary" as an answer (AgileJoe will attest to this, although I've taken it again and got C++, so maybe I'm improving).  Regardless of the difficulty, however, I think that it is crucial that we make an effort to speak using the customer's language.  Developing a ubiquitous language is a start, but is by no means sufficient in and of itself.  The use of Metaphor is also key in communicating in terms of the business itself while saving the customer from confusing technical and often abstract terminology.  It's an often ignored tool that we can use when speaking to "real people". 

    Because of the use of Metaphor (and humor for that matter), the texts that I recently bought my daughter have captured her interest in a normally dry topic and have helped her both understand and memorize key concepts.  Granted, I may prefer that she learn formal terminology, but I'm satisfied with her being able to understand and apply key concepts even if it means her using strange terminology.  For instance, she now thinks of prime numbers as primate numbers and the process of creating a factor tree as the "Hanging Monkey Method".  I'm really not concerned about the strange terminology that she's adopting, rather I'm pleased that she's understanding the concepts and spending her free hours pondering them (we'll test long term memory later).

    The bottom line is that we, as developers, must make greater efforts to speak in terms that the customer can easily understand and Metaphor is a tool that aids in just that.  If you see your customer's eyes glazing over, stop to think about what you are saying, then try presenting it in another manner that they can (hopefully)  better understand.  The customer is not stupid because he can't understand your language, he simply speaks a different language (Just as you are not stupid because you don't speak Tagalog, Esperanto, SNOBOL, or any number of other languages).  With continued practice we can become increasingly proficient at speaking to "real people".

    P.S.  I must admit, however, that I do love my little mp3 clip and am happy that I was at the wrong place at the right time to get it.  We lived up to the quote of one of my favorite demotivational posters (for Mistakes) which reads, "It could be that the purpose of your life is only to serve as a warning to others".  Happy coding!

  • Calling .Net Web Services from Oracle PL/SQL

    I'm working relatively closely these days with an Oracle DBA on this super-cool mainframe integration project (anyone want to join me?  LOL).  The old batch ops were managed through cron'd jobs in Oracle and I was asked to take a different approach.  I haven't found anything like Control-M here and was toying with the idea of rolling my own scheduling services.  The management wanted the integration pieces written in VB.Net, not PL/SQL scripts as had been done in the past, fair enough.  In a later meeting, the DBA had said that he REALLY wanted to replace the cron jobs with Oracle Jobs...hmmm...what to do, what to do...

    I'd already planned on publishing .Net web services to support calls to the actual service objects.  A scheduler would be configured to call the web services at set intervals and kick of the batch processing.  I did a little research and found the utl_http library in Oracle.  I ran a quick test if it was installed and working and was delighted.

    With utl_http it's pretty easy to call an XML web service.  It supports using PL/SQL to utilize HTTP requests and responses.  To test it I threw together a very simple web service that allows anonymous callers to write to a custom event log.  Now the DBA can automate sending me nasty grams (none received yet, I'm a little disappointed).

    Here's the PL/SQL script that calls the web service.  All you have to do is define the requesting soap envelope, set the appropriate HTTP header info, point to your target using the right protocol and fire!

    declare http_req utl_http.req; http_resp utl_http.resp; request_env varchar2(32767); response_env varchar2(32767); begin request_env:=' <soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"> <soap:Body> <LogMessage xmlns="http://tempuri.org/"> <message>This is my message</message> </LogMessage> </soap:Body> </soap:Envelope> '; dbms_output.put_line('Length of Request:' || length(request_env)); dbms_output.put_line ('Request: ' || request_env); http_req := utl_http.begin_request('http://wsXXXX/Test_WebService/Service.asmx', 'POST', utl_http.HTTP_VERSION_1_1); utl_http.set_header(http_req, 'Content-Type', 'text/xml; charset=utf-8'); utl_http.set_header(http_req, 'Content-Length', length(request_env)); utl_http.set_header(http_req, 'SOAPAction', '"http://tempuri.org/LogMessage"'); utl_http.write_text(http_req, request_env); dbms_output.put_line(''); http_resp := utl_http.get_response(http_req); dbms_output.put_line('Response Received'); dbms_output.put_line('--------------------------'); dbms_output.put_line ( 'Status code: ' || http_resp.status_code ); dbms_output.put_line ( 'Reason phrase: ' || http_resp.reason_phrase ); utl_http.read_text(http_resp, response_env); dbms_output.put_line('Response: '); dbms_output.put_line(response_env); utl_http.end_response(http_resp); end;

     

    See? Easy as PI!  It's practically self explanatory (and the web service itself gives the client pretty much the info they need to get wired in).  As you see, I used varchars to declare vars for the request and the response.  With larger SOAP messages you'd want to take a different approach (reading chunks into a buffer) because the varchar is so small. 

    Here's the console output showing what was sent and received (reformatted a bit for readability):

    Length of Request:324 Request: <soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"> <soap:Body> <LogMessage xmlns="http://tempuri.org/"> <message>This is my message</message> </LogMessage> </soap:Body> </soap:Envelope> Response Received -------------------------- Status code: 200 Reason phrase: OK Response: <?xml version="1.0" encoding="utf-8"?> <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <soap:Body> <LogMessageResponse xmlns="http://tempuri.org/"> <LogMessageResult>Logged Message: [This is my message]</LogMessageResult> </LogMessageResponse> </soap:Body> </soap:Envelope>

    Now how cool is that?  This was really my first time consuming (or starting to anyway) .Net web services from a disparate technology and hadn't really spent much quality time with SOAP since around 2002.  Now kicking of the jobs through Oracle will be a breeze...after I iron out authentication, of course.

    Now, to learn how to use the 'out of the box'  XML parser that comes with Oracle...

  • Subversion Tip of the Day - Moving Files

    Many of you are beginning to use Subversion for your source control repository these days.  I am also sure that you have found SVNTortoise to be a welcome addition to Subversion and use it also.  Moving files and directories at the command line is a pretty straight-forward affair, but doing so with Tortoise is a little counterintuitive (but never-the-less simple).

    Here's the easiest way that I've found to move a file or subdirectory around using Tortoise...

     

    Before I begin, here is folder/file structure for my demonstration

    folders are named based on initial hierarchy

    image

    documents are likely named...the following are documents in folder1.1

    image

    and here are the contents of folder1

    image

     

    Moving a file/directory

    Many times (especially early in projects) we may find that we've decided that a file should be in another directory.  How to move a file was not readily apparent to me and during the error phase of my trial and error I often ended up exporting the file and adding it to the new location.  This is bad because I lost history on the file at it's new location. 

    Moving the Wrong Way:

    Here's the revision graph for doc1.1.1.txt before a bad move:

    image

    Now I'll drag and drop it to folder 2 by using cut and paste:

    image

    image

    This is the revision graph after committing the move:

    image

    As you can see the revision history is lost for this item because Subversion was unaware of the move.

    Moving the right way:

    To move files the right way using Tortoise, highlight the file(s) you want to move and drag and drop to the new location using the RIGHT mouse button.

    Revision graph of doc1.1.3.txt before the move:

    image

    When you drop the file(s) to the new location you will be presented with a popup menu

    image

    Here you can select a SVN move, copy, or export.  I selected 'SVN Move versioned files here'.

    image

    image

    Notice the 'Add' symbol for the moved file.

    The revision graph for the file hasn't changed (because the contents are unaltered)

    image

    The revision graph for the parent folder shows the file move

    image

    So, as you can see, the history is preserved.  The same process is used to move multiple files and directories to new locations.  You can also use 'Rename' to move individual files, but I'm not too fond of the approach (it's also not good if done at the folder level).  I do wish that there was a hotkey for this functionality or at least inclusion of the move command into the normal SVN menu.  The TortoiseSVN documentation does cover the subject briefly but without the pretty pictures.  I sort of wish that I had RTFM before screwing up the history on some of my repositories, but where's the fun in that? 

  • VB.Net oddity of the day - Array Declarations

    I ran into a recent issue today relating to array declarations in VB.Net.  I looked up array declarations on the net and found something that gave me hope, but alas...

    "Arrays

    In VB6 declaring an array

       Dim Items(5) As String
    

    gives you 6 items from index 0 to index 5. In VB.NET, this same declaration will yield 5 elements from index 0 through index 4. Be on the look out for "out of bounds" type errors. Also, all arrays in .NET must now be zero-based."

    My personal favorite is the last line.  He says it like it's a bad thing!  In any case, I didn't include the source of the quote because the guys is wrong (or at least no longer correct for all versions after .Net beta1, I believe).  True, all arrays in VB.Net must now be zero-based, and thank the computing gods for that, but for the sake of backwards compatibility VB.Net still supports the good(bad)-ole-way of declaring arrays. 

    Coming from C# (and C and Java...) this was a bit of a surprise.  In particular because I have the habit of declaring know max sizes for arrays as constants.  If I was only a VB programmer this wouldn't be so annoying, but it is.  Also, handy little tools like Convert.Net don't handle this case at all, so if you used it to convert C# snippets to VB you would be serving yourself up an instant logical error.  Those Visual Fred guys, always trying to be different...

    So, "Dim Items(UpperBound) as String" is just the way things work, I'll just have to accept it.  Thank God for TDD, that's all I have to say.  If I wrote a bunch of code on my previous assumptions without coverage I would have hated life ferreting out all the places that I would have made the same mistake.  I know that this is the way VB6 worked, but again, I thought that VB6 was pretty stupid when it came to arrays.

     

    It's kind of sad though, why can't the VB folks conform a little to the masses?

    I.E. Here are some other languages declaring arrays containing 10 elements (My COBOL is way weak, so excuse any syntax errors):

    C/C++:   

    int myArray[10];

    Java:      

    int[] myArray = new int[10];

    C#:        

    int[] myArray = new int[10]; 

    Ruby:    

    myArray = Array.new(10)

    COBOL:  

    01 MY-ARRAY

         05 ARRAY-VALUES  PIC9(3)  OCCURS 10 TIMES

    FORTRAN:

    DIMENSION myArray(10)       ! Although arrays can also be defined with upper AND lower bounds similar to VB6

    LISP:

    (setq myArray (make-array 10 :element-type 'integer))

  • Things I hate...

    BTW, sorry I've been out of the loop for a while.  Whatever.

    Things I hate...Windows Vista.  Just kidding (well, not really).  Anyway, I hate Web Services that do little more than allow inefficient remote access to a databases. 

    As you may know, I'm working on a new contract these days for boring details see my blog on the matter.  In any case, I was excited to see the 3rd party vender's published web services that at first glance offered a nice interface to a complex system.  They developed a proxy library that's easy to use, offered an extensive domain library and supports asynchronous communications.  I was stoked and thought that this gig would be a breeze after all.

    Then reality set in...no support for batch operations.  Okay, I can deal with that.  The service API had a 1-for-1 relationship between classes and services, alright, I'm still here.  Then I found that no objects in the domain library have references to other objects.  If object A has a B logically, A will only expose the ID of B.  So let's say I have an house that must have an owner of type person.  A person has an address and a phone number, both required.  With the service interface, I'd have to add a phone number through the phone number service and an address through the address service.  I would get IDs back from both add operations and would have to use those IDs to add a person to the system.  Then I would get the person ID back and use it on the house's owner ID to add a new house.  The system's class hierarchy is much more complex and to say the least and using the web service started to seem silly.

    Whatever happen to "chunky" service interfaces?  If I used the web services, I would be replacing OLEDB with Web Services...dirty.  The argument from the architect was that the granular service API was needed to help performance.

  • Quick Background on my current CICS integration project

    I'm currently working on a stop-gap legacy integration project that is geared toward data integration between a legacy CICS system and a new 3rd party product.  I have 2 major tasks in this project, the first being a web application for bulk data entry into both systems simultaneously and the second being cross-system data transformation and transfer.  The integration points between the two systems are expected to support operations for the next 12 months.  Past integration projects have been handled through cron'd UNIX scripts, PL/SQL stored procedures, triggers, CICS batch jobs, etc.  Past projects also have left a dearth of documentation in their paths.

    The current integration approach to the CICS system is pre-defined, so I just have to work with "what is" in that regard.  I've had the joy of reading COBOL ctl files to complete requirements and design docs.  Integration involves FTPing flat files to and fro.

    The 3rd party product has a service-based API, but service calls are not chunky at all; so interfacing through that is a bit too wordy for the batch processing that I'll need to be doing.  To make things more fun, I have no ER diagrams for the new system's DB (which has a couple hundred tables), many entity relationships are not supported by foreign keys, no one seems to know what sequences are used to generate keys, the 3rd party system's source is closed and lacks technical documentation, I have no customer contact (from XP PoV, I only have a manager and a developer to interface with), my wife left me, and my dog died (okay, maybe not the last two).

    In any case, this is proving to be a delightful challenge (ah yes, and I failed to mention that the client wants betas for 5 batch interfaces and a the web application written in 3 weeks).  The client wants the solution written in VB.Net and has asked that some "best practices" be introduced into the organization along the way.  I've been constructing a domain model(s) that can speak between the two systems and believe that I'm making good headway in understanding the business better.

    I'll be blogging (maybe?) on some of my approaches as I work though this project.  I've done a fair bit of VB6 in the past (distant past), but the VB.Net syntax has felt strange having done so much C# over the last few years (at least now I can relate better to the VB.Net guys' questions at the local UG meetings).  Generics, attributes and reflection look especially weird.

    As far as tools, I'll be using some of the usual suspects, but will probably emphasize my use of NHibernate.  I've also had my first experience with using LDAP with forms authentication (if anyone wants an example I can do that too).  In fact, if there's anything about this project that may be of interest to you, drop a comment and let me know.

  • VB.Net oddity of the day - Assignment/Comparison operator

    On my current project I'm forced to code in VB.Net.  Normally I'm pretty open to other languages, but VB.Net is irritating (more so than VB6 in my opinion).  The language syntax is riddled with ambiguity (at least for a c-type guy like myself) and moving from c# to VB can be confusing.

    Here's my latest beef with VB.Net.  There's only one operator for assignment and comparisons.  As a result, the compiler handles evaluation of the the language syntax in a subtle, but irritating way.

    Here's some code to illustrate my point, I had something like this in my program:

    Dim oldValue, currentValue As Integer

    oldValue = currentValue = 2

    In C# this is cut and dry.  The value 2 would be assigned to currentValue and the side effect would be the value assigned, or 2.  I've long been in the habit of using assignment side effects in C#, but VB looks at this differently.  In VB, the value 2 is assigned to currentValue, but the side effect is the comparison of the two values.  In this case, currentValue initializes to 0, so the expression evaluates to false (or 0).  Therefore, oldValue now equals 0.

    Now, if I did this:

    Dim oldValue, currentValue As Integer

    currentValue = 2

    oldValue = currentValue = 2

    When the statement is evaluated, it will first evaluate the expression currentValue = 2.  2 will be assigned to currentValue and the side effect will be the comparison of currentValue to the assigned value, 2.  They are equal, so true will be returned and converted from bool to int as the non-zero value -1.

    It's no biggy, just annoying.

  • CLOBbered again!

    Hey all,

    I'm currently working on an NHibernate on Oracle project and ran into the first problem with CLOBs that I've had in some time.  I was trying to use a property that mapped to a CLOB in a Example instance for a session Criteria object.  No dice.  Oracle complained saying this:

    System.Data.OracleClient.OracleException: ORA-00932: inconsistent datatypes: expected - got CLOB

    Well, I guess sometimes you get lucky...and sometimes you just get CLOBbered.

    Guess now I have to dig into the NHibernate code if I have time.  All other CRUD works nice with Clobs, just Example chokes.  Could just be a dialect thing. 

    Cheers!

  • How to enlist ADO commands into an NHibernate transaction

    Adoption of NHibernate in a legacy environment can be daunting for a number of reasons.  Aside from the overhead of becoming proficient with the framework itself, developers are also faced with thousands of lines of working (it's assumed) code that is already conversing with the system's data store(s).  If complete migration to NHibernate is a prerequisite, then such systems would never make the move.  That being said, NHibernate does afford a way to make calls using the plain old ADO.Net API.  To be more precise, NHibernate allows users to enlist IDbCommands into NHibernate transactions.

    Personally, I've only used this feature to work around limitations of NHibernate (yes, although I believe NHibernate is the best thing since sliced bread, I do acknowledge its limitations...unlike <disparaging remark about other OS/Language/Methodology fanatics here>).  This feature was necessary for bulk delete operations…example follows:

    HQL in NHibernate is handy, but can get you in trouble.  Say you fire off an HQL query something like this:

    DELETE FROM User WHERE User.Clue = null   //not sure offhand of exact HQL syntax

    This would delete pretty much all your users, so if you have a few million clueless users in the system NHibernate will load the Users into the first level cache and then delete them.  I had a similar situation with a gig I was on not too long ago.  Caching the objects before deleting them would not only have taken a long time, it would have brought the server to its knees after the page file was used up.  I couldn’t skip the caching stage using NHibernate directly, but I could do something like this:

    ISession session = sessionFactory.GetSession();

               

    using(ITransaction transaction = session.BeginTransaction())

    {

                ...NHibernate stuff...

     

    IDbCommand command = new SqlCommand();

    command.Connection = session.Connection;

     

    transaction.Enlist(command);

     

    command.CommandText = "delete from User where clue is null";

    command.ExecuteNonQuery();

     

    ...more NHibernate stuff... 

    }

    In the using block I could do all sorts of NHibernate stuff yet still do my bulk delete without the caching overhead.  ADO commands used in this way are safely tucked into your current NHibernate Transaction context.

     This feature can be handy, but keep in mind that NHibernate remains unaware of state changes in the repository.  If I had a User collection in memory, I’d have to ignore the previous state after the delete and recall the collection based on my previous find criteria.  Stored Procedures could also be used this way, but Ayende blogged not to long ago about an alternative approach (I’m not sure off hand of the version of NHibernate that supports this).

     

  • Reflectionesque behavior in JavaScript

     

    Here's a little something in my continued investigation of JavaScript and its many wonders (man, that sounds strange!)...

    Okay, so for today's topic I'll look at some 'reflectionesque' behavior of JavaScript.  As many know, the class Object can be used as an associative array.  For instance:

    var myvar = new Object();
    myvar["value1"] = 42;
    assert(42, myvar["value1"]);  //would be true

    What many may not know is that objects will behave as associative array whether we like it or not.  Properties (fields or functions) that we add to an object's prototype will show up in a foreach construct if we iterate over an object.  This means that we could iterate over an object to see what's supported by its prototype/interface...sort of like reflection in .Net.  This can be helpful if we want to ensure that a property is supported by a given instance.  If it's not supported we can either inject the property/function at runtime so that the object doesn't cause any problems or we could bypass behavior that depends on the property.  Also, we could take disparate classes that support the same "interface" and apply polymorphic ideas.  In the example I show an attempt at getting the value of the 'name' property from three different classes.

    So that joe has something to play with, I've attached a script file called reflectionesque.js (zipped) that illustrates some of this.  I've also attached a screen shot that shows the output:

  • How'd he get that image up there?

    First off, I'm not much of a blogger so I'm not quite up to speed on the tips and trick of blogging.  I saw recently pretty pictures in one of Nellie's blogs and was instanly green with envy.  I wanted pictures too!  I tinkered around with the dashboard and blog editor for a while to no avail and finally out of desparation went back his blog entry.  I noticed WindowsLiveWriter in the URL and gave a quick search.  To say the least, I wish I was aware of the tool in the first place.  It facilitates creating blog entries easily with rich content.  Just as a simple example, I've included and image of one of the more lackluster constellations, Triangulum.........now I can include screen shots in discussions....yiiiihaaa!

    Posted Apr 06 2007, 06:30 PM by jlockwood with 1 comment(s)
    Filed under:
More Posts Next page »
Copyright Los Techies 2007. All rights reserved.