Web Toys

Discussion of all kinds of web technologies

About the author

Bret Patterson.
E-mail me Send mail

Recent comments

Authors

Disclaimer

The opinions expressed herein are my own personal opinions and do not represent my employer's view in anyway.

© Copyright 2010

I had a Kindle 2 for a week.

I've been wanting a kindle for the past year, pretty much since the original kindle was released. I decided to wait for the kindle 2 because I thought it'd work out most of the kinks in the first version, and implement some nice new features.

I read quite a bit. I read a mixture of science fiction and fantasy, though mostly science fiction as I get older. At least 60% of what I read is computer books, text books, and PDF documents from work. The thought of replacing my novels wasn't really that appealing because I don't tend to have a lot in my queue. I tend to spend more time looking for new authors and series while waiting for new ones in a series I'm already reading.

The thought of replacing my computer books, text books, and PDF documents was very appealing because the first two are really heavy and bulky, I keep and refer to constantly, and PDF's are painful to read on a computer for any length of time. I was hoping the kindle would give me a good portable document reader and an improvement over flipping pages to scan for interesting topics.

Unfortunately what I found was that the kindle 2 is good for only 1 thing, reading novels. The regular old paper back books that you read 1 page at a time from front to back. It's horrible for computer books, and text books, because the screen size is tiny and you can't fit enough text on the screen to be usable. It's even worse for PDF's because you have to first convert them, much of my material is confidential, and then they usually don't render very well and are very hard to read. My iPhone is better for reading Word Docs, PDF's and looking at Powerpoint presentations despite the tiny screen size. I attribute this to the near perfect rendering support, lightning fast load and view, and the amazingly easy and intuitive zoom and pan.

The screen refresh is fine for novels, but absolutely infuriating when trying to flip back a few pages to refer to something you've just read or to use for searching. The keyboard is great for simple web searches or looking up books, but is terrible for more than extremely casual use. The buttons are tiny and far spaced making them a pain to click.

Pretty much the kindle 2 is a $400 novel reader, and you have to pay full price for the book without a discount (compared to what you can get at www.barnesandnoble.com as a member) for the electronic form. Because of this you never actually make back your $400 investment in savings for the books, despite the obviously lower print and distribution costs for the publishers. You might find a few cheap books below what the book store sells, but these are books you'll find 10 or more for 1/3rd the price at half price books and such, so there isn't any actual cost savings.

Because of all of this your just basically locking yourself into the amazon format, the inability to loan your book out, paying full price for books, and using this $400 device to read novels. If I travelled a lot for work and wanted a novel reader for travelling then it'd be a no brainer. For anything else it's also a no brainer, don't buy it.

The browse and buy function was definitely really great and worth the praise. Other than that I'm not sure why anyone would buy it unless they read ALOT of novels, travel a lot so need the remote purchase convenience, and don't have any need to read anything but standard paperback novels while traveling. For the rest of the world it's a very cool sounding, but very niche oriented product that really isn't for me.

I had a kindle 2 for a week, and then sold it on craiglist


Posted by bpatters on Wednesday, April 15, 2009 6:29 PM
Permalink | Comments (0) | Post RSSRSS comment feed

Configure Websphere and DB2 to issue ARM calls (ITCAM for Transactions 7.1 update)

General Requirements

   

  1. DB2 Distributed Version 8.2 (or 8.1 FP11)
    1. Only non-zos DB2 8.2+ supports ARM, and it supports ARM v4
  2. Websphere Application Server 5.1 or higher
    1. Only Websphere can pass correlators to DB2, and DB2 will not issue ARM calls unless a correlator is received for the connection.

