New type of Handler

16 views
Skip to first unread message

tre...@silverfieldstech.com

unread,
Dec 6, 2013, 3:09:29 PM12/6/13
to tu...@googlegroups.com
I've spent today implementing a new type of Handler.

I like Tufao so far, although I've only been playing with it a couple of days.  But I found the handlers very lacking, and not intuitive. 

Not intuitive, because lots of links are hard to find for documentation, and who likes regular expressions?

Lacking, because other than the built in Handlers for rewriting, serving static content, and 404, they don't do much.  Writing all of those regular expressions is not only a pain in the ass, but, are very gross level; you can forward to an instance of your own handler, but, the handler really has no context as to what it needs to do, so has to figure all of that out.  And each other handler would need to do the same, all based on the request; there is no fine-grained dispatch mechanism.  In Java, I hate Spring, but, one thing it does well is fined-grained dispatch, based on annotations.

So I wrote a very automatic, fined-grained, small, dispatch system, based on ReST.  I hope I didn't miss something somewhere, where this is already possible. :)  I am using the Qt meta object system.

This new handler is called a ClassHandler.  These are Qt plugins, and can be either statically linked, or dynamically linked.  There is a ClassHandlerManager that not only handles the subclasses of ClassHandler, but is also the Hander that is used by the HttpServerRequestRouter.  It is wired up like all other Handlers.

ClassHandlerManager classHandler;
classHandler.init();

Tufao::HttpServerRequestRouter router{
    {QRegularExpression{"^/$"}, Tufao::UrlRewriterHandler::handler(QUrl("/index.html"))},
    {QRegularExpression{""}, Tufao::HttpFileServer::handler("static")},
    {QRegularExpression{""}, classHandler},
    {QRegularExpression{""}, Tufao::NotFoundHandler::handler()}
};

When ClassHandlerManager::handleRequest() is called, it determines if a class has been registered that can handle the request.  Subclasses of ClassHandler are registered automatically, either at compile time for static plugins, or at startup for dynamic ones.  No acton is required on the developers side, other than implementing the Qt interface, ClassHandlerInterface.  That's it.

In the sublcasses of ClassHandler, slots are used.  A slot will automatically be called based on the URL.  The subclass can have an arbitrary number of slots.

For example, if the URL is:
/server/settings

then the ClassHandlerManager will automatically see if there is a class Server (technically, this is the QObject::name, but, can be the class name), and if there is, will call the settings method on the instance.

/server/temp/20

would call the temp(20) method on the server instance, as long as the class defined a slot temp(int) method.  If not, the request is not handled, and the request is passed on down the router, like any other request, and any other handler.

The first path component is the name of the class to receive the call.  Every component after that is used to determine which slot to call, and what the arguments are. Again, the QMetaObject system is used to do this.

These URL paths can be arbitrarily complex, with the system determining the call path each URL represents, and what are arguments to the slot methods, etc.  I'm sure I'm not explaining this too well, but it's really not complex for a developer to use.  Then they just need the one router entry, and they can write classes for everything they need to do, without worrying about configuration, and parsing requests.


If there is more general interest in this, I'll fork and integrate my code, and create a pull request.  I'm sure a better C++ coder than me could make improvements; it's not perfect, and I'm still tweeking it, as I use it myself.

Thoughts?

Vinícius dos Santos Oliveira

unread,
Dec 6, 2013, 10:17:47 PM12/6/13
to tu...@googlegroups.com
Em Sex, 2013-12-06 às 12:09 -0800, tre...@silverfieldstech.com escreveu:
I've spent today implementing a new type of Handler.

I like Tufao so far, although I've only been playing with it a couple of days.  But I found the handlers very lacking, and not intuitive. 

Not intuitive, because lots of links are hard to find for documentation, and who likes regular expressions?

Well, so can I assume the problem with the documentation are difficult to find links? It seems reasonable, given you're *only* fast when you already know the name of the class you want to use.

I could create some pages implementing the concept of knowledge map (same as Khan Academy). What do you think? The only problem is *how* should we categorize/create the map. Feedback appreciated.

Lacking, because other than the built in Handlers for rewriting, serving static content, and 404, they don't do much.  [...]


So I wrote a very automatic, fined-grained, small, dispatch system, based on ReST.  I hope I didn't miss something somewhere, where this is already possible. :)  I am using the Qt meta object system.

This new handler is called a ClassHandler.  These are Qt plugins, and can be either statically linked, or dynamically linked.  There is a ClassHandlerManager that not only handles the subclasses of ClassHandler, but is also the Hander that is used by the HttpServerRequestRouter.  It is wired up like all other Handlers.

ClassHandlerManager classHandler;
classHandler.init();

