Showing posts with label tutorial. Show all posts
Showing posts with label tutorial. Show all posts

Thursday, April 19, 2012

Searching Like a Native

A user in the Yahoo! Intradoc Users forum asked a really interesting question.
He was looking for a way to conduct database specific searches from the user interface in such a way that the database’s native functionality could be leveraged.

Well, let's put on our thinking caps, shall we?...  hmmm...

- I need a way to conduct searches in a more native fashion in UCM.
- I'm not really wanting to bust up my Content Server, because this will be a gnarly change.

The answer is (a drum roll please...) - a Content Server profile.

You might ask, "Have you lost your mind?"  Well, not totally. I've done this type of thing before.

Let me explain. Content Server has basically given you options to conduct queries in lots of ways. You just have to know and use the right flags. Keep in mind that the Content Server search works off a beast called a datasource, which is a partial query that mostly looks for a WHERE clause to execute.

- So your steps (assuming here that the Content Server is configured for full text searching - you'll need the full text box later.):

1. Create a new profile and one profile rule in Configuration Manager. For kicks, make the profile rule a search only profile, on request.




2. In the profile side effects set the following as shown:

<$SearchEngineName="DATABASE"$>
<$SearchQueryFormat="Native"$>




3. Save the rule, and add it to your new profile. Close the admin applet, and go to your newly created profiled search page.

4. Go down into the fulltext box and enter "FREETEXT(dDocTitle, 'weather floodcar')", or the appropriate "native" SQL WHERE clause for the situation and applicable to your database – minus the WHERE keyword.   (I used an IN statement for the example below.)



5. Click “Search”. Voila (or wah-wah-wah), depending on your query.

Your mileage definitely may vary, but it's a neat way to get at some of the more interesting functionality of the underlying database.

Friday, January 21, 2011

UCM 11g: Desktop Integration Suite Walkthrough - Adding custom metadata to Office properties



Here’s a quick post to show the added power of the DesktopTag component which comes bundled with the Desktop Integration Suite.

DIS 11g allows for much more dynamic and flexible handling of native content. One of the mechanisms used to do this is Outside In’s BitLocker SDK (acquired by Stellent in 2006). The containing jar can be located here:

../<middleware_home>/Oracle_ECM_prod/ucm/idc/components/OracleCleanContent/libs/java/CleanContent.jar

This SDK is typically used by UCM to clean content of hidden metadata, revisions, comments, etc; but, in this case, it is being used to embed metadata information into the content’s native format.

The metadata usually embedded by the DesktopTag component are:



  • DISidcName
  • DISdID
  • DIScgiUrl
  • DISProperties
  • DISTaskPaneUrl
  • DISdUser
  • DISdDocName



All of these are what you expect them to be, except the TaskPaneUrl, which is a url to the DESKTOP_DOC_INFO service for the specific document.

These variables work together to determine the validity of the current doc compared to the version currently within the content server. For more information on DIS and its new features, please see:

http://download.oracle.com/docs/cd/E14571_01/doc.1111/e10624/c01_introduction.htm#BABHAEHF
 






Now that we’ve had a quick peak under the covers of DIS, let’s see how we can leverage that for our own custom metadata.




The DesktopTag component sets a number of environmental variables. One of the variables is DesktopTagFieldsCustom, but it’s currently commented out. So let’s create our own component to set this variable.

You can get a look at my sample component here.

This component overrides all values to allow testing, but specifically, focus on the following:


DesktopTagFieldsCustom=xComments,xkeywords(Keywords)

This test implements two different syntax options: standard & special syntax, as defined in the original cfg:
# Special syntax: binderName(propertyName)
# Example: dID(DISMyId) will create a custom property named DISMyID with
# the value of dID.


For our customization, we’re adding xComments and xkeywords to the list of embedded metadata. We want to leverage this metadata, which is managed within the content server, within our native content. I will be demonstrating using Microsoft Word, but this technique should work with any compatible application.




  • To start, let’s create a new blank Word document




  • Now, let’s add some static text.


I have added some static text to the header & body


  • At this time, we'll add a quick part for the keywords. This is a standard Word property.
    • Place the cursor after the "Keywords:" text
    • Click on the Insert Word Ribbon (i.e., the menu tab)
    • Click on  Quick Parts à field










      • Could also shortcut buy using Quick Parts à Document Property à Keywords
    • Click on “DocProperty” in the Field Names list
    • Click on “Keywords” in the Property list
    • Click Ok


  • Note: Nothing appears immediately in the document as there are no keywords assigned

  • Commit doc as new to UCM, applying metadata as it is checked in. specifically the comments and keywords.



  • Open the document from UCM


  •  Note: Nothing appears in the document, but this time it’s specifically due to Microsoft Word not auto-updating Quick Parts
    • Out of the box, Word would require right-clicking and manually updating each field.

  • Now that we have opened the document via DIS, our custom UCM metadata have been applied as Word properties


    • Notice the value of “under review” for the DISCxCo… property
    • Also notice that because we targeted our custom UCM metadata at a standard Word property, it appears in the standard field


  • Let’s add our custom property now:
    • Place the cursor after the “Status:” text in the header
    • Click on the Insert Word Ribbon (i.e., the menu tab)
    • Click on  Quick Parts --> field
    • Click on “DocProperty” in the Field Names list
    • Click on “DISCxCommets” in the Property list
    • Click Ok 



  • Now both of our values are showing in the document 



  • To show the lack of auto update, let’s save the document and update the metadata
    • On the Oracle UCM ribbon, click Check In With Metadata
    • Alter the Comments & keywords 


    • Click Ok
  • Re-open the document from UCM
    • On the Oracle UCM ribbon, click Open
    • Search for your document
    • Select it to be opened

  • Notice that the metadata values did not update automatically.
  • It appears that this is a often encountered issue as Microsoft has put out a support article addressing it.
    • http://support.microsoft.com/kb/832897/en-us
    • We will use the Method 2 workaround, Creating a macro to automatically update the field
    • The step-by-step procedure is listed on Microsoft’s site, so I’ll skip that for now 



  • Save & reopen from UCM

  • Notice that the metadata is applied automatically. 




Thanks it, now we have a word document that receives updates from UCM during each re-open. This ensures that any metadata applied to a document is current during each edit session.


Get a copy of the SenaDIS component here.


Thanks again for reading & I hope you've found some part of this useful and perhaps even reusable.


Disclaimer: The code, opinions, and other content on this page are my own and are not necessarily representative of my employer. There is no expressed support for any code contained herein. Most code supplied within these pages has been created to proof out a specific concept or to show a specific case. No code should be considered production-ready without your own testing and validation.

Monday, November 22, 2010

UCM 11g: Sourcing of metadata fields and/or How to create metadata during component installation





Just wanted to note an interesting and useful new feature of 11g: metadata can now be sourced.

It appears that this functionality is specifically designed to be leveraged by components, but perhaps this will be expanded to metadata created via the Config Manager applet in the future (or perhaps someone will create an enhancement will allow admin access to these values).

This ability is useful for any system where multiple custom, or component,  attributes are in use. The ability to track an attribute back to the component that’s leveraging it allows for better understanding of its intended purpose. This can prevent illogical hijacking of attributes which could potentially confuse programmers and users alike. On the other hand, if it is decided to share an attribute across components, this also can be detailed.

Anything that helps answer the question, “why is this here?”, is useful in my opinion.


As previously mentioned, it appears that there is no admin-level UI to modify this field. To leverage this, I’ll show how the ‘dComponentName’ property can be appended to the standard set of attribute metadata in order to use this feature. 

I’ve created a simple component to demonstrate this functionality. I’ll start by briefly reviewing the functional aspects, then I’ll go into the different features of the component.


The SenaSampleManageMetadata component is an example of a starting template one could use to create components. Some people prefer to work out of the ComponentWizard for editing, modifying, and generally managing their components. I prefer to use Eclipse and my svn to keep a history of each component I create. 

That being the case, I have a few different starting templates I use to jump-start my component building. This component has two useful maintenance features: managing of metadata & tracing information. Side note: I’m working on building an ant build file that will automate the cloning and renaming of the template files into the new template. I also would like it to auto increment the version information (<today’s date> <previous build # + 1).

The first feature will allow for the simultaneous deployment of metadata with their associated components instead of creating a component bundle or manual creation via an IQ/OQ document or implementation notes. Anything that simplifies and streamlines deployment and implementation is typically going to be a step in the right direction.

The second feature is an important step in keeping log files tidy and useful. Developers can easily enable or disable debugging output from their custom components by leveraging custom trace sections. Using custom trace sections will not only allow for easy isolation (e.g., by grepping a tail) of output, but it will ensure that I/O is limited when the trace is disabled. Think about the last project you were on where all code utilized the system trace… it’s not pretty.


Now that the reasons for the maintenance features have been defined, we can discuss how we approach these via component additions. 

The first feature is handled by leveraging a component installation filter. The ComponentWizard creates a starting class that includes a conditional structure for handling multiple filter events within the same class. I’m using the extraAfterServicesLoadInit filter as well as the SenaSampleManageMetadataComponentUninstallFilter filter.

As defined in the template, the extraAfterServicesLoadInit filter is called after the last standard activity of a server side application initialization. These events are triggered as the content server starts during the post-installation restart. This is a good place to manipulate cached data or override standard configuration data. The SenaSampleManageMetadataComponentUninstallFilter filter is called for custom un-installation steps. NOTE: Change the uninstall filter name to have your component name prefix. For example: <ComponentName>CompnentUninstallFilter. This event is triggered after confirmation of component uninstallation via the UCM admin server. I’ve modified the descriptions a bit for added clarity, but they’re basically lifted from the filter template comments.

Code added for the extraAfterServicesLoadInit filter condition:

 else if (param.equals("extraAfterServicesLoadInit"))
    {
      SystemUtils.trace("senasamplemeta", "\n\n\nSenaSampleManageMetadata: Found install filter\n\n\n");
      processMeta(loader, ws, binder, cxt, true);
    }

Code added to the SenaSampleManageMetadataComponentUninstallFilter filter condition:

else if (param.equals("SenaSampleManageMetadataComponentUninstallFilter"))
    {
      SystemUtils.trace("senasamplemeta", "\n\n\nSenaSampleManageMetadata: Found uninstall filter\n\n\n");
      processMeta(loader, ws, binder, cxt, false);
    }

The function created to handle the create/delete of metadata:

protected int processMeta(IdcExtendedLoader idcextendedloader,
      Workspace ws, DataBinder binder,
      ExecutionContext cxt, boolean isInstall)
  {
    SystemUtils.trace("senasamplemeta", "Starting to process custom meta..");

    try
    {
      1: DataResultSet dataresultset = SharedObjects
          .getTable("SenaSampleManageMetadata_Metadata");
      SystemUtils.trace("senasamplemeta", "after get table");
      if (dataresultset != null)
      {
        SystemUtils.trace("senasamplemeta", "table not null");
        dataresultset.first();
        for (; dataresultset.isRowPresent(); dataresultset.next())
        {
          2: Properties properties = dataresultset.getCurrentRowProps();
          String metaDefName = properties.getProperty("dName");
          SystemUtils.trace("senasamplemeta", "retrieved metadata name: " + metaDefName);
          SystemUtils.trace("senasamplemeta", "hasDocMetaDef: " + MetaFieldUtils.hasDocMetaDef(metaDefName));
          3: if (metaDefName == null || metaDefName.length() == 0
              || ( isInstall && MetaFieldUtils.hasDocMetaDef(metaDefName))
              || ( !isInstall && !MetaFieldUtils.hasDocMetaDef(metaDefName)))
            continue;
          try
          {
            SystemUtils.trace("senasamplemeta", "is install: " + isInstall);
            4: if (isInstall)
              MetaFieldUtils.updateMetaDataFromProps(ws, null, properties,metaDefName, true);
            else
              MetaFieldUtils.deleteMetaData(ws, cxt, metaDefName);
            SystemUtils.trace("senasamplemeta", "after Meta call");
          } catch (ServiceException serviceexception)
          {
            SystemUtils.error(serviceexception, (new StringBuilder()).append(
                "Error:").append(metaDefName).append(
                " senasamplemeta -- metadata field was not installed.").toString());
          }
        }

      }
    } catch (Exception exception)
    {
      SystemUtils.error(exception,
          "senasamplemeta: Unable to execute install filter.");
    }
    return 0;
  }

There are four main points of interest:

  1. Instead of hard-coding metadata values, they can be externalized into an UCM static table (see below)
  2. While looping over the rows in the table, this retrieves the property keysets for each row
  3. Verification check: ensure that the current metaField exists; if this is an install request, verify that the metaField doesn’t already exist; if this is an uninstall, verify that the metaField exists 
  4. Choose function based upon install/uninstall

The MetaFieldUtils helper class supplies the heavy lifting by encapsulating the COLLETION_UPDATE_META_TABLE and DEL_METADEF services.
Below is the detail of my static table:
<@table SenaSampleManageMetadata_Metadata@>
<table border=1><caption><strong>

<tr>
      <td>dsdComponentName</td>
      <td>dComponentName</td>
      <td>dsdVersion</td>
      <td>dName</td>
      <td>dCaption</td>
      <td>dType</td>
      <td>dIsRequired</td>
      <td>dIsEnabled</td>
      <td>dIsSearchable</td>
      <td>dIsOptionList</td>
      <td>dOptionListKey</td>
      <td>dOptionListType</td>
      <td>dDefaultValue</td>
      <td>dOrder</td>
      <td>dIsPlaceholderField</td>
      <td>dsdCheckFlag</td>
      <td>dsdDisableOnUninstall</td>
</tr>
<tr>
      <td>SenaSampleManageMetadata</td>
      <td>SenaSampleManageMetadata</td>
      <td>1.0.0</td>
      <td>xSampleMetaField1</td>
      <td>Sample Meta Field 1</td>
      <td>BigText</td>
      <td>0</td>
      <td>1</td>
      <td>1</td>
      <td>0</td>
      <td></td>
      <td></td>
      <td></td>
      <td>25000</td>
      <td>0</td>
      <td></td>
      <td></td>
</tr>
<tr>
      <td>SenaSampleManageMetadata</td>
      <td>SenaSampleManageMetadata</td>
      <td>1.0.0</td>
      <td>xSampleMetaField2</td>
      <td>Sample Meta Field 2</td>
      <td>BigText</td>
      <td>0</td>
      <td>1</td>
      <td>1</td>
      <td>0</td>
      <td></td>
      <td></td>
      <td></td>
      <td>25100</td>
      <td>0</td>
      <td></td>
      <td></td>
</tr>

</table>
<@end@>
After installing this component, you can verify that the metadata has been added:

Uninstalling the component will remove the attributes. Again, this is a POC, whether this is a feature you would want to implement is up to your specific requirements.

Going forward:

This code can be enhanced to include much more functionality. Different datatypes can be introduced and managed. The creation and population of views, drop-down lists (ddl), user attributes, etc can all be handled within this filter. Modification of these variables can also occur. Other possibilities include sharing an existing component attribute. You could check if the attribute exists, then modify the dComponentName attribute by appending your component name to the end of the existing string.

Values could also be maintained via component install strings and/or component configurations which would allow users to review and potentially modify during install. Component configurations can also be configured to be modifiable while the component is installed.



For the second feature, I’ve added a custom trace to the standard ddl so that it’s easily remembered and accessible by developers and admins alike. Remember, just because the initial developer that added the custom trace remembers the exact string doesn’t preclude that the next developer will remember when it comes time to debug … or, the even the initial developer just a few months down the road for that matter…



The table where the custom trace section is defined:
<@table SenaSampleManageMetadataTraceSections@>
<table border=1><caption><strong>SenaSampleManageMetadata Tracing Sections</strong></caption>
<tr>
  <td>itsSection</td>
  <td>itsDescription</td>
  <td>itsDefaultEnabled</td>
</tr>
<tr>
  <td>senasamplemeta</td>
  <td>Sena Sample Manage Metadata Tracing</td>
  <td></td>
</tr>
</table>
<@end@>
This table is merged into IdcTracingSections.


You can find the component here.


I hope you’ve found some part of this useful and perhaps even reusable.

Thanks,
-ryan

edits: 
12/17/2012: updated download link


Disclaimer: The code, opinions, and other content on this page are my own and are not necessarily representative of my employer. There is no expressed support for any code contained herein. Most code supplied within these pages has been created to proof out a specific concept or to show a specific case. No code should be considered production-ready without your own testing and validation.