/**
   * Extract items using reflect api
   *
   * @param monitor progress monitor
   * @param meta items meta info
   * @param oldList previous child items
   * @param toList list ot add new items @return true on success
   * @return true on success
   * @throws DBException on any DB error
   */
  private boolean loadTreeItems(
      DBRProgressMonitor monitor,
      DBXTreeItem meta,
      final DBNDatabaseNode[] oldList,
      final List<DBNDatabaseNode> toList)
      throws DBException {
    if (this.isDisposed()) {
      // Property reading can take really long time so this node can be disposed at this moment -
      // check it
      return false;
    }
    // Read property using reflection
    Object valueObject = getValueObject();
    if (valueObject == null) {
      return false;
    }
    String propertyName = meta.getPropertyName();
    Object propertyValue = extractPropertyValue(monitor, valueObject, propertyName);
    if (propertyValue == null) {
      return false;
    }
    if (!(propertyValue instanceof Collection<?>)) {
      log.warn(
          "Bad property '"
              + propertyName
              + "' value: "
              + propertyValue.getClass().getName()); // $NON-NLS-1$ //$NON-NLS-2$
      return false;
    }

    DBSObjectFilter filter = getNodeFilter(meta, false);
    this.filtered = filter != null && !filter.isEmpty();

    Collection<?> itemList = (Collection<?>) propertyValue;
    if (itemList.isEmpty()) {
      return false;
    }
    if (this.isDisposed()) {
      // Property reading can take really long time so this node can be disposed at this moment -
      // check it
      return false;
    }

    DBPDataSourceContainer dataSourceContainer = getDataSourceContainer();
    boolean showSystem = dataSourceContainer == null || dataSourceContainer.isShowSystemObjects();
    for (Object childItem : itemList) {
      if (childItem == null) {
        continue;
      }
      if (!(childItem instanceof DBSObject)) {
        log.warn("Bad item type: " + childItem.getClass().getName()); // $NON-NLS-1$
        continue;
      }
      if (DBUtils.isHiddenObject(childItem)) {
        // Skip hidden objects
        continue;
      }
      if (!showSystem
          && childItem instanceof DBPSystemObject
          && ((DBPSystemObject) childItem).isSystem()) {
        // Skip system objects
        continue;
      }
      if (filter != null && !filter.matches(((DBSObject) childItem).getName())) {
        // Doesn't match filter
        continue;
      }
      DBSObject object = (DBSObject) childItem;
      boolean added = false;
      if (oldList != null) {
        // Check that new object is a replacement of old one
        for (DBNDatabaseNode oldChild : oldList) {
          if (oldChild.getMeta() == meta && equalObjects(oldChild.getObject(), object)) {
            oldChild.reloadObject(monitor, object);

            if (oldChild.allowsChildren() && !oldChild.needsInitialization()) {
              // Refresh children recursive
              oldChild.reloadChildren(monitor);
            }
            getModel().fireNodeUpdate(this, oldChild, DBNEvent.NodeChange.REFRESH);

            toList.add(oldChild);
            added = true;
            break;
          }
        }
      }
      if (!added) {
        // Simply add new item
        DBNDatabaseItem treeItem = new DBNDatabaseItem(this, meta, object, oldList != null);
        toList.add(treeItem);
      }
    }

    if (oldList != null) {
      // Now remove all non-existing items
      for (DBNDatabaseNode oldChild : oldList) {
        if (oldChild.getMeta() != meta) {
          // Wrong type
          continue;
        }
        boolean found = false;
        for (Object childItem : itemList) {
          if (childItem instanceof DBSObject
              && equalObjects(oldChild.getObject(), (DBSObject) childItem)) {
            found = true;
            break;
          }
        }
        if (!found) {
          // Remove old child object
          oldChild.dispose(true);
        }
      }
    }
    return true;
  }
  private void loadChildren(
      DBRProgressMonitor monitor,
      final DBXTreeNode meta,
      final DBNDatabaseNode[] oldList,
      final List<DBNDatabaseNode> toList)
      throws DBException {
    if (monitor.isCanceled()) {
      return;
    }
    this.filtered = false;

    List<DBXTreeNode> childMetas = meta.getChildren(this);
    if (CommonUtils.isEmpty(childMetas)) {
      return;
    }
    monitor.beginTask(ModelMessages.model_navigator_load_items_, childMetas.size());

    for (DBXTreeNode child : childMetas) {
      if (monitor.isCanceled()) {
        break;
      }
      monitor.subTask(
          ModelMessages.model_navigator_load_
              + " "
              + child.getChildrenType(getObject().getDataSource()));
      if (child instanceof DBXTreeItem) {
        final DBXTreeItem item = (DBXTreeItem) child;
        boolean isLoaded = loadTreeItems(monitor, item, oldList, toList);
        if (!isLoaded && item.isOptional() && item.getRecursiveLink() == null) {
          // This may occur only if no child nodes was read
          // Then we try to go on next DBX level
          loadChildren(monitor, item, oldList, toList);
        }
      } else if (child instanceof DBXTreeFolder) {
        if (oldList == null) {
          // Load new folders only if there are no old ones
          toList.add(new DBNDatabaseFolder(this, (DBXTreeFolder) child));
        } else {
          for (DBNDatabaseNode oldFolder : oldList) {
            if (oldFolder.getMeta() == child) {
              oldFolder.reloadChildren(monitor);
              toList.add(oldFolder);
              break;
            }
          }
        }
      } else if (child instanceof DBXTreeObject) {
        if (oldList == null) {
          // Load new objects only if there are no old ones
          toList.add(new DBNDatabaseObject(this, (DBXTreeObject) child));
        } else {
          for (DBNDatabaseNode oldObject : oldList) {
            if (oldObject.getMeta() == child) {
              oldObject.reloadChildren(monitor);
              toList.add(oldObject);
              break;
            }
          }
        }
      } else {
        log.warn("Unsupported meta node type: " + child); // $NON-NLS-1$
      }
      monitor.worked(1);
    }
    monitor.done();

    if (filtered) {
      getModel().fireNodeUpdate(this, this, DBNEvent.NodeChange.REFRESH);
    }
  }