Ever get the feeling there's something very wrong with the library you're using, something a little too framework-y about it, but you can't quite put your finger on the problem? My pet theory: it's often that the library is structured to push its functionality to client code, rather than having client code pull functionality that's needed.
In a push library, the library pushes the functionality to clients, who then override how certain steps are performed. In this model, client code can only change overall program behavior by overriding or changing code in places predetermined by the library. A consequence is that overall control flow is rigid - it is mostly fixed by the library writer. As push libraries develop over time, they accumulate more and more options and hooks in different places to handle all the different control flows users want. The result isn't pretty. But even with all the complexity that accumulates, the library never seems to do exactly what you want it to.
In contrast, a "pull" library puts client code in control. Client code makes all decisions regarding control flow and the library provides control flow combinators appropriate for the domain. Not only is this way more flexible and expressive (the client can construct control flows not envisioned by the framework designer), it's also much more pleasant for the client programmer. The client programmer now just has to understand the primitives and the control flow combinators he's using for his particular application, and nothing more.
Libraries written in the pull style are more like combinator libraries and tend to make use of higher order functions, closures, etc. Perhaps this explains why this style isn't very common in languages like Java and why the big "frameworks" in these languages are often bloated monstrosities nobody likes using.