subRelation = new Relation(subnodeMapping, "_children", this, props);
subRelation = new Relation("_children", this);
    public synchronized void update() {        // read in properties        tableName = props.getProperty("_table");        idgen = props.getProperty("_idgen");        dbSourceName = props.getProperty("_db");        if (dbSourceName != null) {            dbSource = app.getDbSource(dbSourceName);            if (dbSource == null) {                app.logEvent("*** Data Source for prototype " + typename +                             " does not exist: " + dbSourceName);                app.logEvent("*** accessing or storing a " + typename +                             " object will cause an error.");            } else if (tableName == null) {                app.logEvent("*** No table name specified for prototype " + typename);                app.logEvent("*** accessing or storing a " + typename +                             " object will cause an error.");                // mark mapping as invalid by nulling the dbSource field                dbSource = null;            }        }        // if id field is null, we assume "ID" as default. We don't set it        // however, so that if null we check the parent prototype first.        idField = props.getProperty("_id");        nameField = props.getProperty("_name");        protoField = props.getProperty("_prototype");        String parentSpec = props.getProperty("_parent");        if (parentSpec != null) {            // comma-separated list of properties to be used as parent            StringTokenizer st = new StringTokenizer(parentSpec, ",;");            parentInfo = new ParentInfo[st.countTokens()];            for (int i = 0; i < parentInfo.length; i++)                parentInfo[i] = new ParentInfo(st.nextToken().trim());        } else {            parentInfo = null;        }        lastTypeChange = props.lastModified();        // see if this prototype extends (inherits from) any other prototype        extendsProto = props.getProperty("_extends");        if (extendsProto != null) {            parentMapping = app.getDbMapping(extendsProto);            if (parentMapping != null && parentMapping.needsUpdate()) {                parentMapping.update();            }        } else {            parentMapping = null;        }        // set the parent prototype in the corresponding Prototype object!        // this was previously done by TypeManager, but we need to do it        // ourself because DbMapping.update() may be called by other code than        // the TypeManager.        if (typename != null &&                !"global".equalsIgnoreCase(typename) &&                !"hopobject".equalsIgnoreCase(typename)) {            Prototype proto = app.getPrototypeByName(typename);            if (proto != null) {                if (extendsProto != null) {                    proto.setParentPrototype(app.getPrototypeByName(extendsProto));                } else if (!app.isJavaPrototype(typename)) {                    proto.setParentPrototype(app.getPrototypeByName("hopobject"));                }            }        }        // null the cached columns and select string        columns = null;        columnMap.clear();        selectString = insertString = updateString = null;        HashMap p2d = new HashMap();        HashMap d2p = new HashMap();        ArrayList joinList = new ArrayList();        for (Enumeration e = props.keys(); e.hasMoreElements();) {            String propName = (String) e.nextElement();            try {                // ignore internal properties (starting with "_") and sub-options (containing a ".")                if (!propName.startsWith("_") && (propName.indexOf(".") < 0)) {                    String dbField = props.getProperty(propName);                    // check if a relation for this propery already exists. If so, reuse it                    Relation rel = (Relation) prop2db.get(propName.toLowerCase());                    if (rel == null) {                        rel = new Relation(dbField, propName, this, props);                    }                    rel.update(dbField, props);                    // key enumerations from SystemProperties are all lower case, which is why                    // even though we don't do a toLowerCase() here,                    // we have to when we lookup things in p2d later.                    p2d.put(propName, rel);                    if ((rel.columnName != null) &&                            ((rel.reftype == Relation.PRIMITIVE) ||                            (rel.reftype == Relation.REFERENCE))) {                        Relation old = (Relation) d2p.put(rel.columnName.toUpperCase(), rel);                        // check if we're overwriting another relation                        // if so, primitive relations get precendence to references                        if (old != null) {                            app.logEvent("*** Duplicate mapping for "+typename+"."+rel.columnName);                            if (old.reftype == Relation.PRIMITIVE) {                                d2p.put(old.columnName.toUpperCase(), old);                            }                        }                    }                    // check if a reference is aggressively fetched                    if ((rel.reftype == Relation.REFERENCE ||                             rel.reftype == Relation.COMPLEX_REFERENCE) &&                             rel.aggressiveLoading) {                        joinList.add(rel);                    }                    // app.logEvent ("Mapping "+propName+" -> "+dbField);                }            } catch (Exception x) {                app.logEvent("Error in type.properties: " + x.getMessage());            }        }        prop2db = p2d;        db2prop = d2p;        joins = new Relation[joinList.size()];        joins = (Relation[]) joinList.toArray(joins);        String subnodeMapping = props.getProperty("_children");        if (subnodeMapping != null) {            try {                // check if subnode relation already exists. If so, reuse it                if (subRelation == null) {                    subRelation = new Relation(subnodeMapping, "_children", this, props);                }                subRelation.update(subnodeMapping, props);                // if subnodes are accessed via access name or group name,                // the subnode relation is also the property relation.                if ((subRelation.accessName != null) || (subRelation.groupby != null)) {                    propRelation = subRelation;                } else {                    propRelation = null;                }            } catch (Exception x) {                app.logEvent("Error reading _subnodes relation for " + typename + ": " +                             x.getMessage());                // subRelation = null;            }        } else {            subRelation = propRelation = null;        }        if (groupbyMapping != null) {            initGroupbyMapping();            groupbyMapping.lastTypeChange = this.lastTypeChange;        }    }