Hello, > I'll answer backwards.
Yes, to add some clarity to the topic :-) These design decisions are hard to fully grasp by e-mail... > Synchronizing on a static object is not a problem as far as I know. Most often, no. But static state can be a major pain in clustered and/or distributed environments from my experience. As soon as you cluster your J2EE application (for instance in Weblogic), and you use static objects, you'll have to think about synchronizing them manually. The current JooqLogger is a static *final* object. It is thus guaranteed to always be the same in every cluster node. But a static listener list where clients can add / remove listeners can be problematic. I'm not saying it is wrong. In your use case, it will work perfectly. But no one keeps you from maintaining such a static list in your implementation (see further down). Another example would be Weblogic's call-by-reference EJB setting. Some sample documentation: http://docs.oracle.com/cd/E11035_01/wls100/perform/topten.html#wp1132668 While this is not part of the EJB standard, it can be a major performance improvement in some fine-tuned setups. Other containers may have similar features. Unfortunately, I only know Weblogic. Here's how jOOQ behaves with respect to this Weblogic setting. Let's assume we use EJB SessionBeans and both ends of the bean call maintain references to jOOQ factories. 1. static list in jOOQ call-by-reference=true: both ends of the EJB session bean call would have the same list instance call-by-reference=false: the two ends of the bean would have different list instances 2. instance list in Factory call-by-reference=true: both ends have the same list instance call-by-reference=false: both ends have the same list instance (serialized with the Factory) Another example: I've had tremendous trouble in the past with Apache FOP 0.20's static configuration. While this is very convenient in a PDF-generating script, it was really painful when generating PDF's in a container. Unfortunately, I don't remember the details anymore, but it involved quite a bit of FOP patching... So you can call this FUD if you want. But, I try to avoid static state as much as possible. Static is usually the path of least resistance at design and implementation time, but the time saved in finding an equivalent "dynamic" solution will be paid later when debugging weird issues related to static-ness. As I said, maybe this is not true in your case, and it's also just an opinion. :-) >> In a J2EE context, >> it would be very hard to get this correctly within jOOQ. > > I don't know what "this" refers to. "this" refers to synchronizing updatable static state across class loaders in a cluster / distributed J2EE application. > It is a solution, but it is not an optimal solution for 2 reasons: > - it reduces performance for the lazy. > - it complexifies registration of listeners for those who want to > maximize performance. This is where the misunderstanding was. I provided you with a silly sample implementation of "YourJooqAdapter", maybe I should have elaborated more in detail. Note that I used the term "Adapter". It is just a bridge between your tool and jOOQ. No one keeps you from writing the adapter like this: ------------------------------------------------------------------- class YourJooqAdapter implements JooqLoggerPlugin { static Object LOCK = new Object(); static List<YourListenerType> listeners; // Your adapter maintains the static synchronized list, // Not jOOQ! static void register(YourListenerType listener) { synchronized (LOCK) { listeners.add(listener); } } static void unregister(YourListenerType listener) { ... } @Override // From the jOOQ Plugin interface void event(Query query) { } } ------------------------------------------------------------------- > Because you don't like the idea of a central place, your work around > is to always add a listener to the factories, which would ignore all > the events unless it "isListening". The problem is that all the > mechanics I explained above would happen, for nothing, 99.9% of the > time (this is what I called "reducing performance for the lazy"). Not really. Obviously, my sample was too silly. But jOOQ will not perform any heavy load in 99.9% of the time. The heavy load is implemented in your adapter. And your adapter knows when to run the "heavy" code and when not to run it. By configuring your factories accordingly, you will have full control over both jOOQ's default logging and your data collection. Think about these methods (still draft): ------------------------------------------------------------------- // Maybe these could even be used to optionally // modify rendered SQL? void eventRenderStart(Query query); String eventRenderEnd(Query query, String sql); // These methods allow for wrapping the statement at any moment. // But that decision is up to the adapter PreparedStatement eventPrepareStart(Query query, PreparedStatement stmt); PreparedStatement eventPrepareEnd(Query query, PreparedStatement stmt); PreparedStatement eventBindStart(Query query, PreparedStatement stmt); PreparedStatement eventBindEnd(Query query, PreparedStatement stmt); // Open point: how to treat java.sql.Statement, java.sql.CallableStatement // These are useful for measurements only void eventExecuteStart(Query query); void eventExecuteEnd(Query query); // ResultSet / Result wrapping is also optional ResultSet eventFetchStart(Query query, ResultSet rs); org.jooq.Result eventFetchEnd(Query query, ResultSet rs, org.jooq.Result); ------------------------------------------------------------------- Even better, this design will finally clean up the static ConfigurationRegistry that I introduced due to a request by Sander Plas. Note that I've had similar discussions with him. Already then, I didn't like the idea of introducing static state in jOOQ for the same reasons: https://groups.google.com/d/topic/jooq-user/0z6akCcH0RE/discussion The new solution: ------------------------------------------------------------------- // This can be used to "patch" or re-configure a JDBC // connection. In the original use case, this was due to // the Connection being transient an thus lost after // deserialisation of POJOs Configuration eventConfigureStart(Query query, Configuration configuration); ------------------------------------------------------------------- > Advanced Java developers who do not want that overhead would track all > the factories that get created and lost in GC to a central place of > theirs so that when they activate/deactivate logging they add/remove > their listener to all of them. This latter behavior is hard to > implement and error prone whereas the central access is easy for the > library to implement. Why track the factories? The callback has access to them...? You can still add/remove your listener to your implementation of the plugin, which, for you specifically, is the same as adding listeners to jOOQ. But for jOOQ it is not the same. > For me, logging is a debugging feature mainly because it can have a > cost (in my code, I also have to aggregate parameters used in a batch > for example). It is not something that runs permanently but rather a > way to attach monitoring tools that can perform advanced analysis. I agree, completely. But I don't see why my idea is so much slower or more complex. It just helps jOOQ not making any assumptions about concrete logging strategies and allows for a few more use-cases while not really impacting yours. It furthermore allows for adding "strategies" to jOOQ, not "state". Whether or not a strategy maintains its (static or non-static) state is up to the implementation, up to you. What do you think, now? :-) Cheers Lukas