Tufao::HttpServerRequestRouter router{
    {QRegularExpression{"^/$"}, Tufao::UrlRewriterHandler::handler(QUrl("/index.html"))},
    {QRegularExpression{""}, Tufao::HttpFileServer::handler("static")},
    {QRegularExpression{""}, classHandler},
    {QRegularExpression{""}, Tufao::NotFoundHandler::handler()}
};

My thoughts:
  • Why not do the introspection on *any* QObject subclass? Why only ClassHandler subclass?
  • What/why is the init method?
  • Can we add a prefix for classHandler? e.g. if we choose the prefix "plugin/", then the handler will prepend "plugin/" to its normal handling mechanism.

When ClassHandlerManager::handleRequest() is called, it determines if a class has been registered that can handle the request.  Subclasses of ClassHandler are registered automatically, either at compile time for static plugins, or at startup for dynamic ones.  No acton is required on the developers side, other than implementing the Qt interface, ClassHandlerInterface.  That's it.

I like the idea of automatic detection, but can we have both? Not actually both, but automatic and semi-automatic. I mean, at register-time, we could say our plugin is related to the string "forum" and on the ClassHandler instance, we could choose the prefix "forum/". It would greatly improve application deploying and decoupling and etc...

Not that hard to do.

In the sublcasses of ClassHandler, slots are used.  A slot will automatically be called based on the URL.  The subclass can have an arbitrary number of slots.

For example, if the URL is:
/server/settings

then the ClassHandlerManager will automatically see if there is a class Server (technically, this is the QObject::name, but, can be the class name), and if there is, will call the settings method on the instance.

/server/temp/20

would call the temp(20) method on the server instance, as long as the class defined a slot temp(int) method.  If not, the request is not handled, and the request is passed on down the router, like any other request, and any other handler. [...]

It's perfect for single and zero argument functions, but I think we should use query strings or something else for multi-argument functions.

