Book Contents | Previous Chapter | Next Chapter
Search STEP Tools Web Support

Overview

The ST-Developer for Java library includes a class library which provides data management service and the Part21 reader and writer. This class library includes the base classes that the EXPRESS compiler extends to provide schema-specific functionality. These classes provide the high-level data management, store metadata for the EXPRESS schema, and implement a late-bound API to the data. The EXPRESS generated classes provide an early-bound API.

Unless otherwise indicated, all classes and interfaces are declared in the com.steptools.stdev namespace. Definitions in the schema namespace are generated by the EXPRESS compiler under com.steptools.schemas.<schname>, where schname is the name of the schema.

Schema

EXPRESS information models are organized into schemas. A schema is a set of related definition, which together define an information model. Generally, a Part 21 exchange file will generally consist of instances from a single EXPRESS schema. An EXPRESS schema is represented by a Schema.SCHEMA object in the schema's namespace. There is a single (static static) instances of the schema object, identifies the EXPRESS schema that that defines the instance data. This value is used in the constructor for Models and Population to identify the EXPRESS schema being used.

For example, for the ifc2x3 schema, the full name of the schema object is com.steptools.schemas.ifc2x3.Schema.SCHEMA. com.steptools.schemas.ifc2x3.Schema is the schema class. There is a single instance of the class in the static field named SCHEMA, which is the schema identifier.

Models and Populations

STEP instances are organized into model and populations. A model corresponds to an entire a STEP Part 21 file, and a population corresponds to the HEADER or DATA section within the file. Most models will contain a header and a single data population, but some might contain several data populations (the second edition of Part 21 allows more than one data section). Populations contain the STEP entity instances. Each population is associated with exactly one EXPRESS schema.

A model is represented by the Model class in com.steptools.stdev. A population is represented by a generated class named Population in the schema namespace. The Population class extends the PopulationBase class in com.steptools.stdev. There is no schema-specific model class, since a schema can contain instances from several schemas. Any method of Model that returns a population object is declared to return PopulationBase, which you may need to cast down to the intended Population type.

To create a Model with a Population, pass the schema to the constructor for the Model. The Population can then be obtained by calling getPopulation() on the Model. The following example shows how to create and populate a model. In this example, the schema is not imported in order to emphasize which definitions come from the ST-Developer class library, and which are EXPRESS compiler generated classes.

    /*
     * For clarity in this example, no schemas are imported.
     * Actual code is likely to be much less verbose.
     */
    Model mod = new Model
    (com.steptools.schemas.config_control_design.Schema.SCHEMA);
     com.steptools.schemas.config_control_design.Population pop
     = mod.getPopulation();

    /* Create a instance */
    com.steptools.schemas.config_control_design.Cartesian_point point
    = pop.newCartesian_point();

Most commonly, a Model will only contain a single Population of user instances. The Part 21 interface uses an additional Population to hold the STEP header information. It is possible, however, to create a Model with more than one Population. This can be used, to create a Part 21 file with multiple data sections. To create a Model with more than one Population, use the default, no argument, constructor for Model, and use the newPopulation method to create each Population in the model. Each Population must have an identifier, which is a java.lang.Object that is specified as a parameter to the newPopulation method. For models saved in Part 21 files, this identifier must be a string that gives the name of the data section in the Part 21 file.

To get a default Population from a Model, use one of the getPopulation methods. With no arguments, or with a null parameter getPopulation return the default Population of the Model. If you specify an argument it is interpreted as an identifier,and getPopulation returns the Population with the specified identifier, or null if no Population exists with that identifier.

Managing Entity Instances

STEP entity instances are represented by interfaces generated by the EXPRESS compiler. For every entity in a schema, the compiler creates a corresponding interface in the schema namespace. These generated interfaces extend the EntityInstance interface.

The schema-specific Population class contains factory methods to create entity instances for each entity type declared in the schema. This methods follow the naming convention of new followed by the name of the class corresponding to the entity.

To remove an entity instance from a Population call the removeInstance method. The instance is removed from the Population, but it will not get deleted from memory until the garbage collector notices that the instance is unreferenced.

Accessing Entity Instances by Type

The Population classes provides several methods to find instances by type. This is the most common way to access the data after loading a Model from a file on disk. The getExtent and getFolder methods each return an EntityExtent containing all the entity instances of a given type. The EntityExtent that the getExtent method returns also contain instances of all subtypes of the specified type. The EntityExtent class implements the java.util.Set interface, so you can obtain an Iterator, and traverse over the instances.

The following code traverses over all the product entity instances in a Population.

    import com.steptools.schemas.config_control_design.*;
    import com.steptools.stdev.*;
    import java.util.*;

    /* much further down - inside a class */
    void processProducts(Population pop) {
       EntityExtent prods = pop.getExtent(Product.DOMAIN);
       Iterator itor = prods.iterator();
       while (itor.hasNext()) {
          Product prod = (Product) itor.next();
          /* Now do something with the product */
       }
    }

