Showing posts with label CASE Tool. Show all posts
Showing posts with label CASE Tool. Show all posts

Wednesday, July 20, 2011

mclib_case_html_reporter gives erroneous Mandatory? results

The mclib_case_html_reporter is used by Smallworld clients to create an HTML-based report of the CASE tool. The HTML-based format is very helpful for deploying the datamodel information to users who either don't have access to a Smallworld license or do not have the skills to navigate throught the CASE tool.

A customer recently pointed out to me that the Mandatory? flag reported in the HTML report is not always the same as the value reported in the CASE tool. That is problematic in certain situations where users rely on the accuracy of the data in the HTML report to make decisions about how to migrate data in and out of data models. Having good information about the Mandatory property on a field is important for making good decisions about how to default values, etc.

Here is some background on how the pieces work and why the Mandatory? result was inconsistent.

A review of method case_field.mandatory? indicates that there are actually two different ways that a field can be defined as mandatory. If a user explicitly modifies a case_field to be Mandatory=Yes or Mandatory=No, that explicit action will create a join between the sw_gis!case_field object and a sw_gis!case_field_mandatory? record. That sw_gis!case_field_mandatory? record will hold the explicit information about whether the sw_gis!case_field is mandatory or not. But... there are also situations where no such explicit sw_gis!case_field_mandatory? record exists. In that case, method case_field.mandatory? says that as long as the field is a physical field, it should be considered Mandatory.

The mclib_case_html_reporter works by first making an XML dump of all the relevant CASE tables into a large XML file. Then a series of XSLT transformations are done to morph the relevant XML data into suitable HTML representation. It was in this XSLT transformation that I discovered that the XSL file did not take into consideration both "mandatory" scenarios described in case_field.mandatory?.

The fix was to extend the relevant XSL files to include the second "mandatory?" scenario. You can see for yourselves the changes that were made by looking at the SVN changeset. There weren't that many lines to change, but because it was so deep down in the XSL definitions, it took a while to sort out.

This code is freely available to anyone and I encourage you to download and contribute to the Magik Code Library.

Wednesday, February 6, 2008

CASE Tool out of synch with your actual datamodel

It is possible that your CASE Tool representation of your datamodel might not accurately reflect the actual datamodel you have in your database. This happened to me recently when I discovered that some CASE work I had done in my own development environment had touched more objects than I was working with when I did a CASE Archive. When I loaded the CASE archive into the production database I had not noticed that it also updated some other objects with an older version of the CASE definition.

This was not a problem until someone tried to apply changes for the "unknowingly-touched" CASE object and it introduced some confusion into the production environment. Well, we resolved the issue but then had the question... How do we ensure that the CASE Tool accurately represents the state of the datamodel?

The answer to that question: "Reverse Engineer"

Here are some tips that will help you to reverse engineer a CASE model.
  • read the Smallworld Case Tutorial help "Reverse engineering from the Gis dataset"
  • an important thing to note is that you need to do the reverse engineer action into an empty CASE partition. Use a procedure such as create_database() to create new "empty" case.ds and case_dd.ds files and then update your Case SOC to point to these new .ds files
  • you should also temporarily keep your "old" case.ds and case_dd.ds files. Do this by creating a new SOC (:old_case) that has a :case dataset that points to these old ds files.
  • when you perform the reverse engineer action you will see that the graphics for relationships and drafting_* objects are not visible in the new CASE. You will also see that the CASE objects are not grouped together the way you had them in the original CASE tool. That is because the Gis dataset does not keep information about CASE graphics in its data dictionary.
  • I use a script like the following one to "recover" some of my description geometries from the "old" CASE tool into the new recently-reverse-engineered CASE tool. (Be sure that you have a handle to both the old and new CASE tools for this).

_local new_case_v << gis_program_manager.cached_dataset(:case)
_local old_case_v << gis_program_manager.cached_dataset(:old_case)

_local old_drafting_coll, new_drafting_coll , geometries , properties , new_rec

write("creating CASE drafting_* objects...")
_for drafting_table_name _over {:drafting_lines,:drafting_areas,:drafting_points,:drafting_texts}.fast_elements()
_loop
old_drafting_coll << old_case_v.collections[drafting_table_name]
new_drafting_coll << new_case_v.collections[drafting_table_name]

_for old_rec _over old_drafting_coll.fast_elements()
_loop
properties << property_list.new()

new_rec << new_drafting_coll.insert(old_rec)

_for a_geom _over old_rec.geometries().fast_elements()
_loop
properties[a_geom.app_type] << a_geom
_endloop

_if properties.empty?
_then
_continue
_endif

record_transaction.new_update(new_rec,properties).run()
_endloop
_endloop

_local new_case_coll << new_case_v.collections[:sw_gis!case_object]
_local old_case_coll << old_case_v.collections[:sw_gis!case_object]

write("updating CASE Object geometries...")
_for new_co _over new_case_coll.fast_elements()
_loop
_if (old_co << old_case_coll.select(predicate.eq(:name,new_co.name)).an_element()) _is _unset
_then
show("skipping ",new_co.name)
_continue
_endif
show(old_co,new_co)

record_transaction.new_update(new_co,property_list.new_with(:outline,old_co.outline,
:position,old_co.position)).run()
_endloop

_local new_case_coll << new_case_v.collections[:sw_gis!case_relationship]
_local old_case_coll << old_case_v.collections[:sw_gis!case_relationship]

write("redrawing CASE relationship geometries...")
_for new_co _over new_case_coll.fast_elements()
_loop
_if (old_co << old_case_coll.select(predicate.eq(:object_info,new_co.object_info)).an_element()) _is _unset
_then
show("skipping ",new_co.object_info)
_continue
_endif

record_transaction.new_update(new_co,property_list.new_with(:centreline,old_co.centreline,
:end1,old_co.end1,
:end2,old_co.end2,
:label,old_co.label)).run()
_endloop