But it can be released as is. Support for multi-argument functions can be released in later versions (and we'd have more feedback and ideas).


If there is more general interest in this, I'll fork and integrate my code, and create a pull request.  I'm sure a better C++ coder than me could make improvements; it's not perfect, and I'm still tweeking it, as I use it myself.

If you keep in a private branch, you'll have to maintain the set of patches for yourself (new Tufão release, more work to you to backport the new features ...).

Thoughts?

I like it. See comments above.


--
Vinícius dos Santos Oliveira
https://about.me/vinipsmaker
signature.asc

Reaves, Timothy

unread,
Dec 9, 2013, 12:55:25 PM12/9/13
to tu...@googlegroups.com
On Fri, Dec 6, 2013 at 10:17 PM, Vinícius dos Santos Oliveira <vini.i...@gmail.com> wrote:
Em Sex, 2013-12-06 às 12:09 -0800, tre...@silverfieldstech.com escreveu:

I've spent today implementing a new type of Handler.

I like Tufao so far, although I've only been playing with it a couple of days.  But I found the handlers very lacking, and not intuitive. 

Not intuitive, because lots of links are hard to find for documentation, and who likes regular expressions?

Well, so can I assume the problem with the documentation are difficult to find links? It seems reasonable, given you're *only* fast when you already know the name of the class you want to use.

I could create some pages implementing the concept of knowledge map (same as Khan Academy). What do you think? The only problem is *how* should we categorize/create the map. Feedback appreciated.



As for the documentation: having a WIKI with better examples would be better.  Having meaningful information with links to the other pages would be good.  The current WIKI is basically a waste.  You must click each page to see what if any content is one it.  I understand this requires time, and that's always in short supply.
 

Lacking, because other than the built in Handlers for rewriting, serving static content, and 404, they don't do much.  [...]


So I wrote a very automatic, fined-grained, small, dispatch system, based on ReST.  I hope I didn't miss something somewhere, where this is already possible. :)  I am using the Qt meta object system.

This new handler is called a ClassHandler.  These are Qt plugins, and can be either statically linked, or dynamically linked.  There is a ClassHandlerManager that not only handles the subclasses of ClassHandler, but is also the Hander that is used by the HttpServerRequestRouter.  It is wired up like all other Handlers.

ClassHandlerManager classHandler;
classHandler.init();

Tufao::HttpServerRequestRouter router{
    {QRegularExpression{"^/$"}, Tufao::UrlRewriterHandler::handler(QUrl("/index.html"))},
    {QRegularExpression{""}, Tufao::HttpFileServer::handler("static")},
    {QRegularExpression{""}, classHandler},
    {QRegularExpression{""}, Tufao::NotFoundHandler::handler()}
};

My thoughts:
  • Why not do the introspection on *any* QObject subclass? Why only ClassHandler subclass?
  • What/why is the init method?
  • Can we add a prefix for classHandler? e.g. if we choose the prefix "plugin/", then the handler will prepend "plugin/" to its normal handling mechanism.



There are a lot of reasons to not consider any QObject; an application can have hundreds or thousands of such classes, that have nothing to do with responding to HTTP requests.  And it's not only subclasses of ClassHandler, it's any class that implements the interface. I just chose to have an abstract class implement the interface. An interface makes perfect sense, as that is what an interface is for; it says that a class is intended to be used for a particular reason or in a particular fashion.

As for the init(), that's mainly due to the fact that C++ does not separate memory allocation and instance initialization, the way, say, Objective-C does.  And as you should never call a method from a constructor, the init method allows for the initialization before use.  In this case, the init method iterates over plugins, and builds  a dispatch table for faster run-time performance.

By prefix, do you mean in the URL?  That would be a really bad idea.  Something accessing a URI doesn't need to know if the implementation is a plugin or not.  If I misunderstood, please clarify.

 
When ClassHandlerManager::handleRequest() is called, it determines if a class has been registered that can handle the request.  Subclasses of ClassHandler are registered automatically, either at compile time for static plugins, or at startup for dynamic ones.  No acton is required on the developers side, other than implementing the Qt interface, ClassHandlerInterface.  That's it.

I like the idea of automatic detection, but can we have both? Not actually both, but automatic and semi-automatic. I mean, at register-time, we could say our plugin is related to the string "forum" and on the ClassHandler instance, we could choose the prefix "forum/". It would greatly improve application deploying and decoupling and etc...

Not that hard to do.


I do not understand what you mean here.  If you had a class named Forum, then any URL starting with /forum would be dispatched to that class.  That happens without intervention reuqired
 
In the sublcasses of ClassHandler, slots are used.  A slot will automatically be called based on the URL.  The subclass can have an arbitrary number of slots.

For example, if the URL is:
/server/settings

then the ClassHandlerManager will automatically see if there is a class Server (technically, this is the QObject::name, but, can be the class name), and if there is, will call the settings method on the instance.

/server/temp/20

would call the temp(20) method on the server instance, as long as the class defined a slot temp(int) method.  If not, the request is not handled, and the request is passed on down the router, like any other request, and any other handler. [...]

It's perfect for single and zero argument functions, but I think we should use query strings or something else for multi-argument functions.

But it can be released as is. Support for multi-argument functions can be released in later versions (and we'd have more feedback and ideas).


No, it's actually perfect regardless of the number of arguments.  As I'm trying to follow ReST, something like:

/catalog/parts/chapter/3/page/2

would result in a call to Catalog::parts(int chapter, int page) as content(3,2)

Catalog is the area of interest, parts is the catalog in particular, and it's the second page of the third chapter.

There are options here.  /catalog/parts/3/2 would work as well, as long as there was no polymorphic versions of the parts method with only two arguments.  But the number of arguments just isn't relevant.

As to the query strings, a dispatcher could also use
/catalog/parts?chapter=3&page=2
I just personally prefer the former, as I think it's more clear.

 

If there is more general interest in this, I'll fork and integrate my code, and create a pull request.  I'm sure a better C++ coder than me could make improvements; it's not perfect, and I'm still tweeking it, as I use it myself.

If you keep in a private branch, you'll have to maintain the set of patches for yourself (new Tufão release, more work to you to backport the new features ...).


I'll try to get it in source control, and you can merge if you see fit.  It would probably be easier to discuss some of these options with code examples, as it may become clearer.  And there is still some things that need to be decided, such as the best way to return from these methods.  For example, the init method on the implementing classes could accept the request & response object, to directly interact with them.  Or the methods could just return a data structure to be rendered some way.

Vinícius dos Santos Oliveira

unread,
Dec 9, 2013, 2:12:37 PM12/9/13
to tu...@googlegroups.com
Em Seg, 2013-12-09 às 12:55 -0500, Reaves, Timothy escreveu:
There are a lot of reasons to not consider any QObject; an application can have hundreds or thousands of such classes, that have nothing to do with responding to HTTP requests.  And it's not only subclasses of ClassHandler, it's any class that implements the interface. I just chose to have an abstract class implement the interface. An interface makes perfect sense, as that is what an interface is for; it says that a class is intended to be used for a particular reason or in a particular fashion.

My understanding about your solution is growing and I think it's a contribution worth enough to have upstream.

Currently Tufão acts more like a library and less like a framework. When you use Tufão, you guide Tufão tools to work together. Your solution would add the other option too, where Tufão would call user code (freeing the user from the responsibility of piecing and communicating different components).

If I understood correctly, your solution will navigate through all subclasses of ClassHandler at runtime and register them as handlers. If this is the case, then I agree with you. It's a bad idea to consider any QObject.


As for the init(), that's mainly due to the fact that C++ does not separate memory allocation and instance initialization, the way, say, Objective-C does.  And as you should never call a method from a constructor, the init method allows for the initialization before use.  In this case, the init method iterates over plugins, and builds  a dispatch table for faster run-time performance.

When you create a class you are abstracting something. The something can be a resource and what you care about is the resource, not memory. Memory is also a resource, but not the only type of resource. RAII free us from the responsibility of think about every exit point to put a free-function call. More than that, RAII allow us to abstract other kind of resources not possible in other languages like mutexes and is the most robust way to exception-safe programming.

A separate init function will complicate the life of the user, because now he has not only to call another function that won't bring him any benefit, but also he has to track a third possible state: the invalid/non-initialized state object.

But... the init function could benefit the implementer, letting him abstract common initialization tasks. If this is the case, just make the method private and call it from the constructors.

Maybe the game will change with transactional memory research. Until there we can continue to use RAII.


By prefix, do you mean in the URL?  That would be a really bad idea.  Something accessing a URI doesn't need to know if the implementation is a plugin or not.  If I misunderstood, please clarify.


 

When ClassHandlerManager::handleRequest() is called, it determines if a class has been registered that can handle the request.  Subclasses of ClassHandler are registered automatically, either at compile time for static plugins, or at startup for dynamic ones.  No acton is required on the developers side, other than implementing the Qt interface, ClassHandlerInterface.  That's it.


I like the idea of automatic detection, but can we have both? Not actually both, but automatic and semi-automatic. I mean, at register-time, we could say our plugin is related to the string "forum" and on the ClassHandler instance, we could choose the prefix "forum/". It would greatly improve application deploying and decoupling and etc...

Not that hard to do.




I do not understand what you mean here.  If you had a class named Forum, then any URL starting with /forum would be dispatched to that class.  That happens without intervention reuqired

Your proposed solution is a bit intrusive and require changes to previous components to make them work against the new approach. If the user doesn't have control over all components, he can't update the source to match the new approach, but you avoid this problem with the ClassHandlerManager request handler.

I see this as an opportunity to make Tufão smart enough to handle "embedded apps". Imagine if we have multiple ClassHandlerManagers. Can we register ClassHandler-inherited handlers to different ClassHandlerManagers? Maybe we can use a root fallback ClassHandlerManager handler and some string-identified ClassHandlerManager handlers. They still would be decoupled and would only interact at runtime.

My overly bad explained suggestions quoted above were related about this change.

Imagine the user wants to use an embedded app to provide a forum to its site. Maybe he wants to put this app under the "/forum" url or maybe he wants to put it under the "/boards" url, but he must have control to avoid collision without the need to change the imported components. This is what I meant with the "url-prefixing".

And what if the user wants to import a wiki app/component and a forum app/component to embed on its site? The components shouldn't register to the same ClassHandlerManager, because each one will "prefix" to different paths to the beginning of the url. If the user doesn't identify a ClassHandlerManager, then the wiki should just use the root ClassHandlerManager (the one without a id string associated, always present).

Thoughts?
No, it's actually perfect regardless of the number of arguments.  As I'm trying to follow ReST, something like:


/catalog/parts/chapter/3/page/2


would result in a call to Catalog::parts(int chapter, int page) as content(3,2)

I didn't realized that. Thanks for the explanation. It's good enough and no changes are required.
signature.asc

Reaves, Timothy

unread,
Dec 9, 2013, 3:21:13 PM12/9/13
to tu...@googlegroups.com
On Mon, Dec 9, 2013 at 2:12 PM, Vinícius dos Santos Oliveira <vini.i...@gmail.com> wrote:
Em Seg, 2013-12-09 às 12:55 -0500, Reaves, Timothy escreveu:
There are a lot of reasons to not consider any QObject; an application can have hundreds or thousands of such classes, that have nothing to do with responding to HTTP requests.  And it's not only subclasses of ClassHandler, it's any class that implements the interface. I just chose to have an abstract class implement the interface. An interface makes perfect sense, as that is what an interface is for; it says that a class is intended to be used for a particular reason or in a particular fashion.

My understanding about your solution is growing and I think it's a contribution worth enough to have upstream.

Currently Tufão acts more like a library and less like a framework. When you use Tufão, you guide Tufão tools to work together. Your solution would add the other option too, where Tufão would call user code (freeing the user from the responsibility of piecing and communicating different components).

If I understood correctly, your solution will navigate through all subclasses of ClassHandler at runtime and register them as handlers. If this is the case, then I agree with you. It's a bad idea to consider any QObject.


That is basically correct.  Qt will automatically handle identifying the classes that implement the interface, and if they are not statically, my code will load it.  But you have the overall idea correct.
 

As for the init(), that's mainly due to the fact that C++ does not separate memory allocation and instance initialization, the way, say, Objective-C does.  And as you should never call a method from a constructor, the init method allows for the initialization before use.  In this case, the init method iterates over plugins, and builds  a dispatch table for faster run-time performance.

When you create a class you are abstracting something. The something can be a resource and what you care about is the resource, not memory. Memory is also a resource, but not the only type of resource. RAII free us from the responsibility of think about every exit point to put a free-function call. More than that, RAII allow us to abstract other kind of resources not possible in other languages like mutexes and is the most robust way to exception-safe programming.

A separate init function will complicate the life of the user, because now he has not only to call another function that won't bring him any benefit, but also he has to track a third possible state: the invalid/non-initialized state object.

But... the init function could benefit the implementer, letting him abstract common initialization tasks. If this is the case, just make the method private and call it from the constructors.

Maybe the game will change with transactional memory research. Until there we can continue to use RAII.


This still all misses the point of separating memory allocation with object initialization.  I understand that for C++ ( & Java) this introduces - as you say - a third state.  This is unfortunate, but the trade-off in testability far outweighs that.  In every use of these objects (with the possible exception of the test cases), init() would be immediately called, minimizing confusion.

What you are missing here is the decoupling of memory allocation and object initialization.  Before an instance of a class is ready to be used in an application, it may need to acquire resource.  Those resources should never be acquired - and may not be able to be acquired - during testing.  If my class has a method foo(), and I am testing - as all good developers do -my code, testing foo() should have zero side effects.  I should not need to acquire a database connection to test foo(), whereas a database connection would be needed to use the instance in the running application. 

While working at a large internet search company, the main code base could not be tested, as the programmers there did not make this separation, and their object constructors acquired so many resources that testing was impossible, as these resources where not available to the test harnesses, and lots so exceptions where thrown.

This is a fundamental approach to software development, and people will either agree or disagree, just as some poor programmers disagree when I say a conditional body should always be enclosed in brackets, even when that body is a single line.  As a general statement, I fundamentally believe a constructor should never do more than assignment; no use of 'new' and no use of the de-refernce operators.  Because when you do, and a test fails, you do not know if the test failed because the logic was wrong, or some resource was unavailable.  That's a bad test.  So other than using an init() method, how do you separate the two concerns?


Now, if that is the only thing that would preclude merging of my code, I'd change it.

 

By prefix, do you mean in the URL?  That would be a really bad idea.  Something accessing a URI doesn't need to know if the implementation is a plugin or not.  If I misunderstood, please clarify.


 

When ClassHandlerManager::handleRequest() is called, it determines if a class has been registered that can handle the request.  Subclasses of ClassHandler are registered automatically, either at compile time for static plugins, or at startup for dynamic ones.  No acton is required on the developers side, other than implementing the Qt interface, ClassHandlerInterface.  That's it.


I like the idea of automatic detection, but can we have both? Not actually both, but automatic and semi-automatic. I mean, at register-time, we could say our plugin is related to the string "forum" and on the ClassHandler instance, we could choose the prefix "forum/". It would greatly improve application deploying and decoupling and etc...

Not that hard to do.




I do not understand what you mean here.  If you had a class named Forum, then any URL starting with /forum would be dispatched to that class.  That happens without intervention reuqired

Your proposed solution is a bit intrusive and require changes to previous components to make them work against the new approach. If the user doesn't have control over all components, he can't update the source to match the new approach, but you avoid this problem with the ClassHandlerManager request handler.

I see this as an opportunity to make Tufão smart enough to handle "embedded apps". Imagine if we have multiple ClassHandlerManagers. Can we register ClassHandler-inherited handlers to different ClassHandlerManagers? Maybe we can use a root fallback ClassHandlerManager handler and some string-identified ClassHandlerManager handlers. They still would be decoupled and would only interact at runtime.

My overly bad explained suggestions quoted above were related about this change.

Imagine the user wants to use an embedded app to provide a forum to its site. Maybe he wants to put this app under the "/forum" url or maybe he wants to put it under the "/boards" url, but he must have control to avoid collision without the need to change the imported components. This is what I meant with the "url-prefixing".

And what if the user wants to import a wiki app/component and a forum app/component to embed on its site? The components shouldn't register to the same ClassHandlerManager, because each one will "prefix" to different paths to the beginning of the url. If the user doesn't identify a ClassHandlerManager, then the wiki should just use the root ClassHandlerManager (the one without a id string associated, always present).

Thoughts?

First of all, a clarification:  for the context, technically I'm not using the class name, but, the result of setObjectName() in the plugin class.  This is because QObject::objectName() is called, and the default is an empty string, not the class name.  So technically there is no coupling between the class name and the object name, but as a practice, I'd keep the two the same.  It's just not required.

I use a ClassHandlerPluginInfo struct to track plugin information.    I'll add a context attribute to it, and in the ClassHandlerManager, treat the first path component as the context (ala Spring).  But if I do that, I do not think there should be a default fallback as you suggest.  if /context/objectName does not exist, the handler would return false instead of checking for /objectName.  This is because I think the concept of an application context should be used, or not, but not both.

I'm a bit unsure about your mentioning more than one ClassHandlerManager.  If I add 'contextPath' as an attribute of the plugin. the ClassHandlerManager can test for it.  The other possibility is for the Tufao::HttpServerRequestRouter to use a context in the RegEx to map to more than one ClassHandlerManager, and in that case the ClassHandler Manager would need to ignore the context.  I see no benefit to more than one instance of ClassHandlerManager is I add the 'contextPath' check, do you?




Reaves, Timothy

unread,
Dec 9, 2013, 3:41:22 PM12/9/13
to tu...@googlegroups.com
A followup on the context.

Are you saying you think a user should be able to specify context and over-ride what the pluging author wants?  Or to specify a context if the plugin author did not?

Vinícius dos Santos Oliveira

unread,
Dec 9, 2013, 3:44:05 PM12/9/13
to tu...@googlegroups.com
Em Seg, 2013-12-09 às 15:21 -0500, Reaves, Timothy escreveu:
While working at a large internet search company, the main code base could not be tested, as the programmers there did not make this separation, and their object constructors acquired so many resources that testing was impossible, as these resources where not available to the test harnesses, and lots so exceptions where thrown.


This is a fundamental approach to software development, and people will either agree or disagree, just as some poor programmers disagree when I say a conditional body should always be enclosed in brackets, even when that body is a single line.  As a general statement, I fundamentally believe a constructor should never do more than assignment; no use of 'new' and no use of the de-refernce operators.  Because when you do, and a test fails, you do not know if the test failed because the logic was wrong, or some resource was unavailable.  That's a bad test.  So other than using an init() method, how do you separate the two concerns?

Just to clarify: My main concern here is the library's user, not the library's implementer. So there would be one class with a init() method only and even if I migrate all Tufão classes to use a init() method, the API wouldn't be beautiful integrated with Qt. The *consistency* would be buried very deep.

Clarification done, I can answer the questions without caring about Tufão/Qt/... and mostly thinking about the design. When a allocation function fails, it will throw bad_alloc. Then you actually can know if the fail reason is a resource acquisition problem or another reason (of course Qt style doesn't allow exceptions, but I left this discussion aside on the paragraph above).

About add a different initialization routine/order/scheme/technique for testing-purposes, you can add a secondary constructor and use it. The secondary constructor could even receive a mock object, improving the testability. Win-win without harming the library's user life. And if you want to restrict the access to the secondary constructor (to avoid the commitment of API-stability), you can use an opaque type and put the type definition of the mock object's class on a private header.


Now, if that is the only thing that would preclude merging of my code, I'd change it.

Wait a bit more. The solution is good and ready, but I want to discuss the possibility of extend it to cover more use-cases. If we agree the extension should be in this REST-solution layer, then I wanna check the API to make sure the next-next-release could extend your API without introducing backward-compatibility problems.
signature.asc

Reaves, Timothy

unread,
Dec 9, 2013, 3:46:42 PM12/9/13
to tu...@googlegroups.com
I think there is no 'generally acceptable' answer here, but I do agree about the consistency within the app, and from that perspective, it's better without.


Vinícius dos Santos Oliveira

unread,
Dec 9, 2013, 3:49:24 PM12/9/13
to tu...@googlegroups.com
Em Seg, 2013-12-09 às 15:41 -0500, Reaves, Timothy escreveu:
Are you saying you think a user should be able to specify context and over-ride what the pluging author wants?  Or to specify a context if the plugin author did not?

Well, what do you think about this[1] code user-case?

[1] https://gist.github.com/vinipsmaker/7880599
signature.asc

Reaves, Timothy

unread,
Dec 9, 2013, 4:21:20 PM12/9/13
to tu...@googlegroups.com
Yes, this is do-able easily with dynamic plugins.  Not with static plugins.  It can be done with static plugins differently though, requiring the developer to not only use Q_PLUGIN_METADATA but also Q_CLASSINFO.  This is because QPluginLoader isn't used for static plugins.

So should be figure all plugins dynamic?  Or support both methods?

Vinícius dos Santos Oliveira

unread,
Dec 9, 2013, 4:38:57 PM12/9/13
to tu...@googlegroups.com
Em Seg, 2013-12-09 às 16:21 -0500, Reaves, Timothy escreveu:
Yes, this is do-able easily with dynamic plugins.  Not with static plugins.  It can be done with static plugins differently though, requiring the developer to not only use Q_PLUGIN_METADATA but also Q_CLASSINFO.  This is because QPluginLoader isn't used for static plugins.


So should be figure all plugins dynamic?  Or support both methods?

Well, the proposed interface was just to express the idea.

In the best scenario, we would support non-plugins too.

Maybe there should be a ClassHandler2 class with a constructor that receives the id string argument and the subclasses would fill the string id after the first object is created.

The user wanting to register handlers to the root component would use the ClassHandler and the user wanting to create reusable libraries would use ClassHandler2.

Can you make your code public? It could enlighten me with ideas.
signature.asc

Vinícius dos Santos Oliveira

unread,
Dec 10, 2013, 11:53:28 AM12/10/13
to tu...@googlegroups.com
Well, I'll be busy this week, but I'll try to prepare some design ideas with maybe documentation and UML next week.
signature.asc

Reaves, Timothy

unread,
Dec 13, 2013, 12:35:11 PM12/13/13
to tu...@googlegroups.com

Reaves, Timothy

unread,
Dec 13, 2013, 2:28:21 PM12/13/13
to tu...@googlegroups.com
Please ignore the second link; I figured out the issue.  It's all working now.

Vinícius dos Santos Oliveira

unread,
Dec 20, 2013, 11:48:21 PM12/20/13
to tu...@googlegroups.com
Em Sex, 2013-12-13 às 12:35 -0500, Reaves, Timothy escreveu:
When you get a chance, have a look at:
https://github.com/treaves/tufao

I'm on a kind of vacation right now and I'll be looking your code closely on this time. I hope to include it and release on next version with as few changes as possible.

I just "scratched" the code by now, but it was enough to notice that it partly follows a different style. Most of these styles differences are okay, but identation is not. Identation should always be 4 spaces as noted on the HACKING.md file<https://github.com/vinipsmaker/tufao/blob/master/HACKING.md#coding-style>.

Another thing I noticed was the change on the class HttpServerRequest (the addition of the m_context member). I won't comment this addition now. What I want to comment know is the *way* the addition was done. You should put the m_context member under the HttpServerRequest::Priv struct under the src/priv/httpserverrequest.h member class and access this member through the priv pointer. This technique is called opaque pointer and Qt and Tufão use it to provide binary compatibility among different versions. You can google it for more info.

I'll continue to review your code in the coming days.
=)
signature.asc

Timothy Reaves

unread,
Dec 21, 2013, 9:05:52 AM12/21/13
to tu...@googlegroups.com
I'll change the indentation and re-commit.

When my team wrote Google Maps, we had a discussion on opaque pointers; luckily, as I was the lead, my view won out, and they were not used.  I'll not bore you with the discussion.  I'll move that data member into the private structure as you prefer.
signature.asc

Vinícius dos Santos Oliveira

unread,
Jan 12, 2014, 11:21:56 PM1/12/14
to tu...@googlegroups.com, Reaves, Timothy
Em Sex, 2013-12-13 às 12:35 -0500, Reaves, Timothy escreveu:
When you get a chance, have a look at:
https://github.com/treaves/tufao

I spent some time looking the code and here are some points:
  • CMakeLists.txt: You added compiling flags to build the project correctly under MAC. I appreciate that. But I have to ask you to isolate this change (that is purely C++11 related) under the file cmake/modules/FindCXX11.cmake
  • You added the member context to the initialization list of the HttpServerRequest::Priv's constructor with the argument "", but it should be ommitted, because (1) constructor for complex objects are implicitly called and (2) you are calling it with the empty string argument, which is worse (just a little bit) than calling with no arguments. For pratical purposes, the only differences are when you call QString::isNull, but I believe you aren't exploring this behaviour. In short, you're writing more code to perform worse.
  • Change the license of the *.cpp files to LGPLv2.1+ to keep uniformity (and sanity) of the project.
  • What is the purpose of ClassHandlerPluginInfo constructor?
  • Looks like you wrote a nice documentation for ClassHandler (but even with the documentation, you wrote an example).

There are more items, but I'll review them soon. Also, QtCreator 3.0 is giving trouble to me (change the badly documented API every fucking release for a purely data-driven plugin).
signature.asc

Vinícius dos Santos Oliveira

unread,
Feb 25, 2014, 10:29:38 PM2/25/14
to Reaves, Timothy, tu...@googlegroups.com
Em Sex, 2013-12-06 às 12:09 -0800, tre...@silverfieldstech.com escreveu:
I've spent today implementing a new type of Handler. [...]

Hi Timothy,

I've started to work on your set of patches more seriously. Lots of changes, tests and a bugfix.

You can check my changes at https://github.com/vinipsmaker/tufao/compare/treaves:master...treaves . The first changes are related to branch-merging with main Tufão branch. Check the changes starting from Feb 24.

The only things that I think annoying are the excess of ifdefs. Ideally there would be no ifdefs. I looked on the used ifdefs and here are my list of ideas to reduce/remove them:
  • Plugin search paths (the pluginLocations variable) is okay, but I wanna remove the the lazy evaluation of this global variable and try to make it fully initialized before main() start. I'll check that later
  • pluginExtension and entry.endsWith(pluginExtension) is not okay. I'll not merge the branch while this issue is not resolved. I made a little research and I see two solutions:
  • Replace the entry.endsWith test by QLibrary::isLibrary
  • Use CMake to detect platform features. See this: http://www.cmake.org/pipermail/cmake/2007-June/014688.html

One of my changes has a drawback and this is something that I'll work on, but it isn't a blocker and also isn't something that most of user will notice, then I'll rush the 1.2 release with your changes and come back to my problem later.

If everything is fine and you have nothing against, I'd like to release the 1.2 version with your changes on this weekend.
signature.asc

Timothy Reaves

unread,
Feb 26, 2014, 1:43:54 PM2/26/14
to Vinícius dos Santos Oliveira, tu...@googlegroups.com
From the list below, the only thing you had not done is to change the use of isLibrary().  I agree that ifdefs should be avoided, and one block of them can be removed with the change to isLibrary().  I don't see a need for any of the macros the e-mail you reference mention; the isLibrary() will take care of the library extension.

I have no issues with any of your changes, with the exception of your belief that binary compatibility is a desirable 'feature.'  As I've no desire to debate it, I simply don't care about that change.

If you want me to go ahead with the change for isLibrary(), and merge in your changes, I will, but, it seems to be less work for you to simply update that code.

Let me know.
signature.asc

Vinícius dos Santos Oliveira

unread,
Feb 26, 2014, 2:17:31 PM2/26/14
to Timothy Reaves, tu...@googlegroups.com
Em Qua, 2014-02-26 às 13:43 -0500, Timothy Reaves escreveu:
[...] If you want me to go ahead with the change for isLibrary(), and merge in your changes, I will, but, it seems to be less work for you to simply update that code.

I'll do it. Don't worry.

I just wanted to discuss possible solutions. So "isLibrary()" will be the one.

I won't merge the two branches today, because there's some preparatory changes yet to do, but I'll likely release the new version with your feature during the weekend or before.

Next target to attack is prepare a "2.x" development branch to include work from Benjamin Zeller[1] and refactoring changes to allow things like "HTTP/2.0", FastCGI and maybe better testing. Sooo much work to do.

[1] https://github.com/Esf-Software/tufao/tree/threads
signature.asc

Reaves, Timothy

unread,
Mar 24, 2014, 3:02:22 PM3/24/14
to Vinícius dos Santos Oliveira, tu...@googlegroups.com
I see on the main README that you merged this for 1.2, but in the source, all plugin code was removed.  There is not comment to explain this.  Is this a permanent thing?

Vinícius dos Santos Oliveira

unread,
Mar 24, 2014, 3:09:57 PM3/24/14
to Reaves, Timothy, tu...@googlegroups.com
Em Seg, 2014-03-24 às 15:02 -0400, Reaves, Timothy escreveu:
I see on the main README that you merged this for 1.2, but in the source, all plugin code was removed.  There is not comment to explain this.  Is this a permanent thing?

It is just a temporary thing. There are big problems to tackle in the 2.0 release and the plugin code would delay and distract me.

Plugins will likely to be reintroduced in 2.1. Maybe with some changes to greater code reuse between the two plugin systems.

But there is no need to worry. When the major version differs, it's possible to install several Tufão libraries in parallel in the same system. I already separated the branch to maintain code for the 1.x series and so on.
signature.asc

Reaves, Timothy

unread,
Mar 24, 2014, 3:11:52 PM3/24/14
to Vinícius dos Santos Oliveira, tu...@googlegroups.com
Is there any way I might help out?  I'd like to continue my involvement with the project, and now that I've started a new job, I hope to have some time.

Vinícius dos Santos Oliveira

unread,
Mar 24, 2014, 4:27:25 PM3/24/14
to Reaves, Timothy, tu...@googlegroups.com
Em Seg, 2014-03-24 às 15:11 -0400, Reaves, Timothy escreveu:
Is there any way I might help out?  I'd like to continue my involvement with the project, and now that I've started a new job, I hope to have some time.

Great.

I'd like to improve Tufão support for HTTP pipelining and multiple backends (such as FastCGI, CoAP and others). This require a greater separation between request objects and the communication channel. That's the reason to release the version 2.0 with little concerns to keep API stability.

Discussion about this specific design can happen here on the mailing list or on the GitHub issue[1].

I was thinking initially about make some AbstractHttpRequest class, but I haven't spend much effort or time in the design yet. Feel free to contribute with anything.

You can help with this issue or just state your plans for the future and work on them. There are also several GitHub issues with hints for enhancement.

[1] https://github.com/vinipsmaker/tufao/issues/19
signature.asc
Reply all
Reply to author
Forward
0 new messages