Reading Part 21 Files

The Part21Parser class reads a Part 21 file into memory. To read a file, create an instance of Part21Parser, then call one of the parse methods to read the Model. For flexibility, the parse method is overloaded to take either a file name, a java.io.File object, or a java.io.InputStream object. Whichever version is called, a Model is returned. The Part21Parser object may be reused to read additional files.

For many applications, it may be more convenient to use Part21LoggingParser instead. That subtype provides error reporting and recovery.

The following code demonstrates how to read a Part 21 file, given the file name.

    /* at the top of your code: */
    import com.steptools.stdev.*;
    import com.steptools.stdev.p21.*;

    /* inside a class: */
    Model read_file (String filename) throws STDevException, IOException {
       Part21Parser parser = new Part21Parser();
       return parser.parse(filename);
    }

When you use the Part 21 parser to read from a InputStream, you need should specify a filename and a length of the data in bytes to the parse method for status and error reporting. If you to not know the length (such as when you are reading from a pipe), you can pass zero as the length. This will result in any progress messages reporting 0% complete, but otherwise it will work.

The Part 21 parser contains a number of fields and methods that can be overridden to control the behavior of the parser. These options allow the application to control error reporting and recovery in the parser, and to monitor, report, and possibly interrupt the progress of the parser. Several of these options are controlled by public instance variables of the parser, While some require that the Part21Parser be subclassed to override a method.

fail_fast

By default, the parser throws an exception and aborts reading when it detects any error in the Part 21 file. If you wish the parser to to recover from errors in the input file, set fast_fail to false, or use a Part21LoggingParser.

Since the default configuration of the parser has no way to report status information to the called other than throwing exceptions, we determined that it is better for the parser to fail quickly rather the silently reading and recovering from syntax errors in the Part 21 file.

convert

The convert field, determines if the parser should attempt to convert the types of arguments that are passed in. By default, this field is true, indicating that the parser should attempt to convert parameters to the correct type. This generally does not need to be changed, but if you need a very picky Part21 reader for some reason, you can set this to false.

For example, if the Part 21 file attempts to read a field declared as REAL in the EXPRESS, and gets 1234, this is an error according. The token 1234 is an integer, but if convert is true, it will be converted to a REAL, and stored.

Whenever a conversion is done reportError is called with a warning message, but no exception is thrown.

Status Updates

The statusUpdate method is called periodically by the parser to report the progress. The default version of this method does nothing, but it can be overridden in subtypes of Part21Parser to report progress to the user, or to interrupt the reading of the file. To terminate reading the file, throw CanceledException.

The status_freq field determines how frequently the statusUpdate method is called. The default value, zero, indicated that statusUpdate is never to be called. Otherwise, the value indicates the number of entity instances to read from the part 21 file between calls to statusUpdate.

Here is an example that prints a status report to System.out, while watching a flag for an abort request.


/* 
 * Flag variable: may be updated by another thread.
 * If this is set to true, the P21 parse will abort.
 */
volatile boolean cancel = false;

/* Anonymous subclass of Part21Parser. */
Part21Parser parser = new Part21Parser() {
    {status_freq = 200;}  /* how often to call statusUpdate() */
  
    public void statusUpdate(Part21Parser.State st) 
        throws CanceledException
    {
        if (cancel) throw new CanceledException();

	float fract = st.getFractionRead();
	String msg = String.format("%d%% done: %d instances read",
				   (int)(fract*100.f), st.getInstancesRead());
        System.out.println (msg);
    }
};

parser.parse("bar.stp");

The statusUpdate method is passed a parameter of type Part21Parser.State, which contains methods to get the progress of the parser in various ways: getBytesRead(), getFilename(), getFractionRead(), getInstancesRead(), and getLineNumber().

reportError()

The reportError() method is called whenever an error is encountered by the parser. This method is intended to report the error to the user by writing it to System.out, displaying a message in a window, or taking other action to report the message to the user. If you simply want to display the message on System.out or some other stream, consider using Part21LoggingParser, rather than overriding this method in a subtype of Part21Parser.

If fail_fast is true, the exception will the thrown after the call to reportError(). Note that conversion warnings (if convert is true) will result is reportError() getting called, and will never result in an exception getting thrown.

getSchema()

The Part 21 file header contains string that identifies the STEP schema. Normally the schema is found by loading the class named com.steptools.schemas.<schema-name>.Schema. You can override this behavior, by subclassing Part21Parser, and overriding the getSchema method. The following code demonstrates how to read every Part 21 file as if it were an AP203 file:

    import com.steptools.stdev.p21.*;

    class AP203Parser extends Part21Parser {
       public SchemaBase getSchema(String name) {
          /* The schema object is in a static field of the Schema class */
          return com.steptools.schemas.config_control_design.Schema.SCHEMA;
       }
    }

