/* * DocumentNode.java * * $Id: DocumentNode.java 85 2008-01-24 19:02:22Z harald $ */ // @{ // # name of database table // tablename = docnode // mapping = $scripts/$tablename.map # java <-> db mapping // relations = $scripts/$tablename.rel # object relations // @} // @> $mapping // # mapping for DocumentNode // # // # CREATE UNIQUE INDEX ${tablename}_parent ON $tablename (parent_id, parent_ndx); // // long 0 parentId parent_id ID of the parent DocumentNode or DocumentJob // int 0 parentNdx parent_ndx order within the parent node // String 128 nodeName node_name name of the node // @< // @> $relations // # relations for DocumentNode // // DocumentNode: // relation = composite tracked list, // delete = cascade, // select = lazy, // method = ParentId, // link = linkToParent indexed; // // DocumentData: // relation = composite tracked list, // delete = cascade, // select = lazy, // link = linkToNode indexed; // @< package de.krake.lager.dbms; import de.krake.lager.dbms.rmi.DocumentNodeRemoteDelegate; import org.tentackle.appworx.AppDbObject; import org.tentackle.appworx.AppDbObjectClassVariables; import org.tentackle.appworx.ContextDb; import org.tentackle.db.Db; import org.tentackle.db.PreparedStatementWrapper; import org.tentackle.db.ResultSetWrapper; import org.tentackle.util.Compare; import org.tentackle.util.TrackedArrayList; /** * A node of a document. * Nodes may contain subnodes and data elements (key/value pairs). */ public class DocumentNode extends AppDbObject { public static final String TABLENAME = /**/"docnode"/**/; // @wurblet < Inject --string $tablename private static AppDbObjectClassVariables classVariables = new AppDbObjectClassVariables(DocumentNode.class, TABLENAME, "DocumentNode", "DocumentNodes"); /** * Creates an instance of DocumentNode. * * @param db the db-context * @param nodeName the name of the node */ public DocumentNode(ContextDb db, String nodeName) { super(db); this.nodeName = nodeName; } /** * Creates an instance of DocumentNode. * * @param db the db-context */ public DocumentNode(ContextDb db) { this(db, null); } /** * Creates an instance of DocumentNode. */ public DocumentNode() { this(null); } /** * Gets the string representation of the object. * This is usually a unique attribute of the object. * * @return the string value */ @Override public String toString() { return nodeName; } /** * Appends a node to an XML document. * * @param buf the xml text buffer * @param indent the blanks for indentation */ public void appendToXml(StringBuilder buf, String indent) { buf.append(indent); buf.append("\n"); String nodeIndent = indent + " "; // node data for (DocumentData data: getDocumentDataList()) { data.appendToXml(buf, nodeIndent); } // subnodes for (DocumentNode node: getDocumentNodeList()) { node.appendToXml(buf, nodeIndent); } buf.append(indent); buf.append("\n"); } /** * Adds a subnode. * * @param nodeName the name of the subnode * @return the added subnode */ public DocumentNode addNode(String nodeName) { DocumentNode node = new DocumentNode(getContextDb(), nodeName); getDocumentNodeList().add(node); return node; } /** * Adds a key/value-pair to the node. * * @param key the key string * @param value the value object * @return the added data object */ public DocumentData addData(String key, Object value) { DocumentData data = new DocumentData(getContextDb(), key, value == null ? "" : value.toString()); getDocumentDataList().add(data); return data; } /** * Sets the link to the parent node or job. * * @param parent the parent node or job * @param ndx the index within the parent */ public void linkToParent(AppDbObject parent, int ndx) { setParentId(parent.getId()); setParentNdx(ndx); } /** * Gets the sql order by suffix. * * @return the natural ordering to be added following "ORDER BY ", * null, no order-by-clause will be added */ public String orderBy() { return FIELD_PARENTNDX; } /** * Selects a DocumentNode-object by id. * * @param id the object id * @return the DocumentNode object */ @Override public DocumentNode select(long id) { return (DocumentNode)super.select(id); } /** * Selects all subnodes of a node. * * @param parentId the ID of the node * @return the list of subnodes * * @wurblet selectByParentId AppDbSelectList $mapping $remote --sort --tracked parentId */ // Code generated by wurblet. Do not edit!//GEN-BEGIN:selectByParentId public TrackedArrayList selectByParentId(long parentId) { if (getDb().isRemote()) { // invoke remote method try { TrackedArrayList list = ((DocumentNodeRemoteDelegate)getRemoteDelegate()).selectByParentId(parentId); ContextDb.applyToCollection(getContextDb(), list); return list; } catch (Exception e) { org.tentackle.db.Global.errorHandler.severe(getDb(), e, "remote selectByParentId failed"); return null; } } // else: local mode if (selectByParentIdStatementId == 0 || alwaysPrepare()) { // prepare it String sql = "SELECT "; sql += getSqlAllFields() + " AND " + FIELD_PARENTID + "=?"; String orderSuffix = orderBy(); sql += " ORDER BY " + (orderSuffix == null ? (getSqlPrefixWithDot() + FIELD_ID) : orderSuffix); selectByParentIdStatementId = getDb().prepareStatement(sql); } PreparedStatementWrapper st = getDb().getPreparedStatement(selectByParentIdStatementId); int ndx = 1; st.setLong(ndx++, parentId); ResultSetWrapper rs = st.executeQuery(); TrackedArrayList list = new TrackedArrayList(); boolean derived = getClass() != DocumentNode.class; while (rs.next()) { DocumentNode obj = derived ? (DocumentNode)newObject() : new DocumentNode(getContextDb()); if (obj.readFromResultSetWrapper(rs)) { list.add(obj); } } rs.close(); list.setModified(false); return list; } private static int selectByParentIdStatementId; // End of wurblet generated code.//GEN-END:selectByParentId /** * Prepares the insert statement. */ @Override public int prepareInsertStatement() { // @wurblet insert DbInsert $mapping // Code generated by wurblet. Do not edit!//GEN-BEGIN:insert int stmtId = getInsertStatementId(); if (stmtId == 0 || alwaysPrepare()) { // prepare it stmtId = getDb().prepareStatement( "INSERT INTO " + getTableName() + " (" + FIELD_PARENTID + "," + FIELD_PARENTNDX + "," + FIELD_NODENAME + "," + FIELD_ID + "," + FIELD_SERIAL + ") VALUES (" + "?," + "?," + "?," + "?," + "?)"); setInsertStatementId(stmtId); } // End of wurblet generated code.//GEN-END:insert return stmtId; } /** * Prepares the update statement. */ @Override public int prepareUpdateStatement() { // @wurblet update DbUpdate $mapping // Code generated by wurblet. Do not edit!//GEN-BEGIN:update int stmtId = getUpdateStatementId(); if (stmtId == 0 || alwaysPrepare()) { // prepare it stmtId = getDb().prepareStatement( "UPDATE " + getTableName() + " SET " + FIELD_PARENTID + "=?" + "," + FIELD_PARENTNDX + "=?" + "," + FIELD_NODENAME + "=?" + "," + FIELD_SERIAL + "=" + FIELD_SERIAL + "+1" + " WHERE " + FIELD_ID + "=?" + " AND " + FIELD_SERIAL + "=?" ); setUpdateStatementId(stmtId); } // End of wurblet generated code.//GEN-END:update return stmtId; } /** * Gets all fields from a resultset. * * @param rs the result set * @return true if all fields read, false if not (e.g. invalid row) */ @Override public boolean getFields(ResultSetWrapper rs) { // @wurblet getfields DbGetFields $mapping // Code generated by wurblet. Do not edit!//GEN-BEGIN:getfields if (columnsValid == false) { if (!isGettingFieldCount() && (rs.getColumnOffset() > 0 || isPartial())) { // invoked within joined select the first time getFieldCount(); // get column indexes with offset 0 if (columnsValid == false) { org.tentackle.db.Global.errorHandler.severe(rs.getDb(), null, "initial getFieldCount() failed in " + getTableName()); } } else { COLUMN_PARENTID = rs.findColumn(FIELD_PARENTID); updateFieldCount(COLUMN_PARENTID); COLUMN_PARENTNDX = rs.findColumn(FIELD_PARENTNDX); updateFieldCount(COLUMN_PARENTNDX); COLUMN_NODENAME = rs.findColumn(FIELD_NODENAME); updateFieldCount(COLUMN_NODENAME); COLUMN_SERIAL = rs.findColumn(FIELD_SERIAL); updateFieldCount(COLUMN_SERIAL); COLUMN_ID = rs.findColumn(FIELD_ID); updateFieldCount(COLUMN_ID); columnsValid = true; } } if (rs.getRow() <= 0) return false; // no valid row parentId = rs.getLong(COLUMN_PARENTID); parentNdx = rs.getInt(COLUMN_PARENTNDX); nodeName = rs.getString(COLUMN_NODENAME); setId(rs.getLong(COLUMN_ID)); setSerial(rs.getLong(COLUMN_SERIAL)); // End of wurblet generated code.//GEN-END:getfields return true; } /** * Prepares the fields before setFields(). * * @return true if preparation done, false if some error. */ @Override public boolean prepareSetFields() { // setNormText(StringHelper.normalize(...)); return true; } /** * Sets the fields in the prepared statement for insert and update. * * @param st the prepared statement * @return the number of fields */ @Override public int setFields(PreparedStatementWrapper st) { // @wurblet setfields DbSetFields $mapping // Code generated by wurblet. Do not edit!//GEN-BEGIN:setfields int ndx = 0; st.setLong(++ndx, parentId); st.setInt(++ndx, parentNdx); st.setString(++ndx, nodeName); st.setLong(++ndx, getId()); st.setLong(++ndx, getSerial()); // End of wurblet generated code.//GEN-END:setfields return ndx; } /** * Gets the class variables. * * @return the static variables for this class */ @Override public AppDbObjectClassVariables getAppDbObjectClassVariables() { return classVariables; } /** * Wurblet generates methods to implement the relations to other objects. * * @wurblet relations AppDbRelations $mapping $relations */ // Code generated by wurblet. Do not edit!//GEN-BEGIN:relations /** * # Relations for DocumentNode: * * DocumentNode: relation=list composite tracked, select=lazy, delete=cascade, method=ParentId, link=linkToParent indexed; * DocumentData: relation=list composite tracked, select=lazy, delete=cascade, link=linkToNode indexed; */ // composite tracked lazy list of DocumentNode private TrackedArrayList documentNodeList; private boolean documentNodeListLoaded; // composite tracked lazy list of DocumentData private TrackedArrayList documentDataList; private boolean documentDataListLoaded; /** * Gets list of DocumentNode. * * @return documentNodeList */ public TrackedArrayList getDocumentNodeList() { if (documentNodeListLoaded == false) { documentNodeList = isNew() ? new TrackedArrayList(false) : new DocumentNode(getContextDb()).selectByParentId(getId()); documentNodeListLoaded = true; } return documentNodeList; } /** * Sets list of DocumentNode. * * @param documentNodeList */ public void setDocumentNodeList(TrackedArrayList documentNodeList) { this.documentNodeList = documentNodeList; documentNodeListLoaded = true; } /** * Gets list of DocumentData. * * @return documentDataList */ public TrackedArrayList getDocumentDataList() { if (documentDataListLoaded == false) { documentDataList = isNew() ? new TrackedArrayList(false) : new DocumentData(getContextDb()).selectByDocumentNodeId(getId()); documentDataListLoaded = true; } return documentDataList; } /** * Sets list of DocumentData. * * @param documentDataList */ public void setDocumentDataList(TrackedArrayList documentDataList) { this.documentDataList = documentDataList; documentDataListLoaded = true; } /** * Sets the db-connection in all related objects. * * @param db the db-connection */ @Override public void setDb(Db db) { super.setDb(db); Db.applyToCollection(db, documentNodeList); Db.applyToCollection(db, documentDataList); } /** * Sets the contextDb in all related objects. * * @param db the db-connection */ @Override public void setContextDb(ContextDb cd) { super.setContextDb(cd); ContextDb.applyToCollection(cd, documentNodeList); ContextDb.applyToCollection(cd, documentDataList); } /** * Deletes all composite relations from storage. * * @return true if deleted, false if failed and rollback required */ @Override public boolean deleteLinkedObjects() { return isVirgin() || super.deleteLinkedObjects() && deleteLinkedObjects(true); } /** * Deletes composite relations. * This method is invoked from deleteLinkedObjects() or saveLinkedObjects(). * When invoked from saveLinkedObjects() lazy relations not * already loaded will be considered to be unchanged, i.e. * need no update or insert. * * @param delete is true if invoked from delete() * @return true if deleted, false if failed and rollback required */ private boolean deleteLinkedObjects(boolean delete) { boolean rv = true; // composite tracked lazy list of DocumentNode if (delete) { rv = rv && deleteList(getDocumentNodeList()) >= 0; } else if (documentNodeList != null && documentNodeList.isObjectRemoved()) { rv = rv && deleteList(documentNodeList.getRemovedObjects()) >= 0; } // composite tracked lazy list of DocumentData if (delete) { rv = rv && deleteList(getDocumentDataList()) >= 0; } else if (documentDataList != null && documentDataList.isObjectRemoved()) { rv = rv && deleteList(documentDataList.getRemovedObjects()) >= 0; } return rv; } /** * Saves composite relations. * * @return true if all saved, false if rollback required. */ @Override public boolean saveLinkedObjects() { if (!super.saveLinkedObjects() || !isVirgin() && !deleteLinkedObjects(false)) { return false; } // composite tracked lazy list of DocumentNode if (documentNodeList != null) { int ndx = 0; for (DocumentNode obj: documentNodeList) { obj.linkToParent(this, ndx); ndx++; } if (saveList(documentNodeList, true) < 0) return false; } // composite tracked lazy list of DocumentData if (documentDataList != null) { int ndx = 0; for (DocumentData obj: documentDataList) { obj.linkToNode(this, ndx); ndx++; } if (saveList(documentDataList, true) < 0) return false; } return true; } /** * Checks composite relations for modification recursively. * * @return true if this or any composition is modified */ @Override public boolean isModified() { return super.isModified() // composite tracked lazy list of DocumentNode || isListModified(documentNodeList) // composite tracked lazy list of DocumentData || isListModified(documentDataList) ; } /** * This is a composite object. */ @Override public boolean isComposite() { return true; } /** * Marks this object and all its composites to be deleted. */ @Override public void markDeleted() { super.markDeleted(); // composite tracked lazy list of DocumentNode markListDeleted(getDocumentNodeList()); // composite tracked lazy list of DocumentData markListDeleted(getDocumentDataList()); } // End of wurblet generated code.//GEN-END:relations /** * Wurblet generates accessor methods to the objects attributes. * * @wurblet methods DbMethods $mapping --tracked */ // Code generated by wurblet. Do not edit!//GEN-BEGIN:methods /** * Overwritten cause of "--tracked". * @return true = setters check for modification */ public boolean isTracked() { return true; // invoking isModified() is ok } /** *

