There’s a WCI App For That 4: CardMigrator

In my last post, I talked about the need to update both a cards’ location AND its CRC in the WebCenter Interaction database to migrate cards from one UNC path to another.  Today’s post is about an “App For That“, which is a utility I had written last year but essentially abandoned until Fabien Sanglier’s great tip about the CRC value needing to be changed.

The app is one of those “thrown together” .NET jobs where I was more focused on the need to update tens of thousands of cards for a client, rather than building a pretty and usable UI.  As such there isn’t a whole lot of error checking, and I’m not comfortable sharing the whole code base here – mostly because I’m just embarrassed about how it was hacked together.  But, if you’ve got a need for something like this, drop me a line and hopefully I can help you out or just send you the code as long as you promise not to make fun of me :).

The code is pretty straight-forward:

  1. After entering the connection strings for the API and the DB (since, as mentioned, we haven’t yet found an ALUI / WebCenter API to make the change to the CRC), you click “Load Crawlers”. 
  2. The crawler list shows up in the tree on the left, grouped by Content Source since you’re likely only updating cards based on the NTCWS, and not WWW or Collaboration Server crawlers. 
  3. Clicking on a crawler shows you all the cards associated with that crawler, as well as a bunch of useful metadata. 
  4. From there, you can do a search and replace on the UNC paths for all the cards.  The update process uses the API and Database methods to update the cards and the crawler, so the next time the crawler or Search Update jobs run, no cards are updated since everything matches up – assuming, of course, you’ve already moved the physical files to the new location! 

Some relevant code is after the break; again, drop me a line if you’re looking for more.


        private void btnSearchReplace_Click(object sender, EventArgs e)
        {
            txtDBStatus.Text = "";
            int numCards = lstCards.Items.Count;
            int cardsUpdated = 0;
            int x = 0;
            prgStatus.Maximum = numCards;

            IEnumerator cards = lstCards.Items.GetEnumerator();
            IPTCatalog catalog = session.GetCatalog();
            string cardName="";
            bool needsUpdateBag = false;
            bool needsUpdateProp = false;
            String searchString = txtSearch.Text;
            String replaceString = txtReplace.Text;
            String searchStringEscaped = txtSearch.Text.Replace("\\", "%5C");
            String replaceStringEscaped = txtReplace.Text.Replace("\\", "%5C");

            string oldString, newString, strCardLocation;

            // open a DB connection
            DbConnection oConn = getDBConnection();
            try
            {
                oConn.Open();

                while (cards.MoveNext())
                {
                    ListViewItem lvi = (ListViewItem)cards.Current;
                    string PTC_UNIQUE = lvi.SubItems["PTC_UNIQUE"].Text;
                    int CARD_ID = int.Parse(lvi.SubItems["CARD_ID"].Text);
                    try
                    {
                        needsUpdateProp = false;
                        needsUpdateBag = false;
                        IPTCard card = catalog.OpenCard(CARD_ID, false);
                        cardName = card.GetName();
                        setStatus("Checking " + cardName);

                        // UPDATE PROPERTY BAG
                        IXPPropertyBag bag = card.GetDocumentLocation();
                        oldString = bag.ReadAsString("PTC_UNIQUE");
                        newString = oldString.Replace(searchString, replaceString);
                        strCardLocation = newString;
                        if (!oldString.Equals(newString))
                        {
                            needsUpdateBag = true;
                            bag.Write("PTC_UNIQUE", newString);
                            card.SetDocumentLocation(bag);
                        }

                        // UPDATE URL PROPERTY
                        IPTCardPropertyValues values = card.GetPropertyValues();
                        IPTCardPropertyValue URLProp = values.GetItem(URL_PROP);
                        oldString = URLProp.GetValueAsString();
                        newString = oldString.Replace(searchStringEscaped, replaceStringEscaped);
                        if (!oldString.Equals(newString))
                        {
                            needsUpdateProp = true;
                            URLProp.SetFieldValue(newString);
                        }

                        // UPDATE THE CRC DIRECTLY IN THE DB IF SOMETHING HAS CHANGED
                        if (needsUpdateBag || needsUpdateProp)
                        {

                            int crca = XPCRC.GenerateCRC64(strCardLocation).m_crcA;
                            int crcb = XPCRC.GenerateCRC64(strCardLocation).m_crcB;

                            DbCommand updateComm = oConn.CreateCommand();
                            updateComm.CommandType = CommandType.Text;
                            updateComm.CommandText = "update ptinternalcardinfo set locationcrc_a = " + crca + ", locationcrc_b = " + crcb + " where cardid = " + card.GetObjectID();
                            if (updateComm.ExecuteNonQuery() > 0)
                            {
                                txtDBStatus.Text += "Updated card " + card.GetObjectID() + " with CRCs: " + crca + ", " + crcb + Environment.NewLine;
                            }
                            else
                            {
                                txtDBStatus.Text += "*FAILED updating card " + card.GetObjectID() + " with CRCs: " + crca + ", " + crcb + Environment.NewLine;
                            }

                            cardsUpdated++;
                            lvi.SubItems["STATUS"].Text = "Updating strings " + oldString + " with " + newString;
                            setStatus("Updating " + cardName);
                            card.SetCardSettings(PT_CARD_SETTINGS.PT_CARD_INDEXONSTORE, 1);
                            card.LockObject();
                            card.Store();
                            card.UnlockObject();
                        }
                        else
                        {
                            lvi.SubItems["STATUS"].Text = "no string to replace";
                        }

                    }
                    catch (Exception ex)
                    {
                        lvi.SubItems["STATUS"].Text = "Exception: " + ex.Message;
                        setStatus("Exception updating card " + cardName + ": " + ex.Message);
                    }
                    x++;
                    prgStatus.Value = x;

                }
            }
            catch (Exception e2)
            {
                MessageBox.Show("Unexpected error: " + e2.Message + Environment.NewLine + e2.StackTrace);
            }
            finally {
                try
                {
                    oConn.Close();
                }
                catch (Exception) {}
            }
            prgStatus.Value = 0;
            setStatus("Finished: updated " + cardsUpdated + " out of " + numCards + " cards");
        }

Tags: , ,

One Response to “There’s a WCI App For That 4: CardMigrator”

  1. […] This post was mentioned on Twitter by Geoff Garcia, Webcenter Blogs. Webcenter Blogs said: There’s a WCI App For That 4… http://goo.gl/fb/JfY9f #codingtricks #contentcrawlers #appforthat #crawlers […]

Leave a Reply