Part21LoggingParser

The Part21LoggingParser is a subtype of Part21Parser which provides error recovery and reporting. It sets fast_fail to false, and provides a errorReporter method which sends message to the PrintStream specified in the constructor, or by its out field (it uses System.out by default). This parser provides a statusUpdate method which reports the percentage of the file that has been read. To activate the statusUpdate reporting, set the status_freq field.

    import com.steptools.stdev.p21.*;

    /*
     * Read a model with error recover and error messages sent to System.out.
     * Every 10,000 objects, report the progress.
     */
    Part21LoggingParser parser = new Part21LoggingParser();

    /* Not needed -- we just want status reports */
    parser.status_freq = 1000;

    Model mod = parser.parse ("foo.stp");

This results in the following output, assuming a file with some errors. Note that there are status messages, as well as errors. This output is sent to System.out unless a different stream is specified.

foo.stp:3079: Expecting token "#".
foo.stp:1079: Bad character '1' at start of keyword.
foo.stp:1087: WARNING: converting object java.lang.Integer to DOUBLE
foo.stp:1088: 45% done: 1000 instances read.
foo.stp:1090: com.steptools.stdev.TypeException: java.lang.Double cannot be cast to com.steptools.stdev.keystone.ListReal
foo.stp:1102: Expecting token "(".
foo.stp:2100: 90% done: 2000 instances read.

Writing Part 21 Files

The Part21Writer class is used to write a Model to secondary storage. To write a Part 21 file, create an instance of Part21Writer, and call one of the write methods. The write method is overloaded to take either a file name, a java.io.File object, or a java.io.OutputStream object for maximum flexibility. The same Part21Writer can be used to write multiple models to secondary storage.

The following example demonstrates how to write a Model to secondary storage:

    /* at the top of your code: */
    import com.steptools.stdev.*;
    import com.steptools.stdev.p21.*;

    /* inside a class: */
    Model write_file (Model mod) throws STDevException, IOException {
       Part21Writer writer = new Part21Writer();
       return writer.write("test.stp", mod);
    }

If you need to the control the name of the schema that gets written in the header of the file, you can subclass Part21Writer and override the getSchema method.

Status Updates

Writing a large data set can take a while, so the Part21Writer includes a feature to allow a program to monitor the progress of a write, or to terminate it. This is done by calling the statusUpdate method which can be overridden in subclasses of Part21Writer.

The status_freq field determines the frequency at which the statusUpdate method is called. After that number of instances are written, the statusUpdate method is called. This method can query the state information to determine the fraction in entity instances written to the Part 21 file, or it can throw CancelledException to terminate the writing.

Entity Instance Identifiers

Every entity instance in a Part 21 file has an identifier. In the Part 21 file, the identifier is a "#" character followed by a number. ST-Developer includes the EntityIDTable to track the identifiers in a Model. The EntityIDTable is created when a Model is read from or written to a Part 21 file, or is can be created dynamically with the EntityIDTable.forModel static method. Identifiers in the EntityIDTable are of type int.

To find an EntityInstance by identifier, use the getInstance method of the EntityIDTable instance. The following example shows how to find an instance:

    void EntityInstance findByID (Model mod, BigInteger id) {

        /* Get the EntityIDTable for the model. This method will get the
         * table associated with the model. This will create the table if it
         * does not already exist.
         */

        EntityIDTable tab = EntityIDTable.forModel(mod);
        return tab.getInstance(id);
    }

To get the identifier for an EntityInstance, use the getId() method. Initially, only objects that were read from a Part 21 file or written to one will have IDs. The getId() takes a second parameter, which, if true, will assign an identifier to object that do not yet have one; otherwise, the method returns zero.

STEP Header

The HEADER section of a Part 21 file contains a timestamps, author, organization, and related information. In memory, the header is represented as a Population of the header_section_schema, which is defined in the Part 21 specification. While you can directory access to population, it is more convenient to use the com.steptools.stdev.p21.Header class.

The Header class includes methods getFileName() and getFileDescription() which return the file_name and file_description instances, respectively, from the Part 21 header. If these instances do not exist, they are created. In addition, a number of attributes of these entities are declared as lists of strings. These methods insure that these lists exist by creating them is they are set to null.

This example shows how you could add a string to the description of a file:

    import com.steptools.stdev.p21.*;
    import com.steptools.stdev.*;

    void addDescription (Model mod, String desc) {
        Header head = Header.forModel(mod);
        return head.getFileName().getFileDescription().getDescription()
           .add(desc);
    }

The following example returns the "originating system" attribute:

    String getOrig (Model mod) {
        Header head = Header.forModel(mod);
        return head.getFileName().getOriginating_system();
    }
| Book Contents | ST-Developer Home | Previous Chapter | Next Chapter |