class AbstractQueryImpl implements Query {

    protected List<AbstractQueryImpl> children;
    protected Query parent;
    protected Graph result;

    public AbstractQueryImpl() {
        this.children = new ArrayList<>();
    }

    @Override
    public abstract int getChildrenSlotsCount();

    @Override
    public abstract int getPropertiesCount();

    @Override
    public abstract String getPropertyName(int index);

    @Override
    public abstract Object getPropertyValue(int index);

    @Override
    public abstract String getName();

    public abstract void setName(String name);

    @Override
    public Query[] getChildren() {
        return children.toArray(new Query[0]);
    }

    public int getChildrenCount() {
        return children.size();
    }

    public AbstractQueryImpl getChildAt(int index) {
        return children.get(index);
    }

    public void addSubQuery(Query subQuery) {
        children.add((AbstractQueryImpl) subQuery);
        ((AbstractQueryImpl) subQuery).setParent(this);
    }

    public void removeSubQuery(Query subQuery) {
        children.remove((AbstractQueryImpl) subQuery);
    }

    @Override
    public Query getParent() {
        return parent;
    }

    public void setParent(Query parent) {
        this.parent = parent;
    }

    public Graph getResult() {
        return result;
    }

    public void setResult(Graph result) {
        this.result = result;
    }

    public AbstractQueryImpl getRoot() {
        AbstractQueryImpl root = this;
        while (root.getParent() != null) {
            root = (AbstractQueryImpl) root.getParent();
        }
        return root;
    }

    public AbstractQueryImpl[] getLeaves() {<FILL_FUNCTION_BODY>}

    public AbstractQueryImpl copy() {
        AbstractQueryImpl copy = null;
        if (this instanceof FilterQueryImpl) {
            copy = new FilterQueryImpl(this.getBuilder(), this.getFilter());
        } else if (this instanceof OperatorQueryImpl) {
            copy = new OperatorQueryImpl((Operator) this.getFilter());
        }

        for (int i = 0; i < children.size(); i++) {
            AbstractQueryImpl child = children.get(i);
            AbstractQueryImpl childCopy = child.copy();
            childCopy.parent = copy;
            copy.children.add(childCopy);
        }

        return copy;
    }

    @Override
    public Query[] getQueries(Class<? extends Filter> filterClass) {
        List<Query> r = new LinkedList<>();
        LinkedList<Query> stack = new LinkedList<>();
        stack.add(this);
        while (!stack.isEmpty()) {
            Query q = stack.pop();
            r.add(q);
            stack.addAll(Arrays.asList(q.getChildren()));
        }
        for (Iterator<Query> itr = r.iterator(); itr.hasNext(); ) {
            Query q = itr.next();
            if (!q.getFilter().getClass().equals(filterClass)) {
                itr.remove();
            }
        }
        return r.toArray(new Query[0]);
    }

    @Override
    public Query[] getDescendantsAndSelf() {
        List<Query> r = new LinkedList<>();
        LinkedList<Query> stack = new LinkedList<>();
        stack.add(this);
        while (!stack.isEmpty()) {
            Query q = stack.pop();
            r.add(q);
            stack.addAll(Arrays.asList(q.getChildren()));
        }
        return r.toArray(new Query[0]);
    }
}

        ArrayList<AbstractQueryImpl> leaves = new ArrayList<>();
        Deque<Query> stack = new ArrayDeque<>();
        stack.add(this);
        while (!stack.isEmpty()) {
            AbstractQueryImpl query = (AbstractQueryImpl) stack.pop();
            if (query.children.size() > 0) {
                stack.addAll(query.children);
            } else {
                //Leaf
                leaves.add(query);
            }
        }
        return leaves.toArray(new AbstractQueryImpl[0]);
    
<no_super_class>