* get db attribute parentId *

* @return ID of the parent DocumentNode or DocumentJob */ public long getParentId() { return parentId; } /** *

* set db attribute parentId *

* @param parentId ID of the parent DocumentNode or DocumentJob */ public void setParentId(long parentId) { if (!isModified()) { setModified(this.parentId != parentId); } this.parentId = parentId; } /** *

* get db attribute parentNdx *

* @return order within the parent node */ public int getParentNdx() { return parentNdx; } /** *

* set db attribute parentNdx *

* @param parentNdx order within the parent node */ public void setParentNdx(int parentNdx) { if (!isModified()) { setModified(this.parentNdx != parentNdx); } this.parentNdx = parentNdx; } /** *

* get db attribute nodeName *

* @return name of the node */ public String getNodeName() { return nodeName; } /** *

* set db attribute nodeName *

* @param nodeName name of the node */ public void setNodeName(String nodeName) { if (!isModified()) { setModified(Compare.equals(this.nodeName, nodeName) == false); } this.nodeName = nodeName; } // End of wurblet generated code.//GEN-END:methods /** * Wurblet generates the declarations of the attributes. * * @wurblet declare DbDeclare $mapping */ // Code generated by wurblet. Do not edit!//GEN-BEGIN:declare /** *

ID of the parent DocumentNode or DocumentJob

*/ private long parentId; /** *

order within the parent node

*/ private int parentNdx; /** *

name of the node

*/ private String nodeName; // End of wurblet generated code.//GEN-END:declare /** * Wurblet generates the fieldnames of the attributes. * * @wurblet fieldnames DbFieldNames $mapping */ // Code generated by wurblet. Do not edit!//GEN-BEGIN:fieldnames private static boolean columnsValid; // true if COLUMN_.... are valid for getFields() public static final String FIELD_PARENTID = "parent_id"; private static int COLUMN_PARENTID; public static final String FIELD_PARENTNDX = "parent_ndx"; private static int COLUMN_PARENTNDX; public static final String FIELD_NODENAME = "node_name"; private static int COLUMN_NODENAME; private static int COLUMN_ID; private static int COLUMN_SERIAL; // End of wurblet generated code.//GEN-END:fieldnames /** * Wurblet generates the field-lengths of the attributes. * * @wurblet fieldlengths DbFieldLengths $mapping */ // Code generated by wurblet. Do not edit!//GEN-BEGIN:fieldlengths public static final int LENGTH_NODENAME = 128; // End of wurblet generated code.//GEN-END:fieldlengths }