Step 1: ITCAM for Transactions 7.1- Install the Transaction Collector Agent

    The Transaction Collector agent is the agent that supports monitoring ARM instrumented applications. Installing it automatically installs support for all ARM instrumented applications (TU is it's prefix as you will see in paths below). This agent replaces the previous 6.2 Client Response Time agent for monitoring ARM applications (though similar steps can be used to configure the CRT agent to monitor ARM also, if you want the CRT workspaces instead or in addition to the Transaction Collector Workspaces).

Step 2: Configure Websphere

 ConfigureRequestMetrics

  1. In the picture above you need to do the following:

    1. Check the box labeled "Prepare Servers for Request metrics collection"
    2. Select "All" Radio button under "Components to be instrumented".
    3. Set the Trace Level
      1. HOPS - Preferred Level
        1. Generates instrumentation information on process boundaries only (for example, at the entry and exit points for the Web container).
        2. Generates instrumentation information on process boundaries only (for example, a servlet request coming from a browser or a Web server and a JDBC request going to a database).
      2. Performance_Debug
        1. Generates one additional level of instrumentation data, whereas debug generates detailed instrumentation data.
        2. Generates the data at Hops level and the first level of the intra-process servlet and Enterprise JavaBeans (EJB) call (for example, when an inbound servlet forwards to a servlet and an inbound EJB calls another EJB). Other intra-process calls like naming and service integration bus (SIB) are not enabled at this level
      3. Debug
        1. Provides detailed instrumentation data, including response times for all intra-process servlet and Enterprise JavaBeans (EJB) calls.
        2. Provides detailed instrumentation data, including response times for all intra-process calls.  Note: Requests to servlet filters will only be instrumented at this level.
    4. Check the box under "Request Metrics Destination" labeled "Application Response Measurement (ARM) agent".
    5. Select Agent Type ARM40.
    6. type in "com.ibm.tivoli.transperf.arm4.transaction.Arm40TransactionFactory" in the edit box labeled "ARM transaction factory implementation class name".
  2. Set a custom property (Application Servers->server1->ProcessDefinition->Java Virtual Machine -> Custom Properties) of ws.ext.dirs equal to the values below ( which will include the armjni4.jar file) – Key is to have ws.ext.dirs point to where the armjni4.jar file is located at.
  3. You also have to set your LIBRARY PATH before starting WebSphere to point to the ITM framework libraries, the ARM libraries, and the TTAPI libraries as noted below.

ITCAM for Transactions 7.1 only

    1. Setup websphere to include the armjni4.jar file in it's library path. $ITMHOME defaults to c:\ibm\itm for windows and /opt/IBM/ITM/ for unix.
      1. Windows - set ws.ext.dirs $ITMHOME\tmaitm6\tusupport
      2. Linux - $ITMHOME/li6263/tu/tusupport
      3. AIX - $ITMHOME/aix533/tu/tusupport/
      4. HPUX - $ITMHOME/hp11/tu/tusupport/
      5. Solaris - $ITMHOME/sol293/tu/tusupport/
    2. Unix only, windows does this during installation: Set CANDLE_HOME to the ITM base installation directory. This is normally /opt/IBM/ITM/.
    3. Set your LD_LIBRARY_PATH  to include the ARM libraries (before running ./startServer.sh on unix to start Websphere)
      1. Windows - You can skip this step since ITM automatically includes c:\ibm\itm\tmaitm6\ in your system path. You might need to reboot for it to take effect if you haven't rebooted since you first installed ITM framework.
      2. Linux    - Set your LD_LIBRARY_PATH=  $ITMHOME/li6263/tu/tusupport:$ITMHOME/li6263/tu/lib/:$ITMHOME/tmaitm6/lib/li6263/
      3. AIX      - Set your LIBPATH=  $ITMHOME/aix533/tu/tusupport:$ITMHOME/aix533/tu/lib/:$ITMHOME/tmaitm6/aix533/lib/
      4. HPUX    - Set your SHLIB_PATH= $ITMHOME/hp11/tu/tusupport/:$ITMHOME/hp11/tu/lib/:$ITMHOME/tmaitm6/hp11/lib/
      5. Solaris  - Set your LD_LIBRARY_PATH= $ITMHOME/sol293/tu/tusupport/:$ITMHOME/sol293/tu/lib/:$ITMHOME/tmaitm6/sol283/lib/

 

ITCAM for RT 6.2

    1. Setup websphere to include the armjni4.jar file in it's library path. $ITMHOME defaults to c:\ibm\itm for windows and /opt/IBM/ITM/ for unix.
      1. Windows - set ws.ext.dirs $ITMHOME\tmaitm6\t4\lib
      2. Linux - $ITMHOME/li6243/kt4/lib/
      3. AIX - $ITMHOME/aix51/kt4/lib/
      4. HPUX - $ITMHOME/ hpx1111/kt4/lib/
      5. Solaris - $ITMHOME/ sol283/kt4/lib/
    2. Set your LD_LIBRARY_PATH  to include the ARM libraries (before runing ./startServer.sh on unix)
      1. Windows - You can skip this step since ITM automatically includes c:\ibm\itm\tmaitm6\ in your system path. You might need to reboot for it to take effect if you haven't rebooted since you first installed ITM framework.
      2. Linux    - Set your LD_LIBRARY_PATH=  $ITMHOME/li6243/kt4/lib/:$ITMHOME/tmaitm6/li6243/lib/
      3. AIX      - Set your LIBPATH=  $ITMHOME/aix51/kt4/lib/:$ITMHOME/tmaitm6/aix51/lib/
      4. HPUX    - Set your SHLIB_PATH= $ITMHOME/hpx1111/kt4/lib/:$ITMHOME/tmaitm6/hpx1111/lib
      5. Solaris  - Set your LD_LIBRARY_PATH= $ITMHOME/sol283/kt4/lib/:$ITMHOME/tmaitm6/sol283/lib/

ITCAM for RTT 5.3, 6.0, 6.1 only 

  1. Setup websphere to include the armjni4.jar file in it's library path. $MAHOME defaults to c:\Program files\IBM\Tivoli\MA for windows and /opt/IBM/tivoli/MA for unix.
    1. ws.ext.dirs=$MAHOME\lib
  2. Set your LD_LIBRARY_PATH  to include the ARM libraries
    1. Windows – set your PATH to include $MAHOME\bin\w32-ix86\SYSTEM32\
    2. Linux x86- set LD_LIBRARY_PATH to $MAHOME/bin/linux-ix86/USRLIB/
    3. Linux PPC - set LD_LIBRARY_PATH to $MAHOME/bin/linux-ppc/USRLIB/
    4. Linux s390 - set LD_LIBRARY_PATH to $MAHOME/bin/linux-s390/USRLIB/
    5. AIX - set LIBPATH to $MAHOME/bin/aix4-r1/USRLIB/
    6. HPUX - set SHLIB_PATH to $MAHOME/bin/hpux10/USRLIB/
    7. OS/400 - set LIBPATH to $MAHOME/bin/os400/USRLIB/
    8. Solaris2 - set LD_LIBRARY_PATH to $MAHOME/bin/solaris2/USRLIB/

 

Required for All Versions

  1. Configure request metrics
    1. Detail Level you want (Monitoring and Tuning -> Request Metrics)
      The detail level you want:
      1. HOPS – Entry and exit only. Lowest overhead and only gives overall transaction performance.
      2. Performance_DEBUG – Medium overhead and higher detail. Includes Session Beans etc.
      3. DEBUG – Highest overhead and the most detail. Gives Entity bean get/set timings
    2. Set the Request metrics destination to ARM agent
    3. Set the agent type to ARM4
    4. Set the ARM factory to com.ibm.tivoli.transperf.arm4.transaction.Arm40TransactionFactory
  2. To enable correlator passing to DB2 (required for DB2 to issue ARM calls) do the following
    define this custom JVM property: com.ibm.websphere.pmi.reqmetrics.PassCorrelatorToDB to true;
    To set custom properties, you can either specify the command as a -D option to the Java™ command, or connect to the administrative console and navigate to the Java virtual machine custom properties panel:
    Application server Servers > Application Servers > server1, and then, under Server Infrastructure, click Java and Process Management > Process Definition > Java Virtual Machine > Custom Properties
    Custom Properties Documentation

  3. Restart websphere.
  4. Websphere should now be issuing ARM calls when you navigate through it's servlets. Additionally it should be passing correlators to DB2.

   

Step 3: Configure IHS

Setting up IHS to issue ARM calls is pretty easy, after configuring Websphere all you need to do is regenerate and and redeploy your IHS plugin configuration and it will be configured to issue ARM calls.

 

Step 4: Configure DB2 for ARM support

    DB2 register with ARM if it finds a libarm4.dll (.a/.so) in it's LIBPATH. In order to issue actual start/stop calls for transactions it requires a correlator be passed in with the JDBC connection, which we configured above inside of WAS. To configure the DB2 LIBPATH issue the following command from within the DB2 environment:

db2set DB2LIBPATH=<libarm4.dll directory location>

Where <libarm4.dll directory location> is equal to one of the paths below (

  1. ITCAM for Transactions 7.1 – $ITMHOME defaults to c:\ibm\itm for windows and /opt/IBM/ITM/ for unix.
    1. Windows - You can skip this step since ITM automatically includes c:\ibm\itm\tmaitm6\ in your system path. You might need to reboot for it to take effect if you haven't rebooted since you first installed ITM framework.
    2. Linux    - $ITMHOME/li6263/tu/tusupport:$ITMHOME/li6263/tu/lib/:$ITMHOME/tmaitm6/lib/li6263/
    3. AIX      - $ITMHOME/tmaitm6/aix533/lib/
    4. HPUX    - $ITMHOME/hp11/tu/tusupport/:$ITMHOME/hp11/tu/lib/:$ITMHOME/tmaitm6/hp11/lib/
    5. Solaris  - $ITMHOME/sol293/tu/tusupport/:$ITMHOME/sol293/tu/lib/:$ITMHOME/tmaitm6/sol293/lib/
  2. ITCAM for RT 6.2  – $ITMHOME defaults to c:\ibm\itm for windows and /opt/IBM/ITM/ for unix.
    1. Windows - $ITMHOME\tmaitm6\
    2. Linux - $ITMHOME/li6243/t4/lib/:$ITMHOME/tmaitm6/li6243/lib/
    3. AIX - $ITMHOME/aix51/t4/lib/:$ITMHOME/tmaitm6/aix51/lib/
    4. HPUX - $ITMHOME/ hpx1111/t4/lib/:$ITMHOME/tmaitm6/hpx1111/lib/
    5. Solaris - $ITMHOME/sol283/t4/lib/:$ITMHOME/tmaitm6/sol283/lib/
  3. ITCAM for RTT 5.3, 6.0, 6.1 - $MAHOME defaults to c:\Program files\IBM\Tivoli\MA for windows and /opt/IBM/tivoli/MA for unix.
    1. Windows - $MAHOME\bin\w32-ix86\SYSTEM32\ AND $MAHOME\lib
    2. Linux x86- $MAHOME\bin\linux-ix86\USRLIB\ AND $MAHOME\lib
    3. Linux PPC - $MAHOME/bin/linux-ppc/USRLIB
    4. Linux s390 - $MAHOME/bin/linux-s390/USRLIB
    5. AIX - $MAHOME/bin/aix4-r1/USRLIB/
    6. HPUX - $MAHOME/bin/hpux10/USRLIB/
    7. OS/400 - $MAHOME/bin/os400/USRLIB
    8. Solaris - $MAHOME/bin/solaris2/USRLIB/

Posted by bpatters on Tuesday, November 25, 2008 3:01 PM
Permalink | Comments (2) | Post RSSRSS comment feed

Working with Image Metadata in .NET 3.0 Part I

Working with image metadata has always been pretty painful. There are several standards out there, with alot of overlap and data conversion to/from the meta data to consumable values is usually required. There have been numerous blogs and code samples for working with metadata in .NET 2.0, so I'm only going to focus on using the latest .NET 3.0.

In .NET 3.0 accessing basic image metadata is very simple.

First get the System.Windows.Media.Imaging.BitmapSource:

   1: public static BitmapSource GetBitmapSource(string filename)
   2: {
   3:     BitmapSource rv = null;
   4:     BitmapDecoder decoder;
   5:     if (File.Exists(filename))
   6:     {
   7:         using (FileStream fs = new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Read))
   8:         {
   9:             decoder = BitmapDecoder.Create(fs, BitmapCreateOptions.None, BitmapCacheOption.OnLoad);
  10:  
  11:             if (decoder != null)
  12:             {
  13:                 rv = decoder.Frames[0];
  14:             }
  15:  
  16:             fs.Close();
  17:         }
  18:     }
  19:  
  20: }

Next you can pull out all of the metadata into a Dictionary<string,string> using something simple like:

   1: public const string METADATA_TITLE = "Title";
   2: public const string METADATA_SUBJECT = "Subject";
   3: public const string METADATA_RATING = "Rating";
   4: public const string METADATA_LOCATION = "Location";
   5: public const string METADATA_KEYWORDS = "Keywords";
   6: public const string METADATA_FORMAT = "Format";
   7: public const string METADATA_DATETAKEN = "DateTaken";
   8: public const string METADATA_COPYRIGHT = "Copyright";
   9: public const string METADATA_COMMENT = "Comment";
  10: public const string METADATA_CAMERAMODEL = "CameraModel";
  11: public const string METADATA_CAMERAMANUFACTURER = "CameraManufacturer";
  12: public const string METADATA_AUTHOR = "Author";
  13: public const string METADATA_APPLICATIONNAME = "ApplicationName";
  14: public static void GetImageMetadata(Dictionary<string, string> result, BitmapSource bs)
  15: {
  16:  
  17:     if (bs != null)
  18:     {
  19:  
  20:         BitmapMetadata meta = bs.Metadata as BitmapMetadata;
  21:         if (meta.Title != null)
  22:         {
  23:             result.Add(METADATA_TITLE, meta.Title);
  24:         }
  25:         if (meta.Subject != null)
  26:         {
  27:             result.Add(METADATA_SUBJECT, meta.Subject);
  28:         }
  29:  
  30:         result.Add(METADATA_RATING, meta.Rating.ToString());
  31:         if (meta.Location != null)
  32:         {
  33:             result.Add(METADATA_LOCATION, meta.Location);
  34:         }
  35:         if (meta.Format != null)
  36:         {
  37:             result.Add(METADATA_FORMAT, meta.Format);
  38:         }
  39:         if (meta.DateTaken != null)
  40:         {
  41:             result.Add(METADATA_DATETAKEN, meta.DateTaken);
  42:         }
  43:         if (meta.Copyright != null)
  44:         {
  45:             result.Add(METADATA_COPYRIGHT, meta.Copyright);
  46:         }
  47:         if (meta.Comment != null)
  48:         {
  49:             result.Add(METADATA_COMMENT, meta.Comment);
  50:         }
  51:         if (meta.CameraModel != null)
  52:         {
  53:             result.Add(METADATA_CAMERAMODEL, meta.CameraModel);
  54:         }
  55:         if (meta.CameraManufacturer != null)
  56:         {
  57:             result.Add(METADATA_CAMERAMANUFACTURER, meta.CameraManufacturer);
  58:         }
  59:         StringBuilder keywords = new StringBuilder();
  60:         if (meta.Keywords != null)
  61:         {
  62:             foreach (string s in meta.Keywords)
  63:             {
  64:                 keywords.Append(s).Append(" ");
  65:             }
  66:             result.Add(METADATA_KEYWORDS, keywords.ToString().Trim());
  67:         }
  68:         if (meta.ApplicationName != null)
  69:         {
  70:             result.Add(METADATA_APPLICATIONNAME, meta.ApplicationName);
  71:         }
  72:         if (meta.Author != null)
  73:         {
  74:             StringBuilder authors = new StringBuilder();
  75:             foreach (string s in meta.Author)
  76:             {
  77:                 authors.Append(s).Append(",");
  78:             }
  79:             result.Add(METADATA_AUTHOR, authors.ToString().TrimEnd(new char[] { ',' }));
  80:         }
  81:  
  82:     }
  83: }

As you can see in the code .NET 3.0 provides some really useful convenience methods for accessing image metadata. You will also notice that the Keywords and Author properties are collections and can have multiple values. More on that later.

 

The above is fine if those are the only metadata fields you wish to access. If you want to access all of the metadata fields you need to use the new Query interface:

   1: BitmapMetadata meta = bs.Metadata;
   2: // to obtain the camera manufacturer
   3: // check if the data is present, otherwise you will get an exception in GetQuery
   4: if (bs.ContainsQuery("/xmp/tiff:make")) {
   5:     string CameraManufacturer = (string)bs.GetQuery("/xmp/tiff:make");
   6: }
   7: // or you can get the exif Camera Manufacturer
   8: if (bs.ContainsQuery("/app1/ifd/{ushort=271}")) {
   9:     string CameraManufacturer = (string)bs.GetQuery("/app1/ifd/{ushort=271}");
  10: }



Pretty nice. However those query syntaxes really leave alot to be desired. You can also use the following syntax to perform BOTH of the above in a priority order, with the first one called and if not data exists then it calls the second one:

   1: if (meta.ContainsQuery("System.Photo.CameraManufacturer")) {
   2:     string CameraManufacturer = (string)meta.GetQuery("System.Photo.CameraManufacturer");
   3: }


You can find all of the "System" query documentation at the following URL: http://msdn2.microsoft.com/en-us/library/bb643802.aspx
*NOTE: I recently opened a defect against microsoft for these fields, it appears this works for everything except those of type RATIONAL.

The documentation is for C/C++ code, however you can translate it into equivalent c# pretty easily.

One little quirk is that the code doesn't necessarily return very easy to work with data types. A good example of this is the System.Photo.DateTaken query returns a FILETIME object. You can convert this to a datetime object using:

 

   1: System.Runtime.InteropServices.ComTypes.FILETIME ft = (System.Runtime.InteropServices.ComTypes.FILETIME)_Value; 
   2:  
   3: DateTime time; 
   4:  
   5: long ticks = 0; 
   6:  
   7:  
   8:  
   9: ticks = ((long)ft.dwHighDateTime) << 32; 
  10:  
  11: += ft.dwLowDateTime; 
  12:  
  13: time = DateTime.FromFileTimeUtc(ticks); 

.NET 3.0 also allows you to modify these values using SetQuery, this will be the topic of Part II.


Posted by bpatters on Thursday, December 06, 2007 8:45 AM
Permalink | Comments (3) | Post RSSRSS comment feed

ITCAM for RT 6.2 and ARM instrumentation debugging.

Turning on tracing for the ITCAM ARM DLL is now easier than ever.

Client Application Tracker Agent

Goto the $ITMHOME/tmaitm6/arm/log/cat directory do one of the following:

  1. Create a file named debug_all.txt - This turns on DLL level tracing for all processes.
  2. Create a file named debug_<pid>.txt – This turns on DLL level tracing only for the specified process.

This turns on debugging until you delete the file, and then the tracing turns off.

Robotic Agent

Goto the $ITMHOME/tmaitm6/arm/log/kt6 directory do one of the following:

  1. Create a file named debug_all.txt - This turns on DLL level tracing for all processes.
  2. Create a file named debug_<pid>.txt – This turns on DLL level tracing only for the specified process.

This turns on debugging until you delete the file, and then the tracing turns off. Be aware that this will incur significant overhead and only leave it on as long as you need it.

General Notes

If both agents are on the same machine, then you will use the CAT instructions for all ARM applications except our robotic agents.

All logging will goto (ensure the directories exist before you turn logging on, or you won't get any logging).

Windows:

C:\program files\ibm\tivoli\common\bwm\logs\trace-armdebug.log

Unix:

/opt/ibm/tivoli/common/bwm/logs/trace-armdebug.log

 

Important things to keep in Mind

  • Also keep in mind that the files sizes are not limited and do not rollover, so you will need to turn off tracing and delete the files when you are done.
  • Tracing every ARM call will incur significant overhead and you should only leave it on as long as you need it.

Categories: ARM
Posted by bpatters on Wednesday, October 24, 2007 4:57 PM
Permalink | Comments (0) | Post RSSRSS comment feed

Configuring DB2 and Websphere to Issue ARM calls to ITCAM

Probably the most common question I get asked is "How do I configure Websphere and/or DB2 to issue ARM calls?". Below is the answer, enjoy!

   

General Requirements

   

  1. DB2 Distributed Version 8.2 (or 8.1 FP11)
    1. Only non-zos DB2 8.2+ supports ARM, and it supports ARM v4
  2. Websphere Application Server 5.1 or higher
    1. Only Sebsphere can pass correlators to DB2, and DB2 will not issue ARM calls unless a correlator is received for the connection.

Step 1: (RT 6.2 only )Install the Client Application Monitoring Agent

    The CAT agent is the agent that supports Generic ARM instrumentation. Installing it automatically installs support for all ARM instrumented applications (t4 is it's prefix as you will see in paths below).

Step 2: Configure Websphere

  1. Set a custom property (Application Servers->server1->ProcessDefinition->Java Virtual Machine -> Custom Properties) of ws.ext.dirs equal to the values below ( which will include the armjni4.jar, armjni4.dll and libarm4.dll files. ) – Key is to have ws.ext.dirs point to where the armjni4.jar file is located at.

ITCAM for RT 6.2 and above only 

    1. Setup websphere to include the armjni4.jar file in it's library path. $ITMHOME defaults to c:\ibm\itm for windows and /opt/IBM/ITM/ for unix.
      1. Windows - set ws.ext.dirs $ITMHOME\tmaitm6\t4\lib
      2. Linux - $ITMHOME/li6243/kt4/lib/
      3. AIX - $ITMHOME/aix51/kt4/lib/
      4. HPUX - $ITMHOME/ hpx1111/kt4/lib/
      5. Solaris - $ITMHOME/ sol283/kt4/lib/
    2. Set your LD_LIBRARY_PATH  to include the ARM libraries (before runing ./startServer.sh on unix)
      1. Windows - You can skip this step since ITM automatically includes c:\ibm\itm\tmaitm6\ in your system path. You might need to reboot for it to take effect if you haven't rebooted since you first installed ITM framework.
      2. Linux    - Set your LD_LIBRARY_PATH=  $ITMHOME/li6243/kt4/lib/
      3. AIX      - Set your LIBPATH=  $ITMHOME/aix51/kt4/lib/
      4. HPUX    - Set your SHLIB_PATH= $ITMHOME/hpx1111/kt4/lib/
      5. Solaris  - Set your LD_LIBRARY_PATH= $ITMHOME/sol283/kt4/lib/

 

ITCAM for RTT 5.3, 6.0, 6.1 only 

  1. Setup websphere to include the armjni4.jar file in it's library path. $MAHOME defaults to c:\Program files\IBM\Tivoli\MA for windows and /opt/IBM/tivoli/MA for unix.
    1. ws.ext.dirs=$MAHOME\lib
  2. Set your LD_LIBRARY_PATH  to include the ARM libraries
    1. Windows – set your PATH to include $MAHOME\bin\w32-ix86\SYSTEM32\
    2. Linux x86- set LD_LIBRARY_PATH to $MAHOME/bin/linux-ix86/USRLIB/
    3. Linux PPC - set LD_LIBRARY_PATH to $MAHOME/bin/linux-ppc/USRLIB/
    4. Linux s390 - set LD_LIBRARY_PATH to $MAHOME/bin/linux-s390/USRLIB/
    5. AIX - set LIBPATH to $MAHOME/bin/aix4-r1/USRLIB/
    6. HPUX - set SHLIB_PATH to $MAHOME/bin/hpux10/USRLIB/
    7. OS/400 - set LIBPATH to $MAHOME/bin/os400/USRLIB/
    8. Solaris2 - set LD_LIBRARY_PATH to $MAHOME/bin/solaris2/USRLIB/

 

Required for All Versions

  1. Configure request metrics
    1. Detail Level you want (Monitoring and Tuning -> Request Metrics)
      The detail level you want:
      1. HOPS – Entry and exit only. Lowest overhead and only gives overall transaction performance.
      2. Performance_DEBUG – Medium overhead and higher detail. Includes Session Beans etc.
      3. DEBUG – Highest overhead and the most detail. Gives Entity bean get/set timings
    2. Set the Request metrics destination to ARM agent
    3. Set the agent type to ARM4
    4. Set the ARM factory to com.ibm.tivoli.transperf.arm4.transaction.Arm40TransactionFactory
  2. To enable correlator passing to DB2 (required for DB2 to issue ARM calls) do the following
    define this custom JVM property: com.ibm.websphere.pmi.reqmetrics.PassCorrelatorToDB to true;
    To set custom properties, you can either specify the command as a -D option to the Java™ command, or connect to the administrative console and navigate to the Java virtual machine custom properties panel:
    Application server Servers > Application Servers > server1, and then, under Server Infrastructure, click Java and Process Management > Process Definition > Java Virtual Machine > Custom Properties
    Custom Properties Documentation

  3. Restart websphere.
  4. Websphere should now be issuing ARM calls when you navigate through it's servlets. Additionally it should be passing correlators to DB2.

   

Step 3: Configure DB2 for ARM support

    DB2 register with ARM if it finds a libarm4.dll (.a/.so) in it's LIBPATH. In order to issue actual start/stop calls for transactions it requires a correlator be passed in with the JDBC connection, which we configured above inside of WAS. To configure the DB2 LIBPATH issue the following command from within the DB2 environment:

db2set DB2LIBPATH=<libarm4.dll directory location>

Where <libarm4.dll directory location> is equal to one of the paths below:

  1. ITCAM for RT 6.2 and above – $ITMHOME defaults to c:\ibm\itm for windows and /opt/IBM/ITM/ for unix.
    1. Windows - $ITMHOME\tmaitm6\
    2. Linux - $ITMHOME/li6243/t4/lib/
    3. AIX - $ITMHOME/aix51/t4/lib/
    4. HPUX - $ITMHOME/ hpx1111/t4/lib/
    5. Solaris - $ITMHOME/sol283/t4/lib/
  2. ITCAM for RTT 5.3, 6.0, 6.1 - $MAHOME defaults to c:\Program files\IBM\Tivoli\MA for windows and /opt/IBM/tivoli/MA for unix.
    1. Windows - $MAHOME\bin\w32-ix86\SYSTEM32\ AND $MAHOME\lib
    2. Linux x86- $MAHOME\bin\linux-ix86\USRLIB\ AND $MAHOME\lib
    3. Linux PPC - $MAHOME/bin/linux-ppc/USRLIB
    4. Linux s390 - $MAHOME/bin/linux-s390/USRLIB
    5. AIX - $MAHOME/bin/aix4-r1/USRLIB/
    6. HPUX - $MAHOME/bin/hpux10/USRLIB/
    7. OS/400 - $MAHOME/bin/os400/USRLIB
    8. Solaris - $MAHOME/bin/solaris2/USRLIB/

Updated: 10/25/2007 – Corrected path windows for ws.ext.dirs and where to set the custom properties.
Updated: 6/5/2008 - setting java.library.path doesn't work, you have to manually set your library path before starting websphere on unix.


Posted by bpatters on Tuesday, October 23, 2007 2:55 PM
Permalink | Comments (1) | Post RSSRSS comment feed

WPF Challenge to the Experts...

I have a simple challenge for all the WPF experts out there...

 

Pretend that XAML and XBAPS were a replacement for HTML and attempt to create a website purely using:

  1. XBAPS
  2. Loose Xaml
  3. Loose image files referenced from Xbaps/Xaml.
  4. Rest and Webservice style server side handlers for post/get type interaction between the client/server.

Basic website design guidelines would be something like:

  • Share images as much as possible to minimize download times
  • Provide as much content as you possibly can in an indexable format (IE loose Xaml etc).
  • Make small changes not require large deployments or large downloads

 

You might ask yourself why you would do this, after all WPF/XAML only works on windows platforms and in Internet Explorer. Some might ask why I don't just make this challenge for Silverlight instead.

While I believe Silverlight to be an incredibly powerful up and coming technology, I personally see it more as a competitor to flash and not for HTML. Which basically means it's going to be used for:

  1. Advertisements.
  2. Rich interactive applications (well by current web standards it's mostly going to make things easier and open a few new possibilities).
  3. Small standalone applications

However there are some of us our there, myself at least, that are aching for a HTML replacement technology. HTML is ancient by technology standards. HTML has really come a long way since the revolutionary 1.0 version, yet it's still a really clunky way to develop interactive applications and publicize content.

Currently XAML/XBAPS are not cross platform and hence will not be a serious competitor for HTML in the near future. However, Silverlight has proven that this is not a necessity and that in the foreseeable future this could change through the implementation of a Mono based WPF implementation that brings WPF/Xbaps to the cross-platform world.

Try the above challenge, I think you'll be both pleasantly surprised how nice it is to develop web content in XAML versus html, however you will be surprised at how unexplainably hard it still is.

Few issues to give you a taste of the challenges:

Pretend your website is organized something like:

.
./images
./actions/
./assemblies/
./xaml/
..

Scenario: Try and reference loose images on your website from your xbaps xaml.

<Image Source="images/logo.png"/>

Problem: You will notice that it doesn't work because the xbap only searches it's resources and assembly!

Solution: You need to use the syntax: "pack://siteoforigin:,,,/images/logo.png"

Scenario: You've directed the user to a loose xaml file index.xaml and your website gets busy and your webserver returns an error accessing an Image that xaml file loads.

Problem: An error occurs and Nothing is rendered.

Solution:  You must compile your web pages to xbaps in order to handle ANY errors, even simple url not available for resources. There is no silent failure for certain scenarios. Imagine if a website failed to load if even one of the spacer images wasn't available!

There are many more issues which I've noticed so far, as I've personally undertaken the challenge myself to build an entire website using zero html, 100% xbaps, loose Xaml and server side services.

Once I get a bit more content on the website I'll publish it's URL...

Current major issuing I'm pursuing is:

How to load DLL assemblies dynamically and then loading loose Xaml files that bind to event handlers in those assemblies.


Posted by bpatters on Wednesday, July 11, 2007 6:06 PM
Permalink | Comments (0) | Post RSSRSS comment feed

Facebook image uploader tidbit

I rewrote the previous example to be a bit simpler such that it basically is just an application you can use to select a directory and upload all of the images in it, and optionally all subdirectories, into an album that you describe. It will then split the images up into groups of 60, the maximum images per album, and then create as many albums as necessary to upload all of the images ( Appending "Part x" as necessary to the album name). If your like me and have a lot of pictures, this is a pretty useful utility. I ran into a hidden limit however when trying to upload 1152 images from my backpacking trip. Facebook only allows you to have a maximum of 720 pictures that are in the approval queue, at which point it returns an error to your application. So I had to go delete all of the 20 albums from a previous upload, then re-upload the watch the upload to approve the albums a they were uploaded to prevent this limit from being reached. I'll post the application with source code soon.


Categories: Facebook
Posted by bpatters on Monday, June 18, 2007 5:26 PM
Permalink | Comments (0) | Post RSSRSS comment feed

Writing Facebook Applications

Facebook has opened up it's Social website to third-party developers http://developers.facebook.com/

Additionally they have partnered with Microsoft to make developing applications extremely simple

http://msdn.microsoft.com/vstudio/express/showcase/
 

Last night I decided to take this Facebook toolkit for a spin, by first converting a very simple Windows Presentation Foundation (WPF) application I'd written to automatically synchronize your My Pictures and Shared Pictures folders with Facebook.

The below process is what I did.

  1. Download the facebook toolkit from the Microsoft link above.
  2. Create your project type per normal. (WPF/Website etc!) I used WPF in this example
  3. Add the facebook/facebook.csproj project to your solution (yes you can add just a reference to the facebook.dll also if you wish, but i didn't for reasons below).

Once you've done the above it's as simple as adding:

   1: using Facebook;
   2: using Facebook.Components;
   3: FacebookService fbService;
   4:  
   5: fbService = new FacebookService();
   6: fbService.IsDesktopApplication = true;  // set this to true for desktop applications. 
   7:  
   8: fbService.ApplicationKey = "[your key here]";
   9: fbService.Secret = "[your secret here]"; 
  10:  
  11: Collection<Album> tAlbums = fbService.GetPhotoAlbums();   // Make the call to a function you wish to use 
  12:  

If your not already logged in it will automatically popup a window like the following:  

Untitled_thumb

The login screen is automatic, and the function you called while the user was not logged in will not return until the user has successfully logged in or cancelled the login process.

Very easily done.

Next once I've gotten all of the albums it's a simple matter to get all the photo's using:

   1: Collection<Photo> tPhotos;
   2:  
   3: foreach (Album ta in tAlbums)
   4:  {
   5:        fbAlbums.Add(ta.Name, ta);
   6:        if (getPhotos)
   7:        {
   8:          tPhotos = fbService.GetPhotos(ta.AlbumId); // gets all of the photo's for the album.
   9:          fbPhotos.Add(ta.Name, tPhotos);                 // global Dictionary<string,Collection<Photo>> where i store album --> photo reference.
  10:        }
  11:  }

Finally to figure out which Photo's I want to upload I scan the folders "My Pictures" and "Shared Pictures" using the following methods to get the directories:

   1: // Shared Pictures folder path
   2: // You might get "C:\Documents and Settings\All Users\Documents\My Pictures" 
   3: // Here, "My Pictures" is the real name of the folder "Shared Pictures", where "Shared Pictures"
   4: // is only the alias of "My Pictures" and can't be retrieved.
   5: string shrpic = (string)Registry.GetValue(key.Name, "CommonPictures", ""); 
   6:  
   7: lbDirectories.Items.Add(new DirectoryInfo(Environment.GetFolderPath(Environment.SpecialFolder.MyPictures))); 
   8:  
   9: if (shrpic != null && shrpic.Length > 0)
  10: {
  11:    lbDirectories.Items.Add(new DirectoryInfo(shrpic));
  12: } 
  13:  

Then using a simple recursive function to get the list of picture files (not shown here for brevity).

 

Now the next step is to compare what pictures I have on the local machine to what's one the server so I do:

Oops Facebook doesn't store the original filename!! So there technically is no way to figure out which local pictures match which server pictures.

This was a major stumbling block, as I originally didn't want to have to store any information locally on the users computer. Alas you must manually keep track of what photo's you've uploaded previously and what their photoID is (details coming later).

 

Next what I do is loop through all of the pictures and upload them using:

   1: foreach (string aname in dNewImages.Keys)
   2: {
   3:     if (fbAlbums.ContainsKey(aname) == false)  // if the album doesn't exist on the server then create it.
   4:     {
   5:         fbService.CreateAlbum(aname, "", "");    // create the album
   6:         getAlbums(false);                                    // refresh my list of albums, You could remove this step by doing something similar to what i do later.
   7:     }
   8:     Collection<CFileInfo> aImages = dNewImages[aname];   // list of all the images for this album
   9:     XmlDocument rv = null;
  10:     long pid;
  11:     foreach (CFileInfo f in aImages)   // loop through the images.
  12:     {
  13:         string tempFile = System.IO.Path.GetTempFileName();  // create a temporary file
  14:         FileInfo fi = new FileInfo(tempFile);
  15:         CImageUtils.resizeImageAndSave(f.File.FullName,tempFile,604,453);   // resize the image
  16:         rv = fbService.UploadPhoto(fbAlbums[aname].AlbumId,fi);      // upload the image to facebook!
  17:         fi.Delete();
  18:         pid = FacebookUtils.getUploadedPhotoID(rv);   // get the photo id for the new image. 
  19:  
  20:         dUploadedImages.Add(f.File.FullName,pid.ToString());  // add a mapping of the filename to the photo id.
  21:     
  22:     }
  23: } 
  24:  

The primary problem with the above is shown in the purple line, if you look at your copy of FacebookService the UploadPhoto does not return a result! So there is no way to determine, the result of the call. We need this result because we need to be able to determine what the new Photo's ID is. Now you'll see why I added the Facebook project to my solution, so I could jump into the source code and fix this small issue. If you jump to this function you will see that it calls:

ExecuteApiUpload(uploadFile, parameterList);

 

This method Does return a result, and the result is an xml document that looks like the following:


 

   1: <?xml version="1.0" encoding="UTF-8" ?> 
   2: <photos_upload_response xmlns="http://api.facebook.com/1.0/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://api.facebook.com/1.0/ http://api.facebook.com/1.0/facebook.xsd">
   3: <pid>2958831660596058150</pid> 
   4: <aid>2958831660595942926</aid> 
   5: <owner>688906680</owner> 
   6: <src>http://photos-870.ak.facebook.com/photos-ak-sf2p/v73/140/31/688906680/s688906680_120870_3345.jpg</src> 
   7: <src_big>http://photos-870.ak.facebook.com/photos-ak-sf2p/v73/140/31/688906680/n688906680_120870_3345.jpg</src_big> 
   8: <src_small>http://photos-870.ak.facebook.com/photos-ak-sf2p/v73/140/31/688906680/t688906680_120870_3345.jpg</src_small> 
   9: <link>http://www.facebook.com/photo.php?pid=120870&id=688906680</link> 
  10: <caption /> 
  11: <created>1181012493</created> 
  12: </photos_upload_response>

From here you can see that the tag <PID> contains the newly created Photo ID. What we need to do then is modify the UploadPhoto method to return an XmlDocument that we get from the ExecuteApiUpload method call. I changed the function and then wrote the following function to extract the photoid.

   1: public static long getUploadedPhotoID(XmlDocument doc)
   2:        {
   3:  
   4:            XmlNamespaceManager xnm = new XmlNamespaceManager(doc.NameTable);
   5:            xnm.AddNamespace("fb", "http://api.facebook.com/1.0/");
   6:            XmlNode node = doc.SelectSingleNode("/fb:photos_upload_response/fb:pid/text()",xnm);
   7:            return long.Parse(node.Value);          
   8:        }

If you notice here I had to include an XmlNamespaceManager because the default namespace is not blank, otherwise your select will fail.

 

At this point it's just a simple matter of saving a reference of the FileName --> PID into a Dictionary<string,string> and then saving this to a application state file that we can load the next time we run. This works fine as long as the user always only uses our program to upload files, otherwise it's very easy to get duplicates. Unfortunantly there isn't an easy way around this since facebook doesn't save the original image filename.

 

Anyway this was just a simple app to try and testout the new facebook api's that microsoft provides. Overall I'd give them a A+ for simplicity of use, however they left out quite a few obvious pieces of required functionality like return codes from the api set. However since they distributed the source it is quite easy to work around that issue.


Categories: Facebook
Posted by bpatters on Friday, June 08, 2007 4:17 AM
Permalink | Comments (2) | Post RSSRSS comment feed